[net.sources] Toy window editor for playing with Maryland Window Package

greg@uwvax.UUCP (07/14/83)

Here is a toy window editor that can be used to play with the Maryland
Window Editor that came out over net.sources a week or so ago.

If the window package has been installed in /usr/lib and the include
files have been put in /usr/include/local, and program can be compiled
by typing

cc -o wined wined.c -lwinlib -ljobs -ltermlib

after stripping the header off this file and putting it in a file named
wined.c.
If your site has not installed the window package, but you got it off
the net and have it "ranlib"ed into a file called libwinlib.a, you
can compile the program by typing

cc -o wined wined.c libwinlib.a -ljobs -ltermlib

This latter assumes that the "include" files win.h and window.h are
accessible, as they would be, for instance, if they are in the
directory that is current when you do the compilation.
				- Greg Johnson
				  ...seismo!uwvax!greg

|||
VVV   Start of program
/*
This is a toy window editor that can be used to play with the Maryland
Window Package.  There are four modes: 1) window manipulation mode in which
the "box" is the cursor; 2) window editing "command" mode inside a window;
3) text insertion mode (analogous to that of "vi") inside a window;
4) window-painting mode (explained below).

When the toy editor starts up, seven windows have been created.  One of
them is a special debug/message window that gives error messages and is
usually hidden, and another is a window that displays the current
editor mode and occupies the last line of the screen.

In all modes, the cursor can be moved left, down, up, or right by typing
control-h, control-j, control-k, or control-l, respectively.  Also,
control-r will cause the screen to be re-drawn in all modes.

In window manipulation mode:
The cursor movement control characters move the "box", a large cursor
that can change shape.  In window manipulation mode the cursor commands
and the commands to change the shape of the box can be preceded by
positive numerical arguments if desired.
The box can be made skinnier, taller, shorter, or fatter by typing
"h", "j", "k", or "l".
"c" causes the box to be made tiny.
"w" causes a window to be created under the box.
"W" causes a window to be created under the box and linked to the buffer of
    the "current" window.
"f1", "f2", "f3", and "f4" cause the window under the box to be framed in
    various ways.
"d" deletes the window under the upper left corner of the box.
"i" "identifies" the window under the box as the "current" window.
"m" moves the last window that was found using "i" to the location of the box.
"M" acts like "m", but also changes the the window to be the size of the box.
"s" sets the margins of the window under the box to correspond to the box.
"H" hides the window under the box.
"U" unhides all windows.
"t" brings the window under the box to the top, so that it now sits on top
    of any windows that had been partially obscuring it.
"b" puts a window on the bottom of the pile (opposite of "t").
"r filename<esc or return>" reads part of the file named "filename" into the
    buffer attached to the window under the box.  NOTE:  buffers are all
    only 80 columns by 100 rows, so you'll only get the last 100 or
    so lines of your file.
"n" gets you into window command mode in the window under the box.
"<esc>" gets you out of the toy window editor.

Window command mode:
The usual control characters move the window cursor around.
"h" scrolls the window to the left over the buffer.
"j" scrolls the window down the buffer.
"k" scrolls the window up the buffer.
"l" scrolls the window to the right over the buffer.
"dl" deletes a line from the buffer.
"dc" deletes a column from the buffer.
"x" deletes the character under the window cursor.
"ol" inserts a line into the buffer.
"oc" inserts a column into the buffer.
"m1" toggles the "BOLD" paint attribute for the current window command
     mode session.
"m2" toggles the "BLINK" paint attribute.
"m3" toggles the "UNDERLINE" paint attribute.
"m4" toggles the "INVERSE" paint attribute.
"m5" toggles the "transparent" paint attribute.
"i" gets you into insert mode at the window cursor.
"p" gets you into paint mode at the window's auxiliary cursor.
"<esc>" gets you back to window manipulation mode.

Window insert mode:
The usual control characters move the window cursor around.
"<esc>" gets you back to window command mode.
Other characters get inserted into the buffer under the window,
at the window's cursor.

Window paint mode:
The usual control characters move the window's auxiliary cursor around.
"<esc>" gets you back to window command mode.
Other characters get "painted" onto the window, and affect how (and
whether) one can see through the window at the buffer below.
					- Greg Johnson
*/

#include <stdio.h>
#include <local/window.h>

#define CTRL(c) ((c)&0x1f)

/* macros for moving the auxiliary cursor around */
#define	Wauxcurup(w,n)	(Wauxcursor (w,			\
			 (w)->w_auxcursor.row-(n),\
			 (w)->w_auxcursor.col))
#define	Wauxcurdown(w,n)	(Wauxcursor (w,			\
			 (w)->w_auxcursor.row+(n),\
			 (w)->w_auxcursor.col))
#define	Wauxcurleft(w,n)	(Wauxcursor (w,			\
			 (w)->w_auxcursor.row,\
			 (w)->w_auxcursor.col-(n)))
#define	Wauxcurright(w,n)	(Wauxcursor (w,			\
			 (w)->w_auxcursor.row,\
			 (w)->w_auxcursor.col+(n)))

/* macro that puts the physical cusror where the auxiliary cursor is */
#define	WauxSetReal(w)	(WRCurRow   					      \
			   = (w)->w_auxcursor.row + (w)->w_outside.yorigin,   \
			 WRCurCol   					      \
			   = (w)->w_auxcursor.col + (w)->w_outside.xorigin)

#define	WSetReal(w)	(WRCurRow   					      \
			   = (w)->w_cursor.row + (w)->OYO + (w)->IYO,	      \
			 WRCurCol   					      \
			   = (w)->w_cursor.col + (w)->OXO + (w)->IXO,	      \
			 WSetRealCursor++)

#define MAXWIN 100
#define MAXLINE 200
#define MAXNAME 100

/* Insert n blanks in buffer at cursor */
/* version with a bug fix */
WBinschars (w, n)
Win *w;
int n;
{
	register Buf *b;
	register Ch *cp, *ct, *start;
	int blank;

	if (n < 0)
		return -1;
	if (n == 0)
		return 0;
	b = w -> w_textbuf;
	if (n + b -> b_cursor.col > b -> b_ncols)
		n = b -> b_ncols - b -> b_cursor.col;
	blank = ' ' | (w -> w_mode << NBPB);

	ct = b -> b_contents + b -> b_cursor.row * b -> b_ncols;
	start = ct + b -> b_cursor.col;
	ct += b -> b_ncols;
	cp = ct - n; /* <- new */
	while (cp > start)
		(--ct) -> ch_all = (--cp) -> ch_all;
	while (ct > start)
		(--ct) -> ch_all = blank;
	b -> b_nmodw = -1;
	return 0;
}


/* Delete n chars from buffer at cursor */
/* version with a bug fix. */
WBdelchars (w, n)
Win *w;
int n;
{
	register Buf *b;
	register Ch *cp, *ct, *stop;
	int blank;

	if (n < 0)
		return -1;
	if (n == 0)
		return 0;
	b = w -> w_textbuf;
	if (n + b -> b_cursor.col > b -> b_ncols)
		n = b -> b_ncols - b -> b_cursor.col;
	blank = ' ' | (w -> w_mode << NBPB);

	/* start of row being deleted from */
	ct = b -> b_contents + b -> b_cursor.row * b -> b_ncols;

	/* end of row being deleted from */
	stop = ct + b -> b_ncols;

	/* first character to be deleted */
	cp = ct + b -> b_cursor.col;

	/* first character past set to be deleted */
	ct = cp + n;

	while (ct < stop)
		(cp++) -> ch_all = (ct++) -> ch_all;
	while (cp < stop)
		(cp++) -> ch_all = blank;
	b -> b_nmodw = -1;
	return 0;
}

int boxx, boxy, boxxext, boxyext;

int MaxRow, MaxCol;
Win *modewindow, *wdebug;

Wrefrsh( n )
int n;
{
   WSetRealCursor++;
   WRCurRow = MaxRow-1;
   WRCurCol = 0;
   Wrefresh( n );
}

BrightFrame( w, DoSides )
/* frame the window.  In all cases, set the margins so that the
   entire window is transparent.
   DoSides = 0:  clear frame.
   DoSides = 1:  Highlight the bottom of the window.
   DoSides = 2:  Highlight the perimeter of the window.
*/
register Win *w;
int DoSides;
{
   int i;

   Wborder( CurWin, ' ', ' ', ' ', ' ', ' ', ' ', ' ', ' ' );

   if ( Wsetmargins( w, 0, 0, w->OXE, w->OYE ) == -1 ) {
      Wputs( "\12Wsetmargins didn't work.\15", wdebug );
      Wrefrsh(0);
   }

   if ( DoSides > 0 ) {
      /* paint the frame of the window in a bright, translucent shade */
      Wauxcursor( w, w->OYE-1, 0 );
      for (i = 1; i <= w->OXE; i++) Waputc( ' ', WULINE + WINVERSE + WBUF, w );

      if ( DoSides > 1 ) {
	 Wauxcursor( w, 0, 0 );
	 for (i = 1; i <= (w->OXE); i++)
	    Waputc( ' ', WULINE + WINVERSE + WBUF, w );

	 for (i=1; i <= w->OYE-2; i++) {
	    Wauxcursor( w, i, 0 );
	    Waputc( ' ', WULINE + WINVERSE + WBUF, w );

	    Wauxcursor( w, i, w->OXE-1 );
	    Waputc( ' ', WULINE + WINVERSE + WBUF, w );
	 }
      }
   }
}

initbox( wdebug )
register Win *wdebug;
{
   char ch;

      boxx = MaxCol / 2;
      boxy = MaxRow / 2;
      boxxext = 4;
      boxyext = 4;
      UpdateBox();
   }

   WinEd (s, n, w)
   /* edit the buffer in window "w". */
   char *s;
   register n;
   register Win *w;
   {
	   register c;
	   register char *cp = s;
	   int x, y, xlen, ylen;
	   int auxmode;
	   char line[ 200 ];
	   Buf *b = w-> w_textbuf;

	   Wputs( "\12buffer editing command mode.\15", modewindow );
	   Wrefrsh(0);

	   auxmode = 0;
	   for(;;) {
		   WSetReal( w );
		   Wrefresh (0);           /* Update screen */
		   c = getchar();
		   if (c == '\33' ) break;
		   if (c == 'p') {
			 Wputs( "\12window painting mode.\15", modewindow );

			 WauxSetReal( w );
			 Wrefresh(0);
			 while(( c = getchar() ) != '\33') {
				   if (c == CTRL('H')) Wauxcurleft (w, 1);
			      else if (c == CTRL('J')) Wauxcurdown (w, 1);
			      else if (c == CTRL('K')) Wauxcurup (w, 1);
			      else if (c == CTRL('L')) Wauxcurright (w, 1);
			      else if (c == CTRL('R')) ScreenGarbaged++;
			      else {
				 Waputc( c, auxmode, w );
			     }
			     WauxSetReal( w );
			     Wrefresh(0);
			 }
			 Wputs( "\12buffer editing command mode.\15",
				modewindow );
			 Wrefrsh(0);
			 continue;
		   }
		   if (c == 'm') {
		     switch ( getchar() ) {
			case '1' : auxmode ^= WBOLD; break;
			case '2' : auxmode ^= WBLINK; break;
			case '3' : auxmode ^= WULINE; break;
			case '4' : auxmode ^= WINVERSE; break;
			case '5' : auxmode ^= WBUF; break;
		     }
		     continue;
		   }
		   if (c == 'i') {
			 Wputs( "\12text insertion mode.\15", modewindow );
			 WSetReal( w );
			 Wrefresh(0);
			 while(( c = getchar() ) != '\33') {
				   if (c == CTRL('H')) Wcurleft (w, 1);
			      else if (c == CTRL('J')) Wcurdown (w, 1);
			      else if (c == CTRL('K')) Wcurup (w, 1);
			      else if (c == CTRL('L')) Wcurright (w, 1);
			      else if (c == CTRL('R')) ScreenGarbaged++;
			      else {
				 WBtoWcursor( w );
				 WBinschars (w, 1);
				 WBputc( c, w );
				 /* WWtoBcursor( w ); */
				 WAcursor (w,
				    w->w_textbuf->b_cursor.row - w->IYO,
				    w->w_textbuf->b_cursor.col - w->IXO );
			     }
			     WSetReal( w );
			     Wrefresh(0);
			 }
			 Wputs( "\12buffer editing command mode.\15",
				modewindow );
			 WSetReal( w );
			 Wrefresh(0);
			 continue;
		   }

		   if (c == CTRL( 'H' )) { Wcurleft (w, 1); continue; }
		   if (c == CTRL( 'J' )) { Wcurdown (w, 1); continue; }
		   if (c == CTRL( 'K' )) { Wcurup (w, 1); continue; }
		   if (c == CTRL( 'L' )) { Wcurright (w, 1); continue; }

		   if (c == 'h' ) { Wrelscroll( w,  0, -1, 0 ); continue; }
		   if (c == 'j' ) { Wrelscroll( w, -1,  0, 0 ); continue; }
		   if (c == 'k' ) { Wrelscroll( w,  1,  0, 0 ); continue; }
		   if (c == 'l' ) { Wrelscroll( w,  0,  1, 0 ); continue; }

		   if (c == CTRL('R')) {   /* Redraw screen */
			   ScreenGarbaged++;
			   continue;
		   }
		   if (c == 'x') {
		      WBtoWcursor( w );
		      WBdelchars (w, 1);
		      continue;
		   }
		   if (c == 'd') {
			   WBtoWcursor( w );
			   switch( getchar() ) {
				   case 'c' : WBdelcols (w, 1); break;
				   case 'l' : WBdellines (w, 1); break;
			   }
			   continue;
		   }
		   if (c == 'o') {
		      WBtoWcursor( w );
		      switch( getchar() ) {
			 case 'c' : WBinscols (w, 1); break;
			 case 'l' : WBinslines (w, 1); break;
		      }
		      continue;
		   }
	   }
   }

   ReadFile( w, wdebug )
   /* read part of a file into the buffer associated with the
      specified window.  Prompt the user in the debug window for
      the name of the file. */
   register Win *w, *wdebug;
   {
      FILE *fp, *fopen();
      char name[ MAXNAME ];
      char *c, ch;
      char line[ MAXLINE ];
      int i;

      Wputs( "\12:r ", wdebug );
      Wunhide( wdebug );
      WSetReal( wdebug );
      Wrefresh(0);
      c = name;
      while ( ((ch = getchar() ) != '\33') && ch != '\15' ) {
	 Wputc( ch, wdebug );
	 WSetReal( wdebug );
	 Wrefresh(0);
	 *c = ch;
	 c++;
      }
      *c = '\0';
      Wputs( "\15", wdebug );
      Wrefresh(0);

      if ( (fp = fopen( name, "r" )) == NULL ) {
	 sprintf( line, "\12Couldn't open %s.\15", name );
	 Wputs( line, wdebug );
	 WSetReal( wdebug );
	 Wrefresh(0);
	 return(0);
      }

   BrightFrame( w, 1 );

   WBclear( w, 2 );
   WBcursor( w, 0, 0 );

   while ( fgets(line, MAXLINE, fp) != NULL ) {
      WBputs( line, w );
      WBputs( "\15", w );
   }

   Wrefrsh(0);

}

UpdateBox()
{
      Wbox( boxx, boxy, boxxext, boxyext );

      /* put the terminal's cursor on the upper left corner of box */
      WSetRealCursor++;
      WRCurRow = boxy;
      WRCurCol = boxx;

      Wrefresh( 0 );
}

main( )

{
char *s;
register n;
register Win *w1, *w2, *w3, *w4, *w5, *w;
Win *windows[MAXWIN];
char line[ MAXLINE ];
char ch;
int winid, i;
int buildingnum, numarg;

   Winit( 0, 0 );

   Wscreensize( &MaxRow, &MaxCol );

   initbox( );

   for ( i = 0; i < MAXWIN; i++ ) windows[ i ] = 0;

   wdebug = Wopen( 47, 0, MaxRow-2, MaxCol, 1, 81, 10 );

   if ( wdebug == 0 ) {
      Wcleanup();
      printf( "Could not open wdebug.  Forget it.\n" );
      return(0);
   }
   else {
      sprintf( line, "This is the debug window; MaxRow:  %d;  MaxCol:  %d.\15", MaxRow, MaxCol );
      Wputs( line, wdebug );
      Wrefrsh(0);
   }

   modewindow = Wopen( 83, 0, MaxRow-1, MaxCol, 1, 81, 10 );

   if ( modewindow == 0 ) {
      Wcleanup();
      printf( "Could not open modewindow.  Forget it.\n" );
      return(0);
   }
   else {
      Wputs( "Window manipulation mode.\15", modewindow );
      Wrefrsh(0);
   }

   /* create a few windows for fun */
   if ( (windows[ 1 ] = Wopen( 1, 3, 3, 70, 18, 81, 100 )) != 0 ) {
      ch = '*';
      Wborder( windows[ 1 ], ch, ch, ch, ch, ch, ch, ch, ch );
      Wlabel( windows[ 1 ], "hi guy.", 0, 1 );
      Wrefrsh(0);
   }

   if ( (windows[ 3 ] = Wopen( 3, 40, 10, 9, 5, 81, 100 )) != 0 ) {
      Wframe( windows[ 3 ] );
      Wrefrsh(0);
   }

   if ( (windows[ 4 ] = Wopen( 4, 42, 12, 9, 5, 81, 100 )) != 0 ) {
      Wframe( windows[ 4 ] );
      Wrefrsh(0);
   }

   if ( (windows[ 5 ] = Wopen( 5, 44, 14, 9, 5, 81, 100 )) != 0 ) {
      Wframe( windows[ 5 ] );
      Wrefrsh(0);
   }

   if ( (windows[ 2 ] = Wlink( windows[ 4 ], 2, 10, 10, 9, 5, 81, 100 )) != 0 )
   {
      Wframe( windows[ 2 ] );
      Wrefrsh(0);
   }

   buildingnum = 0;
   UpdateBox();

   /* main loop for window manipulation mode */
   while ( (ch = getchar( ch ) & 0x7f) != '\33' ) {

      if ( (buildingnum = Max( 0, buildingnum - 1 )) == 0 ) numarg = 0;

      Whide( wdebug );
      UpdateBox();

      switch(ch) {

	 case '0' :
	 case '1' :
	 case '2' :
	 case '3' :
	 case '4' :
	 case '5' :
	 case '6' :
	 case '7' :
	 case '8' :
	 case '9' : {
	    numarg = 10 * numarg + ch - '0';
	    buildingnum = 2;
	    break;
	 }

	 /* box moving commands */
	 case CTRL( 'H' ) : boxx = Max( boxx - Max( numarg, 1), 0 );
				 break;
	 case CTRL( 'J' ) : boxy = Min( boxy + Max( numarg, 1), MaxRow - 1);
				 break;
	 case CTRL( 'K' ) : boxy = Max( boxy - Max( numarg, 1), 0 );     
				 break;
	 case CTRL( 'L' ) : boxx = Min( boxx + Max( numarg, 1), MaxCol - 1);
				 break;

	 /* change size of box */
	 case 'h' : boxxext = Max( boxxext - Max( numarg, 1), 1 );
			 break;
	 case 'j' : boxyext = Min( boxyext + Max( numarg, 1), MaxRow-boxy );
		         break;
	 case 'k' : boxyext = Max( boxyext - Max( numarg, 1), 1 );
			 break;
	 case 'l' : boxxext = Min( boxxext + Max( numarg, 1), MaxCol-boxx );
			 break;

	 /* shrink box */
	 case 'c' : boxxext = 1; boxyext = 1; break;

	 /* make a new window under the box. */
	 case 'w' : {

	    for ( i = 0; windows[ i ] != 0; i++ ) ;

	    if ( i == MAXWIN-1 ) {
	       Wputs( "\12No more windows.\15", wdebug ); Wunhide( wdebug );
	    }
	    else {
	       windows[ i ] = Wopen( i, boxx, boxy, boxxext, boxyext,
				     81, 100 );
	       Wframe( windows[ i ] );
	    }
	    break;
	 }

	 /* make a new window under the box that is linked to the buffer
	    of CurWin. */
	 case 'W' : {

	    if ( CurWin == 0 ) {
	       Wputs( "\12No current window.\15", wdebug ); Wunhide( wdebug );
	    }
	    else {
	       for ( i = 0; windows[ i ] != 0; i++ ) ;

	       if ( i == MAXWIN-1 ) {
		  Wputs( "\12No more windows.\15", wdebug ); Wunhide( wdebug );
	       }
	       else {
		  windows[ i ] = Wlink( CurWin, i, boxx, boxy, boxxext, boxyext,
					81, 100 );
		  Wframe( windows[ i ] );
	       }
	    }
	    break;
	 }

	 case 'f' : {
	    if ( Wboxfind() == 0 ) {
		  Wputs( "\12Couldn't find a window.\15", wdebug );
		  Wunhide( wdebug );
	    }
	    else
	       switch getchar() {
		  case '1' : Wframe( CurWin ); break;
		  case '2' : BrightFrame( CurWin, 0 ); break;
		  case '3' : BrightFrame( CurWin, 1 ); break;
		  case '4' : BrightFrame( CurWin, 2 ); break;
	       }
	    break;
	 }

	 case 't' : {
	    if ( Wboxfind() == 0 ) {
		  Wputs( "\12Couldn't find a window.\15", wdebug );
		  Wunhide( wdebug );
	    }
	    else {
	       Wfront( CurWin );
	    }
	    break;
	 }

	 case 'b' : {
	    if ( Wboxfind() == 0 ) {
		  Wputs( "\12Couldn't find a window.\15", wdebug );
		  Wunhide( wdebug );
	    }
	    else {
	       Wback( CurWin );
	    }
	    break;
	 }

	 case 'i' : {
	    if ( Wboxfind() == 0 ) {
		  Wputs( "\12Couldn't find a window.\15", wdebug );
		  Wunhide( wdebug );
	    }
	    break;
	 }

	 case 'd' : {
	       if ( Wboxfind() == 0 ) {
		  Wputs( "\12No current window.\15", wdebug );
		  Wunhide( wdebug );
	       }
	       else if ( CurWin == wdebug || CurWin == modewindow ) {
		  s = "\12You really don't want to delete that window.\15";
		  Wputs( s, wdebug );
		  Wunhide( wdebug );
	       }
	       else
		  Wclose (CurWin);
	       break;
	 }

	 case 's' : {
	       if ( Wboxfind() != 0 ) {
		  Wsetmargins( CurWin, boxx - CurWin->OXO,
				       boxy - CurWin->OYO,
				       boxxext, boxyext );
	       }
	       else {
		  Wputs( "\12No current window.\15", wdebug );
		  Wunhide( wdebug );
	       }
	       break;
	 }

	 case 'U' : {
	    Wunhide( wdebug );
	    Wunhide( modewindow );
	    for (i = 0; i < MAXWIN; i++)
	       if ( windows[ i ] != 0 ) Wunhide( windows[ i ] );
	    break;
	 }

	 case 'H' : {
	       if ( Wboxfind() != 0 )
		  Whide (CurWin);
	       else {
		  Wputs( "\12No current window.\15", wdebug );
		  Wunhide( wdebug );
	       }
	       break;
	 }

	 case 'n' : {
	       if ( Wboxfind() != 0 ) {
		  WBoxActive = 0;
		  Wrefrsh(0);
		  WinEd (s, 200, CurWin);
		  Wputs( "\12Window manipulation mode.\15", modewindow );
	       }
	       else {
		  Wputs( "\12No current window.\15", wdebug );
		  Wunhide( wdebug );
	       }
	       break;
	 }

	 case 'M' : {
	       if ( CurWin != 0 ) {
		  Wsize( CurWin, boxxext, boxyext );
		  Wmove( CurWin, boxx, boxy );
	       }
	       else {
		  Wputs( "\12No current window.\15", wdebug );
		  Wunhide( wdebug );
	       }
	       break;
	 }

	 case 'm' : {
	       if ( CurWin != 0 )
		  Wmove( CurWin, boxx, boxy );
	       else {
		  Wputs( "\12No current window.\15", wdebug );
		  Wunhide( wdebug );
	       }
	       break;
	 }

	 case CTRL('R') : ScreenGarbaged++; Wrefrsh(0); break;

	 case 'r' : {
	       if ( Wboxfind() != 0 )
		  ReadFile( CurWin, wdebug );
	       else {
		  Wputs( "\12No current window.\15", wdebug );
		  Wunhide( wdebug );
	       }
	       break;
	 }
      }
      UpdateBox();
   }

   Wcleanup( );
}