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 */
20
/* for some reason, it draws text 1 pixel lower on Mac OS X (& linux too?) */
47
struct _rtext *x_next;
50
t_rtext *rtext_new(t_glist *glist, t_text *who)
52
t_rtext *x = (t_rtext *)getbytes(sizeof *x);
53
int w = 0, h = 0, indx;
57
x->x_next = glist->gl_editor->e_rtext;
58
x->x_selstart = x->x_selend = x->x_active =
59
x->x_drawnwidth = x->x_drawnheight = 0;
60
binbuf_gettext(who->te_binbuf, &x->x_buf, &x->x_bufsize);
61
glist->gl_editor->e_rtext = x;
62
sprintf(x->x_tag, ".x%lx.t%lx", (t_int)glist_getcanvas(x->x_glist),
67
static t_rtext *rtext_entered;
69
void rtext_free(t_rtext *x)
71
if (x->x_glist->gl_editor->e_textedfor == x)
72
x->x_glist->gl_editor->e_textedfor = 0;
73
if (x->x_glist->gl_editor->e_rtext == x)
74
x->x_glist->gl_editor->e_rtext = x->x_next;
78
for (e2 = x->x_glist->gl_editor->e_rtext; e2; e2 = e2->x_next)
81
e2->x_next = x->x_next;
85
if (rtext_entered == x) rtext_entered = 0;
86
freebytes(x->x_buf, x->x_bufsize);
87
freebytes(x, sizeof *x);
90
char *rtext_gettag(t_rtext *x)
95
void rtext_gettext(t_rtext *x, char **buf, int *bufsize)
98
*bufsize = x->x_bufsize;
101
void rtext_getseltext(t_rtext *x, char **buf, int *bufsize)
103
*buf = x->x_buf + x->x_selstart;
104
*bufsize = x->x_selend - x->x_selstart;
107
/* LATER deal with tcl-significant characters */
109
static int firstone(char *s, int c, int n)
115
if (*s == c) return (i);
122
static int lastone(char *s, int c, int n)
129
if (*s2 == c) return (n);
134
/* the following routine computes line breaks and carries out
135
some action which could be:
136
SEND_FIRST - draw the box for the first time
137
SEND_UPDATE - redraw the updated box
138
otherwise - don't draw, just calculate.
139
Called with *widthp and *heightpas coordinates of
140
a test point, the routine reports the index of the character found
141
there in *indexp. *widthp and *heightp are set to the width and height
142
of the entire text in pixels.
145
/* LATER get this and sys_vgui to work together properly,
146
breaking up messages as needed. As of now, there's
147
a limit of 1950 characters, imposed by sys_vgui(). */
148
#define UPBUFSIZE 4000
151
/* Older (pre-8.3.4) TCL versions handle text selection differently; this
152
flag is set from the GUI if this happens. LATER take this out: early 2006? */
154
extern int sys_oldtclversion;
156
static void rtext_senditup(t_rtext *x, int action, int *widthp, int *heightp,
159
t_float dispx, dispy;
160
char smallbuf[200], *tempbuf;
161
int outchars = 0, nlines = 0, ncolumns = 0,
162
pixwide, pixhigh, font, fontwidth, fontheight, findx, findy;
163
int reportedindex = 0;
164
t_canvas *canvas = glist_getcanvas(x->x_glist);
165
int widthspec = x->x_text->te_width;
166
int widthlimit = (widthspec ? widthspec : BOXWIDTH);
168
int selstart = 0, selend = 0;
169
/* if we're a GOP (the new, "goprect" style) borrow the font size
170
from the inside to preserve the spacing */
171
if (pd_class(&x->x_text->te_pd) == canvas_class &&
172
((t_glist *)(x->x_text))->gl_isgraph &&
173
((t_glist *)(x->x_text))->gl_goprect)
174
font = glist_getfont((t_glist *)(x->x_text));
175
else font = glist_getfont(x->x_glist);
176
fontwidth = sys_fontwidth(font);
177
fontheight = sys_fontheight(font);
178
findx = (*widthp + (fontwidth/2)) / fontwidth;
179
findy = *heightp / fontheight;
180
if (x->x_bufsize >= 100)
181
tempbuf = (char *)t_getbytes(2 * x->x_bufsize + 1);
182
else tempbuf = smallbuf;
183
while (x->x_bufsize - inindex > 0)
185
int inchars = x->x_bufsize - inindex;
186
int maxindex = (inchars > widthlimit ? widthlimit : inchars);
188
int foundit = firstone(x->x_buf + inindex, '\n', maxindex);
191
if (inchars > widthlimit)
193
foundit = lastone(x->x_buf + inindex, ' ', maxindex);
208
int actualx = (findx < 0 ? 0 :
209
(findx > foundit ? foundit : findx));
210
*indexp = inindex + actualx;
213
strncpy(tempbuf+outchars, x->x_buf + inindex, foundit);
214
if (x->x_selstart >= inindex &&
215
x->x_selstart <= inindex + foundit + eatchar)
216
selstart = x->x_selstart + outchars - inindex;
217
if (x->x_selend >= inindex &&
218
x->x_selend <= inindex + foundit + eatchar)
219
selend = x->x_selend + outchars - inindex;
221
inindex += (foundit + eatchar);
222
if (inindex < x->x_bufsize)
223
tempbuf[outchars++] = '\n';
224
if (foundit > ncolumns)
230
dispx = text_xpix(x->x_text, x->x_glist);
231
dispy = text_ypix(x->x_text, x->x_glist);
232
if (nlines < 1) nlines = 1;
237
tempbuf[outchars++] = ' ';
241
else ncolumns = widthspec;
242
pixwide = ncolumns * fontwidth + (LMARGIN + RMARGIN);
243
pixhigh = nlines * fontheight + (TMARGIN + BMARGIN);
245
if (action == SEND_FIRST)
246
sys_vgui("pdtk_text_new .x%lx.c %s %f %f {%.*s} %d %s\n",
248
dispx + LMARGIN, dispy + TMARGIN,
249
outchars, tempbuf, sys_hostfontsize(font),
250
(glist_isselected(x->x_glist,
251
&x->x_glist->gl_gobj)? "blue" : "black"));
252
else if (action == SEND_UPDATE)
254
sys_vgui("pdtk_text_set .x%lx.c %s {%.*s}\n",
255
canvas, x->x_tag, outchars, tempbuf);
256
if (pixwide != x->x_drawnwidth || pixhigh != x->x_drawnheight)
257
text_drawborder(x->x_text, x->x_glist, x->x_tag,
258
pixwide, pixhigh, 0);
261
if (selend > selstart)
263
sys_vgui(".x%lx.c select from %s %d\n", canvas,
265
sys_vgui(".x%lx.c select to %s %d\n", canvas,
266
x->x_tag, selend + (sys_oldtclversion ? 0 : -1));
267
sys_vgui(".x%lx.c focus \"\"\n", canvas);
271
sys_vgui(".x%lx.c select clear\n", canvas);
272
sys_vgui(".x%lx.c icursor %s %d\n", canvas, x->x_tag,
274
sys_vgui(".x%lx.c focus %s\n", canvas, x->x_tag);
278
x->x_drawnwidth = pixwide;
279
x->x_drawnheight = pixhigh;
283
if (tempbuf != smallbuf)
284
t_freebytes(tempbuf, 2 * x->x_bufsize + 1);
287
void rtext_retext(t_rtext *x)
289
int w = 0, h = 0, indx;
290
t_text *text = x->x_text;
291
t_freebytes(x->x_buf, x->x_bufsize);
292
binbuf_gettext(text->te_binbuf, &x->x_buf, &x->x_bufsize);
293
/* special case: for number boxes, try to pare the number down
294
to the specified width of the box. */
295
if (text->te_width > 0 && text->te_type == T_ATOM &&
296
x->x_bufsize > text->te_width)
298
t_atom *atomp = binbuf_getvec(text->te_binbuf);
299
int natom = binbuf_getnatom(text->te_binbuf);
300
int bufsize = x->x_bufsize;
301
if (natom == 1 && atomp->a_type == A_FLOAT)
303
/* try to reduce size by dropping decimal digits */
304
int wantreduce = bufsize - text->te_width;
305
char *decimal = 0, *nextchar, *ebuf = x->x_buf + bufsize,
308
for (decimal = x->x_buf; decimal < ebuf; decimal++)
313
for (nextchar = decimal + 1; nextchar < ebuf; nextchar++)
314
if (*nextchar < '0' || *nextchar > '9')
316
if (nextchar - decimal - 1 < wantreduce)
318
for (s1 = nextchar - wantreduce, s2 = s1 + wantreduce;
319
s2 < ebuf; s1++, s2++)
321
x->x_buf = t_resizebytes(x->x_buf, bufsize, text->te_width);
322
bufsize = text->te_width;
325
/* give up and bash it to "+" or "-" */
326
x->x_buf[0] = (atomp->a_w.w_float < 0 ? '-' : '+');
327
x->x_buf = t_resizebytes(x->x_buf, bufsize, 1);
330
else if (bufsize > text->te_width)
332
x->x_buf[text->te_width - 1] = '>';
333
x->x_buf = t_resizebytes(x->x_buf, bufsize, text->te_width);
334
bufsize = text->te_width;
337
x->x_bufsize = bufsize;
339
rtext_senditup(x, SEND_UPDATE, &w, &h, &indx);
342
/* find the rtext that goes with a text item */
343
t_rtext *glist_findrtext(t_glist *gl, t_text *who)
347
canvas_create_editor(gl);
348
for (x = gl->gl_editor->e_rtext; x && x->x_text != who; x = x->x_next)
350
if (!x) bug("glist_findrtext");
354
int rtext_width(t_rtext *x)
356
int w = 0, h = 0, indx;
357
rtext_senditup(x, SEND_CHECK, &w, &h, &indx);
361
int rtext_height(t_rtext *x)
363
int w = 0, h = 0, indx;
364
rtext_senditup(x, SEND_CHECK, &w, &h, &indx);
368
void rtext_draw(t_rtext *x)
370
int w = 0, h = 0, indx;
371
rtext_senditup(x, SEND_FIRST, &w, &h, &indx);
374
void rtext_erase(t_rtext *x)
376
sys_vgui(".x%lx.c delete %s\n", glist_getcanvas(x->x_glist), x->x_tag);
379
void rtext_displace(t_rtext *x, int dx, int dy)
381
sys_vgui(".x%lx.c move %s %d %d\n", glist_getcanvas(x->x_glist),
385
void rtext_select(t_rtext *x, int state)
387
t_glist *glist = x->x_glist;
388
t_canvas *canvas = glist_getcanvas(glist);
389
sys_vgui(".x%lx.c itemconfigure %s -fill %s\n", canvas,
390
x->x_tag, (state? "blue" : "black"));
391
canvas_editing = canvas;
394
void rtext_activate(t_rtext *x, int state)
396
int w = 0, h = 0, indx;
397
t_glist *glist = x->x_glist;
398
t_canvas *canvas = glist_getcanvas(glist);
401
sys_vgui(".x%lx.c focus %s\n", canvas, x->x_tag);
402
glist->gl_editor->e_textedfor = x;
403
glist->gl_editor->e_textdirty = 0;
404
x->x_dragfrom = x->x_selstart = 0;
405
x->x_selend = x->x_bufsize;
410
sys_vgui("selection clear .x%lx.c\n", canvas);
411
sys_vgui(".x%lx.c focus \"\"\n", canvas);
412
if (glist->gl_editor->e_textedfor == x)
413
glist->gl_editor->e_textedfor = 0;
416
rtext_senditup(x, SEND_UPDATE, &w, &h, &indx);
419
void rtext_key(t_rtext *x, int keynum, t_symbol *keysym)
421
int w = 0, h = 0, indx, i, newsize, ndel;
426
if (n == '\r') n = '\n';
427
if (n == '\b') /* backspace */
429
/* LATER delete the box if all text is selected...
430
this causes reentrancy problems now. */
431
/* if ((!x->x_selstart) && (x->x_selend == x->x_bufsize))
435
if (x->x_selstart && (x->x_selstart == x->x_selend))
438
else if (n == 127) /* delete */
440
if (x->x_selend < x->x_bufsize && (x->x_selstart == x->x_selend))
444
ndel = x->x_selend - x->x_selstart;
445
for (i = x->x_selend; i < x->x_bufsize; i++)
446
x->x_buf[i- ndel] = x->x_buf[i];
447
newsize = x->x_bufsize - ndel;
448
x->x_buf = resizebytes(x->x_buf, x->x_bufsize, newsize);
449
x->x_bufsize = newsize;
451
/* at Guenter's suggestion, use 'n>31' to test wither a character might
452
be printable in whatever 8-bit character set we find ourselves. */
454
if (n == '\n' || (n > 31 && n != 127))
456
newsize = x->x_bufsize+1;
457
x->x_buf = resizebytes(x->x_buf, x->x_bufsize, newsize);
458
for (i = x->x_bufsize; i > x->x_selstart; i--)
459
x->x_buf[i] = x->x_buf[i-1];
460
x->x_buf[x->x_selstart] = n;
461
x->x_bufsize = newsize;
462
x->x_selstart = x->x_selstart + 1;
464
x->x_selend = x->x_selstart;
465
x->x_glist->gl_editor->e_textdirty = 1;
467
else if (!strcmp(keysym->s_name, "Right"))
469
if (x->x_selend == x->x_selstart && x->x_selstart < x->x_bufsize)
470
x->x_selend = x->x_selstart = x->x_selstart + 1;
472
x->x_selstart = x->x_selend;
474
else if (!strcmp(keysym->s_name, "Left"))
476
if (x->x_selend == x->x_selstart && x->x_selstart > 0)
477
x->x_selend = x->x_selstart = x->x_selstart - 1;
479
x->x_selend = x->x_selstart;
481
/* this should be improved... life's too short */
482
else if (!strcmp(keysym->s_name, "Up"))
486
while (x->x_selstart > 0 && x->x_buf[x->x_selstart] != '\n')
488
x->x_selend = x->x_selstart;
490
else if (!strcmp(keysym->s_name, "Down"))
492
while (x->x_selend < x->x_bufsize &&
493
x->x_buf[x->x_selend] != '\n')
495
if (x->x_selend < x->x_bufsize)
497
x->x_selstart = x->x_selend;
499
rtext_senditup(x, SEND_UPDATE, &w, &h, &indx);
502
void rtext_mouse(t_rtext *x, int xval, int yval, int flag)
504
int w = xval, h = yval, indx;
505
rtext_senditup(x, SEND_CHECK, &w, &h, &indx);
506
if (flag == RTEXT_DOWN)
508
x->x_dragfrom = x->x_selstart = x->x_selend = indx;
510
else if (flag == RTEXT_DBL)
512
int whereseparator, newseparator;
515
if ((newseparator = lastone(x->x_buf, ' ', indx)) > whereseparator)
516
whereseparator = newseparator+1;
517
if ((newseparator = lastone(x->x_buf, '\n', indx)) > whereseparator)
518
whereseparator = newseparator+1;
519
if ((newseparator = lastone(x->x_buf, ';', indx)) > whereseparator)
520
whereseparator = newseparator+1;
521
if ((newseparator = lastone(x->x_buf, ',', indx)) > whereseparator)
522
whereseparator = newseparator+1;
523
x->x_selstart = whereseparator;
525
whereseparator = x->x_bufsize - indx;
527
firstone(x->x_buf+indx, ' ', x->x_bufsize - indx)) >= 0 &&
528
newseparator < whereseparator)
529
whereseparator = newseparator;
531
firstone(x->x_buf+indx, '\n', x->x_bufsize - indx)) >= 0 &&
532
newseparator < whereseparator)
533
whereseparator = newseparator;
535
firstone(x->x_buf+indx, ';', x->x_bufsize - indx)) >= 0 &&
536
newseparator < whereseparator)
537
whereseparator = newseparator;
539
firstone(x->x_buf+indx, ',', x->x_bufsize - indx)) >= 0 &&
540
newseparator < whereseparator)
541
whereseparator = newseparator;
542
x->x_selend = indx + whereseparator;
544
else if (flag == RTEXT_SHIFT)
546
if (indx * 2 > x->x_selstart + x->x_selend)
547
x->x_dragfrom = x->x_selstart, x->x_selend = indx;
549
x->x_dragfrom = x->x_selend, x->x_selstart = indx;
551
else if (flag == RTEXT_DRAG)
553
if (x->x_dragfrom < 0)
555
x->x_selstart = (x->x_dragfrom < indx ? x->x_dragfrom : indx);
556
x->x_selend = (x->x_dragfrom > indx ? x->x_dragfrom : indx);
558
rtext_senditup(x, SEND_UPDATE, &w, &h, &indx);