1 #include <stdio.h>
2 #include <ctype.h>
3 #include <X11/Xlib.h>
4 #include <X11/Xutil.h>
5
6 #include "ztypes.h"
7 #include "xio.h"
8
9 static char *charbuf;
10 static long numchars;
11 static long char_size;
12
13 typedef struct style_t {
14 int attr; /* flags are REVERSE, BOLD, EMPHASIS, FIXED_FONT */
15 long pos; /* position this style starts at */
16 } style;
17
18 static style *stylelist;
19 static long numstyles;
20 static long styles_size;
21
22 typedef struct word_t {
23 long pos, len;
24 long width; /* in pixels */
25 int attr;
26
27 long *letterpos; /* if not NULL, an array[0..len] of pixel offsets from wordpos; */
28 } word;
29
30 #define lineflag_Wrapped (1) /* line is a wrap or split from previous line */
31 #define lineflag_Extra (2) /* the magic extra line on the end */
32
33 typedef struct line_t {
34 long pos; /* line starts here */
35 long posend; /* number of chars. May not be exactly to start of next line, because it won't include the newline or space that ends the line. */
36 word *wordlist;
37 long numwords;
38 int flags;
39 } lline;
40
41 static lline *linelist;
42 static long numlines;
43 static long lines_size;
44
45 static lline *tmplinelist;
46 static long tmplines_size;
47
48 static long scrollpos; /* character position at top of screen */
49 static long scrollline; /* number of line at top of screen, after xtext_layout() */
50 static long lastlineseen; /* last line read before more stuff was output. (-1) to indicate all lines read. */
51 static long dotpos, dotlen; /* dotpos is in [0..numchars] */
52 static long lastdotpos = (-1), lastdotlen = 0; /* cached values -- fiddled inside xtext_layout() */
53
54 static long dirtybeg, dirtyend; /* mark the limits of what needs to be laid out, [) format */
55 static long dirtydelta; /* how much the dirty area has grown (or shrunk) */
56 static long startlay; /* pos of the char that starts the first laid-out line. */
57
58 static int textwin_x, textwin_y, textwin_w, textwin_h;
59 static int scrollwin_x, scrollwin_y, scrollwin_w, scrollwin_h;
60 static int scrollel_top, scrollel_bot;
61
62 typedef struct histunit {
63 char *str;
64 int len;
65 } histunit;
66 static int historynum, historypos;
67 static histunit *history;
68
69 /* these are for xtext editing */
70 static int buflen;
71 static char *buffer;
72 static int *readpos;
73 static long inputfence;
74 static int *killflag;
75 static int originalattr;
76
77 #define collapse_dot() (dotpos += dotlen, dotlen = 0)
78 #define SIDEMARGIN (4)
79 #define BARENDHEIGHT (12)
80 #define BARWIDTH (17)
81 #define BAREXTRA (4)
82
83 static XPoint polydot[3];
84 static long linesperpage;
85
86 #ifdef __STDC__
87 static void redrawtext(long beg, long num, int clearnum);
88 static void flip_selection(long dpos, long dlen);
89 static void find_loc_by_pos(long pos, int *xposret, int *yposret);
90 static long find_pos_by_loc(int xpos, int ypos);
91 static long find_line_by_pos(long pos, long guessline);
92 static void measure_word(lline *curline, word *curword);
93 static void adjust_elevator();
94 void xtext_delete_start(long num);
95 #else
96 static void redrawtext();
97 static void flip_selection();
98 static void find_loc_by_pos();
99 static long find_pos_by_loc();
100 static long find_line_by_pos();
101 static void measure_word();
102 static void adjust_elevator();
103 void xtext_delete_start();
104 #endif
105
106
107 #ifdef __STDC__
xtext_init()108 void xtext_init()
109 #else
110 void xtext_init()
111 #endif
112 {
113 char_size = 256;
114 charbuf = (char *)malloc(sizeof(char) * char_size);
115 numchars = 0;
116
117 styles_size = 8;
118 stylelist = (style *)malloc(sizeof(style) * styles_size);
119 numstyles = 1;
120 stylelist[0].pos = 0;
121 stylelist[0].attr = 0; /* NORMAL style */
122
123 lines_size = 8;
124 linelist = (lline *)malloc(sizeof(lline) * lines_size);
125 numlines = 0;
126
127 tmplines_size = 8;
128 tmplinelist = (lline *)malloc(sizeof(lline) * tmplines_size);
129
130 historynum = 0;
131 history = (histunit *)malloc(prefs.historylength * sizeof(histunit));
132
133 scrollpos = 0;
134 scrollline = 0;
135 startlay = 0; /* not yet used */
136
137 dirtybeg = 0;
138 dirtyend = 0;
139 dirtydelta = 0;
140
141 dotpos = 0;
142 dotlen = 0;
143
144 polydot[0].x = 0;
145 polydot[0].y = 0;
146 polydot[1].x = SIDEMARGIN;
147 polydot[1].y = 5;
148 polydot[2].x = -2*SIDEMARGIN;
149 polydot[2].y = 0;
150
151 scrollel_top = (-1); /* indicate elevator is not there */
152 scrollel_bot = (-1);
153
154 lastlineseen = 0;
155 }
156
157 #ifdef __STDC__
xtext_clear_window()158 void xtext_clear_window()
159 #else
160 void xtext_clear_window()
161 #endif
162 {
163 xtext_delete_start(numlines);
164 }
165
166 #ifdef __STDC__
xtext_resize(int xpos,int ypos,int width,int height)167 void xtext_resize(int xpos, int ypos, int width, int height)
168 #else
169 void xtext_resize(xpos, ypos, width, height)
170 int xpos;
171 int ypos;
172 int width;
173 int height;
174 #endif
175 {
176 scrollwin_x = xpos;
177 scrollwin_w = BARWIDTH;
178 scrollwin_y = ypos+BARENDHEIGHT;
179 scrollwin_h = height-2*BARENDHEIGHT;
180 textwin_x = xpos+scrollwin_w+SIDEMARGIN+prefs.marginx;
181 textwin_y = ypos;
182 textwin_w = width-2*SIDEMARGIN-scrollwin_w-2*prefs.marginx;
183 textwin_h = height;
184
185 dirtybeg = 0;
186 dirtyend = numchars;
187 dirtydelta = 0;
188
189 linesperpage = height / lineheight;
190
191 xtext_layout();
192 }
193
194 #ifdef __STDC__
xtext_redraw()195 void xtext_redraw()
196 #else
197 void xtext_redraw()
198 #endif
199 {
200 XPoint poly[3];
201
202 /* this assumes that an exposure event will not come in between a data update and an xtext_layout call. (unless the exposure event itself forces xtext_layout first?) */
203 /*flip_selection(dotpos, dotlen);*/
204 redrawtext(0, -1, -1);
205 flip_selection(dotpos, dotlen);
206
207 poly[0].x = scrollwin_x + scrollwin_w/2;
208 poly[0].y = textwin_y + 1;
209 poly[1].x = scrollwin_x + 0;
210 poly[1].y = scrollwin_y - 2;
211 poly[2].x = scrollwin_x + scrollwin_w - 1;
212 poly[2].y = scrollwin_y - 2;
213 XFillPolygon(xiodpy, xiowin, gcgrey, poly, 3, Convex, CoordModeOrigin);
214
215 poly[0].x = scrollwin_x + scrollwin_w/2;
216 poly[0].y = textwin_y + textwin_h - 1;
217 poly[1].x = scrollwin_x + 0;
218 poly[1].y = scrollwin_y + scrollwin_h + 2;
219 poly[2].x = scrollwin_x + scrollwin_w - 1;
220 poly[2].y = scrollwin_y + scrollwin_h + 2;
221 XFillPolygon(xiodpy, xiowin, gcgrey, poly, 3, Convex, CoordModeOrigin);
222
223 XDrawLine(xiodpy, xiowin, gcblack, scrollwin_x+scrollwin_w, textwin_y, scrollwin_x+scrollwin_w, textwin_h);
224 scrollel_top = (-1);
225 scrollel_bot = (-1);
226 XFillRectangle(xiodpy, xiowin, gcgrey, scrollwin_x, scrollwin_y, scrollwin_w, scrollwin_h);
227 adjust_elevator();
228 }
229
230 #ifdef __STDC__
back_to_white(long pos)231 static long back_to_white(long pos)
232 #else
233 static long back_to_white(pos)
234 long pos;
235 #endif
236 {
237 while (pos > 0 && charbuf[pos-1] != ' ' && charbuf[pos-1] != '\n')
238 pos--;
239 return pos;
240 }
241
242 #ifdef __STDC__
fore_to_white(long pos)243 static long fore_to_white(long pos)
244 #else
245 static long fore_to_white(pos)
246 long pos;
247 #endif
248 {
249 while (pos < numchars && charbuf[pos] != ' ' && charbuf[pos] != '\n')
250 pos++;
251 return pos;
252 }
253
254 #ifdef __STDC__
back_to_nonwhite(long pos)255 static long back_to_nonwhite(long pos)
256 #else
257 static long back_to_nonwhite(pos)
258 long pos;
259 #endif
260 {
261 while (pos > 0 && (charbuf[pos-1] == ' ' || charbuf[pos-1] == '\n'))
262 pos--;
263 return pos;
264 }
265
266 #ifdef __STDC__
fore_to_nonwhite(long pos)267 static long fore_to_nonwhite(long pos)
268 #else
269 static long fore_to_nonwhite(pos)
270 long pos;
271 #endif
272 {
273 while (pos < numchars && (charbuf[pos] == ' ' || charbuf[pos] == '\n'))
274 pos++;
275 return pos;
276 }
277
278 /* Coordinates are in screen lines. If num < 0, go to the end. clearnum is the number of lines to clear (may be to a notional line); if 0, don't clear at all; if -1, clear whole window. */
279 #ifdef __STDC__
redrawtext(long beg,long num,int clearnum)280 static void redrawtext(long beg, long num, int clearnum)
281 #else
282 static void redrawtext(beg, num, clearnum)
283 long beg;
284 long num;
285 int clearnum;
286 #endif
287 {
288 long lx, wx, end, clearend;
289 int ypos, ypos2, xpos;
290 lline *thisline;
291 word *thisword;
292
293 if (num<0)
294 end = numlines;
295 else {
296 end = beg+num;
297 if (end > numlines)
298 end = numlines;
299 }
300
301 if (beg < scrollline)
302 beg = scrollline;
303
304 if (clearnum > 0) {
305 clearend = beg+clearnum;
306 ypos = textwin_y + (beg-scrollline) * lineheight;
307 ypos2 = textwin_y + (clearend-scrollline) * lineheight;
308 if (ypos2 > textwin_y+textwin_h) {
309 ypos2 = textwin_y+textwin_h;
310 }
311 if (ypos != ypos2)
312 XClearArea(xiodpy, xiowin, textwin_x-SIDEMARGIN, ypos, textwin_w+2*SIDEMARGIN, ypos2-ypos, FALSE);
313 }
314 else if (clearnum < 0) {
315 ypos = textwin_y + (beg-scrollline) * lineheight;
316 ypos2 = textwin_y+textwin_h;
317 if (ypos != ypos2)
318 XClearArea(xiodpy, xiowin, textwin_x-SIDEMARGIN, ypos, textwin_w+2*SIDEMARGIN, ypos2-ypos, FALSE);
319 }
320
321 for (lx=beg; lx<end; lx++) {
322 thisline = (&linelist[lx]);
323 ypos = textwin_y + (lx-scrollline) * lineheight;
324 if (ypos + lineheight >= textwin_y + textwin_h)
325 break;
326 xpos = textwin_x;
327 for (wx=0; wx<thisline->numwords; wx++) {
328 thisword = thisline->wordlist+wx;
329 if (thisword->attr & REVERSE)
330 XDrawImageString(xiodpy, xiowin, gcfont[thisword->attr], xpos, ypos+lineheightoff, charbuf+thisline->pos+thisword->pos, thisword->len);
331 else
332 XDrawString(xiodpy, xiowin, gcfont[thisword->attr], xpos, ypos+lineheightoff, charbuf+thisline->pos+thisword->pos, thisword->len);
333 xpos += thisword->width;
334 }
335 }
336 }
337
338 #ifdef __STDC__
adjust_elevator()339 static void adjust_elevator()
340 #else
341 static void adjust_elevator()
342 #endif
343 {
344 long newtop, newbot;
345 int barheight = (scrollwin_h-2*BAREXTRA);
346
347 if (numlines) {
348 newtop = ((barheight*scrollline) / numlines) + BAREXTRA;
349 newbot = ((barheight*(scrollline+linesperpage)) / numlines) + BAREXTRA;
350 if (newtop < BAREXTRA)
351 newtop = BAREXTRA;
352 if (newbot >= scrollwin_h-BAREXTRA)
353 newbot = scrollwin_h-BAREXTRA;
354 }
355 else {
356 newtop = BAREXTRA;
357 newbot = scrollwin_h-BAREXTRA;
358 }
359
360 if (newtop == scrollel_top && newbot==scrollel_bot)
361 return;
362
363 if (scrollel_top != (-1)
364 && (scrollel_top >= newbot || newtop >= scrollel_bot)) {
365 /* erase old completely */
366 XFillRectangle(xiodpy, xiowin, gcgrey, scrollwin_x, scrollwin_y+scrollel_top, scrollwin_w, scrollel_bot-scrollel_top);
367 scrollel_top = (-1);
368 }
369
370 if (scrollel_top == (-1)) {
371 /* redraw new completely */
372 XDrawRectangle(xiodpy, xiowin, gcblack, scrollwin_x, scrollwin_y+newtop, scrollwin_w-1, (newbot-newtop)-1);
373 XFillRectangle(xiodpy, xiowin, gcwhite, scrollwin_x+1, scrollwin_y+newtop+1, scrollwin_w-2, (newbot-newtop)-2);
374 scrollel_top = newtop;
375 scrollel_bot = newbot;
376 return;
377 }
378
379 /* ok, the old and new overlap */
380 if (newtop < scrollel_top) {
381 XFillRectangle(xiodpy, xiowin, gcwhite, scrollwin_x+1, scrollwin_y+newtop+1, scrollwin_w-2, scrollel_top-newtop);
382 }
383 else if (newtop > scrollel_top) {
384 XFillRectangle(xiodpy, xiowin, gcgrey, scrollwin_x, scrollwin_y+scrollel_top, scrollwin_w, newtop-scrollel_top);
385 }
386
387 if (newbot > scrollel_bot) {
388 XFillRectangle(xiodpy, xiowin, gcwhite, scrollwin_x+1, scrollwin_y+scrollel_bot-1, scrollwin_w-2, newbot-scrollel_bot);
389 }
390 else if (newbot < scrollel_bot) {
391 XFillRectangle(xiodpy, xiowin, gcgrey, scrollwin_x, scrollwin_y+newbot, scrollwin_w, scrollel_bot-newbot);
392 }
393
394 XDrawRectangle(xiodpy, xiowin, gcblack, scrollwin_x, scrollwin_y+newtop, scrollwin_w-1, (newbot-newtop)-1);
395 scrollel_top = newtop;
396 scrollel_bot = newbot;
397 }
398
399 #ifdef __STDC__
scroll_to(long newscrollline)400 static void scroll_to(long newscrollline)
401 #else
402 static void scroll_to(newscrollline)
403 long newscrollline;
404 #endif
405 {
406 long oldscrollline;
407
408 if (newscrollline > numlines-2)
409 newscrollline = numlines-2;
410 if (newscrollline < 0)
411 newscrollline = 0;
412
413 scrollpos = linelist[newscrollline].pos;
414 if (scrollline != newscrollline) {
415 oldscrollline = scrollline;
416 if (!xiobackstore
417 || oldscrollline + linesperpage <= newscrollline
418 || newscrollline + linesperpage <= oldscrollline) {
419 scrollline = newscrollline;
420 redrawtext(scrollline, -1, -1);
421 flip_selection(dotpos, dotlen);
422 }
423 else {
424 int ypos1, ypos2, yhgt;
425 flip_selection(dotpos, dotlen);
426 scrollline = newscrollline;
427 if (oldscrollline < newscrollline) {
428 /* scroll down -- things move up */
429 ypos1 = textwin_y + (newscrollline-oldscrollline) * lineheight;
430 ypos2 = textwin_y + (0) * lineheight;
431 yhgt = (linesperpage-(newscrollline-oldscrollline)) * lineheight;
432 XCopyArea(xiodpy, xiowin, xiowin, gcblack, textwin_x-SIDEMARGIN, ypos1, textwin_w+2*SIDEMARGIN, yhgt, textwin_x-SIDEMARGIN, ypos2);
433 redrawtext(linesperpage + oldscrollline, (newscrollline-oldscrollline), (newscrollline-oldscrollline));
434 }
435 else {
436 /* scroll up -- things move down */
437 ypos2 = textwin_y + (oldscrollline-newscrollline) * lineheight;
438 ypos1 = textwin_y + (0) * lineheight;
439 yhgt = (linesperpage-(oldscrollline-newscrollline)) * lineheight;
440 XCopyArea(xiodpy, xiowin, xiowin, gcblack, textwin_x-SIDEMARGIN, ypos1, textwin_w+2*SIDEMARGIN, yhgt, textwin_x-SIDEMARGIN, ypos2);
441 redrawtext(newscrollline, (oldscrollline-newscrollline), (oldscrollline-newscrollline));
442 }
443 flip_selection(dotpos, dotlen);
444 }
445 adjust_elevator();
446 }
447 }
448
449 #ifdef __STDC__
refiddle_selection(long oldpos,long oldlen,long newpos,long newlen)450 static void refiddle_selection(long oldpos, long oldlen, long newpos, long newlen)
451 #else
452 static void refiddle_selection(oldpos, oldlen, newpos, newlen)
453 long oldpos;
454 long oldlen;
455 long newpos;
456 long newlen;
457 #endif
458 {
459 if (oldlen==0 || newlen==0 || oldpos<0 || newpos<0) {
460 flip_selection(oldpos, oldlen);
461 flip_selection(newpos, newlen);
462 return;
463 }
464
465 if (oldpos == newpos) {
466 /* start at same place */
467 if (oldlen < newlen) {
468 flip_selection(oldpos+oldlen, newlen-oldlen);
469 }
470 else if (newlen < oldlen) {
471 flip_selection(oldpos+newlen, oldlen-newlen);
472 }
473 return;
474 }
475 if (oldpos+oldlen == newpos+newlen) {
476 /* end at same place */
477 if (oldpos < newpos) {
478 flip_selection(oldpos, newpos-oldpos);
479 }
480 else if (newpos < oldpos) {
481 flip_selection(newpos, oldpos-newpos);
482 }
483 return;
484 }
485
486 flip_selection(oldpos, oldlen);
487 flip_selection(newpos, newlen);
488 }
489
490 #ifdef __STDC__
flip_selection(long dpos,long dlen)491 static void flip_selection(long dpos, long dlen)
492 #else
493 static void flip_selection(dpos, dlen)
494 long dpos;
495 long dlen;
496 #endif
497 {
498 int xpos, ypos;
499 int xpos2, ypos2;
500 long ybody, ybody2;
501
502 if (dpos < 0) {
503 return; /* dot hidden */
504 }
505
506 if (dlen==0) {
507 find_loc_by_pos(dpos, &xpos, &ypos);
508 if (ypos < 0 || ypos+lineheight >= textwin_h) {
509 return;
510 }
511 polydot[0].x = textwin_x + xpos;
512 polydot[0].y = textwin_y + ypos + lineheightoff;
513 XFillPolygon(xiodpy, xiowin, gcflip, polydot, 3, Convex, CoordModePrevious);
514 }
515 else {
516 find_loc_by_pos(dpos, &xpos, &ypos);
517 find_loc_by_pos(dpos+dlen, &xpos2, &ypos2);
518 if (ypos==ypos2) {
519 /* within one line */
520 if (xpos!=xpos2 && ypos>=0 && ypos+lineheight<textwin_h) {
521 XFillRectangle(xiodpy, xiowin, gcflip, xpos+textwin_x, ypos+textwin_y, xpos2-xpos, lineheight);
522 }
523 }
524 else {
525 if (xpos < textwin_w && ypos>=0 && ypos+lineheight<textwin_h) {
526 /* first partial line */
527 XFillRectangle(xiodpy, xiowin, gcflip, xpos+textwin_x, ypos+textwin_y, textwin_w-xpos, lineheight);
528 }
529 ybody = ypos+lineheight;
530 ybody2 = ypos2;
531 if (ybody < ybody2 && ybody2>=0 && ybody+lineheight<textwin_h) {
532 if (ybody < 0)
533 ybody = 0;
534 if (ybody2+lineheight >= textwin_h)
535 ybody2 = textwin_h;
536 /* main body */
537 XFillRectangle(xiodpy, xiowin, gcflip, textwin_x, ybody+textwin_y, textwin_w, ybody2-ybody);
538 }
539 if (xpos2 && ypos2>=0 && ypos2+lineheight<textwin_h) {
540 /* last partial line */
541 XFillRectangle(xiodpy, xiowin, gcflip, textwin_x, ypos2+textwin_y, xpos2, lineheight);
542 }
543 }
544 }
545 }
546
547 /* push lines from tmplinelist[0..newnum) in place of linelist[oldbeg..oldend) */
548 #ifdef __STDC__
slapover(long newnum,long oldbeg,long oldend)549 static void slapover(long newnum, long oldbeg, long oldend)
550 #else
551 static void slapover(newnum, oldbeg, oldend)
552 long newnum;
553 long oldbeg;
554 long oldend;
555 #endif
556 {
557 long wx, lx;
558 long newnumlines;
559
560 newnumlines = numlines-(oldend-oldbeg)+newnum;
561 if (newnumlines >= lines_size) {
562 while (newnumlines >= lines_size)
563 lines_size *= 2;
564 linelist = (lline *)realloc(linelist, sizeof(lline) * lines_size);
565 }
566
567 /* clobber old */
568 for (lx=oldbeg; lx<oldend; lx++) {
569 word *thisword;
570 /* --- finalize word structure --- */
571 for (wx=0, thisword=linelist[lx].wordlist;
572 wx<linelist[lx].numwords;
573 wx++, thisword++) {
574 if (thisword->letterpos) {
575 free(thisword->letterpos);
576 }
577 }
578 free(linelist[lx].wordlist);
579 linelist[lx].wordlist = NULL;
580 }
581
582 if (oldend < numlines && newnumlines != numlines) {
583 memmove(&linelist[oldend+(newnumlines-numlines)],
584 &linelist[oldend],
585 sizeof(lline) * (numlines-oldend));
586 }
587 /* ### adjust scrollline by difference too? */
588 numlines = newnumlines;
589
590 if (newnum) {
591 memcpy(&linelist[oldbeg],
592 &tmplinelist[0],
593 sizeof(lline) * (newnum));
594 }
595 }
596
597 /* xpos, ypos are relative to textwin origin */
598 #ifdef __STDC__
find_pos_by_loc(int xpos,int ypos)599 static long find_pos_by_loc(int xpos, int ypos)
600 #else
601 static long find_pos_by_loc(xpos, ypos)
602 int xpos;
603 int ypos;
604 #endif
605 {
606 int ix;
607 long linenum;
608 long wx, atpos, newpos;
609 lline *curline;
610 word *curword;
611
612 if (ypos < 0)
613 linenum = (-1) - ((-1)-ypos / lineheight);
614 else
615 linenum = ypos / lineheight;
616
617 linenum += scrollline;
618
619 if (linenum < 0)
620 return 0;
621 if (linenum >= numlines)
622 return numchars;
623
624 curline = (&linelist[linenum]);
625 if (xpos < 0) {
626 return curline->pos; /* beginning of line */
627 }
628 atpos = 0;
629 for (wx=0; wx<curline->numwords; wx++) {
630 newpos = atpos + curline->wordlist[wx].width;
631 if (xpos < newpos)
632 break;
633 atpos = newpos;
634 }
635 if (wx==curline->numwords) {
636 return curline->posend; /* end of line */
637 }
638
639 xpos -= atpos; /* now xpos is relative to word beginning */
640 curword = (&curline->wordlist[wx]);
641 if (!curword->letterpos)
642 measure_word(curline, curword);
643
644 for (ix=0; ix<curword->len; ix++) {
645 if (xpos <= (curword->letterpos[ix]+curword->letterpos[ix+1])/2)
646 break;
647 }
648 return curline->pos + curword->pos + ix;
649 }
650
651 /* returns the last line such that pos >= line.pos. guessline is a guess to start searching at; -1 means end of file. Can return -1 if pos is before the start of the layout. */
652 #ifdef __STDC__
find_line_by_pos(long pos,long guessline)653 static long find_line_by_pos(long pos, long guessline)
654 #else
655 static long find_line_by_pos(pos, guessline)
656 long pos;
657 long guessline;
658 #endif
659 {
660 long lx;
661
662 if (guessline < 0 || guessline >= numlines)
663 guessline = numlines-1;
664
665 if (guessline < numlines-1 && linelist[guessline].pos <= pos) {
666 for (lx=guessline; lx<numlines; lx++) {
667 if (linelist[lx].pos > pos)
668 break;
669 }
670 lx--;
671 }
672 else {
673 for (lx=guessline; lx>=0; lx--) {
674 if (linelist[lx].pos <= pos)
675 break;
676 }
677 }
678
679 return lx;
680 }
681
682 /* returns values relative to textwin origin, at top of line. */
683 #ifdef __STDC__
find_loc_by_pos(long pos,int * xposret,int * yposret)684 static void find_loc_by_pos(long pos, int *xposret, int *yposret)
685 #else
686 static void find_loc_by_pos(pos, xposret, yposret)
687 long pos;
688 int *xposret;
689 int *yposret;
690 #endif
691 {
692 long lx;
693 long wx, atpos;
694 lline *curline;
695 word *curword;
696
697 lx = find_line_by_pos(pos, -1);
698 if (lx < 0) {
699 /* somehow before first line laid out */
700 *xposret = 0;
701 *yposret = (-scrollline) * lineheight;
702 return;
703 }
704 curline = (&linelist[lx]);
705
706 *yposret = (lx-scrollline) * lineheight;
707 atpos = 0;
708 for (wx=0; wx<curline->numwords; wx++) {
709 if (curline->pos+curline->wordlist[wx].pos+curline->wordlist[wx].len >= pos)
710 break;
711 atpos += curline->wordlist[wx].width;
712 }
713 if (wx==curline->numwords) {
714 *xposret = atpos;
715 return;
716 }
717
718 curword = (&curline->wordlist[wx]);
719 if (!curword->letterpos)
720 measure_word(curline, curword);
721
722 atpos += curword->letterpos[pos - (curline->pos+curword->pos)];
723
724 *xposret = atpos;
725 }
726
727 #ifdef __STDC__
measure_word(lline * curline,word * curword)728 static void measure_word(lline *curline, word *curword)
729 #else
730 static void measure_word(curline, curword)
731 lline *curline;
732 word *curword;
733 #endif
734 {
735 int cx;
736 char *buf;
737 int direction;
738 int ascent, descent;
739 XCharStruct overall;
740 long *arr;
741
742 if (curword->letterpos)
743 free(curword->letterpos);
744
745 arr = (long *)malloc(sizeof(long) * (curword->len+1));
746
747 buf = charbuf+curline->pos+curword->pos;
748 arr[0] = 0;
749 for (cx=0; cx<curword->len-1; cx++) {
750 XTextExtents(fontstr[curword->attr], buf+cx, 1, &direction, &ascent, &descent, &overall);
751 arr[cx+1] = arr[cx] + overall.width;
752 }
753 arr[cx+1] = curword->width;
754
755 curword->letterpos = arr;
756 }
757
758 #ifdef __STDC__
strip_garbage(char * buf,int len)759 static void strip_garbage(char *buf, int len)
760 #else
761 static void strip_garbage(buf, len)
762 char *buf;
763 int len;
764 #endif
765 {
766 int ix;
767
768 for (ix=0; ix<len; ix++, buf++) {
769 if (iscntrl(*buf))
770 *buf = ' ';
771 }
772 }
773
774 /* pos < 0 means add at end.
775 all this is grotesquely inefficient if adding anywhere but the end. */
776 #ifdef __STDC__
xtext_add(char ch,long pos)777 void xtext_add(char ch, long pos)
778 #else
779 void xtext_add(ch, pos)
780 char ch;
781 long pos;
782 #endif
783 {
784 if (pos<0)
785 pos = numchars;
786 xtext_replace(pos, 0, &ch, 1);
787 }
788
789 /* update data, adjusting dot and styles as necessary. */
790 #ifdef __STDC__
xtext_replace(long pos,long oldlen,char * buf,long newlen)791 void xtext_replace(long pos, long oldlen, char *buf, long newlen)
792 #else
793 void xtext_replace(pos, oldlen, buf, newlen)
794 long pos;
795 long oldlen;
796 char *buf;
797 long newlen;
798 #endif
799 {
800 long newnumchars;
801
802 newnumchars = numchars-oldlen+newlen;
803 if (newnumchars >= char_size) {
804 while (newnumchars >= char_size)
805 char_size *= 2;
806 charbuf = (char *)realloc(charbuf, sizeof(char) * char_size);
807 }
808
809 if (pos < dirtybeg || dirtybeg < 0)
810 dirtybeg = pos;
811
812 if (newlen != oldlen) {
813 if (pos+oldlen != numchars) {
814 memmove(charbuf+pos+newlen, charbuf+pos+oldlen, sizeof(char) * (numchars-(pos+oldlen)));
815 }
816 if (numchars >= dirtyend)
817 dirtyend = numchars+1;
818 dirtydelta += (newlen-oldlen);
819 }
820 else {
821 if (pos+newlen >= dirtyend)
822 dirtyend = pos+newlen+1;
823 dirtydelta += (newlen-oldlen);
824 }
825
826 /* copy in the new stuff */
827 if (newlen)
828 memmove(charbuf+pos, buf, sizeof(char) * newlen);
829
830 /* diddle the dot */
831 if (dotpos >= pos+oldlen) {
832 /* starts after changed region */
833 dotpos += (newlen-oldlen);
834 }
835 else if (dotpos >= pos) {
836 /* starts inside changed region */
837 if (dotpos+dotlen >= pos+oldlen) {
838 /* ...but ends after it */
839 dotlen = (dotpos+dotlen)-(pos+oldlen);
840 dotpos = pos+newlen;
841 }
842 else {
843 /* ...and ends inside it */
844 dotpos = pos+newlen;
845 dotlen = 0;
846 }
847 }
848 else {
849 /* starts before changed region */
850 if (dotpos+dotlen >= pos+oldlen) {
851 /* ...but ends after it */
852 dotlen += (newlen-oldlen);
853 }
854 else if (dotpos+dotlen >= pos) {
855 /* ...but ends inside it */
856 dotlen = (pos+newlen) - dotpos;
857 }
858 }
859
860 numchars = newnumchars;
861 }
862
863 #ifdef __STDC__
xtext_setstyle(long pos,int attr)864 void xtext_setstyle(long pos, int attr)
865 #else
866 void xtext_setstyle(pos, attr)
867 long pos;
868 int attr;
869 #endif
870 {
871 long sx;
872
873 if (pos < 0)
874 pos = numchars;
875
876 for (sx=numstyles-1; sx>=0; sx--) {
877 if (stylelist[sx].pos <= pos) {
878 break;
879 }
880 }
881 if (sx < 0) {
882 printf("### oops, went back behind style 0\n");
883 return;
884 }
885
886 if (stylelist[sx].pos == pos) {
887 stylelist[sx].attr = attr;
888 }
889 else {
890 /* insert a style after sx */
891 sx++;
892 if (numstyles+1 >= styles_size) {
893 styles_size *= 2;
894 stylelist = (style *)realloc(stylelist, sizeof(style) * styles_size);
895 }
896 numstyles++;
897 if (sx < numstyles) {
898 memmove(&stylelist[sx+1], &stylelist[sx], sizeof(style) * (numstyles-sx));
899 stylelist[sx].pos = pos;
900 stylelist[sx].attr = attr;
901 }
902 }
903
904 if (pos != numchars) {
905 /* ### should only go to next style */
906 dirtybeg = pos;
907 dirtyend = numchars;
908 dirtydelta = 0;
909 xtext_layout();
910 }
911 }
912
913 #ifdef __STDC__
xtext_set_lastseen()914 void xtext_set_lastseen()
915 #else
916 void xtext_set_lastseen()
917 #endif
918 {
919 lastlineseen = numlines;
920 }
921
922 #ifdef __STDC__
xtext_end_visible()923 void xtext_end_visible()
924 #else
925 void xtext_end_visible()
926 #endif
927 {
928 long lx;
929
930 if (lastlineseen < 0 || lastlineseen >= (numlines-linesperpage)-1) {
931 /* straight to end */
932 if (scrollline < numlines-linesperpage) {
933 scroll_to(numlines-linesperpage);
934 }
935 }
936 else {
937 lx = lastlineseen-1;
938 while (lx < numlines-linesperpage) {
939 scroll_to(lx);
940 xmess_set_message("[Hit any key to continue.]", TRUE);
941 xio_pause();
942 lx += (linesperpage-1);
943 }
944 scroll_to(numlines-linesperpage);
945 xmess_set_message(NULL, TRUE);
946 }
947
948 lastlineseen = (-1);
949 }
950
951 /* delete num lines from the top */
952 #ifdef __STDC__
xtext_delete_start(long num)953 void xtext_delete_start(long num)
954 #else
955 void xtext_delete_start(num)
956 long num;
957 #endif
958 {
959 long delchars;
960 long lx, sx, sx2;
961 int origattr;
962
963 if (num > numlines)
964 num = numlines;
965 if (num < 0)
966 num = 0;
967
968 if (num == numlines)
969 delchars = numchars;
970 else
971 delchars = linelist[num].pos;
972 if (!delchars)
973 return;
974
975 /* lines */
976 slapover(0, 0, num);
977 for (lx=0; lx<numlines; lx++) {
978 linelist[lx].pos -= delchars;
979 linelist[lx].posend -= delchars;
980 }
981
982 /* styles */
983 for (sx=0; sx<numstyles; sx++) {
984 if (stylelist[sx].pos > delchars)
985 break;
986 }
987 if (sx>0) {
988 origattr = stylelist[sx-1].attr;
989 stylelist[0].pos = 0;
990 stylelist[0].attr = origattr;
991 for (sx2=1; sx<numstyles; sx++, sx2++) {
992 stylelist[sx2].pos = stylelist[sx].pos - delchars;
993 stylelist[sx2].attr = stylelist[sx].attr;
994 }
995 numstyles = sx2;
996 }
997
998 /* chars */
999 if (delchars < numchars)
1000 memmove(&charbuf[0], &charbuf[delchars], sizeof(char) * (numchars-delchars));
1001 numchars -= delchars;
1002
1003 /* adjust, I mean, everything */
1004 if (dirtybeg != (-1)) {
1005 dirtybeg -= delchars;
1006 dirtyend -= delchars;
1007 if (dirtyend < 0) {
1008 dirtybeg = (-1);
1009 dirtyend = (-1);
1010 }
1011 else if (dirtybeg < 0) {
1012 dirtybeg = 0;
1013 }
1014 }
1015
1016 dotpos -= delchars;
1017 if (dotpos < 0) {
1018 if (dotpos+dotlen < 0) {
1019 dotpos = 0;
1020 dotlen = 0;
1021 }
1022 else {
1023 dotlen += dotpos;
1024 dotpos = 0;
1025 }
1026 }
1027 lastdotpos -= delchars;
1028 if (lastdotpos < 0) {
1029 if (lastdotpos+lastdotlen < 0) {
1030 lastdotpos = 0;
1031 lastdotlen = 0;
1032 }
1033 else {
1034 lastdotlen += lastdotpos;
1035 lastdotpos = 0;
1036 }
1037 }
1038 inputfence -= delchars;
1039 if (inputfence < 0)
1040 inputfence = 0;
1041
1042 if (lastlineseen != (-1)) {
1043 lastlineseen -= num;
1044 if (lastlineseen < 0)
1045 lastlineseen = (-1);
1046 }
1047
1048 scrollline -= num;
1049 scrollpos -= delchars;
1050 if (scrollline < 0 || scrollpos < 0) {
1051 scrollline = 0;
1052 scrollpos = 0;
1053 redrawtext(0, -1, -1);
1054 flip_selection(dotpos, dotlen);
1055 adjust_elevator();
1056 }
1057 else {
1058 adjust_elevator();
1059 }
1060 }
1061
1062 #ifdef __STDC__
xtext_layout()1063 void xtext_layout()
1064 #else
1065 void xtext_layout()
1066 #endif
1067 {
1068 long ix, jx, ejx, lx;
1069 long styx, nextstylepos;
1070 int curstyle;
1071 long overline, overlineend;
1072 long tmpl, startpos;
1073 int prevflags;
1074 int needwholeredraw;
1075
1076 int direction;
1077 int ascent, descent;
1078 XCharStruct overall;
1079
1080 static long lastline = 0; /* last line dirtied */
1081
1082 if (dirtybeg < 0 || dirtyend < 0) {
1083 if (lastdotpos != dotpos || lastdotlen != dotlen) {
1084 refiddle_selection(lastdotpos, lastdotlen, dotpos, dotlen);
1085 /*flip_selection(lastdotpos, lastdotlen);*/
1086 lastdotpos = dotpos;
1087 lastdotlen = dotlen;
1088 /*flip_selection(lastdotpos, lastdotlen);*/
1089 }
1090 return;
1091 }
1092
1093 /* if any text diddling is done, we'll just flip automatically */
1094 flip_selection(lastdotpos, lastdotlen);
1095 lastdotpos = dotpos;
1096 lastdotlen = dotlen;
1097
1098 if (numlines==0) {
1099 overline = 0;
1100 startpos = 0;
1101 }
1102 else {
1103 lx = find_line_by_pos(dirtybeg, lastline);
1104 /* now lx is the line containing dirtybeg */
1105
1106 if (lx>0 && lx<numlines && (linelist[lx].flags & lineflag_Wrapped)) {
1107 /* do layout from previous line, in case a word from the changed area pops back there. */
1108 lx--;
1109 }
1110 overline = lx;
1111 startpos = linelist[overline].pos;
1112 }
1113
1114 /* get the first relevant style */
1115 for (styx=numstyles-1; styx>0; styx--)
1116 if (stylelist[styx].pos <= startpos)
1117 break;
1118 if (styx==numstyles-1)
1119 nextstylepos = numchars+10;
1120 else
1121 nextstylepos = stylelist[styx+1].pos;
1122 curstyle = stylelist[styx].attr;
1123
1124 /* start a-layin' */
1125 tmpl = 0;
1126 prevflags = 0;
1127
1128 while (startpos<numchars && !(startpos >= dirtyend && charbuf[startpos]=='\n')) {
1129 lline *thisline;
1130 long tmpw, tmpwords_size;
1131 long widthsofar, spaceswidth;
1132
1133 if (tmpl+1 >= tmplines_size) {
1134 /* the +1 allows the extra blank line at the end */
1135 tmplines_size *= 2;
1136 tmplinelist = (lline *)realloc(tmplinelist, sizeof(lline) * tmplines_size);
1137 }
1138 thisline = (&tmplinelist[tmpl]);
1139 thisline->flags = prevflags;
1140 tmpwords_size = 8;
1141 thisline->wordlist = (word *)malloc(tmpwords_size * sizeof(word));
1142 tmpw = 0;
1143
1144 /*printf("### laying tmpline %d, from charpos %d\n", tmpl, startpos);*/
1145 tmpl++;
1146
1147 ix = startpos;
1148 widthsofar = 0;
1149 prevflags = 0;
1150
1151 while (ix<numchars && charbuf[ix]!='\n') {
1152 word *thisword;
1153
1154 while (ix >= nextstylepos) {
1155 /* ahead one style */
1156 styx++;
1157 if (styx==numstyles-1)
1158 nextstylepos = numchars+10;
1159 else
1160 nextstylepos = stylelist[styx+1].pos;
1161 curstyle = stylelist[styx].attr;
1162 }
1163
1164 if (tmpw >= tmpwords_size) {
1165 tmpwords_size *= 2;
1166 thisline->wordlist = (word *)realloc(thisline->wordlist, tmpwords_size * sizeof(word));
1167 }
1168 thisword = (&thisline->wordlist[tmpw]);
1169 /* --- initialize word structure --- */
1170
1171 thisword->letterpos = NULL;
1172 for (jx=ix; jx<numchars && jx<nextstylepos && charbuf[jx]!=' ' && charbuf[jx]!='\n'; jx++);
1173
1174 XTextExtents(fontstr[curstyle], charbuf+ix, jx-ix, &direction, &ascent, &descent, &overall);
1175 if (widthsofar + overall.width > textwin_w) {
1176 prevflags = lineflag_Wrapped;
1177 if (tmpw == 0) {
1178 /* do something clever -- split the word, put first part in tmplist. */
1179 int letx;
1180 long wordwidthsofar = 0;
1181 for (letx=ix; letx<jx; letx++) {
1182 XTextExtents(fontstr[curstyle], charbuf+letx, 1, &direction, &ascent, &descent, &overall);
1183 if (widthsofar + wordwidthsofar+overall.width > textwin_w) {
1184 break;
1185 }
1186 wordwidthsofar += overall.width;
1187 }
1188 jx = letx;
1189 overall.width = wordwidthsofar;
1190 /* spaceswidth and ejx will be 0 */
1191 /* don't break */
1192 }
1193 else {
1194 /* ejx and spaceswidth are properly set from last word, trim them off. */
1195 thisword--;
1196 thisword->len -= ejx;
1197 thisword->width -= spaceswidth;
1198 break;
1199 }
1200 }
1201
1202 /* figure out trailing whitespace */
1203 ejx = 0;
1204 while (jx+ejx<numchars && jx+ejx<nextstylepos && charbuf[jx+ejx]==' ') {
1205 ejx++;
1206 }
1207 spaceswidth = ejx * spacewidth[curstyle];
1208
1209 /* put the word in tmplist */
1210 thisword->pos = ix-startpos;
1211 thisword->len = jx+ejx-ix;
1212 thisword->attr = curstyle;
1213 thisword->width = overall.width+spaceswidth;
1214 widthsofar += thisword->width;
1215 tmpw++;
1216
1217 ix = jx+ejx;
1218 }
1219 thisline->pos = startpos;
1220 if (tmpw) {
1221 word *thisword = (&thisline->wordlist[tmpw-1]);
1222 thisline->posend = startpos + thisword->pos + thisword->len;
1223 }
1224 else {
1225 thisline->posend = startpos;
1226 }
1227
1228 if (ix<numchars && charbuf[ix]=='\n')
1229 ix++;
1230
1231 thisline->numwords = tmpw;
1232 if (prefs.fulljustify && prevflags==lineflag_Wrapped && tmpw>1) {
1233 /* gonna regret this, I just bet */
1234 long extraspace, each;
1235 extraspace = textwin_w - widthsofar;
1236 each = extraspace / (tmpw-1);
1237 extraspace -= (each*(tmpw-1));
1238 for (jx=0; jx<extraspace; jx++) {
1239 thisline->wordlist[jx].width += (each+1);
1240 }
1241 for (; jx<tmpw-1; jx++) {
1242 thisline->wordlist[jx].width += each;
1243 }
1244 }
1245
1246 startpos = ix;
1247 } /* done laying tmp lines */
1248
1249 if (startpos == numchars && (numchars==0 || charbuf[numchars-1]=='\n')) {
1250 /* lay one more line! */
1251 lline *thisline;
1252 thisline = (&tmplinelist[tmpl]);
1253 thisline->flags = lineflag_Extra;
1254 tmpl++;
1255
1256 thisline->wordlist = (word *)malloc(sizeof(word));
1257 thisline->numwords = 0;
1258 thisline->pos = startpos;
1259 thisline->posend = startpos;
1260 }
1261
1262 /*printf("### laid %d tmplines, and startpos now %d (delta %d)\n", tmpl, startpos, dirtydelta);*/
1263
1264 for (lx=overline; lx<numlines && linelist[lx].pos < startpos-dirtydelta; lx++);
1265 if (lx==numlines-1 && (linelist[lx].flags & lineflag_Extra)) {
1266 /* account for the extra line */
1267 lx++;
1268 }
1269 overlineend = lx;
1270
1271 /*printf("### overwrite area is lines [%d..%d) (of %d); replacing with %d lines\n", overline, overlineend, numlines, tmpl);*/
1272
1273 slapover(tmpl, overline, overlineend);
1274
1275 lastline = overline+tmpl; /* re-cache value */
1276 needwholeredraw = FALSE;
1277
1278 /* diddle scroll stuff */
1279 if (scrollpos <= dirtybeg) {
1280 /* disturbance is off bottom of screen -- do nothing */
1281 }
1282 else if (scrollpos >= startpos-dirtydelta) {
1283 /* disturbance is off top of screen -- adjust so that no difference is visible. */
1284 scrollpos += dirtydelta;
1285 scrollline += (overline-overlineend) - tmpl;
1286 }
1287 else {
1288 scrollpos += dirtydelta; /* kind of strange, but shouldn't cause trouble */
1289 if (scrollpos >= numchars)
1290 scrollpos = numchars-1;
1291 if (scrollpos < 0)
1292 scrollpos = 0;
1293 scrollline = find_line_by_pos(scrollpos, scrollline);
1294 needwholeredraw = TRUE;
1295 }
1296
1297 dirtybeg = -1;
1298 dirtyend = -1;
1299 dirtydelta = 0;
1300
1301 if (needwholeredraw) {
1302 redrawtext(scrollline, -1, -1);
1303 }
1304 else if (tmpl == overlineend-overline) {
1305 redrawtext(overline, tmpl, tmpl);
1306 }
1307 else {
1308 if (overlineend > numlines)
1309 redrawtext(overline, -1, overlineend-overline);
1310 else
1311 redrawtext(overline, -1, numlines-overline);
1312 }
1313
1314 flip_selection(lastdotpos, lastdotlen);
1315
1316 adjust_elevator();
1317 }
1318
1319 static long drag_firstbeg, drag_firstend;
1320 static int drag_inscroll;
1321 static int drag_scrollmode; /* 0 for click in elevator; 1 for dragged in elevator; 2 for endzones; 3 for click in background */
1322 static int drag_hitypos;
1323 static long drag_origline;
1324
1325 /* got a mouse hit. */
1326 #ifdef __STDC__
xtext_hitdown(int xpos,int ypos,unsigned int button,unsigned int mods,int clicknum)1327 void xtext_hitdown(int xpos, int ypos, unsigned int button, unsigned int mods, int clicknum)
1328 #else
1329 void xtext_hitdown(xpos, ypos, button, mods, clicknum)
1330 int xpos;
1331 int ypos;
1332 unsigned int button;
1333 unsigned int mods;
1334 int clicknum;
1335 #endif
1336 {
1337 long pos;
1338 long px, px2;
1339
1340 if (xpos < scrollwin_x+scrollwin_w)
1341 drag_inscroll = TRUE;
1342 else
1343 drag_inscroll = FALSE;
1344
1345 if (drag_inscroll) {
1346 drag_origline = scrollline;
1347 drag_hitypos = ypos-textwin_y;
1348 switch (button) { /* scrollbar */
1349 case Button1:
1350 if (ypos < scrollwin_y) {
1351 drag_scrollmode = 2;
1352 xted_scroll(op_ToTop);
1353 }
1354 else if (ypos >= scrollwin_y+scrollwin_h) {
1355 drag_scrollmode = 2;
1356 xted_scroll(op_ToBottom);
1357 }
1358 else {
1359 if (ypos >= scrollwin_y+scrollel_top
1360 && ypos < scrollwin_y+scrollel_bot)
1361 drag_scrollmode = 0;
1362 else
1363 drag_scrollmode = 3;
1364 }
1365 break;
1366 case Button3:
1367 if (ypos < scrollwin_y) {
1368 drag_scrollmode = 2;
1369 xted_scroll(op_UpLine);
1370 }
1371 else if (ypos >= scrollwin_y+scrollwin_h) {
1372 drag_scrollmode = 2;
1373 xted_scroll(op_DownLine);
1374 }
1375 else {
1376 if (ypos >= scrollwin_y+scrollel_top
1377 && ypos < scrollwin_y+scrollel_bot)
1378 drag_scrollmode = 0;
1379 else
1380 drag_scrollmode = 3;
1381 }
1382 break;
1383 }
1384 }
1385 else {
1386 switch (button) { /* text window */
1387 case Button1:
1388 case Button3:
1389 xpos -= textwin_x;
1390 ypos -= textwin_y;
1391
1392 pos = find_pos_by_loc(xpos, ypos);
1393 if (button==Button1) {
1394 if (!(clicknum & 1)) {
1395 px = back_to_white(pos);
1396 px2 = fore_to_white(pos);
1397 }
1398 else {
1399 px = pos;
1400 px2 = pos;
1401 }
1402 dotpos = px;
1403 dotlen = px2-px;
1404 drag_firstbeg = px;
1405 drag_firstend = px2;
1406 }
1407 else {
1408 if (pos < dotpos+dotlen/2) {
1409 drag_firstbeg = dotpos+dotlen;
1410 }
1411 else {
1412 drag_firstbeg = dotpos;
1413 }
1414 drag_firstend = drag_firstbeg;
1415 if (pos < drag_firstbeg) {
1416 if (!(clicknum & 1))
1417 dotpos = back_to_white(pos);
1418 else
1419 dotpos = pos;
1420 dotlen = drag_firstend-dotpos;
1421 }
1422 else if (pos > drag_firstend) {
1423 dotpos = drag_firstbeg;
1424 if (!(clicknum & 1))
1425 dotlen = fore_to_white(pos)-drag_firstbeg;
1426 else
1427 dotlen = pos-drag_firstbeg;
1428 }
1429 else {
1430 dotpos = drag_firstbeg;
1431 dotlen = drag_firstend-drag_firstbeg;
1432 }
1433 }
1434 xtext_layout();
1435 break;
1436 default:
1437 break;
1438 }
1439 }
1440 }
1441
1442 #ifdef __STDC__
xtext_hitmove(int xpos,int ypos,unsigned int button,unsigned int mods,int clicknum)1443 void xtext_hitmove(int xpos, int ypos, unsigned int button, unsigned int mods, int clicknum)
1444 #else
1445 void xtext_hitmove(xpos, ypos, button, mods, clicknum)
1446 int xpos;
1447 int ypos;
1448 unsigned int button;
1449 unsigned int mods;
1450 int clicknum;
1451 #endif
1452 {
1453 long pos, px;
1454
1455 if (drag_inscroll) {
1456 if (drag_scrollmode==0 || drag_scrollmode==1) {
1457 drag_scrollmode = 1;
1458 px = ((ypos - drag_hitypos)*numlines) / (scrollwin_h-2*BAREXTRA);
1459 scroll_to(drag_origline+px);
1460 }
1461 }
1462 else {
1463 xpos -= textwin_x;
1464 ypos -= textwin_y;
1465
1466 switch (button) {
1467 case Button1:
1468 case Button3:
1469 pos = find_pos_by_loc(xpos, ypos);
1470 if (pos < drag_firstbeg) {
1471 if (!(clicknum & 1))
1472 dotpos = back_to_white(pos);
1473 else
1474 dotpos = pos;
1475 dotlen = drag_firstend-dotpos;
1476 }
1477 else if (pos > drag_firstend) {
1478 dotpos = drag_firstbeg;
1479 if (!(clicknum & 1))
1480 dotlen = fore_to_white(pos)-drag_firstbeg;
1481 else
1482 dotlen = pos-drag_firstbeg;
1483 }
1484 else {
1485 dotpos = drag_firstbeg;
1486 dotlen = drag_firstend-drag_firstbeg;
1487 }
1488 xtext_layout();
1489 break;
1490 default:
1491 break;
1492 }
1493 }
1494 }
1495
1496 #ifdef __STDC__
xtext_hitup(int xpos,int ypos,unsigned int button,unsigned int mods,int clicknum)1497 void xtext_hitup(int xpos, int ypos, unsigned int button, unsigned int mods, int clicknum)
1498 #else
1499 void xtext_hitup(xpos, ypos, button, mods, clicknum)
1500 int xpos;
1501 int ypos;
1502 unsigned int button;
1503 unsigned int mods;
1504 int clicknum;
1505 #endif
1506 {
1507 int px;
1508
1509 if (drag_inscroll && (drag_scrollmode==0 || drag_scrollmode==3)) {
1510 switch (button) { /* scrollbar */
1511 case Button1:
1512 px = (ypos - textwin_y) / lineheight;
1513 scroll_to(scrollline+px);
1514 break;
1515 case Button3:
1516 px = (ypos - textwin_y) / lineheight;
1517 scroll_to(scrollline-px);
1518 break;
1519 }
1520 }
1521 }
1522
1523 /* editing functions... */
1524
1525 #ifdef __STDC__
xted_init(int vbuflen,char * vbuffer,int * vreadpos,int * vkillflag,int firsttime)1526 void xted_init(int vbuflen, char *vbuffer, int *vreadpos, int *vkillflag,
1527 int firsttime)
1528 #else
1529 void xted_init(vbuflen, vbuffer, vreadpos, vkillflag, firsttime)
1530 int vbuflen;
1531 char *vbuffer;
1532 int *vreadpos;
1533 int *vkillflag;
1534 int firsttime;
1535 #endif
1536 {
1537 killflag = vkillflag;
1538 *killflag = (-1);
1539 buflen = vbuflen;
1540 buffer = vbuffer;
1541 readpos = vreadpos;
1542
1543 if (*readpos) {
1544 if (firsttime) {
1545 /* Z-machine has already entered the text into the buffer. */
1546 inputfence = numchars - (*readpos);
1547 originalattr = stylelist[numstyles-1].attr;
1548 xtext_setstyle(inputfence, prefs.inputattr);
1549 }
1550 else {
1551 /* The terp has to enter the text. */
1552 inputfence = numchars;
1553 originalattr = stylelist[numstyles-1].attr;
1554 xtext_setstyle(-1, prefs.inputattr);
1555 xtext_replace(dotpos, 0, buffer, *readpos);
1556 xtext_layout();
1557 }
1558 }
1559 else {
1560 inputfence = numchars;
1561 originalattr = stylelist[numstyles-1].attr;
1562 xtext_setstyle(-1, prefs.inputattr);
1563 }
1564
1565 historypos = historynum;
1566 }
1567
1568 #ifdef __STDC__
xted_insert(int ch)1569 void xted_insert(int ch)
1570 #else
1571 void xted_insert(ch)
1572 int ch;
1573 #endif
1574 {
1575 if (iscntrl(ch))
1576 ch = ' ';
1577
1578 if (dotpos < inputfence) {
1579 dotpos = numchars;
1580 dotlen = 0;
1581 }
1582 else {
1583 collapse_dot();
1584 }
1585
1586 xtext_add(ch, dotpos);
1587 xtext_layout();
1588 xtext_end_visible();
1589 }
1590
1591 #ifdef __STDC__
xted_delete(int op)1592 void xted_delete(int op)
1593 #else
1594 void xted_delete(op)
1595 int op;
1596 #endif
1597 {
1598 long pos;
1599
1600 if (dotpos < inputfence)
1601 return;
1602 collapse_dot();
1603
1604 switch (op) {
1605 case op_BackChar:
1606 if (dotpos <= inputfence)
1607 return;
1608 xtext_replace(dotpos-1, 1, "", 0);
1609 break;
1610 case op_ForeChar:
1611 if (dotpos < inputfence || dotpos >= numchars)
1612 return;
1613 xtext_replace(dotpos, 1, "", 0);
1614 break;
1615 case op_BackWord:
1616 pos = back_to_nonwhite(dotpos);
1617 pos = back_to_white(pos);
1618 if (pos < inputfence)
1619 pos = inputfence;
1620 if (pos >= dotpos)
1621 return;
1622 xtext_replace(pos, dotpos-pos, "", 0);
1623 break;
1624 case op_ForeWord:
1625 pos = fore_to_nonwhite(dotpos);
1626 pos = fore_to_white(pos);
1627 if (pos < inputfence)
1628 pos = inputfence;
1629 if (pos <= dotpos)
1630 return;
1631 xtext_replace(dotpos, pos-dotpos, "", 0);
1632 break;
1633 }
1634 xtext_layout();
1635 }
1636
1637 #ifdef __STDC__
xted_enter(int op)1638 void xted_enter(int op)
1639 #else
1640 void xted_enter(op)
1641 int op;
1642 #endif
1643 {
1644 int len;
1645
1646 if (op != op_Enter)
1647 return;
1648
1649 if (killflag)
1650 *killflag = '\n';
1651 xtext_setstyle(-1, originalattr);
1652
1653 len = numchars-inputfence;
1654 if (len > buflen)
1655 len = buflen;
1656 memmove(buffer, charbuf+inputfence, len*sizeof(char));
1657 *readpos = len;
1658
1659 if (len) {
1660 /* add to history */
1661 if (historynum==prefs.historylength) {
1662 free(history[0].str);
1663 memmove(&history[0], &history[1], (prefs.historylength-1) * (sizeof(histunit)));
1664 }
1665 else
1666 historynum++;
1667 history[historynum-1].str = malloc(len*sizeof(char));
1668 memmove(history[historynum-1].str, charbuf+inputfence, len*sizeof(char));
1669 history[historynum-1].len = len;
1670 }
1671
1672 xtext_add('\n', -1);
1673 dotpos = numchars;
1674 dotlen = 0;
1675 xtext_layout();
1676
1677 /* a somewhat strange place to put the buffer trimmer, but what the heck. The status line shrinker too. */
1678 xstat_reset_window_size(op_Shrink);
1679 if (numchars > prefs.buffersize + prefs.bufferslack) {
1680 long lx;
1681 for (lx=0; lx<numlines; lx++)
1682 if (linelist[lx].pos > (numchars-prefs.buffersize))
1683 break;
1684 if (lx) {
1685 xtext_delete_start(lx);
1686 }
1687 }
1688 }
1689
1690 #ifdef __STDC__
xtext_line_timeout()1691 void xtext_line_timeout()
1692 #else
1693 void xtext_line_timeout()
1694 #endif
1695 {
1696 int len;
1697
1698 /* same as xted_enter(), but skip the unnecessary stuff.
1699 We don't need to add to history, collapse the dot, xtext_layout, trim the buffer, or shrink the status window. */
1700
1701 len = numchars-inputfence;
1702 if (len > buflen)
1703 len = buflen;
1704 memmove(buffer, charbuf+inputfence, len*sizeof(char));
1705 *readpos = len;
1706
1707 if (len) {
1708 xtext_replace(inputfence, len, "", 0);
1709 dotpos = numchars;
1710 dotlen = 0;
1711 xtext_layout();
1712 }
1713
1714 xtext_setstyle(-1, originalattr);
1715 }
1716
1717 #ifdef __STDC__
xted_scroll(int op)1718 void xted_scroll(int op)
1719 #else
1720 void xted_scroll(op)
1721 int op;
1722 #endif
1723 {
1724 switch (op) {
1725 case op_UpLine:
1726 scroll_to(scrollline-1);
1727 break;
1728 case op_DownLine:
1729 scroll_to(scrollline+1);
1730 break;
1731 case op_UpPage:
1732 scroll_to(scrollline-(linesperpage-1));
1733 break;
1734 case op_DownPage:
1735 scroll_to(scrollline+(linesperpage-1));
1736 break;
1737 case op_ToTop:
1738 scroll_to(0);
1739 break;
1740 case op_ToBottom:
1741 scroll_to(numlines);
1742 break;
1743 }
1744 }
1745
1746 #ifdef __STDC__
xted_movecursor(int op)1747 void xted_movecursor(int op)
1748 #else
1749 void xted_movecursor(op)
1750 int op;
1751 #endif
1752 {
1753 long pos;
1754
1755 switch (op) {
1756 case op_BackChar:
1757 collapse_dot();
1758 if (dotpos > 0)
1759 dotpos--;
1760 break;
1761 case op_ForeChar:
1762 collapse_dot();
1763 if (dotpos < numchars)
1764 dotpos++;
1765 break;
1766 case op_BackWord:
1767 collapse_dot();
1768 dotpos = back_to_nonwhite(dotpos);
1769 dotpos = back_to_white(dotpos);
1770 break;
1771 case op_ForeWord:
1772 collapse_dot();
1773 dotpos = fore_to_nonwhite(dotpos);
1774 dotpos = fore_to_white(dotpos);
1775 break;
1776 case op_BeginLine:
1777 if (dotlen) {
1778 dotlen = 0;
1779 }
1780 else {
1781 if (dotpos >= inputfence)
1782 dotpos = inputfence;
1783 else {
1784 pos = dotpos;
1785 while (pos > 0 && charbuf[pos-1] != '\n')
1786 pos--;
1787 dotpos = pos;
1788 }
1789 }
1790 break;
1791 case op_EndLine:
1792 if (dotlen) {
1793 collapse_dot();
1794 }
1795 else {
1796 if (dotpos >= inputfence)
1797 dotpos = numchars;
1798 else {
1799 pos = dotpos;
1800 while (pos < numchars && charbuf[pos] != '\n')
1801 pos++;
1802 dotpos = pos;
1803 }
1804 }
1805 break;
1806 }
1807 xtext_layout();
1808 }
1809
1810 #ifdef __STDC__
xted_cutbuf(int op)1811 void xted_cutbuf(int op)
1812 #else
1813 void xted_cutbuf(op)
1814 int op;
1815 #endif
1816 {
1817 char *cx;
1818 int num;
1819 long tmppos;
1820
1821 switch (op) {
1822 case op_Copy:
1823 if (dotlen) {
1824 XRotateBuffers(xiodpy, 1);
1825 XStoreBytes(xiodpy, charbuf+dotpos, sizeof(char)*dotlen);
1826 }
1827 break;
1828 case op_Wipe:
1829 if (dotlen) {
1830 XRotateBuffers(xiodpy, 1);
1831 XStoreBytes(xiodpy, charbuf+dotpos, sizeof(char)*dotlen);
1832 if (dotpos >= inputfence) {
1833 xtext_replace(dotpos, dotlen, "", 0);
1834 xtext_layout();
1835 }
1836 }
1837 break;
1838 case op_Yank:
1839 collapse_dot();
1840 if (dotpos < inputfence)
1841 dotpos = numchars;
1842 cx = XFetchBytes(xiodpy, &num);
1843 strip_garbage(cx, num);
1844 if (cx && num) {
1845 tmppos = dotpos;
1846 xtext_replace(tmppos, 0, cx, num);
1847 dotpos = tmppos;
1848 dotlen = num;
1849 free(cx);
1850 }
1851 xtext_layout();
1852 break;
1853 case op_Untype:
1854 if (numchars == inputfence)
1855 break;
1856 dotpos = inputfence;
1857 dotlen = numchars-inputfence;
1858 XRotateBuffers(xiodpy, 1);
1859 XStoreBytes(xiodpy, charbuf+dotpos, sizeof(char)*dotlen);
1860 xtext_replace(dotpos, dotlen, "", 0);
1861 xtext_layout();
1862 break;
1863 case op_Kill:
1864 if (dotpos < inputfence) {
1865 /* maybe extend to end-of-line and copy? */
1866 break;
1867 }
1868 dotlen = numchars-dotpos;
1869 XRotateBuffers(xiodpy, 1);
1870 XStoreBytes(xiodpy, charbuf+dotpos, sizeof(char)*dotlen);
1871 xtext_replace(dotpos, dotlen, "", 0);
1872 xtext_layout();
1873 break;
1874 }
1875 }
1876
1877 #ifdef __STDC__
xted_history(int op)1878 void xted_history(int op)
1879 #else
1880 void xted_history(op)
1881 int op;
1882 #endif
1883 {
1884 long pos, len;
1885
1886 switch (op) {
1887 case op_BackLine:
1888 if (historypos > 0) {
1889 if (dotpos < inputfence) {
1890 dotpos = numchars;
1891 dotlen = 0;
1892 }
1893 historypos--;
1894 pos = dotpos;
1895 xtext_replace(pos, dotlen, history[historypos].str, history[historypos].len);
1896 dotpos = pos;
1897 dotlen = history[historypos].len;
1898 xtext_layout();
1899 }
1900 break;
1901 case op_ForeLine:
1902 if (historypos < historynum) {
1903 if (dotpos < inputfence) {
1904 dotpos = numchars;
1905 dotlen = 0;
1906 }
1907 historypos++;
1908 if (historypos < historynum) {
1909 pos = dotpos;
1910 xtext_replace(dotpos, dotlen, history[historypos].str, history[historypos].len);
1911 dotpos = pos;
1912 dotlen = history[historypos].len;
1913 }
1914 else {
1915 pos = dotpos;
1916 xtext_replace(dotpos, dotlen, "", 0);
1917 dotpos = pos;
1918 dotlen = 0;
1919 }
1920 xtext_layout();
1921 }
1922 }
1923 }
1924
1925 #ifdef __STDC__
xted_define_macro(int keynum)1926 void xted_define_macro(int keynum)
1927 #else
1928 void xted_define_macro(keynum)
1929 int keynum;
1930 #endif
1931 {
1932 static cmdentry *macrocommand = NULL;
1933 char buf[256];
1934 char *cx, *cx2;
1935
1936 if (!macrocommand) {
1937 macrocommand = xkey_find_cmd_by_name("macro");
1938 if (!macrocommand) {
1939 xmess_set_message("Error: unable to find macro command entry.", FALSE);
1940 return;
1941 }
1942 }
1943 if (keycmds[keynum] != macrocommand) {
1944 cx = xkey_get_key_name(keynum);
1945 sprintf(buf, "Key <%s> is not bound to the macro command.", cx);
1946 xmess_set_message(buf, FALSE);
1947 return;
1948 }
1949
1950 if (dotlen == 0) {
1951 xmess_set_message("You must highlight a string to define this macro to.", FALSE);
1952 return;
1953 }
1954
1955 cx2 = (char *)malloc(sizeof(char) * (dotlen+1));
1956 memcpy(cx2, charbuf+dotpos, dotlen * sizeof(char));
1957 cx2[dotlen] = '\0';
1958 strip_garbage(cx2, dotlen);
1959
1960 if (keycmdargs[keynum])
1961 free(keycmdargs[keynum]);
1962 keycmdargs[keynum] = cx2;
1963 cx = xkey_get_key_name(keynum);
1964 if (!cx2 || !cx2[0])
1965 sprintf(buf, "Macro <%s> is not defined.", cx);
1966 else if (strlen(cx2) > (sizeof(buf)-64))
1967 sprintf(buf, "Macro <%s> is defined to something too long to display.", cx);
1968 else
1969 sprintf(buf, "Macro <%s> defined to \"%s\".", cx, cx2);
1970 xmess_set_message(buf, FALSE);
1971 }
1972
1973 #ifdef __STDC__
xted_macro(int op)1974 void xted_macro(int op)
1975 #else
1976 void xted_macro(op)
1977 int op;
1978 #endif
1979 {
1980 char *str, *cx;
1981
1982 str = keycmdargs[op];
1983 if (!str || !str[0]) {
1984 char buf[128];
1985 cx = xkey_get_key_name(op);
1986 sprintf(buf, "Macro <%s> is not defined.", cx);
1987 xmess_set_message(buf, FALSE);
1988 return;
1989 }
1990
1991 if (dotpos < inputfence) {
1992 dotpos = numchars;
1993 dotlen = 0;
1994 }
1995 else {
1996 collapse_dot();
1997 }
1998
1999 xtext_replace(dotpos, 0, str, strlen(str));
2000
2001 xtext_layout();
2002 xtext_end_visible();
2003 }
2004
2005 #ifdef __STDC__
xted_noop(int op)2006 void xted_noop(int op)
2007 #else
2008 void xted_noop(op)
2009 int op;
2010 #endif
2011 {
2012 /* good for debugging */
2013 }
2014