1 #include <stdlib.h>
2 #include <string.h>
3 #include "xglk.h"
4 #include "xg_internal.h"
5 #include "xg_win_textbuf.h"
6
7 #define stype_Text (0)
8 #define stype_Image (1)
9 #define stype_Break (2)
10
11 /* ### find and kill: cutwin->font.line{height,off} */
12
13 typedef struct style_struct {
14 int stype;
15 int imagealign; /* from the Glk constants */
16 glui32 linkid; /* for hyperlinks */
17 glui32 image; /* resource ID */
18 glui32 imagewidth, imageheight; /* scaled bounds */
19 glui32 attr; /* a style number */
20 long pos; /* position this style starts at */
21 } style_t;
22
23 typedef struct imageword_struct {
24 picture_t *pic;
25 long width, height; /* scaled bounds */
26 long pos; /* inline: distance up from the baseline to put top edge;
27 margin: distance in from margin. */
28 int imagealign; /* from the Glk constants */
29 } imageword_t;
30
31 typedef struct word_struct {
32 int stype;
33 long pos, len;
34 long width; /* in pixels */
35 glui32 attr;
36 glui32 linkid;
37 union {
38 long *letterpos; /* if not NULL, an array[0..len] of pixel offsets
39 from wordpos; */
40 imageword_t *image;
41 } u;
42 } word_t;
43
44 #define lineflag_Wrapped (1) /* line is a wrap or split from previous line */
45 #define lineflag_Extra (2) /* the magic extra line on the end */
46
47 typedef struct lline_struct {
48 long pos; /* line starts here */
49 long posend; /* number of chars. May not be exactly to start of next line,
50 because it won't include the newline or space that ends
51 the line. */
52 long indent; /* in pixels, from textwin_w (0 or greater) */
53 word_t *wordlist;
54 long numwords;
55 long height; /* in pixels */
56 long off; /* baseline offset from top, in pixels */
57 long leftindent; /* how much flow-object there is on the left margin */
58 long leftbelow; /* how much of that object hangs below this line */
59 long rightindent; /* how much flow-object there is on the right margin */
60 long rightbelow; /* how much of that object hangs below this line */
61 int flags;
62 } lline_t;
63
64 typedef struct histunit {
65 char *str;
66 int len;
67 } histunit;
68
69 struct window_textbuffer_struct {
70 window_t *owner;
71 XRectangle bbox;
72
73 int textwin_x, textwin_y, textwin_w, textwin_h; /* bbox minus margins */
74 /*XRectangle textwin_cursor_box;*/ /* This is the area in which the cursor
75 is an ibeam. Assuming we do cursors. */
76 wegscroll_t scrollbar;
77
78 stylehints_t hints;
79 fontset_t font;
80
81 char *charbuf;
82 long numchars;
83 long char_size;
84
85 style_t *stylelist;
86 long numstyles;
87 long styles_size;
88
89 lline_t *linelist;
90 long numlines;
91 long lines_size;
92
93 lline_t *tmplinelist;
94 long tmplines_size;
95
96 long scrollpos; /* character position at top of screen */
97 long scrollline; /* number of line at top of screen, after
98 win_textbuffer_layout() */
99 long lastseenline; /* last line read before more stuff was output. If
100 everything has been read, this is numlines. */
101 long dotpos, dotlen; /* dotpos is in [0..numchars] */
102 long lastdotpos, lastdotlen; /* cached values -- fiddled inside
103 win_textbuffer_layout() */
104
105 long linesonpage; /* this stuff is set by xtext_layout() too. */
106 long lineoffset_size;
107 int *lineoffsetlist; /* In [0..linesonpage], and the first element is
108 zero. */
109
110 long drag_firstbeg, drag_firstend;
111 int drag_inscroll;
112 glui32 drag_firstlink;
113
114 int isactive; /* is window active? */
115
116 long dirtybeg, dirtyend; /* mark the limits of what needs to be laid
117 out, [) format */
118 long dirtydelta; /* how much the dirty area has grown (or shrunk) */
119
120 int isclear;
121
122 int historylength; /* cached in case the pref is changed */
123 int historynum, historypos;
124 histunit *history;
125
126 /* these are for line input */
127 long buflen;
128 char *buffer;
129 long inputfence;
130 glui32 originalattr;
131 gidispatch_rock_t inarrayrock;
132 };
133
134 #define collapse_dot(cwin) (cwin->dotpos += cwin->dotlen, cwin->dotlen = 0)
135 #define SIDEMARGIN (0)
136 #define BARWIDTH (18)
137 #define MACSTYLESCROLL
138
139 static void redrawtext(window_textbuffer_t *cutwin, long beg,
140 long num, int clearnum);
141 static void win_textbuffer_layout(window_textbuffer_t *cutwin);
142 static void flip_selection(window_textbuffer_t *cutwin, long dpos, long dlen);
143 static long find_loc_by_pos(window_textbuffer_t *cutwin, long pos,
144 int *xposret, int *yposret);
145 static long find_pos_by_loc(window_textbuffer_t *cutwin, int xpos, int ypos,
146 long *truepos);
147 static long find_line_by_pos(window_textbuffer_t *cutwin, long pos,
148 long guessline);
149 static void measure_word(window_textbuffer_t *cutwin, lline_t *curline,
150 word_t *curword);
151 static void win_textbuffer_line_cancel(window_textbuffer_t *cutwin,
152 event_t *ev);
153 static void win_textbuffer_setstyle(window_textbuffer_t *cutwin,
154 long pos, int stype,
155 glui32 attr, glui32 linkid, glui32 image, int imagealign,
156 glui32 imagewidth, glui32 imageheight);
157 static void readd_lineheights(window_textbuffer_t *cutwin, long lx);
158
159 static long back_to_white(window_textbuffer_t *cutwin, long pos);
160 static long fore_to_white(window_textbuffer_t *cutwin, long pos);
161 static long back_to_nonwhite(window_textbuffer_t *cutwin, long pos);
162 static long fore_to_nonwhite(window_textbuffer_t *cutwin, long pos);
163 static void delete_imageword(imageword_t *iwd);
164
win_textbuffer_create(window_t * win)165 window_textbuffer_t *win_textbuffer_create(window_t *win)
166 {
167 window_textbuffer_t *res =
168 (window_textbuffer_t *)malloc(sizeof(window_textbuffer_t));
169 if (!res)
170 return NULL;
171
172 res->owner = win;
173
174 gli_stylehints_for_window(wintype_TextBuffer, &(res->hints));
175 gli_styles_compute(&(res->font), &(res->hints));
176
177 res->char_size = 256;
178 res->charbuf = (char *)malloc(sizeof(char) * res->char_size);
179 res->numchars = 0;
180
181 res->styles_size = 8;
182 res->stylelist = (style_t *)malloc(sizeof(style_t) * res->styles_size);
183 res->numstyles = 1;
184 res->stylelist[0].pos = 0;
185 res->stylelist[0].stype = stype_Text;
186 res->stylelist[0].attr = style_Normal;
187 res->stylelist[0].linkid = 0;
188 res->stylelist[0].image = 0;
189 res->stylelist[0].imagealign = 0;
190
191 res->lines_size = 8;
192 res->linelist = (lline_t *)malloc(sizeof(lline_t) * res->lines_size);
193 res->numlines = 0;
194
195 res->tmplines_size = 8;
196 res->tmplinelist = (lline_t *)malloc(sizeof(lline_t) * res->tmplines_size);
197
198 res->historynum = 0;
199 res->historylength = prefs.historylength;
200 res->history = (histunit *)malloc(res->historylength * sizeof(histunit));
201
202 res->scrollpos = 0;
203 res->scrollline = 0;
204 xweg_init_scrollbar(&res->scrollbar, win, xgc_scroll, xgc_scrollto);
205
206 res->dirtybeg = 0;
207 res->dirtyend = 0;
208 res->dirtydelta = 0;
209
210 res->dotpos = 0;
211 res->dotlen = 0;
212 res->lastdotpos = -1;
213 res->lastdotlen = 0;
214
215 res->drag_firstbeg = 0;
216 res->drag_firstend = 0;
217 res->drag_firstlink = 0;
218 res->drag_inscroll = FALSE;
219
220 res->isactive = FALSE;
221
222 res->lastseenline = 0;
223 res->isclear = TRUE;
224
225 res->linesonpage = 0;
226 res->lineoffset_size = 80;
227 res->lineoffsetlist = (int *)malloc(res->lineoffset_size * sizeof(int));
228 res->lineoffsetlist[0] = 0;
229 /*### res->charsperline = 0; */
230
231 res->buffer = NULL;
232 res->buflen = 0;
233 res->inputfence = 0;
234
235 return res;
236 }
237
win_textbuffer_destroy(struct window_textbuffer_struct * dwin)238 void win_textbuffer_destroy(struct window_textbuffer_struct *dwin)
239 {
240 int ix;
241
242 if (dwin->buffer) {
243 if (gli_unregister_arr) {
244 (*gli_unregister_arr)(dwin->buffer, dwin->buflen, "&+#!Cn",
245 dwin->inarrayrock);
246 }
247 dwin->buffer = NULL;
248 }
249
250 if (dwin->history) {
251 for (ix=0; ix<dwin->historynum; ix++) {
252 free(dwin->history[ix].str);
253 }
254 free(dwin->history);
255 dwin->history = NULL;
256 }
257
258 if (dwin->stylelist) {
259 free(dwin->stylelist);
260 dwin->stylelist = NULL;
261 }
262
263 if (dwin->linelist) {
264 long lx, wx;
265
266 for (lx=0; lx<dwin->numlines; lx++) {
267 word_t *thisword;
268 for (wx=0, thisword=dwin->linelist[lx].wordlist;
269 wx<dwin->linelist[lx].numwords;
270 wx++, thisword++) {
271 if (thisword->stype == stype_Text) {
272 if (thisword->u.letterpos) {
273 free(thisword->u.letterpos);
274 thisword->u.letterpos = NULL;
275 }
276 }
277 else if (thisword->stype == stype_Image) {
278 if (thisword->u.image) {
279 delete_imageword(thisword->u.image);
280 thisword->u.image = NULL;
281 }
282 }
283 }
284 free(dwin->linelist[lx].wordlist);
285 dwin->linelist[lx].wordlist = NULL;
286 }
287
288 free(dwin->linelist);
289 dwin->linelist = NULL;
290 }
291
292 if (dwin->tmplinelist) {
293 /* don't free contents; they're owned by linelist. */
294 free(dwin->tmplinelist);
295 dwin->tmplinelist = NULL;
296 }
297
298 if (dwin->charbuf) {
299 free(dwin->charbuf);
300 dwin->charbuf = NULL;
301 }
302
303 free(dwin);
304 }
305
win_textbuffer_rearrange(window_t * win,XRectangle * box)306 void win_textbuffer_rearrange(window_t *win, XRectangle *box)
307 {
308 window_textbuffer_t *cutwin = win->data;
309
310 int xpos = box->x;
311 int ypos = box->y;
312 int width = box->width;
313 int height = box->height;
314
315 cutwin->bbox = *box;
316
317 cutwin->textwin_x = xpos+SIDEMARGIN+prefs.textbuffer.marginx;
318 cutwin->textwin_y = ypos+prefs.textbuffer.marginy;
319 cutwin->textwin_w = width-2*SIDEMARGIN-BARWIDTH-2*prefs.textbuffer.marginx;
320 cutwin->textwin_h = height-2*prefs.textbuffer.marginy;
321
322 cutwin->scrollbar.box.y = ypos;
323 cutwin->scrollbar.box.height = height;
324 cutwin->scrollbar.box.width = BARWIDTH;
325 cutwin->scrollbar.box.x = xpos + width - BARWIDTH;
326
327 /*
328 cutwin->textwin_cursor_box.x = xpos;
329 cutwin->textwin_cursor_box.y = ypos;
330 cutwin->textwin_cursor_box.width = width - BARWIDTH;
331 cutwin->textwin_cursor_box.height = height;
332 */
333
334 cutwin->dirtybeg = 0;
335 cutwin->dirtyend = cutwin->numchars;
336 cutwin->dirtydelta = 0;
337
338 cutwin->linesonpage = 0;
339 cutwin->lineoffsetlist[0] = 0;
340 /* This will be set to something real later. */
341 }
342
win_textbuffer_get_rect(window_t * win)343 XRectangle *win_textbuffer_get_rect(window_t *win)
344 {
345 window_textbuffer_t *dwin = win->data;
346 return &dwin->bbox;
347 }
348
win_textbuffer_get_size(window_t * win,glui32 * width,glui32 * height)349 void win_textbuffer_get_size(window_t *win, glui32 *width, glui32 *height)
350 {
351 window_textbuffer_t *dwin = win->data;
352 *width = 0; /*###dwin->linesperpage; */
353 *height = 0; /*###dwin->charsperline; */
354 }
355
win_textbuffer_figure_size(window_t * win,long size,int vertical)356 long win_textbuffer_figure_size(window_t *win, long size, int vertical)
357 {
358 window_textbuffer_t *dwin = win->data;
359
360 if (vertical) {
361 /* size * charwidth */
362 long textwin_w = size * dwin->font.gc[style_Normal].spacewidth;
363 return textwin_w + 2*SIDEMARGIN + BARWIDTH + 2*prefs.textbuffer.marginx;
364 }
365 else {
366 /* size * lineheight */
367 long textwin_h = size * dwin->font.lineheight;
368 return textwin_h + 2*prefs.textbuffer.marginy;
369 }
370 }
371
win_textbuffer_get_fontset(window_t * win)372 fontset_t *win_textbuffer_get_fontset(window_t *win)
373 {
374 window_textbuffer_t *dwin = win->data;
375 return &(dwin->font);
376 }
377
win_textbuffer_get_stylehints(window_t * win)378 stylehints_t *win_textbuffer_get_stylehints(window_t *win)
379 {
380 window_textbuffer_t *dwin = win->data;
381 return &(dwin->hints);
382 }
383
win_textbuffer_redraw(window_t * win)384 void win_textbuffer_redraw(window_t *win)
385 {
386 window_textbuffer_t *cutwin = win->data;
387
388 gli_draw_window_outline(&cutwin->bbox);
389
390 gli_draw_window_margin(&(cutwin->font.backcolor),
391 cutwin->bbox.x, cutwin->bbox.y,
392 cutwin->bbox.width-BARWIDTH, cutwin->bbox.height,
393 cutwin->textwin_x-SIDEMARGIN, cutwin->textwin_y,
394 cutwin->textwin_w+2*SIDEMARGIN, cutwin->textwin_h);
395
396 xweg_draw_scrollbar(&cutwin->scrollbar);
397
398 if (cutwin->dirtybeg >= 0 || cutwin->dirtyend >= 0) {
399 /* something is dirty. Go through the whole shebang. */
400 win_textbuffer_layout(cutwin);
401 return;
402 }
403
404 /* this assumes that an exposure event will not come in
405 between a data update and an win_textbuffer_layout call. */
406 /*flip_selection(cutwin->dotpos, cutwin->dotlen);*/
407 redrawtext(cutwin, 0, -1, -1);
408 flip_selection(cutwin, cutwin->dotpos, cutwin->dotlen);
409
410 xweg_adjust_scrollbar(&cutwin->scrollbar, cutwin->numlines,
411 cutwin->scrollline, cutwin->linesonpage);
412 }
413
win_textbuffer_flush(window_t * win)414 void win_textbuffer_flush(window_t *win)
415 {
416 window_textbuffer_t *cutwin = win->data;
417 win_textbuffer_layout(cutwin);
418 }
419
win_textbuffer_setfocus(window_t * win,int turnon)420 void win_textbuffer_setfocus(window_t *win, int turnon)
421 {
422 window_textbuffer_t *cutwin = win->data;
423
424 if (turnon) {
425 if (!cutwin->isactive) {
426 cutwin->isactive = TRUE;
427 flip_selection(cutwin, cutwin->dotpos, cutwin->dotlen);
428 }
429 }
430 else {
431 if (cutwin->isactive) {
432 flip_selection(cutwin, cutwin->dotpos, cutwin->dotlen);
433 cutwin->isactive = FALSE;
434 }
435 }
436 }
win_textbuffer_init_line(window_t * win,char * buffer,int buflen,int readpos)437 void win_textbuffer_init_line(window_t *win, char *buffer, int buflen,
438 int readpos)
439 {
440 window_textbuffer_t *cutwin = win->data;
441
442 cutwin->buflen = buflen;
443 cutwin->buffer = buffer;
444
445 if (readpos) {
446 /* The terp has to enter the text. */
447 cutwin->inputfence = cutwin->numchars;
448 cutwin->originalattr = cutwin->stylelist[cutwin->numstyles-1].attr;
449 win_textbuffer_set_style_text(cutwin, style_Input);
450 win_textbuffer_replace(cutwin, cutwin->inputfence, 0,
451 cutwin->buffer, readpos);
452 win_textbuffer_layout(cutwin);
453 }
454 else {
455 cutwin->inputfence = cutwin->numchars;
456 cutwin->originalattr = cutwin->stylelist[cutwin->numstyles-1].attr;
457 win_textbuffer_set_style_text(cutwin, style_Input);
458 }
459
460 cutwin->historypos = cutwin->historynum;
461
462 if (gli_register_arr) {
463 cutwin->inarrayrock = (*gli_register_arr)(buffer, buflen, "&+#!Cn");
464 }
465 }
466
win_textbuffer_cancel_line(window_t * win,event_t * ev)467 void win_textbuffer_cancel_line(window_t *win, event_t *ev)
468 {
469 window_textbuffer_t *cutwin = win->data;
470 win_textbuffer_line_cancel(cutwin, ev);
471 }
472
win_textbuffer_perform_click(window_t * win,int dir,XPoint * pt,int butnum,int clicknum,unsigned int state)473 void win_textbuffer_perform_click(window_t *win, int dir, XPoint *pt,
474 int butnum, int clicknum, unsigned int state)
475 {
476 window_textbuffer_t *cutwin = win->data;
477 long pos, hitpos;
478 long px, px2;
479
480 if (dir == mouse_Down) {
481 cutwin->drag_firstlink = 0;
482 if (pt->x >= cutwin->scrollbar.box.x)
483 cutwin->drag_inscroll = TRUE;
484 else
485 cutwin->drag_inscroll = FALSE;
486
487 if (cutwin->drag_inscroll) {
488 xweg_click_scrollbar(&cutwin->scrollbar, dir, pt, butnum,
489 clicknum, state,
490 cutwin->numlines, cutwin->scrollline, cutwin->linesonpage);
491 }
492 else {
493 pt->x -= cutwin->textwin_x;
494 pt->y -= cutwin->textwin_y;
495
496 pos = find_pos_by_loc(cutwin, pt->x, pt->y, &hitpos);
497 if (butnum==1) {
498 if (!(clicknum & 1)) {
499 px = back_to_white(cutwin, pos);
500 px2 = fore_to_white(cutwin, pos);
501 }
502 else {
503 if (cutwin->owner->hyperlink_request) {
504 long sx;
505 /* find the last style at or before hitpos. */
506 for (sx=cutwin->numstyles-1; sx>=0; sx--) {
507 if (cutwin->stylelist[sx].pos <= hitpos) {
508 cutwin->drag_firstlink = cutwin->stylelist[sx].linkid;
509 break;
510 }
511 }
512 }
513 px = pos;
514 px2 = pos;
515 }
516 cutwin->dotpos = px;
517 cutwin->dotlen = px2-px;
518 cutwin->drag_firstbeg = px;
519 cutwin->drag_firstend = px2;
520 }
521 else {
522 if (pos < cutwin->dotpos+cutwin->dotlen/2) {
523 cutwin->drag_firstbeg = cutwin->dotpos+cutwin->dotlen;
524 }
525 else {
526 cutwin->drag_firstbeg = cutwin->dotpos;
527 }
528 cutwin->drag_firstend = cutwin->drag_firstbeg;
529 if (pos < cutwin->drag_firstbeg) {
530 if (!(clicknum & 1))
531 cutwin->dotpos = back_to_white(cutwin, pos);
532 else
533 cutwin->dotpos = pos;
534 cutwin->dotlen = cutwin->drag_firstend-cutwin->dotpos;
535 }
536 else if (pos > cutwin->drag_firstend) {
537 cutwin->dotpos = cutwin->drag_firstbeg;
538 if (!(clicknum & 1))
539 cutwin->dotlen = fore_to_white(cutwin, pos)-cutwin->drag_firstbeg;
540 else
541 cutwin->dotlen = pos-cutwin->drag_firstbeg;
542 }
543 else {
544 cutwin->dotpos = cutwin->drag_firstbeg;
545 cutwin->dotlen = cutwin->drag_firstend-cutwin->drag_firstbeg;
546 }
547 }
548 win_textbuffer_layout(cutwin);
549 }
550 }
551 else if (dir == mouse_Move) {
552 if (cutwin->drag_inscroll) {
553 xweg_click_scrollbar(&cutwin->scrollbar, dir, pt, butnum,
554 clicknum, state,
555 cutwin->numlines, cutwin->scrollline, cutwin->linesonpage);
556 }
557 else {
558 pt->x -= cutwin->textwin_x;
559 pt->y -= cutwin->textwin_y;
560
561 pos = find_pos_by_loc(cutwin, pt->x, pt->y, &hitpos);
562
563 if (pos < cutwin->drag_firstbeg) {
564 if (!(clicknum & 1))
565 cutwin->dotpos = back_to_white(cutwin, pos);
566 else
567 cutwin->dotpos = pos;
568 cutwin->dotlen = cutwin->drag_firstend-cutwin->dotpos;
569 }
570 else if (pos > cutwin->drag_firstend) {
571 cutwin->dotpos = cutwin->drag_firstbeg;
572 if (!(clicknum & 1))
573 cutwin->dotlen = fore_to_white(cutwin, pos)-cutwin->drag_firstbeg;
574 else
575 cutwin->dotlen = pos-cutwin->drag_firstbeg;
576 }
577 else {
578 cutwin->dotpos = cutwin->drag_firstbeg;
579 cutwin->dotlen = cutwin->drag_firstend-cutwin->drag_firstbeg;
580 }
581 win_textbuffer_layout(cutwin);
582 }
583 }
584 else if (dir == mouse_Up) {
585 if (cutwin->drag_inscroll) {
586 }
587 else {
588 pt->x -= cutwin->textwin_x;
589 pt->y -= cutwin->textwin_y;
590 if (cutwin->drag_firstlink && cutwin->owner->hyperlink_request) {
591 pos = find_pos_by_loc(cutwin, pt->x, pt->y, &hitpos);
592 if (pos == cutwin->drag_firstbeg) {
593 cutwin->owner->hyperlink_request = FALSE;
594 eventloop_setevent(evtype_Hyperlink, cutwin->owner,
595 cutwin->drag_firstlink, 0);
596 /* suppressdblclick = TRUE; */
597 }
598 }
599 }
600 }
601 }
602
delete_imageword(imageword_t * iwd)603 static void delete_imageword(imageword_t *iwd)
604 {
605 if (iwd->pic) {
606 picture_release(iwd->pic);
607 iwd->pic = NULL;
608 }
609 free(iwd);
610 }
611
back_to_white(window_textbuffer_t * cutwin,long pos)612 static long back_to_white(window_textbuffer_t *cutwin, long pos)
613 {
614 char *charbuf = cutwin->charbuf;
615 long inputfence = cutwin->inputfence;
616 while (pos > 0 && charbuf[pos-1] != ' ' && charbuf[pos-1] != '\n' && pos-1 != inputfence-1)
617 pos--;
618 return pos;
619 }
620
fore_to_white(window_textbuffer_t * cutwin,long pos)621 static long fore_to_white(window_textbuffer_t *cutwin, long pos)
622 {
623 char *charbuf = cutwin->charbuf;
624 long inputfence = cutwin->inputfence;
625 long numchars = cutwin->numchars;
626 while (pos < numchars && charbuf[pos] != ' ' && charbuf[pos] != '\n' && pos != inputfence-1)
627 pos++;
628 return pos;
629 }
630
back_to_nonwhite(window_textbuffer_t * cutwin,long pos)631 static long back_to_nonwhite(window_textbuffer_t *cutwin, long pos)
632 {
633 char *charbuf = cutwin->charbuf;
634 long inputfence = cutwin->inputfence;
635 while (pos > 0 && (charbuf[pos-1] == ' ' || charbuf[pos-1] == '\n' || pos-1 == inputfence-1))
636 pos--;
637 return pos;
638 }
639
fore_to_nonwhite(window_textbuffer_t * cutwin,long pos)640 static long fore_to_nonwhite(window_textbuffer_t *cutwin, long pos)
641 {
642 char *charbuf = cutwin->charbuf;
643 long inputfence = cutwin->inputfence;
644 long numchars = cutwin->numchars;
645 while (pos < numchars && (charbuf[pos] == ' ' || charbuf[pos] == '\n' || pos == inputfence-1))
646 pos++;
647 return pos;
648 }
649
650 /* Coordinates are in screen lines. If num < 0, go to the end. clearnum is the
651 number of lines to clear (may be to a notional line); if 0, don't clear at
652 all; if -1, clear whole window. */
redrawtext(window_textbuffer_t * cutwin,long beg,long num,int clearnum)653 static void redrawtext(window_textbuffer_t *cutwin, long beg, long num,
654 int clearnum)
655 {
656 long lx, wx, end;
657 int ypos, ypos2, xpos;
658 lline_t *thisline;
659 fontref_t *gclist;
660 word_t *thisword;
661 int textwin_x, textwin_y, textwin_w, textwin_h;
662 XRectangle textwinbox;
663
664 /* cache some much-used values. */
665 gclist = cutwin->font.gc;
666 textwinbox.x = textwin_x = cutwin->textwin_x;
667 textwinbox.y = textwin_y = cutwin->textwin_y;
668 textwinbox.width = textwin_w = cutwin->textwin_w;
669 textwinbox.height = textwin_h = cutwin->textwin_h;
670
671 if (num<0)
672 end = cutwin->numlines;
673 else {
674 end = beg+num;
675 if (end > cutwin->numlines)
676 end = cutwin->numlines;
677 }
678
679 if (beg < cutwin->scrollline)
680 beg = cutwin->scrollline;
681
682 if (clearnum != 0) {
683 if (beg-cutwin->scrollline < 0) {
684 ypos = textwin_y;
685 }
686 else if (beg-cutwin->scrollline >= cutwin->linesonpage) {
687 ypos = textwin_y + cutwin->lineoffsetlist[cutwin->linesonpage];
688 }
689 else {
690 ypos = textwin_y + cutwin->lineoffsetlist[beg-cutwin->scrollline];
691 }
692 if (clearnum > 0) {
693 long clearend = beg+clearnum;
694 if (clearend-cutwin->scrollline < 0) {
695 ypos2 = textwin_y;
696 }
697 else if (clearend-cutwin->scrollline >= cutwin->linesonpage) {
698 ypos2 = textwin_y + textwin_h;
699 }
700 else {
701 ypos2 = textwin_y + cutwin->lineoffsetlist[clearend-cutwin->scrollline];
702 }
703 }
704 else {
705 ypos2 = textwin_y+textwin_h;
706 }
707 if (ypos < ypos2) {
708 xglk_clearfor_string(&(cutwin->font.backcolor),
709 textwin_x-SIDEMARGIN, ypos,
710 textwin_w+2*SIDEMARGIN, ypos2-ypos);
711 }
712 }
713
714 /* Back up and draw any hanging images above. */
715 if (beg < end
716 && (cutwin->linelist[beg].leftindent || cutwin->linelist[beg].rightindent)) {
717 int stillleft = (cutwin->linelist[beg].leftindent != 0);
718 int stillright = (cutwin->linelist[beg].rightindent != 0);
719 ypos = textwin_y + cutwin->lineoffsetlist[beg-cutwin->scrollline];
720 for (lx = beg-1; lx >= 0; lx--) {
721 thisline = (&cutwin->linelist[lx]);
722 if (thisline->leftbelow == 0)
723 stillleft = FALSE;
724 if (thisline->rightbelow == 0)
725 stillright = FALSE;
726 if (!stillleft && !stillright)
727 break;
728 ypos -= thisline->height;
729 for (wx=0; wx<thisline->numwords; wx++) {
730 thisword = thisline->wordlist+wx;
731 if (thisword->stype == stype_Image) {
732 imageword_t *iwd = thisword->u.image;
733 if (iwd) {
734 if (iwd->imagealign == imagealign_MarginLeft) {
735 if (stillleft)
736 picture_draw(iwd->pic, xiowin, textwin_x+iwd->pos, ypos,
737 iwd->width, iwd->height, &textwinbox);
738 }
739 else if (iwd->imagealign == imagealign_MarginRight) {
740 if (stillright)
741 picture_draw(iwd->pic, xiowin,
742 (textwin_x+textwin_w-iwd->width)-iwd->pos,
743 ypos, iwd->width, iwd->height, &textwinbox);
744 }
745 }
746 }
747 else if (thisword->stype == stype_Text) {
748 break;
749 }
750 }
751 }
752 }
753
754 /* The main line-drawing loop. */
755 for (lx=beg; lx<end; lx++) {
756 thisline = (&cutwin->linelist[lx]);
757 if (lx-cutwin->scrollline >= cutwin->linesonpage) {
758 break;
759 }
760 ypos = textwin_y + cutwin->lineoffsetlist[lx-cutwin->scrollline];
761 xpos = textwin_x + thisline->indent;
762 for (wx=0; wx<thisline->numwords; wx++) {
763 thisword = thisline->wordlist+wx;
764 if (thisword->stype == stype_Image) {
765 imageword_t *iwd = thisword->u.image;
766 if (iwd) {
767 if (iwd->imagealign == imagealign_MarginLeft) {
768 picture_draw(iwd->pic, xiowin, textwin_x+iwd->pos, ypos,
769 iwd->width, iwd->height, &textwinbox);
770 }
771 else if (iwd->imagealign == imagealign_MarginRight) {
772 picture_draw(iwd->pic, xiowin,
773 (textwin_x+textwin_w-iwd->width)-iwd->pos,
774 ypos, iwd->width, iwd->height, &textwinbox);
775 }
776 else {
777 picture_draw(iwd->pic, xiowin,
778 xpos, ypos+thisline->off-iwd->pos,
779 iwd->width, iwd->height, &textwinbox);
780 }
781 }
782 }
783 else if (thisword->stype == stype_Text) {
784 if (gclist[thisword->attr].backcolor.pixel
785 != cutwin->font.backcolor.pixel) {
786 xglk_clearfor_string(&(gclist[thisword->attr].backcolor),
787 xpos, ypos, thisword->width, thisline->height);
788 }
789 xglk_draw_string(&(gclist[thisword->attr]),
790 (thisword->linkid != 0), thisword->width,
791 xpos, ypos+thisline->off,
792 cutwin->charbuf+thisline->pos+thisword->pos, thisword->len);
793 }
794 xpos += thisword->width;
795 }
796 }
797 }
798
scroll_to(window_textbuffer_t * cutwin,long newscrollline)799 static void scroll_to(window_textbuffer_t *cutwin, long newscrollline)
800 {
801 long ix, val, total;
802 long oldscrollline;
803
804 #ifdef MACSTYLESCROLL
805 total = 0;
806 for (val = cutwin->numlines; val > 0; val--) {
807 total += cutwin->linelist[val-1].height;
808 if (total > cutwin->textwin_h)
809 break;
810 }
811 if (newscrollline > val)
812 newscrollline = val;
813 if (newscrollline < 0)
814 newscrollline = 0;
815 #else
816 if (newscrollline > cutwin->numlines-cutwin->linesonpage)
817 newscrollline = cutwin->numlines-cutwin->linesonpage;
818 if (newscrollline < 0)
819 newscrollline = 0;
820 #endif
821
822 if (cutwin->numlines == 0)
823 cutwin->scrollpos = 0;
824 else
825 cutwin->scrollpos = cutwin->linelist[newscrollline].pos;
826
827 if (cutwin->scrollline != newscrollline) {
828 oldscrollline = cutwin->scrollline;
829 if (!xiobackstore
830 || oldscrollline + cutwin->linesonpage <= newscrollline
831 || newscrollline + cutwin->linesonpage <= oldscrollline) {
832 /* scroll to an entirely new place. */
833 cutwin->scrollline = newscrollline;
834 readd_lineheights(cutwin, cutwin->scrollline);
835 redrawtext(cutwin, cutwin->scrollline, -1, -1);
836 flip_selection(cutwin, cutwin->dotpos, cutwin->dotlen);
837 }
838 else {
839 int ypos1, ypos2, yhgt;
840 long oldlop, diff;
841 flip_selection(cutwin, cutwin->dotpos, cutwin->dotlen);
842 cutwin->scrollline = newscrollline;
843 if (oldscrollline < newscrollline) {
844 /* scroll down -- things move up */
845 ypos1 = cutwin->textwin_y + cutwin->lineoffsetlist[newscrollline-oldscrollline];
846 ypos2 = cutwin->textwin_y;
847 yhgt = cutwin->textwin_y + cutwin->textwin_h - ypos1;
848 XCopyArea(xiodpy, xiowin, xiowin, gcfore,
849 cutwin->textwin_x-SIDEMARGIN, ypos1,
850 cutwin->textwin_w+2*SIDEMARGIN, yhgt,
851 cutwin->textwin_x-SIDEMARGIN, ypos2);
852 oldlop = cutwin->linesonpage;
853 readd_lineheights(cutwin, cutwin->scrollline);
854 diff = (cutwin->scrollline + cutwin->linesonpage) - (oldscrollline + oldlop);
855 redrawtext(cutwin, oldscrollline + oldlop, diff, diff);
856 }
857 else {
858 /* scroll up -- things move down */
859 ypos2 = cutwin->textwin_y;
860 for (ix = newscrollline; ix < oldscrollline; ix++)
861 ypos2 += cutwin->linelist[ix].height;
862 ypos1 = cutwin->textwin_y;
863 yhgt = cutwin->textwin_y + cutwin->textwin_h - ypos2;
864 XCopyArea(xiodpy, xiowin, xiowin, gcfore,
865 cutwin->textwin_x-SIDEMARGIN, ypos1,
866 cutwin->textwin_w+2*SIDEMARGIN, yhgt,
867 cutwin->textwin_x-SIDEMARGIN, ypos2);
868 readd_lineheights(cutwin, cutwin->scrollline);
869 redrawtext(cutwin, newscrollline, (oldscrollline-newscrollline),
870 (oldscrollline-newscrollline));
871 }
872 flip_selection(cutwin, cutwin->dotpos, cutwin->dotlen);
873 }
874 xweg_adjust_scrollbar(&cutwin->scrollbar, cutwin->numlines,
875 cutwin->scrollline, cutwin->linesonpage);
876 }
877
878 if (cutwin->lastseenline < cutwin->scrollline) {
879 cutwin->lastseenline = cutwin->scrollline;
880 }
881 if (cutwin->lastseenline >= cutwin->numlines - cutwin->linesonpage) {
882 /* this is wrong -- linesonpage doesn't correctly measure lines at
883 the end. */
884 cutwin->lastseenline = cutwin->numlines;
885 }
886 }
887
refiddle_selection(window_textbuffer_t * cutwin,long oldpos,long oldlen,long newpos,long newlen)888 static void refiddle_selection(window_textbuffer_t *cutwin,
889 long oldpos, long oldlen, long newpos, long newlen)
890 {
891 if (oldlen==0 || newlen==0 || oldpos<0 || newpos<0) {
892 flip_selection(cutwin, oldpos, oldlen);
893 flip_selection(cutwin, newpos, newlen);
894 return;
895 }
896
897 if (oldpos == newpos) {
898 /* start at same place */
899 if (oldlen < newlen) {
900 flip_selection(cutwin, oldpos+oldlen, newlen-oldlen);
901 }
902 else if (newlen < oldlen) {
903 flip_selection(cutwin, oldpos+newlen, oldlen-newlen);
904 }
905 return;
906 }
907 if (oldpos+oldlen == newpos+newlen) {
908 /* end at same place */
909 if (oldpos < newpos) {
910 flip_selection(cutwin, oldpos, newpos-oldpos);
911 }
912 else if (newpos < oldpos) {
913 flip_selection(cutwin, newpos, oldpos-newpos);
914 }
915 return;
916 }
917
918 flip_selection(cutwin, oldpos, oldlen);
919 flip_selection(cutwin, newpos, newlen);
920 }
921
flip_selection(window_textbuffer_t * cutwin,long dpos,long dlen)922 static void flip_selection(window_textbuffer_t *cutwin, long dpos, long dlen)
923 {
924 int xpos, ypos;
925 int xpos2, ypos2;
926 int off, height;
927 long ybody, ybody2;
928 long lx, lx2;
929
930 if (!cutwin->isactive) {
931 return; /* not the front window */
932 }
933
934 if (dpos < 0) {
935 return; /* dot hidden */
936 }
937
938 if (dlen==0) {
939 lx = find_loc_by_pos(cutwin, dpos, &xpos, &ypos);
940 if (lx-cutwin->scrollline < 0
941 || lx-cutwin->scrollline >= cutwin->linesonpage)
942 return;
943 height = cutwin->linelist[lx].height;
944 xglk_draw_dot(cutwin->textwin_x + xpos,
945 cutwin->textwin_y + ypos + height, height);
946 }
947 else {
948 lx = find_loc_by_pos(cutwin, dpos, &xpos, &ypos);
949 lx2 = find_loc_by_pos(cutwin, dpos+dlen, &xpos2, &ypos2);
950 if (ypos==ypos2) {
951 /* within one line */
952 if (lx-cutwin->scrollline < 0
953 || lx-cutwin->scrollline >= cutwin->linesonpage)
954 return;
955 height = cutwin->linelist[lx].height;
956 if (xpos < xpos2) {
957 XFillRectangle(xiodpy, xiowin, gcflip,
958 xpos+cutwin->textwin_x, ypos+cutwin->textwin_y,
959 xpos2-xpos, height);
960 }
961 }
962 else {
963 if (lx-cutwin->scrollline >= cutwin->linesonpage)
964 return;
965 if (lx2-cutwin->scrollline < 0)
966 return;
967 if (lx-cutwin->scrollline >= 0) {
968 height = cutwin->linelist[lx].height;
969 if (xpos < cutwin->textwin_w) {
970 /* first partial line */
971 XFillRectangle(xiodpy, xiowin, gcflip,
972 xpos+cutwin->textwin_x, ypos+cutwin->textwin_y,
973 cutwin->textwin_w-xpos, height);
974 }
975 ybody = ypos + cutwin->linelist[lx].height;
976 if (ybody < 0)
977 ybody = 0;
978 }
979 else {
980 ybody = 0;
981 }
982 if (lx2-cutwin->scrollline < cutwin->linesonpage) {
983 ybody2 = ypos2;
984 height = cutwin->linelist[lx2].height;
985 }
986 else {
987 ybody2 = cutwin->textwin_h;
988 height = 0;
989 }
990 if (ybody < ybody2) {
991 /* main body */
992 XFillRectangle(xiodpy, xiowin, gcflip,
993 cutwin->textwin_x, ybody+cutwin->textwin_y,
994 cutwin->textwin_w, ybody2-ybody);
995 }
996 if (xpos2 > 0 && height) {
997 /* last partial line */
998 XFillRectangle(xiodpy, xiowin, gcflip,
999 cutwin->textwin_x, ypos2+cutwin->textwin_y,
1000 xpos2, height);
1001 }
1002 }
1003 }
1004 }
1005
1006 /* push lines from tmplinelist[0..newnum) in place of
1007 linelist[oldbeg..oldend) */
slapover(window_textbuffer_t * cutwin,long newnum,long oldbeg,long oldend)1008 static void slapover(window_textbuffer_t *cutwin, long newnum,
1009 long oldbeg, long oldend)
1010 {
1011 long wx, lx;
1012 long newnumlines;
1013
1014 newnumlines = cutwin->numlines-(oldend-oldbeg)+newnum;
1015 if (newnumlines >= cutwin->lines_size) {
1016 while (newnumlines >= cutwin->lines_size)
1017 cutwin->lines_size *= 2;
1018 cutwin->linelist = (lline_t *)realloc(cutwin->linelist,
1019 sizeof(lline_t) * cutwin->lines_size);
1020 }
1021
1022 /* clobber old */
1023 for (lx=oldbeg; lx<oldend; lx++) {
1024 word_t *thisword;
1025 /* --- finalize word structure --- */
1026 for (wx=0, thisword=cutwin->linelist[lx].wordlist;
1027 wx<cutwin->linelist[lx].numwords;
1028 wx++, thisword++) {
1029 if (thisword->stype == stype_Text) {
1030 if (thisword->u.letterpos) {
1031 free(thisword->u.letterpos);
1032 thisword->u.letterpos = NULL;
1033 }
1034 }
1035 else if (thisword->stype == stype_Image) {
1036 if (thisword->u.image) {
1037 delete_imageword(thisword->u.image);
1038 thisword->u.image = NULL;
1039 }
1040 }
1041 }
1042 free(cutwin->linelist[lx].wordlist);
1043 cutwin->linelist[lx].wordlist = NULL;
1044 }
1045
1046 if (oldend < cutwin->numlines && newnumlines != cutwin->numlines) {
1047 memmove(&cutwin->linelist[oldend+(newnumlines-cutwin->numlines)],
1048 &cutwin->linelist[oldend],
1049 sizeof(lline_t) * (cutwin->numlines-oldend));
1050 }
1051 cutwin->numlines = newnumlines;
1052
1053 if (newnum) {
1054 memcpy(&cutwin->linelist[oldbeg],
1055 &cutwin->tmplinelist[0],
1056 sizeof(lline_t) * (newnum));
1057 }
1058 }
1059
1060 /* xpos, ypos are relative to textwin origin */
find_pos_by_loc(window_textbuffer_t * cutwin,int xpos,int ypos,long * truepos)1061 static long find_pos_by_loc(window_textbuffer_t *cutwin, int xpos, int ypos,
1062 long *truepos)
1063 {
1064 int ix, jx;
1065 long linenum;
1066 long wx, atpos, newpos;
1067 lline_t *curline;
1068 word_t *curword;
1069
1070 *truepos = -1;
1071
1072 if (ypos < 0)
1073 linenum = (-1) - ((-1)-ypos / cutwin->font.lineheight);
1074 else if (ypos >= cutwin->lineoffsetlist[cutwin->linesonpage])
1075 linenum = cutwin->linesonpage
1076 + (ypos - cutwin->lineoffsetlist[cutwin->linesonpage])
1077 / cutwin->font.lineheight;
1078 else {
1079 long min = 0;
1080 long max = cutwin->linesonpage;
1081 while (min+1 < max) {
1082 linenum = (min+max) / 2;
1083 if (ypos < cutwin->lineoffsetlist[linenum])
1084 max = linenum;
1085 else if (ypos >= cutwin->lineoffsetlist[linenum+1])
1086 min = linenum+1;
1087 else {
1088 min = linenum;
1089 break;
1090 }
1091 }
1092 linenum = min;
1093 }
1094
1095 linenum += cutwin->scrollline;
1096
1097 if (linenum < 0)
1098 return 0;
1099 if (linenum >= cutwin->numlines)
1100 return cutwin->numchars;
1101
1102 curline = (&cutwin->linelist[linenum]);
1103
1104 if (curline->leftindent > 0 && xpos < curline->leftindent) {
1105 long lx;
1106 int ylinepos = cutwin->lineoffsetlist[linenum-cutwin->scrollline];
1107 for (lx = linenum; lx >= 0; lx--) {
1108 lline_t *thisline = (&cutwin->linelist[lx]);
1109 if (thisline->leftbelow == 0 && lx < linenum)
1110 break;
1111 for (wx=0; wx<thisline->numwords; wx++) {
1112 curword = thisline->wordlist+wx;
1113 if (curword->stype == stype_Image) {
1114 imageword_t *iwd = curword->u.image;
1115 if (iwd) {
1116 if (iwd->imagealign == imagealign_MarginLeft
1117 && xpos >= iwd->pos && xpos < iwd->pos+iwd->width
1118 && ypos >= ylinepos && ypos < ylinepos+iwd->height) {
1119 *truepos = thisline->pos + curword->pos;
1120 break;
1121 }
1122 }
1123 }
1124 else if (curword->stype == stype_Text) {
1125 break;
1126 }
1127 }
1128 ylinepos -= thisline->height;
1129 }
1130 }
1131
1132 if (curline->rightindent > 0 && xpos >= cutwin->textwin_w - curline->rightindent) {
1133 long lx;
1134 int ylinepos = cutwin->lineoffsetlist[linenum-cutwin->scrollline];
1135 for (lx = linenum; lx >= 0; lx--) {
1136 lline_t *thisline = (&cutwin->linelist[lx]);
1137 if (thisline->rightbelow == 0 && lx < linenum)
1138 break;
1139 for (wx=0; wx<thisline->numwords; wx++) {
1140 curword = thisline->wordlist+wx;
1141 if (curword->stype == stype_Image) {
1142 imageword_t *iwd = curword->u.image;
1143 if (iwd) {
1144 if (iwd->imagealign == imagealign_MarginRight
1145 && xpos >= (cutwin->textwin_w-iwd->pos)-iwd->width
1146 && xpos < cutwin->textwin_w-iwd->pos
1147 && ypos >= ylinepos && ypos < ylinepos+iwd->height) {
1148 *truepos = thisline->pos + curword->pos;
1149 break;
1150 }
1151 }
1152 }
1153 else if (curword->stype == stype_Text) {
1154 break;
1155 }
1156 }
1157 ylinepos -= thisline->height;
1158 }
1159 }
1160
1161 xpos -= curline->indent; /* now xpos is relative to line beginning */
1162 if (xpos < 0) {
1163 return curline->pos; /* beginning of line */
1164 }
1165 atpos = 0;
1166 for (wx=0; wx<curline->numwords; wx++) {
1167 newpos = atpos + curline->wordlist[wx].width;
1168 if (xpos < newpos)
1169 break;
1170 atpos = newpos;
1171 }
1172 if (wx==curline->numwords) {
1173 return curline->posend; /* end of line */
1174 }
1175
1176 xpos -= atpos; /* now xpos is relative to word beginning */
1177 curword = (&curline->wordlist[wx]);
1178
1179 if (curword->stype == stype_Text) {
1180 if (!curword->u.letterpos)
1181 measure_word(cutwin, curline, curword);
1182
1183 for (ix=0; ix<curword->len; ix++) {
1184 if (xpos <= (curword->u.letterpos[ix]+curword->u.letterpos[ix+1])/2) {
1185 jx = ix;
1186 /* if (curword->pos+ix && xpos <= curword->u.letterpos[ix])
1187 jx--;*/ /* doesn't work right */
1188 break;
1189 }
1190 }
1191 *truepos = curline->pos + curword->pos + ix; /* jx */
1192 return curline->pos + curword->pos + ix;
1193 }
1194 else if (curword->stype == stype_Image) {
1195 imageword_t *iwd = curword->u.image;
1196 if (iwd) {
1197 if (iwd->imagealign != imagealign_MarginLeft
1198 && iwd->imagealign != imagealign_MarginRight) {
1199 /* Just hit the beginning or end of the word. */
1200 *truepos = curline->pos + curword->pos;
1201 ix = 0;
1202 if (xpos > iwd->width/2)
1203 ix++;
1204 return curline->pos + curword->pos + ix;
1205 }
1206 }
1207 }
1208
1209 /* Just the beginning. */
1210 *truepos = curline->pos + curword->pos;
1211 return curline->pos + curword->pos;
1212 }
1213
1214 /* returns the last line such that pos >= line.pos. guessline is a guess
1215 to start searching at; -1 means end of file. Can return -1 if pos is
1216 before the start of the layout. */
find_line_by_pos(window_textbuffer_t * cutwin,long pos,long guessline)1217 static long find_line_by_pos(window_textbuffer_t *cutwin, long pos,
1218 long guessline)
1219 {
1220 long lx;
1221
1222 if (guessline < 0 || guessline >= cutwin->numlines)
1223 guessline = cutwin->numlines-1;
1224
1225 if (guessline < cutwin->numlines-1
1226 && cutwin->linelist[guessline].pos <= pos) {
1227 for (lx=guessline; lx<cutwin->numlines; lx++) {
1228 if (cutwin->linelist[lx].pos > pos)
1229 break;
1230 }
1231 lx--;
1232 }
1233 else {
1234 for (lx=guessline; lx>=0; lx--) {
1235 if (cutwin->linelist[lx].pos <= pos)
1236 break;
1237 }
1238 }
1239
1240 return lx;
1241 }
1242
1243 /* returns values relative to textwin origin, at top of line. */
find_loc_by_pos(window_textbuffer_t * cutwin,long pos,int * xposret,int * yposret)1244 static long find_loc_by_pos(window_textbuffer_t *cutwin, long pos,
1245 int *xposret, int *yposret)
1246 {
1247 long lx, lx2;
1248 long wx, atpos;
1249 lline_t *curline;
1250 word_t *curword;
1251
1252 lx = find_line_by_pos(cutwin, pos, -1);
1253 lx2 = lx - cutwin->scrollline;
1254 if (lx < 0 || lx2 < 0) {
1255 /* somehow before first line laid out */
1256 *xposret = 0;
1257 *yposret = (-cutwin->scrollline) * cutwin->font.lineheight;
1258 return lx;
1259 }
1260 if (lx2 >= cutwin->linesonpage) {
1261 /* or after */
1262 *xposret = 0;
1263 *yposret = cutwin->lineoffsetlist[cutwin->linesonpage]
1264 + (lx2 - cutwin->linesonpage) * cutwin->font.lineheight;
1265 return lx;
1266 }
1267 curline = (&cutwin->linelist[lx]);
1268 *yposret = cutwin->lineoffsetlist[lx2];
1269
1270 atpos = curline->indent;
1271 for (wx=0; wx<curline->numwords; wx++) {
1272 if (curline->pos+curline->wordlist[wx].pos+curline->wordlist[wx].len >= pos)
1273 break;
1274 atpos += curline->wordlist[wx].width;
1275 }
1276 if (wx==curline->numwords) {
1277 *xposret = atpos;
1278 return lx;
1279 }
1280
1281 curword = (&curline->wordlist[wx]);
1282 if (curword->stype == stype_Text) {
1283 if (!curword->u.letterpos)
1284 measure_word(cutwin, curline, curword);
1285 atpos += curword->u.letterpos[pos - (curline->pos+curword->pos)];
1286 }
1287 else if (curword->stype == stype_Image) {
1288 if (curword->u.image && pos > (curline->pos+curword->pos))
1289 atpos += curword->u.image->width;
1290 }
1291 else if (curword->stype == stype_Break) {
1292 /* leave it */
1293 }
1294
1295 *xposret = atpos;
1296 return lx;
1297 }
1298
readd_lineheights(window_textbuffer_t * cutwin,long lx)1299 static void readd_lineheights(window_textbuffer_t *cutwin, long lx)
1300 {
1301 long jx, lx2;
1302
1303 lx2 = lx-cutwin->scrollline;
1304 if (lx2 > cutwin->linesonpage)
1305 return;
1306
1307 for (; lx < cutwin->numlines; lx++, lx2++) {
1308 jx = cutwin->lineoffsetlist[lx2] + cutwin->linelist[lx].height;
1309 if (jx > cutwin->textwin_h)
1310 break;
1311 if (lx2+1 >= cutwin->lineoffset_size) {
1312 cutwin->lineoffset_size = cutwin->lineoffset_size * 2 + lx2 + 1;
1313 cutwin->lineoffsetlist = (int *)realloc(cutwin->lineoffsetlist,
1314 cutwin->lineoffset_size * sizeof(int));
1315 }
1316 cutwin->lineoffsetlist[lx2+1] = jx;
1317 }
1318 cutwin->linesonpage = lx2;
1319 }
1320
1321 /* Text words only, please. */
measure_word(window_textbuffer_t * cutwin,lline_t * curline,word_t * curword)1322 static void measure_word(window_textbuffer_t *cutwin, lline_t *curline,
1323 word_t *curword)
1324 {
1325 int cx;
1326 char *buf;
1327 int direction;
1328 int letterwid;
1329 long *arr;
1330
1331 if (curword->u.letterpos) {
1332 free(curword->u.letterpos);
1333 curword->u.letterpos = NULL;
1334 }
1335
1336 arr = (long *)malloc(sizeof(long) * (curword->len+1));
1337
1338 buf = cutwin->charbuf+curline->pos+curword->pos;
1339 arr[0] = 0;
1340 for (cx=0; cx<curword->len-1; cx++) {
1341 letterwid = XTextWidth(cutwin->font.gc[curword->attr].fontstr, buf+cx, 1);
1342 /* attend to curword->linkid? */
1343 arr[cx+1] = arr[cx] + letterwid;
1344 }
1345 arr[cx+1] = curword->width;
1346
1347 curword->u.letterpos = arr;
1348 }
1349
win_textbuffer_clear_window(window_textbuffer_t * cutwin)1350 void win_textbuffer_clear_window(window_textbuffer_t *cutwin)
1351 {
1352 int ix;
1353
1354 if (1) {
1355 /* normal clear */
1356 win_textbuffer_delete_start(cutwin, cutwin->numlines);
1357 }
1358 else {
1359 /* bonzo scrolling clear. This doesn't actually work, since lines can
1360 be of different heights. */
1361 if (!cutwin->isclear) {
1362 for (ix=0; ix<cutwin->linesonpage; ix++)
1363 win_textbuffer_add(cutwin, '\n', -1);
1364 }
1365 }
1366
1367 cutwin->isclear = TRUE;
1368 }
1369
1370 /* pos < 0 means add at end.
1371 all this is grotesquely inefficient if adding anywhere but the end. */
win_textbuffer_add(window_textbuffer_t * cutwin,char ch,long pos)1372 void win_textbuffer_add(window_textbuffer_t *cutwin, char ch, long pos)
1373 {
1374 if (ch != '\n')
1375 cutwin->isclear = FALSE;
1376 if (pos<0)
1377 pos = cutwin->numchars;
1378 win_textbuffer_replace(cutwin, pos, 0, &ch, 1);
1379 }
1380
1381 /* update data, adjusting dot and styles as necessary. */
win_textbuffer_replace(window_textbuffer_t * cutwin,long pos,long oldlen,char * buf,long newlen)1382 void win_textbuffer_replace(window_textbuffer_t *cutwin, long pos, long oldlen,
1383 char *buf, long newlen)
1384 {
1385 long newnumchars;
1386
1387 newnumchars = cutwin->numchars-oldlen+newlen;
1388 if (newnumchars >= cutwin->char_size) {
1389 while (newnumchars >= cutwin->char_size)
1390 cutwin->char_size *= 2;
1391 cutwin->charbuf = (char *)realloc(cutwin->charbuf, sizeof(char) * cutwin->char_size);
1392 }
1393
1394 if (pos < cutwin->dirtybeg || cutwin->dirtybeg < 0)
1395 cutwin->dirtybeg = pos;
1396
1397 if (newlen != oldlen) {
1398 if (pos+oldlen != cutwin->numchars) {
1399 memmove(cutwin->charbuf+pos+newlen, cutwin->charbuf+pos+oldlen, sizeof(char) * (cutwin->numchars-(pos+oldlen)));
1400 }
1401 if (cutwin->numchars >= cutwin->dirtyend)
1402 cutwin->dirtyend = cutwin->numchars+1;
1403 cutwin->dirtydelta += (newlen-oldlen);
1404 }
1405 else {
1406 if (pos+newlen >= cutwin->dirtyend)
1407 cutwin->dirtyend = pos+newlen+1;
1408 cutwin->dirtydelta += (newlen-oldlen);
1409 }
1410
1411 /* copy in the new stuff */
1412 if (newlen)
1413 memmove(cutwin->charbuf+pos, buf, sizeof(char) * newlen);
1414
1415 /* diddle the dot */
1416 if (cutwin->dotpos >= pos+oldlen) {
1417 /* starts after changed region */
1418 cutwin->dotpos += (newlen-oldlen);
1419 }
1420 else if (cutwin->dotpos >= pos) {
1421 /* starts inside changed region */
1422 if (cutwin->dotpos+cutwin->dotlen >= pos+oldlen) {
1423 /* ...but ends after it */
1424 cutwin->dotlen = (cutwin->dotpos+cutwin->dotlen)-(pos+oldlen);
1425 cutwin->dotpos = pos+newlen;
1426 }
1427 else {
1428 /* ...and ends inside it */
1429 cutwin->dotpos = pos+newlen;
1430 cutwin->dotlen = 0;
1431 }
1432 }
1433 else {
1434 /* starts before changed region */
1435 if (cutwin->dotpos+cutwin->dotlen >= pos+oldlen) {
1436 /* ...but ends after it */
1437 cutwin->dotlen += (newlen-oldlen);
1438 }
1439 else if (cutwin->dotpos+cutwin->dotlen >= pos) {
1440 /* ...but ends inside it */
1441 cutwin->dotlen = (pos+newlen) - cutwin->dotpos;
1442 }
1443 }
1444
1445 cutwin->numchars = newnumchars;
1446 }
1447
win_textbuffer_set_style_text(window_textbuffer_t * cutwin,glui32 attr)1448 void win_textbuffer_set_style_text(window_textbuffer_t *cutwin, glui32 attr)
1449 {
1450 style_t *sty = &(cutwin->stylelist[cutwin->numstyles-1]);
1451 if (attr == 0xFFFFFFFF)
1452 attr = sty->attr;
1453 win_textbuffer_setstyle(cutwin, -1, stype_Text, attr, sty->linkid,
1454 0, 0, 0, 0);
1455 }
1456
win_textbuffer_set_style_image(window_textbuffer_t * cutwin,glui32 image,int imagealign,glui32 imagewidth,glui32 imageheight)1457 void win_textbuffer_set_style_image(window_textbuffer_t *cutwin,
1458 glui32 image, int imagealign,
1459 glui32 imagewidth, glui32 imageheight)
1460 {
1461 style_t *sty = &(cutwin->stylelist[cutwin->numstyles-1]);
1462 win_textbuffer_setstyle(cutwin, -1, stype_Image, sty->attr, sty->linkid,
1463 image, imagealign, imagewidth, imageheight);
1464 }
1465
win_textbuffer_set_style_break(window_textbuffer_t * cutwin)1466 void win_textbuffer_set_style_break(window_textbuffer_t *cutwin)
1467 {
1468 style_t *sty = &(cutwin->stylelist[cutwin->numstyles-1]);
1469 win_textbuffer_setstyle(cutwin, -1, stype_Break, sty->attr, sty->linkid,
1470 0, 0, 0, 0);
1471 }
1472
win_textbuffer_set_style_link(window_textbuffer_t * cutwin,glui32 linkid)1473 void win_textbuffer_set_style_link(window_textbuffer_t *cutwin,
1474 glui32 linkid)
1475 {
1476 style_t *sty = &(cutwin->stylelist[cutwin->numstyles-1]);
1477 win_textbuffer_setstyle(cutwin, -1, sty->stype, sty->attr, linkid,
1478 sty->image, sty->imagealign, sty->imagewidth, sty->imageheight);
1479 }
1480
win_textbuffer_setstyle(window_textbuffer_t * cutwin,long pos,int stype,glui32 attr,glui32 linkid,glui32 image,int imagealign,glui32 imagewidth,glui32 imageheight)1481 static void win_textbuffer_setstyle(window_textbuffer_t *cutwin,
1482 long pos, int stype,
1483 glui32 attr, glui32 linkid, glui32 image, int imagealign,
1484 glui32 imagewidth, glui32 imageheight)
1485 {
1486 long sx;
1487
1488 if (pos < 0)
1489 pos = cutwin->numchars;
1490
1491 /* find the last style at or before pos. */
1492 for (sx=cutwin->numstyles-1; sx>=0; sx--) {
1493 if (cutwin->stylelist[sx].pos <= pos) {
1494 break;
1495 }
1496 }
1497 if (sx < 0) {
1498 /*printf("oops, went back behind style 0\n");*/
1499 return;
1500 }
1501
1502 if (cutwin->stylelist[sx].pos == pos) {
1503 /* if sx is *at* pos, just change it. */
1504 }
1505 else {
1506 /* if before, insert a new style after it. */
1507 sx++;
1508 if (cutwin->numstyles+1 >= cutwin->styles_size) {
1509 cutwin->styles_size *= 2;
1510 cutwin->stylelist = (style_t *)realloc(cutwin->stylelist,
1511 sizeof(style_t) * cutwin->styles_size);
1512 }
1513 cutwin->numstyles++;
1514 if (sx+1 < cutwin->numstyles) {
1515 memmove(&cutwin->stylelist[sx+1], &cutwin->stylelist[sx],
1516 sizeof(style_t) * (cutwin->numstyles-sx));
1517 }
1518 cutwin->stylelist[sx].pos = pos;
1519 }
1520
1521 cutwin->stylelist[sx].stype = stype;
1522 cutwin->stylelist[sx].linkid = linkid;
1523 cutwin->stylelist[sx].attr = attr;
1524 cutwin->stylelist[sx].image = image;
1525 cutwin->stylelist[sx].imagealign = imagealign;
1526 cutwin->stylelist[sx].imagewidth = imagewidth;
1527 cutwin->stylelist[sx].imageheight = imageheight;
1528
1529 if (pos != cutwin->numchars) {
1530 /* really, should only go to next style_t */
1531 cutwin->dirtybeg = pos;
1532 cutwin->dirtyend = cutwin->numchars;
1533 cutwin->dirtydelta = 0;
1534 win_textbuffer_layout(cutwin);
1535 }
1536 }
1537
win_textbuffer_end_visible(window_textbuffer_t * cutwin)1538 void win_textbuffer_end_visible(window_textbuffer_t *cutwin)
1539 {
1540 if (cutwin->scrollline < cutwin->numlines-cutwin->linesonpage) {
1541 /* this is wrong -- linesonpage doesn't correctly measure lines
1542 at the end. */
1543 scroll_to(cutwin, cutwin->numlines-cutwin->linesonpage);
1544 }
1545 }
1546
win_textbuffer_set_paging(window_textbuffer_t * cutwin,int forcetoend)1547 void win_textbuffer_set_paging(window_textbuffer_t *cutwin, int forcetoend)
1548 {
1549 long val;
1550 long total;
1551
1552 if (cutwin->lastseenline == cutwin->numlines)
1553 return;
1554
1555 if (!forcetoend
1556 && cutwin->lastseenline - 0 < cutwin->numlines - cutwin->linesonpage) {
1557 /* this is wrong -- linesonpage doesn't correctly measure lines
1558 at the end. */
1559 /* scroll lastseenline to top, stick there */
1560 val = cutwin->lastseenline;
1561 if (val > cutwin->scrollline)
1562 val--;
1563 }
1564 else {
1565 /* scroll to bottom, set lastseenline to end. */
1566 total = 0;
1567 for (val = cutwin->numlines; val > 0; val--) {
1568 total += cutwin->linelist[val-1].height;
1569 if (total > cutwin->textwin_h)
1570 break;
1571 }
1572
1573 cutwin->lastseenline = cutwin->numlines;
1574 }
1575
1576 scroll_to(cutwin, val);
1577 }
1578
win_textbuffer_is_paging(window_t * win)1579 int win_textbuffer_is_paging(window_t *win)
1580 {
1581 window_textbuffer_t *dwin = win->data;
1582
1583 if (dwin->lastseenline < dwin->numlines - dwin->linesonpage) {
1584 /* this is wrong -- linesonpage doesn't correctly measure lines
1585 at the end. */
1586 return TRUE;
1587 }
1588 return FALSE;
1589 }
1590
1591 /* delete num lines from the top */
win_textbuffer_delete_start(window_textbuffer_t * cutwin,long num)1592 void win_textbuffer_delete_start(window_textbuffer_t *cutwin, long num)
1593 {
1594 long delchars;
1595 long lx, sx, sx2;
1596 glui32 origattr;
1597
1598 if (num > cutwin->numlines)
1599 num = cutwin->numlines;
1600 if (num < 0)
1601 num = 0;
1602
1603 if (cutwin->numlines==0)
1604 return;
1605
1606 if (num < cutwin->numlines)
1607 delchars = cutwin->linelist[num].pos;
1608 else
1609 delchars = cutwin->numchars;
1610
1611 if (!delchars)
1612 return;
1613
1614 /* lines */
1615 slapover(cutwin, 0, 0, num);
1616 for (lx=0; lx<cutwin->numlines; lx++) {
1617 cutwin->linelist[lx].pos -= delchars;
1618 cutwin->linelist[lx].posend -= delchars;
1619 }
1620
1621 /* styles */
1622 for (sx=0; sx<cutwin->numstyles; sx++) {
1623 if (cutwin->stylelist[sx].pos > delchars)
1624 break;
1625 }
1626 if (sx>0) {
1627 origattr = cutwin->stylelist[sx-1].attr;
1628 cutwin->stylelist[0].pos = 0;
1629 cutwin->stylelist[0].attr = origattr;
1630 for (sx2=1; sx<cutwin->numstyles; sx++, sx2++) {
1631 cutwin->stylelist[sx2].pos = cutwin->stylelist[sx].pos - delchars;
1632 cutwin->stylelist[sx2].attr = cutwin->stylelist[sx].attr;
1633 }
1634 cutwin->numstyles = sx2;
1635 }
1636
1637 /* chars */
1638 if (cutwin->numchars > delchars)
1639 memmove(&cutwin->charbuf[0], &cutwin->charbuf[delchars], sizeof(char) * (cutwin->numchars-delchars));
1640 cutwin->numchars -= delchars;
1641
1642 /* adjust, I mean, everything */
1643 if (cutwin->dirtybeg != (-1)) {
1644 cutwin->dirtybeg -= delchars;
1645 cutwin->dirtyend -= delchars;
1646 if (cutwin->dirtyend < 0) {
1647 cutwin->dirtybeg = (-1);
1648 cutwin->dirtyend = (-1);
1649 }
1650 else if (cutwin->dirtybeg < 0) {
1651 cutwin->dirtybeg = 0;
1652 }
1653 }
1654
1655 cutwin->dotpos -= delchars;
1656 if (cutwin->dotpos < 0) {
1657 if (cutwin->dotpos+cutwin->dotlen < 0) {
1658 cutwin->dotpos = 0;
1659 cutwin->dotlen = 0;
1660 }
1661 else {
1662 cutwin->dotlen += cutwin->dotpos;
1663 cutwin->dotpos = 0;
1664 }
1665 }
1666 cutwin->lastdotpos -= delchars;
1667 if (cutwin->lastdotpos < 0) {
1668 if (cutwin->lastdotpos+cutwin->lastdotlen < 0) {
1669 cutwin->lastdotpos = 0;
1670 cutwin->lastdotlen = 0;
1671 }
1672 else {
1673 cutwin->lastdotlen += cutwin->lastdotpos;
1674 cutwin->lastdotpos = 0;
1675 }
1676 }
1677 cutwin->inputfence -= delchars;
1678 if (cutwin->inputfence < 0)
1679 cutwin->inputfence = 0;
1680
1681 cutwin->lastseenline -= num;
1682 if (cutwin->lastseenline < 0)
1683 cutwin->lastseenline = 0;
1684
1685 cutwin->scrollline -= num;
1686 cutwin->scrollpos -= delchars;
1687 if (cutwin->scrollline < 0 || cutwin->scrollpos < 0) {
1688 cutwin->scrollline = 0;
1689 cutwin->scrollpos = 0;
1690 readd_lineheights(cutwin, cutwin->scrollline);
1691 redrawtext(cutwin, 0, -1, -1);
1692 flip_selection(cutwin, cutwin->dotpos, cutwin->dotlen);
1693 xweg_adjust_scrollbar(&cutwin->scrollbar, cutwin->numlines,
1694 cutwin->scrollline, cutwin->linesonpage);
1695 }
1696 else {
1697 xweg_adjust_scrollbar(&cutwin->scrollbar, cutwin->numlines,
1698 cutwin->scrollline, cutwin->linesonpage);
1699 }
1700 }
1701
win_textbuffer_layout(window_textbuffer_t * cutwin)1702 static void win_textbuffer_layout(window_textbuffer_t *cutwin)
1703 {
1704 long ix, jx, ejx, lx;
1705 long styx, nextstylepos;
1706 style_t *curattr;
1707 long overline, overlineend;
1708 long tmpl, startpos;
1709 int prevflags;
1710 int needwholeredraw;
1711 int textwin_w = cutwin->textwin_w; /* cache */
1712 int textwin_h = cutwin->textwin_h; /* cache */
1713 long leftindent, leftbelow, rightindent, rightbelow;
1714
1715 int direction;
1716 int wordwidth;
1717
1718 static long lastline = 0; /* last line dirtied */
1719
1720 /* Shut up compiler warnings */
1721 ejx = 0;
1722 jx = 0;
1723
1724 if (cutwin->dirtybeg < 0 || cutwin->dirtyend < 0) {
1725 if (cutwin->lastdotpos != cutwin->dotpos
1726 || cutwin->lastdotlen != cutwin->dotlen) {
1727 refiddle_selection(cutwin, cutwin->lastdotpos,
1728 cutwin->lastdotlen, cutwin->dotpos, cutwin->dotlen);
1729 /*flip_selection(cutwin, cutwin->lastdotpos, cutwin->lastdotlen);*/
1730 cutwin->lastdotpos = cutwin->dotpos;
1731 cutwin->lastdotlen = cutwin->dotlen;
1732 /*flip_selection(cutwin, cutwin->lastdotpos, cutwin->lastdotlen);*/
1733 }
1734 return;
1735 }
1736
1737 /* we start by turning off the selection. */
1738 flip_selection(cutwin, cutwin->lastdotpos, cutwin->lastdotlen);
1739 cutwin->lastdotpos = cutwin->dotpos;
1740 cutwin->lastdotlen = cutwin->dotlen;
1741
1742 if (cutwin->numlines==0) {
1743 overline = 0;
1744 startpos = 0;
1745 }
1746 else {
1747 lx = find_line_by_pos(cutwin, cutwin->dirtybeg, lastline);
1748 /* now lx is the line containing dirtybeg */
1749
1750 if (lx>0 && lx<cutwin->numlines && (cutwin->linelist[lx].flags & lineflag_Wrapped)) {
1751 /* do layout from previous line, in case a word from the changed area pops back there. */
1752 lx--;
1753 }
1754 overline = lx;
1755 startpos = cutwin->linelist[overline].pos;
1756 }
1757
1758 /* get any margin info left from previous lines */
1759 if (overline > 0 && cutwin->linelist[overline-1].leftbelow) {
1760 leftbelow = cutwin->linelist[overline-1].leftbelow;
1761 leftindent = cutwin->linelist[overline-1].leftindent;
1762 }
1763 else {
1764 leftbelow = 0;
1765 leftindent = 0;
1766 }
1767 if (overline > 0 && cutwin->linelist[overline-1].rightbelow) {
1768 rightbelow = cutwin->linelist[overline-1].rightbelow;
1769 rightindent = cutwin->linelist[overline-1].rightindent;
1770 }
1771 else {
1772 rightbelow = 0;
1773 rightindent = 0;
1774 }
1775
1776 /* get the first relevant style_t */
1777 for (styx=cutwin->numstyles-1; styx>0; styx--)
1778 if (cutwin->stylelist[styx].pos <= startpos)
1779 break;
1780 if (styx==cutwin->numstyles-1)
1781 nextstylepos = cutwin->numchars+10;
1782 else
1783 nextstylepos = cutwin->stylelist[styx+1].pos;
1784 curattr = &(cutwin->stylelist[styx]);
1785
1786 /* start a-layin' */
1787 tmpl = 0;
1788 prevflags = 0;
1789
1790 while (startpos<cutwin->numchars
1791 && !(startpos >= cutwin->dirtyend && cutwin->charbuf[startpos]=='\n')) {
1792 lline_t *thisline;
1793 long tmpw, tmpwords_size;
1794 long widthsofar, spaceswidth=0;
1795 int lineattrknown, anyimages;
1796 glui32 lineattr;
1797 long ascent, descent, superscent;
1798
1799 if (tmpl+1 >= cutwin->tmplines_size) {
1800 /* the +1 allows the extra blank line at the end */
1801 cutwin->tmplines_size *= 2;
1802 cutwin->tmplinelist = (lline_t *)realloc(cutwin->tmplinelist,
1803 sizeof(lline_t) * cutwin->tmplines_size);
1804 }
1805 thisline = (&cutwin->tmplinelist[tmpl]);
1806 thisline->flags = prevflags;
1807 thisline->height = 64; /* initially silly values */
1808 thisline->off = 48;
1809 thisline->indent = cutwin->font.baseindent + leftindent;
1810 /* indent will be added to when lineattr is known. */
1811 lineattrknown = FALSE;
1812 lineattr = style_Normal;
1813 tmpwords_size = 8;
1814 thisline->wordlist = (word_t *)malloc(tmpwords_size * sizeof(word_t));
1815 tmpw = 0;
1816
1817 /*printf("laying tmpline %d, from charpos %d\n", tmpl, startpos);*/
1818 tmpl++;
1819
1820 ix = startpos;
1821 widthsofar = thisline->indent; /* will be set when lineattr is known. */
1822 prevflags = 0;
1823
1824 while (ix<cutwin->numchars && cutwin->charbuf[ix]!='\n') {
1825 word_t *thisword;
1826 int sidebar;
1827
1828 while (ix >= nextstylepos) {
1829 /* ahead one style_t */
1830 styx++;
1831 if (styx==cutwin->numstyles-1)
1832 nextstylepos = cutwin->numchars+10;
1833 else
1834 nextstylepos = cutwin->stylelist[styx+1].pos;
1835 curattr = &(cutwin->stylelist[styx]);
1836 }
1837
1838 if (!lineattrknown) {
1839 lineattr = curattr->attr;
1840 thisline->indent += cutwin->font.gc[lineattr].indent;
1841 if (!(thisline->flags & lineflag_Wrapped)) {
1842 thisline->indent += cutwin->font.gc[lineattr].parindent;
1843 }
1844 widthsofar = thisline->indent;
1845 lineattrknown = TRUE;
1846 }
1847
1848 if (tmpw >= tmpwords_size) {
1849 tmpwords_size *= 2;
1850 thisline->wordlist = (word_t *)realloc(thisline->wordlist,
1851 tmpwords_size * sizeof(word_t));
1852 }
1853 thisword = (&thisline->wordlist[tmpw]);
1854 /* --- initialize word structure --- */
1855
1856 sidebar = FALSE;
1857 wordwidth = 0;
1858
1859 if (curattr->stype == stype_Text) {
1860 thisword->stype = stype_Text;
1861 thisword->u.letterpos = NULL;
1862 for (jx=ix;
1863 jx<cutwin->numchars && jx<nextstylepos
1864 && cutwin->charbuf[jx]!=' '
1865 && cutwin->charbuf[jx]!='\n';
1866 jx++);
1867 wordwidth = XTextWidth(cutwin->font.gc[curattr->attr].fontstr,
1868 cutwin->charbuf+ix, jx-ix);
1869 /* attend to curattr->linkid? */
1870 }
1871 else if (curattr->stype == stype_Break) {
1872 thisword->stype = stype_Break;
1873 thisword->u.letterpos = NULL;
1874 jx = ix+1;
1875 if (leftindent || rightindent)
1876 wordwidth = textwin_w + 10;
1877 else
1878 wordwidth = 0;
1879 }
1880 else if (curattr->stype == stype_Image) {
1881 thisword->stype = stype_Image;
1882 jx = ix+1;
1883 thisword->u.image = (imageword_t *)malloc(sizeof(imageword_t));
1884 thisword->u.image->pic = picture_find(curattr->image);
1885 if (!thisword->u.image->pic) {
1886 delete_imageword(thisword->u.image);
1887 thisword->u.image = NULL;
1888 wordwidth = 0;
1889 }
1890 else {
1891 thisword->u.image->width = curattr->imagewidth;
1892 thisword->u.image->height = curattr->imageheight;
1893 thisword->u.image->imagealign = curattr->imagealign;
1894 thisword->u.image->pos = 0;
1895 wordwidth = thisword->u.image->width;
1896
1897 if (curattr->imagealign == imagealign_MarginLeft
1898 || curattr->imagealign == imagealign_MarginRight) {
1899 int px, pcount;
1900 wordwidth = 0;
1901 sidebar = TRUE;
1902 pcount = 0;
1903 for (px=0; !pcount && px<tmpw; px++) {
1904 if (thisline->wordlist[px].stype == stype_Text)
1905 pcount++;
1906 }
1907 if (pcount) {
1908 delete_imageword(thisword->u.image);
1909 thisword->u.image = NULL;
1910 }
1911 else {
1912 if (curattr->imagealign == imagealign_MarginLeft) {
1913 long oldleftindent = leftindent;
1914 leftindent += thisword->u.image->width;
1915 if (!oldleftindent) {
1916 leftindent += prefs.textbuffer.marginx;
1917 thisword->u.image->pos = 0;
1918 }
1919 else {
1920 thisword->u.image->pos = oldleftindent
1921 - prefs.textbuffer.marginx;
1922 }
1923 if (leftbelow < thisword->u.image->height)
1924 leftbelow = thisword->u.image->height;
1925 thisline->indent += (leftindent - oldleftindent);
1926 widthsofar += (leftindent - oldleftindent);
1927 }
1928 else {
1929 long oldrightindent = rightindent;
1930 rightindent += thisword->u.image->width;
1931 if (!oldrightindent) {
1932 rightindent += prefs.textbuffer.marginx;
1933 thisword->u.image->pos = 0;
1934 }
1935 else {
1936 thisword->u.image->pos = oldrightindent
1937 - prefs.textbuffer.marginx;
1938 }
1939 if (rightbelow < thisword->u.image->height)
1940 rightbelow = thisword->u.image->height;
1941 }
1942 }
1943 }
1944 }
1945 }
1946
1947 if (widthsofar + wordwidth > textwin_w - rightindent && !sidebar) {
1948 prevflags = lineflag_Wrapped;
1949 /* the word overflows, so throw it away -- unless it's the first
1950 word on a line. (That would lead to an infinite loop.)
1951 Of course break-words are always thrown away. */
1952 if (tmpw == 0 && !(curattr->stype == stype_Break && wordwidth)
1953 /*###&& (leftindent == 0 && rightindent == 0)*/) {
1954 if (curattr->stype == stype_Text) {
1955 /* do something clever -- split the word, put first part in tmplist.
1956 but be sure to take at least one letter. */
1957 long letx;
1958 long wordwidthsofar = 0;
1959 for (letx=ix; letx<jx; letx++) {
1960 wordwidth = XTextWidth(cutwin->font.gc[curattr->attr].fontstr,
1961 cutwin->charbuf+letx, 1);
1962 /* attend to curattr->linkid? */
1963 if (letx > ix
1964 && widthsofar + wordwidthsofar+wordwidth
1965 > (textwin_w - rightindent)) {
1966 break;
1967 }
1968 wordwidthsofar += wordwidth;
1969 }
1970 jx = letx;
1971 wordwidth = wordwidthsofar;
1972 /* spaceswidth and ejx will be 0 */
1973 }
1974 /* don't break */
1975 }
1976 else {
1977 /* pitch this word. */
1978 if (thisword->stype == stype_Image) {
1979 if (thisword->u.image) {
1980 delete_imageword(thisword->u.image);
1981 thisword->u.image = NULL;
1982 }
1983 }
1984 /* ejx and spaceswidth are properly set from last word,
1985 trim them off. */
1986 thisword--;
1987 thisword->len -= ejx;
1988 thisword->width -= spaceswidth;
1989 break; /* line over. */
1990 }
1991 }
1992
1993 /* figure out trailing whitespace ### for images too? */
1994 if (!sidebar) {
1995 ejx = 0;
1996 while (jx+ejx<cutwin->numchars
1997 && jx+ejx<nextstylepos && cutwin->charbuf[jx+ejx]==' ') {
1998 ejx++;
1999 }
2000 spaceswidth = ejx * cutwin->font.gc[curattr->attr].spacewidth;
2001 }
2002 else {
2003 ejx = 0;
2004 spaceswidth = 0;
2005 }
2006
2007 /* put the word in tmplist */
2008 thisword->pos = ix-startpos;
2009 thisword->len = jx+ejx-ix;
2010 thisword->attr = curattr->attr;
2011 thisword->linkid = curattr->linkid;
2012 thisword->width = wordwidth+spaceswidth;
2013 widthsofar += thisword->width;
2014 tmpw++;
2015
2016 ix = jx+ejx;
2017 }
2018 thisline->pos = startpos;
2019 if (tmpw) {
2020 word_t *thisword = (&thisline->wordlist[tmpw-1]);
2021 thisline->posend = startpos + thisword->pos + thisword->len;
2022 }
2023 else {
2024 thisline->posend = startpos;
2025 }
2026
2027 if (ix<cutwin->numchars && cutwin->charbuf[ix]=='\n')
2028 ix++;
2029
2030 thisline->numwords = tmpw;
2031
2032 superscent = 0;
2033 ascent = 0;
2034 descent = 0;
2035 anyimages = FALSE;
2036 for (jx=0; jx<tmpw; jx++) {
2037 word_t *thisword = (&thisline->wordlist[jx]);
2038 if (thisword->stype == stype_Text) {
2039 fontref_t *font = &cutwin->font.gc[thisword->attr];
2040 if (font->ascent > ascent)
2041 ascent = font->ascent;
2042 if (font->descent > descent)
2043 descent = font->descent;
2044 }
2045 else {
2046 anyimages = TRUE;
2047 }
2048 }
2049 if (anyimages) {
2050 int diff;
2051 for (jx=0; jx<tmpw; jx++) {
2052 word_t *thisword = (&thisline->wordlist[jx]);
2053 if (thisword->stype == stype_Image) {
2054 imageword_t *iwd = thisword->u.image;
2055 if (!iwd)
2056 continue;
2057 switch (iwd->imagealign) {
2058 case imagealign_InlineUp:
2059 if (superscent < iwd->height - ascent)
2060 superscent = iwd->height - ascent;
2061 iwd->pos = iwd->height;
2062 break;
2063 case imagealign_InlineCenter:
2064 diff = iwd->height - ascent;
2065 diff = (diff+1) / 2;
2066 if (superscent < diff)
2067 superscent = diff;
2068 if (descent < diff)
2069 descent = diff;
2070 iwd->pos = ascent + diff;
2071 break;
2072 case imagealign_InlineDown:
2073 if (descent < iwd->height - ascent)
2074 descent = iwd->height - ascent;
2075 iwd->pos = ascent;
2076 break;
2077 case imagealign_MarginLeft:
2078 case imagealign_MarginRight:
2079 /* iwd->pos already set */
2080 break;
2081 }
2082 }
2083 }
2084 }
2085 if (superscent+ascent+descent == 0) {
2086 fontref_t *font = &cutwin->font.gc[lineattr];
2087 ascent = font->ascent;
2088 descent = font->descent;
2089 }
2090 thisline->height = superscent+ascent+descent;
2091 thisline->off = superscent+ascent;
2092
2093 switch (cutwin->font.gc[lineattr].justify) {
2094 case stylehint_just_LeftRight:
2095 if (prevflags==lineflag_Wrapped && tmpw>1) {
2096 /* full-justify (but only wrapped lines) */
2097 long extraspace, each;
2098 extraspace = (textwin_w - rightindent) - widthsofar;
2099 each = extraspace / (tmpw-1);
2100 extraspace -= (each*(tmpw-1));
2101 for (jx=0; jx<extraspace; jx++) {
2102 thisline->wordlist[jx].width += (each+1);
2103 }
2104 for (; jx<tmpw-1; jx++) {
2105 thisline->wordlist[jx].width += each;
2106 }
2107 }
2108 break;
2109 case stylehint_just_Centered:
2110 {
2111 long extraspace;
2112 extraspace = (textwin_w - rightindent) - widthsofar;
2113 thisline->indent += extraspace / 2;
2114 }
2115 break;
2116 case stylehint_just_RightFlush:
2117 {
2118 long extraspace;
2119 extraspace = (textwin_w - rightindent) - widthsofar;
2120 thisline->indent += extraspace;
2121 }
2122 break;
2123 case stylehint_just_LeftFlush:
2124 default:
2125 break;
2126 }
2127
2128 thisline->leftindent = leftindent;
2129 if (leftindent && thisline->height < leftbelow) {
2130 leftbelow -= thisline->height;
2131 thisline->leftbelow = leftbelow;
2132 }
2133 else {
2134 leftbelow = 0;
2135 leftindent = 0;
2136 thisline->leftbelow = 0;
2137 }
2138 thisline->rightindent = rightindent;
2139 if (rightindent && thisline->height < rightbelow) {
2140 rightbelow -= thisline->height;
2141 thisline->rightbelow = rightbelow;
2142 }
2143 else {
2144 rightbelow = 0;
2145 rightindent = 0;
2146 thisline->rightbelow = 0;
2147 }
2148
2149 startpos = ix;
2150 } /* done laying tmp lines */
2151
2152 if (startpos == cutwin->numchars
2153 && (cutwin->numchars==0 || cutwin->charbuf[cutwin->numchars-1]=='\n')) {
2154 /* lay one more line! */
2155 lline_t *thisline;
2156 fontref_t *font;
2157
2158 curattr = &(cutwin->stylelist[cutwin->numstyles-1]);
2159 font = &(cutwin->font.gc[curattr->attr]);
2160
2161 thisline = (&cutwin->tmplinelist[tmpl]);
2162 thisline->flags = lineflag_Extra;
2163 thisline->height = font->ascent + font->descent;
2164 thisline->off = font->ascent;
2165 thisline->indent = cutwin->font.baseindent;
2166 tmpl++;
2167
2168 thisline->leftindent = leftindent;
2169 if (leftindent && thisline->height < leftbelow) {
2170 leftbelow -= thisline->height;
2171 thisline->leftbelow = leftbelow;
2172 }
2173 else {
2174 thisline->leftbelow = 0;
2175 }
2176 thisline->rightindent = rightindent;
2177 if (rightindent && thisline->height < rightbelow) {
2178 rightbelow -= thisline->height;
2179 thisline->rightbelow = rightbelow;
2180 }
2181 else {
2182 thisline->rightbelow = 0;
2183 }
2184
2185 thisline->wordlist = (word_t *)malloc(sizeof(word_t));
2186 thisline->numwords = 0;
2187 thisline->pos = startpos;
2188 thisline->posend = startpos;
2189 }
2190
2191 /*printf("laid %d tmplines, and startpos now %d (delta %d)\n", tmpl, startpos, dirtydelta);*/
2192
2193 for (lx=overline; lx<cutwin->numlines && cutwin->linelist[lx].pos < startpos-cutwin->dirtydelta; lx++);
2194 if (lx==cutwin->numlines-1 && (cutwin->linelist[lx].flags & lineflag_Extra)) {
2195 /* account for the extra line */
2196 lx++;
2197 }
2198 overlineend = lx;
2199
2200 /*printf("overwrite area is lines [%d..%d) (of %d); replacing with %d lines\n", overline, overlineend, numlines, tmpl);*/
2201
2202 slapover(cutwin, tmpl, overline, overlineend);
2203
2204 lastline = overline+tmpl; /* re-cache value */
2205 needwholeredraw = FALSE;
2206
2207 /* diddle scroll stuff */
2208 if (cutwin->scrollpos <= cutwin->dirtybeg) {
2209 /* disturbance is at or below the screen-top -- do nothing */
2210 }
2211 else if (cutwin->scrollpos >= startpos-cutwin->dirtydelta) {
2212 /* disturbance is off top of screen -- adjust so that no difference
2213 is visible. */
2214 cutwin->scrollpos += cutwin->dirtydelta;
2215 cutwin->scrollline += (overline-overlineend) - tmpl;
2216 /* the lineoffsetlist therefore doesn't need to be changed,
2217 theoretically. */
2218 }
2219 else {
2220 /* The disturbance spans the screen-top, which is annoying. */
2221 cutwin->scrollpos += cutwin->dirtydelta; /* kind of strange, but
2222 shouldn't cause trouble */
2223 if (cutwin->scrollpos >= cutwin->numchars)
2224 cutwin->scrollpos = cutwin->numchars-1;
2225 if (cutwin->scrollpos < 0)
2226 cutwin->scrollpos = 0;
2227 cutwin->scrollline = find_line_by_pos(cutwin, cutwin->scrollpos,
2228 cutwin->scrollline);
2229 needwholeredraw = TRUE;
2230 }
2231
2232 /* rebuild lineoffsetlist */
2233 if (needwholeredraw) {
2234 lx = cutwin->scrollline;
2235 }
2236 else {
2237 lx = overline;
2238 if (lx < cutwin->scrollline)
2239 lx = cutwin->scrollline;
2240 }
2241 readd_lineheights(cutwin, lx);
2242
2243 /* clean up afterwards. */
2244 cutwin->dirtybeg = -1;
2245 cutwin->dirtyend = -1;
2246 cutwin->dirtydelta = 0;
2247
2248 if (needwholeredraw) {
2249 redrawtext(cutwin, cutwin->scrollline, -1, -1);
2250 }
2251 else if (tmpl == overlineend-overline) {
2252 redrawtext(cutwin, overline, tmpl, tmpl);
2253 }
2254 else {
2255 if (overlineend > cutwin->numlines)
2256 redrawtext(cutwin, overline, -1, overlineend-overline);
2257 else
2258 redrawtext(cutwin, overline, -1, cutwin->numlines-overline);
2259 }
2260
2261 flip_selection(cutwin, cutwin->lastdotpos, cutwin->lastdotlen);
2262
2263 xweg_adjust_scrollbar(&cutwin->scrollbar, cutwin->numlines,
2264 cutwin->scrollline, cutwin->linesonpage);
2265 }
2266
xgc_buf_scrollto(window_textbuffer_t * cutwin,int op)2267 void xgc_buf_scrollto(window_textbuffer_t *cutwin, int op)
2268 {
2269 scroll_to(cutwin, op);
2270 }
2271
xgc_buf_scroll(window_textbuffer_t * cutwin,int op)2272 void xgc_buf_scroll(window_textbuffer_t *cutwin, int op)
2273 {
2274 long total, val;
2275
2276 switch (op) {
2277 case op_UpLine:
2278 scroll_to(cutwin, cutwin->scrollline-1);
2279 break;
2280 case op_DownLine:
2281 scroll_to(cutwin, cutwin->scrollline+1);
2282 break;
2283 case op_UpPage:
2284 total = 0;
2285 for (val = cutwin->scrollline; val > 0; val--) {
2286 total += cutwin->linelist[val-1].height;
2287 if (total > cutwin->textwin_h) {
2288 val++;
2289 break;
2290 }
2291 }
2292 scroll_to(cutwin, val);
2293 break;
2294 case op_DownPage:
2295 scroll_to(cutwin, cutwin->scrollline+(cutwin->linesonpage-1));
2296 break;
2297 case op_ToTop:
2298 scroll_to(cutwin, 0);
2299 break;
2300 case op_ToBottom:
2301 scroll_to(cutwin, cutwin->numlines);
2302 break;
2303 }
2304 }
2305
xgc_buf_movecursor(window_textbuffer_t * cutwin,int op)2306 void xgc_buf_movecursor(window_textbuffer_t *cutwin, int op)
2307 {
2308 long pos;
2309
2310 switch (op) {
2311 case op_BackChar:
2312 if (cutwin->dotlen) {
2313 cutwin->dotlen = 0;
2314 }
2315 else {
2316 collapse_dot(cutwin);
2317 if (cutwin->dotpos > 0)
2318 cutwin->dotpos--;
2319 }
2320 break;
2321 case op_ForeChar:
2322 if (cutwin->dotlen) {
2323 collapse_dot(cutwin);
2324 }
2325 else {
2326 collapse_dot(cutwin);
2327 if (cutwin->dotpos < cutwin->numchars)
2328 cutwin->dotpos++;
2329 }
2330 break;
2331 case op_BackWord:
2332 collapse_dot(cutwin);
2333 cutwin->dotpos = back_to_nonwhite(cutwin, cutwin->dotpos);
2334 cutwin->dotpos = back_to_white(cutwin, cutwin->dotpos);
2335 break;
2336 case op_ForeWord:
2337 collapse_dot(cutwin);
2338 cutwin->dotpos = fore_to_nonwhite(cutwin, cutwin->dotpos);
2339 cutwin->dotpos = fore_to_white(cutwin, cutwin->dotpos);
2340 break;
2341 case op_BeginLine:
2342 if (cutwin->dotlen) {
2343 cutwin->dotlen = 0;
2344 }
2345 else {
2346 if (cutwin->buffer && cutwin->dotpos >= cutwin->inputfence)
2347 cutwin->dotpos = cutwin->inputfence;
2348 else {
2349 pos = cutwin->dotpos;
2350 while (pos > 0 && cutwin->charbuf[pos-1] != '\n')
2351 pos--;
2352 cutwin->dotpos = pos;
2353 }
2354 }
2355 break;
2356 case op_EndLine:
2357 if (cutwin->dotlen) {
2358 collapse_dot(cutwin);
2359 }
2360 else {
2361 if (cutwin->buffer && cutwin->dotpos >= cutwin->inputfence)
2362 cutwin->dotpos = cutwin->numchars;
2363 else {
2364 pos = cutwin->dotpos;
2365 while (pos < cutwin->numchars && cutwin->charbuf[pos] != '\n')
2366 pos++;
2367 cutwin->dotpos = pos;
2368 }
2369 }
2370 break;
2371 }
2372 win_textbuffer_layout(cutwin);
2373 }
2374
xgc_buf_getchar(window_textbuffer_t * cutwin,int ch)2375 void xgc_buf_getchar(window_textbuffer_t *cutwin, int ch)
2376 {
2377 if (cutwin->owner->char_request) {
2378 glui32 key = ch;
2379 eventloop_setevent(evtype_CharInput, cutwin->owner, key, 0);
2380 cutwin->owner->char_request = FALSE;
2381 }
2382 }
2383
xgc_buf_insert(window_textbuffer_t * cutwin,int ch)2384 void xgc_buf_insert(window_textbuffer_t *cutwin, int ch)
2385 {
2386 char realch;
2387
2388 /* ###### not perfect -- should be all typable chars */
2389 if (ch < 32 || ch >= 127)
2390 ch = ' ';
2391
2392 realch = ch;
2393
2394 if (cutwin->dotpos < cutwin->inputfence) {
2395 cutwin->dotpos = cutwin->numchars;
2396 cutwin->dotlen = 0;
2397 win_textbuffer_add(cutwin, ch, cutwin->dotpos);
2398 }
2399 else {
2400 win_textbuffer_replace(cutwin, cutwin->dotpos, cutwin->dotlen, &realch, 1);
2401 }
2402
2403 win_textbuffer_layout(cutwin);
2404 win_textbuffer_end_visible(cutwin);
2405 }
2406
xgc_buf_delete(window_textbuffer_t * cutwin,int op)2407 void xgc_buf_delete(window_textbuffer_t *cutwin, int op)
2408 {
2409 long pos;
2410
2411 if (cutwin->dotpos < cutwin->inputfence)
2412 return;
2413
2414 if (cutwin->dotlen != 0 && (op == op_BackChar || op == op_ForeChar)) {
2415 win_textbuffer_replace(cutwin, cutwin->dotpos, cutwin->dotlen, "", 0);
2416 win_textbuffer_layout(cutwin);
2417 return;
2418 }
2419
2420 collapse_dot(cutwin);
2421
2422 switch (op) {
2423 case op_BackChar:
2424 if (cutwin->dotpos <= cutwin->inputfence)
2425 return;
2426 win_textbuffer_replace(cutwin, cutwin->dotpos-1, 1, "", 0);
2427 break;
2428 case op_ForeChar:
2429 if (cutwin->dotpos < cutwin->inputfence || cutwin->dotpos >= cutwin->numchars)
2430 return;
2431 win_textbuffer_replace(cutwin, cutwin->dotpos, 1, "", 0);
2432 break;
2433 case op_BackWord:
2434 pos = back_to_nonwhite(cutwin, cutwin->dotpos);
2435 pos = back_to_white(cutwin, pos);
2436 if (pos < cutwin->inputfence)
2437 pos = cutwin->inputfence;
2438 if (pos >= cutwin->dotpos)
2439 return;
2440 win_textbuffer_replace(cutwin, pos, cutwin->dotpos-pos, "", 0);
2441 break;
2442 case op_ForeWord:
2443 pos = fore_to_nonwhite(cutwin, cutwin->dotpos);
2444 pos = fore_to_white(cutwin, pos);
2445 if (pos < cutwin->inputfence)
2446 pos = cutwin->inputfence;
2447 if (pos <= cutwin->dotpos)
2448 return;
2449 win_textbuffer_replace(cutwin, cutwin->dotpos, pos-cutwin->dotpos, "", 0);
2450 break;
2451 }
2452 win_textbuffer_layout(cutwin);
2453 }
2454
xgc_buf_cutbuf(window_textbuffer_t * cutwin,int op)2455 void xgc_buf_cutbuf(window_textbuffer_t *cutwin, int op)
2456 {
2457 char *cx;
2458 long num;
2459 long tmppos;
2460
2461 if (op != op_Copy) {
2462 if (!cutwin->buffer) {
2463 xmsg_set_message("You are not editing input in this window.", FALSE);
2464 return;
2465 }
2466 }
2467
2468 switch (op) {
2469 case op_Copy:
2470 if (cutwin->dotlen) {
2471 xglk_store_scrap(cutwin->charbuf+cutwin->dotpos, cutwin->dotlen);
2472 }
2473 break;
2474 case op_Wipe:
2475 if (cutwin->dotlen) {
2476 xglk_store_scrap(cutwin->charbuf+cutwin->dotpos, cutwin->dotlen);
2477 if (cutwin->dotpos >= cutwin->inputfence) {
2478 win_textbuffer_replace(cutwin, cutwin->dotpos, cutwin->dotlen, "", 0);
2479 win_textbuffer_layout(cutwin);
2480 }
2481 }
2482 break;
2483 case op_Erase:
2484 if (cutwin->dotlen) {
2485 if (cutwin->dotpos >= cutwin->inputfence) {
2486 win_textbuffer_replace(cutwin, cutwin->dotpos, cutwin->dotlen, "", 0);
2487 win_textbuffer_layout(cutwin);
2488 }
2489 }
2490 break;
2491 case op_Kill:
2492 if (cutwin->dotpos < cutwin->inputfence) {
2493 /* maybe extend to end-of-line and copy? */
2494 break;
2495 }
2496 cutwin->dotlen = cutwin->numchars-cutwin->dotpos;
2497 xglk_store_scrap(cutwin->charbuf+cutwin->dotpos, cutwin->dotlen);
2498 win_textbuffer_replace(cutwin, cutwin->dotpos, cutwin->dotlen, "", 0);
2499 win_textbuffer_layout(cutwin);
2500 break;
2501 case op_Yank:
2502 collapse_dot(cutwin);
2503 if (cutwin->dotpos < cutwin->inputfence)
2504 cutwin->dotpos = cutwin->numchars;
2505 xglk_fetch_scrap(&cx, &num);
2506 xglk_strip_garbage(cx, num);
2507 if (cx && num) {
2508 tmppos = cutwin->dotpos;
2509 win_textbuffer_replace(cutwin, tmppos, 0, cx, num);
2510 cutwin->dotpos = tmppos+num;
2511 cutwin->dotlen = 0;
2512 free(cx);
2513 }
2514 win_textbuffer_layout(cutwin);
2515 break;
2516 case op_YankReplace:
2517 xglk_fetch_scrap(&cx, &num);
2518 xglk_strip_garbage(cx, num);
2519 if (cx && num) {
2520 if (cutwin->dotpos < cutwin->inputfence) {
2521 cutwin->dotpos = cutwin->numchars;
2522 cutwin->dotlen = 0;
2523 }
2524 tmppos = cutwin->dotpos;
2525 win_textbuffer_replace(cutwin, tmppos, cutwin->dotlen, cx, num);
2526 cutwin->dotpos = tmppos+num;
2527 cutwin->dotlen = 0;
2528 free(cx);
2529 }
2530 win_textbuffer_layout(cutwin);
2531 break;
2532 case op_Untype:
2533 if (cutwin->numchars == cutwin->inputfence)
2534 break;
2535 cutwin->dotpos = cutwin->inputfence;
2536 cutwin->dotlen = cutwin->numchars-cutwin->inputfence;
2537 xglk_store_scrap(cutwin->charbuf+cutwin->dotpos, cutwin->dotlen);
2538 win_textbuffer_replace(cutwin, cutwin->dotpos, cutwin->dotlen, "", 0);
2539 win_textbuffer_layout(cutwin);
2540 break;
2541
2542 }
2543 }
2544
xgc_buf_history(window_textbuffer_t * cutwin,int op)2545 void xgc_buf_history(window_textbuffer_t *cutwin, int op)
2546 {
2547 long pos, len;
2548
2549 switch (op) {
2550 case op_BackLine:
2551 if (cutwin->historypos > 0) {
2552 #ifdef OLDSTYLEHISTORY
2553 if (cutwin->dotpos < cutwin->inputfence) {
2554 cutwin->dotpos = cutwin->numchars;
2555 cutwin->dotlen = 0;
2556 }
2557 cutwin->historypos--;
2558 pos = cutwin->dotpos;
2559 win_textbuffer_replace(cutwin, pos, cutwin->dotlen, cutwin->history[cutwin->historypos].str, cutwin->history[cutwin->historypos].len);
2560 cutwin->dotpos = pos;
2561 cutwin->dotlen = cutwin->history[cutwin->historypos].len;
2562 #else
2563 cutwin->historypos--;
2564 win_textbuffer_replace(cutwin, cutwin->inputfence, cutwin->numchars-cutwin->inputfence,
2565 cutwin->history[cutwin->historypos].str, cutwin->history[cutwin->historypos].len);
2566 cutwin->dotpos = cutwin->inputfence + cutwin->history[cutwin->historypos].len;
2567 cutwin->dotlen = 0;
2568 #endif
2569 win_textbuffer_layout(cutwin);
2570 }
2571 break;
2572 case op_ForeLine:
2573 if (cutwin->historypos < cutwin->historynum) {
2574 #ifdef OLDSTYLEHISTORY
2575 if (cutwin->dotpos < cutwin->inputfence) {
2576 cutwin->dotpos = cutwin->numchars;
2577 cutwin->dotlen = 0;
2578 }
2579 cutwin->historypos++;
2580 if (cutwin->historypos < cutwin->historynum) {
2581 pos = cutwin->dotpos;
2582 win_textbuffer_replace(cutwin, cutwin->dotpos, cutwin->dotlen, cutwin->history[cutwin->historypos].str, cutwin->history[cutwin->historypos].len);
2583 cutwin->dotpos = pos;
2584 cutwin->dotlen = cutwin->history[cutwin->historypos].len;
2585 }
2586 else {
2587 pos = cutwin->dotpos;
2588 win_textbuffer_replace(cutwin, cutwin->dotpos, cutwin->dotlen, "", 0);
2589 cutwin->dotpos = pos;
2590 cutwin->dotlen = 0;
2591 }
2592 #else
2593 cutwin->historypos++;
2594 if (cutwin->historypos < cutwin->historynum) {
2595 win_textbuffer_replace(cutwin, cutwin->inputfence, cutwin->numchars-cutwin->inputfence,
2596 cutwin->history[cutwin->historypos].str, cutwin->history[cutwin->historypos].len);
2597 cutwin->dotpos = cutwin->inputfence + cutwin->history[cutwin->historypos].len;
2598 cutwin->dotlen = 0;
2599 }
2600 else {
2601 win_textbuffer_replace(cutwin, cutwin->inputfence, cutwin->numchars-cutwin->inputfence, "", 0);
2602 cutwin->dotpos = cutwin->inputfence;
2603 cutwin->dotlen = 0;
2604 }
2605 #endif
2606 win_textbuffer_layout(cutwin);
2607 }
2608 }
2609 }
2610
xgc_buf_enter(window_textbuffer_t * cutwin,int op)2611 void xgc_buf_enter(window_textbuffer_t *cutwin, int op)
2612 {
2613 long ix, len, len2;
2614 long buflen;
2615 char *buffer;
2616 gidispatch_rock_t inarrayrock;
2617
2618 if (op != op_Enter)
2619 return;
2620
2621 if (!cutwin->buffer)
2622 return;
2623
2624 buffer = cutwin->buffer;
2625 buflen = cutwin->buflen;
2626 inarrayrock = cutwin->inarrayrock;
2627
2628 win_textbuffer_set_style_text(cutwin, cutwin->originalattr);
2629
2630 len = cutwin->numchars - cutwin->inputfence;
2631 len2 = 0;
2632 for (ix=0; ix < len && len2 < buflen; ix++) {
2633 unsigned char ch = cutwin->charbuf[cutwin->inputfence+ix];
2634 buffer[len2] = ch;
2635 len2++;
2636 }
2637
2638 len = cutwin->numchars - cutwin->inputfence;
2639 if (len) {
2640 /* add to history */
2641 if (cutwin->historynum==cutwin->historylength) {
2642 free(cutwin->history[0].str);
2643 memmove(&cutwin->history[0], &cutwin->history[1], (cutwin->historylength-1) * (sizeof(histunit)));
2644 }
2645 else
2646 cutwin->historynum++;
2647 cutwin->history[cutwin->historynum-1].str = malloc(len*sizeof(char));
2648 memmove(cutwin->history[cutwin->historynum-1].str, cutwin->charbuf+cutwin->inputfence, len*sizeof(char));
2649 cutwin->history[cutwin->historynum-1].len = len;
2650 }
2651
2652 if (cutwin->owner->echostr) {
2653 window_t *oldwin = cutwin->owner;
2654 /*gli_stream_echo_line(cutwin->owner->echostr,
2655 cutwin->charbuf+cutwin->inputfence, len*sizeof(char));*/
2656 gli_stream_echo_line(cutwin->owner->echostr,
2657 buffer, len2*sizeof(char));
2658 }
2659
2660 win_textbuffer_add(cutwin, '\n', -1);
2661 cutwin->dotpos = cutwin->numchars;
2662 cutwin->dotlen = 0;
2663 cutwin->inputfence = 0;
2664 win_textbuffer_layout(cutwin);
2665
2666 eventloop_setevent(evtype_LineInput, cutwin->owner, len2, 0);
2667 cutwin->owner->line_request = FALSE;
2668 cutwin->buffer = NULL;
2669 cutwin->buflen = 0;
2670
2671 if (gli_unregister_arr) {
2672 (*gli_unregister_arr)(buffer, buflen, "&+#!Cn", inarrayrock);
2673 }
2674 }
2675
win_textbuffer_line_cancel(window_textbuffer_t * cutwin,event_t * ev)2676 static void win_textbuffer_line_cancel(window_textbuffer_t *cutwin,
2677 event_t *ev)
2678 {
2679 long ix, len, len2;
2680 long buflen;
2681 char *buffer;
2682 gidispatch_rock_t inarrayrock;
2683
2684 /* same as xgc_buf_enter(), but skip the unnecessary stuff.
2685 We don't need to add to history, collapse the dot, win_textbuffer_layout,
2686 trim the buffer, or shrink the status window. */
2687
2688 if (!cutwin->buffer)
2689 return;
2690
2691 buffer = cutwin->buffer;
2692 buflen = cutwin->buflen;
2693 inarrayrock = cutwin->inarrayrock;
2694
2695 len = cutwin->numchars - cutwin->inputfence;
2696 len2 = 0;
2697 for (ix=0; ix < len && len2 < buflen; ix++) {
2698 unsigned char ch = cutwin->charbuf[cutwin->inputfence+ix];
2699 buffer[len2] = ch;
2700 len2++;
2701 }
2702
2703 len = cutwin->numchars - cutwin->inputfence;
2704 /*if (len) {
2705 win_textbuffer_replace(cutwin->inputfence, len, "", 0);
2706 cutwin->dotpos = cutwin->numchars;
2707 cutwin->dotlen = 0;
2708 win_textbuffer_layout(cutwin);
2709 }*/
2710
2711 win_textbuffer_set_style_text(cutwin, cutwin->originalattr);
2712
2713 if (cutwin->owner->echostr) {
2714 window_t *oldwin = cutwin->owner;
2715 /*gli_stream_echo_line(cutwin->owner->echostr,
2716 cutwin->charbuf+cutwin->inputfence, len*sizeof(char));*/
2717 gli_stream_echo_line(cutwin->owner->echostr,
2718 buffer, len2*sizeof(char));
2719 }
2720
2721 win_textbuffer_add(cutwin, '\n', -1);
2722 cutwin->dotpos = cutwin->numchars;
2723 cutwin->dotlen = 0;
2724 cutwin->inputfence = 0;
2725 win_textbuffer_layout(cutwin);
2726
2727 /* create event, and set everything blank. */
2728 ev->type = evtype_LineInput;
2729 ev->val1 = len2;
2730 ev->val2 = 0;
2731 ev->win = cutwin->owner;
2732 cutwin->owner->line_request = FALSE;
2733 cutwin->buffer = NULL;
2734 cutwin->buflen = 0;
2735
2736 if (gli_unregister_arr) {
2737 (*gli_unregister_arr)(buffer, buflen, "&+#!Cn", inarrayrock);
2738 }
2739 }
2740
win_textbuffer_trim_buffer(window_textbuffer_t * cutwin)2741 void win_textbuffer_trim_buffer(window_textbuffer_t *cutwin)
2742 {
2743 if (cutwin->numchars > prefs.buffersize + prefs.bufferslack) {
2744 long lx;
2745 for (lx=0; lx<cutwin->numlines; lx++)
2746 if (cutwin->linelist[lx].pos > (cutwin->numchars-prefs.buffersize))
2747 break;
2748 if (lx) {
2749 win_textbuffer_delete_start(cutwin, lx);
2750 }
2751 }
2752 }
2753
2754