/* File: D:\WACKER\tdll\termpnt.c (Created: 11-Dec-1993) * * Copyright 1994 by Hilgraeve Inc. -- Monroe, MI * All rights reserved * * $Revision: 3 $ * $Date: 5/09/01 4:38p $ */ // #define DEBUGSTR 1 #include #pragma hdrstop #include "stdtyp.h" #include "assert.h" #include "timers.h" #include "htchar.h" #include #include "mc.h" #include "term.hh" static void TextAttrOut(const HHTERM hhTerm, const HDC hDC, const int x, const int y, const ECHAR *lpachText, const PSTATTR apstAttrs, const int fForceRight, const int nCount, const int iRow, const int iCol); static int MapCells(const ECHAR *each, const int nStrLen, const int nCellPos); void termPaint(const HHTERM hhTerm, const HWND hwnd) { PAINTSTRUCT ps; RECT rc, rci; HBRUSH hBrush; HFONT hFont; int i, j, k, l, m, n; int iOffset; int iPaintBeg; int iPaintEnd; int xr, xl; ECHAR **fplpstrTxt; POINT ptTemp; const int iScrlInc = hhTerm->yChar; const HDC hdc = BeginPaint(hwnd, &ps); #ifndef CHAR_NARROW int x; int fRight; ECHAR aechTmpBuf[MAX_EMUCOLS + 1]; #endif SetTextAlign(hdc, TA_BOTTOM); SelectObject(hdc, hhTerm->hbrushTerminal); hFont = (HFONT)SelectObject(hdc, hhTerm->hFont); iPaintBeg = max(hhTerm->iVScrlMin, hhTerm->iVScrlPos + (ps.rcPaint.top / hhTerm->yChar)); iPaintEnd = min(hhTerm->iRows + 1, hhTerm->iVScrlPos + ((min(hhTerm->iTermHite * hhTerm->yChar, ps.rcPaint.bottom) + hhTerm->yChar - 1) / hhTerm->yChar)); rc = ps.rcPaint; /* -------------- xl is calculation of left edge. ------------- */ if (hhTerm->iHScrlPos == 0) xl = 0; else xl = min(0, -(hhTerm->iHScrlPos * hhTerm->xChar) - hhTerm->xBezel + hhTerm->xChar); /* -------------- xr = right edge of text. ------------- */ xr = xl + (hhTerm->iCols * hhTerm->xChar) + hhTerm->xIndent + hhTerm->xBezel; if (ps.rcPaint.bottom > (i = ((hhTerm->iTermHite - (hhTerm->xBezel ? 1 : 0)) * hhTerm->yChar))) { // Only draw between bottom line and top of the bezel, since the // bezel gets drawn below anyway. If no bezel, fill to the bottom // of the terminal window. // rc.top = max(rc.top, i); rc.bottom = min(rc.bottom, hhTerm->cy - ((hhTerm->iVScrlMax == hhTerm->iVScrlPos) ? hhTerm->xBezel : 0)); rc.left += (xl == 0 && iPaintEnd > 0 && rc.left == 0) ? hhTerm->xBezel : 0; rc.right = min(rc.right, xr + hhTerm->xIndent); FillRect(hdc, &rc, (iPaintEnd < 0) ? hhTerm->hbrushBackScrl : hhTerm->hbrushTerminal); } // Could be space beyond the emulator screen (ie. hi-res monitor) // that needs filling with the approproiate color. if (ps.rcPaint.right > xr) { rc.left = xr; ptTemp.x = 0; ptTemp.y = hhTerm->yBrushOrg; ClientToScreen(hwnd, &ptTemp); if (iPaintBeg <= 0) { rc.top = (-hhTerm->iVScrlPos + iPaintBeg) * hhTerm->yChar; rc.bottom = (iPaintEnd <= 0) ? ps.rcPaint.bottom : (-hhTerm->iVScrlPos + min(1, iPaintEnd)) * hhTerm->yChar; rc.right = rc.left + hhTerm->xIndent + hhTerm->xBezel; FillRect(hdc, &rc, hhTerm->hbrushBackScrl); rc.right = ps.rcPaint.right; if (i) { SetBkColor(hdc, hhTerm->crBackScrl); SetBrushOrgEx(hdc, ptTemp.x, ptTemp.y, NULL); rc.left += hhTerm->xIndent + hhTerm->xBezel; if (hhTerm->xBezel) FillRect(hdc, &rc, hhTerm->hbrushBackScrl); else FillRect(hdc, &rc, hhTerm->hbrushBackHatch); rc.left -= hhTerm->xIndent + hhTerm->xBezel; } } if (iPaintEnd >= 0) { rc.top = (-hhTerm->iVScrlPos + max(1, iPaintBeg)) * hhTerm->yChar - hhTerm->yChar/2; rc.bottom = ps.rcPaint.bottom; rc.right = rc.left + hhTerm->xIndent; FillRect(hdc, &rc, hhTerm->hbrushTerminal); rc.right = ps.rcPaint.right; if (i) { SetBkColor(hdc, hhTerm->crTerm); SetBrushOrgEx(hdc, ptTemp.x, ptTemp.y, 0); rc.left += hhTerm->xIndent + hhTerm->xBezel; if (hhTerm->xBezel) FillRect(hdc, &rc, hhTerm->hbrushBackScrl); else FillRect(hdc, &rc, hhTerm->hbrushTermHatch); } } } // Fill in the indent margin along the left side of the terminal. if (ps.rcPaint.left < (hhTerm->xIndent + (hhTerm->iHScrlPos ? 0 : hhTerm->xBezel))) { rc.left = ps.rcPaint.left; rc.right = hhTerm->xIndent + (hhTerm->iHScrlPos ? 0 : hhTerm->xBezel); // When scrolling down during marking, corners were left unpainted. // This guy corrects that. - mrw if (iPaintBeg < 0) { rc.top = (-hhTerm->iVScrlPos + iPaintBeg) * hhTerm->yChar; rc.bottom = (-hhTerm->iVScrlPos + min(0,iPaintEnd)) * hhTerm->yChar; FillRect(hdc, &rc, hhTerm->hbrushBackScrl); } if (iPaintEnd > 0) { // The top & bottom should only redraw from & to the bezel. // that is all that's needed... // rc.top = (-hhTerm->iVScrlPos + max(1, iPaintBeg)) * hhTerm->yChar; rc.bottom = (hhTerm->iVScrlPos == hhTerm->iVScrlMax) ? hhTerm->cy - hhTerm->xBezel : ps.rcPaint.bottom; rc.left = max(ps.rcPaint.left, ((hhTerm->iHScrlPos == 0) ? hhTerm->xBezel : 0)); FillRect(hdc, &rc, hhTerm->hbrushTerminal); } // New outdented bezel style requires filling with gray between // bezel and left edge. if (hhTerm->iHScrlPos == 0 && ps.rcPaint.left <= OUTDENT && iPaintEnd > 0) { rc.top = (-hhTerm->iVScrlPos + max(0, iPaintBeg)) * hhTerm->yChar; rc.bottom = (-hhTerm->iVScrlPos + iPaintEnd + 2) * hhTerm->yChar; rc.right = OUTDENT; rc.left = ps.rcPaint.left; FillRect(hdc, &rc, hhTerm->hbrushBackScrl); } } /* -------------- Paint bezel here ------------- */ if (hhTerm->xBezel) { /* -------------- Left edge ------------- */ if (iPaintEnd >= 0) { // n is the width of the thick gray section of the bezel. // we surround the thick gray part with four lines of // of white and gray lines. That's why we subtract 4. n = hhTerm->xBezel - OUTDENT - 4; /* -------------- Left edge ------------- */ rc.left = xl + OUTDENT; rc.right = rc.left + hhTerm->xBezel; k = ((hhTerm->iVScrlMax - hhTerm->iVScrlPos + hhTerm->iTermHite) * hhTerm->yChar) + (hhTerm->cy % hhTerm->yChar); rc.top = (-hhTerm->iVScrlPos * hhTerm->yChar) + OUTDENT; rc.bottom = k - OUTDENT; if (IntersectRect(&rci, &rc, &ps.rcPaint)) { /* --- Paint outer border --- */ SelectObject(hdc, hhTerm->hWhitePen); MoveToEx(hdc, rc.left, rc.top++, NULL); LineTo(hdc, rc.left++, rc.bottom--); MoveToEx(hdc, rc.left, rc.top++, NULL); LineTo(hdc, rc.left++, rc.bottom--); /* --- Paint middle portion --- */ rc.right = rc.left + n; FillRect(hdc, &rc, hhTerm->hbrushBackScrl); rc.left += n; rc.top += n; rc.bottom -= n; /* --- Paint inner border --- */ SelectObject(hdc, hhTerm->hDkGrayPen); MoveToEx(hdc, rc.left, rc.top++, NULL); LineTo(hdc, rc.left++, rc.bottom--); SelectObject(hdc, hhTerm->hBlackPen); MoveToEx(hdc, rc.left, rc.top, NULL); LineTo(hdc, rc.left, rc.bottom); } /* -------------- Bottom edge ------------- */ rc.left = xl + OUTDENT; rc.right = xr + hhTerm->xIndent + hhTerm->xBezel - 1 - OUTDENT; l = rc.right; // save for right side. rc.bottom = k; rc.top = rc.bottom - hhTerm->xBezel; if (IntersectRect(&rci, &rc, &ps.rcPaint)) { /* --- Paint from bezel to bottom of screen --- */ m = rc.top; rc.top = rc.bottom - OUTDENT; FillRect(hdc, &rc, hhTerm->hbrushBackScrl); rc.top = m; rc.bottom -= OUTDENT + 1; /* --- Paint outer border --- */ SelectObject(hdc, hhTerm->hBlackPen); MoveToEx(hdc, rc.left++, rc.bottom, NULL); LineTo(hdc, rc.right--, rc.bottom--); SelectObject(hdc, hhTerm->hDkGrayPen); MoveToEx(hdc, rc.left++, rc.bottom, NULL); LineTo(hdc, rc.right--, rc.bottom); /* --- Paint middle portion --- */ rc.top = rc.bottom - n; FillRect(hdc, &rc, hhTerm->hbrushBackScrl); rc.left += n; rc.right -= n-1; rc.bottom -= n; /* --- Paint inner border --- */ SelectObject(hdc, hhTerm->hWhitePen); MoveToEx(hdc, rc.left++, rc.bottom, NULL); LineTo(hdc, rc.right--, rc.bottom--); MoveToEx(hdc, rc.left++, rc.bottom, NULL); LineTo(hdc, rc.right--, rc.bottom--); SelectObject(hdc, hhTerm->hDkGrayPen); MoveToEx(hdc, rc.left++, rc.bottom, NULL); LineTo(hdc, rc.right--, rc.bottom--); /* --- Fill in the bottom below bezel --- */ rc.top = k; rc.bottom = rc.top + OUTDENT; rc.left = xl + OUTDENT; rc.right = l + 1; FillRect(hdc, &rc, hhTerm->hbrushBackScrl); } /* -------------- Right edge ------------- */ rc.top = (-hhTerm->iVScrlPos * hhTerm->yChar) + OUTDENT; rc.bottom = k; rc.right = l + OUTDENT + 1; rc.left = rc.right - hhTerm->xBezel; if (IntersectRect(&rci, &rc, &ps.rcPaint)) { /* --- Paint outdent region --- */ rc.left = l; FillRect(hdc, &rc, hhTerm->hbrushBackScrl); rc.bottom -= OUTDENT; rc.right -= OUTDENT + 1; /* --- Paint outer border --- */ SelectObject(hdc, hhTerm->hBlackPen); MoveToEx(hdc, rc.right, rc.top++, NULL); LineTo(hdc, rc.right--, rc.bottom--); SelectObject(hdc, hhTerm->hDkGrayPen); MoveToEx(hdc, rc.right, rc.top++, NULL); LineTo(hdc, rc.right, rc.bottom--); /* --- Paint middle portion --- */ rc.left = rc.right - n; FillRect(hdc, &rc, hhTerm->hbrushBackScrl); rc.top += n-1; rc.right -= n; rc.bottom -= n-1; /* --- Paint inner border --- */ SelectObject(hdc, hhTerm->hWhitePen); MoveToEx(hdc, rc.right, rc.top++, NULL); LineTo(hdc, rc.right--, rc.bottom--); MoveToEx(hdc, rc.right, rc.top++, NULL); LineTo(hdc, rc.right--, rc.bottom--); SelectObject(hdc, hhTerm->hDkGrayPen); MoveToEx(hdc, rc.right, rc.top++, NULL); LineTo(hdc, rc.right--, rc.bottom--); /* --- Fill area to right of bezel --- */ rc.left = l + 1; rc.right = rc.left + OUTDENT; rc.top = -hhTerm->iVScrlPos * hhTerm->yChar; rc.bottom = k + OUTDENT; FillRect(hdc, &rc, hhTerm->hbrushBackScrl); } } } // Paint backscroll buffer. Stuff going into the backscroll // region is always on a line basis. You'll notice that the // calculation for l in the terminal area portion is more // complicated since stuff comes in at times on a character // basis. l represents the number of characters in the // character string to paint. i = iPaintBeg; if (i < iPaintEnd && i < 0) { j = (ps.rcPaint.left - hhTerm->xIndent - (hhTerm->iHScrlPos ? 0 : hhTerm->xBezel)) / hhTerm->xChar; j = max(j, 0); k = (j * hhTerm->xChar) + hhTerm->xIndent + (hhTerm->iHScrlPos ? 0 : hhTerm->xBezel); j += hhTerm->iHScrlPos - (hhTerm->xBezel && hhTerm->iHScrlPos ? 1:0); l = min(hhTerm->iCols - j, (ps.rcPaint.right + hhTerm->xChar - 1 - k) / hhTerm->xChar); fplpstrTxt = hhTerm->fplpstrBkTxt; m = hhTerm->iPhysicalBkRows; if (hhTerm->fBackscrlLock == TRUE) iOffset = (abs(hhTerm->iVScrlPos - i) + hhTerm->iNextBkLn) % m; else iOffset = (m + i + hhTerm->iNextBkLn) % m; n = iScrlInc * (-hhTerm->iVScrlPos + i); #ifdef CHAR_NARROW for ( ; i < iPaintEnd && i < 0 ; i+=1, n+=iScrlInc) { TextAttrOut(hhTerm, hdc, k, n, fplpstrTxt[iOffset]+j, (PSTATTR)0, FALSE, l, i, j); if (++iOffset >= m) iOffset = 0; } #else // This little hack is here to display wide (Kanji) characters in // the backscroll, without all of the fuss of adding attributes. // It forces the backscroll to always paint the // enitre row, and strips out the repeated left/right pairs j = (OUTDENT - (hhTerm->iHScrlPos ? 0 : hhTerm->xBezel)) / hhTerm->xChar; j = max(j, 0); k = (j * hhTerm->xChar) + OUTDENT + (hhTerm->iHScrlPos ? 0 : hhTerm->xBezel); j += hhTerm->iHScrlPos - (hhTerm->xBezel && hhTerm->iHScrlPos ? 1:0); l = hhTerm->iCols - j; for ( ; i < iPaintEnd && i < 0 ; i+=1, n+=iScrlInc) { // Hack for starting on the right half of a DB char fRight = FALSE; for (x = 0; x <= j; ) { if (isDBCSChar(*(fplpstrTxt[iOffset]+x))) { fRight = (x == j) ? FALSE : TRUE; x += 2; } else { fRight = FALSE; x += 1; } } memset(aechTmpBuf, 0, sizeof(aechTmpBuf)); StrCharStripDBCSString(aechTmpBuf, sizeof(aechTmpBuf), fplpstrTxt[iOffset]+j); //mpt:12-11-97 too many parameters? , l * sizeof(ECHAR)); TextAttrOut(hhTerm, hdc, k, n, aechTmpBuf, (PSTATTR)0, fRight, l, i, j); if (++iOffset >= m) iOffset = 0; } #endif } /* -------------- Paint divider bar if necessary ------------- */ for ( ; i == 0 ; ++i) { if (hhTerm->xBezel) { // n is the width of the thick gray section of the bezel. // we surround the thick gray part with four lines of // of white and gray lines. That's why we subtract 4. n = hhTerm->xBezel - OUTDENT - 4; rc.top = -hhTerm->iVScrlPos * hhTerm->yChar; rc.bottom = rc.top + OUTDENT; rc.left = ps.rcPaint.left; rc.right = ps.rcPaint.right; /* --- Paint gap above divider bar --- */ FillRect(hdc, &rc, hhTerm->hbrushBackScrl); rc.left = xl + hhTerm->xBezel + hhTerm->xIndent; rc.right = xr; /* --- If hightlighting, paint gap above divider --- */ if (min(hhTerm->ptBeg.y, hhTerm->ptEnd.y) < 0 && max(hhTerm->ptBeg.y, hhTerm->ptEnd.y) > 0) { FillRect(hdc, &rc, hhTerm->hbrushHighlight); } rc.left = xl + OUTDENT; rc.right = xr + hhTerm->xIndent + hhTerm->xBezel - OUTDENT - 1; /* --- note: order is important, bottom, top --- */ rc.bottom = rc.top + hhTerm->yChar; rc.top += OUTDENT; /* --- Paint top outside border --- */ SelectObject(hdc, hhTerm->hWhitePen); MoveToEx(hdc, rc.left++, rc.top, NULL); LineTo(hdc, rc.right--, rc.top++); MoveToEx(hdc, rc.left++, rc.top, NULL); LineTo(hdc, rc.right--, rc.top++); /* --- Paint middle section --- */ m = rc.bottom; rc.bottom = rc.top + n; FillRect(hdc, &rc, hhTerm->hbrushBackScrl); rc.bottom = m; rc.left += n; rc.top += n; rc.right -= n; /* --- Paint bottom border --- */ SelectObject(hdc, hhTerm->hDkGrayPen); MoveToEx(hdc, rc.left++, rc.top, NULL); LineTo(hdc, rc.right--, rc.top++); SelectObject(hdc, hhTerm->hBlackPen); MoveToEx(hdc, rc.left++, rc.top, NULL); LineTo(hdc, rc.right, rc.top++); /* --- Fill in any space left below the bezel --- */ FillRect(hdc, &rc, hhTerm->hbrushTerminal); if (min(hhTerm->ptBeg.y, hhTerm->ptEnd.y) < 0 && max(hhTerm->ptBeg.y, hhTerm->ptEnd.y) > 0) { rc.left = hhTerm->xIndent; rc.left += (hhTerm->iHScrlPos) ? 0 : hhTerm->xBezel; rc.right -= hhTerm->xIndent; FillRect(hdc, &rc, hhTerm->hbrushHighlight); } } else { j = (hhTerm->yChar * -hhTerm->iVScrlPos); k = (hhTerm->yChar) / 3; // Create highlight brush if textmarking crosses divider if (min(hhTerm->ptBeg.y, hhTerm->ptEnd.y) < 0 && max(hhTerm->ptBeg.y, hhTerm->ptEnd.y) > 0) { hBrush = hhTerm->hbrushHighlight; } else { hBrush = 0; } rc = ps.rcPaint; rc.top = j; rc.bottom = j + k + (hhTerm->yChar % 3); l = rc.right = ((hhTerm->iCols - hhTerm->iHScrlPos) * hhTerm->xChar) + hhTerm->xIndent + hhTerm->xIndent + hhTerm->xBezel + hhTerm->xBezel; FillRect(hdc, &rc, (hBrush != (HBRUSH)0) ? hBrush : hhTerm->hbrushBackScrl); rc.top = rc.bottom; rc.bottom = rc.top + k; rc.right = ps.rcPaint.right; FillRect(hdc, &rc, hhTerm->hbrushDivider); rc.top = rc.bottom; rc.bottom = j + hhTerm->yChar; rc.right = l; FillRect(hdc, &rc, (hBrush != (HBRUSH)0) ? hBrush : hhTerm->hbrushTerminal); } } /* -------------- Paint the active terminal portion. ------------- */ xl = (hhTerm->iHScrlPos) ? 0 : hhTerm->xBezel; if (i < iPaintEnd) { j = (ps.rcPaint.left - hhTerm->xIndent - xl) / hhTerm->xChar; j = max(j, 0); k = (j * hhTerm->xChar) + hhTerm->xIndent + xl; j += hhTerm->iHScrlPos - (hhTerm->xBezel && hhTerm->iHScrlPos ? 1:0); l = min(hhTerm->iCols - j, (ps.rcPaint.right + hhTerm->xChar - 1 - k) / hhTerm->xChar); // Formulas to convert from terminal to buffer row and back. // b = (t - 1 + top) % rows // t = (b + rows - top) % rows // t is always between 1 and rows+1. iOffset = (i - 1 + hhTerm->iTopline) % MAX_EMUROWS; n = iScrlInc * (-hhTerm->iVScrlPos + i); for ( ; i < iPaintEnd ; i += 1, n += iScrlInc) { TextAttrOut(hhTerm, hdc, k, n, hhTerm->fplpstrTxt[iOffset]+j, hhTerm->fppstAttr[iOffset]+j, FALSE, l, i, j); if (++iOffset >= MAX_EMUROWS) iOffset = 0; } } /* --- Draw cursors --- */ if (hhTerm->fHstCurOn) { hhTerm->fHstCurOn = FALSE; PaintHostCursor(hhTerm, TRUE, hdc); } if (hhTerm->fLclCurOn) { hhTerm->fLclCurOn = FALSE; PaintLocalCursor(hhTerm, TRUE, hdc); } /* --- cleanup time --- */ SelectObject(hdc, GetStockObject(WHITE_BRUSH)); SelectObject(hdc, GetStockObject(BLACK_PEN)); SelectObject(hdc, hFont); EndPaint(hwnd, &ps); return; } /*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=- * FUNCTION: * TextAttrOut * * DESCRIPTION: * Draws text and attributes on the terminal screen. Optimizes call to * TextOut based on attributes. For example, If attributes are all the * same for a given line, then only one call to TextOut is made. * * ARGUMENTS: * HHTERM hhTerm - internal terminal handle * HDC hdc - Device context from WM_PAINT * int x - x offset in pixels * int y - y offset in pixels * ECHAR *lpachText - long pointer to begining of text to print * PSTATTR apstAttrs - Array of pointers to attribute structures * int fForceRight - used for DBCS in the backscroll * int nCount - number of characters to draw. * int iRow - logical row being displayed * int iCol - logical col being displayed * * RETURNS: * void * */ static void TextAttrOut(const HHTERM hhTerm, const HDC hdc, const int x, const int y, const ECHAR *lpachText, const PSTATTR apstAttrs, const int fForceRight, const int nCount, const int iRow, const int iCol) { int i = 0, // track of how many chars drawn. j, // number of characters in a run. k, // offset where run began. nXPos; int nXStart, nYStart; // screen pos where chars are drawn. #ifndef CHAR_NARROW int nByteCount = 0; #endif int nBegAdj = 0; int nEndAdj = 0; int nStrLen = 0; TCHAR achBuf[MAX_EMUCOLS * 2]; ECHAR aechTmp[MAX_EMUCOLS + 1]; PSTATTR pstAttr = 0; unsigned int uTxtclr, uBkclr; BOOL fUnderlnFont = FALSE; BOOL fSymbolFont = FALSE; BOOL fDblHiHi = FALSE; BOOL fDblHiLo = FALSE; BOOL fDblWiLf = FALSE; BOOL fDblWiRt = FALSE; BOOL fWiLf = FALSE; BOOL fWiRt = FALSE; BOOL fFirstPass = TRUE; RECT rc; DbgOutStr("TAO %d\r\n", iRow, 0, 0, 0, 0); while (i < nCount) { k = i; // save offset of where this run begins in k. if (iRow < 0) { int nCurPos; long l, lBeg, lEnd; BOOL fMarking = FALSE; // Store the positions of the 1st char to draw nCurPos = i; // This check is a speed tweak. If the marking and backscrl // locks are off, we know that no text is can be marked. This // would be the normal case when stuff is streaming into the // terminal so we save the work done of the else body by // by checking and thus speed up the display. // For Far East we have to force the backscroll to paint every // character individualy. This is becuase MicroSquish is not // able to provide fixed pitch fonts that are fixed pitch for // DBCS characters. // if (hhTerm->fMarkingLock == FALSE && hhTerm->fBackscrlLock == FALSE && hhTerm->iEvenFont == TRUE) { SetBkColor(hdc, hhTerm->crBackScrl); SetTextColor(hdc, hhTerm->crBackScrlTxt); i = j = nCount; } else { #ifdef CHAR_NARROW lBeg = hhTerm->ptBeg.y * hhTerm->iCols + hhTerm->ptBeg.x; lEnd = hhTerm->ptEnd.y * hhTerm->iCols + hhTerm->ptEnd.x; #else // Hack city man :) // In the mouse handling routines, we modify the selection // cursor position so that you can't put it into the middle // of a wide character. The problem is that at this // point the repeated characters have been removed. // Therefore we need to modify the cursor position to take // into account the number of repeated characters that // were removed from the string as of our current drawing // position into that string. // pant, pant, pant. lBeg = hhTerm->ptBeg.x; lEnd = hhTerm->ptEnd.x; if (hhTerm->ptBeg.y == iRow) { lBeg = MapCells(lpachText , hhTerm->iCols, hhTerm->ptBeg.x); } if (hhTerm->ptEnd.y == iRow) { lEnd = MapCells(lpachText , hhTerm->iCols, hhTerm->ptEnd.x); } if (hhTerm->iEvenFont) { nBegAdj = lBeg - hhTerm->ptBeg.x; nEndAdj = lEnd - hhTerm->ptEnd.x; } else { nBegAdj = 0; nEndAdj = 0; } lBeg = hhTerm->ptBeg.y * hhTerm->iCols + lBeg; lEnd = hhTerm->ptEnd.y * hhTerm->iCols + lEnd; #endif if (lBeg > lEnd) { l = lEnd; lEnd = lBeg; lBeg = l; } // IN_RANGE macro is inclusive so subtract one from sEnd // which at this point is known to be larger than sBeg lEnd -= 1; l = iRow * hhTerm->iCols + i + iCol; fMarking = (BOOL)IN_RANGE(l, lBeg, lEnd); if (fMarking) { SetBkColor(hdc, GetSysColor(COLOR_HIGHLIGHT)); SetTextColor(hdc, GetSysColor(COLOR_HIGHLIGHTTEXT)); } else { SetBkColor(hdc, hhTerm->crBackScrl); SetTextColor(hdc, hhTerm->crBackScrlTxt); } // For Far East we have to force the backscroll to paint every // character individualy. This is becuase MicroSquish is not // able to provide fixed pitch fonts that are fixed pitch for // DBCS characters. if (hhTerm->iEvenFont) { for (j = 0 ; i < nCount ; ++i, ++j, ++l) { if (fMarking != (BOOL)IN_RANGE(l, lBeg, lEnd)) break; } } else { i++; j = 1; } } nXPos = k = i - j; #ifndef CHAR_NARROW if (nCurPos > 0) // Only copy the buffer if nCurPos > 0. REV: 04/11/2001. { MemCopy(aechTmp, lpachText , (unsigned)nCurPos * sizeof(ECHAR)); nXPos = CnvrtECHARtoMBCS(achBuf, sizeof(achBuf), aechTmp, (unsigned)nCurPos * sizeof(ECHAR)); //nXPos = StrCharGetByteCount(achBuf); // mrw;5/17/95 } // 18-May-1995 DLW // Added for the case where a DBCS string is started with half of // the character, like when scrolling to the right if (fForceRight && fFirstPass) { fWiRt = TRUE; } else { if (fForceRight) nXPos = max(0, nXPos - 1); } #endif } // At this point we know were not painting in the backscrl area. // Since the terminal area has attributes that backscrl does not // have (ie. color, underlining, etc.) we need to do more work. // else { pstAttr = apstAttrs+i; uTxtclr = pstAttr->txtclr; uBkclr = pstAttr->bkclr; // Test for attributes if (pstAttr->revvid) { unsigned uTmp = uTxtclr; uTxtclr = uBkclr; uBkclr = uTmp; } if (pstAttr->hilite) { // Colors are arranged so that high intensity colors are // in the lower half of the color array (currently 16 // colors corresponding to the IBM PC colors). This // guy sets the color to the opposite intensity. uTxtclr = (uTxtclr + (MAX_EMUCOLORS/2)) % MAX_EMUCOLORS; if (uTxtclr == uBkclr) uTxtclr = (uTxtclr + 1) % MAX_EMUCOLORS; } if (pstAttr->bklite) { uBkclr = (uBkclr + (MAX_EMUCOLORS/2)) % MAX_EMUCOLORS; if (uBkclr == uTxtclr) uBkclr = (uBkclr + 1) % MAX_EMUCOLORS; } if (pstAttr->blink) { int iBufRow; if (hhTerm->iBlink == 0) hhTerm->iBlink = 1; if (hhTerm->iBlink == -1) uTxtclr = uBkclr; iBufRow = (iRow - 1 + hhTerm->iTopline) % MAX_EMUROWS; hhTerm->abBlink[iBufRow] = (BYTE)TRUE; } if (pstAttr->undrln) fUnderlnFont = TRUE; if (pstAttr->blank) uTxtclr = uBkclr; // Only allow one double height attribute // if (pstAttr->dblhihi) fDblHiHi = TRUE; else if (pstAttr->dblhilo) fDblHiLo = TRUE; // Only allow one double wide attribute // if (pstAttr->dblwilf) fDblWiLf = TRUE; else if (pstAttr->dblwirt) fDblWiRt = TRUE; // Only allow one wide attribute // if (pstAttr->wilf) fWiLf = TRUE; else if (pstAttr->wirt) fWiRt = TRUE; // If the symbol attribute is on, use alternate font. // if (pstAttr->symbol) fSymbolFont = TRUE; // Find the longest run of characters with the same attributes. // for (j = 0 ; i < nCount ; ++i, ++j) { if (memcmp(pstAttr, apstAttrs+i, sizeof(STATTR)) != 0) break; } /* --- Set text and background colors --- */ if (pstAttr->txtmrk) { SetBkColor(hdc, GetSysColor(COLOR_HIGHLIGHT)); SetTextColor(hdc, GetSysColor(COLOR_HIGHLIGHTTEXT)); } else { SetBkColor(hdc, hhTerm->pacrEmuColors[uBkclr]); SetTextColor(hdc, hhTerm->pacrEmuColors[uTxtclr]); } /* --- How hard can it be to pick a font? --- */ if (fDblHiHi || fDblHiLo) { if (fDblWiLf || fDblWiRt) { if (fSymbolFont) { if (hhTerm->hSymDblHiWiFont == 0) hhTerm->hSymDblHiWiFont = termMakeFont(hhTerm, 0, 1, 1, 1); SelectObject(hdc, hhTerm->hSymDblHiWiFont); } else { if (hhTerm->hDblHiWiFont == 0) hhTerm->hDblHiWiFont = termMakeFont(hhTerm, 0, 1, 1, 0); SelectObject(hdc, hhTerm->hDblHiWiFont); } } else { if (fSymbolFont) { if (hhTerm->hSymDblHiFont == 0) hhTerm->hSymDblHiFont = termMakeFont(hhTerm, 0, 1, 0, 1); SelectObject(hdc, hhTerm->hSymDblHiFont); } else { if (hhTerm->hDblHiFont == 0) hhTerm->hDblHiFont = termMakeFont(hhTerm, 0, 1, 0, 0); SelectObject(hdc, hhTerm->hDblHiFont); } } } else if (fDblWiLf || fDblWiRt) { if (fSymbolFont) { if (hhTerm->hSymDblWiFont == 0) hhTerm->hSymDblWiFont = termMakeFont(hhTerm, 0, 0, 1, 1); SelectObject(hdc, hhTerm->hSymDblWiFont); } else { if (hhTerm->hDblWiFont == 0) hhTerm->hDblWiFont = termMakeFont(hhTerm, 0, 0, 1, 0); SelectObject(hdc, hhTerm->hDblWiFont); } } else if (fSymbolFont) { if (hhTerm->hSymFont == 0) hhTerm->hSymFont = termMakeFont(hhTerm, 0, 0, 0, 1); SelectObject(hdc, hhTerm->hSymFont); } nXPos = k = i - j; } // Ok, go ahead, paint that text, make my day... // Guess I better explain myself here. When Windows synthesizes // a font to get something like bold or italic, TextOut has a nasty // habit of adding a pixel to the end of the string (be it a // character or a run of characters). This is documented in the // TEXTMETRIC structure in the description of tmOverHang. This has // some unfortunate side effects (Don't believe me? Try defing the // old stuff back in, select a bold font and do some hightlighting // and scrolling). The solution is to explicitly clip so that text // is drawn only where I say it can draw. This amounts in extra // work but the end result seems no slower. - mrw // rc.left = x + (nXPos * hhTerm->xChar); #if defined(FAR_EAST) if (rc.left > (x + (hhTerm->iCols * hhTerm->xChar))) rc.left = x + (hhTerm->iCols * hhTerm->xChar); #endif rc.right = rc.left + ((j - nEndAdj) * hhTerm->xChar); if (rc.right > (x + (hhTerm->iCols * hhTerm->xChar))) rc.right = x + (hhTerm->iCols * hhTerm->xChar); rc.top = y; rc.bottom = y + hhTerm->yChar; // If we're painting the bottom half of a double high character, // we need to raise the origin of where the character is drawn // by an additional char height. The clipping rectangle insures // that only the cell portion is actually drawn. nYStart = (fDblHiHi) ? rc.bottom + hhTerm->yChar : rc.bottom; // More painting tricks. If we're painting double wide characters // we'll be painting them one at a time. Why you ask? Well, this // routine tries to paint the longest run of characters with the // same attributes. Just makes good windows sense. In the case // of double wide however, the attributes come as double-wide left, // double-wide right. Since the "double-wide" character has a // different attribute in its left side and right side, this // routine will paint each half one at a time (seperate calls to // ExtTextOut()). This is useful and wanted. Because we clip // the drawing area to the cell or cells region, we can draw the // right half by offsetting the x origin by one character cell // to the left. Windows clipping logic will only draw in the // actual cell region so we get the right half of the character. // Lot of explaination for one measely line of code. // nXStart = (fDblWiRt || fWiRt) ? rc.left - hhTerm->xChar : rc.left; /* --- Hero of the day, ExtTextOut! --- */ MemCopy(aechTmp, lpachText + k, (unsigned int)j * sizeof(ECHAR)); nStrLen = CnvrtECHARtoMBCS(achBuf, sizeof(achBuf), aechTmp, (unsigned)j * sizeof(ECHAR)); //mrw:5/17/95 achBuf[nStrLen] = TEXT('\0'); #if defined(FAR_EAST) // mrw:10/10/95 - ifdef'ed this code if (!hhTerm->iEvenFont && !(fForceRight && fFirstPass)) { // If this is a DBCS character we are painting, then we want to paint 2 cells // instead of 1 (makes sense, DBCS characters are twice as wide as SBCS). if (IsDBCSLeadByte(*achBuf)) { rc.right += hhTerm->xChar; rc.right = min(rc.right, x + (hhTerm->iCols * hhTerm->xChar)); } } #endif ExtTextOut(hdc, nXStart, nYStart, ETO_CLIPPED | ETO_OPAQUE, &rc, achBuf, (unsigned)nStrLen, 0); // Experiment. Most terminals underline their fonts by placing // underscores under the characters. The Windows underline font // places a thin line through the baseline of the character. // Many hosts use underlining in conjunction with box draw chars // to envelop regions of the screen. The underscores complete // envelope and don't give the apperance of part of the characters // bleeding through. - mrw // if (fUnderlnFont) { // The double height makes the underscores too thick yet we // want to maintain the double-wide or symbol font we may be // using so check and recast the font to the samething without // the height component. - mrw // if (fDblHiHi || fDblHiLo) { if (fDblWiLf || fDblWiRt) { if (fSymbolFont) { if (hhTerm->hSymDblWiFont == 0) hhTerm->hSymDblWiFont = termMakeFont(hhTerm, 0, 0, 1, 1); SelectObject(hdc, hhTerm->hSymDblWiFont); } else { if (hhTerm->hDblWiFont == 0) hhTerm->hDblWiFont = termMakeFont(hhTerm, 0, 0, 1, 0); SelectObject(hdc, hhTerm->hDblWiFont); } } else if (fSymbolFont) { if (hhTerm->hSymFont == 0) hhTerm->hSymFont = termMakeFont(hhTerm, 0, 0, 0, 1); SelectObject(hdc, hhTerm->hSymFont); } else { SelectObject(hdc, hhTerm->hFont); } } // Set background to transparent so only the underscore // portion overpaints the character cell. // SetBkMode(hdc, TRANSPARENT); ExtTextOut(hdc, nXStart, nYStart, ETO_CLIPPED, &rc, hhTerm->underscores, (unsigned)j, 0); SetBkMode(hdc, OPAQUE); } /* --- Reselect the regular font only if we had to switch --- */ if (fUnderlnFont || fDblHiHi || fDblHiLo || fDblWiLf || fDblWiRt || fSymbolFont) { SelectObject(hdc, hhTerm->hFont); fUnderlnFont = FALSE; fSymbolFont = FALSE; fDblHiHi = FALSE; fDblHiLo = FALSE; fDblWiLf = FALSE; fDblWiRt = FALSE; } fWiRt = FALSE; fWiLf = FALSE; fFirstPass = FALSE; } return; } /*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=- * FUNCTION: * MapCells * * DESCRIPTION: * Maps screen cell position to internal screen image (echar image) position * * ARGUMENTS: * each - source string (does it start from beg of line?) * nStrLen - length in bytes * nCellPos - screen position to * * RETURNS: * void * */ static int MapCells(const ECHAR *each, const int nStrLen, const int nCellPos) { int i, nCount; if (each == NULL) { assert(FALSE); return 0; } for (i = 0, nCount = 0; nCount < nCellPos && i < nStrLen; i++) { if (isDBCSChar(each[i])) { nCount += 2; } else { nCount += 1; } } return i; }