home *** CD-ROM | disk | FTP | other *** search
/ Usenet 1994 January / usenetsourcesnewsgroupsinfomagicjanuary1994.iso / sources / unix / volume7 / rvi / part3 / rv_move.c < prev    next >
Encoding:
C/C++ Source or Header  |  1989-04-09  |  6.0 KB  |  281 lines

  1. #include "rv.h"
  2. #include <ctype.h>
  3.  
  4. /*
  5.  * rv_move.c  - Cursor motion routines
  6.  */
  7.  
  8. void
  9. move_abs_cursor(lineno, column)
  10. /*
  11.  * Move cursor to absolute position in file.  Try to stay within the window
  12.  * if possible.
  13.  */
  14. INT lineno, column;
  15. {
  16.     register INT    seg;
  17.     register struct li_line    *line, *newline;
  18.     register struct sc_screen      *sc;
  19.     register struct wi_window      *wi;
  20.     INT     oldlineno, offset;
  21.     struct   fi_file           *fi;
  22.     void     rv_scroll(), rv_scroll_backward();
  23.  
  24.     sc = &screen;
  25.     wi = &window;
  26.     fi = &file;
  27.     errflag = 0;
  28.     /*
  29.      * Boundary checks
  30.      */
  31.     if (lineno < 1) { /* If past top of file */
  32.         errflag = 1;
  33.         flash();
  34.         return;
  35.     } else if (lineno > fi->fi_numlines) { /* If past bottom of file */
  36.         errflag = 1;
  37.         flash();
  38.         return;
  39.     }
  40.  
  41.     if (lineno < sc->sc_lineno - (sc->sc_curline-sc->sc_topline)) {
  42.         /*
  43.          * Past top of screen
  44.          */
  45.         oldlineno = sc->sc_lineno;
  46.         if (lineno < sc->sc_lineno - (sc->sc_curline-wi->wi_topline)) {
  47.             /*
  48.              * Past top of window, fetch more data
  49.              */
  50.             fetch_window(lineno-NUM_WINDOW_LINES/4-LINES/2+1,
  51.                                     FALSE);
  52.             if (errflag)
  53.                 return;
  54.         }
  55.         newline = sc->sc_curline - (sc->sc_lineno - lineno);
  56.         seg = 0;
  57.         if (oldlineno == sc->sc_lineno) { /* If relatively close */
  58.             /*
  59.              * Find distance, in segments, above top of screen
  60.              */
  61.             for (line = newline; line < sc->sc_topline; ++line)
  62.                 seg += line->li_segments;
  63.             if (seg <= LINES/3+1) { /* If very close */
  64.                 /*
  65.                  * Scroll backwards
  66.                  */
  67.                 rv_scroll_backward(sc->sc_topline - newline);
  68.                 move_cursor(lineno, column);
  69.                 return;
  70.             }
  71.         }
  72.  
  73.         /*
  74.          * Newline is too far away for scrolling,
  75.          * so we redraw the screen and deposit newline
  76.          * in the center.
  77.          */
  78.  
  79.         /*
  80.          * Set the top of the screen at LINES/2 segments above newline
  81.          */
  82.         xmit_curline();
  83.         seg = LINES/2;
  84.         for (line = newline; line >= wi->wi_topline && seg > 0; --line)
  85.             seg -= line->li_segments;
  86.         sc->sc_topline = line+1;
  87.         sc->sc_curline = newline;
  88.         sc->sc_lineno = lineno;
  89.         sc->sc_abovetop = 0;
  90.         /*
  91.          * Compute bottom line
  92.          */
  93.         line = sc->sc_topline;
  94.         for (seg = line->li_segments; seg < LINES;
  95.                 seg += line->li_segments) {
  96.             ++line;
  97.             if (line > wi->wi_botline)
  98.                 break;
  99.         }
  100.         sc->sc_botline = line-1;
  101.  
  102.         /*
  103.          * Update the screen to curses
  104.          */
  105.         move_cursor(lineno, column);
  106.         redraw_screen((struct li_line *)0);
  107.         return;
  108.     } /* End of past top of screen */
  109.         
  110.  
  111.     if (lineno > sc->sc_lineno + (sc->sc_botline - sc->sc_curline)) {
  112.         /*
  113.          * Past bottom of screen
  114.          */
  115.         oldlineno = sc->sc_lineno;
  116.         offset = sc->sc_botline - sc->sc_curline;
  117.         if (lineno > sc->sc_lineno + (wi->wi_botline-sc->sc_curline)) {
  118.             /*
  119.              * Past bottom of window
  120.              */
  121.             fetch_window(lineno-NUM_WINDOW_LINES/4-LINES/2+1,
  122.                                     TRUE);
  123.             if (errflag)
  124.                 return;
  125.         }
  126.         newline = sc->sc_curline + (lineno - sc->sc_lineno);
  127.         seg = 0;
  128.         if (oldlineno == sc->sc_lineno) { /* If relatively close */
  129.             /*
  130.              * Find distance in segments past bottom of screen
  131.              */
  132.             for (line = sc->sc_curline+offset+1; line <= newline;
  133.                                     ++line)
  134.                 seg += line->li_segments;
  135.             if (seg <= LINES/3+1 && newline >= sc->sc_botline) {
  136.                 /*
  137.                  * Scroll screen forwards
  138.                  */
  139.                 rv_scroll(newline - sc->sc_botline);
  140.                 move_cursor(lineno, column);
  141.                 return;
  142.             }
  143.         }
  144.  
  145.         /*
  146.          * Newline is too far away for scrolling,
  147.          * so we redraw the screen and deposit newline
  148.          * in the center.
  149.          */
  150.  
  151.         /*
  152.          * Set the top of the screen at LINES/2 segments above newline
  153.          */
  154.         xmit_curline();
  155.         seg = LINES/2;
  156.         for (line = newline; line >= wi->wi_topline && seg > 0; --line)
  157.             seg -= line->li_segments;
  158.         sc->sc_abovetop = 0;
  159.         sc->sc_topline = line+1;
  160.         sc->sc_curline = newline;
  161.         sc->sc_lineno = lineno;
  162.         /*
  163.          * Compute bottom line
  164.          */
  165.         line = sc->sc_topline;
  166.         for (seg = line->li_segments; seg < LINES;
  167.                 seg += line->li_segments) {
  168.             ++line;
  169.             if (line > wi->wi_botline)
  170.                 break;
  171.         }
  172.         sc->sc_botline = line-1;
  173.  
  174.         /*
  175.          * Update the screen to curses
  176.          */
  177.         move_cursor(lineno, column);
  178.         redraw_screen((struct li_line *)0);
  179.         return;
  180.     } /* End of past bottom of screen */
  181.         
  182.     /*
  183.      * Otherwise, newline must already be on the screen
  184.      */
  185.  
  186.     move_cursor(lineno, column);
  187.     return;
  188. }
  189.  
  190.  
  191.  
  192. void
  193. move_cursor(lineno, column)
  194. /*
  195.  * Move cursor to position in file.  Must already be on screen.
  196.  */
  197. INT lineno, column;
  198. {
  199.     register INT    seg;
  200.     register struct sc_screen    *sc;
  201.     register struct    li_line        *line, *newline;
  202.     INT      linewidth;
  203.     static     INT    prev_column;
  204.  
  205.     errflag = 0;
  206.     sc = &screen;
  207.     newline = sc->sc_curline + (lineno - sc->sc_lineno);
  208.     /*
  209.      * Boundary checks
  210.      */
  211.     if (newline < sc->sc_topline || newline > sc->sc_botline) {
  212.         errflag = 1;
  213.         botprint(TRUE,"move_cursor, lineno %d beyond screen\n", lineno);
  214.         return;
  215.     }
  216.  
  217.     if (column == COL_SAME)
  218.         column = file_column(newline->li_text, prev_column);
  219.     else {
  220.         prev_column = -1;
  221.         if (column == COL_FIRST_NONWHITE) {
  222.             register char *s;
  223.  
  224.             s = newline->li_text;
  225.             while (*s != '\0' && isspace(*s))
  226.                 ++s;
  227.             column = s - newline->li_text;
  228.         }
  229.     }
  230.  
  231.                 
  232.     if (column < 0) { /* If past left side of screen */
  233.         if (sc->sc_column == 0) { /* Already at left side? */
  234.             errflag = 1;
  235.             flash();
  236.             return;
  237.         }
  238.         column = 0;
  239.     }
  240.  
  241.     if (lineno != sc->sc_lineno && sc->sc_origline.li_text != NULL)
  242.         xmit_curline();
  243.  
  244.     /*
  245.      * Compute screen column and segment #
  246.      */
  247.     sc->sc_curline = newline;
  248.     sc->sc_lineno = lineno;
  249.     /*
  250.      * Limit column to end of line (or line+1 if input mode)
  251.      */
  252.     linewidth = newline->li_width + (input_mode ? 1 : 0);
  253.     if (column >= linewidth && column > 0) {
  254.         column = (linewidth == 0 ? 0 : linewidth-1);
  255.         if (sc->sc_column >= column) /* If already at edge */
  256.             flash();
  257.     }
  258.  
  259.     sc->sc_column = column;
  260.     column = screen_column(newline->li_text, column);
  261.     if (prev_column < 0)
  262.         prev_column = column;
  263.     if (input_mode && sc->sc_column == linewidth-1 && sc->sc_column != 0)
  264.         ++column;
  265.  
  266.     seg = 0;
  267.     for (line=sc->sc_topline; line < newline; ++line)
  268.         seg += line->li_segments;
  269.     seg += column / COLS + sc->sc_abovetop;
  270.     column %= COLS;
  271.     if (seg >= LINES) {
  272.         errflag = 1;
  273.         botprint(TRUE, "move_cursor, seg %d beyond screen\n", seg);
  274.         return;
  275.     }
  276.     /*
  277.      * Update cursor to curses
  278.      */
  279.     move(seg, column);
  280. }
  281.