Add FS #10214. Initial commit of the original PDa code for the GSoC Pure Data plugin...
[kugel-rb.git] / apps / plugins / pdbox / PDa / src / g_rtext.c
blob8ffc8f415b9446d81d6bdc4514e724daaf97f561
1 /* Copyright (c) 1997-1999 Miller Puckette.
2 * For information on usage and redistribution, and for a DISCLAIMER OF ALL
3 * WARRANTIES, see the file, "LICENSE.txt," in this distribution. */
5 /* changes by Thomas Musil IEM KUG Graz Austria 2001 */
6 /* have to insert gui-objects into editor-list */
7 /* all changes are labeled with iemlib */
9 #include <stdlib.h>
10 #include <string.h>
11 #include <stdio.h>
12 #include <ctype.h>
13 #include "m_pd.h"
14 #include "s_stuff.h"
15 #include "g_canvas.h"
16 #include "t_tk.h"
18 #define LMARGIN 1
19 #define RMARGIN 1
20 #define TMARGIN 2
21 #define BMARGIN 2
23 #define SEND_FIRST 1
24 #define SEND_UPDATE 2
25 #define SEND_CHECK 0
27 struct _rtext
29 char *x_buf;
30 int x_bufsize;
31 int x_selstart;
32 int x_selend;
33 int x_active;
34 int x_dragfrom;
35 int x_height;
36 int x_drawnwidth;
37 int x_drawnheight;
38 t_text *x_text;
39 t_glist *x_glist;
40 char x_tag[50];
41 struct _rtext *x_next;
44 t_rtext *rtext_new(t_glist *glist, t_text *who)
46 t_rtext *x = (t_rtext *)getbytes(sizeof *x);
47 int w = 0, h = 0, indx;
48 x->x_height = -1;
49 x->x_text = who;
50 x->x_glist = glist;
51 x->x_next = glist->gl_editor->e_rtext;
52 x->x_selstart = x->x_selend = x->x_active =
53 x->x_drawnwidth = x->x_drawnheight = 0;
54 binbuf_gettext(who->te_binbuf, &x->x_buf, &x->x_bufsize);
55 glist->gl_editor->e_rtext = x;
56 sprintf(x->x_tag, ".x%x.t%x", (t_int)glist_getcanvas(x->x_glist),
57 (t_int)x);
58 return (x);
61 static t_rtext *rtext_entered;
63 void rtext_free(t_rtext *x)
65 if (x->x_glist->gl_editor->e_textedfor == x)
66 x->x_glist->gl_editor->e_textedfor = 0;
67 if (x->x_glist->gl_editor->e_rtext == x)
68 x->x_glist->gl_editor->e_rtext = x->x_next;
69 else
71 t_rtext *e2;
72 for (e2 = x->x_glist->gl_editor->e_rtext; e2; e2 = e2->x_next)
73 if (e2->x_next == x)
75 e2->x_next = x->x_next;
76 break;
79 if (rtext_entered == x) rtext_entered = 0;
80 freebytes(x->x_buf, x->x_bufsize);
81 freebytes(x, sizeof *x);
84 char *rtext_gettag(t_rtext *x)
86 return (x->x_tag);
89 void rtext_gettext(t_rtext *x, char **buf, int *bufsize)
91 *buf = x->x_buf;
92 *bufsize = x->x_bufsize;
96 /* LATER deal with tcl-significant characters */
98 static int firstone(char *s, int c, int n)
100 char *s2 = s + n;
101 int i = 0;
102 while (s != s2)
104 if (*s == c) return (i);
105 i++;
106 s++;
108 return (-1);
111 static int lastone(char *s, int c, int n)
113 char *s2 = s + n;
114 while (s2 != s)
116 s2--;
117 n--;
118 if (*s2 == c) return (n);
120 return (-1);
123 /* the following routine computes line breaks and carries out
124 some action which could be:
125 SEND_FIRST - draw the box for the first time
126 SEND_UPDATE - redraw the updated box
127 otherwise - don't draw, just calculate.
128 Called with *widthp and *heightpas coordinates of
129 a test point, the routine reports the index of the character found
130 there in *indexp. *widthp and *heightp are set to the width and height
131 of the entire text in pixels.
134 /* LATER get this and sys_vgui to work together properly,
135 breaking up messages as needed. As of now, there's
136 a limit of 1950 characters, imposed by sys_vgui(). */
137 #define UPBUFSIZE 4000
138 #define BOXWIDTH 60
140 /* Older (pre-8.3.4) TCL versions handle text selection differently; this
141 flag is set from the GUI if this happens. LATER take this out: early 2006? */
143 extern int sys_oldtclversion;
145 static void rtext_senditup(t_rtext *x, int action, int *widthp, int *heightp,
146 int *indexp)
148 float dispx, dispy;
149 char tempbuf[UPBUFSIZE], *tp = tempbuf, *bp = x->x_buf;
150 int outchars, inchars = x->x_bufsize, nlines = 0, ncolumns = 0,
151 pixwide, pixhigh;
152 int font = glist_getfont(x->x_glist);
153 int fontwidth = sys_fontwidth(font), fontheight = sys_fontheight(font);
154 int findx = (*widthp + (fontwidth/2)) / fontwidth,
155 findy = *heightp / fontheight;
156 int reportedindex = 0;
157 t_canvas *canvas = glist_getcanvas(x->x_glist);
158 int widthspec = x->x_text->te_width;
159 int widthlimit = (widthspec ? widthspec : BOXWIDTH);
160 while (inchars)
162 int maxindex = (inchars > widthlimit ? widthlimit : inchars);
163 int eatchar = 1;
164 int foundit = firstone(bp, '\n', maxindex);
165 if (foundit < 0)
167 if (inchars > widthlimit)
169 foundit = lastone(bp, ' ', maxindex);
170 if (foundit < 0)
172 foundit = maxindex;
173 eatchar = 0;
176 else
178 foundit = inchars;
179 eatchar = 0;
182 if (nlines == findy)
184 int actualx = (findx < 0 ? 0 :
185 (findx > foundit ? foundit : findx));
186 *indexp = (bp - x->x_buf) + actualx;
187 reportedindex = 1;
189 strncpy(tp, bp, foundit);
190 tp += foundit;
191 bp += (foundit + eatchar);
192 inchars -= (foundit + eatchar);
193 if (inchars) *tp++ = '\n';
194 if (foundit > ncolumns) ncolumns = foundit;
195 nlines++;
197 outchars = tp - tempbuf;
198 if (outchars > 1950) outchars = 1950;
199 if (!reportedindex)
200 *indexp = outchars;
201 dispx = text_xpix(x->x_text, x->x_glist);
202 dispy = text_ypix(x->x_text, x->x_glist);
203 if (nlines < 1) nlines = 1;
204 if (!widthspec)
206 while (ncolumns < 3)
208 tempbuf[outchars++] = ' ';
209 ncolumns++;
212 else ncolumns = widthspec;
213 pixwide = ncolumns * fontwidth + (LMARGIN + RMARGIN);
214 pixhigh = nlines * fontheight + (TMARGIN + BMARGIN);
216 if (action == SEND_FIRST)
217 sys_vgui("pdtk_text_new .x%x.c %s %f %f {%.*s} %d %s\n",
218 canvas, x->x_tag,
219 dispx + LMARGIN, dispy + TMARGIN,
220 outchars, tempbuf, sys_hostfontsize(font),
221 (glist_isselected(x->x_glist,
222 &x->x_glist->gl_gobj)? "blue" : "black"));
223 else if (action == SEND_UPDATE)
225 sys_vgui("pdtk_text_set .x%x.c %s {%.*s}\n",
226 canvas, x->x_tag, outchars, tempbuf);
227 if (pixwide != x->x_drawnwidth || pixhigh != x->x_drawnheight)
228 text_drawborder(x->x_text, x->x_glist, x->x_tag,
229 pixwide, pixhigh, 0);
230 if (x->x_active)
232 if (x->x_selend > x->x_selstart)
234 sys_vgui(".x%x.c select from %s %d\n", canvas,
235 x->x_tag, x->x_selstart);
236 sys_vgui(".x%x.c select to %s %d\n", canvas,
237 x->x_tag, x->x_selend + (sys_oldtclversion ? 0 : -1));
238 sys_vgui(".x%x.c focus \"\"\n", canvas);
240 else
242 sys_vgui(".x%x.c select clear\n", canvas);
243 sys_vgui(".x%x.c icursor %s %d\n", canvas, x->x_tag,
244 x->x_selstart);
245 sys_vgui(".x%x.c focus %s\n", canvas, x->x_tag);
249 x->x_drawnwidth = pixwide;
250 x->x_drawnheight = pixhigh;
252 *widthp = pixwide;
253 *heightp = pixhigh;
256 void rtext_retext(t_rtext *x)
258 int w = 0, h = 0, indx;
259 t_text *text = x->x_text;
260 t_freebytes(x->x_buf, x->x_bufsize);
261 binbuf_gettext(text->te_binbuf, &x->x_buf, &x->x_bufsize);
262 /* special case: for number boxes, try to pare the number down
263 to the specified width of the box. */
264 if (text->te_width > 0 && text->te_type == T_ATOM &&
265 x->x_bufsize > text->te_width)
267 t_atom *atomp = binbuf_getvec(text->te_binbuf);
268 int natom = binbuf_getnatom(text->te_binbuf);
269 int bufsize = x->x_bufsize;
270 if (natom == 1 && atomp->a_type == A_FLOAT)
272 /* try to reduce size by dropping decimal digits */
273 int wantreduce = bufsize - text->te_width;
274 char *decimal = 0, *nextchar, *ebuf = x->x_buf + bufsize,
275 *s1, *s2;
276 int ndecimals;
277 for (decimal = x->x_buf; decimal < ebuf; decimal++)
278 if (*decimal == '.')
279 break;
280 if (decimal >= ebuf)
281 goto giveup;
282 for (nextchar = decimal + 1; nextchar < ebuf; nextchar++)
283 if (*nextchar < '0' || *nextchar > '9')
284 break;
285 if (nextchar - decimal - 1 < wantreduce)
286 goto giveup;
287 for (s1 = nextchar - wantreduce, s2 = s1 + wantreduce;
288 s2 < ebuf; s1++, s2++)
289 *s1 = *s2;
290 t_resizebytes(x->x_buf, bufsize, text->te_width);
291 bufsize = text->te_width;
292 goto done;
293 giveup:
294 /* give up and bash it to "+" or "-" */
295 x->x_buf[0] = (atomp->a_w.w_float < 0 ? '-' : '+');
296 t_resizebytes(x->x_buf, bufsize, 1);
297 bufsize = 1;
299 else if (bufsize > text->te_width)
301 x->x_buf[text->te_width - 1] = '>';
302 t_resizebytes(x->x_buf, bufsize, text->te_width);
303 bufsize = text->te_width;
305 done:
306 x->x_bufsize = bufsize;
308 rtext_senditup(x, SEND_UPDATE, &w, &h, &indx);
311 /* find the rtext that goes with a text item */
312 t_rtext *glist_findrtext(t_glist *gl, t_text *who)
314 t_rtext *x = gl->gl_editor->e_rtext;
315 while (x && x->x_text != who) x = x->x_next;
316 if (!x) bug("glist_findrtext");
317 return (x);
320 int rtext_width(t_rtext *x)
322 int w = 0, h = 0, indx;
323 rtext_senditup(x, SEND_CHECK, &w, &h, &indx);
324 return (w);
327 int rtext_height(t_rtext *x)
329 int w = 0, h = 0, indx;
330 rtext_senditup(x, SEND_CHECK, &w, &h, &indx);
331 return (h);
334 void rtext_draw(t_rtext *x)
336 int w = 0, h = 0, indx;
337 rtext_senditup(x, SEND_FIRST, &w, &h, &indx);
340 void rtext_erase(t_rtext *x)
342 sys_vgui(".x%x.c delete %s\n", glist_getcanvas(x->x_glist), x->x_tag);
345 void rtext_displace(t_rtext *x, int dx, int dy)
347 sys_vgui(".x%x.c move %s %d %d\n", glist_getcanvas(x->x_glist),
348 x->x_tag, dx, dy);
351 void rtext_select(t_rtext *x, int state)
353 t_glist *glist = x->x_glist;
354 t_canvas *canvas = glist_getcanvas(glist);
355 sys_vgui(".x%x.c itemconfigure %s -fill %s\n", canvas,
356 x->x_tag, (state? "blue" : "black"));
357 canvas_editing = canvas;
360 void rtext_activate(t_rtext *x, int state)
362 int w = 0, h = 0, indx;
363 t_glist *glist = x->x_glist;
364 t_canvas *canvas = glist_getcanvas(glist);
365 if (state)
367 sys_vgui(".x%x.c focus %s\n", canvas, x->x_tag);
368 glist->gl_editor->e_textedfor = x;
369 glist->gl_editor->e_textdirty = 0;
370 x->x_dragfrom = x->x_selstart = 0;
371 x->x_selend = x->x_bufsize;
372 x->x_active = 1;
374 else
376 sys_vgui("selection clear .x%x.c\n", canvas);
377 sys_vgui(".x%x.c focus \"\"\n", canvas);
378 if (glist->gl_editor->e_textedfor == x)
379 glist->gl_editor->e_textedfor = 0;
380 x->x_active = 0;
382 rtext_senditup(x, SEND_UPDATE, &w, &h, &indx);
385 void rtext_key(t_rtext *x, int keynum, t_symbol *keysym)
387 int w = 0, h = 0, indx, i, newsize, ndel;
388 char *s1, *s2;
389 if (keynum)
391 int n = keynum;
392 if (n == '\r') n = '\n';
393 if (n == '\b') /* backspace */
395 /* LATER delete the box if all text is selected...
396 this causes reentrancy problems now. */
397 /* if ((!x->x_selstart) && (x->x_selend == x->x_bufsize))
399 ....
400 } */
401 if (x->x_selstart && (x->x_selstart == x->x_selend))
402 x->x_selstart--;
404 else if (n == 127) /* delete */
406 if (x->x_selend < x->x_bufsize && (x->x_selstart == x->x_selend))
407 x->x_selend++;
410 ndel = x->x_selend - x->x_selstart;
411 for (i = x->x_selend; i < x->x_bufsize; i++)
412 x->x_buf[i- ndel] = x->x_buf[i];
413 newsize = x->x_bufsize - ndel;
414 x->x_buf = resizebytes(x->x_buf, x->x_bufsize, newsize);
415 x->x_bufsize = newsize;
417 if (n == '\n' || isprint(n))
419 newsize = x->x_bufsize+1;
420 x->x_buf = resizebytes(x->x_buf, x->x_bufsize, newsize);
421 for (i = x->x_bufsize; i > x->x_selstart; i--)
422 x->x_buf[i] = x->x_buf[i-1];
423 x->x_buf[x->x_selstart] = n;
424 x->x_bufsize = newsize;
425 x->x_selstart = x->x_selstart + 1;
427 x->x_selend = x->x_selstart;
428 x->x_glist->gl_editor->e_textdirty = 1;
430 else if (!strcmp(keysym->s_name, "Right"))
432 if (x->x_selend == x->x_selstart && x->x_selstart < x->x_bufsize)
433 x->x_selend = x->x_selstart = x->x_selstart + 1;
434 else
435 x->x_selstart = x->x_selend;
437 else if (!strcmp(keysym->s_name, "Left"))
439 if (x->x_selend == x->x_selstart && x->x_selstart > 0)
440 x->x_selend = x->x_selstart = x->x_selstart - 1;
441 else
442 x->x_selend = x->x_selstart;
444 /* this should be improved... life's too short */
445 else if (!strcmp(keysym->s_name, "Up"))
447 if (x->x_selstart)
448 x->x_selstart--;
449 while (x->x_selstart > 0 && x->x_buf[x->x_selstart] != '\n')
450 x->x_selstart--;
451 x->x_selend = x->x_selstart;
453 else if (!strcmp(keysym->s_name, "Down"))
455 while (x->x_selend < x->x_bufsize &&
456 x->x_buf[x->x_selend] != '\n')
457 x->x_selend++;
458 if (x->x_selend < x->x_bufsize)
459 x->x_selend++;
460 x->x_selstart = x->x_selend;
462 rtext_senditup(x, SEND_UPDATE, &w, &h, &indx);
465 void rtext_mouse(t_rtext *x, int xval, int yval, int flag)
467 int w = xval, h = yval, indx;
468 rtext_senditup(x, SEND_CHECK, &w, &h, &indx);
469 if (flag == RTEXT_DOWN)
471 x->x_dragfrom = x->x_selstart = x->x_selend = indx;
473 else if (flag == RTEXT_SHIFT)
475 if (indx * 2 > x->x_selstart + x->x_selend)
476 x->x_dragfrom = x->x_selstart, x->x_selend = indx;
477 else
478 x->x_dragfrom = x->x_selend, x->x_selstart = indx;
480 else if (flag == RTEXT_DRAG)
482 x->x_selstart = (x->x_dragfrom < indx ? x->x_dragfrom : indx);
483 x->x_selend = (x->x_dragfrom > indx ? x->x_dragfrom : indx);
485 rtext_senditup(x, SEND_UPDATE, &w, &h, &indx);
487 /* Copyright (c) 1997-1999 Miller Puckette.
488 * For information on usage and redistribution, and for a DISCLAIMER OF ALL
489 * WARRANTIES, see the file, "LICENSE.txt," in this distribution. */
491 /* changes by Thomas Musil IEM KUG Graz Austria 2001 */
492 /* have to insert gui-objects into editor-list */
493 /* all changes are labeled with iemlib */
495 #include <stdlib.h>
496 #include <string.h>
497 #include <stdio.h>
498 #include <ctype.h>
499 #include "m_pd.h"
500 #include "s_stuff.h"
501 #include "g_canvas.h"
502 #include "t_tk.h"
504 #define LMARGIN 1
505 #define RMARGIN 1
506 #define TMARGIN 2
507 #define BMARGIN 2
509 #define SEND_FIRST 1
510 #define SEND_UPDATE 2
511 #define SEND_CHECK 0
513 struct _rtext
515 char *x_buf;
516 int x_bufsize;
517 int x_selstart;
518 int x_selend;
519 int x_active;
520 int x_dragfrom;
521 int x_height;
522 int x_drawnwidth;
523 int x_drawnheight;
524 t_text *x_text;
525 t_glist *x_glist;
526 char x_tag[50];
527 struct _rtext *x_next;
530 t_rtext *rtext_new(t_glist *glist, t_text *who)
532 t_rtext *x = (t_rtext *)getbytes(sizeof *x);
533 int w = 0, h = 0, indx;
534 x->x_height = -1;
535 x->x_text = who;
536 x->x_glist = glist;
537 x->x_next = glist->gl_editor->e_rtext;
538 x->x_selstart = x->x_selend = x->x_active =
539 x->x_drawnwidth = x->x_drawnheight = 0;
540 binbuf_gettext(who->te_binbuf, &x->x_buf, &x->x_bufsize);
541 glist->gl_editor->e_rtext = x;
542 sprintf(x->x_tag, ".x%x.t%x", (t_int)glist_getcanvas(x->x_glist),
543 (t_int)x);
544 return (x);
547 static t_rtext *rtext_entered;
549 void rtext_free(t_rtext *x)
551 if (x->x_glist->gl_editor->e_textedfor == x)
552 x->x_glist->gl_editor->e_textedfor = 0;
553 if (x->x_glist->gl_editor->e_rtext == x)
554 x->x_glist->gl_editor->e_rtext = x->x_next;
555 else
557 t_rtext *e2;
558 for (e2 = x->x_glist->gl_editor->e_rtext; e2; e2 = e2->x_next)
559 if (e2->x_next == x)
561 e2->x_next = x->x_next;
562 break;
565 if (rtext_entered == x) rtext_entered = 0;
566 freebytes(x->x_buf, x->x_bufsize);
567 freebytes(x, sizeof *x);
570 char *rtext_gettag(t_rtext *x)
572 return (x->x_tag);
575 void rtext_gettext(t_rtext *x, char **buf, int *bufsize)
577 *buf = x->x_buf;
578 *bufsize = x->x_bufsize;
582 /* LATER deal with tcl-significant characters */
584 static int firstone(char *s, int c, int n)
586 char *s2 = s + n;
587 int i = 0;
588 while (s != s2)
590 if (*s == c) return (i);
591 i++;
592 s++;
594 return (-1);
597 static int lastone(char *s, int c, int n)
599 char *s2 = s + n;
600 while (s2 != s)
602 s2--;
603 n--;
604 if (*s2 == c) return (n);
606 return (-1);
609 /* the following routine computes line breaks and carries out
610 some action which could be:
611 SEND_FIRST - draw the box for the first time
612 SEND_UPDATE - redraw the updated box
613 otherwise - don't draw, just calculate.
614 Called with *widthp and *heightpas coordinates of
615 a test point, the routine reports the index of the character found
616 there in *indexp. *widthp and *heightp are set to the width and height
617 of the entire text in pixels.
620 /* LATER get this and sys_vgui to work together properly,
621 breaking up messages as needed. As of now, there's
622 a limit of 1950 characters, imposed by sys_vgui(). */
623 #define UPBUFSIZE 4000
624 #define BOXWIDTH 60
626 /* Older (pre-8.3.4) TCL versions handle text selection differently; this
627 flag is set from the GUI if this happens. LATER take this out: early 2006? */
629 extern int sys_oldtclversion;
631 static void rtext_senditup(t_rtext *x, int action, int *widthp, int *heightp,
632 int *indexp)
634 float dispx, dispy;
635 char tempbuf[UPBUFSIZE], *tp = tempbuf, *bp = x->x_buf;
636 int outchars, inchars = x->x_bufsize, nlines = 0, ncolumns = 0,
637 pixwide, pixhigh;
638 int font = glist_getfont(x->x_glist);
639 int fontwidth = sys_fontwidth(font), fontheight = sys_fontheight(font);
640 int findx = (*widthp + (fontwidth/2)) / fontwidth,
641 findy = *heightp / fontheight;
642 int reportedindex = 0;
643 t_canvas *canvas = glist_getcanvas(x->x_glist);
644 int widthspec = x->x_text->te_width;
645 int widthlimit = (widthspec ? widthspec : BOXWIDTH);
646 while (inchars)
648 int maxindex = (inchars > widthlimit ? widthlimit : inchars);
649 int eatchar = 1;
650 int foundit = firstone(bp, '\n', maxindex);
651 if (foundit < 0)
653 if (inchars > widthlimit)
655 foundit = lastone(bp, ' ', maxindex);
656 if (foundit < 0)
658 foundit = maxindex;
659 eatchar = 0;
662 else
664 foundit = inchars;
665 eatchar = 0;
668 if (nlines == findy)
670 int actualx = (findx < 0 ? 0 :
671 (findx > foundit ? foundit : findx));
672 *indexp = (bp - x->x_buf) + actualx;
673 reportedindex = 1;
675 strncpy(tp, bp, foundit);
676 tp += foundit;
677 bp += (foundit + eatchar);
678 inchars -= (foundit + eatchar);
679 if (inchars) *tp++ = '\n';
680 if (foundit > ncolumns) ncolumns = foundit;
681 nlines++;
683 outchars = tp - tempbuf;
684 if (outchars > 1950) outchars = 1950;
685 if (!reportedindex)
686 *indexp = outchars;
687 dispx = text_xpix(x->x_text, x->x_glist);
688 dispy = text_ypix(x->x_text, x->x_glist);
689 if (nlines < 1) nlines = 1;
690 if (!widthspec)
692 while (ncolumns < 3)
694 tempbuf[outchars++] = ' ';
695 ncolumns++;
698 else ncolumns = widthspec;
699 pixwide = ncolumns * fontwidth + (LMARGIN + RMARGIN);
700 pixhigh = nlines * fontheight + (TMARGIN + BMARGIN);
702 if (action == SEND_FIRST)
703 sys_vgui("pdtk_text_new .x%x.c %s %f %f {%.*s} %d %s\n",
704 canvas, x->x_tag,
705 dispx + LMARGIN, dispy + TMARGIN,
706 outchars, tempbuf, sys_hostfontsize(font),
707 (glist_isselected(x->x_glist,
708 &x->x_glist->gl_gobj)? "blue" : "black"));
709 else if (action == SEND_UPDATE)
711 sys_vgui("pdtk_text_set .x%x.c %s {%.*s}\n",
712 canvas, x->x_tag, outchars, tempbuf);
713 if (pixwide != x->x_drawnwidth || pixhigh != x->x_drawnheight)
714 text_drawborder(x->x_text, x->x_glist, x->x_tag,
715 pixwide, pixhigh, 0);
716 if (x->x_active)
718 if (x->x_selend > x->x_selstart)
720 sys_vgui(".x%x.c select from %s %d\n", canvas,
721 x->x_tag, x->x_selstart);
722 sys_vgui(".x%x.c select to %s %d\n", canvas,
723 x->x_tag, x->x_selend + (sys_oldtclversion ? 0 : -1));
724 sys_vgui(".x%x.c focus \"\"\n", canvas);
726 else
728 sys_vgui(".x%x.c select clear\n", canvas);
729 sys_vgui(".x%x.c icursor %s %d\n", canvas, x->x_tag,
730 x->x_selstart);
731 sys_vgui(".x%x.c focus %s\n", canvas, x->x_tag);
735 x->x_drawnwidth = pixwide;
736 x->x_drawnheight = pixhigh;
738 *widthp = pixwide;
739 *heightp = pixhigh;
742 void rtext_retext(t_rtext *x)
744 int w = 0, h = 0, indx;
745 t_text *text = x->x_text;
746 t_freebytes(x->x_buf, x->x_bufsize);
747 binbuf_gettext(text->te_binbuf, &x->x_buf, &x->x_bufsize);
748 /* special case: for number boxes, try to pare the number down
749 to the specified width of the box. */
750 if (text->te_width > 0 && text->te_type == T_ATOM &&
751 x->x_bufsize > text->te_width)
753 t_atom *atomp = binbuf_getvec(text->te_binbuf);
754 int natom = binbuf_getnatom(text->te_binbuf);
755 int bufsize = x->x_bufsize;
756 if (natom == 1 && atomp->a_type == A_FLOAT)
758 /* try to reduce size by dropping decimal digits */
759 int wantreduce = bufsize - text->te_width;
760 char *decimal = 0, *nextchar, *ebuf = x->x_buf + bufsize,
761 *s1, *s2;
762 int ndecimals;
763 for (decimal = x->x_buf; decimal < ebuf; decimal++)
764 if (*decimal == '.')
765 break;
766 if (decimal >= ebuf)
767 goto giveup;
768 for (nextchar = decimal + 1; nextchar < ebuf; nextchar++)
769 if (*nextchar < '0' || *nextchar > '9')
770 break;
771 if (nextchar - decimal - 1 < wantreduce)
772 goto giveup;
773 for (s1 = nextchar - wantreduce, s2 = s1 + wantreduce;
774 s2 < ebuf; s1++, s2++)
775 *s1 = *s2;
776 t_resizebytes(x->x_buf, bufsize, text->te_width);
777 bufsize = text->te_width;
778 goto done;
779 giveup:
780 /* give up and bash it to "+" or "-" */
781 x->x_buf[0] = (atomp->a_w.w_float < 0 ? '-' : '+');
782 t_resizebytes(x->x_buf, bufsize, 1);
783 bufsize = 1;
785 else if (bufsize > text->te_width)
787 x->x_buf[text->te_width - 1] = '>';
788 t_resizebytes(x->x_buf, bufsize, text->te_width);
789 bufsize = text->te_width;
791 done:
792 x->x_bufsize = bufsize;
794 rtext_senditup(x, SEND_UPDATE, &w, &h, &indx);
797 /* find the rtext that goes with a text item */
798 t_rtext *glist_findrtext(t_glist *gl, t_text *who)
800 t_rtext *x = gl->gl_editor->e_rtext;
801 while (x && x->x_text != who) x = x->x_next;
802 if (!x) bug("glist_findrtext");
803 return (x);
806 int rtext_width(t_rtext *x)
808 int w = 0, h = 0, indx;
809 rtext_senditup(x, SEND_CHECK, &w, &h, &indx);
810 return (w);
813 int rtext_height(t_rtext *x)
815 int w = 0, h = 0, indx;
816 rtext_senditup(x, SEND_CHECK, &w, &h, &indx);
817 return (h);
820 void rtext_draw(t_rtext *x)
822 int w = 0, h = 0, indx;
823 rtext_senditup(x, SEND_FIRST, &w, &h, &indx);
826 void rtext_erase(t_rtext *x)
828 sys_vgui(".x%x.c delete %s\n", glist_getcanvas(x->x_glist), x->x_tag);
831 void rtext_displace(t_rtext *x, int dx, int dy)
833 sys_vgui(".x%x.c move %s %d %d\n", glist_getcanvas(x->x_glist),
834 x->x_tag, dx, dy);
837 void rtext_select(t_rtext *x, int state)
839 t_glist *glist = x->x_glist;
840 t_canvas *canvas = glist_getcanvas(glist);
841 sys_vgui(".x%x.c itemconfigure %s -fill %s\n", canvas,
842 x->x_tag, (state? "blue" : "black"));
843 canvas_editing = canvas;
846 void rtext_activate(t_rtext *x, int state)
848 int w = 0, h = 0, indx;
849 t_glist *glist = x->x_glist;
850 t_canvas *canvas = glist_getcanvas(glist);
851 if (state)
853 sys_vgui(".x%x.c focus %s\n", canvas, x->x_tag);
854 glist->gl_editor->e_textedfor = x;
855 glist->gl_editor->e_textdirty = 0;
856 x->x_dragfrom = x->x_selstart = 0;
857 x->x_selend = x->x_bufsize;
858 x->x_active = 1;
860 else
862 sys_vgui("selection clear .x%x.c\n", canvas);
863 sys_vgui(".x%x.c focus \"\"\n", canvas);
864 if (glist->gl_editor->e_textedfor == x)
865 glist->gl_editor->e_textedfor = 0;
866 x->x_active = 0;
868 rtext_senditup(x, SEND_UPDATE, &w, &h, &indx);
871 void rtext_key(t_rtext *x, int keynum, t_symbol *keysym)
873 int w = 0, h = 0, indx, i, newsize, ndel;
874 char *s1, *s2;
875 if (keynum)
877 int n = keynum;
878 if (n == '\r') n = '\n';
879 if (n == '\b') /* backspace */
881 /* LATER delete the box if all text is selected...
882 this causes reentrancy problems now. */
883 /* if ((!x->x_selstart) && (x->x_selend == x->x_bufsize))
885 ....
886 } */
887 if (x->x_selstart && (x->x_selstart == x->x_selend))
888 x->x_selstart--;
890 else if (n == 127) /* delete */
892 if (x->x_selend < x->x_bufsize && (x->x_selstart == x->x_selend))
893 x->x_selend++;
896 ndel = x->x_selend - x->x_selstart;
897 for (i = x->x_selend; i < x->x_bufsize; i++)
898 x->x_buf[i- ndel] = x->x_buf[i];
899 newsize = x->x_bufsize - ndel;
900 x->x_buf = resizebytes(x->x_buf, x->x_bufsize, newsize);
901 x->x_bufsize = newsize;
903 if (n == '\n' || isprint(n))
905 newsize = x->x_bufsize+1;
906 x->x_buf = resizebytes(x->x_buf, x->x_bufsize, newsize);
907 for (i = x->x_bufsize; i > x->x_selstart; i--)
908 x->x_buf[i] = x->x_buf[i-1];
909 x->x_buf[x->x_selstart] = n;
910 x->x_bufsize = newsize;
911 x->x_selstart = x->x_selstart + 1;
913 x->x_selend = x->x_selstart;
914 x->x_glist->gl_editor->e_textdirty = 1;
916 else if (!strcmp(keysym->s_name, "Right"))
918 if (x->x_selend == x->x_selstart && x->x_selstart < x->x_bufsize)
919 x->x_selend = x->x_selstart = x->x_selstart + 1;
920 else
921 x->x_selstart = x->x_selend;
923 else if (!strcmp(keysym->s_name, "Left"))
925 if (x->x_selend == x->x_selstart && x->x_selstart > 0)
926 x->x_selend = x->x_selstart = x->x_selstart - 1;
927 else
928 x->x_selend = x->x_selstart;
930 /* this should be improved... life's too short */
931 else if (!strcmp(keysym->s_name, "Up"))
933 if (x->x_selstart)
934 x->x_selstart--;
935 while (x->x_selstart > 0 && x->x_buf[x->x_selstart] != '\n')
936 x->x_selstart--;
937 x->x_selend = x->x_selstart;
939 else if (!strcmp(keysym->s_name, "Down"))
941 while (x->x_selend < x->x_bufsize &&
942 x->x_buf[x->x_selend] != '\n')
943 x->x_selend++;
944 if (x->x_selend < x->x_bufsize)
945 x->x_selend++;
946 x->x_selstart = x->x_selend;
948 rtext_senditup(x, SEND_UPDATE, &w, &h, &indx);
951 void rtext_mouse(t_rtext *x, int xval, int yval, int flag)
953 int w = xval, h = yval, indx;
954 rtext_senditup(x, SEND_CHECK, &w, &h, &indx);
955 if (flag == RTEXT_DOWN)
957 x->x_dragfrom = x->x_selstart = x->x_selend = indx;
959 else if (flag == RTEXT_SHIFT)
961 if (indx * 2 > x->x_selstart + x->x_selend)
962 x->x_dragfrom = x->x_selstart, x->x_selend = indx;
963 else
964 x->x_dragfrom = x->x_selend, x->x_selstart = indx;
966 else if (flag == RTEXT_DRAG)
968 x->x_selstart = (x->x_dragfrom < indx ? x->x_dragfrom : indx);
969 x->x_selend = (x->x_dragfrom > indx ? x->x_dragfrom : indx);
971 rtext_senditup(x, SEND_UPDATE, &w, &h, &indx);