1 #include <stdlib.h>
2 #include <string.h>
3 #include "xglk.h"
4 #include "xg_internal.h"
5 #include "xg_win_textgrid.h"
6
7 typedef struct sattr_struct {
8 glui32 style, linkid;
9 int blank; /* flag */
10 int end;
11 /* style runs from the previous one to (before) here. Everything
12 after the last style is blank. (Actually, this is the start
13 of the next style.) */
14 } sattr_t;
15
16 typedef struct sline_struct {
17 char *text; /* pointer to array of text_size chars */
18 int text_size; /* allocation size; at least width, but could be more */
19 sattr_t *attr;
20 int numattr;
21 int attr_size; /* allocation size */
22 int dirtybeg, dirtyend; /* chars; [) protocol; -1,-1 for non-dirty */
23 } sline_t;
24
25 typedef struct sdot_struct {
26 int begline, begchar;
27 int endline, endchar;
28 } sdot_t;
29
30 #define DOT_EXISTS(dt) ((dt)->begline >= 0)
31
32 #define DOT_LENGTH_ZERO(dt) \
33 (DOT_EXISTS(dt) && \
34 (dt)->begline == (dt)->endline && (dt)->begchar == (dt)->endchar)
35
36 #define collapse_dot(ctw) \
37 (ctw->dot.begline = ctw->dot.endline, \
38 ctw->dot.begchar = ctw->dot.endchar)
39
40 #define collapse_dot_back(ctw) \
41 (ctw->dot.endline = ctw->dot.begline, \
42 ctw->dot.endchar = ctw->dot.begchar)
43
44 #define ATTRMATCH(at1, at2) \
45 ((at1)->style == (at2)->style && (at1)->linkid == (at2)->linkid)
46
47 struct window_textgrid_struct {
48 window_t *owner;
49 XRectangle bbox;
50
51 stylehints_t hints;
52 fontset_t font;
53
54 XRectangle cbox; /* contents -- the characters themselves */
55 int width, height;
56 sline_t *linelist;
57 int height_size; /* allocation size. Lines above height have valid text,
58 text_size, attr, attr_size fields, but the rest are
59 garbage. */
60
61 int cursorx, cursory;
62
63 int dirtybeg, dirtyend; /* lines; [) protocol; -1,-1 for non-dirty */
64
65 sdot_t dot;
66 sdot_t lastdot;
67
68 int isactive; /* is window active? */
69
70 /* these are for line input */
71 long buflen;
72 char *buffer;
73 int inputlen;
74 int inputmaxlen;
75 sdot_t inputdot; /* always one line */
76 glui32 originalattr;
77 gidispatch_rock_t inarrayrock;
78
79 /* these are for mouse input. */
80 int drag_mouseevent, drag_linkevent;
81 glui32 drag_linkid;
82 sdot_t drag_first, drag_linkpos;
83
84 };
85
86 static void win_textgrid_layout(window_textgrid_t *cutwin, int drawall);
87 static void flip_selection(window_textgrid_t *cutwin, sdot_t *dot);
88 static int dot_contains_dot(window_textgrid_t *dwin, sdot_t *bigdot,
89 sdot_t *dot);
90 static void find_pos_by_loc(window_textgrid_t *dwin, int xpos, int ypos,
91 int addhalf, XPoint *res);
92 static int compare_pos_to_dot(window_textgrid_t *dwin, sdot_t *dot,
93 int pchar, int pline);
94 static void kill_input(window_textgrid_t *cutwin, int beg, int end);
95 static void insert_input(window_textgrid_t *cutwin, int pos, char *buf,
96 int len);
97 static void xgrid_line_cancel(window_textgrid_t *cutwin, event_t *ev);
98
win_textgrid_create(window_t * win)99 struct window_textgrid_struct *win_textgrid_create(window_t *win)
100 {
101 int jx;
102 window_textgrid_t *res =
103 (window_textgrid_t *)malloc(sizeof(window_textgrid_t));
104 if (!res)
105 return NULL;
106
107 res->owner = win;
108
109 gli_stylehints_for_window(wintype_TextGrid, &(res->hints));
110 gli_styles_compute(&(res->font), &(res->hints));
111
112 res->width = 0;
113 res->height = 0;
114 res->height_size = 4;
115 res->linelist = (sline_t *)malloc(res->height_size * sizeof(sline_t));
116 for (jx = 0; jx < res->height_size; jx++) {
117 sline_t *ln = &(res->linelist[jx]);
118 ln->text_size = 20;
119 ln->text = (char *)malloc(ln->text_size * sizeof(char));
120 ln->attr_size = 4;
121 ln->attr = (sattr_t *)malloc(ln->attr_size * sizeof(sattr_t));
122 }
123
124 res->cursorx = 0;
125 res->cursory = 0;
126
127 res->dirtybeg = -1;
128 res->dirtyend = -1;
129
130 res->dot.begline = -1;
131 res->lastdot.begline = -1;
132
133 res->isactive = FALSE;
134
135 res->buffer = NULL;
136 res->buflen = 0;
137
138 return res;
139 }
140
win_textgrid_destroy(window_textgrid_t * win)141 void win_textgrid_destroy(window_textgrid_t *win)
142 {
143 int jx;
144
145 if (win->buffer) {
146 if (gli_unregister_arr) {
147 (*gli_unregister_arr)(win->buffer, win->buflen, "&+#!Cn",
148 win->inarrayrock);
149 }
150 win->buffer = NULL;
151 }
152
153 for (jx = 0; jx < win->height_size; jx++) {
154 sline_t *ln = &(win->linelist[jx]);
155 if (ln->text) {
156 free(ln->text);
157 ln->text = NULL;
158 }
159 if (ln->attr) {
160 free(ln->attr);
161 ln->attr = NULL;
162 }
163 }
164
165 free(win->linelist);
166 win->linelist = NULL;
167
168 win->owner = NULL;
169
170 free(win);
171 }
172
173 /* Return the first style whose end is after pos. If all styles
174 end <= pos, return -1. guess is a position to start scanning at (-1
175 means the end).
176 Can call this with pos == -1. */
find_style_at(sline_t * ln,int pos,int guess)177 static int find_style_at(sline_t *ln, int pos, int guess)
178 {
179 int ix;
180 sattr_t *attr;
181
182 if (ln->numattr <= 0)
183 return -1;
184
185 ix = guess;
186 if (ix < 0 || ix >= ln->numattr)
187 ix = ln->numattr-1;
188
189 attr = &(ln->attr[ix]);
190
191 if (attr->end > pos) {
192 /* scan backwards */
193 for (ix--; ix >= 0; ix--) {
194 if (ln->attr[ix].end <= pos)
195 break;
196 }
197 return ix+1;
198 }
199 else {
200 /* scan forwards */
201 for (ix++; ix < ln->numattr; ix++) {
202 if (ln->attr[ix].end > pos)
203 break;
204 }
205 if (ix >= ln->numattr)
206 return -1;
207 else
208 return ix;
209 }
210 }
211
change_size(window_textgrid_t * cutwin,int newwid,int newhgt)212 static void change_size(window_textgrid_t *cutwin, int newwid, int newhgt)
213 {
214 int ix, jx;
215
216 if (newhgt > cutwin->height) {
217
218 if (newhgt > cutwin->height_size) {
219 int oldheightsize = cutwin->height_size;
220 while (newhgt > cutwin->height_size)
221 cutwin->height_size *= 2;
222 cutwin->linelist = (sline_t *)realloc(cutwin->linelist,
223 cutwin->height_size * sizeof(sline_t));
224 for (jx = oldheightsize; jx < cutwin->height_size; jx++) {
225 sline_t *ln = &(cutwin->linelist[jx]);
226 ln->text_size = newwid + 4;
227 ln->text = (char *)malloc(ln->text_size * sizeof(char));
228 ln->attr_size = 4;
229 ln->attr = (sattr_t *)malloc(ln->attr_size * sizeof(sattr_t));
230 }
231 }
232
233 for (jx = 0; jx < cutwin->height; jx++) {
234 sline_t *ln = &(cutwin->linelist[jx]);
235 /* existing valid lines */
236 if (newwid > cutwin->width) {
237 if (newwid > ln->text_size) {
238 while (newwid > ln->text_size)
239 ln->text_size *= 2;
240 ln->text = (char *)realloc(ln->text, ln->text_size * sizeof(char));
241 }
242 }
243 else if (newwid < cutwin->width) {
244 ix = find_style_at(ln, newwid-1, -1);
245 if (ix >= 0) {
246 sattr_t *attr = &(ln->attr[ix]);
247 attr->end = newwid;
248 ln->numattr = ix+1;
249 }
250 }
251 }
252
253 for (jx = cutwin->height; jx < newhgt; jx++) {
254 sline_t *ln = &(cutwin->linelist[jx]);
255 /* recondition new lines (allocation is already done) */
256 if (newwid > ln->text_size) {
257 while (newwid > ln->text_size)
258 ln->text_size *= 2;
259 ln->text = (char *)realloc(ln->text, ln->text_size * sizeof(char));
260 }
261 ln->numattr = 0;
262 ln->dirtybeg = -1;
263 ln->dirtyend = -1;
264 }
265
266 }
267 else { /* (newhgt < or = cutwin->height) */
268
269 for (jx = 0; jx < newhgt; jx++) {
270 sline_t *ln = &(cutwin->linelist[jx]);
271 /* existing valid lines */
272 if (newwid > cutwin->width) {
273 if (newwid > ln->text_size) {
274 while (newwid > ln->text_size)
275 ln->text_size *= 2;
276 ln->text = (char *)realloc(ln->text, ln->text_size * sizeof(char));
277 }
278 }
279 else if (newwid < cutwin->width) {
280 ix = find_style_at(ln, newwid-1, -1);
281 if (ix >= 0) {
282 sattr_t *attr = &(ln->attr[ix]);
283 attr->end = newwid;
284 ln->numattr = ix+1;
285 }
286 }
287 }
288
289 /* everything beyond newhgt: Ignore. The valid fields are valid and
290 everything else will be reconditioned if the window expands. */
291 }
292
293 cutwin->height = newhgt;
294 cutwin->width = newwid;
295
296 if (cutwin->dot.begline >= 0) {
297 sdot_t *dot = &(cutwin->dot);
298 if (dot->begline >= cutwin->height) {
299 dot->begline = cutwin->height - 1;
300 dot->begchar = cutwin->width;
301 }
302 if (dot->begchar > cutwin->width)
303 dot->begchar = cutwin->width;
304 if (dot->endline >= cutwin->height) {
305 dot->endline = cutwin->height - 1;
306 dot->endchar = cutwin->width;
307 }
308 if (dot->endchar > cutwin->width)
309 dot->endchar = cutwin->width;
310 }
311 }
312
insert_style(sline_t * ln,int pos,int num)313 static void insert_style(sline_t *ln, int pos, int num)
314 {
315 int ix, numend;
316
317 if (num <= 0)
318 return;
319 if (ln->numattr + num > ln->attr_size) {
320 while (ln->numattr + num > ln->attr_size)
321 ln->attr_size *= 2;
322 ln->attr = (sattr_t *)realloc(ln->attr, ln->attr_size * sizeof(sattr_t));
323 }
324 numend = ln->numattr - pos;
325 if (numend) {
326 memmove(&ln->attr[pos+num], &ln->attr[pos], sizeof(sattr_t) * (numend));
327 }
328 ln->numattr += num;
329
330 for (ix=pos; ix<pos+num; ix++) {
331 sattr_t *attr = &ln->attr[ix];
332 attr->end = -99;
333 attr->style = -99;
334 attr->linkid = 0;
335 }
336 }
337
delete_style(sline_t * ln,int pos,int num)338 static void delete_style(sline_t *ln, int pos, int num)
339 {
340 int numend;
341
342 if (num <= 0)
343 return;
344 if (pos + num > ln->numattr)
345 num = ln->numattr - pos;
346 numend = ln->numattr - (pos+num);
347 if (numend) {
348 memmove(&ln->attr[pos], &ln->attr[pos+num], sizeof(sattr_t) * (numend));
349 }
350 ln->numattr -= num;
351 }
352
win_textgrid_flush(window_t * win)353 void win_textgrid_flush(window_t *win)
354 {
355 window_textgrid_t *dwin = win->data;
356 win_textgrid_layout(dwin, FALSE);
357 }
358
win_textgrid_get_size(window_t * win,glui32 * width,glui32 * height)359 void win_textgrid_get_size(window_t *win, glui32 *width, glui32 *height)
360 {
361 window_textgrid_t *dwin = win->data;
362 *width = dwin->width;
363 *height = dwin->height;
364 }
365
win_textgrid_get_rect(window_t * win)366 XRectangle *win_textgrid_get_rect(window_t *win)
367 {
368 window_textgrid_t *dwin = win->data;
369 return &dwin->bbox;
370 }
371
win_textgrid_figure_size(window_t * win,long size,int vertical)372 long win_textgrid_figure_size(window_t *win, long size, int vertical)
373 {
374 window_textgrid_t *dwin = win->data;
375
376 if (vertical) {
377 /* size * charwidth */
378 long textwin_w = size * dwin->font.gc[0].spacewidth;
379 return textwin_w + 2 * prefs.textgrid.marginx;
380 }
381 else {
382 /* size * lineheight */
383 long textwin_h = size * dwin->font.lineheight;
384 return textwin_h + 2 * prefs.textgrid.marginy;
385 }
386 }
387
win_textgrid_get_fontset(window_t * win)388 fontset_t *win_textgrid_get_fontset(window_t *win)
389 {
390 window_textgrid_t *dwin = win->data;
391 return &(dwin->font);
392 }
393
win_textgrid_get_stylehints(window_t * win)394 stylehints_t *win_textgrid_get_stylehints(window_t *win)
395 {
396 window_textgrid_t *dwin = win->data;
397 return &(dwin->hints);
398 }
399
win_textgrid_rearrange(window_t * win,XRectangle * box)400 void win_textgrid_rearrange(window_t *win, XRectangle *box)
401 {
402 int wid, hgt;
403 window_textgrid_t *cutwin = win->data;
404
405 cutwin->bbox = *box;
406
407 cutwin->cbox.x = box->x + prefs.textgrid.marginx;
408 cutwin->cbox.width = box->width - 2 * prefs.textgrid.marginx;
409 cutwin->cbox.y = box->y + prefs.textgrid.marginy;
410 cutwin->cbox.height = box->height - 2 * prefs.textgrid.marginy;
411
412 wid = (cutwin->cbox.width) / cutwin->font.gc[0].spacewidth;
413 hgt = (cutwin->cbox.height) / cutwin->font.lineheight;
414 if (wid < 0)
415 wid = 0;
416 if (hgt < 0)
417 hgt = 0;
418
419 change_size(cutwin, wid, hgt);
420 }
421
win_textgrid_redraw(window_t * win)422 void win_textgrid_redraw(window_t *win)
423 {
424 window_textgrid_t *cutwin = win->data;
425
426 gli_draw_window_outline(&cutwin->bbox);
427
428 gli_draw_window_margin(&(cutwin->font.backcolor),
429 cutwin->bbox.x, cutwin->bbox.y,
430 cutwin->bbox.width, cutwin->bbox.height,
431 cutwin->cbox.x, cutwin->cbox.y,
432 cutwin->width * cutwin->font.gc[0].spacewidth,
433 cutwin->height * cutwin->font.lineheight);
434
435 win_textgrid_layout(cutwin, TRUE);
436 }
437
win_textgrid_setfocus(window_t * win,int turnon)438 void win_textgrid_setfocus(window_t *win, int turnon)
439 {
440 window_textgrid_t *cutwin = win->data;
441 if (turnon) {
442 if (!cutwin->isactive) {
443 cutwin->isactive = TRUE;
444 flip_selection(cutwin, &cutwin->dot);
445 }
446 }
447 else {
448 if (cutwin->isactive) {
449 flip_selection(cutwin, &cutwin->dot);
450 cutwin->isactive = FALSE;
451 }
452 }
453 }
454
win_textgrid_perform_click(window_t * win,int dir,XPoint * pt,int butnum,int clicknum,unsigned int state)455 void win_textgrid_perform_click(window_t *win, int dir, XPoint *pt,
456 int butnum, int clicknum, unsigned int state)
457 {
458 window_textgrid_t *cutwin = win->data;
459 XPoint posp, posp2;
460 long px, px2;
461 int ix;
462
463 if (dir == mouse_Down) {
464
465 find_pos_by_loc(cutwin, pt->x, pt->y, TRUE, &posp);
466 find_pos_by_loc(cutwin, pt->x, pt->y, FALSE, &posp2);
467
468 cutwin->drag_mouseevent = FALSE;
469 cutwin->drag_linkevent = FALSE;
470 if (cutwin->owner->mouse_request && butnum==1) {
471 cutwin->drag_mouseevent = TRUE;
472 cutwin->drag_linkpos.begline = posp2.y;
473 cutwin->drag_linkpos.begchar = posp2.x;
474 }
475 else if (cutwin->owner->hyperlink_request && butnum==1) {
476 sline_t *ln = &(cutwin->linelist[posp2.y]);
477 cutwin->drag_linkevent = TRUE;
478 cutwin->drag_linkid = 0;
479 cutwin->drag_linkpos.begline = posp2.y;
480 cutwin->drag_linkpos.begchar = posp2.x;
481 ix = find_style_at(ln, posp2.x, -1);
482 if (ix >= 0)
483 cutwin->drag_linkid = ln->attr[ix].linkid;
484 }
485
486 if (butnum==1) {
487 cutwin->dot.begline = posp.y;
488 cutwin->dot.begchar = posp.x;
489 cutwin->dot.endline = posp.y;
490 cutwin->dot.endchar = posp.x;
491 cutwin->drag_first = cutwin->dot;
492 }
493 else if (butnum==3) {
494 ix = compare_pos_to_dot(cutwin, &cutwin->dot, posp.x, posp.y);
495 if (ix == 0 || ix == 1) {
496 cutwin->drag_first.begline = cutwin->dot.endline;
497 cutwin->drag_first.begchar = cutwin->dot.endchar;
498 }
499 else {
500 cutwin->drag_first.begline = cutwin->dot.begline;
501 cutwin->drag_first.begchar = cutwin->dot.begchar;
502 }
503 cutwin->drag_first.endline = cutwin->drag_first.begline;
504 cutwin->drag_first.endchar = cutwin->drag_first.begchar;
505
506 ix = compare_pos_to_dot(cutwin, &cutwin->drag_first, posp.x, posp.y);
507 if (ix == 0) {
508 cutwin->dot.begline = posp.y;
509 cutwin->dot.begchar = posp.x;
510 cutwin->dot.endline = cutwin->drag_first.endline;
511 cutwin->dot.endchar = cutwin->drag_first.endchar;
512 }
513 else if (ix == 3) {
514 cutwin->dot.begline = cutwin->drag_first.begline;
515 cutwin->dot.begchar = cutwin->drag_first.begchar;
516 cutwin->dot.endline = posp.y;
517 cutwin->dot.endchar = posp.x;
518 }
519 else {
520 cutwin->dot = cutwin->drag_first;
521 }
522 }
523 win_textgrid_layout(cutwin, FALSE);
524 }
525 else if (dir == mouse_Move) {
526
527 find_pos_by_loc(cutwin, pt->x, pt->y, TRUE, &posp);
528 ix = compare_pos_to_dot(cutwin, &cutwin->drag_first, posp.x, posp.y);
529 if (ix == 0) {
530 cutwin->dot.begline = posp.y;
531 cutwin->dot.begchar = posp.x;
532 cutwin->dot.endline = cutwin->drag_first.endline;
533 cutwin->dot.endchar = cutwin->drag_first.endchar;
534 }
535 else if (ix == 3) {
536 cutwin->dot.begline = cutwin->drag_first.begline;
537 cutwin->dot.begchar = cutwin->drag_first.begchar;
538 cutwin->dot.endline = posp.y;
539 cutwin->dot.endchar = posp.x;
540 }
541 else {
542 cutwin->dot = cutwin->drag_first;
543 }
544 win_textgrid_layout(cutwin, FALSE);
545 }
546 else if (dir == mouse_Up) {
547 int singleclick = FALSE;
548 find_pos_by_loc(cutwin, pt->x, pt->y, TRUE, &posp);
549 if (posp.x == cutwin->drag_first.begchar
550 && posp.y == cutwin->drag_first.begline) {
551 singleclick = TRUE;
552 }
553
554 if (cutwin->drag_mouseevent) {
555 if (singleclick) {
556 cutwin->owner->mouse_request = FALSE;
557 eventloop_setevent(evtype_MouseInput, cutwin->owner,
558 cutwin->drag_linkpos.begchar, cutwin->drag_linkpos.begline);
559 return;
560 }
561 }
562
563 if (cutwin->drag_linkevent && cutwin->drag_linkid) {
564 if (singleclick) {
565 find_pos_by_loc(cutwin, pt->x, pt->y, FALSE, &posp);
566 cutwin->owner->hyperlink_request = FALSE;
567 eventloop_setevent(evtype_Hyperlink, cutwin->owner,
568 cutwin->drag_linkid, 0);
569 return;
570 }
571 }
572 }
573
574 }
575
win_textgrid_init_line(window_t * win,char * buffer,int buflen,int readpos)576 void win_textgrid_init_line(window_t *win, char *buffer, int buflen,
577 int readpos)
578 {
579 window_textgrid_t *cutwin = win->data;
580 int len;
581
582 len = cutwin->width - cutwin->cursorx;
583 if (buflen < len)
584 len = buflen;
585
586 cutwin->buflen = buflen;
587 cutwin->buffer = buffer;
588 cutwin->inputlen = 0;
589
590 cutwin->inputmaxlen = len;
591 cutwin->inputdot.begline = cutwin->cursory;
592 cutwin->inputdot.endline = cutwin->cursory;
593 cutwin->inputdot.begchar = cutwin->cursorx;
594 cutwin->inputdot.endchar = cutwin->inputdot.begchar + len;
595 cutwin->originalattr = cutwin->owner->style;
596 cutwin->owner->style = style_Input;
597
598 if (readpos) {
599 /* The terp has to enter the text. */
600 insert_input(cutwin, cutwin->inputdot.begchar, buffer, readpos);
601 win_textgrid_layout(cutwin, FALSE);
602 }
603
604 /*cutwin->historypos = cutwin->historynum;*/
605
606 if (gli_register_arr) {
607 cutwin->inarrayrock = (*gli_register_arr)(buffer, buflen, "&+#!Cn");
608 }
609 }
610
win_textgrid_cancel_line(window_t * win,event_t * ev)611 void win_textgrid_cancel_line(window_t *win, event_t *ev)
612 {
613 window_textgrid_t *cutwin = win->data;
614 xgrid_line_cancel(cutwin, ev);
615 }
616
find_pos_by_loc(window_textgrid_t * dwin,int xpos,int ypos,int addhalf,XPoint * res)617 static void find_pos_by_loc(window_textgrid_t *dwin, int xpos, int ypos,
618 int addhalf, XPoint *res)
619 {
620 int charwidth = dwin->font.gc[0].spacewidth;
621 int charheight = dwin->font.lineheight;
622
623 xpos -= dwin->cbox.x;
624 ypos -= dwin->cbox.y;
625
626 if (ypos < 0) {
627 res->x = 0;
628 res->y = 0;
629 return;
630 }
631 if (xpos < 0)
632 xpos = 0;
633
634 if (addhalf)
635 xpos += charwidth/2;
636 xpos = xpos / charwidth;
637 ypos = ypos / charheight;
638
639 if (xpos > dwin->width) {
640 xpos = dwin->width;
641 }
642 if (ypos >= dwin->height) {
643 ypos = dwin->height - 1;
644 xpos = dwin->width;
645 }
646
647 res->x = xpos;
648 res->y = ypos;
649 }
650
compare_pos_to_dot(window_textgrid_t * dwin,sdot_t * dot,int pchar,int pline)651 static int compare_pos_to_dot(window_textgrid_t *dwin, sdot_t *dot,
652 int pchar, int pline)
653 {
654 long pos, dotbeg, dotend;
655 long winwidth = dwin->width;
656
657 pos = (long)pline * winwidth + (long)pchar;
658 dotbeg = (long)dot->begline * winwidth + (long)dot->begchar;
659 dotend = (long)dot->endline * winwidth + (long)dot->endchar;
660
661 if (pos < dotbeg)
662 return 0;
663 if (pos >= dotend)
664 return 3;
665
666 if (pos < (dotbeg + dotend) / 2)
667 return 1;
668 else
669 return 2;
670 }
671
dot_contains_dot(window_textgrid_t * dwin,sdot_t * bigdot,sdot_t * dot)672 static int dot_contains_dot(window_textgrid_t *dwin, sdot_t *bigdot,
673 sdot_t *dot)
674 {
675 long bigdotbeg, bigdotend, dotbeg, dotend;
676 long winwidth = dwin->width;
677
678 if (!DOT_EXISTS(dot) || !DOT_EXISTS(bigdot))
679 return FALSE;
680
681 dotbeg = (long)dot->begline * winwidth + (long)dot->begchar;
682 dotend = (long)dot->endline * winwidth + (long)dot->endchar;
683 bigdotbeg = (long)bigdot->begline * winwidth + (long)bigdot->begchar;
684 bigdotend = (long)bigdot->endline * winwidth + (long)bigdot->endchar;
685
686 if (dotbeg < bigdotbeg || dotend > bigdotend)
687 return FALSE;
688 return TRUE;
689 }
690
flip_selection(window_textgrid_t * cutwin,sdot_t * dot)691 static void flip_selection(window_textgrid_t *cutwin, sdot_t *dot)
692 {
693 int charwidth = cutwin->font.gc[0].spacewidth;
694 int charheight = cutwin->font.lineheight;
695
696 if (!cutwin->isactive) {
697 return; /* not the front window */
698 }
699
700 if (dot->begline < 0 || dot->endline < 0) {
701 return; /* dot hidden */
702 }
703
704 if (DOT_LENGTH_ZERO(dot)) {
705 if (dot->begline < 0 || dot->begline >= cutwin->height) {
706 return;
707 }
708 xglk_draw_dot(cutwin->cbox.x + dot->begchar*charwidth,
709 cutwin->cbox.y + dot->begline*charheight + cutwin->font.lineoff,
710 cutwin->font.lineoff);
711 return;
712 }
713 else {
714 int xpos, ypos, xpos2, ypos2;
715 int cboxright = cutwin->cbox.x + cutwin->width * charwidth;
716 xpos = cutwin->cbox.x + dot->begchar*charwidth;
717 ypos = cutwin->cbox.y + dot->begline*charheight;
718 xpos2 = cutwin->cbox.x + dot->endchar*charwidth;
719 ypos2 = cutwin->cbox.y + dot->endline*charheight;
720 if (dot->begline == dot->endline) {
721 /* within one line */
722 if (dot->begchar != dot->endchar
723 && dot->begline >= 0 && dot->begline < cutwin->height) {
724 XFillRectangle(xiodpy, xiowin, gcflip, xpos, ypos, xpos2-xpos, charheight);
725 }
726 }
727 else {
728 if (dot->begchar < cutwin->width
729 && dot->begline >= 0 && dot->begline < cutwin->height) {
730 /* first partial line */
731 XFillRectangle(xiodpy, xiowin, gcflip, xpos, ypos,
732 cboxright - xpos, charheight);
733 }
734 if (dot->begline+1 < dot->endline
735 && dot->endline >= 0 && dot->begline+1 < cutwin->height) {
736 /* now, paint from begline+1 to the top of endline. */
737 int ybody = ypos+charheight;
738 int ybody2 = ypos2;
739 if (ybody < cutwin->cbox.y)
740 ybody = cutwin->cbox.y;
741 if (ybody2 > cutwin->cbox.y+cutwin->cbox.height)
742 ybody2 = cutwin->cbox.y+cutwin->cbox.height;
743 /* main body */
744 XFillRectangle(xiodpy, xiowin, gcflip, cutwin->cbox.x, ybody,
745 cboxright - cutwin->cbox.x, ybody2 - ybody);
746 }
747 if (dot->endchar > 0
748 && dot->endline >= 0 && dot->endline < cutwin->height) {
749 /* last partial line */
750 XFillRectangle(xiodpy, xiowin, gcflip, cutwin->cbox.x, ypos2,
751 xpos2 - cutwin->cbox.x, charheight);
752 }
753 }
754 }
755 }
756
refiddle_selection(window_textgrid_t * cutwin,sdot_t * olddot,sdot_t * newdot)757 static void refiddle_selection(window_textgrid_t *cutwin,
758 sdot_t *olddot, sdot_t *newdot)
759 {
760 sdot_t tmpdot;
761 int ix;
762
763 if (DOT_LENGTH_ZERO(olddot) || DOT_LENGTH_ZERO(newdot)
764 || olddot->begline < 0 || newdot->begline < 0) {
765 flip_selection(cutwin, olddot);
766 flip_selection(cutwin, newdot);
767 return;
768 }
769
770 if (olddot->begline == newdot->begline && olddot->begchar == newdot->begchar) {
771 /* start at same place */
772
773 if (olddot->endline == newdot->endline && olddot->endchar == newdot->endchar) {
774 /* identical! */
775 return;
776 }
777
778 ix = compare_pos_to_dot(cutwin, olddot, newdot->endchar, newdot->endline);
779 if (ix == 3) {
780 tmpdot.begline = olddot->endline;
781 tmpdot.begchar = olddot->endchar;
782 tmpdot.endline = newdot->endline;
783 tmpdot.endchar = newdot->endchar;
784 }
785 else {
786 tmpdot.begline = newdot->endline;
787 tmpdot.begchar = newdot->endchar;
788 tmpdot.endline = olddot->endline;
789 tmpdot.endchar = olddot->endchar;
790 }
791 flip_selection(cutwin, &tmpdot);
792 return;
793 }
794
795 if (olddot->endline == newdot->endline && olddot->endchar == newdot->endchar) {
796 /* end at same place */
797
798 ix = compare_pos_to_dot(cutwin, olddot, newdot->begchar, newdot->begline);
799 if (ix == 0) {
800 tmpdot.begline = newdot->begline;
801 tmpdot.begchar = newdot->begchar;
802 tmpdot.endline = olddot->begline;
803 tmpdot.endchar = olddot->begchar;
804 }
805 else {
806 tmpdot.begline = olddot->begline;
807 tmpdot.begchar = olddot->begchar;
808 tmpdot.endline = newdot->begline;
809 tmpdot.endchar = newdot->begchar;
810 }
811 flip_selection(cutwin, &tmpdot);
812 return;
813 }
814
815 flip_selection(cutwin, olddot);
816 flip_selection(cutwin, newdot);
817 }
818
win_textgrid_layout(window_textgrid_t * cutwin,int drawall)819 static void win_textgrid_layout(window_textgrid_t *cutwin, int drawall)
820 {
821 int ix, ix2, jx, sx;
822 int startln, endln, startchar, endchar;
823 sattr_t *attr;
824
825 int charwidth = cutwin->font.gc[0].spacewidth;
826 int charheight = cutwin->font.lineheight;
827 fontref_t *gclist = cutwin->font.gc;
828
829 if (drawall) {
830 startln = 0;
831 endln = cutwin->height;
832 }
833 else {
834 if (cutwin->dirtybeg < 0 || cutwin->dirtyend < 0) {
835 startln = 0;
836 endln = 0;
837 }
838 else {
839 startln = cutwin->dirtybeg;
840 endln = cutwin->dirtyend;
841 if (endln > cutwin->height)
842 endln = cutwin->height;
843 }
844 }
845
846 if (startln >= endln) {
847 /* no text changes */
848 if (cutwin->lastdot.begline != cutwin->dot.begline
849 || cutwin->lastdot.begchar != cutwin->dot.begchar
850 || cutwin->lastdot.endline != cutwin->dot.endline
851 || cutwin->lastdot.endchar != cutwin->dot.endchar) {
852 refiddle_selection(cutwin, &cutwin->lastdot, &cutwin->dot);
853 cutwin->lastdot = cutwin->dot;
854 }
855 return;
856 }
857
858 /* flip dot off */
859 flip_selection(cutwin, &cutwin->lastdot);
860 cutwin->lastdot = cutwin->dot;
861
862 for (jx = startln; jx < endln; jx++) {
863 sline_t *ln = &(cutwin->linelist[jx]);
864
865 if (drawall) {
866 startchar = 0;
867 endchar = cutwin->width;
868 }
869 else {
870 if (ln->dirtybeg < 0 || ln->dirtyend < 0)
871 continue;
872 startchar = ln->dirtybeg;
873 endchar = ln->dirtyend;
874 if (endchar > cutwin->width)
875 endchar = cutwin->width;
876 }
877
878 ix = startchar;
879 sx = find_style_at(ln, ix, 0);
880 while (ix < endchar) {
881 if (sx >= 0 && sx < ln->numattr) {
882 attr = &(ln->attr[sx]);
883 ix2 = attr->end;
884 }
885 else {
886 attr = NULL;
887 ix2 = cutwin->width;
888 }
889 if (ix2 > endchar)
890 ix2 = endchar;
891
892 if (!attr || attr->blank) {
893 /* ### This may screw up styled whitespace (bkcolors) ### */
894 xglk_clearfor_string(&(cutwin->font.backcolor),
895 cutwin->cbox.x+ix*charwidth,
896 cutwin->cbox.y+jx*charheight,
897 (ix2-ix)*charwidth, charheight);
898 }
899 else {
900 xglk_clearfor_string(&(gclist[attr->style].backcolor),
901 cutwin->cbox.x+ix*charwidth,
902 cutwin->cbox.y+jx*charheight,
903 (ix2-ix)*charwidth, charheight);
904 xglk_draw_string(&(gclist[attr->style]),
905 (attr->linkid != 0), (ix2-ix)*charwidth,
906 cutwin->cbox.x+ix*charwidth,
907 cutwin->cbox.y+jx*charheight+cutwin->font.lineoff,
908 ln->text+ix, (ix2-ix));
909 }
910
911 ix = ix2;
912 sx++;
913 }
914
915 ln->dirtybeg = -1;
916 ln->dirtyend = -1;
917 }
918
919 cutwin->dirtybeg = -1;
920 cutwin->dirtyend = -1;
921
922 /* flip dot back on */
923 flip_selection(cutwin, &cutwin->lastdot);
924 }
925
win_textgrid_add(window_textgrid_t * cutwin,char ch)926 void win_textgrid_add(window_textgrid_t *cutwin, char ch)
927 {
928 sline_t *ln;
929 sattr_t *oattr;
930 int sx, sx2, ix, pos;
931
932 if (cutwin->cursorx >= cutwin->width) {
933 cutwin->cursorx = 0;
934 cutwin->cursory++;
935 }
936 if (cutwin->cursory >= cutwin->height)
937 return;
938
939 if (ch == '\n') {
940 cutwin->cursorx = 0;
941 cutwin->cursory++;
942 return;
943 }
944
945 if (cutwin->dirtybeg < 0 || cutwin->dirtybeg > cutwin->cursory)
946 cutwin->dirtybeg = cutwin->cursory;
947 if (cutwin->dirtyend < 0 || cutwin->dirtyend < cutwin->cursory+1)
948 cutwin->dirtyend = cutwin->cursory+1;
949 ln = &(cutwin->linelist[cutwin->cursory]);
950
951 pos = cutwin->cursorx;
952 if (ln->dirtybeg < 0 || ln->dirtybeg > pos)
953 ln->dirtybeg = pos;
954 if (ln->dirtyend < 0 || ln->dirtyend < pos+1)
955 ln->dirtyend = pos+1;
956
957 sx = find_style_at(ln, pos, -1);
958
959 if (sx >= 0 && sx < ln->numattr) {
960 oattr = &(ln->attr[sx]);
961 }
962 else {
963 oattr = NULL;
964 sx = ln->numattr;
965 }
966
967 if (oattr && !oattr->blank && ATTRMATCH(oattr, cutwin->owner)) {
968 /* within a matching style; leave alone */
969 }
970 else {
971 /* within non-matching style */
972 sattr_t *lattr, *nattr;
973 int lastendat, curendat;
974 if (sx == 0) {
975 lattr = NULL;
976 lastendat = 0;
977 }
978 else {
979 lattr = &(ln->attr[sx-1]);
980 lastendat = lattr->end;
981 }
982 if (oattr)
983 curendat = oattr->end;
984 else
985 curendat = cutwin->width + 10;
986 nattr = NULL;
987 if (pos == lastendat && pos == curendat-1) {
988 /* current has length 1; replace. (current is not NULL) */
989 sattr_t *fattr;
990 if (sx+1 < ln->numattr)
991 fattr = &(ln->attr[sx+1]);
992 else
993 fattr = NULL;
994 if (lattr && !lattr->blank && ATTRMATCH(lattr, cutwin->owner)) {
995 if (fattr && !fattr->blank && ATTRMATCH(fattr, cutwin->owner)) {
996 /* no, delete current *and* previous, fall into next */
997 delete_style(ln, sx-1, 2);
998 }
999 else {
1000 /* no, delete current and extend previous. */
1001 delete_style(ln, sx, 1);
1002 lattr = &(ln->attr[sx-1]);
1003 lattr->end = pos+1;
1004 }
1005 nattr = NULL;
1006 }
1007 else if (fattr && !fattr->blank && ATTRMATCH(fattr, cutwin->owner)) {
1008 /* no, delete current and fall into next */
1009 delete_style(ln, sx, 1);
1010 nattr = NULL;
1011 }
1012 else {
1013 nattr = oattr;
1014 /* nattr->end unchanged */
1015 }
1016 }
1017 else if (pos == lastendat) {
1018 /* insert at beginning, or extend previous */
1019 if (lattr && !lattr->blank && ATTRMATCH(lattr, cutwin->owner)) {
1020 /* extend previous */
1021 lattr->end = pos+1; /* that is, += 1 */
1022 nattr = NULL;
1023 }
1024 else {
1025 /* insert at beginning */
1026 insert_style(ln, sx, 1);
1027 nattr = &(ln->attr[sx]);
1028 nattr->end = pos+1;
1029 }
1030 }
1031 else if (pos == curendat-1) {
1032 /* insert at end, or retract current. (current is not NULL) */
1033 sattr_t *fattr;
1034 if (sx+1 < ln->numattr)
1035 fattr = &(ln->attr[sx+1]);
1036 else
1037 fattr = NULL;
1038 if (fattr && !fattr->blank && ATTRMATCH(fattr, cutwin->owner)) {
1039 /* retract current, put char in next */
1040 oattr->end = pos; /* that is, -= 1 */
1041 nattr = NULL;
1042 }
1043 else {
1044 /* retract current, insert at end */
1045 oattr->end = pos; /* that is, -= 1 */
1046 insert_style(ln, sx+1, 1);
1047 nattr = &(ln->attr[sx+1]);
1048 nattr->end = pos+1;
1049 }
1050 }
1051 else {
1052 /* split current (or current NULL) */
1053 if (oattr) {
1054 insert_style(ln, sx, 2);
1055 ln->attr[sx] = ln->attr[sx+2];
1056 ln->attr[sx].end = pos;
1057 nattr = &(ln->attr[sx+1]);
1058 nattr->end = pos+1;
1059 }
1060 else {
1061 insert_style(ln, ln->numattr, 2);
1062 nattr = &(ln->attr[ln->numattr-2]);
1063 nattr->blank = TRUE;
1064 nattr->style = 0;
1065 nattr->linkid = 0;
1066 nattr->end = pos;
1067 nattr++; /* new last attr */
1068 nattr->end = pos+1;
1069 }
1070 }
1071
1072 if (nattr) {
1073 nattr->blank = FALSE;
1074 nattr->style = cutwin->owner->style;
1075 nattr->linkid = cutwin->owner->linkid;
1076 }
1077 }
1078
1079 ln->text[pos] = ch;
1080 cutwin->cursorx++;
1081 /* note that this can leave the cursor out-of-bounds. It's handled at the
1082 beginning of this function. */
1083 }
1084
win_textgrid_set_pos(window_textgrid_t * cutwin,glui32 xpos,glui32 ypos)1085 void win_textgrid_set_pos(window_textgrid_t *cutwin, glui32 xpos, glui32 ypos)
1086 {
1087 if (xpos > 32767)
1088 xpos = 32767;
1089 if (ypos > 32767)
1090 ypos = 32767;
1091 cutwin->cursorx = xpos;
1092 cutwin->cursory = ypos;
1093 }
1094
win_textgrid_clear_window(window_textgrid_t * cutwin)1095 void win_textgrid_clear_window(window_textgrid_t *cutwin)
1096 {
1097 int ix;
1098
1099 for (ix=0; ix<cutwin->height; ix++) {
1100 sline_t *ln;
1101 ln = &(cutwin->linelist[ix]);
1102 ln->numattr = 0;
1103 ln->dirtybeg = 0;
1104 ln->dirtyend = cutwin->width;
1105 }
1106
1107 cutwin->dirtybeg = 0;
1108 cutwin->dirtyend = cutwin->height;
1109
1110 cutwin->cursorx = 0;
1111 cutwin->cursory = 0;
1112 }
1113
insert_input(window_textgrid_t * cutwin,int pos,char * buf,int len)1114 static void insert_input(window_textgrid_t *cutwin,
1115 int pos, char *buf, int len)
1116 {
1117 int ix, left;
1118 sline_t *ln = &cutwin->linelist[cutwin->inputdot.begline];
1119
1120 if (cutwin->inputlen >= cutwin->inputmaxlen) {
1121 cutwin->dot.begchar = pos;
1122 cutwin->dot.begline = cutwin->inputdot.begline;
1123 collapse_dot_back(cutwin);
1124 return;
1125 }
1126 if (pos > cutwin->inputdot.begchar + cutwin->inputlen) {
1127 pos = cutwin->inputdot.begchar + cutwin->inputlen;
1128 }
1129 if (len > cutwin->inputmaxlen - cutwin->inputlen) {
1130 len = cutwin->inputmaxlen - cutwin->inputlen;
1131 }
1132
1133 for (ix = cutwin->inputdot.begchar + cutwin->inputlen + len - 1;
1134 ix >= pos + len;
1135 ix--) {
1136 cutwin->cursorx = ix;
1137 win_textgrid_add(cutwin, ln->text[ix-len]);
1138 }
1139 for (; ix >= pos; ix--) {
1140 cutwin->cursorx = ix;
1141 win_textgrid_add(cutwin, buf[ix-pos]);
1142 cutwin->inputlen++;
1143 }
1144
1145 cutwin->dot.begchar = pos+len;
1146 cutwin->dot.begline = cutwin->inputdot.begline;
1147 collapse_dot_back(cutwin);
1148 }
1149
kill_input(window_textgrid_t * cutwin,int beg,int end)1150 static void kill_input(window_textgrid_t *cutwin, int beg, int end)
1151 {
1152 int diff, post;
1153 int pos;
1154 sline_t *ln = &cutwin->linelist[cutwin->inputdot.begline];
1155
1156 if (beg < cutwin->inputdot.begchar)
1157 beg = cutwin->inputdot.begchar;
1158 if (end > cutwin->inputdot.begchar + cutwin->inputlen)
1159 end = cutwin->inputdot.begchar + cutwin->inputlen;
1160
1161 if (end <= beg)
1162 return;
1163 diff = end - beg;
1164 post = (cutwin->inputdot.begchar + cutwin->inputlen) - end;
1165 cutwin->cursorx = beg;
1166 cutwin->cursory = cutwin->inputdot.begline;
1167 for (pos = beg; pos < beg+post; pos++) {
1168 win_textgrid_add(cutwin, ln->text[pos+diff]);
1169 }
1170 for (; pos < end+post; pos++) {
1171 win_textgrid_add(cutwin, ' ');
1172 }
1173
1174 cutwin->inputlen -= diff;
1175
1176 cutwin->dot.begchar = beg;
1177 cutwin->dot.begline = cutwin->inputdot.begline;
1178 collapse_dot_back(cutwin);
1179 }
1180
xgrid_line_cancel(window_textgrid_t * cutwin,event_t * ev)1181 static void xgrid_line_cancel(window_textgrid_t *cutwin, event_t *ev)
1182 {
1183 long ix, len2;
1184 long inputlen;
1185 sline_t *ln;
1186 long buflen;
1187 char *buffer;
1188 gidispatch_rock_t inarrayrock;
1189
1190 /* same as xged_enter(), but skip the unnecessary stuff. */
1191
1192 if (!cutwin->buffer)
1193 return;
1194
1195 buffer = cutwin->buffer;
1196 buflen = cutwin->buflen;
1197 inarrayrock = cutwin->inarrayrock;
1198
1199 ln = &cutwin->linelist[cutwin->inputdot.begline];
1200
1201 cutwin->owner->style = cutwin->originalattr;
1202
1203 inputlen = cutwin->inputlen;
1204 /*if (inputlen > buflen)
1205 inputlen = buflen;
1206 memmove(buffer, ln->text+cutwin->inputdot.begchar, inputlen*sizeof(char));*/
1207
1208 len2 = 0;
1209 for (ix=0; ix < inputlen && len2 < buflen; ix++) {
1210 /* We could convert input to Latin-1, but we're assuming that the
1211 input *is* Latin-1. */
1212 unsigned char ch = ln->text[cutwin->inputdot.begchar+ix];
1213 buffer[len2] = ch;
1214 len2++;
1215 }
1216
1217 /*len = cutwin->numchars - cutwin->inputfence;
1218 if (len) {
1219 xtext_replace(cutwin->inputfence, len, "", 0);
1220 cutwin->dotpos = cutwin->numchars;
1221 cutwin->dotlen = 0;
1222 xtext_layout();
1223 }*/
1224
1225 if (cutwin->owner->echostr) {
1226 window_t *oldwin = cutwin->owner;
1227 /*gli_stream_echo_line(cutwin->owner->echostr,
1228 ln->text+cutwin->inputdot.begchar, cutwin->inputlen*sizeof(char));*/
1229 gli_stream_echo_line(cutwin->owner->echostr,
1230 buffer, len2*sizeof(char));
1231 }
1232
1233 cutwin->cursorx = 0;
1234 cutwin->cursory = cutwin->inputdot.begline + 1;
1235 win_textgrid_layout(cutwin, FALSE);
1236
1237 /* create event, and set everything blank. */
1238 ev->type = evtype_LineInput;
1239 ev->val1 = len2;
1240 ev->val2 = 0;
1241 ev->win = cutwin->owner;
1242 cutwin->owner->line_request = FALSE;
1243 cutwin->buffer = NULL;
1244 cutwin->buflen = 0;
1245
1246 if (gli_unregister_arr) {
1247 (*gli_unregister_arr)(buffer, buflen, "&+#!Cn", inarrayrock);
1248 }
1249 }
1250
xgc_grid_getchar(window_textgrid_t * cutwin,int ch)1251 void xgc_grid_getchar(window_textgrid_t *cutwin, int ch)
1252 {
1253 if (cutwin->owner->char_request) {
1254 glui32 key = ch;
1255 eventloop_setevent(evtype_CharInput, cutwin->owner, key, 0);
1256 cutwin->owner->char_request = FALSE;
1257 }
1258 }
1259
xgc_grid_movecursor(window_textgrid_t * cutwin,int op)1260 void xgc_grid_movecursor(window_textgrid_t *cutwin, int op)
1261 {
1262 long pos;
1263
1264 switch (op) {
1265 case op_BackChar:
1266 if (DOT_LENGTH_ZERO(&cutwin->dot)) {
1267 if (cutwin->dot.begchar > 0) {
1268 cutwin->dot.begchar--;
1269 collapse_dot_back(cutwin);
1270 }
1271 else {
1272 if (cutwin->dot.begline > 0) {
1273 cutwin->dot.begchar = cutwin->width;
1274 cutwin->dot.begline--;
1275 }
1276 else {
1277 cutwin->dot.begchar = 0;
1278 cutwin->dot.begline = 0;
1279 }
1280 collapse_dot_back(cutwin);
1281 }
1282 }
1283 else if (!DOT_EXISTS(&cutwin->dot)) {
1284 cutwin->dot.begline = 0;
1285 cutwin->dot.begchar = 0;
1286 collapse_dot_back(cutwin);
1287 }
1288 else {
1289 collapse_dot_back(cutwin);
1290 }
1291 break;
1292 case op_ForeChar:
1293 if (DOT_LENGTH_ZERO(&cutwin->dot)) {
1294 if (cutwin->dot.begchar < cutwin->width) {
1295 cutwin->dot.begchar++;
1296 collapse_dot_back(cutwin);
1297 }
1298 else {
1299 if (cutwin->dot.begline < cutwin->height-1) {
1300 cutwin->dot.begchar = 0;
1301 cutwin->dot.begline++;
1302 }
1303 else {
1304 cutwin->dot.begchar = cutwin->width;
1305 cutwin->dot.begline = cutwin->height-1;
1306 }
1307 collapse_dot_back(cutwin);
1308 }
1309 }
1310 else if (!DOT_EXISTS(&cutwin->dot)) {
1311 cutwin->dot.begline = 0;
1312 cutwin->dot.begchar = 0;
1313 collapse_dot_back(cutwin);
1314 }
1315 else {
1316 collapse_dot(cutwin);
1317 }
1318 break;
1319 case op_BeginLine:
1320 if (cutwin->buffer) {
1321 cutwin->dot.begline = cutwin->inputdot.begline;
1322 cutwin->dot.begchar = cutwin->inputdot.begchar;
1323 collapse_dot_back(cutwin);
1324 }
1325 else {
1326 if (DOT_EXISTS(&cutwin->dot)) {
1327 cutwin->dot.begchar = 0;
1328 collapse_dot_back(cutwin);
1329 }
1330 }
1331 break;
1332 case op_EndLine:
1333 if (cutwin->buffer) {
1334 cutwin->dot.begline = cutwin->inputdot.begline;
1335 cutwin->dot.begchar = cutwin->inputdot.begchar + cutwin->inputlen;
1336 collapse_dot_back(cutwin);
1337 }
1338 else {
1339 if (DOT_EXISTS(&cutwin->dot)) {
1340 cutwin->dot.begchar = cutwin->width;
1341 collapse_dot_back(cutwin);
1342 }
1343 }
1344 break;
1345 }
1346
1347 win_textgrid_layout(cutwin, FALSE);
1348 }
1349
xgc_grid_insert(window_textgrid_t * cutwin,int ch)1350 void xgc_grid_insert(window_textgrid_t *cutwin, int ch)
1351 {
1352 char realch;
1353 int ix, pos;
1354
1355 /* ### not perfect -- should be all typable chars */
1356 if (ch < 32 || ch >= 127)
1357 ch = ' ';
1358
1359 realch = ch;
1360
1361 if (!DOT_EXISTS(&cutwin->dot)) {
1362 cutwin->dot.begline = 0;
1363 cutwin->dot.begchar = 0;
1364 collapse_dot_back(cutwin);
1365 }
1366
1367 if (!DOT_LENGTH_ZERO(&cutwin->dot)) {
1368 kill_input(cutwin, cutwin->dot.begchar, cutwin->dot.endchar);
1369 collapse_dot_back(cutwin);
1370 }
1371
1372 ix = compare_pos_to_dot(cutwin, &cutwin->inputdot, cutwin->dot.begchar, cutwin->dot.begline);
1373 if (ix == 0) {
1374 pos = cutwin->inputdot.begchar;
1375 }
1376 else if (ix == 3) {
1377 pos = cutwin->inputdot.begchar + cutwin->inputlen;
1378 }
1379 else {
1380 pos = cutwin->dot.begchar;
1381 if (pos > cutwin->inputdot.begchar + cutwin->inputlen)
1382 pos = cutwin->inputdot.begchar + cutwin->inputlen;
1383 }
1384 cutwin->cursory = cutwin->inputdot.begline;
1385
1386 insert_input(cutwin, pos, &realch, 1);
1387
1388 win_textgrid_layout(cutwin, FALSE);
1389 }
1390
xgc_grid_delete(window_textgrid_t * cutwin,int op)1391 void xgc_grid_delete(window_textgrid_t *cutwin, int op)
1392 {
1393 if (!DOT_EXISTS(&cutwin->dot))
1394 return;
1395
1396 if (!dot_contains_dot(cutwin, &cutwin->inputdot, &cutwin->dot))
1397 return;
1398
1399 if (cutwin->dot.endline > cutwin->inputdot.begline
1400 || cutwin->dot.endchar > cutwin->inputdot.begchar + cutwin->inputmaxlen) {
1401 cutwin->dot.endline = cutwin->inputdot.begline;
1402 cutwin->dot.endchar = cutwin->inputdot.begchar + cutwin->inputmaxlen;
1403 }
1404
1405 if (!DOT_LENGTH_ZERO(&cutwin->dot)
1406 && (op == op_BackChar || op == op_ForeChar)) {
1407 kill_input(cutwin, cutwin->dot.begchar, cutwin->dot.endchar);
1408 win_textgrid_layout(cutwin, FALSE);
1409 return;
1410 }
1411
1412 collapse_dot(cutwin);
1413
1414 switch (op) {
1415 case op_BackChar:
1416 if (cutwin->dot.begchar > cutwin->inputdot.begchar)
1417 kill_input(cutwin, cutwin->dot.begchar-1, cutwin->dot.begchar);
1418 break;
1419 case op_ForeChar:
1420 kill_input(cutwin, cutwin->dot.begchar, cutwin->dot.begchar+1);
1421 break;
1422 }
1423
1424 win_textgrid_layout(cutwin, FALSE);
1425 }
1426
xgrid_alloc_selection(window_textgrid_t * cutwin,sdot_t * dot,long * lenv)1427 static char *xgrid_alloc_selection(window_textgrid_t *cutwin,
1428 sdot_t *dot, long *lenv)
1429 {
1430 long len, cx;
1431 int jx, sx;
1432 char *res;
1433
1434 if (!DOT_EXISTS(dot) || DOT_LENGTH_ZERO(dot))
1435 return NULL;
1436
1437 len = (dot->endline - dot->begline + 1) * (cutwin->width + 1) + 1;
1438 res = malloc(len);
1439 if (!res)
1440 return NULL;
1441
1442 cx = 0;
1443
1444 for (jx = dot->begline; jx <= dot->endline; jx++) {
1445 int begchar, endchar;
1446 sline_t *ln = &(cutwin->linelist[jx]);
1447
1448 if (jx == dot->begline)
1449 begchar = dot->begchar;
1450 else
1451 begchar = 0;
1452 if (jx == dot->endline)
1453 endchar = dot->endchar;
1454 else
1455 endchar = cutwin->width;
1456
1457 if (endchar >= begchar) {
1458 int ix, ix2;
1459 sattr_t *attr;
1460 ix = begchar;
1461 sx = find_style_at(ln, ix, 0);
1462 while (ix < endchar) {
1463 if (sx >= 0 && sx < ln->numattr) {
1464 attr = &(ln->attr[sx]);
1465 ix2 = attr->end;
1466 }
1467 else {
1468 attr = NULL;
1469 ix2 = cutwin->width;
1470 }
1471 if (ix2 > endchar)
1472 ix2 = endchar;
1473
1474 if (!attr || attr->blank) {
1475 int ix3;
1476 if (!attr || sx == ln->numattr-1) {
1477 /* skip trailing blanks */
1478 }
1479 else {
1480 for (ix3 = ix; ix3 < ix2; ix3++) {
1481 res[cx] = ' ';
1482 cx++;
1483 }
1484 }
1485 }
1486 else {
1487 memcpy(res+cx, ln->text + ix, ix2 - ix);
1488 cx += (ix2 - ix);
1489 }
1490
1491 ix = ix2;
1492 sx++;
1493 }
1494
1495 if (jx < dot->endline) {
1496 res[cx] = '\n';
1497 cx++;
1498 }
1499 }
1500 }
1501
1502 if (cx > len) {
1503 gli_strict_warning("xgrid_alloc_selection: overran allocation");
1504 }
1505
1506 *lenv = cx;
1507 return res;
1508 }
1509
xgc_grid_cutbuf(window_textgrid_t * cutwin,int op)1510 void xgc_grid_cutbuf(window_textgrid_t *cutwin, int op)
1511 {
1512 long len, num;
1513 char *buf, *cx;
1514
1515 if (op != op_Copy) {
1516 if (!cutwin->buffer) {
1517 xmsg_set_message("You are not editing input in this window.", FALSE);
1518 return;
1519 }
1520 }
1521
1522 switch (op) {
1523 case op_Copy:
1524 buf = xgrid_alloc_selection(cutwin, &cutwin->dot, &len);
1525 if (buf) {
1526 xglk_store_scrap(buf, len);
1527 free(buf);
1528 }
1529 break;
1530 case op_Wipe:
1531 buf = xgrid_alloc_selection(cutwin, &cutwin->dot, &len);
1532 if (buf) {
1533 xglk_store_scrap(buf, len);
1534 free(buf);
1535 }
1536 if (dot_contains_dot(cutwin, &cutwin->inputdot, &cutwin->dot)) {
1537 if (!DOT_LENGTH_ZERO(&cutwin->dot)) {
1538 kill_input(cutwin, cutwin->dot.begchar, cutwin->dot.endchar);
1539 }
1540 }
1541 break;
1542 case op_Erase:
1543 if (dot_contains_dot(cutwin, &cutwin->inputdot, &cutwin->dot)) {
1544 if (!DOT_LENGTH_ZERO(&cutwin->dot)) {
1545 kill_input(cutwin, cutwin->dot.begchar, cutwin->dot.endchar);
1546 }
1547 }
1548 break;
1549 case op_YankReplace:
1550 if (!dot_contains_dot(cutwin, &cutwin->inputdot, &cutwin->dot))
1551 break;
1552 xglk_fetch_scrap(&cx, &num);
1553 xglk_strip_garbage(cx, num);
1554 if (cx && num) {
1555 if (!DOT_LENGTH_ZERO(&cutwin->dot)) {
1556 kill_input(cutwin, cutwin->dot.begchar, cutwin->dot.endchar);
1557 }
1558 insert_input(cutwin, cutwin->dot.begchar, cx, num);
1559 free(cx);
1560 }
1561 break;
1562 case op_Untype:
1563 if (cutwin->inputlen > 0) {
1564 kill_input(cutwin, cutwin->inputdot.begchar,
1565 cutwin->inputdot.begchar + cutwin->inputlen);
1566 }
1567 break;
1568 }
1569
1570 win_textgrid_layout(cutwin, FALSE);
1571 }
1572
xgc_grid_enter(window_textgrid_t * cutwin,int op)1573 void xgc_grid_enter(window_textgrid_t *cutwin, int op)
1574 {
1575 long ix, len2, inputlen;
1576 sline_t *ln;
1577 long buflen;
1578 char *buffer;
1579 gidispatch_rock_t inarrayrock;
1580
1581 if (op != op_Enter)
1582 return;
1583
1584 if (!cutwin->buffer)
1585 return;
1586
1587 buffer = cutwin->buffer;
1588 buflen = cutwin->buflen;
1589 inarrayrock = cutwin->inarrayrock;
1590
1591 ln = &cutwin->linelist[cutwin->inputdot.begline];
1592
1593 cutwin->owner->style = cutwin->originalattr;
1594
1595 inputlen = cutwin->inputlen;
1596 /*if (inputlen > buflen)
1597 inputlen = buflen;
1598 memmove(buffer, ln->text+cutwin->inputdot.begchar, inputlen*sizeof(char));*/
1599
1600 len2 = 0;
1601 for (ix=0; ix < inputlen && len2 < buflen; ix++) {
1602 unsigned char ch = ln->text[cutwin->inputdot.begchar+ix];
1603 buffer[len2] = ch;
1604 len2++;
1605 }
1606
1607 /*if (len) {
1608 if (cutwin->historynum==cutwin->historylength) {
1609 free(cutwin->history[0].str);
1610 memmove(&cutwin->history[0], &cutwin->history[1], (cutwin->historylength-1) * (sizeof(histunit)));
1611 }
1612 else
1613 cutwin->historynum++;
1614 cutwin->history[cutwin->historynum-1].str = malloc(len*sizeof(char));
1615 memmove(cutwin->history[cutwin->historynum-1].str, cutwin->charbuf+cutwin->inputfence, len*sizeof(char));
1616 cutwin->history[cutwin->historynum-1].len = len;
1617 }*/
1618
1619 if (cutwin->owner->echostr) {
1620 window_t *oldwin = cutwin->owner;
1621 gli_stream_echo_line(cutwin->owner->echostr,
1622 buffer, len2*sizeof(char));
1623 }
1624
1625 cutwin->dot.begline = cutwin->inputdot.begline;
1626 cutwin->dot.begchar = cutwin->inputdot.begchar + inputlen;
1627 collapse_dot_back(cutwin);
1628 cutwin->cursorx = 0;
1629 cutwin->cursory = cutwin->inputdot.begline + 1;
1630 win_textgrid_layout(cutwin, FALSE);
1631
1632 eventloop_setevent(evtype_LineInput, cutwin->owner, len2, 0);
1633 cutwin->owner->line_request = FALSE;
1634 cutwin->buffer = NULL;
1635 cutwin->buflen = 0;
1636
1637 if (gli_unregister_arr) {
1638 (*gli_unregister_arr)(buffer, buflen, "&+#!Cn", inarrayrock);
1639 }
1640
1641 }
1642
1643