[comp.sys.amiga] VT100 2.7 w/ ARP file requester

spencer@eris.berkeley.edu (Randal m Spencer) (01/28/88)

I have been weekend programming on the Amiga for two years now, and I have
posted Lots to comp.sys.amiga, but never have I gotten the two things together.

Here is a file from VT100 that I have modified to include support for the
ARP libraries file requester instead of the string gadget there usually is
(aka. RJ's "Programmer Friendly File Requester").  I have been hacking on
it for the last 4 hours (I said I was just a weekend programmer).  It
probably isn't perfect, but I kept running into VT100 bugs, so I figured
it was time to quit, and if I didn't post it now, it would end up with all
the other program I have written, sitting on my hard disk forever...

I would like to comment on the ARP file requester...I am impressed.  I know
that it doesn't have all the features that one would like, but to be honest
I could only find one real fault with it.

The requester is built as simply as a window, a small structure that includes
the title of the requester and the default directory and file name.  The
FileRequester() call will return wheather or not a file was selected or not,
and the values for Filename and for Directory will have been modified.
Look at this code to see how easy it is to hook into your code.  

The design is what I am really happy with.  Anybody ever look at RJ's 
Programmers Suite in the 2nd Developers Conf. Notes?  Then when he released
the code for it, it really did look beautiful, and I loved the design, but
darn if it wasn't huge.  I have a hard disk backup program I am writting
and when I went to include his code I doubled the size of the program.

The best thing that he did in that requester was make it totally responsive
and FAST to boot.  If you want to look at another directory, just click, 
who cares if the current directory hasn't been scanned in completely.  Well,
that is exactly what the ARP requester does, you can move through directories
VERY fast with it.  

The reqester looks like this:

+-----------------------------+
|     Centered Title Here     |
| |Directory Name Goes Here | |
|  +---------------------+-+  |
|  |  File               |#|  |
|  |     Name            |#|  |
|  |        Space        |#|  |
|  |           Here      | |  |
|  |                     | |  |
|  +---------------------+-+  |
| |File Name Goes Here      | |
|  | OK|  |Parent|  |Cancel|  |
+-----------------------------+

The only, single, problem that I find with this design that I really
liked about RJ's is that there was a "Next Disk" button that advanced
you to the next 'ready' disk (inserted or whatever).  When you clicked
on that button the name of the disk you were looking at (not the
device name, the actual title, "Workbench 1.2:", etc.) is placed in
the Directory gadget.  If anyone from ARP is out there, this is
something that people should think about adding, it is available in
RJ's Programmers Suite.  Since this file requester is so easy to get
to this is probably going to end up in lots of programs, I am glad it
is as good as it is, I would just love to have the ability to choose a
file without picking up the keyboard. 


Ok, so the following file is called "Window.c", it is the only file that
needs to be changed to include ARP in the program VT100.  When you compile
this program be sure to use the -DARP option to define "ARP" for the
#ifdef's.  I just added it to my makefile.  When you link this program
it is necessary to have the file arp.lib in your Manx library.

"What is Arp.lib?", you ask.  Well, this is certainly a point, you won't be
able to compile this program until you lay your hands on it.  The fastest
way to get it (I am told) is off of BIX.  The way I got a copy was from
the Transactor guys at AmiExpo in LA.  If none of the ARP guys are planning
on uploading the ARP stuff (version 1.04) to UseNet, I may be pursuaded
to do it (send me mail if you care one way or the other).  Lastly you could
call my BBS directly (up for maybe a whole 2 more days..., got to swap 
hard disks with a friend...).  The number there is (415) 222-9416.  The
files ARP104.arc and CANDMOD.arc are the ones you want.

What a long posting, will this make it on the net?  

Ok, lastly, I found a bug in VT100 by adding this requester.  Seems that
if you give VT100 a pathname to a file that has spaces in the name it
trunkates the name starting at the last space...  Since the bug was not
in the file Window.c, I leave that to Tony to fix under 2.8 of VT100.
Also, when you choose "Change Dir" the requestor comes up with the old
selection still in it.  To make a valid directory change you must delete
the filename from the requester.  This could be changed, but I didn't want
to modify more than one file to do this.  LIVE with it!!!    :')
This is (BTW) the hint as to how to send a file with spaces in it's path,
change directories to the directory with the spaces in it's path, then
send the file by clearing the Directory gadget, and clicking on the
filename.  Works, no problem... Just not really elegant.

I was going to suggest that someone add the code to make the mouse pointer
invisible when typing, and visible when the mouse is moved, directly to
VT100, but after looking at the code I don't know where in the world 
you would put it.  There is no centeral loop in the program (really...).
So, at least I got a file requester into the program, makes it a whole
lot easier to use (as I just proved to myself when uploading this file),
and ALL that code to generate the dumb requester is GONE!

compile with:
	cc -DARP -DBUGFIXES window.c
        ln ($OBJS) -larp -lc

Enjoy!
 
/****************************************************
 * vt100 emulator - window/keyboard support
 *
 *	v2.7a 880128 RMS - added the ARP file requester, not dynamic, define
 *			  ARP only if you have the arp.library!
 *	v2.7 870825 ACS - Provide an info/status window rather than using
 *			  req().  Better error handling.
 *	v2.6 870227 DBW - bug fixes for all the stuff in v2.5
 *	v2.5 870214 DBW - more additions (see readme file)
 *	v2.4 861214 DBW - lots of fixes/additions (see readme file)
 *	v2.3 861101 DBW - minor bug fixes
 *	v2.2 861012 DBW - more of the same
 *	v2.1 860915 DBW - new features (see README)
 *	     860823 DBW - Integrated and rewrote lots of code
 *	v2.0 860809 DBW - Major rewrite
 *	v1.1 860720 DBW	- Switches, 80 cols, colors, bug fixes
 *	v1.0 860712 DBW	- First version released
 *
 ****************************************************/

#include "vt100.h"
#ifdef ARP
#include "libraries/arpbase.h"	/* Standard ARP header file */
#include "arpfunctions.h"	/* Predeclared functions */
#endif

/* keyboard definitions for toasc() */
static char keys[75] = {
    '`','1','2','3','4','5','6','7','8','9','0','-' ,
    '=','\\', 0, '0','q','w','e','r','t','y','u','i','o' ,
    'p','[',']', 0, '1','2','3','a','s','d','f','g','h' ,
    'j','k','l',';','\'', 0, 0, '4','5','6', 0, 'z','x','c','v',
    'b','n','m',44,'.','/', 0, '.','7','8','9',' ',8,
    '\t',13,13,27,127,0,0,0,'-' } ;
    
/* For InfoMsg...may be changed by a NEWSIZE msg in vt100.c */
int reqminx,	/* Min value for x in reqwindow (pixels) */
    reqmaxx,	/* Max value for x in reqwindow (pixels) */
    reqmaxlen,	/* Max # chars in reqwindow */
    reqminy,	/* Min value for y in reqwindow (scan lines) */	
    reqmaxy,	/* Max value for y in reqwindow (scan lines) */
    reqfudge;	/* Clear space between border and start of 1st char */
int reqy;	/* Current pixel location in reqwindow */

#ifdef ARP
#define MAXPATH		( (FCHARS * 10) + DSIZE + 1)	/* Size of a pathname */

BYTE Filename[FCHARS + 1];
static BYTE Directory[MAXPATH] = "";

struct FileRequester FR = {
	"Greetings! Click on stuff!",	/* Hailing text */
	Filename,			/* filename array */
	Directory,			/* directory array */
	NULL,		/* Window, NULL == workbench */
	NULL,		/* Flags, not used in this release */
	NULL,		/* Function pointers, not used in this release */
	NULL,		/*  "" */
};
#endif

void ReqNewSize(), OpenReqWindow();

/***************************************************
 *  function to swap the use of backspace and delete
 ***************************************************/

void swap_bs_del()
    {
    if (p_bs_del)   p_bs_del = 0;
    else	    p_bs_del = 1;

    keys[0x41] =    p_bs_del ? 127 : 8;
    keys[0x46] =    p_bs_del ? 8 : 127;
    }

/*************************************************
 *  function to get file name (via a requestor)
 *************************************************/
void req(prmpt,name,getinp)
char *prmpt,*name;
int  getinp;
    {
    ULONG class;
    USHORT position, RemoveGadget();
    unsigned int code, qual;
    int  lprmpt, lname;
    struct IntuiMessage *Msg;

    if(reqwinup == 0)
	OpenReqWindow();
    
    if(!getinp) {
    	InfoMsg2Line(prmpt, name);
    	return;
    }

    lprmpt = strlen(prmpt);
    lname = strlen(name);

    /* Don't use strings longer than what we've provided space for. */
    if(lprmpt > (MAXGADSTR-1)) {
	emits("Prompt too long - truncated.\n");
	lprmpt = MAXGADSTR-1;
    }
    if(lname > (MAXGADSTR-1)) {
	emits("Name too long - truncated.\n");
	lname = MAXGADSTR-1;
    }

#ifndef ARP
    if (Msg = (struct IntuiMessage *)GetMsg(reqwindow->UserPort)) {
	class = Msg->Class;
	ReplyMsg(Msg);
	if(class == REQCLEAR)
	    numreqs = 0;
	if(class == NEWSIZE)
	    ReqNewSize(reqwindow->Height, reqwindow->Width);
    }

    /* Make sure the prompt gets updated */
    if (numreqs == 1 && strcmp(Prompt,prmpt) != 0) {
	EndRequest(&myrequest,reqwindow);
	do {
		Wait(1L << reqwindow->UserPort->mp_SigBit);
		while (Msg = (struct IntuiMessage *)GetMsg(reqwindow->UserPort)) {
			class = Msg->Class;
			ReplyMsg(Msg);
			if(class == NEWSIZE)
			    ReqNewSize(reqwindow->Height, reqwindow->Width);
		}
	} while (class != REQCLEAR);
	numreqs = 0;
	}
#endif
    /* copy in a prompt and a default */
#ifdef BUGFIXES
    strncpy(Prompt,prmpt,lprmpt); Prompt[lprmpt] = '\0';
    strncpy(InpBuf,name,lname); InpBuf[lname] = '\0';
#else
    strncpy(Prompt,prmpt,lprmpt); Prompt[lprmpt+1] = '\0';
    strncpy(InpBuf,name,lname); InpBuf[lname+1] = '\0';
#endif
#ifndef ARP
    if (numreqs == 1) {		/* If there is a requester... reuse it */
    	RefreshGadgets(&mystrgad, reqwindow, &myrequest);
    	Delay(2L);
    }
    else {			/* otherwise create it */
	while(numreqs != 1) {
            if (Request(&myrequest, reqwindow) == 0) {
		emits("ERROR - CAN'T CREATE REQUESTOR FOR:\n");
		emits(Prompt); emit('\n'); emits(InpBuf); emit('\n');
		return;
	    }
	    else numreqs = 1;

	    do {
		Wait(1L << reqwindow->UserPort->mp_SigBit);
		while (Msg = (struct IntuiMessage *)GetMsg(reqwindow->UserPort)) {
		    class = Msg->Class;
		    ReplyMsg(Msg);
		    if(class == REQCLEAR)
			numreqs = 0;
		    if(class == NEWSIZE)
			ReqNewSize(reqwindow->Height, reqwindow->Width);
		}
	    } while (class != REQSET);
	} /* end while numreqs != 0 */
    } /* end else */

    /* if we don't want input, we're done */
    if (getinp == 0 || numreqs == 0) return;

#else

    FR.fr_Hail = Prompt;
    FR.fr_Window = mywindow;
    if (FileRequest( &FR )) {
	if (Directory[0] == '\0')
	    strcpy(InpBuf, Filename);
	else {
	    strcpy(InpBuf, Directory);
	    if (Filename[0] != '\0') {
		strcat (InpBuf, "/");
		strcat (InpBuf, Filename);
	    }
	}
    }
    else strcpy(InpBuf, '\0');

#endif

    if((reqwindow->Flags & WINDOWACTIVE) != WINDOWACTIVE) {
    	WindowToFront(reqwindow);
	ActivateWindow(reqwindow);
	do {
	    Wait(1L << reqwindow->UserPort->mp_SigBit);
	    while(Msg = (struct IntuiMessage *)GetMsg(reqwindow->UserPort)) {
		class = Msg->Class;
		ReplyMsg(Msg);
		if(class == NEWSIZE)
		    ReqNewSize(reqwindow->Height, reqwindow->Width);
	    }
	} while (class != ACTIVEWINDOW);
    }
    
#ifndef ARP
    /* here is where we pre-select the gadget   */
    if (!ActivateGadget(&mystrgad,reqwindow,&myrequest)) {

	/* wait for his/her hands to get off the keyboard (Amiga-key) */
	Delay(20L);
	while (Msg = (struct IntuiMessage *)GetMsg(reqwindow->UserPort)) {
	    ReplyMsg(Msg);
	    if(class == NEWSIZE)
		ReqNewSize(reqwindow->Height, reqwindow->Width);
	}

	/* try once more before giving up... */
	ActivateGadget(&mystrgad,reqwindow,&myrequest);
	}

    /* wait for input to show up */
    while (1) {
	if ((NewMessage = (struct IntuiMessage *)
		GetMsg(reqwindow->UserPort)) == FALSE) {
	    Wait(1L<<reqwindow->UserPort->mp_SigBit);
	    continue;
	    }
	class = NewMessage->Class;
	ReplyMsg(NewMessage);

	/* the requestor got terminated... yea!! */
	if (class == REQCLEAR) break;

	if(class == NEWSIZE)
	    ReqNewSize(reqwindow->Height, reqwindow->Width);
	    
	/* maybe this is a menu item to handle */
/*	if (class == MENUPICK) handle_menupick(class,code); */
	}

    /* all done, so return the result */
    numreqs = 0;
#endif
    strcpy(name,InpBuf);
#ifdef BUGFIXES
    ActivateWindow(mywindow);
#endif
    }

/*************************************************
*  function to print a string
*************************************************/
void emits(string)
char string[];
    {
    int i;
    char c;

    i=0;
    while (string[i] != 0)
	{
	c=string[i];
	if (c == 10) emit(13);
	emit(c);
	i += 1;
	}
    }

/*************************************************
*  function to output ascii chars to window
*************************************************/
void emit(c)
char c;
    {
    static char wrap_flag = 0;	/* are we at column 80? */

    c &= 0x7F;
    switch( c )
	{
	case '\t':
	x += 64 - ((x-MINX) % 64);
	break;

	case 10:  /* lf */
	y += 8;
	break;

	case 13:  /* cr */
	x = MINX;
	break;

	case 8:   /* backspace */
	x -= 8;
	if (x < MINX) x = MINX;
	break;

	case 12:     /* page */
	x = MINX;
	y = MINY;
	SetAPen(mywindow->RPort,0L);
	RectFill(mywindow->RPort,(long)MINX,
	    (long)(MINY-7),(long)(MAXX+7),(long)(MAXY+1));
	SetAPen(mywindow->RPort,1L);
	break;

	case 7:     /* bell */
	if (p_volume == 0) DisplayBeep(NULL);
	else {
	    BeginIO(&Audio_Request);
	    WaitIO(&Audio_Request);
	    }
	break;

	default:
	if (c < ' ' || c > '~') break;
	if (p_wrap && wrap_flag && x >= MAXX) {
	    x = MINX;
	    y += 8;
	    if (y > MAXY) {
		y = MAXY;
		ScrollRaster(mywindow->RPort,0L,8L,(long)MINX,
		    (long)(MINY-6),(long)(MAXX+7),(long)(MAXY+1));
		}
	    }
	Move(mywindow->RPort,(long)x,(long)y);

	if (curmode&FSF_BOLD) {
	    if (p_depth > 1) {
		SetAPen(mywindow->RPort,(long)(2+(1^p_screen)));
		SetSoftStyle(mywindow->RPort,(long)curmode,253L);
		}
	    else SetSoftStyle(mywindow->RPort,(long)curmode,255L);
	    }
	else SetSoftStyle(mywindow->RPort,(long)curmode,255L);

	if (curmode&FSF_REVERSE) {
	    SetDrMd(mywindow->RPort,(long)(JAM2+INVERSVID));
	    Text(mywindow->RPort,&c,1L);
	    SetDrMd(mywindow->RPort,(long)JAM2);
	    }
	else Text(mywindow->RPort,&c,1L);

	if (curmode&FSF_BOLD) SetAPen(mywindow->RPort,1L);
	x += 8;
	} /* end of switch */

    if (y > MAXY) {
	y = MAXY;
	x = MINX;
	ScrollRaster(mywindow->RPort,0L,8L,(long)MINX,
	    (long)(MINY-6),(long)(MAXX+7),(long)(MAXY+1));
	}
    if (x > MAXX) {
	wrap_flag = 1;
	x = MAXX;
	}
    else wrap_flag = 0;
    }

/*************************************************
*  function to output ascii chars to window (batched)
*************************************************/
void emitbatch(la,lookahead)
int la;
char *lookahead;
    {
    int i;

    Move(mywindow->RPort,(long)x,(long)y);
    i = x / 8;
    if (i+la >= maxcol) {
	if (p_wrap == 0) la = maxcol - i;
	else {
	    lookahead[la] = 0;
	    emits(lookahead);
	    return;
	    }
	}
    if (curmode&FSF_BOLD) {
	if (p_depth > 1) {
	    SetAPen(mywindow->RPort,(long)(2+(1^p_screen)));
	    SetSoftStyle(mywindow->RPort,(long)curmode,253L);
	    }
	else SetSoftStyle(mywindow->RPort,(long)curmode,255L);
	}
    else SetSoftStyle(mywindow->RPort,(long)curmode,255L);

    if (curmode&FSF_REVERSE) {
	SetDrMd(mywindow->RPort,(long)(JAM2+INVERSVID));
	Text(mywindow->RPort,lookahead,(long)la);
	SetDrMd(mywindow->RPort,(long)JAM2);
	}
    else Text(mywindow->RPort,lookahead,(long)la);
    if (curmode&FSF_BOLD) SetAPen(mywindow->RPort,1L);
    x += (8 * la);
    }

/******************************
* Manipulate cursor
******************************/
void cursorflip()
    {
    SetDrMd(mywindow->RPort,(long)COMPLEMENT);
    SetAPen(mywindow->RPort,3L);
    RectFill(mywindow->RPort,
	(long)(x-1),(long)(y-6),(long)(x+8),(long)(y+1));
    SetAPen(mywindow->RPort,1L);
    SetDrMd(mywindow->RPort,(long)JAM2);
    }

/************************************************
*  function to take raw key data and convert it
*  into ascii chars
**************************************************/
int toasc(code,qual,local)
unsigned int code,qual;
int local;
    {
    unsigned int ctrl,shift,capsl,amiga,alt;
    char c = 0, keypad = 0;
    char *ptr;

    ctrl    = qual & IEQUALIFIER_CONTROL;
    capsl   = qual & IEQUALIFIER_CAPSLOCK;
    amiga   = qual & (IEQUALIFIER_LCOMMAND | IEQUALIFIER_RCOMMAND);
    shift   = qual & (IEQUALIFIER_LSHIFT   | IEQUALIFIER_RSHIFT);
    alt	    = qual & (IEQUALIFIER_LALT     | IEQUALIFIER_RALT);

    switch ( code )
	{
	case 98:
	case 226:
	case 99:
	case 227:
	case 96:
	case 97:
	case 224:
	case 225:
	case 100:
	case 101:
	case 228:
	case 229:
	case 102:
	case 103:
	case 230:
	case 231:   c = 0; break; /* ctrl, shift, capsl, amiga, or alt */

	case 0x50:
	case 0x51:
	case 0x52:
	case 0x53:
	case 0x54:
	case 0x55:
	case 0x56:
	case 0x57:
	case 0x58:
	case 0x59:  c = 0;
		    if (shift)	ptr = p_F[code - 0x50];
		    else	ptr = p_f[code - 0x50];
		    if (!script_on && *ptr == p_keyscript)
			    script_start(++ptr);
		    else    sendstring(ptr);
		    break;
	case 0x0f: c = (p_keyapp) ? 'p' : '0'; keypad = TRUE; break;
	case 0x1d: c = (p_keyapp) ? 'q' : '1'; keypad = TRUE; break;
	case 0x1e: c = (p_keyapp) ? 'r' : '2'; keypad = TRUE; break;
	case 0x1f: c = (p_keyapp) ? 's' : '3'; keypad = TRUE; break;
	case 0x2d: c = (p_keyapp) ? 't' : '4'; keypad = TRUE; break;
	case 0x2e: c = (p_keyapp) ? 'u' : '5'; keypad = TRUE; break;
	case 0x2f: c = (p_keyapp) ? 'v' : '6'; keypad = TRUE; break;
	case 0x3d: c = (p_keyapp) ? 'w' : '7'; keypad = TRUE; break;
	case 0x3e: c = (p_keyapp) ? 'x' : '8'; keypad = TRUE; break;
	case 0x3f: c = (p_keyapp) ? 'y' : '9'; keypad = TRUE; break;
	case 0x43: c = (p_keyapp) ? 'M' : 13 ; keypad = TRUE; break;
	case 0x4a: c = (p_keyapp) ? 'l' : '-'; keypad = TRUE; break;
	case 0x5f: sendstring("\033Om") ;break;
	case 0x3c: c = (p_keyapp) ? 'n' : '.'; keypad = TRUE; break;
	case 0x4c:
	case 0x4d:
	case 0x4e:
	case 0x4f: sendchar(27);            /* cursor keys */
		   if (p_curapp) sendchar('O');
		   else sendchar('[');
		   sendchar(code - 11);
		   break;

	default:
	if (code < 75) c = keys[code];
	else c = 0;
	}

    if (keypad) {
	if (p_keyapp) sendstring("\033O");
	sendchar(c);
	return(0);
	}

    /* add modifiers to the keys */

    if (c != 0) {
	if (shift) {
	    if ((c <= 'z') && (c >= 'a')) c -= 32;
	    else
	    switch( c ) {
		case '[':  c = '{'; break;
		case ']':  c = '}'; break;
		case '\\': c = '|'; break;
		case '\'': c = '"'; break;
		case ';':  c = ':'; break;
		case '/':  c = '?'; break;
		case '.':  c = '>'; break;
		case ',':  c = '<'; break;
		case '`':  c = '~'; break;
		case '=':  c = '+'; break;
		case '-':  c = '_'; break;
		case '1':  c = '!'; break;
		case '2':  c = '@'; break;
		case '3':  c = '#'; break;
		case '4':  c = '$'; break;
		case '5':  c = '%'; break;
		case '6':  c = '^'; break;
		case '7':  c = '&'; break;
		case '8':  c = '*'; break;
		case '9':  c = '('; break;
		case '0':  c = ')'; break;
		default:            break;
		}
	    }
	else if (capsl && (c <= 'z') && (c >= 'a')) c -= 32;
	}
    if (ctrl) {
	if (c > '`' && c <= 127) c -= 96;
	else if (c > '@' && c <= '_') c -= 64;
	else if (c == '6') c = 30;
	else if (c == '-' || c == '?') c = 31;
	}
    if (ctrl && (c == '@' || c == '2' || c == ' ')) {
	if (!local) sendchar(alt?128:0);
	c = 0;
	}
    else if (c != 0 && (!local)) sendchar(alt?c+128:c);
    return((int)c);
    }

void
KillReq()
{
    struct IntuiMessage *Msg;
    ULONG class;
    
    if(numreqs != 0) {
	EndRequest(&myrequest,reqwindow);
	do {
		Wait(1L << reqwindow->UserPort->mp_SigBit);
		while (Msg = (struct IntuiMessage *)GetMsg(reqwindow->UserPort)) {
			class = Msg->Class;
			ReplyMsg(Msg);
		}
	} while (class != REQCLEAR);
	numreqs = 0;
    }

    if(reqwinup) {
    	/* First, clear out all pending messages */
	while (Msg = (struct IntuiMessage *)GetMsg(reqwindow->UserPort)) {
	    class = Msg->Class;
	    ReplyMsg(Msg);
	}
	NewReqWindow.LeftEdge = reqwindow->LeftEdge;	/* Remember ...	  */
	NewReqWindow.TopEdge = reqwindow->TopEdge;	/* ...where...	  */
	NewReqWindow.Width = reqwindow->Width;		/* ...the user... */
	NewReqWindow.Height = reqwindow->Height;	/* ...put it.	  */
	CloseWindow(reqwindow); /* Now we can close the window */
	reqwinup = 0;
    }
}

void
InfoMsg2Line(header, msg)
char *header, *msg;
{
    ScrollInfoMsg(1);
    InfoMsgNoScroll(header);
    ScrollInfoMsg(1);
    InfoMsgNoScroll(msg);
    ScrollInfoMsg(1);
}

void
InfoMsg1Line(msg)
char *msg;
{
    ScrollInfoMsg(1);
    InfoMsgNoScroll(msg);
    ScrollInfoMsg(1);
}

/*   Output the specified data to the "info" window  */
void
ScrollInfoMsg(lines)
int lines;
{
/*  ULONG class;
    struct IntuiMessage *Msg; */
    int pixels = lines << 3;
    
    if(!reqwinup)
	OpenReqWindow();

/*  if(Msg=(struct IntuiMessage *)GetMsg(reqwindow->UserPort)) {
	class = Msg->Class;
	ReplyMsg(Msg);
	if(class == NEWSIZE)
	    ReqNewSize(reqwindow->Height, reqwindow->Width);
    } */

    if ( (reqy += pixels) > reqmaxy) {
	reqy = reqmaxy;
	if(pixels > 0)
	    ScrollRaster(reqwindow->RPort, 0L, (LONG)pixels,
		(LONG)reqminx,
		(LONG)reqminy,
		(LONG)(reqmaxx+7),
		(LONG)(reqmaxy+7));
/* Was:		(LONG)(wp->Width - wp->BorderRight),
		(LONG)(wp->Height - wp->BorderBottom)); */
    }
}

void
InfoMsgNoScroll(msg)
char *msg;
{
    LONG msglen = strlen(msg);

    if(msglen > reqmaxlen)
	msglen = reqmaxlen;

    ScrollInfoMsg(0);	/* Ensure that the msg willbe visible */

    /*  Position the pen at the baseline of the character (7 scan lines
    ** into it). */
    Move(reqwindow->RPort, (LONG)reqminx, (LONG)(reqy+6));
    Text(reqwindow->RPort, msg, msglen);
}

void
ReqNewSize(height, width)
SHORT height, width;
{
    register struct Window *wp = reqwindow;
    int oldmaxy;

    /*   Compute min and max for x and y coordinates.  Note that for y the
    ** value is for the *top* of the character, not the baseline.  Text()
    ** uses a baseline value and so it must be adjusted prior to the call
    ** (characters are assumed to occupy an 8x8 matrix with the baseline at
    ** 7).  When computing the max values, calculate them so that we will
    ** sufficient room for an entire character. */
    oldmaxy = reqmaxy;
    reqminy = wp->BorderTop + reqfudge;
    reqmaxy = (((height - reqminy - wp->BorderBottom) >> 3) << 3)
		+ (reqminy-8);
    reqminx = wp->BorderLeft + reqfudge;
    reqmaxx = (((width - reqminx - wp->BorderRight) >> 3) << 3)
		+ (reqminx-8);
    reqmaxlen = (reqmaxx+7) / 8;
    if(oldmaxy > reqmaxy) { /* Clean up the bottom of the window */
	int temp = height - wp->BorderBottom - reqmaxy;
	
	ScrollRaster(wp->RPort, 0L, (LONG)temp,
	(LONG)reqminx,
	(LONG)reqmaxy,
	(LONG)(width - wp->BorderRight),
	(LONG)(height - wp->BorderBottom));
    }
}

void
OpenReqWindow()
{
    struct IntuiMessage *Msg;
    ULONG class;
    void ReqNewSize();
    
    reqwindow = OpenWindow(&NewReqWindow);
    do {
	Wait(1L << reqwindow->UserPort->mp_SigBit);
	while(Msg = (struct IntuiMessage *)GetMsg(reqwindow->UserPort)) {
	    class = Msg->Class;
	    ReplyMsg(Msg);
	}
    } while (class != ACTIVEWINDOW);
    reqfudge = 0;	/* Leave 0 pixels/scan lines between border and char */
    ReqNewSize(reqwindow->Height, reqwindow->Width);
    reqy = reqminy;	/* Top of character set by ReqNewSize() */
    reqwinup = 1;
}
-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-
Randy Spencer      3461 N. Edison St. Arlington VA 22207      (703)241-2140
spencer@mica.berkeley.edu        I N F I N I T Y         BBS: (415)222-9416
..ucbvax!mica!spencer            s o f t w a r e                  AAA-WH1M
-=-=-=-=-=-=-=-=-=-=-=-=-=See-=-=-you=-=-=-=in-=-=-=-D.C.-=-=-=-=-=-=-=-=-=