2105 lines
52 KiB
C++
2105 lines
52 KiB
C++
// This may look like C code, but it is really -*- C++ -*-
|
|
|
|
// ------------------------------------------------------------------
|
|
// The Goldware Library
|
|
// Copyright (C) 1990-1999 Odinn Sorensen
|
|
// Copyright (C) 1999-2000 Alexander S. Aganichev
|
|
// Copyright (C) 2000 Jacobo Tarrio
|
|
// ------------------------------------------------------------------
|
|
// This library is free software; you can redistribute it and/or
|
|
// modify it under the terms of the GNU Library General Public
|
|
// License as published by the Free Software Foundation; either
|
|
// version 2 of the License, or (at your option) any later version.
|
|
//
|
|
// This library is distributed in the hope that it will be useful,
|
|
// but WITHOUT ANY WARRANTY; without even the implied warranty of
|
|
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
|
|
// Library General Public License for more details.
|
|
//
|
|
// You should have received a copy of the GNU Library General Public
|
|
// License along with this program; if not, write to the Free
|
|
// Software Foundation, Inc., 59 Temple Place, Suite 330, Boston,
|
|
// MA 02111-1307, USA
|
|
// ------------------------------------------------------------------
|
|
// $Id$
|
|
// ------------------------------------------------------------------
|
|
// GCUI: Golded+ Character-oriented User Interface.
|
|
// Windowing kernel.
|
|
// Based on CXL by Mike Smedley.
|
|
// ------------------------------------------------------------------
|
|
|
|
#include <cstdio>
|
|
#include <cstdarg>
|
|
#include <cstdlib>
|
|
#include <cstring>
|
|
#include <gmemdbg.h>
|
|
#include <gutlmisc.h>
|
|
#include <gwinall.h>
|
|
#include <gkbdcode.h>
|
|
|
|
|
|
// ------------------------------------------------------------------
|
|
// Local optimizations
|
|
|
|
#define GOLD_INLINE inline
|
|
#define GOLD_WCHK
|
|
|
|
|
|
// ------------------------------------------------------------------
|
|
|
|
static GOLD_INLINE int _wchkrow(int wrow) {
|
|
|
|
return ((wrow<0) or (wrow>((gwin.active->erow-gwin.active->border)-(gwin.active->srow+gwin.active->border))));
|
|
}
|
|
|
|
static GOLD_INLINE int _wchkcol(int wcol) {
|
|
|
|
return ((wcol<0) or (wcol>((gwin.active->ecol-gwin.active->border)-(gwin.active->scol+gwin.active->border))));
|
|
}
|
|
|
|
static GOLD_INLINE int _wchkcoord(int wrow, int wcol) {
|
|
|
|
return (_wchkrow(wrow) or _wchkcol(wcol));
|
|
}
|
|
|
|
|
|
// ------------------------------------------------------------------
|
|
// Checks validity of given window row coordinate
|
|
|
|
int wchkrow(int wrow) {
|
|
|
|
return _wchkrow(wrow);
|
|
}
|
|
|
|
|
|
// ------------------------------------------------------------------
|
|
// Checks validity of given window column coordinate
|
|
|
|
int wchkcol(int wcol) {
|
|
|
|
return _wchkcol(wcol);
|
|
}
|
|
|
|
|
|
// ------------------------------------------------------------------
|
|
// Checks validity of given window coordinates
|
|
|
|
int wchkcoord(int wrow, int wcol) {
|
|
|
|
return _wchkcoord(wrow, wcol);
|
|
}
|
|
|
|
|
|
// ------------------------------------------------------------------
|
|
// Checks for valid window box coordinates
|
|
|
|
int wchkbox(int wsrow, int wscol, int werow, int wecol) {
|
|
|
|
return (_wchkcoord(wsrow,wscol) or _wchkcoord(werow,wecol) or (wsrow>werow) or (wscol>wecol));
|
|
}
|
|
|
|
|
|
// ------------------------------------------------------------------
|
|
// Sets window cursor coordinates
|
|
|
|
int wgotoxy(int wrow, int wcol) {
|
|
|
|
// check for valid cursor coordinates
|
|
#ifdef GOLD_WCHK
|
|
if(wchkcoord(wrow,wcol))
|
|
return gwin.werrno=W_INVCOORD;
|
|
#endif
|
|
|
|
// calculate effective cursor coordinates and update window record
|
|
const int &row = gwin.active->row = gwin.active->srow + wrow + gwin.active->border;
|
|
const int &col = gwin.active->column = gwin.active->scol + wcol + gwin.active->border;
|
|
|
|
// set cursor location
|
|
vposset(row,col);
|
|
|
|
// return with no error
|
|
return gwin.werrno=W_NOERROR;
|
|
}
|
|
|
|
|
|
// ------------------------------------------------------------------
|
|
// Opens a window and makes it active
|
|
|
|
int wopen(int srow, int scol, int erow, int ecol, int btype, vattr battr, vattr wattr, vattr sbattr, vattr loattr) {
|
|
|
|
// check for valid box type
|
|
if(btype<0 or btype>7) {
|
|
gwin.werrno=W_INVBTYPE;
|
|
return 0;
|
|
}
|
|
|
|
if (ecol >= gvid->numcols)
|
|
ecol = gvid->numcols - 1;
|
|
|
|
// see if window is to have a border
|
|
int border = (btype==5) ? NO : YES;
|
|
|
|
// check for valid coordinates
|
|
if(srow>(erow-border) or scol>(ecol-border)) {
|
|
gwin.werrno=W_INVCOORD;
|
|
return 0;
|
|
}
|
|
|
|
// allocate memory for new record
|
|
_wrec_t* wrec = (_wrec_t*)throw_xmalloc(sizeof(_wrec_t));
|
|
if(wrec==NULL) {
|
|
gwin.werrno=W_ALLOCERR;
|
|
return 0;
|
|
}
|
|
|
|
// save affected area of screen
|
|
vsavebuf* wbuf = vsave(srow,scol,erow,ecol);
|
|
if(wbuf==NULL) {
|
|
throw_xrelease(wrec);
|
|
gwin.werrno=W_ALLOCERR;
|
|
return 0;
|
|
}
|
|
|
|
// add new record to linked list
|
|
if(gwin.active!=NULL)
|
|
gwin.active->next=wrec;
|
|
wrec->prev=gwin.active;
|
|
wrec->next=NULL;
|
|
gwin.active=wrec;
|
|
|
|
// draw and fill text box on screen
|
|
switch(gwin.style) {
|
|
case STYLE_NORMAL:
|
|
if(border)
|
|
vbox(srow,scol,erow,ecol,btype,battr,loattr);
|
|
vfill(srow+border,scol+border,erow-border,ecol-border,gwin.fillch,wattr);
|
|
break;
|
|
}
|
|
|
|
// increment window handle counter
|
|
gwin.handle++;
|
|
|
|
// save window info in window record
|
|
gwin.active->wbuf = wbuf;
|
|
gwin.active->whandle = gwin.handle;
|
|
gwin.active->srow = srow;
|
|
gwin.active->scol = scol;
|
|
gwin.active->erow = erow;
|
|
gwin.active->ecol = ecol;
|
|
gwin.active->btype = btype;
|
|
gwin.active->wattr = wattr;
|
|
gwin.active->battr = battr;
|
|
gwin.active->loattr = loattr;
|
|
gwin.active->sbattr = sbattr;
|
|
gwin.active->border = border;
|
|
gwin.active->row = srow+border;
|
|
gwin.active->column = scol+border;
|
|
gwin.active->attr = wattr;
|
|
gwin.active->title = NULL;
|
|
gwin.active->tpos = 0;
|
|
gwin.active->help = 0;
|
|
gwin.active->form = NULL;
|
|
gwin.active->wsbuf = NULL;
|
|
|
|
// increment total number of open windows
|
|
gwin.total++;
|
|
|
|
// initialize cursor location to window row 0 column 0
|
|
wgotoxy(0,0);
|
|
|
|
// return normally
|
|
gwin.werrno=W_NOERROR;
|
|
return gwin.handle;
|
|
}
|
|
|
|
|
|
// ------------------------------------------------------------------
|
|
// Closes a window
|
|
|
|
int wclose() {
|
|
|
|
// check for active window
|
|
if(!gwin.total or !gwin.active)
|
|
return(gwin.werrno=W_NOACTIVE);
|
|
|
|
// if window has a shadow, close shadow first
|
|
if(gwin.active->wsbuf!=NULL)
|
|
wshadoff();
|
|
|
|
// restore contents of and free memory held by window
|
|
vrestore(gwin.active->wbuf);
|
|
throw_xrelease(gwin.active->wbuf);
|
|
|
|
// decrement total number of open windows
|
|
gwin.total--;
|
|
|
|
// free memory held by window's record and update linked list
|
|
_wrec_t *wrec = gwin.active->prev;
|
|
throw_xrelease(gwin.active);
|
|
gwin.active=wrec;
|
|
if(gwin.active!=NULL)
|
|
gwin.active->next=NULL;
|
|
|
|
// update cursor location and help category
|
|
if(gwin.active!=NULL) {
|
|
vposset(gwin.active->row,gwin.active->column);
|
|
if(gwin.active->help)
|
|
gwin.help=gwin.active->help;
|
|
}
|
|
|
|
// return normally
|
|
return gwin.werrno=W_NOERROR;
|
|
}
|
|
|
|
|
|
// ------------------------------------------------------------------
|
|
// Closes all open windows
|
|
|
|
int wcloseall() {
|
|
|
|
if(!gwin.total)
|
|
return gwin.werrno=W_NOACTIVE;
|
|
|
|
while(gwin.total)
|
|
if(wclose())
|
|
return gwin.werrno;
|
|
|
|
// close hidden windows too
|
|
_wrec_t* prev;
|
|
while(gwin.hidden!=NULL) {
|
|
prev = gwin.hidden->prev;
|
|
throw_xfree(gwin.hidden->wbuf);
|
|
throw_xfree(gwin.hidden);
|
|
gwin.hidden = prev;
|
|
}
|
|
|
|
return gwin.werrno=W_NOERROR;
|
|
}
|
|
|
|
|
|
// ------------------------------------------------------------------
|
|
// Gives active window a shadow
|
|
|
|
int wshadow(vattr attr) {
|
|
|
|
// check for active window
|
|
if(!gwin.total)
|
|
return gwin.werrno=W_NOACTIVE;
|
|
|
|
// see if window already has a shadow
|
|
if(gwin.active->wsbuf!=NULL)
|
|
return gwin.werrno=W_NOERROR;
|
|
|
|
// get window coordinates from the window's record
|
|
const int &srow = gwin.active->srow;
|
|
const int &scol = gwin.active->scol;
|
|
const int &erow = gwin.active->erow;
|
|
const int &ecol = gwin.active->ecol;
|
|
|
|
// allocate buffer to hold shadow's contents
|
|
vatch* wsbuf = (vatch*)throw_xmalloc((((erow-srow)*sizeof(vatch))+ecol-scol+1)*sizeof(vatch));
|
|
|
|
if(wsbuf == NULL)
|
|
return gwin.werrno=W_ALLOCERR;
|
|
|
|
// start at upper right corner of shadow and work down
|
|
int crow = srow+1;
|
|
int ccol = ecol+1;
|
|
vatch* q = wsbuf;
|
|
|
|
// draw shadow to right of window
|
|
while(crow<=erow) {
|
|
|
|
// read current screen characters/attributes and save in shadow's buffer
|
|
vatch tmp[2];
|
|
*q = vgetw(crow, ccol);
|
|
#if defined(__USE_NCURSES__) || !defined(__UNIX__)
|
|
tmp[0] = vsattr(*q, attr);
|
|
#else
|
|
tmp[0] = vsattr(' ', attr);
|
|
#endif
|
|
q++;
|
|
*q = vgetw(crow, ccol + 1);
|
|
#if defined(__USE_NCURSES__) || !defined(__UNIX__)
|
|
tmp[1] = vsattr(*q, attr);
|
|
#else
|
|
tmp[1] = vsattr(' ', attr);
|
|
#endif
|
|
q++;
|
|
|
|
// write characters back to screen using shadow's attribute
|
|
vputws(crow++, ccol, tmp, 2);
|
|
}
|
|
|
|
// start at lower left corner of shadow and work right
|
|
crow = erow+1;
|
|
ccol = scol+2;
|
|
int stop = ecol+2;
|
|
int len = stop - ccol + 1;
|
|
vatch* wptr = (vatch*)gvid->bufwrd;
|
|
|
|
// draw bottom shadow
|
|
while(ccol<=stop) {
|
|
|
|
// read attribs/chars and store in buffers
|
|
*q = vgetw(crow, ccol++);
|
|
#if defined(__USE_NCURSES__) || !defined(__UNIX__)
|
|
*wptr++ = vsattr(*q, attr);
|
|
#else
|
|
*wptr++ = vsattr(' ', attr);
|
|
#endif
|
|
q++;
|
|
}
|
|
|
|
// display complete buffer
|
|
vputws(crow, scol+2, gvid->bufwrd, len);
|
|
|
|
// save info in window's record
|
|
gwin.active->wsbuf = wsbuf;
|
|
gwin.active->wsattr = attr;
|
|
|
|
// reset cursor
|
|
vposset(gwin.active->row,gwin.active->column);
|
|
|
|
// return with no error
|
|
return gwin.werrno=W_NOERROR;
|
|
}
|
|
|
|
|
|
// ------------------------------------------------------------------
|
|
// Removes shadow from active window
|
|
|
|
int wshadoff() {
|
|
|
|
// check for active window
|
|
if(!gwin.total)
|
|
return gwin.werrno=W_NOACTIVE;
|
|
|
|
// if window doesn't have a shadow, ignore request
|
|
if(gwin.active->wsbuf==NULL)
|
|
return gwin.werrno=W_NOERROR;
|
|
|
|
// get window coordinates from the window's record
|
|
const int &srow = gwin.active->srow;
|
|
const int &scol = gwin.active->scol;
|
|
const int &erow = gwin.active->erow;
|
|
const int &ecol = gwin.active->ecol;
|
|
|
|
// start at upper right corner of shadow and work down
|
|
int crow = srow+1;
|
|
int ccol = ecol+1;
|
|
vatch* q = gwin.active->wsbuf;
|
|
|
|
// delete shadow to right of window
|
|
while(crow<=erow) {
|
|
vputw(crow, ccol, *q++);
|
|
vputw(crow++, ccol+1, *q++);
|
|
}
|
|
|
|
// start at lower left corner of shadow and work right
|
|
crow = erow+1;
|
|
ccol = scol+2;
|
|
int stop = ecol+2;
|
|
|
|
// delete bottom shadow
|
|
while(ccol<=stop)
|
|
vputw(crow,ccol++,*q++);
|
|
|
|
// free memory held by shadow
|
|
throw_xrelease(gwin.active->wsbuf);
|
|
|
|
// update window's record
|
|
gwin.active->wsattr = WHITE_|_WHITE;
|
|
|
|
// return with no error
|
|
return gwin.werrno=W_NOERROR;
|
|
}
|
|
|
|
|
|
// ------------------------------------------------------------------
|
|
// Scrolls the active window up or down
|
|
|
|
int wscroll(int count, int direction) {
|
|
|
|
// check for window border
|
|
const int &border = gwin.active->border;
|
|
|
|
vscroll(
|
|
gwin.active->srow + border,
|
|
gwin.active->scol + border,
|
|
gwin.active->erow - border,
|
|
gwin.active->ecol - ((border or (gwin.active->sbattr != DEFATTR)) ? 1 : 0),
|
|
gwin.active->wattr,
|
|
direction == SUP ? count : -count
|
|
);
|
|
|
|
// return with no error
|
|
return gwin.werrno = W_NOERROR;
|
|
}
|
|
|
|
|
|
// ------------------------------------------------------------------
|
|
// Scrolls a region of the active window up or down
|
|
|
|
int wscrollbox(int wsrow, int wscol, int werow, int wecol, int count, int direction) {
|
|
|
|
// check for window border
|
|
const int &border = gwin.active->border;
|
|
|
|
vscroll(
|
|
gwin.active->srow+wsrow+border,
|
|
gwin.active->scol+wscol+border,
|
|
gwin.active->srow+werow+border,
|
|
gwin.active->scol+wecol+border,
|
|
gwin.active->wattr,
|
|
direction == SUP ? count : -count
|
|
);
|
|
|
|
// return with no error
|
|
return gwin.werrno=W_NOERROR;
|
|
}
|
|
|
|
|
|
// ------------------------------------------------------------------
|
|
// Displays a character inside active window
|
|
|
|
int wputc(char ch) {
|
|
|
|
int cwcol;
|
|
|
|
// check for active window
|
|
if(!gwin.total)
|
|
return gwin.werrno=W_NOACTIVE;
|
|
|
|
// get coordinates from window's record
|
|
int crow = gwin.active->row;
|
|
int ccol = gwin.active->column;
|
|
const int &scol = gwin.active->scol;
|
|
const int &border = gwin.active->border;
|
|
|
|
// test the input character for control characters
|
|
switch(ch) {
|
|
case '\n':
|
|
crow++;
|
|
case '\r':
|
|
ccol=scol+border;
|
|
break;
|
|
case '\b':
|
|
if(ccol==(scol+border)) {
|
|
ccol=gwin.active->ecol-border;
|
|
crow--;
|
|
if(crow<(gwin.active->srow+border))
|
|
crow++;
|
|
}
|
|
else {
|
|
ccol--;
|
|
}
|
|
break;
|
|
case '\t':
|
|
cwcol=ccol-border-scol;
|
|
ccol+=(tabstop(cwcol,gwin.tabwidth)-cwcol);
|
|
break;
|
|
default:
|
|
vputc(crow, ccol++, gwin.active->attr, ch);
|
|
}
|
|
|
|
// see if wrap-around is needed
|
|
if(ccol > (gwin.active->ecol-border)) {
|
|
ccol = scol+border;
|
|
crow++;
|
|
}
|
|
|
|
// see if scroll is needed
|
|
if(crow > (gwin.active->erow-border)) {
|
|
wscroll(1,SUP);
|
|
crow--;
|
|
}
|
|
|
|
// update window's record
|
|
gwin.active->row=crow;
|
|
gwin.active->column=ccol;
|
|
|
|
// reset cursor position
|
|
vposset(crow,ccol);
|
|
|
|
// return normally
|
|
return gwin.werrno=W_NOERROR;
|
|
}
|
|
|
|
|
|
// ------------------------------------------------------------------
|
|
// Reads current cursor location inside window
|
|
|
|
int wreadcur(int* wrow, int* wcol) {
|
|
|
|
// check for active window
|
|
if(!gwin.total)
|
|
return gwin.werrno=W_NOACTIVE;
|
|
|
|
// read effective cursor coordinates
|
|
int row,col;
|
|
vposget(&row,&col);
|
|
|
|
// calculate window cursor coordinates
|
|
const int &border = gwin.active->border;
|
|
*wrow = row - gwin.active->srow - border;
|
|
*wcol = col - gwin.active->scol - border;
|
|
|
|
// return normally
|
|
return gwin.werrno=W_NOERROR;
|
|
}
|
|
|
|
|
|
// ------------------------------------------------------------------
|
|
// Display a character specified number of times
|
|
|
|
int wdupc(char ch, int count) {
|
|
|
|
// check for active window
|
|
if(!gwin.total)
|
|
return(gwin.werrno=W_NOACTIVE);
|
|
|
|
// display ch for count times
|
|
while(count--)
|
|
wputc(ch);
|
|
|
|
// return with gwin.werrno set by wputc()
|
|
return(gwin.werrno);
|
|
}
|
|
|
|
|
|
// ------------------------------------------------------------------
|
|
// Clears the active window in specified attribute
|
|
|
|
int wcclear(vattr attr) {
|
|
|
|
// check for active window
|
|
|
|
if(!gwin.total)
|
|
return gwin.werrno=W_NOACTIVE;
|
|
|
|
// check for window border
|
|
|
|
const int &border = gwin.active->border;
|
|
|
|
vfill(
|
|
gwin.active->srow+border,
|
|
gwin.active->scol+border,
|
|
gwin.active->erow-border,
|
|
gwin.active->ecol-border,
|
|
gwin.fillch,
|
|
attr
|
|
);
|
|
|
|
// home the cursor
|
|
|
|
wgotoxy(0,0);
|
|
|
|
return gwin.werrno=W_NOERROR;
|
|
}
|
|
|
|
|
|
// ------------------------------------------------------------------
|
|
// Clears from cursor postion to end of window's line
|
|
|
|
int wclreol() {
|
|
|
|
// check for active window
|
|
if(!gwin.total)
|
|
return gwin.werrno=W_NOACTIVE;
|
|
|
|
// clear to end of window's line
|
|
const int &column = gwin.active->column;
|
|
vputx(
|
|
gwin.active->row,
|
|
column,
|
|
gwin.active->attr,
|
|
gwin.fillch,
|
|
gwin.active->ecol - gwin.active->border - column + 1
|
|
);
|
|
|
|
// return normally
|
|
return gwin.werrno=W_NOERROR;
|
|
}
|
|
|
|
|
|
// ------------------------------------------------------------------
|
|
// Clears from cursor postion to end of window
|
|
|
|
int wclreos() {
|
|
|
|
int wrow, werow, wr, wc;
|
|
|
|
// check for active window
|
|
if(!gwin.total)
|
|
return gwin.werrno=W_NOACTIVE;
|
|
|
|
// save current window row and column
|
|
wreadcur(&wr, &wc);
|
|
|
|
wrow = wr;
|
|
werow = gwin.active->erow - gwin.active->srow - gwin.active->border;
|
|
wclreol();
|
|
wrow++;
|
|
|
|
while(wrow <= werow) {
|
|
wgotoxy(wrow,0);
|
|
wclreol();
|
|
wrow++;
|
|
}
|
|
|
|
// restore window row and column
|
|
wgotoxy(wr,wc);
|
|
|
|
// return normally
|
|
return gwin.werrno=W_NOERROR;
|
|
}
|
|
|
|
|
|
// ------------------------------------------------------------------
|
|
// This function will process an Escape sequence when encountered
|
|
|
|
static const char* process_esc(const char* str)
|
|
{
|
|
int wrow,wcol;
|
|
|
|
const char *p = str;
|
|
for(; *p==ESC; p++) {
|
|
|
|
vattr attr = gwin.active->attr;
|
|
|
|
switch(*(++p)) {
|
|
|
|
case '+': // increase text attribute
|
|
wtextattr(++attr);
|
|
break;
|
|
|
|
case '-': // decrease text attribute
|
|
wtextattr(--attr);
|
|
break;
|
|
|
|
case 'A': // change attribute
|
|
wtextattr(*++p);
|
|
break;
|
|
|
|
case 'F': // change foreground attribute
|
|
wtextattr((int)((*++p & 0x07) | (attr & ~0x07)));
|
|
break;
|
|
|
|
case 'B': // change background attribute
|
|
wtextattr((int)((*++p & 0x70) | (attr & ~0x70)));
|
|
break;
|
|
|
|
case 'I': // toggle intensity bit
|
|
wtextattr((int)(attr ^ INTENSE));
|
|
break;
|
|
|
|
case 'L': // toggle blinking bit
|
|
wtextattr((int)(attr ^ BLINK));
|
|
break;
|
|
|
|
case 'X': // reverse attribute
|
|
wtextattr(revsattr(attr));
|
|
break;
|
|
|
|
case 'R': // set cursor row
|
|
wreadcur(&wrow,&wcol);
|
|
wgotoxy(*++p,wcol);
|
|
break;
|
|
|
|
case 'C': // set cursor column
|
|
wreadcur(&wrow,&wcol);
|
|
wgotoxy(wrow,*++p);
|
|
break;
|
|
|
|
case 'E': // erase
|
|
switch(*++p) {
|
|
case 'W': // erase window
|
|
wclear();
|
|
break;
|
|
case 'S': // erase to end of window
|
|
wclreos();
|
|
break;
|
|
case 'L': // erase to end of window's line
|
|
wclreol();
|
|
break;
|
|
}
|
|
break;
|
|
|
|
case 'D': // duplicate character
|
|
{
|
|
char ch = *++p;
|
|
wdupc(ch,*++p);
|
|
}
|
|
break;
|
|
|
|
default:
|
|
p--;
|
|
}
|
|
}
|
|
|
|
return --p;
|
|
}
|
|
|
|
|
|
// ------------------------------------------------------------------
|
|
// Displays a string inside active window
|
|
|
|
int wputs(const char* str) {
|
|
|
|
int cwcol;
|
|
const char* q;
|
|
|
|
// get effective coordinates from window's record
|
|
int &crow = gwin.active->row;
|
|
int &ccol = gwin.active->column;
|
|
const int &scol = gwin.active->scol;
|
|
const int &border = gwin.active->border;
|
|
|
|
// do while not end of string
|
|
for(q=str; *q; q++) {
|
|
|
|
// test the input character for control characters
|
|
switch(*q) {
|
|
case '\n':
|
|
crow++;
|
|
case '\r':
|
|
ccol=scol+border;
|
|
break;
|
|
case '\b':
|
|
if(ccol==(scol+border)) {
|
|
ccol=gwin.active->ecol-border;
|
|
crow--;
|
|
if(crow<(gwin.active->srow+border))
|
|
crow++;
|
|
}
|
|
else {
|
|
ccol--;
|
|
}
|
|
break;
|
|
case '\t':
|
|
cwcol=ccol-border-scol;
|
|
ccol+=(tabstop(cwcol,gwin.tabwidth)-cwcol);
|
|
break;
|
|
case ESC:
|
|
q=process_esc(q);
|
|
break;
|
|
default:
|
|
vputc(crow, ccol++, gwin.active->attr, *q);
|
|
}
|
|
|
|
// see if wrap-around is needed
|
|
if(ccol > (gwin.active->ecol-border)) {
|
|
ccol=scol+border;
|
|
crow++;
|
|
}
|
|
|
|
// see if scroll is needed
|
|
if(crow > (gwin.active->erow-border)) {
|
|
wscroll(1,SUP);
|
|
crow--;
|
|
}
|
|
}
|
|
|
|
// reset cursor position
|
|
vposset(crow,ccol);
|
|
|
|
// return normally
|
|
return(gwin.werrno=W_NOERROR);
|
|
}
|
|
|
|
|
|
// ------------------------------------------------------------------
|
|
// Displays a character inside active window
|
|
|
|
int wprintc(int wrow, int wcol, vattr atr, vchar chr) {
|
|
|
|
// check for active window
|
|
if(!gwin.total)
|
|
return gwin.werrno=W_NOACTIVE;
|
|
|
|
// check for valid coordinates
|
|
#ifdef GOLD_WCHK
|
|
if(wchkcoord(wrow,wcol))
|
|
return gwin.werrno=W_INVCOORD;
|
|
#endif
|
|
|
|
vputc(wrow+gwin.active->srow+gwin.active->border, wcol+gwin.active->scol+gwin.active->border, atr, chr);
|
|
|
|
// return normally
|
|
return gwin.werrno=W_NOERROR;
|
|
}
|
|
|
|
|
|
// ------------------------------------------------------------------
|
|
// Outputs a formatted string to active window
|
|
|
|
int wprintf(const char* format, ...) {
|
|
|
|
va_list argptr;
|
|
char buf[255];
|
|
|
|
// format string using specified parameters into buffer
|
|
va_start(argptr,format); // access argument list
|
|
int result = vsprintf(buf,format,argptr); // create string using argument list
|
|
va_end(argptr); // end access of argument list
|
|
|
|
// display the created string
|
|
wputs(buf);
|
|
|
|
return result;
|
|
}
|
|
|
|
|
|
// ------------------------------------------------------------------
|
|
// Print a formatted string at a specific position and attribute
|
|
|
|
int wprintfs(int wrow, int wcol, vattr attr, const char* format, ...) {
|
|
|
|
va_list argptr;
|
|
char buf[256];
|
|
|
|
*buf = NUL;
|
|
va_start(argptr, format);
|
|
int result = vsprintf(buf, format, argptr);
|
|
va_end(argptr);
|
|
|
|
wprints(wrow, wcol, attr, buf);
|
|
|
|
return result;
|
|
}
|
|
|
|
|
|
// ------------------------------------------------------------------
|
|
// Displays a string inside active window
|
|
|
|
int wprints(int wrow, int wcol, vattr attr, const char* str) {
|
|
|
|
// check for active window
|
|
if(!gwin.total)
|
|
return gwin.werrno=W_NOACTIVE;
|
|
|
|
// check for valid coordinates
|
|
#ifdef GOLD_WCHK
|
|
if(wchkcoord(wrow,wcol))
|
|
return gwin.werrno=W_INVCOORD;
|
|
#endif
|
|
|
|
const int &border = gwin.active->border;
|
|
vputs(gwin.active->srow+wrow+border,gwin.active->scol+wcol+border,attr,str);
|
|
return gwin.werrno=W_NOERROR;
|
|
}
|
|
|
|
int wprints_box(int wrow, int wcol, vattr attr, const char* str) {
|
|
|
|
// check for active window
|
|
if(!gwin.total)
|
|
return gwin.werrno=W_NOACTIVE;
|
|
|
|
// check for valid coordinates
|
|
#ifdef GOLD_WCHK
|
|
if(wchkcoord(wrow,wcol))
|
|
return gwin.werrno=W_INVCOORD;
|
|
#endif
|
|
|
|
const int &border = gwin.active->border;
|
|
vputs_box(gwin.active->srow+wrow+border,gwin.active->scol+wcol+border,attr,str);
|
|
return gwin.werrno=W_NOERROR;
|
|
}
|
|
|
|
|
|
// ------------------------------------------------------------------
|
|
// Displays a string inside active window
|
|
|
|
int wprintvs(int wrow, int wcol, vattr attr, const vchar* str) {
|
|
|
|
// check for active window
|
|
if(!gwin.total)
|
|
return gwin.werrno=W_NOACTIVE;
|
|
|
|
// check for valid coordinates
|
|
#ifdef GOLD_WCHK
|
|
if(wchkcoord(wrow,wcol))
|
|
return gwin.werrno=W_INVCOORD;
|
|
#endif
|
|
|
|
const int &border = gwin.active->border;
|
|
vputvs(gwin.active->srow+wrow+border,gwin.active->scol+wcol+border,attr,str);
|
|
return gwin.werrno=W_NOERROR;
|
|
}
|
|
|
|
|
|
// ------------------------------------------------------------------
|
|
|
|
int wputx(int wrow, int wcol, vattr attr, vchar chr, uint len) {
|
|
|
|
const int &border = gwin.active->border;
|
|
vputx(gwin.active->srow+wrow+border,gwin.active->scol+wcol+border,attr,chr,len);
|
|
return gwin.werrno=W_NOERROR;
|
|
}
|
|
|
|
|
|
// ------------------------------------------------------------------
|
|
|
|
int wputy(int wrow, int wcol, vattr attr, vchar chr, uint len) {
|
|
|
|
const int &border = gwin.active->border;
|
|
vputy(gwin.active->srow+wrow+border,gwin.active->scol+wcol+border,attr,chr,len);
|
|
return gwin.werrno=W_NOERROR;
|
|
}
|
|
|
|
|
|
// ------------------------------------------------------------------
|
|
// Displays a string inside active window
|
|
|
|
int wprintns(int wrow, int wcol, vattr attr, const std::string &str, uint len, vchar fill, vattr fill_attr)
|
|
{
|
|
char* istr = throw_xstrdup(str.c_str());
|
|
char* ostr = istr;
|
|
char och = *ostr;
|
|
uint olen = strlen(istr);
|
|
if(len < olen) {
|
|
ostr += len;
|
|
och = *ostr;
|
|
*ostr = NUL;
|
|
}
|
|
int retval = wprints(wrow, wcol, attr, istr);
|
|
if(len < olen)
|
|
*ostr = och;
|
|
else if(len > olen)
|
|
retval = wputx(wrow, wcol+olen, (fill_attr != DEFATTR) ? fill_attr : attr, fill, len-olen);
|
|
throw_xfree(istr);
|
|
return retval;
|
|
}
|
|
|
|
|
|
// ------------------------------------------------------------------
|
|
// Displays attrib/char buffer inside active window
|
|
|
|
int wprintws(int wrow, int wcol, vatch* buf, uint len) {
|
|
|
|
// check for active window
|
|
if(!gwin.total)
|
|
return gwin.werrno=W_NOACTIVE;
|
|
|
|
// check for valid coordinates
|
|
#ifdef GOLD_WCHK
|
|
if(wchkcoord(wrow,wcol))
|
|
return gwin.werrno=W_INVCOORD;
|
|
#endif
|
|
|
|
// see if window has border
|
|
const int &border = gwin.active->border;
|
|
|
|
// calculate effective coordinates
|
|
int row = gwin.active->srow+wrow+border;
|
|
int col = gwin.active->scol+wcol+border;
|
|
|
|
// display buffer
|
|
vputws(row, col, buf, len);
|
|
|
|
return gwin.werrno=W_NOERROR;
|
|
}
|
|
|
|
|
|
// ------------------------------------------------------------------
|
|
// Returns address of record of given window handle
|
|
|
|
_wrec_t* wfindrec(int whandle) {
|
|
|
|
_wrec_t *wrec;
|
|
|
|
// scan through linked list for record belonging to requested handle
|
|
|
|
wrec = gwin.active;
|
|
while(wrec) {
|
|
if(whandle==wrec->whandle)
|
|
break;
|
|
wrec=wrec->prev;
|
|
}
|
|
|
|
if(wrec == NULL) {
|
|
|
|
// Search through the hidden windows
|
|
|
|
wrec = gwin.hidden;
|
|
while(wrec) {
|
|
if(whandle==wrec->whandle)
|
|
break;
|
|
wrec=wrec->prev;
|
|
}
|
|
}
|
|
|
|
// return address of found record
|
|
return wrec;
|
|
}
|
|
|
|
|
|
// ------------------------------------------------------------------
|
|
// Hides active window
|
|
|
|
int whide() {
|
|
|
|
vsavebuf *p;
|
|
vattr shattr;
|
|
_wrec_t *temp;
|
|
|
|
// check for active window
|
|
if(!gwin.total)
|
|
return(gwin.werrno=W_NOACTIVE);
|
|
|
|
// save active window
|
|
p = vsave(gwin.active->srow,gwin.active->scol,gwin.active->erow,gwin.active->ecol);
|
|
|
|
// check for/close window's shadow
|
|
if(gwin.active->wsbuf!=NULL) {
|
|
shattr = gwin.active->wsattr;
|
|
wshadoff();
|
|
gwin.active->wsattr = shattr;
|
|
}
|
|
else {
|
|
gwin.active->wsattr = DEFATTR;
|
|
}
|
|
|
|
// restore contents of active window's buffer
|
|
vrestore(gwin.active->wbuf);
|
|
throw_xfree(gwin.active->wbuf);
|
|
gwin.active->wbuf = p;
|
|
|
|
// update visible window record linked list
|
|
temp = gwin.active;
|
|
gwin.active = gwin.active->prev;
|
|
if(gwin.active)
|
|
gwin.active->next = NULL;
|
|
gwin.total--;
|
|
|
|
// update hidden window record linked list
|
|
if(gwin.hidden)
|
|
gwin.hidden->next = temp;
|
|
temp->prev = gwin.hidden;
|
|
temp->next = NULL;
|
|
gwin.hidden = temp;
|
|
|
|
// update cursor location and help category
|
|
if(gwin.active) {
|
|
vposset(gwin.active->row,gwin.active->column);
|
|
if(gwin.active->help)
|
|
gwin.help = gwin.active->help;
|
|
}
|
|
|
|
// return normally
|
|
return(gwin.werrno=W_NOERROR);
|
|
}
|
|
|
|
|
|
// ------------------------------------------------------------------
|
|
// Unhides a previously hidden window
|
|
|
|
int wunhide(int whandle) {
|
|
|
|
vsavebuf* p;
|
|
_wrec_t* found;
|
|
|
|
// check pointer to hidden window linked list ; must not be NULL
|
|
if(gwin.hidden==NULL)
|
|
return gwin.werrno=W_NOHIDDEN;
|
|
|
|
// check to see if input window handle == 0. if so, then
|
|
// that means to unhide the most recently hidden window.
|
|
if(!whandle)
|
|
whandle=gwin.hidden->whandle;
|
|
|
|
// scan through linked list for record belonging to requested handle
|
|
found=gwin.hidden;
|
|
while(found!=NULL) {
|
|
if(whandle==found->whandle)
|
|
break;
|
|
found=found->prev;
|
|
}
|
|
|
|
// was handle found in hidden window record linked list?
|
|
if(found==NULL) {
|
|
|
|
// see if handle is in visible window record linked list
|
|
if(wfindrec(whandle)==NULL)
|
|
return gwin.werrno=W_NOTFOUND;
|
|
else
|
|
return gwin.werrno=W_NOTHIDD;
|
|
}
|
|
|
|
// save area of screen where window is to unhide at
|
|
if((p=vsave(found->srow,found->scol,found->erow,found->ecol))==NULL)
|
|
return gwin.werrno=W_ALLOCERR;
|
|
|
|
// restore contents of hidden window back to screen
|
|
vrestore(found->wbuf);
|
|
throw_xfree(found->wbuf);
|
|
found->wbuf=p;
|
|
|
|
// update hidden window record linked list
|
|
if(found->prev!=NULL)
|
|
found->prev->next=found->next;
|
|
if(found->next==NULL)
|
|
gwin.hidden=found->prev;
|
|
else
|
|
found->next->prev=found->prev;
|
|
|
|
// update visible window record linked list
|
|
if(gwin.active!=NULL)
|
|
gwin.active->next=found;
|
|
found->prev=gwin.active;
|
|
found->next=NULL;
|
|
gwin.active=found;
|
|
gwin.total++;
|
|
|
|
// if window had a shadow before hiding, give it one again
|
|
if(gwin.active->wsattr != DEFATTR)
|
|
wshadow(gwin.active->wsattr);
|
|
|
|
// update help category
|
|
if(gwin.active->help)
|
|
gwin.help=gwin.active->help;
|
|
|
|
// reset cursor
|
|
vposset(gwin.active->row,gwin.active->column);
|
|
|
|
// return normally
|
|
return gwin.werrno=W_NOERROR;
|
|
}
|
|
|
|
|
|
// ------------------------------------------------------------------
|
|
// Unlinks and frees a window from memory, but does not manipulate
|
|
// the screen at all
|
|
|
|
int wunlink(int w) {
|
|
|
|
_wrec_t *found, *prev, *next;
|
|
|
|
// check to see if input window handle == 0. if
|
|
// so, then that means to unlink the active window.
|
|
if(!w)
|
|
w=gwin.active->whandle;
|
|
|
|
// find address of window record for given window handle
|
|
if((found=wfindrec(w))==NULL)
|
|
return gwin.werrno=W_NOTFOUND;
|
|
|
|
// free memory held by shadow's buffer (if shadow exists)
|
|
if(found->wsbuf!=NULL)
|
|
throw_xrelease(found->wsbuf);
|
|
|
|
// free memory held by window's buffer
|
|
throw_xrelease(found->wbuf);
|
|
|
|
// decrement total number of open windows
|
|
gwin.total--;
|
|
|
|
// re-link list pointers around window record to remove
|
|
prev=found->prev;
|
|
next=found->next;
|
|
if(prev!=NULL)
|
|
prev->next=next;
|
|
if(next!=NULL)
|
|
next->prev=prev;
|
|
|
|
// free memory held by window record
|
|
throw_xfree(found);
|
|
|
|
// see if active window has changed
|
|
if(next==NULL) {
|
|
if(prev!=NULL) {
|
|
gwin.active=prev;
|
|
if(gwin.active->help)
|
|
gwin.help=gwin.active->help;
|
|
}
|
|
}
|
|
|
|
// return normally
|
|
return gwin.werrno=W_NOERROR;
|
|
}
|
|
|
|
|
|
// ------------------------------------------------------------------
|
|
// Local variables
|
|
|
|
static _wrec_t *__curr, *__found;
|
|
static int __crow, __ccol;
|
|
static vattr __gattr;
|
|
static const char* __p;
|
|
|
|
|
|
// ------------------------------------------------------------------
|
|
// This function dectects if given window is blocking the current
|
|
// window or its shadow at specified coordinates
|
|
|
|
static GOLD_INLINE int window_blocking() {
|
|
|
|
return (__crow>=__curr->srow and __crow<=__curr->erow and __ccol>=__curr->scol and __ccol<=__curr->ecol) ? YES : NO;
|
|
}
|
|
|
|
|
|
// ------------------------------------------------------------------
|
|
// This function detects if a given window's bottom shadow is
|
|
// blocking the current window or its shadow at specified coordinates
|
|
|
|
static GOLD_INLINE int bshadow_blocking() {
|
|
|
|
if(__crow==(__curr->erow+1))
|
|
if((__ccol>=(__curr->scol+2)) and (__ccol<=(__curr->ecol+2)))
|
|
return YES;
|
|
else
|
|
return NO;
|
|
|
|
return NO;
|
|
}
|
|
|
|
|
|
// ------------------------------------------------------------------
|
|
// This function detects if a given window's right shadow is blocking
|
|
// the current window or its shadow at specified coordinates
|
|
|
|
static GOLD_INLINE int rshadow_blocking() {
|
|
|
|
if(__ccol==(__curr->ecol+1) or __ccol==(__curr->ecol+2))
|
|
if((__crow>=(__curr->srow+1)) and (__crow<=__curr->erow))
|
|
return YES;
|
|
else
|
|
return NO;
|
|
|
|
return NO;
|
|
}
|
|
|
|
|
|
// ------------------------------------------------------------------
|
|
|
|
static GOLD_INLINE vatch* calc_window(_wrec_t *wrec) {
|
|
|
|
return wrec->wbuf->data+((__crow-wrec->srow)*(wrec->ecol-wrec->scol+1))+(__ccol-wrec->scol);
|
|
}
|
|
|
|
|
|
// ------------------------------------------------------------------
|
|
|
|
static GOLD_INLINE vatch* calc_bshadow(_wrec_t *wrec) {
|
|
|
|
return wrec->wsbuf+((((__crow-wrec->srow-1)*2)+(__ccol-wrec->scol-2)));
|
|
}
|
|
|
|
|
|
// ------------------------------------------------------------------
|
|
|
|
static GOLD_INLINE vatch* calc_rshadow(_wrec_t *wrec) {
|
|
|
|
return wrec->wsbuf+((((__crow-wrec->srow-1)*2)+(__ccol-wrec->ecol-1)));
|
|
}
|
|
|
|
|
|
// ------------------------------------------------------------------
|
|
// This function will exchange the contents of the applicable buffers
|
|
|
|
static void swap_contents(vatch* pfound, vatch* pcurr, int shadow) {
|
|
|
|
register _wrec_t *wptr;
|
|
register vatch temp, chat;
|
|
|
|
// display character from current position in window to
|
|
// activate on the screen. if character is part of a
|
|
// shadow, reflect the character on the screen.
|
|
|
|
temp = vgetw(__crow, __ccol);
|
|
|
|
if(shadow&2)
|
|
*pcurr = vschar(*pcurr, vgchar(temp));
|
|
chat = ((vgattr(temp) & BLINK) and shadow) ? vsattr(*pcurr, vgattr(*pcurr) | BLINK) : *pcurr;
|
|
vputw(__crow, __ccol, chat);
|
|
|
|
// let window position directly above position
|
|
// to activate have the character that it holds
|
|
|
|
*pcurr = *pfound;
|
|
|
|
// if current character position to activate will
|
|
// activate over a shadow in another window
|
|
|
|
if(shadow&1) {
|
|
|
|
// resolve all shadows upwards
|
|
|
|
wptr = __curr;
|
|
chat = vsattr(*pfound, __curr->wsattr);
|
|
|
|
for(__curr=__curr->next;__curr!=NULL;__curr=__curr->next) {
|
|
|
|
if(window_blocking()) {
|
|
*(calc_window(__curr)) = chat;
|
|
chat = temp;
|
|
break;
|
|
}
|
|
else {
|
|
if(bshadow_blocking())
|
|
*(calc_bshadow(__curr)) = chat;
|
|
else {
|
|
if(rshadow_blocking())
|
|
*(calc_rshadow(__curr)) = chat;
|
|
}
|
|
}
|
|
}
|
|
|
|
temp = chat;
|
|
__curr = wptr;
|
|
}
|
|
|
|
// let character position activated hold character
|
|
// that was on the screen in the same position
|
|
|
|
*pfound = temp;
|
|
}
|
|
|
|
|
|
// ------------------------------------------------------------------
|
|
|
|
int wactiv(int whandle) {
|
|
|
|
register int startcol, stopcol;
|
|
_wrec_t *prev, *next;
|
|
|
|
// check for active window
|
|
|
|
if(!gwin.total)
|
|
return gwin.werrno=W_NOACTIVE;
|
|
|
|
// if window is already active, ignore request
|
|
|
|
if(whandle==gwin.active->whandle)
|
|
return gwin.werrno=W_NOERROR;
|
|
|
|
// find address of window's record
|
|
|
|
__found=wfindrec(whandle);
|
|
if(__found==NULL)
|
|
return gwin.werrno=W_NOTFOUND;
|
|
|
|
// check every character position in window to activate
|
|
|
|
for(__crow=__found->srow;__crow<=__found->erow;__crow++) {
|
|
for(__ccol=__found->scol;__ccol<=__found->ecol;__ccol++) {
|
|
|
|
// check all window records "above" window to activate
|
|
|
|
for(__curr=__found->next;__curr!=NULL;__curr=__curr->next) {
|
|
|
|
// see if current position in window to activate
|
|
// is blocked by same position in test window
|
|
|
|
if(window_blocking()) {
|
|
|
|
// calculate buffer addresses and swap contents
|
|
|
|
swap_contents(calc_window(__found),calc_window(__curr),0);
|
|
break;
|
|
}
|
|
|
|
// see if test window has a shadow
|
|
|
|
if(__curr->wsbuf!=NULL) {
|
|
|
|
// see if shadow to the right of test window is
|
|
// blocking the current position of window to activate
|
|
|
|
if(rshadow_blocking()) {
|
|
swap_contents(calc_window(__found),calc_rshadow(__curr),1);
|
|
break;
|
|
}
|
|
|
|
// see if shadow to the bottom of test window is
|
|
// blocking the current position of window to activate
|
|
|
|
if(bshadow_blocking()) {
|
|
swap_contents(calc_window(__found),calc_bshadow(__curr),1);
|
|
break;
|
|
}
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
// if window to activate has a shadow, then check
|
|
// every character position in the shadow to see
|
|
// if it is blocked by another window or window shadow
|
|
|
|
if(__found->wsbuf!=NULL) {
|
|
|
|
// search the right shadow of window to activiate
|
|
|
|
startcol=__found->ecol+1;
|
|
stopcol=startcol+1;
|
|
for(__crow=__found->srow+1;__crow<=__found->erow;__crow++) {
|
|
for(__ccol=startcol;__ccol<=stopcol;__ccol++) {
|
|
|
|
// check all window records "above" shadow to activate
|
|
|
|
for(__curr=__found->next;__curr!=NULL;__curr=__curr->next) {
|
|
|
|
// see if current position in shadow to activate
|
|
// is blocked by same position in current window
|
|
|
|
if(window_blocking()) {
|
|
|
|
// calculate buffer addresses and swap contents
|
|
|
|
swap_contents(calc_rshadow(__found),calc_window(__curr),2);
|
|
break;
|
|
}
|
|
|
|
// see if test window has a shadow
|
|
|
|
if(__curr->wsbuf!=NULL) {
|
|
|
|
// see if current position of window to activate is
|
|
// blocked by the right shadow of the test window
|
|
|
|
if(rshadow_blocking()) {
|
|
swap_contents(calc_rshadow(__found),calc_rshadow(__curr),3);
|
|
break;
|
|
}
|
|
|
|
// see if current position of window to activate is
|
|
// blocked by the bottom shadow of the test window
|
|
|
|
if(bshadow_blocking()) {
|
|
swap_contents(calc_rshadow(__found),calc_bshadow(__curr),3);
|
|
break;
|
|
}
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
// search bottom shadow
|
|
|
|
startcol=__found->scol+2;
|
|
stopcol=__found->ecol+2;
|
|
__crow=__found->erow+1;
|
|
for(__ccol=startcol;__ccol<=stopcol;__ccol++) {
|
|
|
|
// check all window records "above" shadow to activate
|
|
|
|
for(__curr=__found->next;__curr!=NULL;__curr=__curr->next) {
|
|
|
|
// see if current position in shadow to activate
|
|
// is blocked by same position in test window
|
|
|
|
if(window_blocking()) {
|
|
|
|
// calculate buffer addresses and swap contents
|
|
|
|
swap_contents(calc_bshadow(__found),calc_window(__curr),2);
|
|
break;
|
|
}
|
|
|
|
// see if test window has a shadow
|
|
|
|
if(__curr->wsbuf!=NULL) {
|
|
if(rshadow_blocking()) {
|
|
swap_contents(calc_bshadow(__found),calc_rshadow(__curr),3);
|
|
break;
|
|
}
|
|
if(bshadow_blocking()) {
|
|
swap_contents(calc_bshadow(__found),calc_bshadow(__curr),3);
|
|
break;
|
|
}
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
// re-link pointer to window record to be activated
|
|
|
|
prev=__found->prev;
|
|
next=__found->next;
|
|
if(prev!=NULL)
|
|
prev->next=next;
|
|
next->prev=prev;
|
|
gwin.active->next=__found;
|
|
__found->prev=gwin.active;
|
|
__found->next=NULL;
|
|
gwin.active=__found;
|
|
|
|
// update help category
|
|
|
|
if(gwin.active->help)
|
|
gwin.help=gwin.active->help;
|
|
|
|
// reset cursor position
|
|
|
|
vposset(gwin.active->row,gwin.active->column);
|
|
|
|
// return normally
|
|
|
|
return gwin.werrno=W_NOERROR;
|
|
}
|
|
|
|
|
|
// ------------------------------------------------------------------
|
|
// Activates a window without overlap checking
|
|
|
|
int wactiv_(int whandle) {
|
|
|
|
// if window is already active, ignore request
|
|
if(gwin.active and (whandle == gwin.active->whandle))
|
|
return gwin.werrno = W_NOERROR;
|
|
|
|
// find address of window's record
|
|
__found = wfindrec(whandle);
|
|
if(__found == NULL)
|
|
return gwin.werrno = W_NOTFOUND;
|
|
|
|
// re-link pointer to window record to be activated
|
|
_wrec_t* prev = __found->prev;
|
|
_wrec_t* next = __found->next;
|
|
if(prev)
|
|
prev->next = next;
|
|
next->prev = prev;
|
|
gwin.active->next = __found;
|
|
__found->prev = gwin.active;
|
|
__found->next = NULL;
|
|
gwin.active = __found;
|
|
|
|
// update help category
|
|
if(gwin.active->help)
|
|
gwin.help = gwin.active->help;
|
|
|
|
// reset cursor position
|
|
vposset(gwin.active->row,gwin.active->column);
|
|
|
|
// return normally
|
|
return gwin.werrno = W_NOERROR;
|
|
}
|
|
|
|
|
|
// ------------------------------------------------------------------
|
|
// this function will update buffers above window string will be displayed in
|
|
|
|
static void update_buffers(vatch* pcurr, int shadow) {
|
|
|
|
_wrec_t *tcurr;
|
|
vattr tgattr;
|
|
|
|
// put current string character and attribute into found window's buffer
|
|
|
|
*pcurr = vcatch(*__p, __gattr);
|
|
|
|
// if window's shadow is what's blocking, check to see
|
|
// if it is the highest shadow. If it is, display the
|
|
// character in the shadow's attribute, otherwise search
|
|
// for other blocking windows
|
|
|
|
if(shadow) {
|
|
if(__curr->next==NULL) {
|
|
vputc(__crow, __ccol, __gattr & BLINK ? (__curr->wsattr | BLINK) : __curr->wsattr, *__p);
|
|
}
|
|
else {
|
|
tcurr = __curr;
|
|
__curr = __curr->next;
|
|
tgattr = __gattr;
|
|
__gattr = __curr->wsattr;
|
|
if(window_blocking())
|
|
update_buffers(calc_window(__curr), 0);
|
|
else {
|
|
if(bshadow_blocking())
|
|
update_buffers(calc_bshadow(__curr), 1);
|
|
else {
|
|
if(rshadow_blocking())
|
|
update_buffers(calc_rshadow(__curr), 1);
|
|
}
|
|
}
|
|
__gattr = tgattr;
|
|
__curr = tcurr;
|
|
}
|
|
}
|
|
}
|
|
|
|
// ------------------------------------------------------------------
|
|
|
|
int wwprintc(int whandle, int wrow, int wcol, vattr attr, const vchar chr) {
|
|
|
|
// check for existance of active window or hidden windows
|
|
if(!gwin.total and gwin.hidden==NULL)
|
|
return gwin.werrno=W_NOACTIVE;
|
|
|
|
// find address of window's record
|
|
_wrec_t* found = wfindrec(whandle);
|
|
if(found==NULL) {
|
|
found = gwin.hidden;
|
|
while(found) {
|
|
if(whandle==found->whandle)
|
|
break;
|
|
found = found->prev;
|
|
}
|
|
if(found==NULL)
|
|
return gwin.werrno=W_NOTFOUND;
|
|
}
|
|
|
|
// display character
|
|
vputc(found->srow+wrow+found->border, found->scol+wcol+found->border, attr, chr);
|
|
|
|
// return to caller
|
|
return gwin.werrno = W_NOERROR;
|
|
}
|
|
|
|
// ------------------------------------------------------------------
|
|
|
|
int wwprints(int whandle, int wrow, int wcol, vattr attr, const char* str) {
|
|
|
|
// check for existance of active window or hidden windows
|
|
if(!gwin.total and gwin.hidden==NULL)
|
|
return gwin.werrno=W_NOACTIVE;
|
|
|
|
// find address of window's record
|
|
int hidden = NO;
|
|
_wrec_t* found = wfindrec(whandle);
|
|
if(found==NULL) {
|
|
found = gwin.hidden;
|
|
while(found) {
|
|
if(whandle==found->whandle)
|
|
break;
|
|
found = found->prev;
|
|
}
|
|
if(found==NULL)
|
|
return gwin.werrno=W_NOTFOUND;
|
|
hidden = YES;
|
|
}
|
|
|
|
// see if window has a border
|
|
int border = found->border;
|
|
|
|
// calculate effective coordinates
|
|
int ecol = found->ecol-border;
|
|
__crow = found->srow+wrow+border;
|
|
__ccol = found->scol+wcol+border;
|
|
__gattr = attr;
|
|
__p = str;
|
|
|
|
// check for valid coordinates
|
|
if((__crow > (found->erow-border)) or (__ccol > ecol))
|
|
return gwin.werrno=W_INVCOORD;
|
|
|
|
// save current cursor position
|
|
int oldrow, oldcol;
|
|
if(gvid->isbios())
|
|
vposget(&oldrow,&oldcol);
|
|
|
|
// do while not end-of-string and not end-of-window
|
|
while(__ccol <= ecol and *__p) {
|
|
|
|
// see if output window is hidden. if so, then there
|
|
// is no need to check for blocking windows/shadows
|
|
if(hidden)
|
|
*(calc_window(found)) = vcatch(*__p, attr);
|
|
else {
|
|
|
|
// check all window records "above" window to activate
|
|
for(__curr=found->next; __curr!=NULL; __curr=__curr->next) {
|
|
|
|
// see if current position in window to activate
|
|
// is blocked by same position in test window
|
|
if(window_blocking()) {
|
|
|
|
// calculate buffer addresses and swap contents
|
|
update_buffers(calc_window(__curr), 0);
|
|
break;
|
|
}
|
|
|
|
// see if test window has a shadow
|
|
if(__curr->wsbuf!=NULL) {
|
|
|
|
// see if shadow to the right of test window is
|
|
// blocking the current position of window to activate
|
|
if(rshadow_blocking()) {
|
|
update_buffers(calc_rshadow(__curr), 1);
|
|
break;
|
|
}
|
|
|
|
// see if shadow to the bottom of test window is
|
|
// blocking the current position of window to activate
|
|
if(bshadow_blocking()) {
|
|
update_buffers(calc_bshadow(__curr), 1);
|
|
break;
|
|
}
|
|
}
|
|
}
|
|
|
|
// if current position is not blocked,
|
|
// then display char to screen
|
|
if(__curr==NULL)
|
|
vputc(__crow, __ccol, attr, *__p);
|
|
}
|
|
|
|
// update pointer into string and current column
|
|
__ccol++;
|
|
__p++;
|
|
}
|
|
|
|
// restore old cursor position
|
|
if(gvid->isbios())
|
|
vposset(oldrow,oldcol);
|
|
|
|
// return to caller
|
|
return gwin.werrno = *__p ? W_STRLONG : W_NOERROR;
|
|
}
|
|
|
|
|
|
// ------------------------------------------------------------------
|
|
|
|
int wwprintstr(int whandle, int wrow, int wcol, vattr attr, const char* str) {
|
|
|
|
// check for existance of active window or hidden windows
|
|
if(!gwin.total and gwin.hidden==NULL)
|
|
return gwin.werrno=W_NOACTIVE;
|
|
|
|
// find address of window's record
|
|
_wrec_t* found = wfindrec(whandle);
|
|
if(found==NULL) {
|
|
found = gwin.hidden;
|
|
while(found) {
|
|
if(whandle==found->whandle)
|
|
break;
|
|
found = found->prev;
|
|
}
|
|
if(found==NULL)
|
|
return gwin.werrno=W_NOTFOUND;
|
|
}
|
|
|
|
// display string
|
|
vputs(found->srow+wrow+found->border, found->scol+wcol+found->border, attr, str);
|
|
|
|
// return to caller
|
|
return gwin.werrno = W_NOERROR;
|
|
}
|
|
|
|
|
|
// ------------------------------------------------------------------
|
|
// Changes the active window's border box type
|
|
|
|
int wborder(int btype) {
|
|
|
|
register int border;
|
|
|
|
// check for active window
|
|
if(!gwin.total)
|
|
return gwin.werrno=W_NOACTIVE;
|
|
|
|
// check for valid box type
|
|
if((btype<0) or (btype>7))
|
|
return gwin.werrno=W_INVBTYPE;
|
|
|
|
// see if window is to have a border
|
|
border = (btype==5) ? NO : YES;
|
|
|
|
// redraw window's border
|
|
vbox(
|
|
gwin.active->srow,
|
|
gwin.active->scol,
|
|
gwin.active->erow,
|
|
gwin.active->ecol,
|
|
btype,
|
|
border ? gwin.active->battr : gwin.active->wattr,
|
|
border ? gwin.active->loattr : gwin.active->wattr
|
|
);
|
|
|
|
// update window's record
|
|
gwin.active->btype=btype;
|
|
gwin.active->border=border;
|
|
|
|
// see if cursor position needs to be updated
|
|
if((gwin.active->row==gwin.active->srow) or
|
|
(gwin.active->row==gwin.active->erow) or
|
|
(gwin.active->column==gwin.active->scol) or
|
|
(gwin.active->column==gwin.active->ecol)) {
|
|
wgotoxy(0,0);
|
|
}
|
|
|
|
// re-display title if one exists
|
|
if(gwin.active->title!=NULL)
|
|
wtitle(gwin.active->title,gwin.active->tpos,gwin.active->tattr);
|
|
|
|
// return normally
|
|
return gwin.werrno=W_NOERROR;
|
|
}
|
|
|
|
|
|
// ------------------------------------------------------------------
|
|
// Fills a region of active window w/specified char/attribute
|
|
|
|
int wfill(int wsrow, int wscol, int werow, int wecol, vchar chr, vattr atr) {
|
|
|
|
// check for active window
|
|
if(!gwin.total)
|
|
return gwin.werrno=W_NOACTIVE;
|
|
|
|
// check for valid coordinates
|
|
if(wchkbox(wsrow,wscol,werow,wecol))
|
|
return gwin.werrno=W_INVCOORD;
|
|
|
|
// check for window border
|
|
const int &border = gwin.active->border;
|
|
|
|
// fill in specified region
|
|
vfill(
|
|
gwin.active->srow+wsrow+border,
|
|
gwin.active->scol+wscol+border,
|
|
gwin.active->srow+werow+border,
|
|
gwin.active->scol+wecol+border,
|
|
chr,
|
|
atr
|
|
);
|
|
|
|
// return with no error
|
|
return gwin.werrno=W_NOERROR;
|
|
}
|
|
|
|
|
|
// ------------------------------------------------------------------
|
|
// Returns the handle of the active window
|
|
|
|
int whandle() {
|
|
|
|
// test for active window
|
|
if(!gwin.total) {
|
|
gwin.werrno=W_NOACTIVE;
|
|
return 0;
|
|
}
|
|
|
|
// return normally
|
|
gwin.werrno = W_NOERROR;
|
|
return gwin.active->whandle;
|
|
}
|
|
|
|
|
|
// ------------------------------------------------------------------
|
|
// Displays text on window's top or bottom border
|
|
|
|
int wmessage(const char* str, int border, int leftofs, vattr attr) {
|
|
|
|
// check for active window
|
|
if(!gwin.total)
|
|
return gwin.werrno=W_NOACTIVE;
|
|
|
|
// make sure window has a border
|
|
if(!gwin.active->border)
|
|
return gwin.werrno=W_NOBORDER;
|
|
|
|
int left = gwin.active->scol+1;
|
|
int right = gwin.active->ecol-1;
|
|
int width = right-left+1;
|
|
int len = strlen(str);
|
|
|
|
// Center string
|
|
if(leftofs < 0)
|
|
leftofs = (len > (width-2)) ? left : (((width/2)+left)-(len/2));
|
|
|
|
// make sure string fits in window
|
|
if((gwin.active->scol+leftofs+len-1) > (gwin.active->ecol))
|
|
return gwin.werrno=W_STRLONG;
|
|
|
|
// display string
|
|
vputs(border ? gwin.active->erow : gwin.active->srow, gwin.active->scol+leftofs, attr, str);
|
|
|
|
// return normally
|
|
return gwin.werrno=W_NOERROR;
|
|
}
|
|
|
|
|
|
// ------------------------------------------------------------------
|
|
// Proportion bar
|
|
|
|
void wpropbar(int xx, int yy, long len, vattr attr, long pos, long size) {
|
|
|
|
// xx, yy = start position in window.
|
|
// len = length (in chars) of progress field.
|
|
// attr = color to use for progress field.
|
|
// pos = present position.
|
|
// size = total size of field.
|
|
|
|
const vchar barchar = _box_table(gwin.active->btype, 13);
|
|
#ifdef __UNIX__ // prefferable under xterm
|
|
const vchar thumbchar = ' ';
|
|
vattr thumbattr = revsattr(attr);
|
|
#else
|
|
const vchar thumbchar = '\xDB';
|
|
vattr thumbattr = attr;
|
|
#endif
|
|
|
|
long thumblen = (pos*len)/size;
|
|
|
|
int x = xx;
|
|
if(thumblen != 0) {
|
|
wputx(yy, x, thumbattr|ACSET, thumbchar, thumblen);
|
|
x += thumblen;
|
|
}
|
|
if(thumblen != len)
|
|
wputx(yy, x, attr|ACSET, barchar, len-thumblen);
|
|
}
|
|
|
|
|
|
// ------------------------------------------------------------------
|
|
// Gives active window a title
|
|
|
|
int wtitle(const char* str, int tpos, vattr tattr) {
|
|
|
|
// check for active window
|
|
if(!gwin.total)
|
|
return gwin.werrno=W_NOACTIVE;
|
|
|
|
// redraw box if deleting or moving title
|
|
if(str==NULL or gwin.active->title!=NULL) {
|
|
if(gwin.active->border) {
|
|
vputx(
|
|
((tpos&TBOTTOM) ? gwin.active->erow : gwin.active->srow),
|
|
gwin.active->scol+1,
|
|
gwin.active->battr|ACSET,
|
|
_box_table(gwin.active->btype, (tpos&TBOTTOM)?6:1),
|
|
gwin.active->ecol-gwin.active->scol-1
|
|
);
|
|
}
|
|
}
|
|
|
|
// if not deleting the title, calculate position and display it
|
|
if(str) {
|
|
|
|
int left = gwin.active->scol+1;
|
|
int right = gwin.active->ecol-1;
|
|
int width = right-left+1;
|
|
int len = strlen(str);
|
|
|
|
// don't display title if window is borderless
|
|
if(gwin.active->border) {
|
|
|
|
int start;
|
|
|
|
switch(tpos&~TBOTTOM) {
|
|
case TLEFT:
|
|
//start = (len>(width-3)) ? left : (left+1);
|
|
start = left;
|
|
break;
|
|
case TCENTER:
|
|
start = (len>(width-2)) ? left : (((width/2)+left)-(len/2));
|
|
break;
|
|
default: // default is TRIGHT
|
|
{
|
|
int offs = width-len;
|
|
if(offs>2)
|
|
offs--;
|
|
start = (len>width) ? left : (left+offs+1);
|
|
}
|
|
}
|
|
|
|
// allocate space for window title string, and copy it there
|
|
char* p = (char*)throw_xmalloc(((width>len) ? width : len)+1);
|
|
if(p==NULL)
|
|
return gwin.werrno=W_ALLOCERR;
|
|
strcpy(p, str);
|
|
*(p+width) = NUL;
|
|
|
|
// display title string
|
|
vputs((tpos&TBOTTOM)?gwin.active->erow:gwin.active->srow, start, tattr, p);
|
|
|
|
// free allocated space
|
|
throw_xfree(p);
|
|
|
|
}
|
|
}
|
|
|
|
// update window's record
|
|
gwin.active->title=str;
|
|
gwin.active->tpos=tpos;
|
|
gwin.active->tattr=tattr;
|
|
|
|
// return normally
|
|
return gwin.werrno=W_NOERROR;
|
|
}
|
|
|
|
|
|
// ------------------------------------------------------------------
|
|
|
|
void wscrollbar(int orientation, uint total, uint maxpos, uint pos, int sadd) {
|
|
|
|
vattr attr = (gwin.active->sbattr == DEFATTR) ? gwin.active->battr : gwin.active->sbattr;
|
|
vattr invattr = revsattr(attr);
|
|
|
|
const vchar barchar = _box_table(gwin.active->btype, 13);
|
|
const vchar arrowupchar = '\x18';
|
|
const vchar arrowdownchar = '\x19';
|
|
const vchar arrowleftchar = '\x1B';
|
|
const vchar arrowrightchar = '\x1A';
|
|
#ifdef __UNIX__ // prefferable under xterm
|
|
const vchar thumbchar = ' ';
|
|
vattr thumbattr = revsattr(attr);
|
|
#else
|
|
const vchar thumbchar = '\xDB';
|
|
vattr thumbattr = attr;
|
|
#endif
|
|
|
|
if(maxpos == 0)
|
|
maxpos = 1;
|
|
|
|
uint visiblelen;
|
|
if(orientation == W_VERT)
|
|
visiblelen = (gwin.active->erow - (gwin.active->srow+sadd)) + 1 - (gwin.active->border?2:0);
|
|
else
|
|
visiblelen = (gwin.active->ecol - (gwin.active->scol+sadd)) + 1 - (gwin.active->border?2:0) - 2;
|
|
uint barlen = visiblelen - 2;
|
|
uint thumblen = (visiblelen*barlen) / total;
|
|
if(thumblen == 0)
|
|
thumblen = 1;
|
|
else if(thumblen > barlen)
|
|
thumblen = barlen;
|
|
uint maxthumbpos = barlen - thumblen;
|
|
uint thumbpos = (pos*maxthumbpos) / maxpos;
|
|
uint thumbdiv = (pos*maxthumbpos) % maxpos;
|
|
if((thumbdiv >= (maxpos/2)) and (maxpos > 1))
|
|
thumbpos++;
|
|
if(thumbpos > maxthumbpos)
|
|
thumbpos = maxthumbpos;
|
|
barlen -= thumbpos + thumblen;
|
|
|
|
if(orientation == W_VERT) {
|
|
uint scol = gwin.active->ecol - gwin.active->scol - gwin.active->border;
|
|
vputc((sadd++)+gwin.active->srow+gwin.active->border, gwin.active->ecol, invattr|ACSET, arrowupchar);
|
|
if(thumbpos != 0) {
|
|
wputy(sadd, scol, attr|ACSET, barchar, thumbpos);
|
|
sadd += thumbpos;
|
|
}
|
|
if(thumblen != 0) {
|
|
wputy(sadd, scol, thumbattr|ACSET, thumbchar, thumblen);
|
|
sadd += thumblen;
|
|
}
|
|
if(barlen != 0) {
|
|
wputy(sadd, scol, attr|ACSET, barchar, barlen);
|
|
sadd += barlen;
|
|
}
|
|
vputc(sadd+gwin.active->srow+gwin.active->border, gwin.active->ecol, invattr|ACSET, arrowdownchar);
|
|
}
|
|
else {
|
|
uint srow = gwin.active->erow - gwin.active->srow - gwin.active->border;
|
|
vputc(gwin.active->erow, (sadd++)+gwin.active->scol+gwin.active->border, invattr|ACSET, arrowleftchar);
|
|
if(thumbpos != 0) {
|
|
wputx(srow, sadd, attr|ACSET, barchar, thumbpos);
|
|
sadd += thumbpos;
|
|
}
|
|
if(thumblen != 0) {
|
|
wputx(srow, sadd, thumbattr|ACSET, thumbchar, thumblen);
|
|
sadd += thumblen;
|
|
}
|
|
if(barlen != 0) {
|
|
wputx(srow, sadd, attr|ACSET, barchar, barlen);
|
|
sadd += barlen;
|
|
}
|
|
vputc(gwin.active->erow, sadd+gwin.active->scol+gwin.active->border, invattr|ACSET, arrowrightchar);
|
|
}
|
|
}
|
|
|
|
|
|
// ------------------------------------------------------------------
|