home
***
CD-ROM
|
disk
|
FTP
|
other
***
search
/
Power Programming
/
powerprogramming1994.iso
/
progtool
/
bbs
/
windkw.arc
/
WINDOW.C
< prev
next >
Wrap
C/C++ Source or Header
|
1985-11-12
|
19KB
|
741 lines
/* module: window.c
* programmer: Ray L. McVay
* started: 1 Aug 84
* version: 1.2, 23 Aug 84
*
* A simple window package based on the article and programs
* by Edward Mitchell in the Jan 84 Dr. Dobb's Journal. This
* implementation uses dynamically allocated buffers for the
* window control blocks and screen save buffers.
*
* An assembly language support library called VLIB is used to
* interface the DeSmet C compiler with the IBM ROM BIOS video
* routines. VLIB will undoubtedly have to be rewritten if the
* window package is to be used with other compilers.
*
* History -
*
* 1.1 - Added style member to wcb structure, wcls and
* use of wn->cx for horizontal scrolling in wrt_txt().
*
* 1.2 - Added oldx, oldy members to wcb structure and use them
* in wopen() and wclose().
*
*/
#include <stdio.h>
#include "window.h"
int page; /* Active page number. */
/************************************************************************
* vwrtch(), write a character and attribute to a specific XY location *
* on the screen. The attribute is the high byte of the character. *
************************************************************************/
vwrtch(x, y, c)
int x, y, c;
{
gotoxy(x, y, page);
vputca(c, page, 1);
}
/************************************************************************
* vrdch(), return the character and attribute at screen XY *
************************************************************************/
vrdch(x, y)
int x, y;
{
gotoxy(x, y, page);
return(vgetc(page));
}
/************************************************************************
* draw_row(), output a row of one character/attribute at XY *
************************************************************************/
draw_row(x, y, count, c)
int x, y, count,c;
{
gotoxy(x, y, page);
vputca(c, page, count);
}
/************************************************************************
* wopen(), open a window of given size with upper left corner at *
* XY. Allocates buffers for the window control block and *
* screen save buffers. Copies overwritten screen to the *
* buffer. Draws the blank window. Returns the address of *
* the window control block or NULL if no buffer space. *
* NOTE: The border attributes are given in the structure *
* pointer bord and can be different than the window's *
* contents attribute. *
************************************************************************/
WINDOW *wopen(wbd, x, y, width, height, attrib)
BORDER *wbd;
int x, y, width, height, attrib;
{
WINDOW *wn;
register int tx, ty, xend, yend;
int *tptr, c;
char *calloc();
if ((wn = (WINDOW *)calloc(1, sizeof(WINDOW))) == NULL)
return(NULL);
else if ((wn->scrnsave = (int *)calloc((width+2) * (height+2),
sizeof(int))) == NULL)
{
free(wn);
return(NULL);
}
else
{
/* store parameters in window control block */
wn->xmargin = wn->ymargin = 0;
wn->ulx = x;
wn->uly = y;
wn->xsize = width;
wn->ysize = height;
wn->cx = 1;
wn->cy = 1;
wn->atrib = attrib;
wn->oldx = getxy(page) & 255;
wn->oldy = getxy(page) >> 8;
/* Copy existing text where the window will be placed */
/* to the scrnsave buffer. Obviously, a less portable */
/* routine could be much faster. */
tptr = wn->scrnsave;
xend = x + width + 2;
yend = y + height + 2;
for (ty = y; ty < yend; ty++)
{
for (tx = x; tx < xend; tx++)
*tptr++ = vrdch(tx, ty);
}
/* draw the window border and clear the text area */
vwrtch(x, y, wbd->ul); /* ul corner*/
draw_row(x + 1, y, width, wbd->h); /* horiz bar*/
vwrtch(x + width + 1, y, wbd->ur); /* ur corner*/
yend = y + height;
for (c=wbd->v,ty = y+1; ty <= yend; ty++)
{
vwrtch(x, ty, c); /* draw the sides*/
vwrtch(x+width+1, ty, c);
}
vwrtch(x, y + height + 1, wbd->ll); /* ll corner*/
/* horiz bar */
draw_row(x + 1, y + height + 1, width, wbd->h);
/* lr corner */
vwrtch(x + width + 1, y + height + 1, wbd->lr);
wcls(wn);
return(wn);
}
}
/************************************************************************
* wclose(), erase the window at the window control block. *
* Must be the "top" window if overlapping windows are *
* used. "Tiled" windows could be removed randomly. *
************************************************************************/
wclose(wn)
WINDOW *wn;
{
register
int tx, ty,
xend, yend;
int *tptr;
/* just repaint the saved text at the appropriate location */
tptr = wn->scrnsave;
xend = wn->ulx + wn->xsize + 2;
yend = wn->uly + wn->ysize + 2;
for (ty = wn->uly; ty < yend; ty++)
{
for (tx = wn->ulx; tx < xend; tx++)
vwrtch(tx, ty, *tptr++);
}
/* put cursor back where it was before this rude interruption */
gotoxy(wn->oldx, wn->oldy, page);
/* then release the dynamic storage used */
free(wn->scrnsave);
free(wn);
}
/************************************************************************
* wputstr(), print a string inside a window using cx, cy in WCB *
************************************************************************/
wputstr(wn, string)
register WINDOW *wn;
register char *string;
{
int tcx;
/* Print as much of the string as will fit in the window. *
* cx is used for relative left margin. If cx is negative then *
* the first cx characters will be removed from the string to *
* allow horizontal scrolling in the window. */
while(*string)
wputchar(wn, *string++);
return set_wcxy(wn,0,0);
}
/************************************************************************
* wputs(), print a string inside a window using cx, cy in WCB. *
* Note that the CR, LF, BS, TAB, and DEL keys are processed. *
************************************************************************/
wputs(wn, string)
register WINDOW *wn;
register char *string;
{
while(*string)
wputch(wn, *string++);
return wbound(wn);
}
/************************************************************************
* wputch(), print a character inside a window using cx, cy in WCB *
* while processing for CR, LF, BS, TAB, and DEL. *
************************************************************************/
wputch(wn, c)
register WINDOW *wn;
char c;
{
int rcode;
rcode = 0;
switch (c) {
case '\r': /* Carriage return */
wn->cx = -wn->xmargin+1;
break;
case '\n': /* Linefeed */
++wn->cy;
break;
case '\b': /* Backspace */
--wn->cx;
break;
case 0x7f: /* Delete */
if(wn->cx < 1) { /* If we are left of the */
++wn->cx; /* window account for the */
return; /* delete. */
}
wputch(wn, 0x08);
wputchar(wn, ' ');
wputch(wn, 0x08);
break;
case 0x09: /* Tab */
do
wputchar(wn,' ');
while(wn->cx & 0x07);
break;
case 0x0c: /* Formfeed */
wcls(wn);
break;
default:
wputchar(wn, c);
break;
}
return set_wcxy(wn,0,0);
}
/************************************************************************
* wputchar(), print a character as is where ever the cursor might be *
* inside a window using cx, cy in WCB. *
* Note that the negitive value of cx is handled and that the *
* window is not scrolled. *
************************************************************************/
wputchar(wn, c)
register WINDOW *wn;
char c;
{
int rcode;
if((rcode = wbound(wn))) {
++wn->cx;
return (rcode);
}
gotoxy(wn->ulx + wn->cx++, wn->uly + wn->cy, page);
vputca(wn->atrib<<8|c, page, 1);
return(0);
}
/************************************************************************
* wins_row(), insert a row of blanks by scrolling the lower portion *
* of a window down. *
* The current (cy) row is inserted. *
************************************************************************/
wins_row(wn)
register WINDOW *wn;
{
int rcode, scrlwn[4];
/* Don't if we are not in the window. */
if((rcode = wbound(wn)))
return(rcode);
/* If it is the last line in the window just delete it. */
if(wn->cy == wn->ysize)
draw_row(wn->ulx+1, wn->uly + wn->cy,
wn->xsize, (wn->atrib <<8) |' ');
else {
/* calculate corners of the scrolling window */
scrlwn[0] = wn->ulx +1; /* ulx */
scrlwn[1] = wn->uly + wn->cy; /* uly */
scrlwn[2] = wn->ulx + wn->xsize; /* lrx */
scrlwn[3] = wn->uly + wn->ysize; /* lry */
scrldn(scrlwn, 1, wn->atrib);
}
return(0);
}
/************************************************************************
* wdel_row(), delete a row by scrolling the lower portion of a window *
* up and inserting a row of blanks at the bottom row *
* The current (cy) row is deleted. *
************************************************************************/
wdel_row(wn)
register WINDOW *wn;
{
int rcode, scrlwn[4];
/* Don't if we are not in the window. */
if((rcode = wbound(wn)))
return(rcode);
if(wn->cy == wn->ysize)
draw_row(wn->ulx+1, wn->uly + wn->cy,
wn->xsize, (wn->atrib <<8) |' ');
else {
/* calculate corners of the scrolling window */
scrlwn[0] = wn->ulx + 1; /* ulx */
scrlwn[1] = wn->uly + wn->cy; /* uly */
scrlwn[2] = wn->ulx + wn->xsize; /* lrx */
scrlwn[3] = wn->uly + wn->ysize; /* lry */
scrlup(scrlwn, 1, wn->atrib);
}
return(0);
}
/************************************************************************
* wcls(), clear the "active" part of a window *
* and "home" internal text cursor *
************************************************************************/
wcls(wn)
register WINDOW *wn;
{
int scrlwn[4];
/* calculate corners of the scrolling window */
scrlwn[0] = wn->ulx + 1; /* ulx */
scrlwn[1] = wn->uly + 1; /* uly */
scrlwn[2] = wn->ulx + wn->xsize; /* lrx */
scrlwn[3] = wn->uly + wn->ysize; /* lry */
scrlup(scrlwn, 0, wn->atrib);
wn->cx = 1;
wn->cy = 1;
}
/************************************************************************
* wceol(), clear to end of the line of the window. *
************************************************************************/
wceol(wn)
register WINDOW *wn;
{
register int tx, ty;
if((tx=wbound(wn)))
return(tx);
tx = wn->ulx + wn->cx;
ty = wn->uly + wn->cy;
draw_row(tx, ty, wn->xsize-wn->cx+1, (wn->atrib <<8) |' ');
gotoxy(tx, ty, page);
return(0);
}
/************************************************************************
* wcursor(), cursor controls for a window. *
************************************************************************/
wcursor(wn,c)
register WINDOW *wn;
{
register int tcx, n, tx, ty;
switch (c) {
case CUR_UP: /* Cursor up */
--wn->cy;
break;
case CUR_DWN: /* Cursor down */
++wn->cy;
break;
case CUR_LEFT: /* Cursor left */
--wn->cx;
break;
case CUR_RIGHT: /* Cursor right */
++wn->cx;
break;
case HOME: /* Home cursor */
return set_wcxy(wn,1,1);
case END: /* End cursor */
return set_wcxy(wn,1, wn->ysize);
default:
return(-1);
}
if(wn->cx <1) {
wn->cx = wn->xsize;
} else if(wn->cx > wn->xsize)
wn->cx = 1;
if(wn->cy <1)
wn->cy = wn->ysize;
else if(wn->cy > wn->ysize)
wn->cy = 1;
return set_wcxy(wn, wn->cx, wn->cy);
}
/************************************************************************
* wdelch(), Deletes a character at the current window cursor position. *
************************************************************************/
wdelch(wn)
register WINDOW *wn;
{
register int tx, ty, xend, rcode;
/* Don't if we are not in the window. */
if((rcode = wbound(wn))) {
--wn->cx;
return(rcode);
}
tx = wn->cx + wn->ulx;
ty = wn->cy + wn->uly;
xend = wn->ulx + wn->xsize;
for(; tx < xend; ++tx)
vwrtch(tx, ty, vrdch(tx+1,ty));
vwrtch(tx, ty, wn->atrib<<8 | ' ');
return set_wcxy(wn, 0, 0);
}
/************************************************************************
* winsch(), Inserts a character at the current window cursor position. *
************************************************************************/
winsch(wn,c)
register WINDOW *wn;
int c;
{
int tcx, tcy;
register int tx, ty, n, rcode, xend;
/* Don't if we are not in the window. */
if((rcode = wbound(wn))) {
++wn->cx;
return(rcode);
}
tcx = wn->cx;
tcy = wn->cy;
tx = wn->cx + wn->ulx;
ty = wn->cy + wn->uly;
switch (c) {
case '\n':
if(wn->cy == wn->ysize) {
wscroll(wn);
if(wn->cy >1)
--ty;
} else {
++wn->cy;
++tcy;
wins_row(wn);
}
for( ; wn->cx <= wn->xsize;) {
wputchar(wn, (n=vrdch(tx,ty)));
vwrtch(tx++, ty, (n&0xff00)|' ');
}
break;
case '\b':
--tcx;
if(wn->cy == 1 && wn->cx ==1)
break;
n=vrdch(tx,ty);
wputch(wn,c);
wputchar(wn,n);
wdelch(wn);
return set_wcxy(wn,-1,0);
case '\r':
return wputch(wn, c);
case 0x09: /* Tab */
do
winsch(wn,' ');
while(wn->cx & 0x07);
break;
default:
c |= (wn->atrib<<8);
if(wn->cx == wn->xsize) {
vwrtch(tx,ty,c);
++tcx;
break;
}
xend = wn->ulx + wn->xsize;
for( ; tx < xend; c=n) {
n=vrdch(tx++,ty);
vputca(c, page, 1);
}
++tcx;
break;
}
return set_wcxy(wn, tcx, tcy);
}
/************************************************************************
* wgets(), Gets a string of characters at the current window cursor *
* position. The number of characters to obtain cnt or reaching *
* the end of the window terminates the function. The number of *
* charaters retrived is returned. *
************************************************************************/
wgets(wn,s,cnt)
register WINDOW *wn;
char *s; /* Where to place the null terminated string. */
int cnt; /* Number of character to retrive. */
{
int xend; register int tx, ty, n;
if(wbound(wn))
return(0);
tx = wn->ulx + wn->cx;
ty = wn->uly + wn->cy;
xend = wn->ulx + wn->xsize +1;
for(n=0; cnt-- && tx < xend; ++n)
*s++ = vrdch(tx++, ty);
*s = 0;
return(n);
}
/************************************************************************
* wscroll(), Scrolls the window up one line. *
************************************************************************/
wscroll(wn)
register WINDOW *wn;
{
int tcy;
tcy = wn->cy;
wn->cy =1;
wdel_row(wn);
wn->cy = tcy;
}
/************************************************************************
* wbound(), Check to see if cursor is within the window. *
* Returns a code indicating whether the cursor is in the window. *
************************************************************************/
wbound(wn)
register WINDOW *wn;
{
register int rcode;
rcode =0;
if(wn->cx <1)
rcode = LEFT_OF;
else if(wn->cx > wn->xsize)
rcode = RIGHT_OF;
if(wn->cy <1)
rcode |= TOP_OF;
else if(wn->cy > wn->ysize)
rcode |= BOTTOM_OF;
return(rcode);
}
/************************************************************************
* wgetch(), Returns the character at window cursor location or the *
* boundry code if the location is not within the window. *
************************************************************************/
wgetch(wn)
register WINDOW *wn;
{
int rcode;
if((rcode=wbound(wn)))
return (rcode);
return (vrdch(wn->ulx + wn->cx, wn->uly + wn->cy) &0xff);
}
/************************************************************************
* set_wcxy(), Sets the relative window cursor to the give x,y location. *
* If either x or y is zero the cursor is moved in the given axis *
* the number of spaces given, where positive x is to the right *
* and positive y is down. *
* Note that the home position for a window is 1,1. *
************************************************************************/
set_wcxy(wn,x,y)
register WINDOW *wn;
int x,y;
{
if(x && y) {
wn->cx = x;
wn->cy = y;
} else {
if(!x && y)
wn->cy += y;
if(!y && x)
wn->cx += x;
}
gotoxy(wn->ulx + wn->cx, wn->uly + wn->cy, page);
return wbound(wn);
}
/************************************************************************
* get_wcxy(), Gets the relative window cursor. *
* x = get_wcur() & 0xff, and y = get_wcur() >> 8 *
* Note that the home position for a window is 1,1. *
************************************************************************/
get_wcxy(wn)
register WINDOW *wn;
{
return((wn->cy << 8) | wn->cx);
}
/************************************************************************
* set_cxy(), Sets the screen cursor to the give x,y location. *
* Note that the home position is 0,0. *
************************************************************************/
set_cxy(x,y)
register int x,y;
{
if(!x || !y) {
if(!x && y)
y += (getxy(page)>>8);
if(!y && x)
x += (getxy(page) & 0xff);
}
gotoxy(x,y,page);
}
/************************************************************************
* get_cxy(), Gets the screen cursor location of page 0. *
* x = get_wcur() & 0xff, and y = get_wcur() >> 8 *
* Note that the home position is 0,0. *
************************************************************************/
get_cxy()
{
return(getxy(page));
}
/************************************************************************
* get_page(), Gets the current video page being used.
************************************************************************/
get_page()
{
return (page);
}
/************************************************************************
* set_page(), Sets the active video page and udates page. *
************************************************************************/
set_page(n)
char n;
{
switch (get_mode()) {
case 0:
case 1:
if(n > 7)
return(-1);
break;
case 2:
case 3:
if(n > 3)
return(-1);
break;
case 7:
if(n > 1)
return(-1);
break;
default:
return(-1);
}
vsetpage(n);
page = n;
return(n);
}
/************************************************************************
* wprintf(), Works like printf for a window. *
************************************************************************/
wprintf(wn,cs,a,b,c,d,e,f,g,h,i,j,k,l,m,n)
WINDOW *wn;
char *cs;
{
static buf[256];
sprintf(buf,cs,a,b,c,d,e,f,g,h,i,j,k,l,m,n);
return wputs(wn,buf);
}
/************************************************************************
* wprinta(), Works like wprintf with the addtion of the x,y *
* position. *
************************************************************************/
wprinta(x,y,wn,cs,a,b,c,d,e,f,g,h,i,j,k,l,m,n)
int x,y;
WINDOW *wn;
char *cs;
{
set_wcxy(wn,x,y);
return wprintf(wn,cs,a,b,c,d,e,f,g,h,i,j,k,l,m,n);
}