home *** CD-ROM | disk | FTP | other *** search
/ The C Users' Group Library 1994 August / wc-cdrom-cusersgrouplibrary-1994-08.iso / vol_300 / 331_01 / paint.c < prev    next >
Text File  |  1990-06-12  |  16KB  |  685 lines

  1. /*
  2. HEADER:         CUG999.03;
  3. TITLE:          GED (nee QED) screen editor -- part 3;
  4. DATE:           5/15/87;
  5.  
  6. DESCRIPTION:   "Screen output functions.
  7.  
  8. KEYWORDS:       screen, output;
  9. SYSTEM:         MS-DOS;
  10. FILENAME:       paint.c;
  11. AUTHORS:        G. Nigel Gilbert, James W. Haefner, Mel Tearle, G. Osborn.
  12. COMPILERS:      Microsoft 4.0
  13. */
  14.  
  15. /*
  16.      e/qed/ged/se screen editor
  17.  
  18.     (C) G. Nigel Gilbert, MICROLOGY, 1981
  19.            August-December 1981
  20.  
  21.     Modified:  Aug-Dec   1984:   BDS-C 'e'(vers 4.6a) to 'qe' (J.W. Haefner)
  22.                March     1985:   BDS-C 'qe' to DeSmet-C 'qed' (J.W. Haefner)
  23.                May       1986:   converted to ged - Mel Tearle
  24.  
  25.     FILE:      paint.c
  26.  
  27.     FUNCTIONS: putline, rewrite, putoffset, putstatusline, putlineno,
  28.                putpage, putmess, unmess, putstr, calcoffset,
  29.                resetcursor, setstatusname, error, error1, cerr, wait
  30.  
  31.     PURPOSE:   write text to screen
  32. */
  33.  
  34.  
  35. #include <stdio.h>
  36. #include "ged.h"
  37.  
  38.  
  39. /* writes a line to the screen.   Uses the text address pointer in the third
  40.  * argument instead of getline if the third argument is not NULL.
  41.  *
  42.  * On most systems the physical cursor will end at the end of the new
  43.  * line.  It is not restored here because groups of lines are usually
  44.  * written and it is more efficiet to repositon the cursor after the
  45.  * group.
  46.  */
  47. putline(line,y,adr)
  48. int  line, y;
  49. char *adr;
  50. {
  51.     unsigned char  vbuf[SWIDTH+1];
  52.     char *getline();
  53.     int   bright, lastcol, off, i, j, x, sav;
  54.  
  55.     unsigned char  *p, c;
  56.     int   cp, low, high;
  57.  
  58.     sav = curson(NO);
  59.     vbuf[0] = '\0';
  60.  
  61.  
  62. /* if block option and line in range  then reverse field */
  63.     if ( blocking ) {
  64.  
  65.         if (vbord2 == 0)
  66.             j = cline;
  67.         else
  68.             j = vbord2;
  69.  
  70.         if (vbord1 < j)
  71.             i = vbord1;
  72.         else {
  73.             i = j;
  74.             j = vbord1;
  75.         }
  76.         bright = (line >= i)  &&  (line <= j);
  77.     }
  78.     else {
  79.         bright = NO;
  80.     }
  81.  
  82.     if (adr == NULL) {
  83.         if (altered && line == cline)
  84.             cerr(32);  /* displayed data is obsolete */
  85.         p = getline(line);
  86.     }
  87.     else
  88.         p = adr;
  89.  
  90.     if (offset > 0) {
  91.         lastcol = SWIDTH + offset;
  92.         off = offset;
  93.         if ( bright )  /* the markers are the opposite of the main color */
  94.             colornorm();
  95.         else
  96.             colorblock();
  97.         scr_aputch( 0, y, '<', ATTR2 );
  98.         x = 1;
  99.     }
  100.     else {
  101.         lastcol = SWIDTH;
  102.         off = 0;
  103.         x = 0;
  104.     }
  105.  
  106.     if ( bright )
  107.         colorblock();
  108.     else
  109.         colornorm();
  110.  
  111.     i = 0;
  112.     for ( cp = 0; (*p)  &&  (cp < (lastcol)); p++, cp++ ) {
  113.         if ( (off == 0) || (cp > off) )  {
  114.             if ( *p >= 0 )      /* change limit to block control characters */
  115.                 vbuf[i++] = *p;
  116.             else {
  117.                 if ( *p == '\t' ) {
  118.                     do  {
  119.                         if ( (off == 0) || (cp > off)  &&  (cp < (lastcol+x)) )
  120.                             vbuf[i++] = ' ';
  121.                     }
  122.                     while ( (++cp % tabwidth) != 0 );
  123.                     cp--;
  124.                 }
  125.             }
  126.         }
  127.     }
  128.     vbuf[i] = '\0';
  129.     scr_putstr( x, y, vbuf, attr );
  130.  
  131.     if ( x + i < SWIDTH) {
  132.         scr_delete( x + i, y );
  133.     }
  134.     else {
  135. /*        if ( bright )
  136.             colornorm();
  137.         else
  138.             colorblock();
  139.   */
  140.         c = *p;
  141.         if (( c != '\0') && (cp == (lastcol))) {
  142.             if ( *(++p) )
  143.                 scr_aputch( SWIDTH, y, '>', ATTR2 );
  144.             else
  145.                 scr_aputch( SWIDTH, y, c, attr );
  146.         }
  147.         else {
  148.             scr_aputch( SWIDTH, y, ' ', attr );
  149.         }
  150.     }
  151.     colornorm();
  152.     curson(sav);
  153.     return;
  154. }
  155.  
  156.  
  157. /* rewrites current line from char 'cp', col 'x', onwards.  cp is the
  158.  * character index, >= 0.  x is the virtual x cursor location.
  159.  *
  160.  * This routine could be called instead of rewrite to show line editing
  161.  * if it is known that the new cursor will be on-screen.  The performance
  162.  * improvement in doing so is insignificant.
  163.  *
  164.  * putline and this routine should be modified to have a greater commonality
  165.  * than they do.
  166.  */
  167.  
  168. rewrite1(cp,x)
  169. int cp, x;
  170. {
  171.     unsigned char  vbuf[SWIDTH+1];
  172.     int   h, i, j, k, begmark, sav;
  173.     unsigned char  c;
  174.  
  175.     sav = curson(NO);
  176.     vbuf[0] = '\0';
  177.     h = i = j = k = 0;
  178.  
  179.     begmark = ( offset > 0 );
  180.     if (begmark == 0)
  181.         k = x;
  182.     else {
  183.         k = x - offset;
  184.         if (k < 1)
  185.             k = 1;
  186.         scr_putstr( 0, cursory, "<", ATTR2 );
  187.     }
  188.     while ( x < SWIDTH+offset  &&  ( c = text[cp] ) )  {
  189.         if ( c == '\t' )  {
  190.             for ( i = tabwidth-x%tabwidth; i>0 && x<SWIDTH+offset-begmark; x++, i--)
  191.                 if ( x >= offset )
  192.                     vbuf[j++] = ' ';
  193.         }
  194. /* change following limit to block control characters */
  195.         else if ( (offset == 0) || ((x > offset)  &&  (c >= 0) ))
  196.             vbuf[j++] = c;
  197.         cp++;
  198.         x++;
  199.     }
  200.     if (blocking)
  201.         colorblock();
  202.     else
  203.         colornorm();
  204.  
  205.     vbuf[j] = '\0';
  206.     scr_putstr( k, cursory, vbuf, attr );
  207.     i = k + strlen(vbuf);
  208.     if (i <= SWIDTH)
  209.         scr_delete( i, cursory );
  210.  
  211.     c = text[cp];
  212.     if ( (c > 0) && (x == SWIDTH+offset) ) {
  213.         if(text[cp+1] == '\0' )
  214.             scr_aputch( SWIDTH, cursory, c, attr );
  215.         else
  216.             scr_aputch( SWIDTH, cursory, '>' , ATTR2 );
  217.     }
  218.     curson(sav);
  219.     return;
  220. }
  221.  
  222.  
  223. putoffset()
  224. {
  225.     gotoxy( 0, 0 );  /*?*/
  226.     gotoxy( (offset>0), cursory );
  227. }
  228.  
  229.  
  230. putstatusline(line)
  231. int line;
  232. {
  233.     int sav;
  234.     char buf[50];
  235.  
  236.     sav = curson(NO);
  237.     putlineno( line );
  238.     strcpy(buf,justfile);
  239.     strcat(buf,"                             ");
  240.     buf[29]=0;   /* clear up to first time digit */
  241.     scr_aputs( FNPOS, 0, buf, ATTR3 );
  242.  
  243.     show_time(1);
  244.     curson(sav);
  245.     blankedmess = NO;
  246.     if (sav)
  247.         resetpcursor();
  248.     return;
  249. }
  250.  
  251.  
  252. /* uses scr_aputs to move the cursor else uspr won't work right.  call
  253.  * resetpcursor after this call
  254.  */
  255. putlineno(line)
  256. int line;
  257. {
  258.     int i, sav;
  259.  
  260.     if ( !displaypos )
  261.         return;
  262.     sav = curson(NO);
  263.     scr_aputs( 0, 0, "       Line ", ATTR3 );
  264.  
  265.     displine = line;
  266.     for ( i=5-uspr(displine, 0L, ATTR3); i > 0; i-- )
  267.         scr_putch( ' ',ATTR3);
  268.  
  269.     scr_aputs( COLPOS-1, 0, " Col ", ATTR3 );
  270.  
  271.     dispcol = cursorx+1;
  272.     for ( i=4-uspr(dispcol, 0L, ATTR3); i > 0; i-- )
  273.         scr_putch( ' ',ATTR3 );
  274.     if (charep) {
  275.         scr_aputs(25,0,"   ",ATTR3);
  276.         scr_aputs(28,0,"Over",ATTR2);
  277. /* adjust space count to just before filename field */
  278.         scr_aputs(32,0,"           ",ATTR3);
  279.     }
  280.     else
  281. /* adjust space count to just before filename field */
  282.         scr_aputs(25,0,"                  ",ATTR3);
  283.     curson(sav);
  284.     if (sav)
  285.        resetpcursor();
  286.     return;
  287. }
  288.  
  289.  
  290.  
  291.  
  292. /* exit help mode
  293.  */
  294. unmess()
  295. {
  296.     if (topline == 1)
  297.         return;
  298.     topline = 1;
  299.     calp();
  300.     putpage();
  301.     return;
  302. }
  303.  
  304. /* Write message to top line.  Uses all of line and clears the last
  305.  * part.
  306.  */
  307.  putmess(s)
  308.  char *s;
  309. {
  310.     int i;
  311.     i = putmess1(s,0,SWIDTH+1);
  312.     gotoxy(i+1,0);     /* position cursor for keyboard input */
  313.     return;
  314. }
  315.  
  316. /* write underlined message in status line.  Characters between || are
  317.  * written highlighted.  xloc is the x cursor position of the first char.
  318.  * width is the field width.  the trailing part if the field is cleared
  319.  * if the message does not fill it.
  320.  */
  321. putmess1( s, xloc, width )
  322. char *s;
  323. int xloc, width;
  324. {
  325.  
  326.     char c;
  327.     int  i, cnt, norm;
  328.  
  329.     cnt = 0;
  330.     gotoxy(abs(xloc), 0);
  331.     norm = 0;
  332.     color3();
  333.     while( (c = *s++) ) {
  334.         switch(c) {
  335.         case '|':
  336.             ( norm = ~norm ) ? color4() : color3();
  337.             break;
  338.         case '\n':
  339.             break;
  340.         default :
  341.             scr_putch( c, attr );
  342.             cnt += 1;
  343.         }
  344.     }
  345.     color3();
  346.  
  347.     i = cnt;
  348.     while (i++ < width)
  349.         scr_putch( ' ', attr);
  350.     colornorm();
  351.     blankedmess = YES;
  352.     return cnt;
  353. }
  354.  
  355. /* Writes prompting/status messages to screen.  Characters between || are
  356.  * written highlighted.
  357.  */
  358. int putstr(s)
  359. char *s;
  360. {
  361.     int  norm;
  362.     char c;
  363.  
  364.     norm = 0;
  365.     colornorm();
  366.     while( (c = *s++) ) {
  367.         switch(c) {
  368.         case '|':
  369.             ( norm = ~norm ) ? color1() : colornorm();
  370.             break;
  371.         case '\n':
  372.             putret();
  373.             break;
  374.         default :
  375.             scr_putch( c, attr );
  376.         }
  377.     }
  378.     colornorm();
  379.     return;
  380.  
  381. }
  382. /* insure that cursor is on screen with horizontal changes.  The argument is
  383.  * the new cursorx that must be visible.  The algorithm uses hysteresis so
  384.  * that horizontal scrolling only occurs when necessary.  If horizontal
  385.  * scrolling gets behind the keyboard then the algorithm will jump ahead
  386.  * twice as much as it finds itself behind.  The adaptive feature makes it
  387.  * practical to scroll in increments of 1 on most display devices.
  388.  */
  389. calcoffset(x)
  390. int x;
  391. {
  392.     int i, j;
  393.     i = offset;
  394.  
  395.     if (x <= offset) {
  396.         i = (x-1)/OFFWIDTH;
  397.         i = i*OFFWIDTH;
  398.         if (i<0)
  399.             i=0;
  400.     }
  401.     j = strlen(text) > (offset+SWIDTH+1);  /*  1 if right marker needed */
  402.  
  403.     if (x > offset + SWIDTH -j) {
  404.         i = x  - SWIDTH + j;
  405.         i = i + (OFFWIDTH - 1);
  406.         i = i - (i % OFFWIDTH);
  407.     }
  408.  
  409. /* scroll horizontally in larger chunks if the program gets behind the
  410.    keyboard
  411.  */
  412.     j = chkbuf();
  413.     if (j > 0)
  414.         while ( (j = chkbuf()) != chkbuf())  /* fill the char buffer */
  415.             ;
  416.     j = 2*j;  /* normally zero */
  417.     if(j>20)
  418.         j=20;
  419.     if (i<offset)
  420.         j=-j;
  421.     if(i != offset)
  422.         i=i+j;
  423.     offset=i;
  424.     if(offset<0)
  425.         offset=0;
  426.     return offset;
  427. }
  428.  
  429. /* Display page.  Called only when a complete rewrite is necessary.
  430.  * The help area and status line, as defined by topline, are unaffected,
  431.  * except that the line and column displays are updated.
  432.  */
  433. putpage()
  434. {
  435.     int  i, j, y, line, sav;
  436.     char c;
  437.     sav = curson(NO);
  438.  
  439. /* The line number has normally changed when putpage is called */
  440.     putlineno(cline);
  441.     rw1();  /* calculate and hold offset */
  442.     rw2();
  443.  
  444.     resetpcursor();
  445.     curson(sav);
  446.     return;
  447. }
  448.  
  449.  
  450. /* Page update.  Called after editing operations which affect screen
  451.  * data and/or horizontal cursor position, but not involving a change
  452.  * in cline.  The screen must already have been written,
  453.  * as only changes are written.  The text buffer must contain
  454.  * valid data.  Horizontal scrolling is performed as needed.
  455.  *
  456.  * Only the current line is scrolled horizontally if blockscroll is false.
  457.  * That option is useful for slow remote terminals.  Operations which move the
  458.  * cursor offscreen vertically will nevertheless result in a full
  459.  * horizontal scroll when the entire page is eventually rewritten if
  460.  * blockscroll is false.  The PC is fast enough that there is little
  461.  * advantage to partial line updates.
  462.  *
  463.  * cp is the text[cp] index of the first character to be written.
  464.  *
  465.  * Call sync() first
  466.  */
  467.  
  468. rewrite(cp)
  469. int cp;
  470. {
  471.     if ( rw1() ) {
  472.         if (blockscroll)
  473.             rw2();         /* all text lines */
  474.         else
  475.             putline(cline, cursory, text);  /* all of cline */
  476.     }
  477.     else {
  478.         rewrite1( cp, cursorx + (cp - charn) );  /* part of cline */
  479.     }
  480.     resetpcursor();  /* always onscreen at this point */
  481.     return;
  482. }
  483.  
  484. /* local function */
  485. rw2()
  486. {
  487.     int line, y;
  488.  
  489. /* cline is put out in sequence with the rest for a good visual effect */
  490.     for ( line = pfirst, y = topline; y <= SHEIGHT; line++, y++ ) {
  491.         if ( line == cline ) {
  492.             putline (line, y, text);
  493.             if (y != cursory)
  494.                 cerr(33);
  495.         }
  496.         else if (line <= plast) {
  497.             putline( line, y, NULL );
  498.         }
  499.         else {
  500.             cleareol(0,y);
  501.         }
  502.     }
  503.     return;
  504. }
  505.  
  506.  
  507. /* resetcursor() is used like rewrite, but is called when the screen change
  508.  * is only a horizontal cursor position change.  The change may be
  509.  * horizontally off-screen, in which case the entire screen is rewritten.
  510.  * Call sync() first.
  511.  *
  512.  * moveline() handles vertical off-screen cursor movements, which may
  513.  * also involve horizontal motion.
  514.  */
  515.  
  516. resetcursor()
  517. {
  518.  
  519.     if ( rw1() ) {
  520.         if (blockscroll)
  521.             rw2();         /* all text lines */
  522.         else
  523.             putline(cline, cursory, text);  /* all of cline */
  524.     }
  525.     resetpcursor();
  526.     return;
  527. }
  528.  
  529.  
  530. /* reset physical cursor is a less general form of resetcursor.  It is used to
  531.  * restore the cursor to the editing location when it is known that the
  532.  * position is somewhere on the existing physical display.  That is
  533.  * generally not true if the result of any operator command is being shown.
  534.  */
  535.  
  536. resetpcursor()
  537. {
  538.     gotoxy( cursorx-offset, cursory );
  539.     return;
  540. }
  541.  
  542. /* local function */
  543. rw1()
  544. {
  545. /* must insure screen current by putpage or otherwise if cline changes */
  546.     if (displine != cline)
  547.         cerr(34);  /* the text display may be wrong if no horz scroll occurs */
  548.  
  549.     if (dispcol != cursorx + 1) {
  550. /* The column number has changed */
  551.         putlineno(cline);
  552.     }
  553. /* compare offsets */
  554.     if ( lastoff != calcoffset(cursorx) )  {
  555.         lastoff = offset;
  556.         return YES;  /* rewrite needed */
  557.     }
  558.     else {
  559.         return NO;
  560.     }
  561. }
  562.  
  563.  
  564.  
  565. /* copy just filename w/o path for 'putstatusline' */
  566.  
  567. setstatusname()
  568. {
  569.     char *np, c;
  570.  
  571.     if ( filename[0] == '\0' )  {
  572.         justfile[0] = '\0';
  573.         return;
  574.     }
  575.     np = filename;
  576.     while( *(np++) )     /* find end */
  577.         ;
  578. /* find last '\',if any  */
  579.     while( ((c = *(--np)) != '\\')  &&  c != ':'  &&  (np != filename) )  {
  580.         if ( c == '.' )  {      /* save any extension */
  581.             if ( *(np+1) == '\0' )
  582.                 *(np) = '\0';
  583.             strncpy(defext,np,4);  /* ".xxx\0"  */
  584.         }
  585.     }
  586.  
  587.     if ( !(*np) )  strcpy( justfile, filename );
  588.     else  {
  589.         memcpy(justfile, filename, 2 );
  590.         strcpy( &justfile[2], ++np);
  591.     }
  592. }
  593.  
  594. /* Show an error message and wait.  The message kept up until the next
  595.  * keystroke, then the key is used normally.  The purpose of the wait
  596.  * is to prevent the status line from overwriting the message.  Use
  597.  * error1 when the hold is not wanted.
  598.  */
  599. error(message)
  600. char *message;
  601. {
  602.     int i;
  603.  
  604.     error1(message);
  605.     i = chkbuf();
  606.     while (chkbuf() == i)
  607.         ;
  608.     return;
  609. }
  610.  
  611. /* Show an error and wait 3.0 to 4.0 seconds, or until a key is entered.
  612.  */
  613. errort(msg)
  614. char *msg;
  615. {
  616.  
  617.     error1(msg);
  618.     wait(3);
  619.     return;
  620. }
  621. /* Wait 'sec' seconds, or until a key is entered.  The amount of
  622.  * delay is independent of the CPU speed.  The delay may be up to
  623.  * one second more than specified.
  624.  */
  625. wait(sec)
  626. int sec;
  627. {
  628.     int i, j, k, ck0;
  629.  
  630.     ck0 = chkbuf();
  631.  
  632.     i = gettime();
  633.     for ( j = 0; j <= sec; j++) {
  634.         while (i == (k = gettime())) {
  635.             if (chkbuf() != ck0) {
  636.                 return;
  637.             }
  638.         }
  639.         i = k;
  640.     }
  641.     return;
  642. }
  643.  
  644. /* show an error message and return immediately.  used only when the
  645.  * caller holds off the status line.  A call to hstart can be used
  646.  * first to specify the first column number.  This call is good
  647.  * for only one message.  The starting column is zero if the call is
  648.  * not made.
  649.  */
  650.  
  651. int bgin = 0;
  652.  
  653. hstart(col)
  654. int col;
  655. {
  656.     bgin = col;
  657.     return;
  658. }
  659. error1(message)
  660. char *message;
  661. {
  662.     gotoxy(bgin,0);
  663.     scr_aputs( bgin, 0, message, colorerr());
  664.     cleareol( bgin+strlen(message), 0 );
  665.     bgin = 0;
  666.     blankedmess = YES;
  667.     resetpcursor();
  668.     colornorm();
  669.     curson(YES);   /* always ready for operator input after an error */
  670.     return;
  671. }
  672.  
  673. /* Show an error message due to a coding error.
  674.  */
  675. cerr(errnum)
  676. int(errnum);
  677. {
  678.     char buf[25];
  679.  
  680.     sprintf(buf, "Coding error %d", errnum);
  681.     hstart(27);
  682.     error(buf);
  683.     return;
  684. }
  685.