/* ELLE - Copyright 1982, 1987 by Ken Harrenstien, SRI International * This software is quasi-public; it may be used freely with * like software, but may NOT be sold or made part of licensed * products without permission of the author. */ /* EEFD Display control functions */ #include "elle.h" #if FX_NEWWIN /* EFUN: "New Window" */ /* Clear current window and set as requested. * ^L - clear current window and redisplay it (default top) * ^L - select new window so that current line is * the 'th from top of window (0 = top line) * ^U^L - clear current line and redisplay. */ f_newwin() { register int i, n; register struct window *w; d_fixcur(); /* Ensure screen vars correct */ w = cur_win; if (exp_p) { if((n = exp) == 4 && exp_p == 4 /* CTRL-U? */ && (i = d_line(cur_dot)) >= 0) /* On valid line? */ { d_lupd(w, i); /* Update it */ return; } } else /* No argument given */ { redp(RD_SCREEN); /* Clear whole screen (later just window? */ #if IMAGEN return; #else n = (ev_nwpct*w->w_ht)/100; /* Set new window using % */ #endif /*-IMAGEN*/ } if (n < 0) n = 0; /* Ensure # is reasonable */ else if (n >= w->w_ht) n = w->w_ht - 1; d_fgoloff(-n); /* Go up given # of lines */ w->w_topldot = e_dot(); /* Set new top-line dot */ e_gocur(); /* Move back to cur_dot */ redp(RD_FIXWIN); /* Say to re-hack window */ } #endif /*FX_NEWWIN*/ #if FX_NSCREEN /* EFUN: "Next Screen" */ f_nscreen() { d_screen( exp); } #endif /*FX_NSCREEN*/ #if FX_PSCREEN /* EFUN: "Previous Screen" */ f_pscreen() { d_screen(-exp); } #endif /*FX_PSCREEN*/ #if FX_OTHNSCREEN /* EFUN: "Other New Screen" (not EMACS) - from IMAGEN config */ f_othnscreen() { if (! oth_win) return; f_othwind(); if (exp_p) /* With arg, back up */ d_screen(-1); else d_screen(1); f_othwind(); redp(RD_WINDS); /* Look at all windows */ } #endif /*FX_OTHNSCREEN*/ #if FX_LWINDBORD /* EFUN: "Line to Window Border" (not EMACS) - from IMAGEN config */ f_lwindbord() { if (exp_p) /* With arg, means "to bottom" */ exp = cur_win->w_ht - 1; else /* Else, to top */ exp = 0; /* Just a "front end" for ^L */ exp_p = 1; f_newwin(); } #endif /*FX_LWINDBORD*/ #if FX_SCUPWIND /* EFUN: "Scroll Window Up" (not EMACS) - from IMAGEN config */ f_scupwind() { scroll_win(exp); } #endif /*FX_SCUPWIND*/ #if FX_SCDNWIND /* EFUN: "Scroll Window Down" (not EMACS) - from IMAGEN config */ f_scdnwind() { scroll_win(-exp); } #endif /*FX_SCDNWIND*/ #if FX_MVWTOP /* EFUN: "Move to Window Top" (not EMACS) - from IMAGEN config */ f_mvwtop() { extern moveborder(); moveborder(1); } #endif /*FX_MVWTOP*/ #if FX_MVWBOT /* EFUN: "Move to Window Bottom" (not EMACS) - from IMAGEN config */ f_mvwbot() { extern moveborder(); moveborder(0); } #endif /*FX_MVWBOT*/ #if FX_NSCREEN || FX_PSCREEN || FX_OTHNSCREEN /* Move to new loc by N screenfuls. * If moving downward, keep bottom 2 lines of current screen on top of next. * If moving up, keep top 2 lines of current screen on bottom of next. */ d_screen(rep) int rep; { register int i; register struct window *w; chroff newdot; w = cur_win; if((i = w->w_ht - 2) <= 0) /* Just-in-case check */ i = 1; if((i *= rep) == 0) return; d_fixcur(); /* Ensure window fixed up */ e_go(w->w_topldot); /* Start at top of screen */ d_fgoloff(i); /* Find where we are now, and make that the new top of window. */ if((newdot = e_dot()) != e_blen()) /* If not at EOF, */ w->w_topldot = newdot; /* set new top of window! */ else w->w_topldot = 0; /* Else let fix_wind select top. */ e_setcur(); /* Ensure cur_dot set to real loc */ #if IMAGEN redp(RD_WINRES|RD_REDO); /* HINT: just repaint screen */ #else redp(RD_FIXWIN|RD_MOVE); #endif /*-IMAGEN*/ } #endif /*FX_NSCREEN || FX_PSCREEN || FX_OTHNSCREEN*/ #if FX_SCUPWIND || FX_SCDNWIND /* If want scroll-window function */ scroll_win(n) register int n; { register struct window *w = cur_win; chroff savdot; if (n == 0) return; d_fixcur(); /* Ensure screen vars for win all set up */ e_go(w->w_topldot); /* Go to top of current window */ d_fgoloff(n); /* Move given # of display lines */ w->w_topldot = e_dot(); /* Set new top of window */ redp(RD_FIXWIN); /* Say new window needs fixing up */ /* Now adjust position of current dot so it is still within window */ if (n > 0) { /* Moving screen text "up" (win down) */ if (cur_dot < w->w_topldot) /* See if scrolled off top */ e_setcur(); /* yes, make dot be win top */ } else { /* Moving screen text "down" (win up) */ savdot = cur_dot; /* Save since must temporarily */ e_setcur(); /* set current dot within window, */ d_fixcur(); /* so screen can be fixed up. */ if (inwinp(w, savdot)) /* Now see if old dot in new win */ cur_dot = savdot; /* Yes, just restore it! */ else /* No, make it beg of bottom line. */ cur_dot = scr[w->w_pos + w->w_ht - 1]->sl_boff; } e_gocur(); /* Make current pos be cur_dot */ } #endif /* FX_SC%%WIND */ #if FX_MVWTOP || FX_MVWBOT /* Guts for above two functions */ static moveborder(top) int top; { d_fixcur(); /* Ensure current win screen image fixed up */ e_gosetcur(top ? cur_win->w_topldot : scr[cur_win->w_pos + cur_win->w_ht - 1]->sl_boff); redp(RD_MOVE); /* Should only be cursor adjustment */ } #endif /*FX_MVW%%%*/ /* Given a line and a position in that line, return the xpos. * NOTE CAREFULLY that when line extends over several screen lines, * the value returned is the screen X position even though it * may be some lines down from the start of the logical line! * Also note this won't work very well if tabs exist on the extra * lines. This rtn should not be used for cursor positioning. * Also note: d_ncols() will never return -1 meaning EOL because the * setup guarantees there is no EOL within the range checked. */ d_curind() /* Find current indentation */ { indtion(e_dot()); } indtion(lin) chroff lin; { register int i, col; chroff savdot; chroff nchars; savdot = e_dot(); /* Save current position */ e_go(lin); /* Go to line caller wants */ e_gobol(); /* Go to its beginning */ col = 0; /* Start at left margin */ if((nchars = lin - e_dot()) > 0) do { if(nchars < (i = scr_wd0)) i = nchars; if((col = d_ncols(i, col)) < 0) /* Hit edge of screen? */ col = 0; /* Reset to left margin */ } while((nchars -= i) > 0); e_go(savdot); /* Restore current position */ return(col); } /* ININDEX - How many positions in lin must we go to get to xpos? * Returns -1 if can't be done. Assumes "lin" is at beginning of a line! */ inindex (lin, xpos) chroff lin; int xpos; { register int col, x; chroff savdot; char tmp[MAXLINE+MAXCHAR]; extern int sctreol; /* From EEDISP */ if((x = xpos) <= 0) return(0); if(x >= MAXLINE) return(-1); /* ?!? */ col = 0; savdot = e_dot(); e_go(lin); /* Assumes this is start of line */ col = sctrin(tmp, x, 0); /* Translate from sb_getc input */ if((col - x) >= 0) /* Exact count-out or past it? */ { x = e_dot() - lin; /* Yup, win. */ if (sctreol > 0) /* Did we hit (and include) EOL? */ #if FX_EOLMODE /* If so, back up over the EOL. */ x -= eolcrlf(cur_buf) ? 2 : 1; #else --x; #endif } else x = -1; /* Nope, EOL or EOF hit too soon. */ e_go(savdot); return(x); } /* * D_ ROUTINES - display-relative functions. Similar to E_, but * a "line" is defined as one line of the screen rather than * as a logical text line. Also, for efficiency reasons * arguments are given saying how many lines to hack. */ d_gopl() { return(d_goloff(-1)); } d_gonl() { return(d_goloff( 1)); } /* D_GOLOFF(i) - Go to beginning of a display line * D_FGOLOFF(i) - ditto, but assumes screen image of window already fixed up. * i - # of lines offset. Negative moves up, positive down. * Zero arg goes to beginning of current display line. * Side effects: screen image of window is fixed up at * start of routine, but is NOT updated by the move to new location. */ d_goloff(cnt) int cnt; { d_fixcur(); d_fgoloff(cnt); /* Now can invoke fixed-up fast version */ } d_fgoloff(cnt) register int cnt; { register int y; struct scr_line l; char line[MAXLINE+MAXCHAR]; int top, bot; /* Find current position in window, since can save time * by using stuff already in fixed-up screen image. */ if((y = d_line(e_dot())) < 0) /* Get current Y position */ { errbarf("Dot out of window"); y = 0; } top = cur_win->w_pos; /* 1st line of window */ bot = top + cur_win->w_ht; /* 1st line not in window */ l.sl_boff = scr[y]->sl_boff; l.sl_nlin = &line[0]; l.sl_cont = 0; if(cnt > 0) goto down; /* Go upwards. This is hairy because we want to be clever about * huge logical lines -- avoid going all the way back to BOL. */ if((y+cnt) >= top) /* Fits? */ goto onscr; /* Hurray, hack it! */ cnt += y - top; /* Sigh, find # lines to skip */ y = top; l.sl_boff = scr[y]->sl_boff; e_go(l.sl_boff); /* Okay, here's the hairy part. Must go backwards from top * line; if no EOL within scr_wid*cnt chars, then simply assume one is * seen. */ cnt = -cnt; d_backup(cnt); return; /* Really should re-adjust stuff, but... */ /* Go downwards. Not too bad... */ down: if((y+cnt) <= bot) /* Fits? */ goto onscr; /* Hurray, hack it! */ cnt -= bot - y; /* Sigh, find # lines can skip */ y = bot - 1; l.sl_boff = scr[y]->sl_boff + scr[y]->sl_len; if(y > top && (l.sl_cont = scr[y-1]->sl_cont)) l.sl_line = scr[y-1]->sl_line; e_go(l.sl_boff); do { fix_line(&l,&l); } while(--cnt > 0 && l.sl_len); return; onscr: if((y += cnt) >= bot) { --y; e_go(scr[y]->sl_boff + scr[y]->sl_len); } else e_go(scr[y]->sl_boff); } /* D_FIXCUR() - Ensure current window is fixed up, with * current location (not necessarily cur_dot)! * Ensure cur_dot reflects real loc so that fix_wind will work, * and always call fix_wind to ensure that screen image vars * are set properly. Note any active redisplay flags must be carried * on into window redisplay flags, so fix_wind will notice them. */ d_fixcur() { register struct window *w; chroff savedot; w = cur_win; savedot = cur_dot; e_setcur(); w->w_redp |= rd_type&RDS_WINFLGS; fix_wind(w); /* Always ensure window is set up! */ redp(w->w_redp); /* Add back new flags */ rd_type &= ~RDS_DOFIX; /* and flush fix-invoking ones */ cur_dot = savedot; /* Restore cur_dot, no longer hacked. */ } d_backup(nlin) /* Try to back up by nlin screen lines */ int nlin; { register int cnt, n, c; int eolstop; if((cnt = nlin+1) <= 0) return; c = 0; do { n = scr_wid; eolstop = 0; /* Not yet stopped at EOL */ do { if((c = e_rgetc()) == EOF) return; if(c == LF) { #if FX_EOLMODE if(eolcrlf(cur_buf)) { if((c = e_rgetc()) == CR) { eolstop++; break; } if(c != EOF) e_getc(); } else #endif { eolstop++; break; } } } while(--n); } while(--cnt); if(eolstop) { #if FX_EOLMODE if(eolcrlf(cur_buf)) e_getc(); /* Skip back over CR */ #endif e_getc(); /* Skip back over LF */ } /* At this point, dot is guaranteed to be less than goal, * which is the important thing for fix_wind, which can handle * things okay if dot is off bottom of window. */ return(1); /* Say always test result */ }