diff options
Diffstat (limited to 'apps/plugins/pdbox/PDa/src/g_rtext.c')
-rw-r--r-- | apps/plugins/pdbox/PDa/src/g_rtext.c | 972 |
1 files changed, 972 insertions, 0 deletions
diff --git a/apps/plugins/pdbox/PDa/src/g_rtext.c b/apps/plugins/pdbox/PDa/src/g_rtext.c new file mode 100644 index 0000000000..8ffc8f415b --- /dev/null +++ b/apps/plugins/pdbox/PDa/src/g_rtext.c | |||
@@ -0,0 +1,972 @@ | |||
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 | /* have to insert gui-objects into editor-list */ | ||
7 | /* all changes are labeled with iemlib */ | ||
8 | |||
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" | ||
17 | |||
18 | #define LMARGIN 1 | ||
19 | #define RMARGIN 1 | ||
20 | #define TMARGIN 2 | ||
21 | #define BMARGIN 2 | ||
22 | |||
23 | #define SEND_FIRST 1 | ||
24 | #define SEND_UPDATE 2 | ||
25 | #define SEND_CHECK 0 | ||
26 | |||
27 | struct _rtext | ||
28 | { | ||
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; | ||
42 | }; | ||
43 | |||
44 | t_rtext *rtext_new(t_glist *glist, t_text *who) | ||
45 | { | ||
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); | ||
59 | } | ||
60 | |||
61 | static t_rtext *rtext_entered; | ||
62 | |||
63 | void rtext_free(t_rtext *x) | ||
64 | { | ||
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 | ||
70 | { | ||
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) | ||
74 | { | ||
75 | e2->x_next = x->x_next; | ||
76 | break; | ||
77 | } | ||
78 | } | ||
79 | if (rtext_entered == x) rtext_entered = 0; | ||
80 | freebytes(x->x_buf, x->x_bufsize); | ||
81 | freebytes(x, sizeof *x); | ||
82 | } | ||
83 | |||
84 | char *rtext_gettag(t_rtext *x) | ||
85 | { | ||
86 | return (x->x_tag); | ||
87 | } | ||
88 | |||
89 | void rtext_gettext(t_rtext *x, char **buf, int *bufsize) | ||
90 | { | ||
91 | *buf = x->x_buf; | ||
92 | *bufsize = x->x_bufsize; | ||
93 | } | ||
94 | |||
95 | |||
96 | /* LATER deal with tcl-significant characters */ | ||
97 | |||
98 | static int firstone(char *s, int c, int n) | ||
99 | { | ||
100 | char *s2 = s + n; | ||
101 | int i = 0; | ||
102 | while (s != s2) | ||
103 | { | ||
104 | if (*s == c) return (i); | ||
105 | i++; | ||
106 | s++; | ||
107 | } | ||
108 | return (-1); | ||
109 | } | ||
110 | |||
111 | static int lastone(char *s, int c, int n) | ||
112 | { | ||
113 | char *s2 = s + n; | ||
114 | while (s2 != s) | ||
115 | { | ||
116 | s2--; | ||
117 | n--; | ||
118 | if (*s2 == c) return (n); | ||
119 | } | ||
120 | return (-1); | ||
121 | } | ||
122 | |||
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. | ||
132 | */ | ||
133 | |||
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 | ||
139 | |||
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? */ | ||
142 | |||
143 | extern int sys_oldtclversion; | ||
144 | |||
145 | static void rtext_senditup(t_rtext *x, int action, int *widthp, int *heightp, | ||
146 | int *indexp) | ||
147 | { | ||
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) | ||
161 | { | ||
162 | int maxindex = (inchars > widthlimit ? widthlimit : inchars); | ||
163 | int eatchar = 1; | ||
164 | int foundit = firstone(bp, '\n', maxindex); | ||
165 | if (foundit < 0) | ||
166 | { | ||
167 | if (inchars > widthlimit) | ||
168 | { | ||
169 | foundit = lastone(bp, ' ', maxindex); | ||
170 | if (foundit < 0) | ||
171 | { | ||
172 | foundit = maxindex; | ||
173 | eatchar = 0; | ||
174 | } | ||
175 | } | ||
176 | else | ||
177 | { | ||
178 | foundit = inchars; | ||
179 | eatchar = 0; | ||
180 | } | ||
181 | } | ||
182 | if (nlines == findy) | ||
183 | { | ||
184 | int actualx = (findx < 0 ? 0 : | ||
185 | (findx > foundit ? foundit : findx)); | ||
186 | *indexp = (bp - x->x_buf) + actualx; | ||
187 | reportedindex = 1; | ||
188 | } | ||
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++; | ||
196 | } | ||
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) | ||
205 | { | ||
206 | while (ncolumns < 3) | ||
207 | { | ||
208 | tempbuf[outchars++] = ' '; | ||
209 | ncolumns++; | ||
210 | } | ||
211 | } | ||
212 | else ncolumns = widthspec; | ||
213 | pixwide = ncolumns * fontwidth + (LMARGIN + RMARGIN); | ||
214 | pixhigh = nlines * fontheight + (TMARGIN + BMARGIN); | ||
215 | |||
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) | ||
224 | { | ||
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) | ||
231 | { | ||
232 | if (x->x_selend > x->x_selstart) | ||
233 | { | ||
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); | ||
239 | } | ||
240 | else | ||
241 | { | ||
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); | ||
246 | } | ||
247 | } | ||
248 | } | ||
249 | x->x_drawnwidth = pixwide; | ||
250 | x->x_drawnheight = pixhigh; | ||
251 | |||
252 | *widthp = pixwide; | ||
253 | *heightp = pixhigh; | ||
254 | } | ||
255 | |||
256 | void rtext_retext(t_rtext *x) | ||
257 | { | ||
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) | ||
266 | { | ||
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) | ||
271 | { | ||
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; | ||
298 | } | ||
299 | else if (bufsize > text->te_width) | ||
300 | { | ||
301 | x->x_buf[text->te_width - 1] = '>'; | ||
302 | t_resizebytes(x->x_buf, bufsize, text->te_width); | ||
303 | bufsize = text->te_width; | ||
304 | } | ||
305 | done: | ||
306 | x->x_bufsize = bufsize; | ||
307 | } | ||
308 | rtext_senditup(x, SEND_UPDATE, &w, &h, &indx); | ||
309 | } | ||
310 | |||
311 | /* find the rtext that goes with a text item */ | ||
312 | t_rtext *glist_findrtext(t_glist *gl, t_text *who) | ||
313 | { | ||
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); | ||
318 | } | ||
319 | |||
320 | int rtext_width(t_rtext *x) | ||
321 | { | ||
322 | int w = 0, h = 0, indx; | ||
323 | rtext_senditup(x, SEND_CHECK, &w, &h, &indx); | ||
324 | return (w); | ||
325 | } | ||
326 | |||
327 | int rtext_height(t_rtext *x) | ||
328 | { | ||
329 | int w = 0, h = 0, indx; | ||
330 | rtext_senditup(x, SEND_CHECK, &w, &h, &indx); | ||
331 | return (h); | ||
332 | } | ||
333 | |||
334 | void rtext_draw(t_rtext *x) | ||
335 | { | ||
336 | int w = 0, h = 0, indx; | ||
337 | rtext_senditup(x, SEND_FIRST, &w, &h, &indx); | ||
338 | } | ||
339 | |||
340 | void rtext_erase(t_rtext *x) | ||
341 | { | ||
342 | sys_vgui(".x%x.c delete %s\n", glist_getcanvas(x->x_glist), x->x_tag); | ||
343 | } | ||
344 | |||
345 | void rtext_displace(t_rtext *x, int dx, int dy) | ||
346 | { | ||
347 | sys_vgui(".x%x.c move %s %d %d\n", glist_getcanvas(x->x_glist), | ||
348 | x->x_tag, dx, dy); | ||
349 | } | ||
350 | |||
351 | void rtext_select(t_rtext *x, int state) | ||
352 | { | ||
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; | ||
358 | } | ||
359 | |||
360 | void rtext_activate(t_rtext *x, int state) | ||
361 | { | ||
362 | int w = 0, h = 0, indx; | ||
363 | t_glist *glist = x->x_glist; | ||
364 | t_canvas *canvas = glist_getcanvas(glist); | ||
365 | if (state) | ||
366 | { | ||
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; | ||
373 | } | ||
374 | else | ||
375 | { | ||
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; | ||
381 | } | ||
382 | rtext_senditup(x, SEND_UPDATE, &w, &h, &indx); | ||
383 | } | ||
384 | |||
385 | void rtext_key(t_rtext *x, int keynum, t_symbol *keysym) | ||
386 | { | ||
387 | int w = 0, h = 0, indx, i, newsize, ndel; | ||
388 | char *s1, *s2; | ||
389 | if (keynum) | ||
390 | { | ||
391 | int n = keynum; | ||
392 | if (n == '\r') n = '\n'; | ||
393 | if (n == '\b') /* backspace */ | ||
394 | { | ||
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)) | ||
398 | { | ||
399 | .... | ||
400 | } */ | ||
401 | if (x->x_selstart && (x->x_selstart == x->x_selend)) | ||
402 | x->x_selstart--; | ||
403 | } | ||
404 | else if (n == 127) /* delete */ | ||
405 | { | ||
406 | if (x->x_selend < x->x_bufsize && (x->x_selstart == x->x_selend)) | ||
407 | x->x_selend++; | ||
408 | } | ||
409 | |||
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; | ||
416 | |||
417 | if (n == '\n' || isprint(n)) | ||
418 | { | ||
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; | ||
426 | } | ||
427 | x->x_selend = x->x_selstart; | ||
428 | x->x_glist->gl_editor->e_textdirty = 1; | ||
429 | } | ||
430 | else if (!strcmp(keysym->s_name, "Right")) | ||
431 | { | ||
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; | ||
436 | } | ||
437 | else if (!strcmp(keysym->s_name, "Left")) | ||
438 | { | ||
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; | ||
443 | } | ||
444 | /* this should be improved... life's too short */ | ||
445 | else if (!strcmp(keysym->s_name, "Up")) | ||
446 | { | ||
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; | ||
452 | } | ||
453 | else if (!strcmp(keysym->s_name, "Down")) | ||
454 | { | ||
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; | ||
461 | } | ||
462 | rtext_senditup(x, SEND_UPDATE, &w, &h, &indx); | ||
463 | } | ||
464 | |||
465 | void rtext_mouse(t_rtext *x, int xval, int yval, int flag) | ||
466 | { | ||
467 | int w = xval, h = yval, indx; | ||
468 | rtext_senditup(x, SEND_CHECK, &w, &h, &indx); | ||
469 | if (flag == RTEXT_DOWN) | ||
470 | { | ||
471 | x->x_dragfrom = x->x_selstart = x->x_selend = indx; | ||
472 | } | ||
473 | else if (flag == RTEXT_SHIFT) | ||
474 | { | ||
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; | ||
479 | } | ||
480 | else if (flag == RTEXT_DRAG) | ||
481 | { | ||
482 | x->x_selstart = (x->x_dragfrom < indx ? x->x_dragfrom : indx); | ||
483 | x->x_selend = (x->x_dragfrom > indx ? x->x_dragfrom : indx); | ||
484 | } | ||
485 | rtext_senditup(x, SEND_UPDATE, &w, &h, &indx); | ||
486 | } | ||
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. */ | ||
490 | |||
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 */ | ||
494 | |||
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" | ||
503 | |||
504 | #define LMARGIN 1 | ||
505 | #define RMARGIN 1 | ||
506 | #define TMARGIN 2 | ||
507 | #define BMARGIN 2 | ||
508 | |||
509 | #define SEND_FIRST 1 | ||
510 | #define SEND_UPDATE 2 | ||
511 | #define SEND_CHECK 0 | ||
512 | |||
513 | struct _rtext | ||
514 | { | ||
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; | ||
528 | }; | ||
529 | |||
530 | t_rtext *rtext_new(t_glist *glist, t_text *who) | ||
531 | { | ||
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); | ||
545 | } | ||
546 | |||
547 | static t_rtext *rtext_entered; | ||
548 | |||
549 | void rtext_free(t_rtext *x) | ||
550 | { | ||
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 | ||
556 | { | ||
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) | ||
560 | { | ||
561 | e2->x_next = x->x_next; | ||
562 | break; | ||
563 | } | ||
564 | } | ||
565 | if (rtext_entered == x) rtext_entered = 0; | ||
566 | freebytes(x->x_buf, x->x_bufsize); | ||
567 | freebytes(x, sizeof *x); | ||
568 | } | ||
569 | |||
570 | char *rtext_gettag(t_rtext *x) | ||
571 | { | ||
572 | return (x->x_tag); | ||
573 | } | ||
574 | |||
575 | void rtext_gettext(t_rtext *x, char **buf, int *bufsize) | ||
576 | { | ||
577 | *buf = x->x_buf; | ||
578 | *bufsize = x->x_bufsize; | ||
579 | } | ||
580 | |||
581 | |||
582 | /* LATER deal with tcl-significant characters */ | ||
583 | |||
584 | static int firstone(char *s, int c, int n) | ||
585 | { | ||
586 | char *s2 = s + n; | ||
587 | int i = 0; | ||
588 | while (s != s2) | ||
589 | { | ||
590 | if (*s == c) return (i); | ||
591 | i++; | ||
592 | s++; | ||
593 | } | ||
594 | return (-1); | ||
595 | } | ||
596 | |||
597 | static int lastone(char *s, int c, int n) | ||
598 | { | ||
599 | char *s2 = s + n; | ||
600 | while (s2 != s) | ||
601 | { | ||
602 | s2--; | ||
603 | n--; | ||
604 | if (*s2 == c) return (n); | ||
605 | } | ||
606 | return (-1); | ||
607 | } | ||
608 | |||
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. | ||
618 | */ | ||
619 | |||
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 | ||
625 | |||
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? */ | ||
628 | |||
629 | extern int sys_oldtclversion; | ||
630 | |||
631 | static void rtext_senditup(t_rtext *x, int action, int *widthp, int *heightp, | ||
632 | int *indexp) | ||
633 | { | ||
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) | ||
647 | { | ||
648 | int maxindex = (inchars > widthlimit ? widthlimit : inchars); | ||
649 | int eatchar = 1; | ||
650 | int foundit = firstone(bp, '\n', maxindex); | ||
651 | if (foundit < 0) | ||
652 | { | ||
653 | if (inchars > widthlimit) | ||
654 | { | ||
655 | foundit = lastone(bp, ' ', maxindex); | ||
656 | if (foundit < 0) | ||
657 | { | ||
658 | foundit = maxindex; | ||
659 | eatchar = 0; | ||
660 | } | ||
661 | } | ||
662 | else | ||
663 | { | ||
664 | foundit = inchars; | ||
665 | eatchar = 0; | ||
666 | } | ||
667 | } | ||
668 | if (nlines == findy) | ||
669 | { | ||
670 | int actualx = (findx < 0 ? 0 : | ||
671 | (findx > foundit ? foundit : findx)); | ||
672 | *indexp = (bp - x->x_buf) + actualx; | ||
673 | reportedindex = 1; | ||
674 | } | ||
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++; | ||
682 | } | ||
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) | ||
691 | { | ||
692 | while (ncolumns < 3) | ||
693 | { | ||
694 | tempbuf[outchars++] = ' '; | ||
695 | ncolumns++; | ||
696 | } | ||
697 | } | ||
698 | else ncolumns = widthspec; | ||
699 | pixwide = ncolumns * fontwidth + (LMARGIN + RMARGIN); | ||
700 | pixhigh = nlines * fontheight + (TMARGIN + BMARGIN); | ||
701 | |||
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) | ||
710 | { | ||
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) | ||
717 | { | ||
718 | if (x->x_selend > x->x_selstart) | ||
719 | { | ||
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); | ||
725 | } | ||
726 | else | ||
727 | { | ||
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); | ||
732 | } | ||
733 | } | ||
734 | } | ||
735 | x->x_drawnwidth = pixwide; | ||
736 | x->x_drawnheight = pixhigh; | ||
737 | |||
738 | *widthp = pixwide; | ||
739 | *heightp = pixhigh; | ||
740 | } | ||
741 | |||
742 | void rtext_retext(t_rtext *x) | ||
743 | { | ||
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) | ||
752 | { | ||
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) | ||
757 | { | ||
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; | ||
784 | } | ||
785 | else if (bufsize > text->te_width) | ||
786 | { | ||
787 | x->x_buf[text->te_width - 1] = '>'; | ||
788 | t_resizebytes(x->x_buf, bufsize, text->te_width); | ||
789 | bufsize = text->te_width; | ||
790 | } | ||
791 | done: | ||
792 | x->x_bufsize = bufsize; | ||
793 | } | ||
794 | rtext_senditup(x, SEND_UPDATE, &w, &h, &indx); | ||
795 | } | ||
796 | |||
797 | /* find the rtext that goes with a text item */ | ||
798 | t_rtext *glist_findrtext(t_glist *gl, t_text *who) | ||
799 | { | ||
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); | ||
804 | } | ||
805 | |||
806 | int rtext_width(t_rtext *x) | ||
807 | { | ||
808 | int w = 0, h = 0, indx; | ||
809 | rtext_senditup(x, SEND_CHECK, &w, &h, &indx); | ||
810 | return (w); | ||
811 | } | ||
812 | |||
813 | int rtext_height(t_rtext *x) | ||
814 | { | ||
815 | int w = 0, h = 0, indx; | ||
816 | rtext_senditup(x, SEND_CHECK, &w, &h, &indx); | ||
817 | return (h); | ||
818 | } | ||
819 | |||
820 | void rtext_draw(t_rtext *x) | ||
821 | { | ||
822 | int w = 0, h = 0, indx; | ||
823 | rtext_senditup(x, SEND_FIRST, &w, &h, &indx); | ||
824 | } | ||
825 | |||
826 | void rtext_erase(t_rtext *x) | ||
827 | { | ||
828 | sys_vgui(".x%x.c delete %s\n", glist_getcanvas(x->x_glist), x->x_tag); | ||
829 | } | ||
830 | |||
831 | void rtext_displace(t_rtext *x, int dx, int dy) | ||
832 | { | ||
833 | sys_vgui(".x%x.c move %s %d %d\n", glist_getcanvas(x->x_glist), | ||
834 | x->x_tag, dx, dy); | ||
835 | } | ||
836 | |||
837 | void rtext_select(t_rtext *x, int state) | ||
838 | { | ||
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; | ||
844 | } | ||
845 | |||
846 | void rtext_activate(t_rtext *x, int state) | ||
847 | { | ||
848 | int w = 0, h = 0, indx; | ||
849 | t_glist *glist = x->x_glist; | ||
850 | t_canvas *canvas = glist_getcanvas(glist); | ||
851 | if (state) | ||
852 | { | ||
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; | ||
859 | } | ||
860 | else | ||
861 | { | ||
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; | ||
867 | } | ||
868 | rtext_senditup(x, SEND_UPDATE, &w, &h, &indx); | ||
869 | } | ||
870 | |||
871 | void rtext_key(t_rtext *x, int keynum, t_symbol *keysym) | ||
872 | { | ||
873 | int w = 0, h = 0, indx, i, newsize, ndel; | ||
874 | char *s1, *s2; | ||
875 | if (keynum) | ||
876 | { | ||
877 | int n = keynum; | ||
878 | if (n == '\r') n = '\n'; | ||
879 | if (n == '\b') /* backspace */ | ||
880 | { | ||
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)) | ||
884 | { | ||
885 | .... | ||
886 | } */ | ||
887 | if (x->x_selstart && (x->x_selstart == x->x_selend)) | ||
888 | x->x_selstart--; | ||
889 | } | ||
890 | else if (n == 127) /* delete */ | ||
891 | { | ||
892 | if (x->x_selend < x->x_bufsize && (x->x_selstart == x->x_selend)) | ||
893 | x->x_selend++; | ||
894 | } | ||
895 | |||
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; | ||
902 | |||
903 | if (n == '\n' || isprint(n)) | ||
904 | { | ||
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; | ||
912 | } | ||
913 | x->x_selend = x->x_selstart; | ||
914 | x->x_glist->gl_editor->e_textdirty = 1; | ||
915 | } | ||
916 | else if (!strcmp(keysym->s_name, "Right")) | ||
917 | { | ||
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; | ||
922 | } | ||
923 | else if (!strcmp(keysym->s_name, "Left")) | ||
924 | { | ||
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; | ||
929 | } | ||
930 | /* this should be improved... life's too short */ | ||
931 | else if (!strcmp(keysym->s_name, "Up")) | ||
932 | { | ||
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; | ||
938 | } | ||
939 | else if (!strcmp(keysym->s_name, "Down")) | ||
940 | { | ||
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; | ||
947 | } | ||
948 | rtext_senditup(x, SEND_UPDATE, &w, &h, &indx); | ||
949 | } | ||
950 | |||
951 | void rtext_mouse(t_rtext *x, int xval, int yval, int flag) | ||
952 | { | ||
953 | int w = xval, h = yval, indx; | ||
954 | rtext_senditup(x, SEND_CHECK, &w, &h, &indx); | ||
955 | if (flag == RTEXT_DOWN) | ||
956 | { | ||
957 | x->x_dragfrom = x->x_selstart = x->x_selend = indx; | ||
958 | } | ||
959 | else if (flag == RTEXT_SHIFT) | ||
960 | { | ||
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; | ||
965 | } | ||
966 | else if (flag == RTEXT_DRAG) | ||
967 | { | ||
968 | x->x_selstart = (x->x_dragfrom < indx ? x->x_dragfrom : indx); | ||
969 | x->x_selend = (x->x_dragfrom > indx ? x->x_dragfrom : indx); | ||
970 | } | ||
971 | rtext_senditup(x, SEND_UPDATE, &w, &h, &indx); | ||
972 | } | ||