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