#include <windows.h>
#include <string.h>
#include <assert.h>
#include "screen.h"
#define ScreenClearAttrib 0
SCREENLINE *
GetScreenLineFromY(SCREEN *pScr, int y)
{
SCREENLINE *pScrLine;
int idx;
pScrLine = pScr->screen_top;
for (idx = 0; idx < pScr->height; idx++) {
if (idx == y)
return(pScrLine);
if (pScrLine == NULL)
return(NULL);
pScrLine = pScrLine->next;
}
return(NULL);
}
SCREENLINE *
ScreenClearLine(SCREEN *pScr, SCREENLINE *pScrLine)
{
memset(pScrLine->attrib, ScreenClearAttrib, pScr->width);
memset(pScrLine->text, ' ', pScr->width);
return(pScrLine);
}
void
ScreenUnscroll(SCREEN *pScr)
{
int idx;
SCREENLINE *pScrLine;
if (pScr->screen_bottom == pScr->buffer_bottom)
return;
pScr->screen_bottom = pScr->buffer_bottom;
pScrLine = pScr->screen_bottom;
for (idx = 1; idx < pScr->height; idx++) {
if (pScrLine == NULL)
return;
pScrLine = pScrLine->prev;
}
pScr->screen_top = pScrLine;
}
void
ScreenCursorOn(SCREEN *pScr)
{
int y;
int nlines;
if (pScr->screen_bottom != pScr->buffer_bottom)
nlines = pScr->numlines - GetScrollPos(pScr->hWnd, SB_VERT);
else
nlines = 0;
y = pScr->y + nlines;
SetCaretPos(pScr->x * pScr->cxChar, (y+1) * pScr->cyChar);
ShowCaret(pScr->hWnd);
}
void
ScreenCursorOff(SCREEN *pScr)
{
HideCaret(pScr->hWnd);
}
void
ScreenELO(SCREEN *pScr, int s)
{
SCREENLINE *pScrLine;
RECT rc;
if (s < 0)
s = pScr->y;
pScrLine = GetScreenLineFromY(pScr,s);
memset(pScrLine->attrib, ScreenClearAttrib, pScr->width);
memset(pScrLine->text, ' ', pScr->width);
rc.left = 0;
rc.right = pScr->width * pScr->cxChar;
rc.top = pScr->cyChar * s;
rc.bottom = pScr->cyChar * (s+1);
InvalidateRect(pScr->hWnd, &rc, TRUE);
}
void
ScreenEraseScreen(SCREEN *pScr)
{
int i;
int x1 = 0;
int y1 = 0;
int x2 = pScr->width;
int y2 = pScr->height;
int n = -1;
for(i = 0; i < pScr->height; i++)
ScreenELO(pScr,i);
InvalidateRect(pScr->hWnd, NULL, TRUE);
UpdateWindow(pScr->hWnd);
}
void
ScreenTabClear(SCREEN *pScr)
{
int x = 0;
while(x <= pScr->width) {
pScr->tabs[x] = ' ';
x++;
}
}
void
ScreenTabInit(SCREEN *pScr)
{
int x = 0;
ScreenTabClear(pScr);
while(x <= pScr->width) {
pScr->tabs[x] = 'x';
x += 8;
}
pScr->tabs[pScr->width] = 'x';
}
void
ScreenReset(SCREEN *pScr)
{
pScr->top = 0;
pScr->bottom = pScr->height-1;
pScr->parmptr = 0;
pScr->escflg = 0;
pScr->DECAWM = 1;
pScr->bWrapPending = FALSE;
pScr->DECCKM = 0;
pScr->DECPAM = 0;
pScr->IRM = 0;
pScr->attrib = 0;
pScr->x = 0;
pScr->y = 0;
ScreenEraseScreen(pScr);
ScreenTabInit(pScr);
#if 0
set_vtwrap(pScrn, pScr->DECAWM);
#endif
}
void
ScreenListMove(SCREENLINE *TD, SCREENLINE *BD, SCREENLINE *TI, SCREENLINE *BI)
{
if (TD->prev != NULL)
TD->prev->next = BD->next;
if (BD->next != NULL)
BD->next->prev = TD->prev;
TD->prev = TI;
BD->next = BI;
if (TI != NULL)
TI->next = TD;
if (BI != NULL)
BI->prev = BD;
}
void
ScreenDelLines(SCREEN *pScr, int n, int s)
{
SCREENLINE *BI;
SCREENLINE *TI;
SCREENLINE *TD;
SCREENLINE *BD;
SCREENLINE *pLine;
int idx;
RECT rc;
HDC hDC;
pScr->bWrapPending = FALSE;
if (s < 0)
s = pScr->y;
if (s + n - 1 > pScr->bottom)
n = pScr->bottom - s + 1;
TD = GetScreenLineFromY(pScr, s);
BD = GetScreenLineFromY(pScr, s + n - 1);
TI = GetScreenLineFromY(pScr, pScr->bottom);
BI = TI->next;
if (TD == pScr->screen_top) {
if (pScr->screen_top == pScr->buffer_top)
pScr->buffer_top = BD->next;
pScr->screen_top = BD->next;
}
if (TI == pScr->screen_bottom) {
if (pScr->screen_bottom == pScr->buffer_bottom)
pScr->buffer_bottom = BD;
pScr->screen_bottom = BD;
}
if (TI != BD)
ScreenListMove(TD, BD, TI, BI);
pLine = TI;
for (idx = 0; idx < n; idx++) {
pLine = pLine->next;
ScreenClearLine(pScr, pLine);
}
rc.left = 0;
rc.right = pScr->width * pScr->cxChar;
rc.top = s * pScr->cyChar;
rc.bottom = (pScr->bottom + 1) * pScr->cyChar;
hDC = GetDC(pScr->hWnd);
ScrollDC(hDC, 0, -pScr->cyChar * n, &rc, &rc, NULL, NULL);
PatBlt(hDC, 0, (pScr->bottom - n + 1) * pScr->cyChar,
pScr->width * pScr->cxChar, n * pScr->cyChar, WHITENESS);
ReleaseDC(pScr->hWnd, hDC);
}
void
ScreenInsertLine(SCREEN *pScr, int s)
{
ScreenInsLines(pScr, 1, s);
}
void
ScreenInsLines(SCREEN *pScr, int n, int s)
{
SCREENLINE *TI;
SCREENLINE *BI;
SCREENLINE *TD;
SCREENLINE *BD;
SCREENLINE *pLine;
int idx;
RECT rc;
HDC hDC;
pScr->bWrapPending = FALSE;
if (s < 0)
s = pScr->y;
if (s + n - 1 > pScr->bottom)
n = pScr->bottom - s + 1;
BI = GetScreenLineFromY(pScr, s);
TI = BI->prev;
TD = GetScreenLineFromY(pScr, pScr->bottom - n + 1);
BD = GetScreenLineFromY(pScr, pScr->bottom);
if (BI == pScr->screen_top) {
if (pScr->screen_top == pScr->buffer_top)
pScr->buffer_top = TD;
pScr->screen_top = TD;
}
if (BD == pScr->screen_bottom) {
if (pScr->screen_bottom == pScr->buffer_bottom)
pScr->buffer_bottom = TD->prev;
pScr->screen_bottom = TD->prev;
}
if (TD != BI)
ScreenListMove(TD,BD,TI,BI);
pLine = GetScreenLineFromY(pScr, s);
for (idx = 0; idx < n; idx++) {
ScreenClearLine(pScr, pLine);
pLine = pLine->next;
}
rc.left = 0;
rc.right = pScr->width * pScr->cxChar;
rc.top = s * pScr->cyChar;
rc.bottom = (pScr->bottom + 1) * pScr->cyChar;
hDC = GetDC(pScr->hWnd);
ScrollDC(hDC, 0, pScr->cyChar * n, &rc, &rc, NULL, NULL);
PatBlt(hDC, 0, s * pScr->cyChar,
pScr->width * pScr->cxChar, n * pScr->cyChar, WHITENESS);
ReleaseDC(pScr->hWnd, hDC);
}
void
ScreenIndex(SCREEN * pScr)
{
if (pScr->y >= pScr->bottom)
ScreenScroll(pScr);
else
pScr->y++;
pScr->bWrapPending = FALSE;
}
void
ScreenWrapNow(SCREEN *pScr, int *xp, int *yp)
{
if (pScr->bWrapPending && pScr->x >= pScr->width - 1) {
pScr->x = 0;
ScreenIndex(pScr);
}
pScr->bWrapPending = FALSE;
*xp = pScr->x;
*yp = pScr->y;
}
void
ScreenEraseToEOL(SCREEN *pScr)
{
int x1 = pScr->x;
int y1 = pScr->y;
int x2 = pScr->width;
int y2 = pScr->y;
int n = -1;
SCREENLINE *pScrLine;
RECT rc;
ScreenWrapNow(pScr, &x1, &y1);
y2 = y1;
#if 0
wsprintf(strTmp,"[EraseEOL:%d]",y2);
OutputDebugString(strTmp);
#endif
pScrLine = GetScreenLineFromY(pScr,y2);
memset(&pScrLine->attrib[x1], ScreenClearAttrib, pScr->width-x1+1);
memset(&pScrLine->text[x1], ' ', pScr->width - x1 + 1);
rc.left = x1 * pScr->cxChar;
rc.right = pScr->width * pScr->cxChar;
rc.top = pScr->cyChar * y1;
rc.bottom = pScr->cyChar * (y1 + 1);
InvalidateRect(pScr->hWnd, &rc, TRUE);
UpdateWindow(pScr->hWnd);
}
void
ScreenDelChars(SCREEN *pScr, int n)
{
int x = pScr->x;
int y = pScr->y;
int width;
SCREENLINE *pScrLine;
RECT rc;
pScr->bWrapPending = FALSE;
pScrLine = GetScreenLineFromY(pScr, y);
width = pScr->width - x - n;
if (width > 0) {
memmove(&pScrLine->attrib[x], &pScrLine->attrib[x + n], width);
memmove(&pScrLine->text[x], &pScrLine->text[x + n], width);
}
memset(&pScrLine->attrib[pScr->width - n], ScreenClearAttrib, n);
memset(&pScrLine->text[pScr->width - n], ' ', n);
rc.left = x * pScr->cxChar;
rc.right = pScr->width * pScr->cxChar;
rc.top = pScr->cyChar * y;
rc.bottom = pScr->cyChar * (y + 1);
InvalidateRect(pScr->hWnd, &rc, TRUE);
UpdateWindow(pScr->hWnd);
}
void
ScreenRevIndex(SCREEN *pScr)
{
SCREENLINE *pScrLine;
SCREENLINE *pTopLine;
pScr->bWrapPending = FALSE;
pScrLine = GetScreenLineFromY(pScr, pScr->y);
pTopLine = GetScreenLineFromY(pScr, pScr->top);
if(pScrLine == pTopLine)
ScreenInsertLine(pScr, pScr->y);
else
pScr->y--;
}
void
ScreenEraseToBOL(SCREEN *pScr)
{
int x1 = 0;
int y1 = pScr->y;
int x2 = pScr->x;
int y2 = pScr->y;
int n = -1;
SCREENLINE *pScrLine;
pScrLine = GetScreenLineFromY(pScr, pScr->y);
ScreenWrapNow(pScr, &x2, &y1);
y2 = y1;
memset(pScrLine->attrib, ScreenClearAttrib, x2);
memset(pScrLine->text, ' ', x2);
}
void
ScreenEraseLine(SCREEN *pScr, int s)
{
int x1 = 0;
int y1 = s;
int x2 = pScr->width;
int y2 = s;
int n = -1;
SCREENLINE *pScrLine;
RECT rc;
if (s < 0) {
ScreenWrapNow(pScr, &x1, &y1);
s = y2 = y1;
x1 = 0;
}
pScrLine = GetScreenLineFromY(pScr,y1);
memset(pScrLine->attrib, ScreenClearAttrib, pScr->width);
memset(pScrLine->text, ' ', pScr->width);
rc.left = 0;
rc.right = pScr->width * pScr->cxChar;
rc.top = pScr->cyChar * y1;
rc.bottom = pScr->cyChar * (y1+1);
InvalidateRect(pScr->hWnd, &rc, TRUE);
SendMessage(pScr->hWnd, WM_PAINT, 0, 0);
}
void
ScreenEraseToEndOfScreen(SCREEN *pScr)
{
int i;
int x1 = 0;
int y1 = pScr->y+1;
int x2 = pScr->width;
int y2 = pScr->height;
int n = -1;
ScreenWrapNow(pScr, &x1, &y1);
y1++;
x1 = 0;
i = y1;
ScreenEraseToEOL(pScr);
while (i < pScr->height) {
ScreenELO(pScr, i);
ScreenEraseLine(pScr, i);
i++;
}
}
void
ScreenRange(SCREEN *pScr)
{
if (pScr->x < 0)
pScr->x = 0;
if (pScr->x >= pScr->width)
pScr->x = pScr->width - 1;
if (pScr->y < 0)
pScr->y = 0;
if (pScr->y >= pScr->height)
pScr->y = pScr->height - 1;
}
void
ScreenAlign(SCREEN *pScr)
{
char *tt;
int i;
int j;
SCREENLINE *pScrLine;
pScrLine = GetScreenLineFromY(pScr, pScr->top);
ScreenEraseScreen(pScr);
for(j = 0; j < pScr->height; j++) {
tt = &pScrLine->text[0];
for(i = 0; i <= pScr->width; i++)
*tt++ = 'E';
pScrLine = pScrLine->next;
}
}
void
ScreenApClear(SCREEN *pScr)
{
for(pScr->parmptr=5; pScr->parmptr>=0; pScr->parmptr--)
pScr->parms[pScr->parmptr] = -1;
pScr->parmptr = 0;
}
void
ScreenSetOption(SCREEN *pScr, int toggle)
{
if (pScr->parms[0] == -2 && pScr->parms[1] == 1)
pScr->DECCKM = toggle;
#if 0
switch(pScr->parms[0]) {
case -2:
switch(pScr->parms[1]) {
case 1:
pScr->DECCKM = toggle;
break;
#ifdef NOT_SUPPORTED
case 2:
break;
#endif
case 3:
pScr->x = pScr->y = 0;
ScreenEraseScreen(pScr);
#if 0
if (toggle)
pScr->width = pScr->allwidth;
else
pScr->width = 79;
#endif
break;
#ifdef NOT_SUPPORTED
case 4:
case 5:
case 6:
pScr->DECORG = toggle;
break;
#endif
case 7:
pScr->DECAWM = toggle;
#if 0
set_vtwrap(pScrn, fpScr->DECAWM);
#endif
break;
#ifdef NOT_SUPPORTED
case 8:
case 9:
break;
#endif
default:
break;
}
break;
case 4:
pScr->IRM=toggle;
break;
default:
break;
}
#endif
}
#ifdef NOT_SUPPORTED
void
ScreenTab(SCREEN *pScr)
{
if (pScr->x> = pScr->width)
pScr->x = pScr->width;
pScr->x++;
while (pScr->tabs[fpScr->x] != 'x' && pScr->x < pScr->width)
pScr->x++;
}
#endif
BOOL
ScreenInsChar(SCREEN *pScr, int x)
{
int i;
SCREENLINE *pScrLine;
RECT rc;
pScrLine = GetScreenLineFromY(pScr, pScr->y);
if (pScrLine == NULL)
return(FALSE);
for(i = pScr->width - x; i >= pScr->x; i--) {
pScrLine->text[x+i] = pScrLine->text[i];
pScrLine->attrib[x+i] = pScrLine->attrib[i];
}
memset(&pScrLine->attrib[pScr->x], ScreenClearAttrib, x);
memset(&pScrLine->text[pScr->x], ' ', x);
rc.left = pScr->cxChar * x;
rc.right = pScr->cxChar * (x + pScr->x);
rc.top = pScr->cyChar * (pScr->y - 1);
rc.bottom = pScr->cyChar * pScr->y;
InvalidateRect(pScr->hWnd, &rc, TRUE);
SendMessage(pScr->hWnd, WM_PAINT, 0, 0);
return(TRUE);
}
void
ScreenSaveCursor(SCREEN *pScr)
{
pScr->Px = pScr->x;
pScr->Py = pScr->y;
pScr->Pattrib = pScr->attrib;
}
void
ScreenRestoreCursor(SCREEN *pScr)
{
pScr->x = pScr->Px;
pScr->y = pScr->Py;
ScreenRange(pScr);
}
void
ScreenDraw(SCREEN *pScr, int x, int y, int a, int len, char *c)
{
int idx;
SCREENLINE *pScrLine;
RECT rc;
pScrLine = GetScreenLineFromY(pScr, y);
assert(pScrLine != NULL);
for(idx = x; idx < x + len; idx++) {
pScrLine->text[idx] = c[idx - x];
pScrLine->attrib[idx - x] = a;
}
rc.left = pScr->cxChar * x;
rc.right = pScr->cxChar * (x + len);
rc.top = pScr->cyChar * pScr->y;
rc.bottom = pScr->cyChar * (pScr->y + 1);
InvalidateRect(pScr->hWnd, &rc, TRUE);
SendMessage(pScr->hWnd, WM_PAINT, 0, 0);
}
#if ! defined(NDEBUG)
BOOL
CheckScreen(SCREEN *pScr)
{
SCREENLINE *pLinePrev;
SCREENLINE *pLine;
int nscreen = 0;
int nbuffer = 0;
int topline = 0;
char buf[512];
BOOL bBottom;
BOOL bOK;
pLine = pScr->buffer_top;
if (pLine == NULL) {
OutputDebugString("CheckScreen: buffer_top invalid");
MessageBox(NULL, "buffer_top invalid", "CheckScreen", MB_OK);
return(FALSE);
}
bBottom = FALSE;
while (TRUE) {
pLinePrev = pLine;
if (nscreen > 0 || pLine == pScr->screen_top)
if (!bBottom)
nscreen++;
nbuffer++;
if (pLine == pScr->screen_top)
topline = nbuffer - 1;
if (pLine == pScr->screen_bottom)
bBottom = TRUE;
pLine = pLine->next;
if (pLine == NULL)
break;
if (pLine->prev != pLinePrev) {
wsprintf(buf,
"Previous ptr of line %d does not match next ptr of line %d",
nbuffer, nbuffer - 1);
OutputDebugString(buf);
MessageBox(NULL, buf, "CheckScreen", MB_OK);
}
}
if (pLinePrev == pScr->buffer_bottom && nscreen == pScr->height)
bOK = TRUE;
else {
OutputDebugString("CheckScreen: Invalid number of lines on screen");
bOK = FALSE;
}
wsprintf(buf, "screen.width = %d\nscreen.height = %d\nscreen.maxlines = %d\nscreen.numlines = %d\nscreen.x = %d\nscreen.y = %d\nscreen.top = %d\nscreen.bottom = %d\nActual top line = %d\nActual buffer lines = %d\nActual screen lines = %d\nBottom of buffer is %s",
pScr->width, pScr->height, pScr->maxlines, pScr->numlines,
pScr->x, pScr->y, pScr->top, pScr->bottom,
topline, nbuffer, nscreen,
(pLinePrev == pScr->buffer_bottom) ? "valid" : "invalid");
MessageBox(NULL, buf, "CheckScreen", MB_OK);
return(bOK);
}
#endif