#include #include #include #include #include "ztypes.h" #include "xio.h" static char *charbuf; static long numchars; static long char_size; typedef struct style_t { int attr; /* flags are REVERSE, BOLD, EMPHASIS, FIXED_FONT */ long pos; /* position this style starts at */ } style; static style *stylelist; static long numstyles; static long styles_size; typedef struct word_t { long pos, len; long width; /* in pixels */ int attr; long *letterpos; /* if not NULL, an array[0..len] of pixel offsets from wordpos; */ } word; #define lineflag_Wrapped (1) /* line is a wrap or split from previous line */ #define lineflag_Extra (2) /* the magic extra line on the end */ typedef struct line_t { long pos; /* line starts here */ 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. */ word *wordlist; long numwords; int flags; } lline; static lline *linelist; static long numlines; static long lines_size; static lline *tmplinelist; static long tmplines_size; static long scrollpos; /* character position at top of screen */ static long scrollline; /* number of line at top of screen, after xtext_layout() */ static long lastlineseen; /* last line read before more stuff was output. (-1) to indicate all lines read. */ static long dotpos, dotlen; /* dotpos is in [0..numchars] */ static long lastdotpos = (-1), lastdotlen = 0; /* cached values -- fiddled inside xtext_layout() */ static long dirtybeg, dirtyend; /* mark the limits of what needs to be laid out, [) format */ static long dirtydelta; /* how much the dirty area has grown (or shrunk) */ static long startlay; /* pos of the char that starts the first laid-out line. */ static int textwin_x, textwin_y, textwin_w, textwin_h; static int scrollwin_x, scrollwin_y, scrollwin_w, scrollwin_h; static int scrollel_top, scrollel_bot; typedef struct histunit { char *str; int len; } histunit; static int historynum, historypos; static histunit *history; /* these are for xtext editing */ static int buflen; static char *buffer; static int *readpos; static long inputfence; static int *killflag; static int originalattr; #define collapse_dot() (dotpos += dotlen, dotlen = 0) #define SIDEMARGIN (4) #define BARENDHEIGHT (12) #define BARWIDTH (17) #define BAREXTRA (4) static XPoint polydot[3]; static long linesperpage; #ifdef __STDC__ static void redrawtext(long beg, long num, int clearnum); static void flip_selection(long dpos, long dlen); static void find_loc_by_pos(long pos, int *xposret, int *yposret); static long find_pos_by_loc(int xpos, int ypos); static long find_line_by_pos(long pos, long guessline); static void measure_word(lline *curline, word *curword); static void adjust_elevator(); void xtext_delete_start(long num); #else static void redrawtext(); static void flip_selection(); static void find_loc_by_pos(); static long find_pos_by_loc(); static long find_line_by_pos(); static void measure_word(); static void adjust_elevator(); void xtext_delete_start(); #endif #ifdef __STDC__ void xtext_init() #else void xtext_init() #endif { char_size = 256; charbuf = (char *)malloc(sizeof(char) * char_size); numchars = 0; styles_size = 8; stylelist = (style *)malloc(sizeof(style) * styles_size); numstyles = 1; stylelist[0].pos = 0; stylelist[0].attr = 0; /* NORMAL style */ lines_size = 8; linelist = (lline *)malloc(sizeof(lline) * lines_size); numlines = 0; tmplines_size = 8; tmplinelist = (lline *)malloc(sizeof(lline) * tmplines_size); historynum = 0; history = (histunit *)malloc(prefs.historylength * sizeof(histunit)); scrollpos = 0; scrollline = 0; startlay = 0; /* not yet used */ dirtybeg = 0; dirtyend = 0; dirtydelta = 0; dotpos = 0; dotlen = 0; polydot[0].x = 0; polydot[0].y = 0; polydot[1].x = SIDEMARGIN; polydot[1].y = 5; polydot[2].x = -2*SIDEMARGIN; polydot[2].y = 0; scrollel_top = (-1); /* indicate elevator is not there */ scrollel_bot = (-1); lastlineseen = 0; } #ifdef __STDC__ void xtext_clear_window() #else void xtext_clear_window() #endif { xtext_delete_start(numlines); } #ifdef __STDC__ void xtext_resize(int xpos, int ypos, int width, int height) #else void xtext_resize(xpos, ypos, width, height) int xpos; int ypos; int width; int height; #endif { scrollwin_x = xpos; scrollwin_w = BARWIDTH; scrollwin_y = ypos+BARENDHEIGHT; scrollwin_h = height-2*BARENDHEIGHT; textwin_x = xpos+scrollwin_w+SIDEMARGIN+prefs.marginx; textwin_y = ypos; textwin_w = width-2*SIDEMARGIN-scrollwin_w-2*prefs.marginx; textwin_h = height; dirtybeg = 0; dirtyend = numchars; dirtydelta = 0; linesperpage = height / lineheight; xtext_layout(); } #ifdef __STDC__ void xtext_redraw() #else void xtext_redraw() #endif { XPoint poly[3]; /* 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?) */ /*flip_selection(dotpos, dotlen);*/ redrawtext(0, -1, -1); flip_selection(dotpos, dotlen); poly[0].x = scrollwin_x + scrollwin_w/2; poly[0].y = textwin_y + 1; poly[1].x = scrollwin_x + 0; poly[1].y = scrollwin_y - 2; poly[2].x = scrollwin_x + scrollwin_w - 1; poly[2].y = scrollwin_y - 2; XFillPolygon(xiodpy, xiowin, gcgrey, poly, 3, Convex, CoordModeOrigin); poly[0].x = scrollwin_x + scrollwin_w/2; poly[0].y = textwin_y + textwin_h - 1; poly[1].x = scrollwin_x + 0; poly[1].y = scrollwin_y + scrollwin_h + 2; poly[2].x = scrollwin_x + scrollwin_w - 1; poly[2].y = scrollwin_y + scrollwin_h + 2; XFillPolygon(xiodpy, xiowin, gcgrey, poly, 3, Convex, CoordModeOrigin); XDrawLine(xiodpy, xiowin, gcblack, scrollwin_x+scrollwin_w, textwin_y, scrollwin_x+scrollwin_w, textwin_h); scrollel_top = (-1); scrollel_bot = (-1); XFillRectangle(xiodpy, xiowin, gcgrey, scrollwin_x, scrollwin_y, scrollwin_w, scrollwin_h); adjust_elevator(); } #ifdef __STDC__ static long back_to_white(long pos) #else static long back_to_white(pos) long pos; #endif { while (pos > 0 && charbuf[pos-1] != ' ' && charbuf[pos-1] != '\n') pos--; return pos; } #ifdef __STDC__ static long fore_to_white(long pos) #else static long fore_to_white(pos) long pos; #endif { while (pos < numchars && charbuf[pos] != ' ' && charbuf[pos] != '\n') pos++; return pos; } #ifdef __STDC__ static long back_to_nonwhite(long pos) #else static long back_to_nonwhite(pos) long pos; #endif { while (pos > 0 && (charbuf[pos-1] == ' ' || charbuf[pos-1] == '\n')) pos--; return pos; } #ifdef __STDC__ static long fore_to_nonwhite(long pos) #else static long fore_to_nonwhite(pos) long pos; #endif { while (pos < numchars && (charbuf[pos] == ' ' || charbuf[pos] == '\n')) pos++; return pos; } /* 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. */ #ifdef __STDC__ static void redrawtext(long beg, long num, int clearnum) #else static void redrawtext(beg, num, clearnum) long beg; long num; int clearnum; #endif { long lx, wx, end, clearend; int ypos, ypos2, xpos; lline *thisline; word *thisword; if (num<0) end = numlines; else { end = beg+num; if (end > numlines) end = numlines; } if (beg < scrollline) beg = scrollline; if (clearnum > 0) { clearend = beg+clearnum; ypos = textwin_y + (beg-scrollline) * lineheight; ypos2 = textwin_y + (clearend-scrollline) * lineheight; if (ypos2 > textwin_y+textwin_h) { ypos2 = textwin_y+textwin_h; } if (ypos != ypos2) XClearArea(xiodpy, xiowin, textwin_x-SIDEMARGIN, ypos, textwin_w+2*SIDEMARGIN, ypos2-ypos, FALSE); } else if (clearnum < 0) { ypos = textwin_y + (beg-scrollline) * lineheight; ypos2 = textwin_y+textwin_h; if (ypos != ypos2) XClearArea(xiodpy, xiowin, textwin_x-SIDEMARGIN, ypos, textwin_w+2*SIDEMARGIN, ypos2-ypos, FALSE); } for (lx=beg; lx= textwin_y + textwin_h) break; xpos = textwin_x; for (wx=0; wxnumwords; wx++) { thisword = thisline->wordlist+wx; if (thisword->attr & REVERSE) XDrawImageString(xiodpy, xiowin, gcfont[thisword->attr], xpos, ypos+lineheightoff, charbuf+thisline->pos+thisword->pos, thisword->len); else XDrawString(xiodpy, xiowin, gcfont[thisword->attr], xpos, ypos+lineheightoff, charbuf+thisline->pos+thisword->pos, thisword->len); xpos += thisword->width; } } } #ifdef __STDC__ static void adjust_elevator() #else static void adjust_elevator() #endif { long newtop, newbot; int barheight = (scrollwin_h-2*BAREXTRA); if (numlines) { newtop = ((barheight*scrollline) / numlines) + BAREXTRA; newbot = ((barheight*(scrollline+linesperpage)) / numlines) + BAREXTRA; if (newtop < BAREXTRA) newtop = BAREXTRA; if (newbot >= scrollwin_h-BAREXTRA) newbot = scrollwin_h-BAREXTRA; } else { newtop = BAREXTRA; newbot = scrollwin_h-BAREXTRA; } if (newtop == scrollel_top && newbot==scrollel_bot) return; if (scrollel_top != (-1) && (scrollel_top >= newbot || newtop >= scrollel_bot)) { /* erase old completely */ XFillRectangle(xiodpy, xiowin, gcgrey, scrollwin_x, scrollwin_y+scrollel_top, scrollwin_w, scrollel_bot-scrollel_top); scrollel_top = (-1); } if (scrollel_top == (-1)) { /* redraw new completely */ XDrawRectangle(xiodpy, xiowin, gcblack, scrollwin_x, scrollwin_y+newtop, scrollwin_w-1, (newbot-newtop)-1); XFillRectangle(xiodpy, xiowin, gcwhite, scrollwin_x+1, scrollwin_y+newtop+1, scrollwin_w-2, (newbot-newtop)-2); scrollel_top = newtop; scrollel_bot = newbot; return; } /* ok, the old and new overlap */ if (newtop < scrollel_top) { XFillRectangle(xiodpy, xiowin, gcwhite, scrollwin_x+1, scrollwin_y+newtop+1, scrollwin_w-2, scrollel_top-newtop); } else if (newtop > scrollel_top) { XFillRectangle(xiodpy, xiowin, gcgrey, scrollwin_x, scrollwin_y+scrollel_top, scrollwin_w, newtop-scrollel_top); } if (newbot > scrollel_bot) { XFillRectangle(xiodpy, xiowin, gcwhite, scrollwin_x+1, scrollwin_y+scrollel_bot-1, scrollwin_w-2, newbot-scrollel_bot); } else if (newbot < scrollel_bot) { XFillRectangle(xiodpy, xiowin, gcgrey, scrollwin_x, scrollwin_y+newbot, scrollwin_w, scrollel_bot-newbot); } XDrawRectangle(xiodpy, xiowin, gcblack, scrollwin_x, scrollwin_y+newtop, scrollwin_w-1, (newbot-newtop)-1); scrollel_top = newtop; scrollel_bot = newbot; } #ifdef __STDC__ static void scroll_to(long newscrollline) #else static void scroll_to(newscrollline) long newscrollline; #endif { long oldscrollline; if (newscrollline > numlines-2) newscrollline = numlines-2; if (newscrollline < 0) newscrollline = 0; scrollpos = linelist[newscrollline].pos; if (scrollline != newscrollline) { oldscrollline = scrollline; if (!xiobackstore || oldscrollline + linesperpage <= newscrollline || newscrollline + linesperpage <= oldscrollline) { scrollline = newscrollline; redrawtext(scrollline, -1, -1); flip_selection(dotpos, dotlen); } else { int ypos1, ypos2, yhgt; flip_selection(dotpos, dotlen); scrollline = newscrollline; if (oldscrollline < newscrollline) { /* scroll down -- things move up */ ypos1 = textwin_y + (newscrollline-oldscrollline) * lineheight; ypos2 = textwin_y + (0) * lineheight; yhgt = (linesperpage-(newscrollline-oldscrollline)) * lineheight; XCopyArea(xiodpy, xiowin, xiowin, gcblack, textwin_x-SIDEMARGIN, ypos1, textwin_w+2*SIDEMARGIN, yhgt, textwin_x-SIDEMARGIN, ypos2); redrawtext(linesperpage + oldscrollline, (newscrollline-oldscrollline), (newscrollline-oldscrollline)); } else { /* scroll up -- things move down */ ypos2 = textwin_y + (oldscrollline-newscrollline) * lineheight; ypos1 = textwin_y + (0) * lineheight; yhgt = (linesperpage-(oldscrollline-newscrollline)) * lineheight; XCopyArea(xiodpy, xiowin, xiowin, gcblack, textwin_x-SIDEMARGIN, ypos1, textwin_w+2*SIDEMARGIN, yhgt, textwin_x-SIDEMARGIN, ypos2); redrawtext(newscrollline, (oldscrollline-newscrollline), (oldscrollline-newscrollline)); } flip_selection(dotpos, dotlen); } adjust_elevator(); } } #ifdef __STDC__ static void refiddle_selection(long oldpos, long oldlen, long newpos, long newlen) #else static void refiddle_selection(oldpos, oldlen, newpos, newlen) long oldpos; long oldlen; long newpos; long newlen; #endif { if (oldlen==0 || newlen==0 || oldpos<0 || newpos<0) { flip_selection(oldpos, oldlen); flip_selection(newpos, newlen); return; } if (oldpos == newpos) { /* start at same place */ if (oldlen < newlen) { flip_selection(oldpos+oldlen, newlen-oldlen); } else if (newlen < oldlen) { flip_selection(oldpos+newlen, oldlen-newlen); } return; } if (oldpos+oldlen == newpos+newlen) { /* end at same place */ if (oldpos < newpos) { flip_selection(oldpos, newpos-oldpos); } else if (newpos < oldpos) { flip_selection(newpos, oldpos-newpos); } return; } flip_selection(oldpos, oldlen); flip_selection(newpos, newlen); } #ifdef __STDC__ static void flip_selection(long dpos, long dlen) #else static void flip_selection(dpos, dlen) long dpos; long dlen; #endif { int xpos, ypos; int xpos2, ypos2; long ybody, ybody2; if (dpos < 0) { return; /* dot hidden */ } if (dlen==0) { find_loc_by_pos(dpos, &xpos, &ypos); if (ypos < 0 || ypos+lineheight >= textwin_h) { return; } polydot[0].x = textwin_x + xpos; polydot[0].y = textwin_y + ypos + lineheightoff; XFillPolygon(xiodpy, xiowin, gcflip, polydot, 3, Convex, CoordModePrevious); } else { find_loc_by_pos(dpos, &xpos, &ypos); find_loc_by_pos(dpos+dlen, &xpos2, &ypos2); if (ypos==ypos2) { /* within one line */ if (xpos!=xpos2 && ypos>=0 && ypos+lineheight=0 && ypos+lineheight=0 && ybody+lineheight= textwin_h) ybody2 = textwin_h; /* main body */ XFillRectangle(xiodpy, xiowin, gcflip, textwin_x, ybody+textwin_y, textwin_w, ybody2-ybody); } if (xpos2 && ypos2>=0 && ypos2+lineheight= lines_size) { while (newnumlines >= lines_size) lines_size *= 2; linelist = (lline *)realloc(linelist, sizeof(lline) * lines_size); } /* clobber old */ for (lx=oldbeg; lxletterpos) { free(thisword->letterpos); } } free(linelist[lx].wordlist); linelist[lx].wordlist = NULL; } if (oldend < numlines && newnumlines != numlines) { memmove(&linelist[oldend+(newnumlines-numlines)], &linelist[oldend], sizeof(lline) * (numlines-oldend)); } /* ### adjust scrollline by difference too? */ numlines = newnumlines; if (newnum) { memcpy(&linelist[oldbeg], &tmplinelist[0], sizeof(lline) * (newnum)); } } /* xpos, ypos are relative to textwin origin */ #ifdef __STDC__ static long find_pos_by_loc(int xpos, int ypos) #else static long find_pos_by_loc(xpos, ypos) int xpos; int ypos; #endif { int ix; long linenum; long wx, atpos, newpos; lline *curline; word *curword; if (ypos < 0) linenum = (-1) - ((-1)-ypos / lineheight); else linenum = ypos / lineheight; linenum += scrollline; if (linenum < 0) return 0; if (linenum >= numlines) return numchars; curline = (&linelist[linenum]); if (xpos < 0) { return curline->pos; /* beginning of line */ } atpos = 0; for (wx=0; wxnumwords; wx++) { newpos = atpos + curline->wordlist[wx].width; if (xpos < newpos) break; atpos = newpos; } if (wx==curline->numwords) { return curline->posend; /* end of line */ } xpos -= atpos; /* now xpos is relative to word beginning */ curword = (&curline->wordlist[wx]); if (!curword->letterpos) measure_word(curline, curword); for (ix=0; ixlen; ix++) { if (xpos <= (curword->letterpos[ix]+curword->letterpos[ix+1])/2) break; } return curline->pos + curword->pos + ix; } /* 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. */ #ifdef __STDC__ static long find_line_by_pos(long pos, long guessline) #else static long find_line_by_pos(pos, guessline) long pos; long guessline; #endif { long lx; if (guessline < 0 || guessline >= numlines) guessline = numlines-1; if (guessline < numlines-1 && linelist[guessline].pos <= pos) { for (lx=guessline; lx pos) break; } lx--; } else { for (lx=guessline; lx>=0; lx--) { if (linelist[lx].pos <= pos) break; } } return lx; } /* returns values relative to textwin origin, at top of line. */ #ifdef __STDC__ static void find_loc_by_pos(long pos, int *xposret, int *yposret) #else static void find_loc_by_pos(pos, xposret, yposret) long pos; int *xposret; int *yposret; #endif { long lx; long wx, atpos; lline *curline; word *curword; lx = find_line_by_pos(pos, -1); if (lx < 0) { /* somehow before first line laid out */ *xposret = 0; *yposret = (-scrollline) * lineheight; return; } curline = (&linelist[lx]); *yposret = (lx-scrollline) * lineheight; atpos = 0; for (wx=0; wxnumwords; wx++) { if (curline->pos+curline->wordlist[wx].pos+curline->wordlist[wx].len >= pos) break; atpos += curline->wordlist[wx].width; } if (wx==curline->numwords) { *xposret = atpos; return; } curword = (&curline->wordlist[wx]); if (!curword->letterpos) measure_word(curline, curword); atpos += curword->letterpos[pos - (curline->pos+curword->pos)]; *xposret = atpos; } #ifdef __STDC__ static void measure_word(lline *curline, word *curword) #else static void measure_word(curline, curword) lline *curline; word *curword; #endif { int cx; char *buf; int direction; int ascent, descent; XCharStruct overall; long *arr; if (curword->letterpos) free(curword->letterpos); arr = (long *)malloc(sizeof(long) * (curword->len+1)); buf = charbuf+curline->pos+curword->pos; arr[0] = 0; for (cx=0; cxlen-1; cx++) { XTextExtents(fontstr[curword->attr], buf+cx, 1, &direction, &ascent, &descent, &overall); arr[cx+1] = arr[cx] + overall.width; } arr[cx+1] = curword->width; curword->letterpos = arr; } #ifdef __STDC__ static void strip_garbage(char *buf, int len) #else static void strip_garbage(buf, len) char *buf; int len; #endif { int ix; for (ix=0; ix= char_size) { while (newnumchars >= char_size) char_size *= 2; charbuf = (char *)realloc(charbuf, sizeof(char) * char_size); } if (pos < dirtybeg || dirtybeg < 0) dirtybeg = pos; if (newlen != oldlen) { if (pos+oldlen != numchars) { memmove(charbuf+pos+newlen, charbuf+pos+oldlen, sizeof(char) * (numchars-(pos+oldlen))); } if (numchars >= dirtyend) dirtyend = numchars+1; dirtydelta += (newlen-oldlen); } else { if (pos+newlen >= dirtyend) dirtyend = pos+newlen+1; dirtydelta += (newlen-oldlen); } /* copy in the new stuff */ if (newlen) memmove(charbuf+pos, buf, sizeof(char) * newlen); /* diddle the dot */ if (dotpos >= pos+oldlen) { /* starts after changed region */ dotpos += (newlen-oldlen); } else if (dotpos >= pos) { /* starts inside changed region */ if (dotpos+dotlen >= pos+oldlen) { /* ...but ends after it */ dotlen = (dotpos+dotlen)-(pos+oldlen); dotpos = pos+newlen; } else { /* ...and ends inside it */ dotpos = pos+newlen; dotlen = 0; } } else { /* starts before changed region */ if (dotpos+dotlen >= pos+oldlen) { /* ...but ends after it */ dotlen += (newlen-oldlen); } else if (dotpos+dotlen >= pos) { /* ...but ends inside it */ dotlen = (pos+newlen) - dotpos; } } numchars = newnumchars; } #ifdef __STDC__ void xtext_setstyle(long pos, int attr) #else void xtext_setstyle(pos, attr) long pos; int attr; #endif { long sx; if (pos < 0) pos = numchars; for (sx=numstyles-1; sx>=0; sx--) { if (stylelist[sx].pos <= pos) { break; } } if (sx < 0) { printf("### oops, went back behind style 0\n"); return; } if (stylelist[sx].pos == pos) { stylelist[sx].attr = attr; } else { /* insert a style after sx */ sx++; if (numstyles+1 >= styles_size) { styles_size *= 2; stylelist = (style *)realloc(stylelist, sizeof(style) * styles_size); } numstyles++; if (sx < numstyles) { memmove(&stylelist[sx+1], &stylelist[sx], sizeof(style) * (numstyles-sx)); stylelist[sx].pos = pos; stylelist[sx].attr = attr; } } if (pos != numchars) { /* ### should only go to next style */ dirtybeg = pos; dirtyend = numchars; dirtydelta = 0; xtext_layout(); } } #ifdef __STDC__ void xtext_set_lastseen() #else void xtext_set_lastseen() #endif { lastlineseen = numlines; } #ifdef __STDC__ void xtext_end_visible() #else void xtext_end_visible() #endif { long lx; if (lastlineseen < 0 || lastlineseen >= (numlines-linesperpage)-1) { /* straight to end */ if (scrollline < numlines-linesperpage) { scroll_to(numlines-linesperpage); } } else { lx = lastlineseen-1; while (lx < numlines-linesperpage) { scroll_to(lx); xmess_set_message("[Hit any key to continue.]", TRUE); xio_pause(); lx += (linesperpage-1); } scroll_to(numlines-linesperpage); xmess_set_message(NULL, TRUE); } lastlineseen = (-1); } /* delete num lines from the top */ #ifdef __STDC__ void xtext_delete_start(long num) #else void xtext_delete_start(num) long num; #endif { long delchars; long lx, sx, sx2; int origattr; if (num > numlines) num = numlines; if (num < 0) num = 0; if (num == numlines) delchars = numchars; else delchars = linelist[num].pos; if (!delchars) return; /* lines */ slapover(0, 0, num); for (lx=0; lx delchars) break; } if (sx>0) { origattr = stylelist[sx-1].attr; stylelist[0].pos = 0; stylelist[0].attr = origattr; for (sx2=1; sx0 && lx0; styx--) if (stylelist[styx].pos <= startpos) break; if (styx==numstyles-1) nextstylepos = numchars+10; else nextstylepos = stylelist[styx+1].pos; curstyle = stylelist[styx].attr; /* start a-layin' */ tmpl = 0; prevflags = 0; while (startpos= dirtyend && charbuf[startpos]=='\n')) { lline *thisline; long tmpw, tmpwords_size; long widthsofar, spaceswidth; if (tmpl+1 >= tmplines_size) { /* the +1 allows the extra blank line at the end */ tmplines_size *= 2; tmplinelist = (lline *)realloc(tmplinelist, sizeof(lline) * tmplines_size); } thisline = (&tmplinelist[tmpl]); thisline->flags = prevflags; tmpwords_size = 8; thisline->wordlist = (word *)malloc(tmpwords_size * sizeof(word)); tmpw = 0; /*printf("### laying tmpline %d, from charpos %d\n", tmpl, startpos);*/ tmpl++; ix = startpos; widthsofar = 0; prevflags = 0; while (ix= nextstylepos) { /* ahead one style */ styx++; if (styx==numstyles-1) nextstylepos = numchars+10; else nextstylepos = stylelist[styx+1].pos; curstyle = stylelist[styx].attr; } if (tmpw >= tmpwords_size) { tmpwords_size *= 2; thisline->wordlist = (word *)realloc(thisline->wordlist, tmpwords_size * sizeof(word)); } thisword = (&thisline->wordlist[tmpw]); /* --- initialize word structure --- */ thisword->letterpos = NULL; for (jx=ix; jx textwin_w) { prevflags = lineflag_Wrapped; if (tmpw == 0) { /* do something clever -- split the word, put first part in tmplist. */ int letx; long wordwidthsofar = 0; for (letx=ix; letx textwin_w) { break; } wordwidthsofar += overall.width; } jx = letx; overall.width = wordwidthsofar; /* spaceswidth and ejx will be 0 */ /* don't break */ } else { /* ejx and spaceswidth are properly set from last word, trim them off. */ thisword--; thisword->len -= ejx; thisword->width -= spaceswidth; break; } } /* figure out trailing whitespace */ ejx = 0; while (jx+ejxpos = ix-startpos; thisword->len = jx+ejx-ix; thisword->attr = curstyle; thisword->width = overall.width+spaceswidth; widthsofar += thisword->width; tmpw++; ix = jx+ejx; } thisline->pos = startpos; if (tmpw) { word *thisword = (&thisline->wordlist[tmpw-1]); thisline->posend = startpos + thisword->pos + thisword->len; } else { thisline->posend = startpos; } if (ixnumwords = tmpw; if (prefs.fulljustify && prevflags==lineflag_Wrapped && tmpw>1) { /* gonna regret this, I just bet */ long extraspace, each; extraspace = textwin_w - widthsofar; each = extraspace / (tmpw-1); extraspace -= (each*(tmpw-1)); for (jx=0; jxwordlist[jx].width += (each+1); } for (; jxwordlist[jx].width += each; } } startpos = ix; } /* done laying tmp lines */ if (startpos == numchars && (numchars==0 || charbuf[numchars-1]=='\n')) { /* lay one more line! */ lline *thisline; thisline = (&tmplinelist[tmpl]); thisline->flags = lineflag_Extra; tmpl++; thisline->wordlist = (word *)malloc(sizeof(word)); thisline->numwords = 0; thisline->pos = startpos; thisline->posend = startpos; } /*printf("### laid %d tmplines, and startpos now %d (delta %d)\n", tmpl, startpos, dirtydelta);*/ for (lx=overline; lx= startpos-dirtydelta) { /* disturbance is off top of screen -- adjust so that no difference is visible. */ scrollpos += dirtydelta; scrollline += (overline-overlineend) - tmpl; } else { scrollpos += dirtydelta; /* kind of strange, but shouldn't cause trouble */ if (scrollpos >= numchars) scrollpos = numchars-1; if (scrollpos < 0) scrollpos = 0; scrollline = find_line_by_pos(scrollpos, scrollline); needwholeredraw = TRUE; } dirtybeg = -1; dirtyend = -1; dirtydelta = 0; if (needwholeredraw) { redrawtext(scrollline, -1, -1); } else if (tmpl == overlineend-overline) { redrawtext(overline, tmpl, tmpl); } else { if (overlineend > numlines) redrawtext(overline, -1, overlineend-overline); else redrawtext(overline, -1, numlines-overline); } flip_selection(lastdotpos, lastdotlen); adjust_elevator(); } static long drag_firstbeg, drag_firstend; static int drag_inscroll; static int drag_scrollmode; /* 0 for click in elevator; 1 for dragged in elevator; 2 for endzones; 3 for click in background */ static int drag_hitypos; static long drag_origline; /* got a mouse hit. */ #ifdef __STDC__ void xtext_hitdown(int xpos, int ypos, unsigned int button, unsigned int mods, int clicknum) #else void xtext_hitdown(xpos, ypos, button, mods, clicknum) int xpos; int ypos; unsigned int button; unsigned int mods; int clicknum; #endif { long pos; long px, px2; if (xpos < scrollwin_x+scrollwin_w) drag_inscroll = TRUE; else drag_inscroll = FALSE; if (drag_inscroll) { drag_origline = scrollline; drag_hitypos = ypos-textwin_y; switch (button) { /* scrollbar */ case Button1: if (ypos < scrollwin_y) { drag_scrollmode = 2; xted_scroll(op_ToTop); } else if (ypos >= scrollwin_y+scrollwin_h) { drag_scrollmode = 2; xted_scroll(op_ToBottom); } else { if (ypos >= scrollwin_y+scrollel_top && ypos < scrollwin_y+scrollel_bot) drag_scrollmode = 0; else drag_scrollmode = 3; } break; case Button3: if (ypos < scrollwin_y) { drag_scrollmode = 2; xted_scroll(op_UpLine); } else if (ypos >= scrollwin_y+scrollwin_h) { drag_scrollmode = 2; xted_scroll(op_DownLine); } else { if (ypos >= scrollwin_y+scrollel_top && ypos < scrollwin_y+scrollel_bot) drag_scrollmode = 0; else drag_scrollmode = 3; } break; } } else { switch (button) { /* text window */ case Button1: case Button3: xpos -= textwin_x; ypos -= textwin_y; pos = find_pos_by_loc(xpos, ypos); if (button==Button1) { if (!(clicknum & 1)) { px = back_to_white(pos); px2 = fore_to_white(pos); } else { px = pos; px2 = pos; } dotpos = px; dotlen = px2-px; drag_firstbeg = px; drag_firstend = px2; } else { if (pos < dotpos+dotlen/2) { drag_firstbeg = dotpos+dotlen; } else { drag_firstbeg = dotpos; } drag_firstend = drag_firstbeg; if (pos < drag_firstbeg) { if (!(clicknum & 1)) dotpos = back_to_white(pos); else dotpos = pos; dotlen = drag_firstend-dotpos; } else if (pos > drag_firstend) { dotpos = drag_firstbeg; if (!(clicknum & 1)) dotlen = fore_to_white(pos)-drag_firstbeg; else dotlen = pos-drag_firstbeg; } else { dotpos = drag_firstbeg; dotlen = drag_firstend-drag_firstbeg; } } xtext_layout(); break; default: break; } } } #ifdef __STDC__ void xtext_hitmove(int xpos, int ypos, unsigned int button, unsigned int mods, int clicknum) #else void xtext_hitmove(xpos, ypos, button, mods, clicknum) int xpos; int ypos; unsigned int button; unsigned int mods; int clicknum; #endif { long pos, px; if (drag_inscroll) { if (drag_scrollmode==0 || drag_scrollmode==1) { drag_scrollmode = 1; px = ((ypos - drag_hitypos)*numlines) / (scrollwin_h-2*BAREXTRA); scroll_to(drag_origline+px); } } else { xpos -= textwin_x; ypos -= textwin_y; switch (button) { case Button1: case Button3: pos = find_pos_by_loc(xpos, ypos); if (pos < drag_firstbeg) { if (!(clicknum & 1)) dotpos = back_to_white(pos); else dotpos = pos; dotlen = drag_firstend-dotpos; } else if (pos > drag_firstend) { dotpos = drag_firstbeg; if (!(clicknum & 1)) dotlen = fore_to_white(pos)-drag_firstbeg; else dotlen = pos-drag_firstbeg; } else { dotpos = drag_firstbeg; dotlen = drag_firstend-drag_firstbeg; } xtext_layout(); break; default: break; } } } #ifdef __STDC__ void xtext_hitup(int xpos, int ypos, unsigned int button, unsigned int mods, int clicknum) #else void xtext_hitup(xpos, ypos, button, mods, clicknum) int xpos; int ypos; unsigned int button; unsigned int mods; int clicknum; #endif { int px; if (drag_inscroll && (drag_scrollmode==0 || drag_scrollmode==3)) { switch (button) { /* scrollbar */ case Button1: px = (ypos - textwin_y) / lineheight; scroll_to(scrollline+px); break; case Button3: px = (ypos - textwin_y) / lineheight; scroll_to(scrollline-px); break; } } } /* editing functions... */ #ifdef __STDC__ void xted_init(int vbuflen, char *vbuffer, int *vreadpos, int *vkillflag, int firsttime) #else void xted_init(vbuflen, vbuffer, vreadpos, vkillflag, firsttime) int vbuflen; char *vbuffer; int *vreadpos; int *vkillflag; int firsttime; #endif { killflag = vkillflag; *killflag = (-1); buflen = vbuflen; buffer = vbuffer; readpos = vreadpos; if (*readpos) { if (firsttime) { /* Z-machine has already entered the text into the buffer. */ inputfence = numchars - (*readpos); originalattr = stylelist[numstyles-1].attr; xtext_setstyle(inputfence, prefs.inputattr); } else { /* The terp has to enter the text. */ inputfence = numchars; originalattr = stylelist[numstyles-1].attr; xtext_setstyle(-1, prefs.inputattr); xtext_replace(dotpos, 0, buffer, *readpos); xtext_layout(); } } else { inputfence = numchars; originalattr = stylelist[numstyles-1].attr; xtext_setstyle(-1, prefs.inputattr); } historypos = historynum; } #ifdef __STDC__ void xted_insert(int ch) #else void xted_insert(ch) int ch; #endif { if (iscntrl(ch)) ch = ' '; if (dotpos < inputfence) { dotpos = numchars; dotlen = 0; } else { collapse_dot(); } xtext_add(ch, dotpos); xtext_layout(); xtext_end_visible(); } #ifdef __STDC__ void xted_delete(int op) #else void xted_delete(op) int op; #endif { long pos; if (dotpos < inputfence) return; collapse_dot(); switch (op) { case op_BackChar: if (dotpos <= inputfence) return; xtext_replace(dotpos-1, 1, "", 0); break; case op_ForeChar: if (dotpos < inputfence || dotpos >= numchars) return; xtext_replace(dotpos, 1, "", 0); break; case op_BackWord: pos = back_to_nonwhite(dotpos); pos = back_to_white(pos); if (pos < inputfence) pos = inputfence; if (pos >= dotpos) return; xtext_replace(pos, dotpos-pos, "", 0); break; case op_ForeWord: pos = fore_to_nonwhite(dotpos); pos = fore_to_white(pos); if (pos < inputfence) pos = inputfence; if (pos <= dotpos) return; xtext_replace(dotpos, pos-dotpos, "", 0); break; } xtext_layout(); } #ifdef __STDC__ void xted_enter(int op) #else void xted_enter(op) int op; #endif { int len; if (op != op_Enter) return; if (killflag) *killflag = '\n'; xtext_setstyle(-1, originalattr); len = numchars-inputfence; if (len > buflen) len = buflen; memmove(buffer, charbuf+inputfence, len*sizeof(char)); *readpos = len; if (len) { /* add to history */ if (historynum==prefs.historylength) { free(history[0].str); memmove(&history[0], &history[1], (prefs.historylength-1) * (sizeof(histunit))); } else historynum++; history[historynum-1].str = malloc(len*sizeof(char)); memmove(history[historynum-1].str, charbuf+inputfence, len*sizeof(char)); history[historynum-1].len = len; } xtext_add('\n', -1); dotpos = numchars; dotlen = 0; xtext_layout(); /* a somewhat strange place to put the buffer trimmer, but what the heck. The status line shrinker too. */ xstat_reset_window_size(op_Shrink); if (numchars > prefs.buffersize + prefs.bufferslack) { long lx; for (lx=0; lx (numchars-prefs.buffersize)) break; if (lx) { xtext_delete_start(lx); } } } #ifdef __STDC__ void xtext_line_timeout() #else void xtext_line_timeout() #endif { int len; /* same as xted_enter(), but skip the unnecessary stuff. We don't need to add to history, collapse the dot, xtext_layout, trim the buffer, or shrink the status window. */ len = numchars-inputfence; if (len > buflen) len = buflen; memmove(buffer, charbuf+inputfence, len*sizeof(char)); *readpos = len; if (len) { xtext_replace(inputfence, len, "", 0); dotpos = numchars; dotlen = 0; xtext_layout(); } xtext_setstyle(-1, originalattr); } #ifdef __STDC__ void xted_scroll(int op) #else void xted_scroll(op) int op; #endif { switch (op) { case op_UpLine: scroll_to(scrollline-1); break; case op_DownLine: scroll_to(scrollline+1); break; case op_UpPage: scroll_to(scrollline-(linesperpage-1)); break; case op_DownPage: scroll_to(scrollline+(linesperpage-1)); break; case op_ToTop: scroll_to(0); break; case op_ToBottom: scroll_to(numlines); break; } } #ifdef __STDC__ void xted_movecursor(int op) #else void xted_movecursor(op) int op; #endif { long pos; switch (op) { case op_BackChar: collapse_dot(); if (dotpos > 0) dotpos--; break; case op_ForeChar: collapse_dot(); if (dotpos < numchars) dotpos++; break; case op_BackWord: collapse_dot(); dotpos = back_to_nonwhite(dotpos); dotpos = back_to_white(dotpos); break; case op_ForeWord: collapse_dot(); dotpos = fore_to_nonwhite(dotpos); dotpos = fore_to_white(dotpos); break; case op_BeginLine: if (dotlen) { dotlen = 0; } else { if (dotpos >= inputfence) dotpos = inputfence; else { pos = dotpos; while (pos > 0 && charbuf[pos-1] != '\n') pos--; dotpos = pos; } } break; case op_EndLine: if (dotlen) { collapse_dot(); } else { if (dotpos >= inputfence) dotpos = numchars; else { pos = dotpos; while (pos < numchars && charbuf[pos] != '\n') pos++; dotpos = pos; } } break; } xtext_layout(); } #ifdef __STDC__ void xted_cutbuf(int op) #else void xted_cutbuf(op) int op; #endif { char *cx; int num; long tmppos; switch (op) { case op_Copy: if (dotlen) { XRotateBuffers(xiodpy, 1); XStoreBytes(xiodpy, charbuf+dotpos, sizeof(char)*dotlen); } break; case op_Wipe: if (dotlen) { XRotateBuffers(xiodpy, 1); XStoreBytes(xiodpy, charbuf+dotpos, sizeof(char)*dotlen); if (dotpos >= inputfence) { xtext_replace(dotpos, dotlen, "", 0); xtext_layout(); } } break; case op_Yank: collapse_dot(); if (dotpos < inputfence) dotpos = numchars; cx = XFetchBytes(xiodpy, &num); strip_garbage(cx, num); if (cx && num) { tmppos = dotpos; xtext_replace(tmppos, 0, cx, num); dotpos = tmppos; dotlen = num; free(cx); } xtext_layout(); break; case op_Untype: if (numchars == inputfence) break; dotpos = inputfence; dotlen = numchars-inputfence; XRotateBuffers(xiodpy, 1); XStoreBytes(xiodpy, charbuf+dotpos, sizeof(char)*dotlen); xtext_replace(dotpos, dotlen, "", 0); xtext_layout(); break; case op_Kill: if (dotpos < inputfence) { /* maybe extend to end-of-line and copy? */ break; } dotlen = numchars-dotpos; XRotateBuffers(xiodpy, 1); XStoreBytes(xiodpy, charbuf+dotpos, sizeof(char)*dotlen); xtext_replace(dotpos, dotlen, "", 0); xtext_layout(); break; } } #ifdef __STDC__ void xted_history(int op) #else void xted_history(op) int op; #endif { long pos, len; switch (op) { case op_BackLine: if (historypos > 0) { if (dotpos < inputfence) { dotpos = numchars; dotlen = 0; } historypos--; pos = dotpos; xtext_replace(pos, dotlen, history[historypos].str, history[historypos].len); dotpos = pos; dotlen = history[historypos].len; xtext_layout(); } break; case op_ForeLine: if (historypos < historynum) { if (dotpos < inputfence) { dotpos = numchars; dotlen = 0; } historypos++; if (historypos < historynum) { pos = dotpos; xtext_replace(dotpos, dotlen, history[historypos].str, history[historypos].len); dotpos = pos; dotlen = history[historypos].len; } else { pos = dotpos; xtext_replace(dotpos, dotlen, "", 0); dotpos = pos; dotlen = 0; } xtext_layout(); } } } #ifdef __STDC__ void xted_define_macro(int keynum) #else void xted_define_macro(keynum) int keynum; #endif { static cmdentry *macrocommand = NULL; char buf[256]; char *cx, *cx2; if (!macrocommand) { macrocommand = xkey_find_cmd_by_name("macro"); if (!macrocommand) { xmess_set_message("Error: unable to find macro command entry.", FALSE); return; } } if (keycmds[keynum] != macrocommand) { cx = xkey_get_key_name(keynum); sprintf(buf, "Key <%s> is not bound to the macro command.", cx); xmess_set_message(buf, FALSE); return; } if (dotlen == 0) { xmess_set_message("You must highlight a string to define this macro to.", FALSE); return; } cx2 = (char *)malloc(sizeof(char) * (dotlen+1)); memcpy(cx2, charbuf+dotpos, dotlen * sizeof(char)); cx2[dotlen] = '\0'; strip_garbage(cx2, dotlen); if (keycmdargs[keynum]) free(keycmdargs[keynum]); keycmdargs[keynum] = cx2; cx = xkey_get_key_name(keynum); if (!cx2 || !cx2[0]) sprintf(buf, "Macro <%s> is not defined.", cx); else if (strlen(cx2) > (sizeof(buf)-64)) sprintf(buf, "Macro <%s> is defined to something too long to display.", cx); else sprintf(buf, "Macro <%s> defined to \"%s\".", cx, cx2); xmess_set_message(buf, FALSE); } #ifdef __STDC__ void xted_macro(int op) #else void xted_macro(op) int op; #endif { char *str, *cx; str = keycmdargs[op]; if (!str || !str[0]) { char buf[128]; cx = xkey_get_key_name(op); sprintf(buf, "Macro <%s> is not defined.", cx); xmess_set_message(buf, FALSE); return; } if (dotpos < inputfence) { dotpos = numchars; dotlen = 0; } else { collapse_dot(); } xtext_replace(dotpos, 0, str, strlen(str)); xtext_layout(); xtext_end_visible(); } #ifdef __STDC__ void xted_noop(int op) #else void xted_noop(op) int op; #endif { /* good for debugging */ }