home
***
CD-ROM
|
disk
|
FTP
|
other
***
search
/
CP/M
/
CPM_CDROM.iso
/
mbug
/
mbug016.arc
/
WINDOW-C.LBR
/
WINDOWS.C
< prev
Wrap
Text File
|
1979-12-31
|
13KB
|
339 lines
/* WINDOWS ROUTINES Dave Nowlan
.po0
May 85 */
struct Window Screen;
/* set up a structure to hold the picture of the real screen */
/*---------------------------------------------------------------------------*/
Wcursor(window) /* routine to put cursor at current position */
struct Window *window;
/* regardless of what the program might think, the operating system thinks
that the screen is 80 * 25. If the facts are different we must fiddle the
address so that it works. If the cursor would be off the real screen leave
it at home and BEEP. Call Wpoke with a null to get the address relative to
the start of screen RAM */
{ int a,x,y;
a = Wpoke(window,'\0'); /* returns -1 if off the screen */
if (a!=-1)
{ y = (a / 80) + 32; x = (a % 80) + 32; }
else
{ y=32; x=32; putchar(7); }
putchar(ESC); putchar('=');
putchar(y); putchar(x);
return;
}
/*---------------------------------------------------------------------------*/
Wdisplay(window)
struct Window *window;
/* this routine is really only for testing but can be used when you want.
Note that it does not use the windows but splatters the message where CP/M
thinks the cursor should be */
{ printf("\nScreen\n");
printf("displacement %d %d ", Screen.Column, Screen.Row);
printf("width %d depth %d ", Screen.Width, Screen.Depth);
printf("X Y position %d %d ", Screen.CursX, Screen.CursY);
printf("fore/back is %d %d ", Screen.Fore, Screen.Back);
printf("\nwindow\n");
printf("displacement %d %d ", window->Column, window->Row);
printf("width %d depth %d ", window->Width, window->Depth);
printf("X Y position %d %d ", window->CursX, window->CursY);
printf("fore/back is %d %d \n", window->Fore, window->Back);
return;
}
/*--------------------------------------------------------------------------*/
Wfold(window)
struct Window *window; /* defines position, size and colour of it */
{
/* this routine `folds' the CursX,Y coordinates into the window. It does not
scroll but wraps around within the window width and depth until it fits. If
the window does not exist it gives up in disgust. It assumes that the current
location is not far outside the window. The new position is returned by
updating CursX,Y in the window */
if ((window->Width < 1) || (window->Depth < 1))
{ printf("Window is %d wide and %d deep",
window->Width, window->Depth);
exit();
}
/* if x is off right hand end of window drop down a line */
while (window->CursX >= window->Width)
{ window->CursX -= window->Width;
window->CursY++;
}
/* if x is off left hand end of window go up one line */
while (window->CursX < 0)
{ window->CursX += window->Width;
window->CursY--;
}
/* if y below window wrap round to the top */
while (window->CursY >= window->Depth)
{ window->CursY -= window->Depth; }
/* if y above window wrap round to the bottom */
while (window->CursY < 0)
{ window->CursY += window->Depth; }
return;
}
/*---------------------------------------------------------------------------*/
Wgetchar(window) /* gets a character from the window */
struct Window *window; /* position, size and colour of it */
{ char c; /* to hold the character from the keyboard */
/* find current position in the window and put cursor there if on screen */
Wfold(window);
Wpoke(window,160);
/* get next character using MCHINW in the ROM. If it is a null ignore it */
do { c = calla(0xe006); }
while (c==0);
Wpoke(window,' '); /* clear the cursor and return the character */
return(c);
}
/*---------------------------------------------------------------------------*/
Wgets(window,option) /* gets a string from the window */
struct Window *window; /* position, size and colour of it */
int option; /* whether to accept control characters */
{ char c,string[128]; /* to hold the gotten string */
int i;
/* put cursor in the right place and then get characters until a return.
If second parameter is TRUE, include all control characters else don't. The
only control characters actioned by this routine are
BACKSPACE (^h) to cancel one character
CANCEL (^x) to cancel everything so far
RETURN (^m) to mark end of input */
i=0;
do /* until RETURN or string full */
{ c=Wgetchar(window);
/* if a backspace go back one spot unless still at initial position */
if (c == Left)
{ if (i)
{ window->CursX--; i--; }
continue;
}
/* if a cancel (^X) then scrap all input so far by moving cursor back */
if (c == Cancel)
{ if (i)
{ window->CursX -= i; i=0; }
continue;
}
/* if a control character and not wanted then Beep and go round again */
if (c < ' ' && option == FALSE)
{ if (c != Return)
putchar(7);
continue;
}
/* if wanted add to string and write to the screen */
string[i] = c;
Wpoke(window,c);
window->CursX++;
i++;
}
while (i < 128 && c != Return);
/* at end add the final null and return address of the string */
string[i] = '\0';
return(&string[0]);
}
/*---------------------------------------------------------------------------*/
Winitial(colour,red,green,blue)
int colour; /* FALSE if no colours to be processed at all */
int red,green,blue; /* FALSE if that colour is half intensity else full */
{
/* this routine must be called before any other window routine. It uses a
global Window structure called Screen to define the real screen. First define
the origin of the real screen as X,Y displacements from the start of screen
RAM. Usually this is 0,0 but can be changed - don't blame me if you do. All
other windows are relative to the origin as defined here */
Screen.Column = 0;
Screen.Row = 0;
/* now define the shape of the screen as seen by the user. By default this is
80 by 25 but may have be changed eg if E01E is called for a 64 by 16 screen */
Screen.Width = 80;
Screen.Depth = 25;
/* the cursor position is irrelevant as the Screen structure should not be
used as a window. If you do, I take no responsibility for the results!!!! */
Screen.CursX = 0;
Screen.CursY = 0;
/* the foreground colour field is used to tell Wpoke whether to access the
possibly non-existent colour RAM. The first parameter to this routine should
be FALSE unless you have a colour BEE !!!!!!!! */
Screen.Fore = colour;
/* the next three parameters define whether the three colour guns are set to
full (not FALSE) or half intensity (FALSE) for the background colours for the
entire screen. Refer to your manual. Try FALSE FALSE FALSE for starters */
Screen.Back = 0; /* start with all three colours at half */
if (colour) /* if (and only if) colour was asked for */
{ if (red) /* turn on full red ie bit 1 */
Screen.Back |= 2;
if (green) /* turn on full green ie bit 2 */
Screen.Back |= 4;
if (blue) /* turn on full blue ie bit 3 */
Screen.Back |= 8;
}
/* finally leave CP/M thinking that cursor is at home */
Wcursor(Screen);
return;
}
/*---------------------------------------------------------------------------*/
Wpoke(window,it)
struct Window *window; /* defines position, size and colour of it */
char it; /* what to poke into the window */
{ int colour,spot,x,y;
/* first of all see if the spot is within the logical screen. Add the position
within the window to the origin of the window and then to the origin of the
screen. If not within the logical screen return FALSE. Note that this allows
windows to be scrolled - if you refresh the contents of the windows!!!!!!! */
x = window->CursX + window->Column + Screen.Column;
if (x < 0 || x >= Screen.Width)
return(-1);
y = window->CursY + window->Row + Screen.Row;
if (y < 0 || y >= Screen.Depth)
return(-1);
/* now see if the spot is within the real screen RAM ie from 0xf000 to 0xf7ff.
If it isn't, it can't be displayed so return -1. If it is, calculate real
address to be poked */
spot = (y * Screen.Width) + x;
if (spot & 0xf800)
return(-1);
/* now check to see if called with a null. If so return from here */
if (it == 0)
return(spot);
/* if colour was selected in Winitial build colour byte and poke it in */
if (Screen.Fore) /* if colour selected */
{ colour = (window->Back << 5) + window->Fore;
outp (8,(Screen.Back | 64)); /* select colour RAM */
poke ((spot | 0xf800), colour); /* poke in the colour */
outp (8,Screen.Back); /* go back to PCG RAM */
}
/* finally poke in the character advised */
poke ((spot | 0xf000),it);
return(spot);
}
/*---------------------------------------------------------------------------*/
Wputchar(window,it)
struct Window *window; /* defines position, size and colour of it */
char it; /* the character of the moment */
{ int x,y;
/* first of all sort out all the control characters which don't need the
folded address in the window to be calculated. Maybe a bell */
if (it == Bell)
{ putchar(7); return; }
/* move cursor one spot in the appropiate direction */
if (it == Left)
{ window->CursX--; return; }
if (it == Right)
{ window->CursX++; return; }
if (it == Up)
{ window->CursY--; return; }
if (it == Down)
{ window->CursY++; return; }
/* at return move cursor to start of next line; do not space fill rest of
the current line as this can be by using Clrline */
if (it == Return)
{ window->CursX=0;
window->CursY++;
return;
}
/* at home move cursor to top left corner of window */
if (it == Home)
{ window->CursX=0;
window->CursY=0;
return;
}
/* if a clear screen, space out the window from bottom right to top left.
There is no good reason for going this way except that it leaves the cursor
position correctly at the origin of the window */
if (it == Clear)
{ window->CursY = window->Depth;
while (window->CursY)
{ window->CursY--;
window->CursX = window->Width;
while (window->CursX)
{ window->CursX--;
Wpoke(window,' ');
}
}
return;
}
/* all the following codes need the correct position in the window to be
calculated so call Wfold to do it */
Wfold(window);
/* if a delete, write a space to current position and then move cursor back
one position */
if (it == Delete)
{ Wpoke(window,' ');
window->CursX--;
return;
}
/* if not a control character ie at least 0x20 then display it */
if (it & 0xe0)
{ Wpoke(window,it);
window->CursX++;
return;
}
/* Tab means space fill to the next mutiple of 8 characters from the start
of the window or the end of the current line if that comes first. Unless the
cursor is already at the end of the line always give at least one space */
if (it == Tab)
{ if (window->CursX >= window->Width)
{ return; }
do
{ Wpoke(window,' ');
window->CursX++;
}
while ((window->CursX < window->Width)
&& (window->CursX & 7));
return;
}
/* if a clear current line or clear rest of page, space fill the rest of
the current line or page but leave cursor where it is */
if (it == Clrline || it == Clrpage)
{ x=window->CursX; /* save current CursX */
y=window->CursY; /* save current CursY */
/* space fill rest of cuurent line */
while (window->CursX < window->Width)
{ Wpoke(window,' ');
window->CursX++;
}
/* if clear page space fill the rest of the lines in the window */
if (it == Clrpage)
{ window->CursX=0;
window->CursY++;
while (window->CursY < window->Depth)
{ while (window->CursX < window->Width)
{ Wpoke(window,' ');
window->CursX++;
}
window->CursX=0;
window->CursY++;
}
}
window->CursX=x; /* restore saved CursX */
window->CursY=y; /* restore saved CursY */
return;
}
/* no other character updates the screen */
return;
}
/*---------------------------------------------------------------------------*/
Wputs(window,string)
struct Window *window; /* defines position, size and colour of it */
char string[]; /* the string to be processed */
{ char it;
int i;
/* from the start of the string, work through it one character at a time
until you get to the terminating null */
i = 0;
while ((it = string[i]))
{ Wputchar(window,it); i++; }
/* call Wfold to get final cursor position in window right */
Wfold(window);
return;
}
/*---------------------------------------------------------------------------*/
Wsize(width,depth) /* routine to change real screen size */
{ if (width < 1 || depth < 1)
{ printf("Wsize invalid screen width %d or depth %d",
width, depth);
exit();
}
Screen.Width=width;
Screen.Depth=depth;
return(TRUE);
}
/*---------------------------------------------------------------------------*/