summaryrefslogtreecommitdiff
path: root/apps/plugins/pdbox/PDa/src/g_text.c
diff options
context:
space:
mode:
Diffstat (limited to 'apps/plugins/pdbox/PDa/src/g_text.c')
-rw-r--r--apps/plugins/pdbox/PDa/src/g_text.c2632
1 files changed, 2632 insertions, 0 deletions
diff --git a/apps/plugins/pdbox/PDa/src/g_text.c b/apps/plugins/pdbox/PDa/src/g_text.c
new file mode 100644
index 0000000000..8cf1fe2834
--- /dev/null
+++ b/apps/plugins/pdbox/PDa/src/g_text.c
@@ -0,0 +1,2632 @@
1/* Copyright (c) 1997-1999 Miller Puckette.
2* For information on usage and redistribution, and for a DISCLAIMER OF ALL
3* WARRANTIES, see the file, "LICENSE.txt," in this distribution. */
4
5/* changes by Thomas Musil IEM KUG Graz Austria 2001 */
6/* the methods for calling the gui-objects from menu are implemented */
7/* all changes are labeled with iemlib */
8
9#include <stdlib.h>
10#include "m_pd.h"
11#include "m_imp.h"
12#include "s_stuff.h"
13#include "t_tk.h"
14#include "g_canvas.h"
15#include <stdio.h>
16#include <string.h>
17#include <math.h>
18
19static t_class *text_class;
20static t_class *message_class;
21static t_class *gatom_class;
22static void text_vis(t_gobj *z, t_glist *glist, int vis);
23static void text_displace(t_gobj *z, t_glist *glist,
24 int dx, int dy);
25static void text_getrect(t_gobj *z, t_glist *glist,
26 int *xp1, int *yp1, int *xp2, int *yp2);
27
28void canvas_startmotion(t_canvas *x);
29t_widgetbehavior text_widgetbehavior;
30
31/* ----------------- the "text" object. ------------------ */
32
33 /* add a "text" object (comment) to a glist. While this one goes for any glist,
34 the other 3 below are for canvases only. (why?) This is called
35 without args if invoked from the GUI; otherwise at least x and y
36 are provided. */
37
38void glist_text(t_glist *gl, t_symbol *s, int argc, t_atom *argv)
39{
40 t_text *x = (t_text *)pd_new(text_class);
41 t_atom at;
42 x->te_width = 0; /* don't know it yet. */
43 x->te_type = T_TEXT;
44 x->te_binbuf = binbuf_new();
45 if (argc > 1)
46 {
47 x->te_xpix = atom_getfloatarg(0, argc, argv);
48 x->te_ypix = atom_getfloatarg(1, argc, argv);
49 if (argc > 2) binbuf_restore(x->te_binbuf, argc-2, argv+2);
50 else
51 {
52 SETSYMBOL(&at, gensym("comment"));
53 binbuf_restore(x->te_binbuf, 1, &at);
54 }
55 glist_add(gl, &x->te_g);
56 }
57 else
58 {
59 int xpix, ypix;
60 pd_vmess((t_pd *)glist_getcanvas(gl), gensym("editmode"), "i", 1);
61 SETSYMBOL(&at, gensym("comment"));
62 glist_noselect(gl);
63 glist_getnextxy(gl, &xpix, &ypix);
64 x->te_xpix = glist_pixelstox(gl, xpix-3);
65 x->te_ypix = glist_pixelstoy(gl, ypix-3);
66 binbuf_restore(x->te_binbuf, 1, &at);
67 glist_add(gl, &x->te_g);
68 glist_noselect(gl);
69 glist_select(gl, &x->te_g);
70 /* it would be nice to "activate" here, but then the second,
71 "put-me-down" click changes the text selection, which is quite
72 irritating, so I took this back out. It's OK in messages
73 and objects though since there's no text in them at menu
74 creation. */
75 /* gobj_activate(&x->te_g, gl, 1); */
76 canvas_startmotion(glist_getcanvas(gl));
77 }
78}
79
80/* ----------------- the "object" object. ------------------ */
81
82extern t_pd *newest;
83void canvas_getargs(int *argcp, t_atom **argvp);
84
85static void canvas_objtext(t_glist *gl, int xpix, int ypix, int selected,
86 t_binbuf *b)
87{
88 t_text *x;
89 int argc;
90 t_atom *argv;
91 newest = 0;
92 canvas_setcurrent((t_canvas *)gl);
93 canvas_getargs(&argc, &argv);
94 binbuf_eval(b, &pd_objectmaker, argc, argv);
95 if (binbuf_getnatom(b))
96 {
97 if (!newest)
98 {
99 binbuf_print(b);
100 post("... couldn't create");
101 x = 0;
102 }
103 else if (!(x = pd_checkobject(newest)))
104 {
105 binbuf_print(b);
106 post("... didn't return a patchable object");
107 }
108 }
109 else x = 0;
110 if (!x)
111 {
112
113 /* LATER make the color reflect this */
114 x = (t_text *)pd_new(text_class);
115 }
116 x->te_binbuf = b;
117 x->te_xpix = xpix;
118 x->te_ypix = ypix;
119 x->te_width = 0;
120 x->te_type = T_OBJECT;
121 glist_add(gl, &x->te_g);
122 if (selected)
123 {
124 /* this is called if we've been created from the menu. */
125 glist_select(gl, &x->te_g);
126 gobj_activate(&x->te_g, gl, 1);
127 }
128 if (pd_class(&x->ob_pd) == vinlet_class)
129 canvas_resortinlets(glist_getcanvas(gl));
130 if (pd_class(&x->ob_pd) == voutlet_class)
131 canvas_resortoutlets(glist_getcanvas(gl));
132 canvas_unsetcurrent((t_canvas *)gl);
133}
134
135 /* object creation routine. These are called without any arguments if
136 they're invoked from the
137 gui; when pasting or restoring from a file, we get at least x and y. */
138
139void canvas_obj(t_glist *gl, t_symbol *s, int argc, t_atom *argv)
140{
141 t_text *x;
142 if (argc >= 2)
143 {
144 t_binbuf *b = binbuf_new();
145 binbuf_restore(b, argc-2, argv+2);
146 canvas_objtext(gl, atom_getintarg(0, argc, argv),
147 atom_getintarg(1, argc, argv), 0, b);
148 }
149 else
150 {
151 t_binbuf *b = binbuf_new();
152 int xpix, ypix;
153 pd_vmess(&gl->gl_pd, gensym("editmode"), "i", 1);
154 glist_noselect(gl);
155 glist_getnextxy(gl, &xpix, &ypix);
156 canvas_objtext(gl, xpix, ypix, 1, b);
157 canvas_startmotion(glist_getcanvas(gl));
158 }
159}
160
161/* make an object box for an object that's already there. */
162
163/* iemlib */
164void canvas_iemguis(t_glist *gl, t_symbol *guiobjname)
165{
166 t_atom at;
167 t_binbuf *b = binbuf_new();
168 int xpix, ypix;
169
170 pd_vmess(&gl->gl_pd, gensym("editmode"), "i", 1);
171 glist_noselect(gl);
172 SETSYMBOL(&at, guiobjname);
173 binbuf_restore(b, 1, &at);
174 glist_getnextxy(gl, &xpix, &ypix);
175 canvas_objtext(gl, xpix, ypix, 1, b);
176 canvas_startmotion(glist_getcanvas(gl));
177}
178
179void canvas_bng(t_glist *gl, t_symbol *s, int argc, t_atom *argv)
180{
181 canvas_iemguis(gl, gensym("bng"));
182}
183
184void canvas_toggle(t_glist *gl, t_symbol *s, int argc, t_atom *argv)
185{
186 canvas_iemguis(gl, gensym("tgl"));
187}
188
189void canvas_vslider(t_glist *gl, t_symbol *s, int argc, t_atom *argv)
190{
191 canvas_iemguis(gl, gensym("vsl"));
192}
193
194void canvas_hslider(t_glist *gl, t_symbol *s, int argc, t_atom *argv)
195{
196 canvas_iemguis(gl, gensym("hsl"));
197}
198
199void canvas_hdial(t_glist *gl, t_symbol *s, int argc, t_atom *argv)
200{
201 canvas_iemguis(gl, gensym("hdl"));
202}
203
204void canvas_vdial(t_glist *gl, t_symbol *s, int argc, t_atom *argv)
205{
206 canvas_iemguis(gl, gensym("vdl"));
207}
208
209void canvas_hradio(t_glist *gl, t_symbol *s, int argc, t_atom *argv)
210{
211 canvas_iemguis(gl, gensym("hradio"));
212}
213
214void canvas_vradio(t_glist *gl, t_symbol *s, int argc, t_atom *argv)
215{
216 canvas_iemguis(gl, gensym("vradio"));
217}
218
219void canvas_vumeter(t_glist *gl, t_symbol *s, int argc, t_atom *argv)
220{
221 canvas_iemguis(gl, gensym("vu"));
222}
223
224void canvas_mycnv(t_glist *gl, t_symbol *s, int argc, t_atom *argv)
225{
226 canvas_iemguis(gl, gensym("cnv"));
227}
228
229void canvas_numbox(t_glist *gl, t_symbol *s, int argc, t_atom *argv)
230{
231 canvas_iemguis(gl, gensym("nbx"));
232}
233
234/* iemlib */
235
236void canvas_objfor(t_glist *gl, t_text *x, int argc, t_atom *argv)
237{
238 x->te_width = 0; /* don't know it yet. */
239 x->te_type = T_OBJECT;
240 x->te_binbuf = binbuf_new();
241 x->te_xpix = atom_getfloatarg(0, argc, argv);
242 x->te_ypix = atom_getfloatarg(1, argc, argv);
243 if (argc > 2) binbuf_restore(x->te_binbuf, argc-2, argv+2);
244 glist_add(gl, &x->te_g);
245}
246
247/* ---------------------- the "message" text item ------------------------ */
248
249typedef struct _messresponder
250{
251 t_pd mr_pd;
252 t_outlet *mr_outlet;
253} t_messresponder;
254
255typedef struct _message
256{
257 t_text m_text;
258 t_messresponder m_messresponder;
259 t_glist *m_glist;
260 t_clock *m_clock;
261} t_message;
262
263static t_class *message_class, *messresponder_class;
264
265static void messresponder_bang(t_messresponder *x)
266{
267 outlet_bang(x->mr_outlet);
268}
269
270static void messresponder_float(t_messresponder *x, t_float f)
271{
272 outlet_float(x->mr_outlet, f);
273}
274
275static void messresponder_symbol(t_messresponder *x, t_symbol *s)
276{
277 outlet_symbol(x->mr_outlet, s);
278}
279
280static void messresponder_list(t_messresponder *x,
281 t_symbol *s, int argc, t_atom *argv)
282{
283 outlet_list(x->mr_outlet, s, argc, argv);
284}
285
286static void messresponder_anything(t_messresponder *x,
287 t_symbol *s, int argc, t_atom *argv)
288{
289 outlet_anything(x->mr_outlet, s, argc, argv);
290}
291
292static void message_bang(t_message *x)
293{
294 binbuf_eval(x->m_text.te_binbuf, &x->m_messresponder.mr_pd, 0, 0);
295}
296
297static void message_float(t_message *x, t_float f)
298{
299 t_atom at;
300 SETFLOAT(&at, f);
301 binbuf_eval(x->m_text.te_binbuf, &x->m_messresponder.mr_pd, 1, &at);
302}
303
304static void message_symbol(t_message *x, t_symbol *s)
305{
306 t_atom at;
307 SETSYMBOL(&at, s);
308 binbuf_eval(x->m_text.te_binbuf, &x->m_messresponder.mr_pd, 1, &at);
309}
310
311static void message_list(t_message *x, t_symbol *s, int argc, t_atom *argv)
312{
313 binbuf_eval(x->m_text.te_binbuf, &x->m_messresponder.mr_pd, argc, argv);
314}
315
316static void message_set(t_message *x, t_symbol *s, int argc, t_atom *argv)
317{
318 binbuf_clear(x->m_text.te_binbuf);
319 binbuf_add(x->m_text.te_binbuf, argc, argv);
320 glist_retext(x->m_glist, &x->m_text);
321}
322
323static void message_add2(t_message *x, t_symbol *s, int argc, t_atom *argv)
324{
325 binbuf_add(x->m_text.te_binbuf, argc, argv);
326 glist_retext(x->m_glist, &x->m_text);
327}
328
329static void message_add(t_message *x, t_symbol *s, int argc, t_atom *argv)
330{
331 binbuf_add(x->m_text.te_binbuf, argc, argv);
332 binbuf_addsemi(x->m_text.te_binbuf);
333 glist_retext(x->m_glist, &x->m_text);
334}
335
336static void message_click(t_message *x,
337 t_floatarg xpos, t_floatarg ypos, t_floatarg shift,
338 t_floatarg ctrl, t_floatarg alt)
339{
340 message_float(x, 0);
341 if (glist_isvisible(x->m_glist))
342 {
343 t_rtext *y = glist_findrtext(x->m_glist, &x->m_text);
344 sys_vgui(".x%x.c itemconfigure %sR -width 5\n",
345 glist_getcanvas(x->m_glist), rtext_gettag(y));
346 clock_delay(x->m_clock, 120);
347 }
348}
349
350static void message_tick(t_message *x)
351{
352 if (glist_isvisible(x->m_glist))
353 {
354 t_rtext *y = glist_findrtext(x->m_glist, &x->m_text);
355 sys_vgui(".x%x.c itemconfigure %sR -width 1\n",
356 glist_getcanvas(x->m_glist), rtext_gettag(y));
357 }
358}
359
360static void message_free(t_message *x)
361{
362 clock_free(x->m_clock);
363}
364
365void canvas_msg(t_glist *gl, t_symbol *s, int argc, t_atom *argv)
366{
367 t_message *x = (t_message *)pd_new(message_class);
368 x->m_messresponder.mr_pd = messresponder_class;
369 x->m_messresponder.mr_outlet = outlet_new(&x->m_text, &s_float);
370 x->m_text.te_width = 0; /* don't know it yet. */
371 x->m_text.te_type = T_MESSAGE;
372 x->m_text.te_binbuf = binbuf_new();
373 x->m_glist = gl;
374 x->m_clock = clock_new(x, (t_method)message_tick);
375 if (argc > 1)
376 {
377 x->m_text.te_xpix = atom_getfloatarg(0, argc, argv);
378 x->m_text.te_ypix = atom_getfloatarg(1, argc, argv);
379 if (argc > 2) binbuf_restore(x->m_text.te_binbuf, argc-2, argv+2);
380 glist_add(gl, &x->m_text.te_g);
381 }
382 else
383 {
384 int xpix, ypix;
385 pd_vmess(&gl->gl_pd, gensym("editmode"), "i", 1);
386 glist_noselect(gl);
387 glist_getnextxy(gl, &xpix, &ypix);
388 x->m_text.te_xpix = xpix-3;
389 x->m_text.te_ypix = ypix-3;
390 glist_add(gl, &x->m_text.te_g);
391 glist_noselect(gl);
392 glist_select(gl, &x->m_text.te_g);
393 gobj_activate(&x->m_text.te_g, gl, 1);
394 canvas_startmotion(glist_getcanvas(gl));
395 }
396}
397
398/* ---------------------- the "atom" text item ------------------------ */
399
400#define ATOMBUFSIZE 40
401#define ATOM_LABELLEFT 0
402#define ATOM_LABELRIGHT 1
403#define ATOM_LABELUP 2
404#define ATOM_LABELDOWN 3
405
406typedef struct _gatom
407{
408 t_text a_text;
409 t_atom a_atom; /* this holds the value and the type */
410 t_glist *a_glist; /* owning glist */
411 t_float a_toggle; /* value to toggle to */
412 t_float a_draghi; /* high end of drag range */
413 t_float a_draglo; /* low end of drag range */
414 t_symbol *a_label; /* symbol to show as label next to box */
415 t_symbol *a_symfrom; /* "receive" name -- bind ourselvs to this */
416 t_symbol *a_symto; /* "send" name -- send to this on output */
417 char a_buf[ATOMBUFSIZE];/* string buffer for typing */
418 char a_shift; /* was shift key down when dragging started? */
419 char a_wherelabel; /* 0-3 for left, right, above, below */
420 t_symbol *a_expanded_to; /* a_symto after $0, $1, ... expansion */
421} t_gatom;
422
423 /* prepend "-" as necessary to avoid empty strings, so we can
424 use them in Pd messages. A more complete solution would be
425 to introduce some quoting mechanism; but then we'd be much more
426 complicated. */
427static t_symbol *gatom_escapit(t_symbol *s)
428{
429 if (!*s->s_name)
430 return (gensym("-"));
431 else if (*s->s_name == '-')
432 {
433 char shmo[100];
434 shmo[0] = '-';
435 strncpy(shmo+1, s->s_name, 99);
436 shmo[99] = 0;
437 return (gensym(shmo));
438 }
439 else return (iemgui_dollar2raute(s));
440}
441
442 /* undo previous operation: strip leading "-" if found. */
443static t_symbol *gatom_unescapit(t_symbol *s)
444{
445 if (*s->s_name == '-')
446 return (gensym(s->s_name+1));
447 else return (iemgui_raute2dollar(s));
448}
449
450#if 0 /* ??? */
451 /* expand leading $0, $1, etc. in the symbol */
452static t_symbol *gatom_realizedollar(t_gatom *x, t_symbol *s)
453{
454 return (canvas_realizedollar(x->a_glist, s));
455}
456#endif
457
458static void gatom_retext(t_gatom *x, int senditup)
459{
460 binbuf_clear(x->a_text.te_binbuf);
461 binbuf_add(x->a_text.te_binbuf, 1, &x->a_atom);
462 if (senditup)
463 glist_retext(x->a_glist, &x->a_text);
464}
465
466static void gatom_set(t_gatom *x, t_symbol *s, int argc, t_atom *argv)
467{
468 t_atom oldatom = x->a_atom;
469 int senditup = 0;
470 if (!argc) return;
471 if (x->a_atom.a_type == A_FLOAT)
472 x->a_atom.a_w.w_float = atom_getfloat(argv),
473 senditup = (x->a_atom.a_w.w_float != oldatom.a_w.w_float);
474 else if (x->a_atom.a_type == A_SYMBOL)
475 x->a_atom.a_w.w_symbol = atom_getsymbol(argv),
476 senditup = (x->a_atom.a_w.w_symbol != oldatom.a_w.w_symbol);
477 gatom_retext(x, senditup);
478 x->a_buf[0] = 0;
479}
480
481static void gatom_bang(t_gatom *x)
482{
483 if (x->a_atom.a_type == A_FLOAT)
484 {
485 if (x->a_text.te_outlet)
486 outlet_float(x->a_text.te_outlet, x->a_atom.a_w.w_float);
487 if (*x->a_expanded_to->s_name && x->a_expanded_to->s_thing)
488 {
489 if (x->a_symto == x->a_symfrom)
490 pd_error(x,
491 "%s: atom with same send/receive name (infinite loop)",
492 x->a_symto->s_name);
493 else pd_float(x->a_expanded_to->s_thing, x->a_atom.a_w.w_float);
494 }
495 }
496 else if (x->a_atom.a_type == A_SYMBOL)
497 {
498 if (x->a_text.te_outlet)
499 outlet_symbol(x->a_text.te_outlet, x->a_atom.a_w.w_symbol);
500 if (*x->a_symto->s_name && x->a_expanded_to->s_thing)
501 {
502 if (x->a_symto == x->a_symfrom)
503 pd_error(x,
504 "%s: atom with same send/receive name (infinite loop)",
505 x->a_symto->s_name);
506 else pd_symbol(x->a_expanded_to->s_thing, x->a_atom.a_w.w_symbol);
507 }
508 }
509}
510
511static void gatom_float(t_gatom *x, t_float f)
512{
513 t_atom at;
514 SETFLOAT(&at, f);
515 gatom_set(x, 0, 1, &at);
516 gatom_bang(x);
517}
518
519static void gatom_clipfloat(t_gatom *x, t_float f)
520{
521 if (x->a_draglo != 0 || x->a_draghi != 0)
522 {
523 if (f < x->a_draglo)
524 f = x->a_draglo;
525 if (f > x->a_draghi)
526 f = x->a_draghi;
527 }
528 gatom_float(x, f);
529}
530
531static void gatom_symbol(t_gatom *x, t_symbol *s)
532{
533 t_atom at;
534 SETSYMBOL(&at, s);
535 gatom_set(x, 0, 1, &at);
536 gatom_bang(x);
537}
538
539static void gatom_motion(void *z, t_floatarg dx, t_floatarg dy)
540{
541 t_gatom *x = (t_gatom *)z;
542 if (dy == 0) return;
543 if (x->a_atom.a_type == A_FLOAT)
544 {
545 if (x->a_shift)
546 {
547 double nval = x->a_atom.a_w.w_float - 0.01 * dy;
548 double trunc = 0.01 * (floor(100. * nval + 0.5));
549 if (trunc < nval + 0.0001 && trunc > nval - 0.0001) nval = trunc;
550 gatom_clipfloat(x, nval);
551 }
552 else
553 {
554 double nval = x->a_atom.a_w.w_float - dy;
555 double trunc = 0.01 * (floor(100. * nval + 0.5));
556 if (trunc < nval + 0.0001 && trunc > nval - 0.0001) nval = trunc;
557 trunc = floor(nval + 0.5);
558 if (trunc < nval + 0.001 && trunc > nval - 0.001) nval = trunc;
559 gatom_clipfloat(x, nval);
560 }
561 }
562}
563
564static void gatom_key(void *z, t_floatarg f)
565{
566 t_gatom *x = (t_gatom *)z;
567 int c = f;
568 int len = strlen(x->a_buf);
569 t_atom at;
570 char sbuf[ATOMBUFSIZE + 4];
571 if (c == 0)
572 {
573 /* we're being notified that no more keys will come for this grab */
574 if (x->a_buf[0])
575 gatom_retext(x, 1);
576 return;
577 }
578 else if (c == ' ') return;
579 else if (c == '\b')
580 {
581 if (len > 0)
582 x->a_buf[len-1] = 0;
583 goto redraw;
584 }
585 else if (c == '\n')
586 {
587 if (x->a_atom.a_type == A_FLOAT)
588 x->a_atom.a_w.w_float = atof(x->a_buf);
589 else if (x->a_atom.a_type == A_SYMBOL)
590 x->a_atom.a_w.w_symbol = gensym(x->a_buf);
591 else bug("gatom_key");
592 gatom_bang(x);
593 gatom_retext(x, 1);
594 x->a_buf[0] = 0;
595 }
596 else if (len < (ATOMBUFSIZE-1))
597 {
598 /* for numbers, only let reasonable characters through */
599 if ((x->a_atom.a_type == A_SYMBOL) ||
600 (c >= '0' && c <= '9' || c == '.' || c == '-'
601 || c == 'e' || c == 'E'))
602 {
603 x->a_buf[len] = c;
604 x->a_buf[len+1] = 0;
605 goto redraw;
606 }
607 }
608 return;
609redraw:
610 /* LATER figure out how to avoid creating all these symbols! */
611 sprintf(sbuf, "%s...", x->a_buf);
612 SETSYMBOL(&at, gensym(sbuf));
613 binbuf_clear(x->a_text.te_binbuf);
614 binbuf_add(x->a_text.te_binbuf, 1, &at);
615 glist_retext(x->a_glist, &x->a_text);
616}
617
618static void gatom_click(t_gatom *x,
619 t_floatarg xpos, t_floatarg ypos, t_floatarg shift, t_floatarg ctrl,
620 t_floatarg alt)
621{
622 if (x->a_text.te_width == 1)
623 {
624 if (x->a_atom.a_type == A_FLOAT)
625 gatom_float(x, (x->a_atom.a_w.w_float == 0));
626 }
627 else
628 {
629 if (alt)
630 {
631 if (x->a_atom.a_type != A_FLOAT) return;
632 if (x->a_atom.a_w.w_float != 0)
633 {
634 x->a_toggle = x->a_atom.a_w.w_float;
635 gatom_float(x, 0);
636 return;
637 }
638 else gatom_float(x, x->a_toggle);
639 }
640 x->a_shift = shift;
641 x->a_buf[0] = 0;
642 glist_grab(x->a_glist, &x->a_text.te_g, gatom_motion, gatom_key,
643 xpos, ypos);
644 }
645}
646
647 /* message back from dialog window */
648static void gatom_param(t_gatom *x, t_symbol *sel, int argc, t_atom *argv)
649{
650 t_float width = atom_getfloatarg(0, argc, argv);
651 t_float draglo = atom_getfloatarg(1, argc, argv);
652 t_float draghi = atom_getfloatarg(2, argc, argv);
653 t_symbol *label = gatom_unescapit(atom_getsymbolarg(3, argc, argv));
654 t_float wherelabel = atom_getfloatarg(4, argc, argv);
655 t_symbol *symfrom = gatom_unescapit(atom_getsymbolarg(5, argc, argv));
656 t_symbol *symto = gatom_unescapit(atom_getsymbolarg(6, argc, argv));
657
658 gobj_vis(&x->a_text.te_g, x->a_glist, 0);
659 if (!*symfrom->s_name && *x->a_symfrom->s_name)
660 inlet_new(&x->a_text, &x->a_text.te_pd, 0, 0);
661 else if (*symfrom->s_name && !*x->a_symfrom->s_name && x->a_text.te_inlet)
662 {
663 canvas_deletelinesforio(x->a_glist, &x->a_text,
664 x->a_text.te_inlet, 0);
665 inlet_free(x->a_text.te_inlet);
666 }
667 if (!*symto->s_name && *x->a_symto->s_name)
668 outlet_new(&x->a_text, 0);
669 else if (*symto->s_name && !*x->a_symto->s_name && x->a_text.te_outlet)
670 {
671 canvas_deletelinesforio(x->a_glist, &x->a_text,
672 0, x->a_text.te_outlet);
673 outlet_free(x->a_text.te_outlet);
674 }
675 if (draglo >= draghi)
676 draglo = draghi = 0;
677 x->a_draglo = draglo;
678 x->a_draghi = draghi;
679 if (width < 0)
680 width = 4;
681 else if (width > 80)
682 width = 80;
683 x->a_text.te_width = width;
684 x->a_wherelabel = ((int)wherelabel & 3);
685 x->a_label = label;
686 if (*x->a_symfrom->s_name)
687 pd_unbind(&x->a_text.te_pd,
688 canvas_realizedollar(x->a_glist, x->a_symfrom));
689 x->a_symfrom = symfrom;
690 if (*x->a_symfrom->s_name)
691 pd_bind(&x->a_text.te_pd,
692 canvas_realizedollar(x->a_glist, x->a_symfrom));
693 x->a_symto = symto;
694 x->a_expanded_to = canvas_realizedollar(x->a_glist, x->a_symto);
695 gobj_vis(&x->a_text.te_g, x->a_glist, 1);
696
697 /* glist_retext(x->a_glist, &x->a_text); */
698}
699
700 /* ---------------- gatom-specific widget functions --------------- */
701static void gatom_getwherelabel(t_gatom *x, t_glist *glist, int *xp, int *yp)
702{
703 int x1, y1, x2, y2, width, height;
704 text_getrect(&x->a_text.te_g, glist, &x1, &y1, &x2, &y2);
705 width = x2 - x1;
706 height = y2 - y1;
707 if (x->a_wherelabel == ATOM_LABELLEFT)
708 {
709 *xp = x1 - 3 -
710 strlen(canvas_realizedollar(x->a_glist, x->a_label)->s_name) *
711 sys_fontwidth(glist_getfont(glist));
712 *yp = y1 + 2;
713 }
714 else if (x->a_wherelabel == ATOM_LABELRIGHT)
715 {
716 *xp = x2 + 2;
717 *yp = y1 + 2;
718 }
719 else if (x->a_wherelabel == ATOM_LABELUP)
720 {
721 *xp = x1 - 1;
722 *yp = y1 - 1 - sys_fontheight(glist_getfont(glist));;
723 }
724 else
725 {
726 *xp = x1 - 1;
727 *yp = y2 + 3;
728 }
729}
730
731static void gatom_displace(t_gobj *z, t_glist *glist,
732 int dx, int dy)
733{
734 t_gatom *x = (t_gatom*)z;
735 text_displace(z, glist, dx, dy);
736 sys_vgui(".x%x.c move %x.l %d %d\n", glist_getcanvas(glist),
737 x, dx, dy);
738}
739
740static void gatom_vis(t_gobj *z, t_glist *glist, int vis)
741{
742 t_gatom *x = (t_gatom*)z;
743 text_vis(z, glist, vis);
744 if (*x->a_label->s_name)
745 {
746 if (vis)
747 {
748 int x1, y1;
749 gatom_getwherelabel(x, glist, &x1, &y1);
750 sys_vgui("pdtk_text_new .x%x.c %x.l %f %f {%s} %d %s\n",
751 glist_getcanvas(glist), x,
752 (double)x1, (double)y1,
753 canvas_realizedollar(x->a_glist, x->a_label)->s_name,
754 sys_hostfontsize(glist_getfont(glist)),
755 "black");
756 }
757 else sys_vgui(".x%x.c delete %x.l\n", glist_getcanvas(glist), x);
758 }
759}
760
761void canvas_atom(t_glist *gl, t_atomtype type,
762 t_symbol *s, int argc, t_atom *argv)
763{
764 t_gatom *x = (t_gatom *)pd_new(gatom_class);
765 t_atom at;
766 x->a_text.te_width = 0; /* don't know it yet. */
767 x->a_text.te_type = T_ATOM;
768 x->a_text.te_binbuf = binbuf_new();
769 x->a_glist = gl;
770 x->a_atom.a_type = type;
771 x->a_toggle = 1;
772 x->a_draglo = 0;
773 x->a_draghi = 0;
774 x->a_wherelabel = 0;
775 x->a_label = &s_;
776 x->a_symfrom = &s_;
777 x->a_symto = x->a_expanded_to = &s_;
778 if (type == A_FLOAT)
779 {
780 x->a_atom.a_w.w_float = 0;
781 x->a_text.te_width = 5;
782 SETFLOAT(&at, 0);
783 }
784 else
785 {
786 x->a_atom.a_w.w_symbol = &s_symbol;
787 x->a_text.te_width = 10;
788 SETSYMBOL(&at, &s_symbol);
789 }
790 binbuf_add(x->a_text.te_binbuf, 1, &at);
791 if (argc > 1)
792 /* create from file. x, y, width, low-range, high-range, flags,
793 label, receive-name, send-name */
794 {
795 x->a_text.te_xpix = atom_getfloatarg(0, argc, argv);
796 x->a_text.te_ypix = atom_getfloatarg(1, argc, argv);
797 x->a_text.te_width = atom_getintarg(2, argc, argv);
798 /* sanity check because some very old patches have trash in this
799 field... remove this in 2003 or so: */
800 if (x->a_text.te_width < 0 || x->a_text.te_width > 500)
801 x->a_text.te_width = 4;
802 x->a_draglo = atom_getfloatarg(3, argc, argv);
803 x->a_draghi = atom_getfloatarg(4, argc, argv);
804 x->a_wherelabel = (((int)atom_getfloatarg(5, argc, argv)) & 3);
805 x->a_label = gatom_unescapit(atom_getsymbolarg(6, argc, argv));
806 x->a_symfrom = gatom_unescapit(atom_getsymbolarg(7, argc, argv));
807 if (*x->a_symfrom->s_name)
808 pd_bind(&x->a_text.te_pd,
809 canvas_realizedollar(x->a_glist, x->a_symfrom));
810
811 x->a_symto = gatom_unescapit(atom_getsymbolarg(8, argc, argv));
812 x->a_expanded_to = canvas_realizedollar(x->a_glist, x->a_symto);
813 if (x->a_symto == &s_)
814 outlet_new(&x->a_text,
815 x->a_atom.a_type == A_FLOAT ? &s_float: &s_symbol);
816 if (x->a_symfrom == &s_)
817 inlet_new(&x->a_text, &x->a_text.te_pd, 0, 0);
818 glist_add(gl, &x->a_text.te_g);
819 }
820 else
821 {
822 int xpix, ypix;
823 outlet_new(&x->a_text,
824 x->a_atom.a_type == A_FLOAT ? &s_float: &s_symbol);
825 inlet_new(&x->a_text, &x->a_text.te_pd, 0, 0);
826 pd_vmess(&gl->gl_pd, gensym("editmode"), "i", 1);
827 glist_noselect(gl);
828 glist_getnextxy(gl, &xpix, &ypix);
829 x->a_text.te_xpix = xpix;
830 x->a_text.te_ypix = ypix;
831 glist_add(gl, &x->a_text.te_g);
832 glist_noselect(gl);
833 glist_select(gl, &x->a_text.te_g);
834 canvas_startmotion(glist_getcanvas(gl));
835 }
836}
837
838void canvas_floatatom(t_glist *gl, t_symbol *s, int argc, t_atom *argv)
839{
840 canvas_atom(gl, A_FLOAT, s, argc, argv);
841}
842
843void canvas_symbolatom(t_glist *gl, t_symbol *s, int argc, t_atom *argv)
844{
845 canvas_atom(gl, A_SYMBOL, s, argc, argv);
846}
847
848static void gatom_free(t_gatom *x)
849{
850 if (*x->a_symfrom->s_name)
851 pd_unbind(&x->a_text.te_pd,
852 canvas_realizedollar(x->a_glist, x->a_symfrom));
853 gfxstub_deleteforkey(x);
854}
855
856static void gatom_properties(t_gobj *z, t_glist *owner)
857{
858 t_gatom *x = (t_gatom *)z;
859 char buf[200];
860 sprintf(buf, "pdtk_gatom_dialog %%s %d %g %g %d %s %s %s\n",
861 x->a_text.te_width, x->a_draglo, x->a_draghi,
862 x->a_wherelabel, gatom_escapit(x->a_label)->s_name,
863 gatom_escapit(x->a_symfrom)->s_name,
864 gatom_escapit(x->a_symto)->s_name);
865 gfxstub_new(&x->a_text.te_pd, x, buf);
866}
867
868
869/* -------------------- widget behavior for text objects ------------ */
870
871static void text_getrect(t_gobj *z, t_glist *glist,
872 int *xp1, int *yp1, int *xp2, int *yp2)
873{
874 t_text *x = (t_text *)z;
875 int width, height, iscomment = (x->te_type == T_TEXT);
876 float x1, y1, x2, y2;
877
878 /* for number boxes, we know width and height a priori, and should
879 report them here so that graphs can get swelled to fit. */
880
881 if (x->te_type == T_ATOM && x->te_width > 0)
882 {
883 int font = glist_getfont(glist);
884 int fontwidth = sys_fontwidth(font), fontheight = sys_fontheight(font);
885 width = (x->te_width > 0 ? x->te_width : 6) * fontwidth + 2;
886 height = fontheight + 1; /* borrowed from TMARGIN, etc, in g_rtext.c */
887 }
888 /* if we're invisible we don't know our size so we just lie about
889 it. This is called on invisible boxes to establish order of inlets
890 and possibly other reasons.
891 To find out if the box is visible we can't just check the "vis"
892 flag because we might be within the vis() routine and not have set
893 that yet. So we check directly whether the "rtext" list has been
894 built. LATER reconsider when "vis" flag should be on and off? */
895
896 else if (glist->gl_editor && glist->gl_editor->e_rtext)
897 {
898 t_rtext *y = glist_findrtext(glist, x);
899 width = rtext_width(y);
900 height = rtext_height(y) - (iscomment << 1);
901 }
902 else width = height = 10;
903 x1 = text_xpix(x, glist);
904 y1 = text_ypix(x, glist);
905 x2 = x1 + width;
906 y2 = y1 + height;
907 y1 += iscomment;
908 *xp1 = x1;
909 *yp1 = y1;
910 *xp2 = x2;
911 *yp2 = y2;
912}
913
914static void text_displace(t_gobj *z, t_glist *glist,
915 int dx, int dy)
916{
917 t_text *x = (t_text *)z;
918 x->te_xpix += dx;
919 x->te_ypix += dy;
920 if (glist_isvisible(glist))
921 {
922 t_rtext *y = glist_findrtext(glist, x);
923 rtext_displace(y, dx, dy);
924 text_drawborder(x, glist, rtext_gettag(y),
925 rtext_width(y), rtext_height(y), 0);
926 canvas_fixlinesfor(glist_getcanvas(glist), x);
927 }
928}
929
930static void text_select(t_gobj *z, t_glist *glist, int state)
931{
932 t_text *x = (t_text *)z;
933 t_rtext *y = glist_findrtext(glist, x);
934 rtext_select(y, state);
935 if (glist_isvisible(glist) && text_shouldvis(x, glist))
936 sys_vgui(".x%x.c itemconfigure %sR -fill %s\n", glist,
937 rtext_gettag(y), (state? "blue" : "black"));
938}
939
940static void text_activate(t_gobj *z, t_glist *glist, int state)
941{
942 t_text *x = (t_text *)z;
943 t_rtext *y = glist_findrtext(glist, x);
944 if (z->g_pd != gatom_class) rtext_activate(y, state);
945}
946
947static void text_delete(t_gobj *z, t_glist *glist)
948{
949 t_text *x = (t_text *)z;
950 canvas_deletelinesfor(glist, x);
951}
952
953 /* return true if the text box should be drawn.
954 We don't show object boxes inside graphs. */
955int text_shouldvis(t_text *x, t_glist *glist)
956{
957 return (glist->gl_havewindow ||
958 (x->te_pd != canvas_class && x->te_pd->c_wb != &text_widgetbehavior) ||
959 (x->te_pd == canvas_class && (((t_glist *)x)->gl_isgraph)));
960}
961
962static void text_vis(t_gobj *z, t_glist *glist, int vis)
963{
964 t_text *x = (t_text *)z;
965 if (vis)
966 {
967 if (text_shouldvis(x, glist))
968 {
969 t_rtext *y = glist_findrtext(glist, x);
970 if (x->te_type == T_ATOM)
971 glist_retext(glist, x);
972 text_drawborder(x, glist, rtext_gettag(y),
973 rtext_width(y), rtext_height(y), 1);
974 rtext_draw(y);
975 }
976 }
977 else
978 {
979 t_rtext *y = glist_findrtext(glist, x);
980 if (text_shouldvis(x, glist))
981 {
982 text_eraseborder(x, glist, rtext_gettag(y));
983 rtext_erase(y);
984 }
985 }
986}
987
988static int text_click(t_gobj *z, struct _glist *glist,
989 int xpix, int ypix, int shift, int alt, int dbl, int doit)
990{
991 t_text *x = (t_text *)z;
992 if (x->te_type == T_OBJECT)
993 {
994 t_symbol *clicksym = gensym("click");
995 if (zgetfn(&x->te_pd, clicksym))
996 {
997 if (doit)
998 pd_vmess(&x->te_pd, clicksym, "fffff",
999 (double)xpix, (double)ypix,
1000 (double)shift, 0, (double)alt);
1001 return (1);
1002 }
1003 else return (0);
1004 }
1005 else if (x->te_type == T_ATOM)
1006 {
1007 if (doit)
1008 gatom_click((t_gatom *)x, (t_floatarg)xpix, (t_floatarg)ypix,
1009 (t_floatarg)shift, 0, (t_floatarg)alt);
1010 return (1);
1011 }
1012 else if (x->te_type == T_MESSAGE)
1013 {
1014 if (doit)
1015 message_click((t_message *)x, (t_floatarg)xpix, (t_floatarg)ypix,
1016 (t_floatarg)shift, 0, (t_floatarg)alt);
1017 return (1);
1018 }
1019 else return (0);
1020}
1021
1022void text_save(t_gobj *z, t_binbuf *b)
1023{
1024 t_text *x = (t_text *)z;
1025 if (x->te_type == T_OBJECT)
1026 {
1027 /* if we have a "saveto" method, and if we don't happen to be
1028 a canvas that's an abstraction, the saveto method does the work */
1029 if (zgetfn(&x->te_pd, gensym("saveto")) &&
1030 !((pd_class(&x->te_pd) == canvas_class) &&
1031 (canvas_isabstraction((t_canvas *)x)
1032 || canvas_istable((t_canvas *)x))))
1033 {
1034 mess1(&x->te_pd, gensym("saveto"), b);
1035 binbuf_addv(b, "ssii", gensym("#X"), gensym("restore"),
1036 (t_int)x->te_xpix, (t_int)x->te_ypix);
1037 }
1038 else /* otherwise just save the text */
1039 {
1040 binbuf_addv(b, "ssii", gensym("#X"), gensym("obj"),
1041 (t_int)x->te_xpix, (t_int)x->te_ypix);
1042 }
1043 binbuf_addbinbuf(b, x->te_binbuf);
1044 binbuf_addv(b, ";");
1045 }
1046 else if (x->te_type == T_MESSAGE)
1047 {
1048 binbuf_addv(b, "ssii", gensym("#X"), gensym("msg"),
1049 (t_int)x->te_xpix, (t_int)x->te_ypix);
1050 binbuf_addbinbuf(b, x->te_binbuf);
1051 binbuf_addv(b, ";");
1052 }
1053 else if (x->te_type == T_ATOM)
1054 {
1055 t_atomtype t = ((t_gatom *)x)->a_atom.a_type;
1056 t_symbol *sel = (t == A_SYMBOL ? gensym("symbolatom") :
1057 (t == A_FLOAT ? gensym("floatatom") : gensym("intatom")));
1058 t_symbol *label = gatom_escapit(((t_gatom *)x)->a_label);
1059 t_symbol *symfrom = gatom_escapit(((t_gatom *)x)->a_symfrom);
1060 t_symbol *symto = gatom_escapit(((t_gatom *)x)->a_symto);
1061 binbuf_addv(b, "ssiiifffsss", gensym("#X"), sel,
1062 (t_int)x->te_xpix, (t_int)x->te_ypix, (t_int)x->te_width,
1063 (double)((t_gatom *)x)->a_draglo,
1064 (double)((t_gatom *)x)->a_draghi,
1065 (double)((t_gatom *)x)->a_wherelabel,
1066 label, symfrom, symto);
1067 binbuf_addv(b, ";");
1068 }
1069 else
1070 {
1071 binbuf_addv(b, "ssii", gensym("#X"), gensym("text"),
1072 (t_int)x->te_xpix, (t_int)x->te_ypix);
1073 binbuf_addbinbuf(b, x->te_binbuf);
1074 binbuf_addv(b, ";");
1075 }
1076}
1077
1078 /* this one is for everyone but "gatoms"; it's imposed in m_class.c */
1079t_widgetbehavior text_widgetbehavior =
1080{
1081 text_getrect,
1082 text_displace,
1083 text_select,
1084 text_activate,
1085 text_delete,
1086 text_vis,
1087 text_click,
1088};
1089
1090static t_widgetbehavior gatom_widgetbehavior =
1091{
1092 text_getrect,
1093 gatom_displace,
1094 text_select,
1095 text_activate,
1096 text_delete,
1097 gatom_vis,
1098 text_click,
1099};
1100
1101/* -------------------- the "text" class ------------ */
1102
1103#ifdef MACOSX
1104#define EXTRAPIX 2
1105#else
1106#define EXTRAPIX 1
1107#endif
1108
1109 /* draw inlets and outlets for a text object or for a graph. */
1110void glist_drawiofor(t_glist *glist, t_object *ob, int firsttime,
1111 char *tag, int x1, int y1, int x2, int y2)
1112{
1113 int n = obj_noutlets(ob), nplus = (n == 1 ? 1 : n-1), i;
1114 int width = x2 - x1;
1115 for (i = 0; i < n; i++)
1116 {
1117 int onset = x1 + (width - IOWIDTH) * i / nplus;
1118 if (firsttime)
1119 sys_vgui(".x%x.c create rectangle %d %d %d %d -tags %so%d\n",
1120 glist_getcanvas(glist),
1121 onset, y2 - 1,
1122 onset + IOWIDTH, y2,
1123 tag, i);
1124 else
1125 sys_vgui(".x%x.c coords %so%d %d %d %d %d\n",
1126 glist_getcanvas(glist), tag, i,
1127 onset, y2 - 1,
1128 onset + IOWIDTH, y2);
1129 }
1130 n = obj_ninlets(ob);
1131 nplus = (n == 1 ? 1 : n-1);
1132 for (i = 0; i < n; i++)
1133 {
1134 int onset = x1 + (width - IOWIDTH) * i / nplus;
1135 if (firsttime)
1136 sys_vgui(".x%x.c create rectangle %d %d %d %d -tags %si%d\n",
1137 glist_getcanvas(glist),
1138 onset, y1,
1139 onset + IOWIDTH, y1 + EXTRAPIX,
1140 tag, i);
1141 else
1142 sys_vgui(".x%x.c coords %si%d %d %d %d %d\n",
1143 glist_getcanvas(glist), tag, i,
1144 onset, y1,
1145 onset + IOWIDTH, y1 + EXTRAPIX);
1146 }
1147}
1148
1149void text_drawborder(t_text *x, t_glist *glist,
1150 char *tag, int width2, int height2, int firsttime)
1151{
1152 t_object *ob;
1153 int x1, y1, x2, y2, width, height;
1154 text_getrect(&x->te_g, glist, &x1, &y1, &x2, &y2);
1155 width = x2 - x1;
1156 height = y2 - y1;
1157 if (x->te_type == T_OBJECT)
1158 {
1159 if (firsttime)
1160 sys_vgui(".x%x.c create line\
1161 %d %d %d %d %d %d %d %d %d %d -tags %sR\n",
1162 glist_getcanvas(glist),
1163 x1, y1, x2, y1, x2, y2, x1, y2, x1, y1, tag);
1164 else
1165 sys_vgui(".x%x.c coords %sR\
1166 %d %d %d %d %d %d %d %d %d %d\n",
1167 glist_getcanvas(glist), tag,
1168 x1, y1, x2, y1, x2, y2, x1, y2, x1, y1);
1169 }
1170 else if (x->te_type == T_MESSAGE)
1171 {
1172 if (firsttime)
1173 sys_vgui(".x%x.c create line\
1174 %d %d %d %d %d %d %d %d %d %d %d %d %d %d -tags %sR\n",
1175 glist_getcanvas(glist),
1176 x1, y1, x2+4, y1, x2, y1+4, x2, y2-4, x2+4, y2,
1177 x1, y2, x1, y1,
1178 tag);
1179 else
1180 sys_vgui(".x%x.c coords %sR\
1181 %d %d %d %d %d %d %d %d %d %d %d %d %d %d\n",
1182 glist_getcanvas(glist), tag,
1183 x1, y1, x2+4, y1, x2, y1+4, x2, y2-4, x2+4, y2,
1184 x1, y2, x1, y1);
1185 }
1186 else if (x->te_type == T_ATOM)
1187 {
1188 if (firsttime)
1189 sys_vgui(".x%x.c create line\
1190 %d %d %d %d %d %d %d %d %d %d %d %d -tags %sR\n",
1191 glist_getcanvas(glist),
1192 x1, y1, x2-4, y1, x2, y1+4, x2, y2, x1, y2, x1, y1,
1193 tag);
1194 else
1195 sys_vgui(".x%x.c coords %sR\
1196 %d %d %d %d %d %d %d %d %d %d %d %d\n",
1197 glist_getcanvas(glist), tag,
1198 x1, y1, x2-4, y1, x2, y1+4, x2, y2, x1, y2, x1, y1);
1199 }
1200 /* draw inlets/outlets */
1201
1202 if (ob = pd_checkobject(&x->te_pd))
1203 glist_drawiofor(glist, ob, firsttime, tag, x1, y1, x2, y2);
1204}
1205
1206void glist_eraseiofor(t_glist *glist, t_object *ob, char *tag)
1207{
1208 int i, n;
1209 n = obj_noutlets(ob);
1210 for (i = 0; i < n; i++)
1211 sys_vgui(".x%x.c delete %so%d\n",
1212 glist_getcanvas(glist), tag, i);
1213 n = obj_ninlets(ob);
1214 for (i = 0; i < n; i++)
1215 sys_vgui(".x%x.c delete %si%d\n",
1216 glist_getcanvas(glist), tag, i);
1217}
1218
1219void text_eraseborder(t_text *x, t_glist *glist, char *tag)
1220{
1221 if (x->te_type == T_TEXT) return;
1222 sys_vgui(".x%x.c delete %sR\n",
1223 glist_getcanvas(glist), tag);
1224 glist_eraseiofor(glist, x, tag);
1225}
1226
1227 /* change text; if T_OBJECT, remake it. LATER we'll have an undo buffer
1228 which should be filled in here before making the change. */
1229
1230void text_setto(t_text *x, t_glist *glist, char *buf, int bufsize)
1231{
1232 if (x->te_type == T_OBJECT)
1233 {
1234 t_binbuf *b = binbuf_new();
1235 int natom1, natom2;
1236 t_atom *vec1, *vec2;
1237 binbuf_text(b, buf, bufsize);
1238 natom1 = binbuf_getnatom(x->te_binbuf);
1239 vec1 = binbuf_getvec(x->te_binbuf);
1240 natom2 = binbuf_getnatom(b);
1241 vec2 = binbuf_getvec(b);
1242 /* special case: if pd args change just pass the message on. */
1243 if (natom1 >= 1 && natom2 >= 1 && vec1[0].a_type == A_SYMBOL
1244 && !strcmp(vec1[0].a_w.w_symbol->s_name, "pd") &&
1245 vec2[0].a_type == A_SYMBOL
1246 && !strcmp(vec2[0].a_w.w_symbol->s_name, "pd"))
1247 {
1248 typedmess(&x->te_pd, gensym("rename"), natom2-1, vec2+1);
1249 binbuf_free(x->te_binbuf);
1250 x->te_binbuf = b;
1251 }
1252 else /* normally, just destroy the old one and make a new one. */
1253 {
1254 int xwas = x->te_xpix, ywas = x->te_ypix;
1255 glist_delete(glist, &x->te_g);
1256 canvas_objtext(glist, xwas, ywas, 0, b);
1257 /* if it's an abstraction loadbang it here */
1258 if (newest && pd_class(newest) == canvas_class)
1259 canvas_loadbang((t_canvas *)newest);
1260 canvas_restoreconnections(glist_getcanvas(glist));
1261 }
1262 /* if we made a new "pd" or changed a window name,
1263 update window list */
1264 if (natom2 >= 1 && vec2[0].a_type == A_SYMBOL
1265 && !strcmp(vec2[0].a_w.w_symbol->s_name, "pd"))
1266 canvas_updatewindowlist();
1267 }
1268 else binbuf_text(x->te_binbuf, buf, bufsize);
1269}
1270
1271void g_text_setup(void)
1272{
1273 text_class = class_new(gensym("text"), 0, 0, sizeof(t_text),
1274 CLASS_NOINLET | CLASS_PATCHABLE, 0);
1275
1276 message_class = class_new(gensym("message"), 0, (t_method)message_free,
1277 sizeof(t_message), CLASS_PATCHABLE, 0);
1278 class_addbang(message_class, message_bang);
1279 class_addfloat(message_class, message_float);
1280 class_addsymbol(message_class, message_symbol);
1281 class_addlist(message_class, message_list);
1282 class_addanything(message_class, message_list);
1283
1284 class_addmethod(message_class, (t_method)message_click, gensym("click"),
1285 A_FLOAT, A_FLOAT, A_FLOAT, A_FLOAT, A_FLOAT, 0);
1286 class_addmethod(message_class, (t_method)message_set, gensym("set"),
1287 A_GIMME, 0);
1288 class_addmethod(message_class, (t_method)message_add, gensym("add"),
1289 A_GIMME, 0);
1290 class_addmethod(message_class, (t_method)message_add2, gensym("add2"),
1291 A_GIMME, 0);
1292
1293 messresponder_class = class_new(gensym("messresponder"), 0, 0,
1294 sizeof(t_text), CLASS_PD, 0);
1295 class_addbang(messresponder_class, messresponder_bang);
1296 class_addfloat(messresponder_class, (t_method) messresponder_float);
1297 class_addsymbol(messresponder_class, messresponder_symbol);
1298 class_addlist(messresponder_class, messresponder_list);
1299 class_addanything(messresponder_class, messresponder_anything);
1300
1301 gatom_class = class_new(gensym("gatom"), 0, (t_method)gatom_free,
1302 sizeof(t_gatom), CLASS_NOINLET | CLASS_PATCHABLE, 0);
1303 class_addbang(gatom_class, gatom_bang);
1304 class_addfloat(gatom_class, gatom_float);
1305 class_addsymbol(gatom_class, gatom_symbol);
1306 class_addmethod(gatom_class, (t_method)gatom_set, gensym("set"),
1307 A_GIMME, 0);
1308 class_addmethod(gatom_class, (t_method)gatom_click, gensym("click"),
1309 A_FLOAT, A_FLOAT, A_FLOAT, A_FLOAT, A_FLOAT, 0);
1310 class_addmethod(gatom_class, (t_method)gatom_param, gensym("param"),
1311 A_GIMME, 0);
1312 class_setwidget(gatom_class, &gatom_widgetbehavior);
1313 class_setpropertiesfn(gatom_class, gatom_properties);
1314}
1315
1316
1317/* Copyright (c) 1997-1999 Miller Puckette.
1318* For information on usage and redistribution, and for a DISCLAIMER OF ALL
1319* WARRANTIES, see the file, "LICENSE.txt," in this distribution. */
1320
1321/* changes by Thomas Musil IEM KUG Graz Austria 2001 */
1322/* the methods for calling the gui-objects from menu are implemented */
1323/* all changes are labeled with iemlib */
1324
1325#include <stdlib.h>
1326#include "m_pd.h"
1327#include "m_imp.h"
1328#include "s_stuff.h"
1329#include "t_tk.h"
1330#include "g_canvas.h"
1331#include <stdio.h>
1332#include <string.h>
1333#include <math.h>
1334
1335static t_class *text_class;
1336static t_class *message_class;
1337static t_class *gatom_class;
1338static void text_vis(t_gobj *z, t_glist *glist, int vis);
1339static void text_displace(t_gobj *z, t_glist *glist,
1340 int dx, int dy);
1341static void text_getrect(t_gobj *z, t_glist *glist,
1342 int *xp1, int *yp1, int *xp2, int *yp2);
1343
1344void canvas_startmotion(t_canvas *x);
1345t_widgetbehavior text_widgetbehavior;
1346
1347/* ----------------- the "text" object. ------------------ */
1348
1349 /* add a "text" object (comment) to a glist. While this one goes for any glist,
1350 the other 3 below are for canvases only. (why?) This is called
1351 without args if invoked from the GUI; otherwise at least x and y
1352 are provided. */
1353
1354void glist_text(t_glist *gl, t_symbol *s, int argc, t_atom *argv)
1355{
1356 t_text *x = (t_text *)pd_new(text_class);
1357 t_atom at;
1358 x->te_width = 0; /* don't know it yet. */
1359 x->te_type = T_TEXT;
1360 x->te_binbuf = binbuf_new();
1361 if (argc > 1)
1362 {
1363 x->te_xpix = atom_getfloatarg(0, argc, argv);
1364 x->te_ypix = atom_getfloatarg(1, argc, argv);
1365 if (argc > 2) binbuf_restore(x->te_binbuf, argc-2, argv+2);
1366 else
1367 {
1368 SETSYMBOL(&at, gensym("comment"));
1369 binbuf_restore(x->te_binbuf, 1, &at);
1370 }
1371 glist_add(gl, &x->te_g);
1372 }
1373 else
1374 {
1375 int xpix, ypix;
1376 pd_vmess((t_pd *)glist_getcanvas(gl), gensym("editmode"), "i", 1);
1377 SETSYMBOL(&at, gensym("comment"));
1378 glist_noselect(gl);
1379 glist_getnextxy(gl, &xpix, &ypix);
1380 x->te_xpix = glist_pixelstox(gl, xpix-3);
1381 x->te_ypix = glist_pixelstoy(gl, ypix-3);
1382 binbuf_restore(x->te_binbuf, 1, &at);
1383 glist_add(gl, &x->te_g);
1384 glist_noselect(gl);
1385 glist_select(gl, &x->te_g);
1386 /* it would be nice to "activate" here, but then the second,
1387 "put-me-down" click changes the text selection, which is quite
1388 irritating, so I took this back out. It's OK in messages
1389 and objects though since there's no text in them at menu
1390 creation. */
1391 /* gobj_activate(&x->te_g, gl, 1); */
1392 canvas_startmotion(glist_getcanvas(gl));
1393 }
1394}
1395
1396/* ----------------- the "object" object. ------------------ */
1397
1398extern t_pd *newest;
1399void canvas_getargs(int *argcp, t_atom **argvp);
1400
1401static void canvas_objtext(t_glist *gl, int xpix, int ypix, int selected,
1402 t_binbuf *b)
1403{
1404 t_text *x;
1405 int argc;
1406 t_atom *argv;
1407 newest = 0;
1408 canvas_setcurrent((t_canvas *)gl);
1409 canvas_getargs(&argc, &argv);
1410 binbuf_eval(b, &pd_objectmaker, argc, argv);
1411 if (binbuf_getnatom(b))
1412 {
1413 if (!newest)
1414 {
1415 binbuf_print(b);
1416 post("... couldn't create");
1417 x = 0;
1418 }
1419 else if (!(x = pd_checkobject(newest)))
1420 {
1421 binbuf_print(b);
1422 post("... didn't return a patchable object");
1423 }
1424 }
1425 else x = 0;
1426 if (!x)
1427 {
1428
1429 /* LATER make the color reflect this */
1430 x = (t_text *)pd_new(text_class);
1431 }
1432 x->te_binbuf = b;
1433 x->te_xpix = xpix;
1434 x->te_ypix = ypix;
1435 x->te_width = 0;
1436 x->te_type = T_OBJECT;
1437 glist_add(gl, &x->te_g);
1438 if (selected)
1439 {
1440 /* this is called if we've been created from the menu. */
1441 glist_select(gl, &x->te_g);
1442 gobj_activate(&x->te_g, gl, 1);
1443 }
1444 if (pd_class(&x->ob_pd) == vinlet_class)
1445 canvas_resortinlets(glist_getcanvas(gl));
1446 if (pd_class(&x->ob_pd) == voutlet_class)
1447 canvas_resortoutlets(glist_getcanvas(gl));
1448 canvas_unsetcurrent((t_canvas *)gl);
1449}
1450
1451 /* object creation routine. These are called without any arguments if
1452 they're invoked from the
1453 gui; when pasting or restoring from a file, we get at least x and y. */
1454
1455void canvas_obj(t_glist *gl, t_symbol *s, int argc, t_atom *argv)
1456{
1457 t_text *x;
1458 if (argc >= 2)
1459 {
1460 t_binbuf *b = binbuf_new();
1461 binbuf_restore(b, argc-2, argv+2);
1462 canvas_objtext(gl, atom_getintarg(0, argc, argv),
1463 atom_getintarg(1, argc, argv), 0, b);
1464 }
1465 else
1466 {
1467 t_binbuf *b = binbuf_new();
1468 int xpix, ypix;
1469 pd_vmess(&gl->gl_pd, gensym("editmode"), "i", 1);
1470 glist_noselect(gl);
1471 glist_getnextxy(gl, &xpix, &ypix);
1472 canvas_objtext(gl, xpix, ypix, 1, b);
1473 canvas_startmotion(glist_getcanvas(gl));
1474 }
1475}
1476
1477/* make an object box for an object that's already there. */
1478
1479/* iemlib */
1480void canvas_iemguis(t_glist *gl, t_symbol *guiobjname)
1481{
1482 t_atom at;
1483 t_binbuf *b = binbuf_new();
1484 int xpix, ypix;
1485
1486 pd_vmess(&gl->gl_pd, gensym("editmode"), "i", 1);
1487 glist_noselect(gl);
1488 SETSYMBOL(&at, guiobjname);
1489 binbuf_restore(b, 1, &at);
1490 glist_getnextxy(gl, &xpix, &ypix);
1491 canvas_objtext(gl, xpix, ypix, 1, b);
1492 canvas_startmotion(glist_getcanvas(gl));
1493}
1494
1495void canvas_bng(t_glist *gl, t_symbol *s, int argc, t_atom *argv)
1496{
1497 canvas_iemguis(gl, gensym("bng"));
1498}
1499
1500void canvas_toggle(t_glist *gl, t_symbol *s, int argc, t_atom *argv)
1501{
1502 canvas_iemguis(gl, gensym("tgl"));
1503}
1504
1505void canvas_vslider(t_glist *gl, t_symbol *s, int argc, t_atom *argv)
1506{
1507 canvas_iemguis(gl, gensym("vsl"));
1508}
1509
1510void canvas_hslider(t_glist *gl, t_symbol *s, int argc, t_atom *argv)
1511{
1512 canvas_iemguis(gl, gensym("hsl"));
1513}
1514
1515void canvas_hdial(t_glist *gl, t_symbol *s, int argc, t_atom *argv)
1516{
1517 canvas_iemguis(gl, gensym("hdl"));
1518}
1519
1520void canvas_vdial(t_glist *gl, t_symbol *s, int argc, t_atom *argv)
1521{
1522 canvas_iemguis(gl, gensym("vdl"));
1523}
1524
1525void canvas_hradio(t_glist *gl, t_symbol *s, int argc, t_atom *argv)
1526{
1527 canvas_iemguis(gl, gensym("hradio"));
1528}
1529
1530void canvas_vradio(t_glist *gl, t_symbol *s, int argc, t_atom *argv)
1531{
1532 canvas_iemguis(gl, gensym("vradio"));
1533}
1534
1535void canvas_vumeter(t_glist *gl, t_symbol *s, int argc, t_atom *argv)
1536{
1537 canvas_iemguis(gl, gensym("vu"));
1538}
1539
1540void canvas_mycnv(t_glist *gl, t_symbol *s, int argc, t_atom *argv)
1541{
1542 canvas_iemguis(gl, gensym("cnv"));
1543}
1544
1545void canvas_numbox(t_glist *gl, t_symbol *s, int argc, t_atom *argv)
1546{
1547 canvas_iemguis(gl, gensym("nbx"));
1548}
1549
1550/* iemlib */
1551
1552void canvas_objfor(t_glist *gl, t_text *x, int argc, t_atom *argv)
1553{
1554 x->te_width = 0; /* don't know it yet. */
1555 x->te_type = T_OBJECT;
1556 x->te_binbuf = binbuf_new();
1557 x->te_xpix = atom_getfloatarg(0, argc, argv);
1558 x->te_ypix = atom_getfloatarg(1, argc, argv);
1559 if (argc > 2) binbuf_restore(x->te_binbuf, argc-2, argv+2);
1560 glist_add(gl, &x->te_g);
1561}
1562
1563/* ---------------------- the "message" text item ------------------------ */
1564
1565typedef struct _messresponder
1566{
1567 t_pd mr_pd;
1568 t_outlet *mr_outlet;
1569} t_messresponder;
1570
1571typedef struct _message
1572{
1573 t_text m_text;
1574 t_messresponder m_messresponder;
1575 t_glist *m_glist;
1576 t_clock *m_clock;
1577} t_message;
1578
1579static t_class *message_class, *messresponder_class;
1580
1581static void messresponder_bang(t_messresponder *x)
1582{
1583 outlet_bang(x->mr_outlet);
1584}
1585
1586static void messresponder_float(t_messresponder *x, t_float f)
1587{
1588 outlet_float(x->mr_outlet, f);
1589}
1590
1591static void messresponder_symbol(t_messresponder *x, t_symbol *s)
1592{
1593 outlet_symbol(x->mr_outlet, s);
1594}
1595
1596static void messresponder_list(t_messresponder *x,
1597 t_symbol *s, int argc, t_atom *argv)
1598{
1599 outlet_list(x->mr_outlet, s, argc, argv);
1600}
1601
1602static void messresponder_anything(t_messresponder *x,
1603 t_symbol *s, int argc, t_atom *argv)
1604{
1605 outlet_anything(x->mr_outlet, s, argc, argv);
1606}
1607
1608static void message_bang(t_message *x)
1609{
1610 binbuf_eval(x->m_text.te_binbuf, &x->m_messresponder.mr_pd, 0, 0);
1611}
1612
1613static void message_float(t_message *x, t_float f)
1614{
1615 t_atom at;
1616 SETFLOAT(&at, f);
1617 binbuf_eval(x->m_text.te_binbuf, &x->m_messresponder.mr_pd, 1, &at);
1618}
1619
1620static void message_symbol(t_message *x, t_symbol *s)
1621{
1622 t_atom at;
1623 SETSYMBOL(&at, s);
1624 binbuf_eval(x->m_text.te_binbuf, &x->m_messresponder.mr_pd, 1, &at);
1625}
1626
1627static void message_list(t_message *x, t_symbol *s, int argc, t_atom *argv)
1628{
1629 binbuf_eval(x->m_text.te_binbuf, &x->m_messresponder.mr_pd, argc, argv);
1630}
1631
1632static void message_set(t_message *x, t_symbol *s, int argc, t_atom *argv)
1633{
1634 binbuf_clear(x->m_text.te_binbuf);
1635 binbuf_add(x->m_text.te_binbuf, argc, argv);
1636 glist_retext(x->m_glist, &x->m_text);
1637}
1638
1639static void message_add2(t_message *x, t_symbol *s, int argc, t_atom *argv)
1640{
1641 binbuf_add(x->m_text.te_binbuf, argc, argv);
1642 glist_retext(x->m_glist, &x->m_text);
1643}
1644
1645static void message_add(t_message *x, t_symbol *s, int argc, t_atom *argv)
1646{
1647 binbuf_add(x->m_text.te_binbuf, argc, argv);
1648 binbuf_addsemi(x->m_text.te_binbuf);
1649 glist_retext(x->m_glist, &x->m_text);
1650}
1651
1652static void message_click(t_message *x,
1653 t_floatarg xpos, t_floatarg ypos, t_floatarg shift,
1654 t_floatarg ctrl, t_floatarg alt)
1655{
1656 message_float(x, 0);
1657 if (glist_isvisible(x->m_glist))
1658 {
1659 t_rtext *y = glist_findrtext(x->m_glist, &x->m_text);
1660 sys_vgui(".x%x.c itemconfigure %sR -width 5\n",
1661 glist_getcanvas(x->m_glist), rtext_gettag(y));
1662 clock_delay(x->m_clock, 120);
1663 }
1664}
1665
1666static void message_tick(t_message *x)
1667{
1668 if (glist_isvisible(x->m_glist))
1669 {
1670 t_rtext *y = glist_findrtext(x->m_glist, &x->m_text);
1671 sys_vgui(".x%x.c itemconfigure %sR -width 1\n",
1672 glist_getcanvas(x->m_glist), rtext_gettag(y));
1673 }
1674}
1675
1676static void message_free(t_message *x)
1677{
1678 clock_free(x->m_clock);
1679}
1680
1681void canvas_msg(t_glist *gl, t_symbol *s, int argc, t_atom *argv)
1682{
1683 t_message *x = (t_message *)pd_new(message_class);
1684 x->m_messresponder.mr_pd = messresponder_class;
1685 x->m_messresponder.mr_outlet = outlet_new(&x->m_text, &s_float);
1686 x->m_text.te_width = 0; /* don't know it yet. */
1687 x->m_text.te_type = T_MESSAGE;
1688 x->m_text.te_binbuf = binbuf_new();
1689 x->m_glist = gl;
1690 x->m_clock = clock_new(x, (t_method)message_tick);
1691 if (argc > 1)
1692 {
1693 x->m_text.te_xpix = atom_getfloatarg(0, argc, argv);
1694 x->m_text.te_ypix = atom_getfloatarg(1, argc, argv);
1695 if (argc > 2) binbuf_restore(x->m_text.te_binbuf, argc-2, argv+2);
1696 glist_add(gl, &x->m_text.te_g);
1697 }
1698 else
1699 {
1700 int xpix, ypix;
1701 pd_vmess(&gl->gl_pd, gensym("editmode"), "i", 1);
1702 glist_noselect(gl);
1703 glist_getnextxy(gl, &xpix, &ypix);
1704 x->m_text.te_xpix = xpix-3;
1705 x->m_text.te_ypix = ypix-3;
1706 glist_add(gl, &x->m_text.te_g);
1707 glist_noselect(gl);
1708 glist_select(gl, &x->m_text.te_g);
1709 gobj_activate(&x->m_text.te_g, gl, 1);
1710 canvas_startmotion(glist_getcanvas(gl));
1711 }
1712}
1713
1714/* ---------------------- the "atom" text item ------------------------ */
1715
1716#define ATOMBUFSIZE 40
1717#define ATOM_LABELLEFT 0
1718#define ATOM_LABELRIGHT 1
1719#define ATOM_LABELUP 2
1720#define ATOM_LABELDOWN 3
1721
1722typedef struct _gatom
1723{
1724 t_text a_text;
1725 t_atom a_atom; /* this holds the value and the type */
1726 t_glist *a_glist; /* owning glist */
1727 t_float a_toggle; /* value to toggle to */
1728 t_float a_draghi; /* high end of drag range */
1729 t_float a_draglo; /* low end of drag range */
1730 t_symbol *a_label; /* symbol to show as label next to box */
1731 t_symbol *a_symfrom; /* "receive" name -- bind ourselvs to this */
1732 t_symbol *a_symto; /* "send" name -- send to this on output */
1733 char a_buf[ATOMBUFSIZE];/* string buffer for typing */
1734 char a_shift; /* was shift key down when dragging started? */
1735 char a_wherelabel; /* 0-3 for left, right, above, below */
1736 t_symbol *a_expanded_to; /* a_symto after $0, $1, ... expansion */
1737} t_gatom;
1738
1739 /* prepend "-" as necessary to avoid empty strings, so we can
1740 use them in Pd messages. A more complete solution would be
1741 to introduce some quoting mechanism; but then we'd be much more
1742 complicated. */
1743static t_symbol *gatom_escapit(t_symbol *s)
1744{
1745 if (!*s->s_name)
1746 return (gensym("-"));
1747 else if (*s->s_name == '-')
1748 {
1749 char shmo[100];
1750 shmo[0] = '-';
1751 strncpy(shmo+1, s->s_name, 99);
1752 shmo[99] = 0;
1753 return (gensym(shmo));
1754 }
1755 else return (iemgui_dollar2raute(s));
1756}
1757
1758 /* undo previous operation: strip leading "-" if found. */
1759static t_symbol *gatom_unescapit(t_symbol *s)
1760{
1761 if (*s->s_name == '-')
1762 return (gensym(s->s_name+1));
1763 else return (iemgui_raute2dollar(s));
1764}
1765
1766#if 0 /* ??? */
1767 /* expand leading $0, $1, etc. in the symbol */
1768static t_symbol *gatom_realizedollar(t_gatom *x, t_symbol *s)
1769{
1770 return (canvas_realizedollar(x->a_glist, s));
1771}
1772#endif
1773
1774static void gatom_retext(t_gatom *x, int senditup)
1775{
1776 binbuf_clear(x->a_text.te_binbuf);
1777 binbuf_add(x->a_text.te_binbuf, 1, &x->a_atom);
1778 if (senditup)
1779 glist_retext(x->a_glist, &x->a_text);
1780}
1781
1782static void gatom_set(t_gatom *x, t_symbol *s, int argc, t_atom *argv)
1783{
1784 t_atom oldatom = x->a_atom;
1785 int senditup = 0;
1786 if (!argc) return;
1787 if (x->a_atom.a_type == A_FLOAT)
1788 x->a_atom.a_w.w_float = atom_getfloat(argv),
1789 senditup = (x->a_atom.a_w.w_float != oldatom.a_w.w_float);
1790 else if (x->a_atom.a_type == A_SYMBOL)
1791 x->a_atom.a_w.w_symbol = atom_getsymbol(argv),
1792 senditup = (x->a_atom.a_w.w_symbol != oldatom.a_w.w_symbol);
1793 gatom_retext(x, senditup);
1794 x->a_buf[0] = 0;
1795}
1796
1797static void gatom_bang(t_gatom *x)
1798{
1799 if (x->a_atom.a_type == A_FLOAT)
1800 {
1801 if (x->a_text.te_outlet)
1802 outlet_float(x->a_text.te_outlet, x->a_atom.a_w.w_float);
1803 if (*x->a_expanded_to->s_name && x->a_expanded_to->s_thing)
1804 {
1805 if (x->a_symto == x->a_symfrom)
1806 pd_error(x,
1807 "%s: atom with same send/receive name (infinite loop)",
1808 x->a_symto->s_name);
1809 else pd_float(x->a_expanded_to->s_thing, x->a_atom.a_w.w_float);
1810 }
1811 }
1812 else if (x->a_atom.a_type == A_SYMBOL)
1813 {
1814 if (x->a_text.te_outlet)
1815 outlet_symbol(x->a_text.te_outlet, x->a_atom.a_w.w_symbol);
1816 if (*x->a_symto->s_name && x->a_expanded_to->s_thing)
1817 {
1818 if (x->a_symto == x->a_symfrom)
1819 pd_error(x,
1820 "%s: atom with same send/receive name (infinite loop)",
1821 x->a_symto->s_name);
1822 else pd_symbol(x->a_expanded_to->s_thing, x->a_atom.a_w.w_symbol);
1823 }
1824 }
1825}
1826
1827static void gatom_float(t_gatom *x, t_float f)
1828{
1829 t_atom at;
1830 SETFLOAT(&at, f);
1831 gatom_set(x, 0, 1, &at);
1832 gatom_bang(x);
1833}
1834
1835static void gatom_clipfloat(t_gatom *x, t_float f)
1836{
1837 if (x->a_draglo != 0 || x->a_draghi != 0)
1838 {
1839 if (f < x->a_draglo)
1840 f = x->a_draglo;
1841 if (f > x->a_draghi)
1842 f = x->a_draghi;
1843 }
1844 gatom_float(x, f);
1845}
1846
1847static void gatom_symbol(t_gatom *x, t_symbol *s)
1848{
1849 t_atom at;
1850 SETSYMBOL(&at, s);
1851 gatom_set(x, 0, 1, &at);
1852 gatom_bang(x);
1853}
1854
1855static void gatom_motion(void *z, t_floatarg dx, t_floatarg dy)
1856{
1857 t_gatom *x = (t_gatom *)z;
1858 if (dy == 0) return;
1859 if (x->a_atom.a_type == A_FLOAT)
1860 {
1861 if (x->a_shift)
1862 {
1863 double nval = x->a_atom.a_w.w_float - 0.01 * dy;
1864 double trunc = 0.01 * (floor(100. * nval + 0.5));
1865 if (trunc < nval + 0.0001 && trunc > nval - 0.0001) nval = trunc;
1866 gatom_clipfloat(x, nval);
1867 }
1868 else
1869 {
1870 double nval = x->a_atom.a_w.w_float - dy;
1871 double trunc = 0.01 * (floor(100. * nval + 0.5));
1872 if (trunc < nval + 0.0001 && trunc > nval - 0.0001) nval = trunc;
1873 trunc = floor(nval + 0.5);
1874 if (trunc < nval + 0.001 && trunc > nval - 0.001) nval = trunc;
1875 gatom_clipfloat(x, nval);
1876 }
1877 }
1878}
1879
1880static void gatom_key(void *z, t_floatarg f)
1881{
1882 t_gatom *x = (t_gatom *)z;
1883 int c = f;
1884 int len = strlen(x->a_buf);
1885 t_atom at;
1886 char sbuf[ATOMBUFSIZE + 4];
1887 if (c == 0)
1888 {
1889 /* we're being notified that no more keys will come for this grab */
1890 if (x->a_buf[0])
1891 gatom_retext(x, 1);
1892 return;
1893 }
1894 else if (c == ' ') return;
1895 else if (c == '\b')
1896 {
1897 if (len > 0)
1898 x->a_buf[len-1] = 0;
1899 goto redraw;
1900 }
1901 else if (c == '\n')
1902 {
1903 if (x->a_atom.a_type == A_FLOAT)
1904 x->a_atom.a_w.w_float = atof(x->a_buf);
1905 else if (x->a_atom.a_type == A_SYMBOL)
1906 x->a_atom.a_w.w_symbol = gensym(x->a_buf);
1907 else bug("gatom_key");
1908 gatom_bang(x);
1909 gatom_retext(x, 1);
1910 x->a_buf[0] = 0;
1911 }
1912 else if (len < (ATOMBUFSIZE-1))
1913 {
1914 /* for numbers, only let reasonable characters through */
1915 if ((x->a_atom.a_type == A_SYMBOL) ||
1916 (c >= '0' && c <= '9' || c == '.' || c == '-'
1917 || c == 'e' || c == 'E'))
1918 {
1919 x->a_buf[len] = c;
1920 x->a_buf[len+1] = 0;
1921 goto redraw;
1922 }
1923 }
1924 return;
1925redraw:
1926 /* LATER figure out how to avoid creating all these symbols! */
1927 sprintf(sbuf, "%s...", x->a_buf);
1928 SETSYMBOL(&at, gensym(sbuf));
1929 binbuf_clear(x->a_text.te_binbuf);
1930 binbuf_add(x->a_text.te_binbuf, 1, &at);
1931 glist_retext(x->a_glist, &x->a_text);
1932}
1933
1934static void gatom_click(t_gatom *x,
1935 t_floatarg xpos, t_floatarg ypos, t_floatarg shift, t_floatarg ctrl,
1936 t_floatarg alt)
1937{
1938 if (x->a_text.te_width == 1)
1939 {
1940 if (x->a_atom.a_type == A_FLOAT)
1941 gatom_float(x, (x->a_atom.a_w.w_float == 0));
1942 }
1943 else
1944 {
1945 if (alt)
1946 {
1947 if (x->a_atom.a_type != A_FLOAT) return;
1948 if (x->a_atom.a_w.w_float != 0)
1949 {
1950 x->a_toggle = x->a_atom.a_w.w_float;
1951 gatom_float(x, 0);
1952 return;
1953 }
1954 else gatom_float(x, x->a_toggle);
1955 }
1956 x->a_shift = shift;
1957 x->a_buf[0] = 0;
1958 glist_grab(x->a_glist, &x->a_text.te_g, gatom_motion, gatom_key,
1959 xpos, ypos);
1960 }
1961}
1962
1963 /* message back from dialog window */
1964static void gatom_param(t_gatom *x, t_symbol *sel, int argc, t_atom *argv)
1965{
1966 t_float width = atom_getfloatarg(0, argc, argv);
1967 t_float draglo = atom_getfloatarg(1, argc, argv);
1968 t_float draghi = atom_getfloatarg(2, argc, argv);
1969 t_symbol *label = gatom_unescapit(atom_getsymbolarg(3, argc, argv));
1970 t_float wherelabel = atom_getfloatarg(4, argc, argv);
1971 t_symbol *symfrom = gatom_unescapit(atom_getsymbolarg(5, argc, argv));
1972 t_symbol *symto = gatom_unescapit(atom_getsymbolarg(6, argc, argv));
1973
1974 gobj_vis(&x->a_text.te_g, x->a_glist, 0);
1975 if (!*symfrom->s_name && *x->a_symfrom->s_name)
1976 inlet_new(&x->a_text, &x->a_text.te_pd, 0, 0);
1977 else if (*symfrom->s_name && !*x->a_symfrom->s_name && x->a_text.te_inlet)
1978 {
1979 canvas_deletelinesforio(x->a_glist, &x->a_text,
1980 x->a_text.te_inlet, 0);
1981 inlet_free(x->a_text.te_inlet);
1982 }
1983 if (!*symto->s_name && *x->a_symto->s_name)
1984 outlet_new(&x->a_text, 0);
1985 else if (*symto->s_name && !*x->a_symto->s_name && x->a_text.te_outlet)
1986 {
1987 canvas_deletelinesforio(x->a_glist, &x->a_text,
1988 0, x->a_text.te_outlet);
1989 outlet_free(x->a_text.te_outlet);
1990 }
1991 if (draglo >= draghi)
1992 draglo = draghi = 0;
1993 x->a_draglo = draglo;
1994 x->a_draghi = draghi;
1995 if (width < 0)
1996 width = 4;
1997 else if (width > 80)
1998 width = 80;
1999 x->a_text.te_width = width;
2000 x->a_wherelabel = ((int)wherelabel & 3);
2001 x->a_label = label;
2002 if (*x->a_symfrom->s_name)
2003 pd_unbind(&x->a_text.te_pd,
2004 canvas_realizedollar(x->a_glist, x->a_symfrom));
2005 x->a_symfrom = symfrom;
2006 if (*x->a_symfrom->s_name)
2007 pd_bind(&x->a_text.te_pd,
2008 canvas_realizedollar(x->a_glist, x->a_symfrom));
2009 x->a_symto = symto;
2010 x->a_expanded_to = canvas_realizedollar(x->a_glist, x->a_symto);
2011 gobj_vis(&x->a_text.te_g, x->a_glist, 1);
2012
2013 /* glist_retext(x->a_glist, &x->a_text); */
2014}
2015
2016 /* ---------------- gatom-specific widget functions --------------- */
2017static void gatom_getwherelabel(t_gatom *x, t_glist *glist, int *xp, int *yp)
2018{
2019 int x1, y1, x2, y2, width, height;
2020 text_getrect(&x->a_text.te_g, glist, &x1, &y1, &x2, &y2);
2021 width = x2 - x1;
2022 height = y2 - y1;
2023 if (x->a_wherelabel == ATOM_LABELLEFT)
2024 {
2025 *xp = x1 - 3 -
2026 strlen(canvas_realizedollar(x->a_glist, x->a_label)->s_name) *
2027 sys_fontwidth(glist_getfont(glist));
2028 *yp = y1 + 2;
2029 }
2030 else if (x->a_wherelabel == ATOM_LABELRIGHT)
2031 {
2032 *xp = x2 + 2;
2033 *yp = y1 + 2;
2034 }
2035 else if (x->a_wherelabel == ATOM_LABELUP)
2036 {
2037 *xp = x1 - 1;
2038 *yp = y1 - 1 - sys_fontheight(glist_getfont(glist));;
2039 }
2040 else
2041 {
2042 *xp = x1 - 1;
2043 *yp = y2 + 3;
2044 }
2045}
2046
2047static void gatom_displace(t_gobj *z, t_glist *glist,
2048 int dx, int dy)
2049{
2050 t_gatom *x = (t_gatom*)z;
2051 text_displace(z, glist, dx, dy);
2052 sys_vgui(".x%x.c move %x.l %d %d\n", glist_getcanvas(glist),
2053 x, dx, dy);
2054}
2055
2056static void gatom_vis(t_gobj *z, t_glist *glist, int vis)
2057{
2058 t_gatom *x = (t_gatom*)z;
2059 text_vis(z, glist, vis);
2060 if (*x->a_label->s_name)
2061 {
2062 if (vis)
2063 {
2064 int x1, y1;
2065 gatom_getwherelabel(x, glist, &x1, &y1);
2066 sys_vgui("pdtk_text_new .x%x.c %x.l %f %f {%s} %d %s\n",
2067 glist_getcanvas(glist), x,
2068 (double)x1, (double)y1,
2069 canvas_realizedollar(x->a_glist, x->a_label)->s_name,
2070 sys_hostfontsize(glist_getfont(glist)),
2071 "black");
2072 }
2073 else sys_vgui(".x%x.c delete %x.l\n", glist_getcanvas(glist), x);
2074 }
2075}
2076
2077void canvas_atom(t_glist *gl, t_atomtype type,
2078 t_symbol *s, int argc, t_atom *argv)
2079{
2080 t_gatom *x = (t_gatom *)pd_new(gatom_class);
2081 t_atom at;
2082 x->a_text.te_width = 0; /* don't know it yet. */
2083 x->a_text.te_type = T_ATOM;
2084 x->a_text.te_binbuf = binbuf_new();
2085 x->a_glist = gl;
2086 x->a_atom.a_type = type;
2087 x->a_toggle = 1;
2088 x->a_draglo = 0;
2089 x->a_draghi = 0;
2090 x->a_wherelabel = 0;
2091 x->a_label = &s_;
2092 x->a_symfrom = &s_;
2093 x->a_symto = x->a_expanded_to = &s_;
2094 if (type == A_FLOAT)
2095 {
2096 x->a_atom.a_w.w_float = 0;
2097 x->a_text.te_width = 5;
2098 SETFLOAT(&at, 0);
2099 }
2100 else
2101 {
2102 x->a_atom.a_w.w_symbol = &s_symbol;
2103 x->a_text.te_width = 10;
2104 SETSYMBOL(&at, &s_symbol);
2105 }
2106 binbuf_add(x->a_text.te_binbuf, 1, &at);
2107 if (argc > 1)
2108 /* create from file. x, y, width, low-range, high-range, flags,
2109 label, receive-name, send-name */
2110 {
2111 x->a_text.te_xpix = atom_getfloatarg(0, argc, argv);
2112 x->a_text.te_ypix = atom_getfloatarg(1, argc, argv);
2113 x->a_text.te_width = atom_getintarg(2, argc, argv);
2114 /* sanity check because some very old patches have trash in this
2115 field... remove this in 2003 or so: */
2116 if (x->a_text.te_width < 0 || x->a_text.te_width > 500)
2117 x->a_text.te_width = 4;
2118 x->a_draglo = atom_getfloatarg(3, argc, argv);
2119 x->a_draghi = atom_getfloatarg(4, argc, argv);
2120 x->a_wherelabel = (((int)atom_getfloatarg(5, argc, argv)) & 3);
2121 x->a_label = gatom_unescapit(atom_getsymbolarg(6, argc, argv));
2122 x->a_symfrom = gatom_unescapit(atom_getsymbolarg(7, argc, argv));
2123 if (*x->a_symfrom->s_name)
2124 pd_bind(&x->a_text.te_pd,
2125 canvas_realizedollar(x->a_glist, x->a_symfrom));
2126
2127 x->a_symto = gatom_unescapit(atom_getsymbolarg(8, argc, argv));
2128 x->a_expanded_to = canvas_realizedollar(x->a_glist, x->a_symto);
2129 if (x->a_symto == &s_)
2130 outlet_new(&x->a_text,
2131 x->a_atom.a_type == A_FLOAT ? &s_float: &s_symbol);
2132 if (x->a_symfrom == &s_)
2133 inlet_new(&x->a_text, &x->a_text.te_pd, 0, 0);
2134 glist_add(gl, &x->a_text.te_g);
2135 }
2136 else
2137 {
2138 int xpix, ypix;
2139 outlet_new(&x->a_text,
2140 x->a_atom.a_type == A_FLOAT ? &s_float: &s_symbol);
2141 inlet_new(&x->a_text, &x->a_text.te_pd, 0, 0);
2142 pd_vmess(&gl->gl_pd, gensym("editmode"), "i", 1);
2143 glist_noselect(gl);
2144 glist_getnextxy(gl, &xpix, &ypix);
2145 x->a_text.te_xpix = xpix;
2146 x->a_text.te_ypix = ypix;
2147 glist_add(gl, &x->a_text.te_g);
2148 glist_noselect(gl);
2149 glist_select(gl, &x->a_text.te_g);
2150 canvas_startmotion(glist_getcanvas(gl));
2151 }
2152}
2153
2154void canvas_floatatom(t_glist *gl, t_symbol *s, int argc, t_atom *argv)
2155{
2156 canvas_atom(gl, A_FLOAT, s, argc, argv);
2157}
2158
2159void canvas_symbolatom(t_glist *gl, t_symbol *s, int argc, t_atom *argv)
2160{
2161 canvas_atom(gl, A_SYMBOL, s, argc, argv);
2162}
2163
2164static void gatom_free(t_gatom *x)
2165{
2166 if (*x->a_symfrom->s_name)
2167 pd_unbind(&x->a_text.te_pd,
2168 canvas_realizedollar(x->a_glist, x->a_symfrom));
2169 gfxstub_deleteforkey(x);
2170}
2171
2172static void gatom_properties(t_gobj *z, t_glist *owner)
2173{
2174 t_gatom *x = (t_gatom *)z;
2175 char buf[200];
2176 sprintf(buf, "pdtk_gatom_dialog %%s %d %g %g %d %s %s %s\n",
2177 x->a_text.te_width, x->a_draglo, x->a_draghi,
2178 x->a_wherelabel, gatom_escapit(x->a_label)->s_name,
2179 gatom_escapit(x->a_symfrom)->s_name,
2180 gatom_escapit(x->a_symto)->s_name);
2181 gfxstub_new(&x->a_text.te_pd, x, buf);
2182}
2183
2184
2185/* -------------------- widget behavior for text objects ------------ */
2186
2187static void text_getrect(t_gobj *z, t_glist *glist,
2188 int *xp1, int *yp1, int *xp2, int *yp2)
2189{
2190 t_text *x = (t_text *)z;
2191 int width, height, iscomment = (x->te_type == T_TEXT);
2192 float x1, y1, x2, y2;
2193
2194 /* for number boxes, we know width and height a priori, and should
2195 report them here so that graphs can get swelled to fit. */
2196
2197 if (x->te_type == T_ATOM && x->te_width > 0)
2198 {
2199 int font = glist_getfont(glist);
2200 int fontwidth = sys_fontwidth(font), fontheight = sys_fontheight(font);
2201 width = (x->te_width > 0 ? x->te_width : 6) * fontwidth + 2;
2202 height = fontheight + 1; /* borrowed from TMARGIN, etc, in g_rtext.c */
2203 }
2204 /* if we're invisible we don't know our size so we just lie about
2205 it. This is called on invisible boxes to establish order of inlets
2206 and possibly other reasons.
2207 To find out if the box is visible we can't just check the "vis"
2208 flag because we might be within the vis() routine and not have set
2209 that yet. So we check directly whether the "rtext" list has been
2210 built. LATER reconsider when "vis" flag should be on and off? */
2211
2212 else if (glist->gl_editor && glist->gl_editor->e_rtext)
2213 {
2214 t_rtext *y = glist_findrtext(glist, x);
2215 width = rtext_width(y);
2216 height = rtext_height(y) - (iscomment << 1);
2217 }
2218 else width = height = 10;
2219 x1 = text_xpix(x, glist);
2220 y1 = text_ypix(x, glist);
2221 x2 = x1 + width;
2222 y2 = y1 + height;
2223 y1 += iscomment;
2224 *xp1 = x1;
2225 *yp1 = y1;
2226 *xp2 = x2;
2227 *yp2 = y2;
2228}
2229
2230static void text_displace(t_gobj *z, t_glist *glist,
2231 int dx, int dy)
2232{
2233 t_text *x = (t_text *)z;
2234 x->te_xpix += dx;
2235 x->te_ypix += dy;
2236 if (glist_isvisible(glist))
2237 {
2238 t_rtext *y = glist_findrtext(glist, x);
2239 rtext_displace(y, dx, dy);
2240 text_drawborder(x, glist, rtext_gettag(y),
2241 rtext_width(y), rtext_height(y), 0);
2242 canvas_fixlinesfor(glist_getcanvas(glist), x);
2243 }
2244}
2245
2246static void text_select(t_gobj *z, t_glist *glist, int state)
2247{
2248 t_text *x = (t_text *)z;
2249 t_rtext *y = glist_findrtext(glist, x);
2250 rtext_select(y, state);
2251 if (glist_isvisible(glist) && text_shouldvis(x, glist))
2252 sys_vgui(".x%x.c itemconfigure %sR -fill %s\n", glist,
2253 rtext_gettag(y), (state? "blue" : "black"));
2254}
2255
2256static void text_activate(t_gobj *z, t_glist *glist, int state)
2257{
2258 t_text *x = (t_text *)z;
2259 t_rtext *y = glist_findrtext(glist, x);
2260 if (z->g_pd != gatom_class) rtext_activate(y, state);
2261}
2262
2263static void text_delete(t_gobj *z, t_glist *glist)
2264{
2265 t_text *x = (t_text *)z;
2266 canvas_deletelinesfor(glist, x);
2267}
2268
2269 /* return true if the text box should be drawn.
2270 We don't show object boxes inside graphs. */
2271int text_shouldvis(t_text *x, t_glist *glist)
2272{
2273 return (glist->gl_havewindow ||
2274 (x->te_pd != canvas_class && x->te_pd->c_wb != &text_widgetbehavior) ||
2275 (x->te_pd == canvas_class && (((t_glist *)x)->gl_isgraph)));
2276}
2277
2278static void text_vis(t_gobj *z, t_glist *glist, int vis)
2279{
2280 t_text *x = (t_text *)z;
2281 if (vis)
2282 {
2283 if (text_shouldvis(x, glist))
2284 {
2285 t_rtext *y = glist_findrtext(glist, x);
2286 if (x->te_type == T_ATOM)
2287 glist_retext(glist, x);
2288 text_drawborder(x, glist, rtext_gettag(y),
2289 rtext_width(y), rtext_height(y), 1);
2290 rtext_draw(y);
2291 }
2292 }
2293 else
2294 {
2295 t_rtext *y = glist_findrtext(glist, x);
2296 if (text_shouldvis(x, glist))
2297 {
2298 text_eraseborder(x, glist, rtext_gettag(y));
2299 rtext_erase(y);
2300 }
2301 }
2302}
2303
2304static int text_click(t_gobj *z, struct _glist *glist,
2305 int xpix, int ypix, int shift, int alt, int dbl, int doit)
2306{
2307 t_text *x = (t_text *)z;
2308 if (x->te_type == T_OBJECT)
2309 {
2310 t_symbol *clicksym = gensym("click");
2311 if (zgetfn(&x->te_pd, clicksym))
2312 {
2313 if (doit)
2314 pd_vmess(&x->te_pd, clicksym, "fffff",
2315 (double)xpix, (double)ypix,
2316 (double)shift, 0, (double)alt);
2317 return (1);
2318 }
2319 else return (0);
2320 }
2321 else if (x->te_type == T_ATOM)
2322 {
2323 if (doit)
2324 gatom_click((t_gatom *)x, (t_floatarg)xpix, (t_floatarg)ypix,
2325 (t_floatarg)shift, 0, (t_floatarg)alt);
2326 return (1);
2327 }
2328 else if (x->te_type == T_MESSAGE)
2329 {
2330 if (doit)
2331 message_click((t_message *)x, (t_floatarg)xpix, (t_floatarg)ypix,
2332 (t_floatarg)shift, 0, (t_floatarg)alt);
2333 return (1);
2334 }
2335 else return (0);
2336}
2337
2338void text_save(t_gobj *z, t_binbuf *b)
2339{
2340 t_text *x = (t_text *)z;
2341 if (x->te_type == T_OBJECT)
2342 {
2343 /* if we have a "saveto" method, and if we don't happen to be
2344 a canvas that's an abstraction, the saveto method does the work */
2345 if (zgetfn(&x->te_pd, gensym("saveto")) &&
2346 !((pd_class(&x->te_pd) == canvas_class) &&
2347 (canvas_isabstraction((t_canvas *)x)
2348 || canvas_istable((t_canvas *)x))))
2349 {
2350 mess1(&x->te_pd, gensym("saveto"), b);
2351 binbuf_addv(b, "ssii", gensym("#X"), gensym("restore"),
2352 (t_int)x->te_xpix, (t_int)x->te_ypix);
2353 }
2354 else /* otherwise just save the text */
2355 {
2356 binbuf_addv(b, "ssii", gensym("#X"), gensym("obj"),
2357 (t_int)x->te_xpix, (t_int)x->te_ypix);
2358 }
2359 binbuf_addbinbuf(b, x->te_binbuf);
2360 binbuf_addv(b, ";");
2361 }
2362 else if (x->te_type == T_MESSAGE)
2363 {
2364 binbuf_addv(b, "ssii", gensym("#X"), gensym("msg"),
2365 (t_int)x->te_xpix, (t_int)x->te_ypix);
2366 binbuf_addbinbuf(b, x->te_binbuf);
2367 binbuf_addv(b, ";");
2368 }
2369 else if (x->te_type == T_ATOM)
2370 {
2371 t_atomtype t = ((t_gatom *)x)->a_atom.a_type;
2372 t_symbol *sel = (t == A_SYMBOL ? gensym("symbolatom") :
2373 (t == A_FLOAT ? gensym("floatatom") : gensym("intatom")));
2374 t_symbol *label = gatom_escapit(((t_gatom *)x)->a_label);
2375 t_symbol *symfrom = gatom_escapit(((t_gatom *)x)->a_symfrom);
2376 t_symbol *symto = gatom_escapit(((t_gatom *)x)->a_symto);
2377 binbuf_addv(b, "ssiiifffsss", gensym("#X"), sel,
2378 (t_int)x->te_xpix, (t_int)x->te_ypix, (t_int)x->te_width,
2379 (double)((t_gatom *)x)->a_draglo,
2380 (double)((t_gatom *)x)->a_draghi,
2381 (double)((t_gatom *)x)->a_wherelabel,
2382 label, symfrom, symto);
2383 binbuf_addv(b, ";");
2384 }
2385 else
2386 {
2387 binbuf_addv(b, "ssii", gensym("#X"), gensym("text"),
2388 (t_int)x->te_xpix, (t_int)x->te_ypix);
2389 binbuf_addbinbuf(b, x->te_binbuf);
2390 binbuf_addv(b, ";");
2391 }
2392}
2393
2394 /* this one is for everyone but "gatoms"; it's imposed in m_class.c */
2395t_widgetbehavior text_widgetbehavior =
2396{
2397 text_getrect,
2398 text_displace,
2399 text_select,
2400 text_activate,
2401 text_delete,
2402 text_vis,
2403 text_click,
2404};
2405
2406static t_widgetbehavior gatom_widgetbehavior =
2407{
2408 text_getrect,
2409 gatom_displace,
2410 text_select,
2411 text_activate,
2412 text_delete,
2413 gatom_vis,
2414 text_click,
2415};
2416
2417/* -------------------- the "text" class ------------ */
2418
2419#ifdef MACOSX
2420#define EXTRAPIX 2
2421#else
2422#define EXTRAPIX 1
2423#endif
2424
2425 /* draw inlets and outlets for a text object or for a graph. */
2426void glist_drawiofor(t_glist *glist, t_object *ob, int firsttime,
2427 char *tag, int x1, int y1, int x2, int y2)
2428{
2429 int n = obj_noutlets(ob), nplus = (n == 1 ? 1 : n-1), i;
2430 int width = x2 - x1;
2431 for (i = 0; i < n; i++)
2432 {
2433 int onset = x1 + (width - IOWIDTH) * i / nplus;
2434 if (firsttime)
2435 sys_vgui(".x%x.c create rectangle %d %d %d %d -tags %so%d\n",
2436 glist_getcanvas(glist),
2437 onset, y2 - 1,
2438 onset + IOWIDTH, y2,
2439 tag, i);
2440 else
2441 sys_vgui(".x%x.c coords %so%d %d %d %d %d\n",
2442 glist_getcanvas(glist), tag, i,
2443 onset, y2 - 1,
2444 onset + IOWIDTH, y2);
2445 }
2446 n = obj_ninlets(ob);
2447 nplus = (n == 1 ? 1 : n-1);
2448 for (i = 0; i < n; i++)
2449 {
2450 int onset = x1 + (width - IOWIDTH) * i / nplus;
2451 if (firsttime)
2452 sys_vgui(".x%x.c create rectangle %d %d %d %d -tags %si%d\n",
2453 glist_getcanvas(glist),
2454 onset, y1,
2455 onset + IOWIDTH, y1 + EXTRAPIX,
2456 tag, i);
2457 else
2458 sys_vgui(".x%x.c coords %si%d %d %d %d %d\n",
2459 glist_getcanvas(glist), tag, i,
2460 onset, y1,
2461 onset + IOWIDTH, y1 + EXTRAPIX);
2462 }
2463}
2464
2465void text_drawborder(t_text *x, t_glist *glist,
2466 char *tag, int width2, int height2, int firsttime)
2467{
2468 t_object *ob;
2469 int x1, y1, x2, y2, width, height;
2470 text_getrect(&x->te_g, glist, &x1, &y1, &x2, &y2);
2471 width = x2 - x1;
2472 height = y2 - y1;
2473 if (x->te_type == T_OBJECT)
2474 {
2475 if (firsttime)
2476 sys_vgui(".x%x.c create line\
2477 %d %d %d %d %d %d %d %d %d %d -tags %sR\n",
2478 glist_getcanvas(glist),
2479 x1, y1, x2, y1, x2, y2, x1, y2, x1, y1, tag);
2480 else
2481 sys_vgui(".x%x.c coords %sR\
2482 %d %d %d %d %d %d %d %d %d %d\n",
2483 glist_getcanvas(glist), tag,
2484 x1, y1, x2, y1, x2, y2, x1, y2, x1, y1);
2485 }
2486 else if (x->te_type == T_MESSAGE)
2487 {
2488 if (firsttime)
2489 sys_vgui(".x%x.c create line\
2490 %d %d %d %d %d %d %d %d %d %d %d %d %d %d -tags %sR\n",
2491 glist_getcanvas(glist),
2492 x1, y1, x2+4, y1, x2, y1+4, x2, y2-4, x2+4, y2,
2493 x1, y2, x1, y1,
2494 tag);
2495 else
2496 sys_vgui(".x%x.c coords %sR\
2497 %d %d %d %d %d %d %d %d %d %d %d %d %d %d\n",
2498 glist_getcanvas(glist), tag,
2499 x1, y1, x2+4, y1, x2, y1+4, x2, y2-4, x2+4, y2,
2500 x1, y2, x1, y1);
2501 }
2502 else if (x->te_type == T_ATOM)
2503 {
2504 if (firsttime)
2505 sys_vgui(".x%x.c create line\
2506 %d %d %d %d %d %d %d %d %d %d %d %d -tags %sR\n",
2507 glist_getcanvas(glist),
2508 x1, y1, x2-4, y1, x2, y1+4, x2, y2, x1, y2, x1, y1,
2509 tag);
2510 else
2511 sys_vgui(".x%x.c coords %sR\
2512 %d %d %d %d %d %d %d %d %d %d %d %d\n",
2513 glist_getcanvas(glist), tag,
2514 x1, y1, x2-4, y1, x2, y1+4, x2, y2, x1, y2, x1, y1);
2515 }
2516 /* draw inlets/outlets */
2517
2518 if (ob = pd_checkobject(&x->te_pd))
2519 glist_drawiofor(glist, ob, firsttime, tag, x1, y1, x2, y2);
2520}
2521
2522void glist_eraseiofor(t_glist *glist, t_object *ob, char *tag)
2523{
2524 int i, n;
2525 n = obj_noutlets(ob);
2526 for (i = 0; i < n; i++)
2527 sys_vgui(".x%x.c delete %so%d\n",
2528 glist_getcanvas(glist), tag, i);
2529 n = obj_ninlets(ob);
2530 for (i = 0; i < n; i++)
2531 sys_vgui(".x%x.c delete %si%d\n",
2532 glist_getcanvas(glist), tag, i);
2533}
2534
2535void text_eraseborder(t_text *x, t_glist *glist, char *tag)
2536{
2537 if (x->te_type == T_TEXT) return;
2538 sys_vgui(".x%x.c delete %sR\n",
2539 glist_getcanvas(glist), tag);
2540 glist_eraseiofor(glist, x, tag);
2541}
2542
2543 /* change text; if T_OBJECT, remake it. LATER we'll have an undo buffer
2544 which should be filled in here before making the change. */
2545
2546void text_setto(t_text *x, t_glist *glist, char *buf, int bufsize)
2547{
2548 if (x->te_type == T_OBJECT)
2549 {
2550 t_binbuf *b = binbuf_new();
2551 int natom1, natom2;
2552 t_atom *vec1, *vec2;
2553 binbuf_text(b, buf, bufsize);
2554 natom1 = binbuf_getnatom(x->te_binbuf);
2555 vec1 = binbuf_getvec(x->te_binbuf);
2556 natom2 = binbuf_getnatom(b);
2557 vec2 = binbuf_getvec(b);
2558 /* special case: if pd args change just pass the message on. */
2559 if (natom1 >= 1 && natom2 >= 1 && vec1[0].a_type == A_SYMBOL
2560 && !strcmp(vec1[0].a_w.w_symbol->s_name, "pd") &&
2561 vec2[0].a_type == A_SYMBOL
2562 && !strcmp(vec2[0].a_w.w_symbol->s_name, "pd"))
2563 {
2564 typedmess(&x->te_pd, gensym("rename"), natom2-1, vec2+1);
2565 binbuf_free(x->te_binbuf);
2566 x->te_binbuf = b;
2567 }
2568 else /* normally, just destroy the old one and make a new one. */
2569 {
2570 int xwas = x->te_xpix, ywas = x->te_ypix;
2571 glist_delete(glist, &x->te_g);
2572 canvas_objtext(glist, xwas, ywas, 0, b);
2573 /* if it's an abstraction loadbang it here */
2574 if (newest && pd_class(newest) == canvas_class)
2575 canvas_loadbang((t_canvas *)newest);
2576 canvas_restoreconnections(glist_getcanvas(glist));
2577 }
2578 /* if we made a new "pd" or changed a window name,
2579 update window list */
2580 if (natom2 >= 1 && vec2[0].a_type == A_SYMBOL
2581 && !strcmp(vec2[0].a_w.w_symbol->s_name, "pd"))
2582 canvas_updatewindowlist();
2583 }
2584 else binbuf_text(x->te_binbuf, buf, bufsize);
2585}
2586
2587void g_text_setup(void)
2588{
2589 text_class = class_new(gensym("text"), 0, 0, sizeof(t_text),
2590 CLASS_NOINLET | CLASS_PATCHABLE, 0);
2591
2592 message_class = class_new(gensym("message"), 0, (t_method)message_free,
2593 sizeof(t_message), CLASS_PATCHABLE, 0);
2594 class_addbang(message_class, message_bang);
2595 class_addfloat(message_class, message_float);
2596 class_addsymbol(message_class, message_symbol);
2597 class_addlist(message_class, message_list);
2598 class_addanything(message_class, message_list);
2599
2600 class_addmethod(message_class, (t_method)message_click, gensym("click"),
2601 A_FLOAT, A_FLOAT, A_FLOAT, A_FLOAT, A_FLOAT, 0);
2602 class_addmethod(message_class, (t_method)message_set, gensym("set"),
2603 A_GIMME, 0);
2604 class_addmethod(message_class, (t_method)message_add, gensym("add"),
2605 A_GIMME, 0);
2606 class_addmethod(message_class, (t_method)message_add2, gensym("add2"),
2607 A_GIMME, 0);
2608
2609 messresponder_class = class_new(gensym("messresponder"), 0, 0,
2610 sizeof(t_text), CLASS_PD, 0);
2611 class_addbang(messresponder_class, messresponder_bang);
2612 class_addfloat(messresponder_class, (t_method) messresponder_float);
2613 class_addsymbol(messresponder_class, messresponder_symbol);
2614 class_addlist(messresponder_class, messresponder_list);
2615 class_addanything(messresponder_class, messresponder_anything);
2616
2617 gatom_class = class_new(gensym("gatom"), 0, (t_method)gatom_free,
2618 sizeof(t_gatom), CLASS_NOINLET | CLASS_PATCHABLE, 0);
2619 class_addbang(gatom_class, gatom_bang);
2620 class_addfloat(gatom_class, gatom_float);
2621 class_addsymbol(gatom_class, gatom_symbol);
2622 class_addmethod(gatom_class, (t_method)gatom_set, gensym("set"),
2623 A_GIMME, 0);
2624 class_addmethod(gatom_class, (t_method)gatom_click, gensym("click"),
2625 A_FLOAT, A_FLOAT, A_FLOAT, A_FLOAT, A_FLOAT, 0);
2626 class_addmethod(gatom_class, (t_method)gatom_param, gensym("param"),
2627 A_GIMME, 0);
2628 class_setwidget(gatom_class, &gatom_widgetbehavior);
2629 class_setpropertiesfn(gatom_class, gatom_properties);
2630}
2631
2632