/* * Smart terminal module * * Copyright (c) 1990, 1991 by * William S. Hall * 3665 Benton Street #66 * Santa Clara, CA 95051 * */ #define NOSOUND #define NOCOMM #define NOKANJI #define NOATOM #include #if defined(WIN2) #define SYMBOL_CHARSET 2 #include #endif #include #include #ifdef COLUMBIA #include "wktsmt.h" #else #include "smterm.h" #endif static void NEAR TermWndPaint(PSMT pSmt, LPPAINTSTRUCT lpps); static int NEAR SmartTermDisplay(PSMT pSmt, BYTE *str, short len); static void NEAR ComputeVisibleWindow(PSMT pSmt, short right, short bottom); static void NEAR DoCR(PSMT pSmt); static void NEAR DoLF(PSMT pSmt); static void NEAR DoBS(PSMT pSmt); static void NEAR AdjustWindowToCursor(PSMT pSmt); static void NEAR CursorUp(PSMT pSmt, int count); static void NEAR CursorDown(PSMT pSmt, int count); static void NEAR CursorRight(PSMT pSmt, int count); static void NEAR CursorLeft(PSMT pSmt, int count); static void NEAR ClearToEndOfLine(PSMT pSmt); static void NEAR ClearToEndOfPage(PSMT pSmt); static void NEAR PositionCursor(PSMT pSmt, short r, short c); static void NEAR ReverseIndex(PSMT pSmt); static void NEAR DoHT(PSMT pSmt); static void NEAR AlignScreen(PSMT pSmt); static void NEAR ClearScreen(PSMT pSmt); static void NEAR SaveCursor(PSMT pSmt, BOOL flag); static void NEAR ClearToTopOfPage(PSMT pSmt); static void NEAR ClearToLineStart(PSMT pSmt); static void NEAR ClearLine(PSMT pSmt); static void NEAR ShowLineOfText(PSMT pSmt, HDC hDC, BYTE *str, short len, short xpos, short ypos, BYTE attrib); static void NEAR InsertLine(PSMT pSmt, int count); static void NEAR DeleteLine(PSMT pSmt, int count); static void NEAR DeleteChar(PSMT pSmt, WORD count); static void NEAR SetTabStop(PSMT pSmt, LONG param); static void NEAR ChangeColors(PSMT pSmt, LONG *pColors); static void NEAR SetVideoAttrib(PSMT pSmt, WORD index); static void NEAR SetScrollRegion(PSMT pSmt, int top, int bottom); static void NEAR FillScreen(PSMT pSmt); static void NEAR SetScreen(PSMT pSmt, WORD rows, WORD cols); static long NEAR CalcScrollRange(PSMT pSmt, short xsize, short ysize); static void NEAR CopyLines(PSMT pSmt, short start, short end, LPSTR pbuf); static void NEAR FlipScreen(PSMT pSmt, short top, short bottom); static void NEAR SetCharSet(PSMT pSmt, WORD index); static void NEAR wordmemset(WORD *dest, WORD val, int count); static void NEAR scrollindex(PSMT pSmt, BOOL direction); static void NEAR SetOriginMode(PSMT pSmt, BOOL param); static void NEAR SmartTermCommand(register PSMT pSmt, register WORD wParam, LONG lParam); static void NEAR SetFont(PSMT pSmt, SETFONT FAR *lplf); static void NEAR ScrollBack(PSMT pSmt, int lines, BOOL direction); long FAR PASCAL SmartTermWndProc(HWND hWnd, unsigned message, WORD wParam, LONG lParam) { register PSMT pSmt = (PSMT)GetWindowWord(hWnd,0); PAINTSTRUCT ps; long numrem; switch(message) { case SMT_STRINGINPUT: HideCaret(hWnd); numrem = SmartTermDisplay(pSmt,(BYTE *)LOWORD(lParam),(short)wParam); SetCaretPos(pSmt->Pos.x, pSmt->Pos.y + pSmt->CharHeight); ShowCaret(hWnd); return ((LONG)numrem); break; case SMT_COMMAND: HideCaret(hWnd); SmartTermCommand(pSmt, wParam, lParam); SetCaretPos(pSmt->Pos.x, pSmt->Pos.y + pSmt->CharHeight); ShowCaret(hWnd); break; case SMT_SIZEPARENT: ComputeVisibleWindow(pSmt, LOWORD(lParam), HIWORD(lParam)); MoveWindow(pSmt->hStatic, pSmt->vrect.left, pSmt->vrect.top, pSmt->vrect.right, pSmt->vrect.bottom, TRUE); pSmt->rect.left = pSmt->rect.top = 0; MoveWindow(pSmt->hWnd,pSmt->rect.left, pSmt->rect.top, pSmt->rect.right, pSmt->rect.bottom,TRUE); AdjustWindowToCursor(pSmt); return(CalcScrollRange(pSmt,(short)LOWORD(lParam), (short)HIWORD(lParam))); break; case SMT_CARETFUNCTION: switch(wParam) { case SM_CREATECARET: if (HIWORD(lParam)) CreateCaret(pSmt->hWnd,(HBITMAP)NULL, pSmt->CharWidth,-pSmt->CharHeight); else CreateCaret(pSmt->hWnd,(HBITMAP)NULL, pSmt->CharWidth,-2); SetCaretPos(pSmt->Pos.x, pSmt->Pos.y + pSmt->CharHeight); if (LOWORD(lParam)) ShowCaret(pSmt->hWnd); break; case SM_DESTROYCARET: HideCaret(pSmt->hWnd); DestroyCaret(); break; case SM_HIDECARET: HideCaret(pSmt->hWnd); break; case SM_SHOWCARET: ShowCaret(pSmt->hWnd); break; case SM_GETCARETPOS: return(MAKELONG(1 + pSmt->Pos.y / pSmt->CharHeight, pSmt->CurLineOffset + 1)); } break; case SMT_SETATTRIBUTE: switch(wParam) { case SM_COLORCHANGE: ChangeColors(pSmt, (LONG *)LOWORD(lParam)); break; case SM_AUTOWRAP: pSmt->Wrap = LOWORD(lParam); break; case SM_MARGINBELL: pSmt->MarginBell = LOWORD(lParam); break; case SM_SMOOTHSCROLL: pSmt->SmoothScroll = LOWORD(lParam); break; case SM_INSERT: pSmt->ICToggle = LOWORD(lParam); break; case SM_SCROLLUNITS: pSmt->ScrollUnits = LOWORD(lParam); break; } break; case SMT_GETATTRIBUTE: switch(wParam) { case SM_AUTOWRAP: return((LONG)pSmt->Wrap); break; case SM_MARGINBELL: return((LONG)pSmt->MarginBell); break; case SM_SMOOTHSCROLL: return((LONG)pSmt->SmoothScroll); break; case SM_SCREENSIZE: return(MAKELONG(pSmt->MaxLines, pSmt->MaxCols)); break; case SM_FONTFACE: lstrcpy((LPSTR)lParam, pSmt->lfnt.lfFaceName); return lstrlen(pSmt->lfnt.lfFaceName); case SM_NORMALFONT: return MAKELONG(pSmt->NFontWidth, pSmt->NFontHeight); case SM_SMALLFONT: return MAKELONG(pSmt->SFontWidth, pSmt->SFontHeight); case SM_SCROLLUNITS: return (LONG)pSmt->ScrollUnits; } break; case SMT_SHOWWINDOW: ShowWindow(pSmt->hStatic, wParam); break; case SMT_INVERT: FlipScreen(pSmt, LOWORD(lParam), HIWORD(lParam)); break; case SMT_COPYLINES: CopyLines(pSmt, (int)LOBYTE(wParam), (int)HIBYTE(wParam), (LPSTR)lParam); break; case WM_CREATE: SmartTermWndCreate(hWnd, lParam); break; case WM_PAINT: BeginPaint(hWnd, (LPPAINTSTRUCT)&ps); TermWndPaint(pSmt, (LPPAINTSTRUCT)&ps); EndPaint(hWnd, (LPPAINTSTRUCT)&ps); break; case WM_ERASEBKGND: SelectObject((HDC)wParam, pSmt->hbr); FillRect((HDC)wParam, (LPRECT)&pSmt->rect, pSmt->hbr); return (LONG)TRUE; case WM_DESTROY: if (pSmt->hbr) DeleteObject(pSmt->hbr); if (pSmt->hFont) DeleteObject(pSmt->hFont); break; default: return ((long)DefWindowProc(hWnd,message,wParam,lParam)); break; } return(0L); } static void NEAR SmartTermCommand(register PSMT pSmt, register WORD wParam, LONG lParam) { switch(wParam) { case SM_CURSORHOME: pSmt->HaveToWrap = FALSE; PositionCursor(pSmt, 0, 0); break; case SM_CURSORUP: CursorUp(pSmt, LOWORD(lParam)); break; case SM_CURSORDOWN: CursorDown(pSmt, LOWORD(lParam)); break; case SM_CURSORRIGHT: CursorRight(pSmt, LOWORD(lParam)); break; case SM_CURSORLEFT: CursorLeft(pSmt, LOWORD(lParam)); break; case SM_CLRTOENDOFLINE: ClearToEndOfLine(pSmt); break; case SM_CLRTOENDOFPAGE: ClearToEndOfLine(pSmt); ClearToEndOfPage(pSmt); break; case SM_POSITIONCURSOR: pSmt->HaveToWrap = FALSE; PositionCursor(pSmt,(short)LOWORD(lParam) - 1, (short)HIWORD(lParam) - 1); break; case SM_REVERSEINDEX: while (lParam--) ReverseIndex(pSmt); break; case SM_INDEX: while (lParam--) DoLF(pSmt); break; case SM_NEXTLINE: while (lParam--) { DoCR(pSmt); DoLF(pSmt); } break; case SM_ALIGNSCREEN: AlignScreen(pSmt); break; case SM_SAVECURSOR: SaveCursor(pSmt, LOWORD(lParam)); break; case SM_CLEARSCREEN: ClearScreen(pSmt); break; case SM_CLEARTOTOPOFPAGE: ClearToTopOfPage(pSmt); ClearToLineStart(pSmt); break; case SM_CLEARTOLINESTART: ClearToLineStart(pSmt); break; case SM_CLEARLINE: ClearLine(pSmt); break; case SM_DELETECHAR: DeleteChar(pSmt, LOWORD(lParam)); break; case SM_INSERTLINE: InsertLine(pSmt, LOWORD(lParam)); break; case SM_DELETELINE: DeleteLine(pSmt, LOWORD(lParam)); break; case SM_SETTAB: SetTabStop(pSmt, lParam); break; case SM_VIDEOATTRIB: SetVideoAttrib(pSmt, LOWORD(lParam)); break; case SM_SCROLLREGION: SetScrollRegion(pSmt, LOWORD(lParam), HIWORD(lParam)); break; case SM_FILLSCREEN: FillScreen(pSmt); break; case SM_HSCROLL: pSmt->rect.left = -LOWORD(lParam) * pSmt->CharWidth; MoveWindow(pSmt->hWnd, pSmt->rect.left, pSmt->rect.top, pSmt->rect.right, pSmt->rect.bottom, TRUE); break; case SM_SETCOLS: SetScreen(pSmt, pSmt->MaxLines, LOWORD(lParam)); break; case SM_LEFTMARGIN: while (lParam--) DoCR(pSmt); break; case SM_TAB: while (lParam--) DoHT(pSmt); break; case SM_BKSP: while (lParam--) DoBS(pSmt); break; case SM_SETCHARSET: SetCharSet(pSmt, LOWORD(lParam)); break; case SM_ORIGINMODE: SetOriginMode(pSmt, LOWORD(lParam)); break; case SM_SETFONT: SetFont(pSmt, (SETFONT FAR *)lParam); break; case SM_SCROLLBACK: ScrollBack(pSmt, LOWORD(lParam), (BOOL)HIWORD(lParam)); break; case SM_PAGEBACK: ScrollBack(pSmt, pSmt->MaxLines, (BOOL)HIWORD(lParam)); break; case SM_HOMEEND: ScrollBack(pSmt, pSmt->MaxTextLines, (BOOL)HIWORD(lParam)); break; } } static void NEAR ScrollBack(PSMT pSmt, int numlines, BOOL direction) { register int buflines = pSmt->MaxTextLines; WORD *temp; register int i; if (direction) { numlines = min(numlines, pSmt->scrollback); if (numlines > 0) { for (i = 0; i < numlines; i++) { temp = pSmt->lines[buflines - 1]; memmove(&pSmt->lines[1], &pSmt->lines[0], (buflines - 1) * sizeof(WORD *)); pSmt->lines[0] = temp; } pSmt->scrollback -= numlines; pSmt->scrollforward += numlines; ScrollWindow(pSmt->hWnd,0,numlines * pSmt->CharHeight, NULL,&pSmt->srect); UpdateWindow(pSmt->hWnd); } } else { numlines = min(numlines, pSmt->scrollforward); if (numlines > 0) { for (i = 0; i < numlines; i++) { temp = pSmt->lines[0]; memmove(&pSmt->lines[0], &pSmt->lines[1], (buflines - 1) * sizeof(WORD *)); pSmt->lines[buflines - 1] = temp; } pSmt->scrollback += numlines; pSmt->scrollforward -= numlines; ScrollWindow(pSmt->hWnd, 0, -numlines * pSmt->CharHeight, NULL, &pSmt->srect); UpdateWindow(pSmt->hWnd); } } } static void NEAR SetFont(PSMT pSmt, SETFONT FAR *lpsf) { RECT size; pSmt->NFontWidth = lpsf->nwidth; pSmt->NFontHeight = lpsf->nheight; pSmt->SFontWidth = lpsf->swidth; pSmt->SFontHeight = lpsf->sheight; lstrcpy(pSmt->lfnt.lfFaceName, lpsf->FaceName); pSmt->hFont = SetFontData(pSmt); pSmt->srect.right = pSmt->rect.right = pSmt->CharWidth * pSmt->MaxCols; pSmt->srect.bottom = pSmt->rect.bottom = pSmt->CharHeight * pSmt->MaxLines; PositionCursor(pSmt, pSmt->CurLine, pSmt->CurLineOffset); GetClientRect(pSmt->hMain, &size); PostMessage(pSmt->hMain, WM_SIZE, SIZENORMAL, MAKELONG(size.right, size.bottom)); } static void NEAR SetCharSet(PSMT pSmt, WORD index) { register BYTE hattrib = (BYTE)HIBYTE((int)pSmt->Attrib); if (index) hattrib |= VA_SPECIAL; else hattrib &= ~VA_SPECIAL; pSmt->Attrib = 256 * hattrib; } /* character deletion */ static void NEAR DeleteChar(PSMT pSmt, WORD count) { RECT rect; short offset = pSmt->CurLineOffset; WORD *dest = pSmt->lines[pSmt->CurLine] + offset; register short copycount; register WORD maxdelchars; if (count > (maxdelchars = pSmt->MaxCols - offset)) count = maxdelchars; copycount = maxdelchars - count; memmove((BYTE *)dest, (BYTE *)(dest + count), copycount * sizeof (WORD)); wordmemset(dest + copycount, SP, count); SetRect(&rect, pSmt->Pos.x, pSmt->Pos.y, pSmt->rect.right, pSmt->Pos.y + pSmt->CharHeight); ScrollWindow(pSmt->hWnd,-pSmt->CharWidth * count, 0, &rect, &rect); UpdateWindow(pSmt->hWnd); } static void NEAR FlipScreen(PSMT pSmt, short top, short bottom) { register int i, j; WORD mask = 256 * VA_MARK; short cols = pSmt->MaxCols; RECT rect; if ((top < 0) || (bottom > pSmt->MaxLines)) return; for (i = top; i <= bottom; i++) for (j = 0; j < cols; j++) *(pSmt->lines[i] + j) ^= mask; rect.left = 0; rect.right = pSmt->rect.right; rect.top = top * pSmt->CharHeight; rect.bottom = (bottom + 1) * pSmt->CharHeight; InvalidateRect(pSmt->hWnd, &rect, FALSE); } static void NEAR CopyLines(PSMT pSmt, short start, short end, LPSTR pbuf) { register int i, j; short cols = pSmt->MaxCols; int count; for (i = start; i <= end; i++) { for (j = cols - 1; (j >= 0) && (LOBYTE(*(pSmt->lines[i] + j)) == SP); j--) ; count = j + 1; for (j = 0; j < count; j++) *pbuf++ = LOBYTE(*(pSmt->lines[i] + j)); *pbuf++ = '\r'; *pbuf++ = '\n'; } } static long NEAR CalcScrollRange(PSMT pSmt, short xsize, short ysize) { register short xrange, yrange; short diff; diff = pSmt->rect.right - xsize; if (diff > 0) { xrange = diff / pSmt->CharWidth; if (diff % pSmt->CharWidth) xrange += 1; } else xrange = 0; yrange = pSmt->rect.bottom - ysize; yrange = (yrange > 0 ? (yrange / pSmt->CharHeight) : 0); return MAKELONG(xrange, yrange); } static void NEAR SetScreen(PSMT pSmt, WORD rows, WORD cols) { short size = rows * cols; HFONT hfont, holdfont; HDC hDC; TEXTMETRIC TM; register int i,j; if (cols == MAXCOLUMNS) { pSmt->lfnt.lfWidth = pSmt->SFontWidth; pSmt->lfnt.lfHeight = pSmt->SFontHeight; pSmt->Bold = pSmt->SBold; pSmt->Symbol = pSmt->SSymbol; } else { pSmt->lfnt.lfWidth = pSmt->NFontWidth; pSmt->lfnt.lfHeight = pSmt->NFontHeight; pSmt->Bold = pSmt->NBold; pSmt->Symbol = pSmt->NSymbol; } hDC = GetDC(pSmt->hWnd); hfont = CreateFontIndirect(&pSmt->lfnt); holdfont = SelectObject(hDC, hfont); GetTextMetrics(hDC, &TM); pSmt->CharHeight = TM.tmHeight + TM.tmExternalLeading; pSmt->CharWidth = TM.tmAveCharWidth; SelectObject(hDC, holdfont); ReleaseDC(pSmt->hWnd, hDC); if (pSmt->hFont) DeleteObject(pSmt->hFont); pSmt->hFont = hfont; pSmt->MaxCols = cols; pSmt->MaxLines = rows; for (i = 0; i < MAXTEXTBUFFERS * pSmt->MaxLines; i++) { pSmt->lines[i] = (pSmt->pVidBuffer + i * MAXCOLUMNS); for (j = 0; j < MAXCOLUMNS; j++) *(pSmt->lines[i] + j) = SP; } pSmt->scrollback = 0; pSmt->scrollforward = 0; pSmt->TopScroll = pSmt->TopOrgLine = 0; pSmt->BottomScroll = pSmt->BottomOrgLine = pSmt->MaxLines - 1; pSmt->CurLine = 0; pSmt->CurLineOffset = 0; pSmt->Pos.x = pSmt->Pos.y = 0; pSmt->rect.left = pSmt->rect.top = 0; pSmt->srect.right = pSmt->rect.right = pSmt->CharWidth * pSmt->MaxCols; pSmt->srect.bottom = pSmt->rect.bottom = pSmt->CharHeight * pSmt->MaxLines; InvalidateRect(pSmt->hWnd, (LPRECT)NULL, TRUE); } static void NEAR SetVideoAttrib(PSMT pSmt, WORD index) { register BYTE hattrib = (BYTE)HIBYTE((int)pSmt->Attrib); register BYTE special = (BYTE)(hattrib & VA_SPECIAL); switch(index) { case 0: hattrib = (BYTE)(VA_NORMAL | special); break; case 1: hattrib |= VA_BOLD; break; case 4: hattrib |= VA_UNDERLINE; break; case 5: hattrib |= VA_BLINK; break; case 7: hattrib |= VA_REVERSE; break; case 8: hattrib |= VA_DIM; break; case 22: hattrib &= ~VA_BOLD; break; case 24: hattrib &= ~VA_UNDERLINE; break; case 25: hattrib &= ~VA_BLINK; break; case 27: hattrib &= ~VA_REVERSE; break; case 28: hattrib &= ~VA_DIM; break; } pSmt->Attrib = 256 * hattrib; } static void NEAR SetScrollRegion(PSMT pSmt, int top, int bottom) { register short max = pSmt->MaxLines; register short cheight = pSmt->CharHeight; if ((top <= max) && (bottom <= max)) { if (top == 0) top = 1; if (bottom == 0) bottom = max; if (top < bottom) { pSmt->srect.top = cheight * (top - 1); pSmt->srect.bottom = cheight * bottom; pSmt->TopScroll = top - 1; pSmt->BottomScroll = bottom - 1; if (pSmt->OriginMode) SetOriginMode(pSmt, TRUE); else PositionCursor(pSmt, 0, 0); } } } static void NEAR ChangeColors(register PSMT pSmt, LONG *pColors) { pSmt->TextColor = pColors[0]; pSmt->BGColor = pColors[1]; DeleteObject(pSmt->hbr); pSmt->hbr = CreateSolidBrush(pSmt->BGColor); InvalidateRect(pSmt->hWnd, (LPRECT)NULL, TRUE); } static void NEAR InsertLine(register PSMT pSmt, int count) { register int i; WORD *save[MAXROWS]; RECT rect; short top = pSmt->TopScroll; short cur = pSmt->CurLine; short bottom = pSmt->BottomScroll; short len; if ((top <= cur) && (cur <= bottom)) { count = min(bottom - cur + 1, count); len = bottom - count + 1; for (i = 0; i < count; i++) save[cur + i] = pSmt->lines[len + i]; for (i = bottom; i >= cur + count; i--) pSmt->lines[i] = pSmt->lines[i - count]; for (i = cur; i < cur + count; i++) { pSmt->lines[i] = save[i]; wordmemset(pSmt->lines[i], SP, pSmt->MaxCols); } DoCR(pSmt); SetRect(&rect, 0, pSmt->Pos.y, pSmt->srect.right, pSmt->srect.bottom); ScrollWindow(pSmt->hWnd, 0, count * pSmt->CharHeight, &rect, &rect); UpdateWindow(pSmt->hWnd); } } static void NEAR DeleteLine(PSMT pSmt, int count) { register int i; WORD *save[MAXROWS]; RECT rect; short top = pSmt->TopScroll; short cur = pSmt->CurLine; short bottom = pSmt->BottomScroll; short len; if ((top <= cur) && (cur <= bottom)) { count = min(bottom - cur + 1, count); len = bottom - count + 1; for (i = 0; i < count; i++) save[len + i] = pSmt->lines[cur + i]; for (i = cur + count; i <= bottom; i++) pSmt->lines[i - count] = pSmt->lines[i]; for (i = len; i <= bottom; i++) { pSmt->lines[i] = save[i]; wordmemset(pSmt->lines[i], SP, pSmt->MaxCols); } DoCR(pSmt); SetRect(&rect, 0, pSmt->Pos.y, pSmt->srect.right, pSmt->srect.bottom); ScrollWindow(pSmt->hWnd, 0, -count * pSmt->CharHeight, &rect, &rect); UpdateWindow(pSmt->hWnd); } } static void NEAR SaveCursor(PSMT pSmt, BOOL flag) { if (flag) { pSmt->CurSaveX = pSmt->CurLineOffset; pSmt->CurSaveY = pSmt->CurLine; pSmt->SaveAttrib = pSmt->Attrib; // pSmt->SaveCharSet = lfnt.lfCharSet; } else { PositionCursor(pSmt, pSmt->CurSaveY, pSmt->CurSaveX); pSmt->Attrib = pSmt->SaveAttrib; // lfnt.lfCharSet = pSmt->SaveCharSet; } } static void NEAR SetTabStop(PSMT pSmt, LONG param) { register BOOL set = LOWORD(param); register WORD val = HIWORD(param); if (set) pSmt->TabStops[pSmt->CurLineOffset] = 'T'; else { if (val == 3) memset(pSmt->TabStops, SP, MAXCOLUMNS); else if (val == 0) pSmt->TabStops[pSmt->CurLineOffset] = SP; } } static void NEAR ClearToEndOfLine(PSMT pSmt) { RECT rect; register short offset = pSmt->CurLineOffset; register short ypos = pSmt->Pos.y; wordmemset(pSmt->lines[pSmt->CurLine] + offset,SP,pSmt->MaxCols - offset); SetRect(&rect,pSmt->Pos.x,ypos,pSmt->rect.right,ypos + pSmt->CharHeight); InvalidateRect(pSmt->hWnd, (LPRECT)&rect, TRUE); UpdateWindow(pSmt->hWnd); } static void NEAR ClearToLineStart(PSMT pSmt) { RECT rect; register short offset = pSmt->CurLineOffset+ 1; register short width = offset * pSmt->CharWidth; wordmemset(pSmt->lines[pSmt->CurLine], SP, offset); SetRect(&rect, 0, pSmt->Pos.y, width, pSmt->Pos.y + pSmt->CharHeight); InvalidateRect(pSmt->hWnd, (LPRECT)&rect, TRUE); UpdateWindow(pSmt->hWnd); } static void NEAR ClearLine(PSMT pSmt) { RECT rect; wordmemset(pSmt->lines[pSmt->CurLine], SP, pSmt->MaxCols); SetRect((LPRECT)&rect, 0, pSmt->Pos.y, pSmt->rect.right, pSmt->Pos.y + pSmt->CharHeight); InvalidateRect(pSmt->hWnd, (LPRECT)&rect, TRUE); UpdateWindow(pSmt->hWnd); } static void NEAR ClearToEndOfPage(PSMT pSmt) { RECT rect; register int i; for (i = pSmt->CurLine; i < pSmt->MaxLines; i++) wordmemset(pSmt->lines[i], SP, pSmt->MaxCols); SetRect(&rect, 0, pSmt->Pos.y + pSmt->CharHeight, pSmt->rect.right, pSmt->rect.bottom); InvalidateRect(pSmt->hWnd, &rect, TRUE); UpdateWindow(pSmt->hWnd); } static void NEAR ClearToTopOfPage(PSMT pSmt) { RECT rect; register int i; for (i = 0; i < pSmt->CurLine; i++) wordmemset(pSmt->lines[i], SP, pSmt->MaxCols); SetRect(&rect, 0, 0, pSmt->rect.right, pSmt->Pos.y); InvalidateRect(pSmt->hWnd, &rect, TRUE); UpdateWindow(pSmt->hWnd); } static void NEAR ClearScreen(PSMT pSmt) { register int i; for (i = 0; i < pSmt->MaxLines; i++) wordmemset(pSmt->lines[i], SP, pSmt->MaxCols); InvalidateRect(pSmt->hWnd, NULL, TRUE); UpdateWindow(pSmt->hWnd); } static void NEAR AlignScreen(PSMT pSmt) { register int i; for (i = 0; i < pSmt->MaxLines; i++) wordmemset(pSmt->lines[i], 'E', pSmt->MaxCols); InvalidateRect(pSmt->hWnd, NULL, TRUE); UpdateWindow(pSmt->hWnd); PositionCursor(pSmt, 0, 0); } static void NEAR FillScreen(PSMT pSmt) { register int i,j; BYTE ch = 0; for (i = 0; i < pSmt->MaxLines; i++) for (j = 0; j < pSmt->MaxCols; j++) *(pSmt->lines[i] + j) = (WORD)ch++; InvalidateRect(pSmt->hWnd, NULL, TRUE); UpdateWindow(pSmt->hWnd); PositionCursor(pSmt, 0, 0); } static void NEAR SetOriginMode(PSMT pSmt, BOOL param) { if (param) { pSmt->TopOrgLine = pSmt->TopScroll; pSmt->BottomOrgLine = pSmt->BottomScroll; } else { pSmt->TopOrgLine = 0; pSmt->BottomOrgLine = (pSmt->MaxLines - 1); } pSmt->OriginMode = param; PositionCursor(pSmt, 0, 0); } static void NEAR PositionCursor(PSMT pSmt, short r, short c) { register short rows = pSmt->BottomOrgLine; register short cols = pSmt->MaxCols; if (c >= cols) c = cols - 1 ; pSmt->Pos.x = c * pSmt->CharWidth; pSmt->CurLineOffset = c; r += pSmt->TopOrgLine; if (r > rows) r = rows; pSmt->Pos.y = r * pSmt->CharHeight; pSmt->CurLine = r; AdjustWindowToCursor(pSmt); } static int NEAR SmartTermDisplay(PSMT pSmt, BYTE *str, short len) { register BYTE *ptr; register short ctr; short cols = pSmt->MaxCols; short cwidth = pSmt->CharWidth; short width = pSmt->rect.right; short txpos; short toff; WORD *tBuf; WORD attrib = pSmt->Attrib; WORD savebuf[MAXCOLUMNS]; while (len > 0) { ptr = str; ctr = 0; toff = pSmt->CurLineOffset; if (pSmt->HaveToWrap && pSmt->Wrap && (toff == (cols - 1))) { DoCR(pSmt); DoLF(pSmt); toff = pSmt->CurLineOffset; pSmt->HaveToWrap = FALSE; } txpos = pSmt->Pos.x; tBuf = pSmt->lines[pSmt->CurLine]; while ((len > 0) && (toff < cols)) { if (pSmt->ICToggle) savebuf[ctr] = *(tBuf + toff); *(tBuf + toff++) = *ptr++ + attrib; if ((pSmt->MarginBell) && (toff == (cols - 8))) MessageBeep(0); ctr += 1; txpos += cwidth; len -= 1; } if (ctr) { if (pSmt->ICToggle) { RECT rect; short ypos = pSmt->Pos.y; short xpos = pSmt->Pos.x; short tomove, tocopy; tomove = cols - toff - ctr; tocopy = min (ctr, cols - toff); if (tomove > 0) memmove(tBuf + toff + ctr, tBuf + toff, tomove); if (tocopy > 0) strncpy((BYTE *)(tBuf + toff), (BYTE *)savebuf, sizeof(WORD) * tocopy); SetRect(&rect, xpos, ypos, width, ypos + pSmt->CharHeight); ScrollWindow(pSmt->hWnd, txpos - xpos, 0, &rect, &rect); UpdateWindow(pSmt->hWnd); } else { HDC hDC = GetDC(pSmt->hWnd); ShowLineOfText(pSmt,hDC,str,ctr,pSmt->Pos.x,pSmt->Pos.y, (BYTE)HIBYTE(attrib)); ReleaseDC(pSmt->hWnd, hDC); } if (toff < cols) { pSmt->Pos.x = txpos; pSmt->CurLineOffset = toff; pSmt->HaveToWrap = FALSE; } else { pSmt->CurLineOffset = (cols - 1); pSmt->Pos.x = width - cwidth; pSmt->HaveToWrap = TRUE; } } str = ptr; } return (len); } static void NEAR ShowLineOfText(PSMT pSmt, HDC hDC, BYTE *str, short len, short xpos, short ypos, BYTE attrib) { HFONT hfont, holdfont; register BOOL underline = attrib & VA_UNDERLINE; register BOOL bold = (attrib & VA_BOLD) && pSmt->Bold; BOOL special = (attrib & VA_SPECIAL) && pSmt->Symbol; if (attrib & VA_MARK) { SetBkColor(hDC, ~pSmt->BGColor); SetTextColor(hDC, ~pSmt->TextColor); } else if (attrib & VA_REVERSE) { SetBkColor(hDC, pSmt->TextColor); SetTextColor(hDC, pSmt->BGColor); } else { SetBkColor(hDC, pSmt->BGColor); SetTextColor(hDC, pSmt->TextColor); } if (bold || underline || special) { pSmt->lfnt.lfUnderline = (BYTE)underline; pSmt->lfnt.lfWeight = bold ? FW_BOLD : FW_NORMAL; pSmt->lfnt.lfCharSet = (BYTE)(special ? SYMBOL_CHARSET : ANSI_CHARSET); hfont = CreateFontIndirect(&pSmt->lfnt); holdfont = SelectObject(hDC, hfont); TextOut(hDC, xpos, ypos, (LPSTR)str, len); SelectObject(hDC, holdfont); DeleteObject(hfont); pSmt->lfnt.lfUnderline = 0; pSmt->lfnt.lfWeight = FW_NORMAL; pSmt->lfnt.lfCharSet = ANSI_CHARSET; } else { SelectObject(hDC, pSmt->hFont); TextOut(hDC, xpos, ypos, (LPSTR)str, len); } } static void NEAR CursorUp(PSMT pSmt, int count) { register short d1 = pSmt->CurLine - pSmt->TopScroll; register short val; if (d1) { if (d1 > 0) val = min(count, d1); else val = min(count, pSmt->CurLine); pSmt->Pos.y -= val * pSmt->CharHeight; pSmt->CurLine -= val; AdjustWindowToCursor(pSmt); } } static void NEAR CursorDown(PSMT pSmt, int count) { register short d1 = pSmt->BottomScroll - pSmt->CurLine; register short val; if (d1) { if (d1 > 0) val = min(count, d1); else val = min(count, pSmt->MaxLines - pSmt->CurLine - 1); pSmt->Pos.y += val * pSmt->CharHeight; pSmt->CurLine += val; AdjustWindowToCursor(pSmt); } } static void NEAR CursorRight(PSMT pSmt, int count) { register short *offset = &pSmt->CurLineOffset; register int *xpos = &pSmt->Pos.x; short cols = pSmt->MaxCols - 1; short cwidth = pSmt->CharWidth; while ((*offset < cols) && (count--)) { *offset += 1; *xpos += cwidth; } } static void NEAR CursorLeft(PSMT pSmt, int count) { register short *offset = &pSmt->CurLineOffset; register int *xpos = &pSmt->Pos.x; short cwidth = pSmt->CharWidth; while ((*offset > 0) && (count--)) { *offset -= 1; *xpos -= cwidth; } } static void NEAR DoCR(PSMT pSmt) { pSmt->Pos.x = pSmt->CurLineOffset = 0; } static void NEAR DoHT(PSMT pSmt) { register short *offset = &pSmt->CurLineOffset; register int *xpos; short cwidth; short cols = pSmt->MaxCols - 1; if (*offset >= cols) return; xpos = &pSmt->Pos.x; cwidth = pSmt->CharWidth; do { *offset += 1; *xpos += cwidth; } while ((pSmt->TabStops[*offset] != 'T') && (*offset < cols)); } static void NEAR DoBS(PSMT pSmt) { if (pSmt->CurLineOffset) { pSmt->CurLineOffset -= 1; pSmt->Pos.x -= pSmt->CharWidth; } } static void NEAR DoLF(PSMT pSmt) { register int scrollrem; if (pSmt->CurLine == pSmt->BottomScroll) { scrollindex(pSmt, TRUE); wordmemset(pSmt->lines[pSmt->CurLine], SP, pSmt->MaxCols); if (pSmt->SmoothScroll) { for (scrollrem = pSmt->CharHeight; scrollrem >= pSmt->ScrollUnits; scrollrem -= pSmt->ScrollUnits) { ScrollWindow(pSmt->hWnd,0,-pSmt->ScrollUnits,NULL,&pSmt->srect); UpdateWindow(pSmt->hWnd); } if (scrollrem) { ScrollWindow(pSmt->hWnd,0,-scrollrem,NULL,&pSmt->srect); UpdateWindow(pSmt->hWnd); } /* for (i = 0; i < pSmt->CharHeight/2; i++) { ScrollWindow(pSmt->hWnd,0, -2, NULL, &pSmt->srect); UpdateWindow(pSmt->hWnd); } if (pSmt->CharHeight & 1) { ScrollWindow(pSmt->hWnd,0, -1, NULL, &pSmt->srect); UpdateWindow(pSmt->hWnd); } */ } else { ScrollWindow(pSmt->hWnd,0,-pSmt->CharHeight, NULL, &pSmt->srect); UpdateWindow(pSmt->hWnd); } } else if (pSmt->CurLine < (pSmt->MaxLines - 1)) { pSmt->Pos.y += pSmt->CharHeight; pSmt->CurLine += 1; AdjustWindowToCursor(pSmt); } } static void NEAR ReverseIndex(PSMT pSmt) { register int scrollrem; if (pSmt->CurLine == pSmt->TopScroll) { scrollindex(pSmt, FALSE); wordmemset(pSmt->lines[pSmt->CurLine], SP, pSmt->MaxCols); if (pSmt->SmoothScroll) { for (scrollrem = pSmt->CharHeight; scrollrem >= pSmt->ScrollUnits; scrollrem -= pSmt->ScrollUnits) { ScrollWindow(pSmt->hWnd,0,+pSmt->ScrollUnits,NULL,&pSmt->srect); UpdateWindow(pSmt->hWnd); } if (scrollrem) { ScrollWindow(pSmt->hWnd,0,+scrollrem,NULL,&pSmt->srect); UpdateWindow(pSmt->hWnd); } /* for (i = 0; i < pSmt->CharHeight/2; i++) { ScrollWindow(pSmt->hWnd,0, 2, (LPRECT)NULL, &pSmt->srect); UpdateWindow(pSmt->hWnd); } if (pSmt->CharHeight & 1) { ScrollWindow(pSmt->hWnd, 0, 1, (LPRECT)NULL, &pSmt->srect); UpdateWindow(pSmt->hWnd); } */ } else { ScrollWindow(pSmt->hWnd,0, pSmt->CharHeight, NULL, &pSmt->srect); UpdateWindow(pSmt->hWnd); } } else if (pSmt->CurLine > 0) { pSmt->Pos.y -= pSmt->CharHeight; pSmt->CurLine -= 1; AdjustWindowToCursor(pSmt); } } static void NEAR TermWndPaint(PSMT pSmt, LPPAINTSTRUCT lpps) { register int i,j, k; BYTE buf[MAXCOLUMNS]; HDC hDC = lpps->hdc; RECT crect; BYTE attrib; short xpos; short cols = pSmt->MaxCols; short cheight = pSmt->CharHeight; short cwidth = pSmt->CharWidth; short count; short leftcol = 0; short leftbase = 0; if (!lpps->fErase) { SelectObject(hDC, pSmt->hbr); FillRect(hDC, (LPRECT)&lpps->rcPaint, pSmt->hbr); } crect.left = lpps->rcPaint.left; crect.right = lpps->rcPaint.right; crect.top = 0; crect.bottom = cheight; /* if (crect.left > cwidth) { leftcol = crect.left / cwidth; leftbase = leftcol * cwidth; } */ for (j = 0; j < pSmt->MaxLines; j++) { if (RectVisible(hDC, &crect)) { k = 0; xpos = leftbase; attrib = (BYTE)HIBYTE(*pSmt->lines[j]); for (i = cols - 1; (i >= leftcol) && (*(pSmt->lines[j] + i) == SP); i--) ; count = i + 1; for (i = leftcol; i < count; i++) { if (attrib != (BYTE)HIBYTE(*(pSmt->lines[j] + i))) { ShowLineOfText(pSmt, hDC, buf, k, xpos, crect.top, attrib); xpos = cwidth * i; k = 0; attrib = (BYTE)HIBYTE(*(pSmt->lines[j] + i)); } buf[k++] = (BYTE)LOBYTE(*(pSmt->lines[j] + i)); } ShowLineOfText(pSmt, hDC, buf, k, xpos, crect.top, attrib); } crect.top += cheight; crect.bottom += cheight; } } static void NEAR scrollindex(PSMT pSmt, BOOL direction) { register WORD *temp; int bottom; register int count = pSmt->BottomScroll - pSmt->TopScroll; if (direction) { if (count == pSmt->MaxLines - 1) { count = pSmt->MaxTextLines - 1; temp = pSmt->lines[0]; bottom = count; if (pSmt->scrollback < pSmt->MaxScrollBack) pSmt->scrollback += 1; if (pSmt->scrollforward > 0) pSmt->scrollforward -= 1; } else { temp = pSmt->lines[pSmt->TopScroll]; bottom = pSmt->BottomScroll; } memmove(&pSmt->lines[pSmt->TopScroll], &pSmt->lines[pSmt->TopScroll + 1], count * sizeof (WORD *)); pSmt->lines[bottom] = temp; } else { temp = pSmt->lines[pSmt->BottomScroll]; memmove(&pSmt->lines[pSmt->TopScroll + 1], &pSmt->lines[pSmt->TopScroll], count * sizeof (WORD *)); pSmt->lines[pSmt->TopScroll] = temp; } } static void NEAR ComputeVisibleWindow(PSMT pSmt, short right, short bottom) { POINT Pt; Pt.x = right; Pt.y = bottom; ClientToScreen(pSmt->hMain, &Pt); ScreenToClient(pSmt->hStatic,&Pt); pSmt->vrect.right = min((Pt.x /pSmt->CharWidth) * pSmt->CharWidth, pSmt->rect.right); if (pSmt->vrect.right <= 0) pSmt->vrect.right = pSmt->CharWidth; pSmt->vrect.bottom = min((Pt.y / pSmt->CharHeight) * pSmt->CharHeight, pSmt->rect.bottom); if (pSmt->vrect.bottom <= 0) pSmt->vrect.bottom = pSmt->CharHeight; } static void NEAR AdjustWindowToCursor(PSMT pSmt) { register short Y2, Y; POINT Pt; short ypos; HWND hWnd = pSmt->hWnd; Y2 = pSmt->vrect.bottom - pSmt->CharHeight; Pt.x = pSmt->Pos.x; Pt.y = ypos = pSmt->Pos.y; ClientToScreen(hWnd, &Pt); ScreenToClient(pSmt->hStatic, &Pt); Y = Pt.y; if (Y > Y2) { pSmt->rect.top = Y2 - ypos; MoveWindow(hWnd,pSmt->rect.left, pSmt->rect.top, pSmt->rect.right,pSmt->rect.bottom, TRUE); } else if (Y < 0) { pSmt->rect.top = -ypos; MoveWindow(hWnd,pSmt->rect.left, pSmt->rect.top, pSmt->rect.right, pSmt->rect.bottom, TRUE); } } static void NEAR wordmemset(WORD *dest, WORD val, int count) { /* register WORD *wptr = dest; register int i; for (i = 0; i < count; i++) *wptr++ = val; */ _asm { pushf ; save direction flag push di ; save pointer cld mov ax,ds ; set up es mov es,ax mov di,dest ; set destination pointer mov ax,val ; value to set mov cx,count ; number of words to store rep stosw ; do it pop di ; restore registers which must be saved popf } } short FAR PASCAL GetFontInfo(LPLOGFONT lf, LPTEXTMETRIC tm, short type, LPSTR lpData) { SMT FAR *pSmt; LPSTR dest; LPSTR src; register int i; int width, height, weight; BYTE charset; static BOOL copied = FALSE; if ((lf->lfPitchAndFamily & 3) != FIXED_PITCH) return TRUE; pSmt = (SMT FAR *)lpData; dest = (LPSTR)&pSmt->lfnt; src = (LPSTR)lf; width = lf->lfWidth; height = lf->lfHeight; weight = lf->lfWeight; charset = lf->lfCharSet; if ((width == pSmt->NFontWidth) && (height == pSmt->NFontHeight)) { if (weight == FW_BOLD) pSmt->NBold = TRUE; if (charset == SYMBOL_CHARSET) pSmt->NSymbol = TRUE; } if ((width == pSmt->SFontWidth) && (height == pSmt->SFontHeight)) { if (weight == FW_BOLD) pSmt->SBold = TRUE; if (charset == SYMBOL_CHARSET) pSmt->SSymbol = TRUE; } if (!copied) { for (i = 0; i < sizeof(LOGFONT); i++) *(dest + i) = *(src + i); copied = TRUE; } return TRUE; } HFONT FAR SetFontData(PSMT pSmt) { TEXTMETRIC TM; HDC hDC; HFONT hFont, hOldFont; FARPROC fp; HWND hWnd = pSmt->hMain; hDC = GetDC(hWnd); fp = MakeProcInstance((FARPROC)GetFontInfo, GetWindowWord(hWnd,GWW_HINSTANCE)); EnumFonts(hDC, pSmt->lfnt.lfFaceName, fp, (LPSTR)pSmt); FreeProcInstance(fp); if (pSmt->MaxCols == MAXCOLUMNS) { pSmt->lfnt.lfWidth = pSmt->SFontWidth; pSmt->lfnt.lfHeight = pSmt->SFontHeight; pSmt->Bold = pSmt->SBold; } else { pSmt->lfnt.lfWidth = pSmt->NFontWidth; pSmt->lfnt.lfHeight = pSmt->NFontHeight; pSmt->Bold = pSmt->NBold; } pSmt->lfnt.lfEscapement = 0; pSmt->lfnt.lfOrientation = 0; pSmt->lfnt.lfWeight = FW_NORMAL; pSmt->lfnt.lfItalic = 0; pSmt->lfnt.lfUnderline = 0; pSmt->lfnt.lfStrikeOut = 0; pSmt->lfnt.lfCharSet = ANSI_CHARSET; hFont = CreateFontIndirect(&pSmt->lfnt); hOldFont = SelectObject(hDC, hFont); GetTextMetrics(hDC, &TM); pSmt->CharHeight = TM.tmHeight + TM.tmExternalLeading; pSmt->CharWidth = TM.tmAveCharWidth; SelectObject(hDC, hOldFont); ReleaseDC(pSmt->hMain, hDC); return (hFont); }