~ubuntu-branches/ubuntu/wily/xzip/wily

1 by Daniel Schepler
Import upstream version 1.8.2
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__
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__
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__
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__
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__
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__
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__
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__
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__
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__
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__
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__
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__
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__
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__
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__
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__
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__
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__
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__
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__
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__
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__
914
void xtext_set_lastseen()
915
#else
916
void xtext_set_lastseen()
917
#endif
918
{
919
    lastlineseen = numlines;
920
}
921
922
#ifdef __STDC__
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__
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__
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__
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__
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__
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__
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__
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__
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__
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__
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__
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__
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__
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__
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__
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__
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__
2006
void xted_noop(int op)
2007
#else
2008
void xted_noop(op)
2009
int op;
2010
#endif
2011
{
2012
    /* good for debugging */
2013
}