Leaked source code of windows server 2003
You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

1268 lines
34 KiB

  1. /* File: D:\WACKER\tdll\termpnt.c (Created: 11-Dec-1993)
  2. *
  3. * Copyright 1994 by Hilgraeve Inc. -- Monroe, MI
  4. * All rights reserved
  5. *
  6. * $Revision: 3 $
  7. * $Date: 5/09/01 4:38p $
  8. */
  9. // #define DEBUGSTR 1
  10. #include <windows.h>
  11. #pragma hdrstop
  12. #include "stdtyp.h"
  13. #include "assert.h"
  14. #include "timers.h"
  15. #include "htchar.h"
  16. #include <emu\emu.h>
  17. #include "mc.h"
  18. #include "term.hh"
  19. static
  20. void TextAttrOut(const HHTERM hhTerm,
  21. const HDC hDC,
  22. const int x,
  23. const int y,
  24. const ECHAR *lpachText,
  25. const PSTATTR apstAttrs,
  26. const int fForceRight,
  27. const int nCount,
  28. const int iRow,
  29. const int iCol);
  30. static int MapCells(const ECHAR *each, const int nStrLen, const int nCellPos);
  31. void termPaint(const HHTERM hhTerm, const HWND hwnd)
  32. {
  33. PAINTSTRUCT ps;
  34. RECT rc, rci;
  35. HBRUSH hBrush;
  36. HFONT hFont;
  37. int i, j, k, l, m, n;
  38. int iOffset;
  39. int iPaintBeg;
  40. int iPaintEnd;
  41. int xr, xl;
  42. ECHAR **fplpstrTxt;
  43. POINT ptTemp;
  44. const int iScrlInc = hhTerm->yChar;
  45. const HDC hdc = BeginPaint(hwnd, &ps);
  46. #ifndef CHAR_NARROW
  47. int x;
  48. int fRight;
  49. ECHAR aechTmpBuf[MAX_EMUCOLS + 1];
  50. #endif
  51. SetTextAlign(hdc, TA_BOTTOM);
  52. SelectObject(hdc, hhTerm->hbrushTerminal);
  53. hFont = (HFONT)SelectObject(hdc, hhTerm->hFont);
  54. iPaintBeg = max(hhTerm->iVScrlMin,
  55. hhTerm->iVScrlPos + (ps.rcPaint.top / hhTerm->yChar));
  56. iPaintEnd = min(hhTerm->iRows + 1, hhTerm->iVScrlPos +
  57. ((min(hhTerm->iTermHite * hhTerm->yChar, ps.rcPaint.bottom) +
  58. hhTerm->yChar - 1) / hhTerm->yChar));
  59. rc = ps.rcPaint;
  60. /* -------------- xl is calculation of left edge. ------------- */
  61. if (hhTerm->iHScrlPos == 0)
  62. xl = 0;
  63. else
  64. xl = min(0, -(hhTerm->iHScrlPos * hhTerm->xChar)
  65. - hhTerm->xBezel + hhTerm->xChar);
  66. /* -------------- xr = right edge of text. ------------- */
  67. xr = xl + (hhTerm->iCols * hhTerm->xChar) + hhTerm->xIndent
  68. + hhTerm->xBezel;
  69. if (ps.rcPaint.bottom > (i = ((hhTerm->iTermHite
  70. - (hhTerm->xBezel ? 1 : 0)) * hhTerm->yChar)))
  71. {
  72. // Only draw between bottom line and top of the bezel, since the
  73. // bezel gets drawn below anyway. If no bezel, fill to the bottom
  74. // of the terminal window.
  75. //
  76. rc.top = max(rc.top, i);
  77. rc.bottom = min(rc.bottom,
  78. hhTerm->cy - ((hhTerm->iVScrlMax == hhTerm->iVScrlPos) ?
  79. hhTerm->xBezel : 0));
  80. rc.left += (xl == 0 && iPaintEnd > 0 && rc.left == 0) ?
  81. hhTerm->xBezel : 0;
  82. rc.right = min(rc.right, xr + hhTerm->xIndent);
  83. FillRect(hdc, &rc, (iPaintEnd < 0) ? hhTerm->hbrushBackScrl :
  84. hhTerm->hbrushTerminal);
  85. }
  86. // Could be space beyond the emulator screen (ie. hi-res monitor)
  87. // that needs filling with the approproiate color.
  88. if (ps.rcPaint.right > xr)
  89. {
  90. rc.left = xr;
  91. ptTemp.x = 0;
  92. ptTemp.y = hhTerm->yBrushOrg;
  93. ClientToScreen(hwnd, &ptTemp);
  94. if (iPaintBeg <= 0)
  95. {
  96. rc.top = (-hhTerm->iVScrlPos + iPaintBeg) * hhTerm->yChar;
  97. rc.bottom = (iPaintEnd <= 0) ? ps.rcPaint.bottom :
  98. (-hhTerm->iVScrlPos + min(1, iPaintEnd)) * hhTerm->yChar;
  99. rc.right = rc.left + hhTerm->xIndent + hhTerm->xBezel;
  100. FillRect(hdc, &rc, hhTerm->hbrushBackScrl);
  101. rc.right = ps.rcPaint.right;
  102. if (i)
  103. {
  104. SetBkColor(hdc, hhTerm->crBackScrl);
  105. SetBrushOrgEx(hdc, ptTemp.x, ptTemp.y, NULL);
  106. rc.left += hhTerm->xIndent + hhTerm->xBezel;
  107. if (hhTerm->xBezel)
  108. FillRect(hdc, &rc, hhTerm->hbrushBackScrl);
  109. else
  110. FillRect(hdc, &rc, hhTerm->hbrushBackHatch);
  111. rc.left -= hhTerm->xIndent + hhTerm->xBezel;
  112. }
  113. }
  114. if (iPaintEnd >= 0)
  115. {
  116. rc.top = (-hhTerm->iVScrlPos + max(1, iPaintBeg)) * hhTerm->yChar
  117. - hhTerm->yChar/2;
  118. rc.bottom = ps.rcPaint.bottom;
  119. rc.right = rc.left + hhTerm->xIndent;
  120. FillRect(hdc, &rc, hhTerm->hbrushTerminal);
  121. rc.right = ps.rcPaint.right;
  122. if (i)
  123. {
  124. SetBkColor(hdc, hhTerm->crTerm);
  125. SetBrushOrgEx(hdc, ptTemp.x, ptTemp.y, 0);
  126. rc.left += hhTerm->xIndent + hhTerm->xBezel;
  127. if (hhTerm->xBezel)
  128. FillRect(hdc, &rc, hhTerm->hbrushBackScrl);
  129. else
  130. FillRect(hdc, &rc, hhTerm->hbrushTermHatch);
  131. }
  132. }
  133. }
  134. // Fill in the indent margin along the left side of the terminal.
  135. if (ps.rcPaint.left < (hhTerm->xIndent +
  136. (hhTerm->iHScrlPos ? 0 : hhTerm->xBezel)))
  137. {
  138. rc.left = ps.rcPaint.left;
  139. rc.right = hhTerm->xIndent + (hhTerm->iHScrlPos ? 0 : hhTerm->xBezel);
  140. // When scrolling down during marking, corners were left unpainted.
  141. // This guy corrects that. - mrw
  142. if (iPaintBeg < 0)
  143. {
  144. rc.top = (-hhTerm->iVScrlPos + iPaintBeg) * hhTerm->yChar;
  145. rc.bottom = (-hhTerm->iVScrlPos + min(0,iPaintEnd)) * hhTerm->yChar;
  146. FillRect(hdc, &rc, hhTerm->hbrushBackScrl);
  147. }
  148. if (iPaintEnd > 0)
  149. {
  150. // The top & bottom should only redraw from & to the bezel.
  151. // that is all that's needed...
  152. //
  153. rc.top = (-hhTerm->iVScrlPos + max(1, iPaintBeg)) *
  154. hhTerm->yChar;
  155. rc.bottom = (hhTerm->iVScrlPos == hhTerm->iVScrlMax) ?
  156. hhTerm->cy - hhTerm->xBezel : ps.rcPaint.bottom;
  157. rc.left = max(ps.rcPaint.left,
  158. ((hhTerm->iHScrlPos == 0) ? hhTerm->xBezel : 0));
  159. FillRect(hdc, &rc, hhTerm->hbrushTerminal);
  160. }
  161. // New outdented bezel style requires filling with gray between
  162. // bezel and left edge.
  163. if (hhTerm->iHScrlPos == 0 && ps.rcPaint.left <= OUTDENT &&
  164. iPaintEnd > 0)
  165. {
  166. rc.top = (-hhTerm->iVScrlPos + max(0, iPaintBeg)) * hhTerm->yChar;
  167. rc.bottom = (-hhTerm->iVScrlPos + iPaintEnd + 2) * hhTerm->yChar;
  168. rc.right = OUTDENT;
  169. rc.left = ps.rcPaint.left;
  170. FillRect(hdc, &rc, hhTerm->hbrushBackScrl);
  171. }
  172. }
  173. /* -------------- Paint bezel here ------------- */
  174. if (hhTerm->xBezel)
  175. {
  176. /* -------------- Left edge ------------- */
  177. if (iPaintEnd >= 0)
  178. {
  179. // n is the width of the thick gray section of the bezel.
  180. // we surround the thick gray part with four lines of
  181. // of white and gray lines. That's why we subtract 4.
  182. n = hhTerm->xBezel - OUTDENT - 4;
  183. /* -------------- Left edge ------------- */
  184. rc.left = xl + OUTDENT;
  185. rc.right = rc.left + hhTerm->xBezel;
  186. k = ((hhTerm->iVScrlMax - hhTerm->iVScrlPos + hhTerm->iTermHite)
  187. * hhTerm->yChar) + (hhTerm->cy % hhTerm->yChar);
  188. rc.top = (-hhTerm->iVScrlPos * hhTerm->yChar) + OUTDENT;
  189. rc.bottom = k - OUTDENT;
  190. if (IntersectRect(&rci, &rc, &ps.rcPaint))
  191. {
  192. /* --- Paint outer border --- */
  193. SelectObject(hdc, hhTerm->hWhitePen);
  194. MoveToEx(hdc, rc.left, rc.top++, NULL);
  195. LineTo(hdc, rc.left++, rc.bottom--);
  196. MoveToEx(hdc, rc.left, rc.top++, NULL);
  197. LineTo(hdc, rc.left++, rc.bottom--);
  198. /* --- Paint middle portion --- */
  199. rc.right = rc.left + n;
  200. FillRect(hdc, &rc, hhTerm->hbrushBackScrl);
  201. rc.left += n;
  202. rc.top += n;
  203. rc.bottom -= n;
  204. /* --- Paint inner border --- */
  205. SelectObject(hdc, hhTerm->hDkGrayPen);
  206. MoveToEx(hdc, rc.left, rc.top++, NULL);
  207. LineTo(hdc, rc.left++, rc.bottom--);
  208. SelectObject(hdc, hhTerm->hBlackPen);
  209. MoveToEx(hdc, rc.left, rc.top, NULL);
  210. LineTo(hdc, rc.left, rc.bottom);
  211. }
  212. /* -------------- Bottom edge ------------- */
  213. rc.left = xl + OUTDENT;
  214. rc.right = xr + hhTerm->xIndent + hhTerm->xBezel - 1 - OUTDENT;
  215. l = rc.right; // save for right side.
  216. rc.bottom = k;
  217. rc.top = rc.bottom - hhTerm->xBezel;
  218. if (IntersectRect(&rci, &rc, &ps.rcPaint))
  219. {
  220. /* --- Paint from bezel to bottom of screen --- */
  221. m = rc.top;
  222. rc.top = rc.bottom - OUTDENT;
  223. FillRect(hdc, &rc, hhTerm->hbrushBackScrl);
  224. rc.top = m;
  225. rc.bottom -= OUTDENT + 1;
  226. /* --- Paint outer border --- */
  227. SelectObject(hdc, hhTerm->hBlackPen);
  228. MoveToEx(hdc, rc.left++, rc.bottom, NULL);
  229. LineTo(hdc, rc.right--, rc.bottom--);
  230. SelectObject(hdc, hhTerm->hDkGrayPen);
  231. MoveToEx(hdc, rc.left++, rc.bottom, NULL);
  232. LineTo(hdc, rc.right--, rc.bottom);
  233. /* --- Paint middle portion --- */
  234. rc.top = rc.bottom - n;
  235. FillRect(hdc, &rc, hhTerm->hbrushBackScrl);
  236. rc.left += n;
  237. rc.right -= n-1;
  238. rc.bottom -= n;
  239. /* --- Paint inner border --- */
  240. SelectObject(hdc, hhTerm->hWhitePen);
  241. MoveToEx(hdc, rc.left++, rc.bottom, NULL);
  242. LineTo(hdc, rc.right--, rc.bottom--);
  243. MoveToEx(hdc, rc.left++, rc.bottom, NULL);
  244. LineTo(hdc, rc.right--, rc.bottom--);
  245. SelectObject(hdc, hhTerm->hDkGrayPen);
  246. MoveToEx(hdc, rc.left++, rc.bottom, NULL);
  247. LineTo(hdc, rc.right--, rc.bottom--);
  248. /* --- Fill in the bottom below bezel --- */
  249. rc.top = k;
  250. rc.bottom = rc.top + OUTDENT;
  251. rc.left = xl + OUTDENT;
  252. rc.right = l + 1;
  253. FillRect(hdc, &rc, hhTerm->hbrushBackScrl);
  254. }
  255. /* -------------- Right edge ------------- */
  256. rc.top = (-hhTerm->iVScrlPos * hhTerm->yChar) + OUTDENT;
  257. rc.bottom = k;
  258. rc.right = l + OUTDENT + 1;
  259. rc.left = rc.right - hhTerm->xBezel;
  260. if (IntersectRect(&rci, &rc, &ps.rcPaint))
  261. {
  262. /* --- Paint outdent region --- */
  263. rc.left = l;
  264. FillRect(hdc, &rc, hhTerm->hbrushBackScrl);
  265. rc.bottom -= OUTDENT;
  266. rc.right -= OUTDENT + 1;
  267. /* --- Paint outer border --- */
  268. SelectObject(hdc, hhTerm->hBlackPen);
  269. MoveToEx(hdc, rc.right, rc.top++, NULL);
  270. LineTo(hdc, rc.right--, rc.bottom--);
  271. SelectObject(hdc, hhTerm->hDkGrayPen);
  272. MoveToEx(hdc, rc.right, rc.top++, NULL);
  273. LineTo(hdc, rc.right, rc.bottom--);
  274. /* --- Paint middle portion --- */
  275. rc.left = rc.right - n;
  276. FillRect(hdc, &rc, hhTerm->hbrushBackScrl);
  277. rc.top += n-1;
  278. rc.right -= n;
  279. rc.bottom -= n-1;
  280. /* --- Paint inner border --- */
  281. SelectObject(hdc, hhTerm->hWhitePen);
  282. MoveToEx(hdc, rc.right, rc.top++, NULL);
  283. LineTo(hdc, rc.right--, rc.bottom--);
  284. MoveToEx(hdc, rc.right, rc.top++, NULL);
  285. LineTo(hdc, rc.right--, rc.bottom--);
  286. SelectObject(hdc, hhTerm->hDkGrayPen);
  287. MoveToEx(hdc, rc.right, rc.top++, NULL);
  288. LineTo(hdc, rc.right--, rc.bottom--);
  289. /* --- Fill area to right of bezel --- */
  290. rc.left = l + 1;
  291. rc.right = rc.left + OUTDENT;
  292. rc.top = -hhTerm->iVScrlPos * hhTerm->yChar;
  293. rc.bottom = k + OUTDENT;
  294. FillRect(hdc, &rc, hhTerm->hbrushBackScrl);
  295. }
  296. }
  297. }
  298. // Paint backscroll buffer. Stuff going into the backscroll
  299. // region is always on a line basis. You'll notice that the
  300. // calculation for l in the terminal area portion is more
  301. // complicated since stuff comes in at times on a character
  302. // basis. l represents the number of characters in the
  303. // character string to paint.
  304. i = iPaintBeg;
  305. if (i < iPaintEnd && i < 0)
  306. {
  307. j = (ps.rcPaint.left - hhTerm->xIndent
  308. - (hhTerm->iHScrlPos ? 0 : hhTerm->xBezel)) / hhTerm->xChar;
  309. j = max(j, 0);
  310. k = (j * hhTerm->xChar) + hhTerm->xIndent
  311. + (hhTerm->iHScrlPos ? 0 : hhTerm->xBezel);
  312. j += hhTerm->iHScrlPos - (hhTerm->xBezel && hhTerm->iHScrlPos ? 1:0);
  313. l = min(hhTerm->iCols - j,
  314. (ps.rcPaint.right + hhTerm->xChar - 1 - k) / hhTerm->xChar);
  315. fplpstrTxt = hhTerm->fplpstrBkTxt;
  316. m = hhTerm->iPhysicalBkRows;
  317. if (hhTerm->fBackscrlLock == TRUE)
  318. iOffset = (abs(hhTerm->iVScrlPos - i) + hhTerm->iNextBkLn) % m;
  319. else
  320. iOffset = (m + i + hhTerm->iNextBkLn) % m;
  321. n = iScrlInc * (-hhTerm->iVScrlPos + i);
  322. #ifdef CHAR_NARROW
  323. for ( ; i < iPaintEnd && i < 0 ; i+=1, n+=iScrlInc)
  324. {
  325. TextAttrOut(hhTerm, hdc, k, n, fplpstrTxt[iOffset]+j,
  326. (PSTATTR)0, FALSE, l, i, j);
  327. if (++iOffset >= m)
  328. iOffset = 0;
  329. }
  330. #else
  331. // This little hack is here to display wide (Kanji) characters in
  332. // the backscroll, without all of the fuss of adding attributes.
  333. // It forces the backscroll to always paint the
  334. // enitre row, and strips out the repeated left/right pairs
  335. j = (OUTDENT - (hhTerm->iHScrlPos ? 0 : hhTerm->xBezel)) / hhTerm->xChar;
  336. j = max(j, 0);
  337. k = (j * hhTerm->xChar) + OUTDENT
  338. + (hhTerm->iHScrlPos ? 0 : hhTerm->xBezel);
  339. j += hhTerm->iHScrlPos - (hhTerm->xBezel && hhTerm->iHScrlPos ? 1:0);
  340. l = hhTerm->iCols - j;
  341. for ( ; i < iPaintEnd && i < 0 ; i+=1, n+=iScrlInc)
  342. {
  343. // Hack for starting on the right half of a DB char
  344. fRight = FALSE;
  345. for (x = 0; x <= j; )
  346. {
  347. if (isDBCSChar(*(fplpstrTxt[iOffset]+x)))
  348. {
  349. fRight = (x == j) ? FALSE : TRUE;
  350. x += 2;
  351. }
  352. else
  353. {
  354. fRight = FALSE;
  355. x += 1;
  356. }
  357. }
  358. memset(aechTmpBuf, 0, sizeof(aechTmpBuf));
  359. StrCharStripDBCSString(aechTmpBuf, sizeof(aechTmpBuf),
  360. fplpstrTxt[iOffset]+j); //mpt:12-11-97 too many parameters? , l * sizeof(ECHAR));
  361. TextAttrOut(hhTerm, hdc, k, n, aechTmpBuf,
  362. (PSTATTR)0, fRight, l, i, j);
  363. if (++iOffset >= m)
  364. iOffset = 0;
  365. }
  366. #endif
  367. }
  368. /* -------------- Paint divider bar if necessary ------------- */
  369. for ( ; i == 0 ; ++i)
  370. {
  371. if (hhTerm->xBezel)
  372. {
  373. // n is the width of the thick gray section of the bezel.
  374. // we surround the thick gray part with four lines of
  375. // of white and gray lines. That's why we subtract 4.
  376. n = hhTerm->xBezel - OUTDENT - 4;
  377. rc.top = -hhTerm->iVScrlPos * hhTerm->yChar;
  378. rc.bottom = rc.top + OUTDENT;
  379. rc.left = ps.rcPaint.left;
  380. rc.right = ps.rcPaint.right;
  381. /* --- Paint gap above divider bar --- */
  382. FillRect(hdc, &rc, hhTerm->hbrushBackScrl);
  383. rc.left = xl + hhTerm->xBezel + hhTerm->xIndent;
  384. rc.right = xr;
  385. /* --- If hightlighting, paint gap above divider --- */
  386. if (min(hhTerm->ptBeg.y, hhTerm->ptEnd.y) < 0 &&
  387. max(hhTerm->ptBeg.y, hhTerm->ptEnd.y) > 0)
  388. {
  389. FillRect(hdc, &rc, hhTerm->hbrushHighlight);
  390. }
  391. rc.left = xl + OUTDENT;
  392. rc.right = xr + hhTerm->xIndent + hhTerm->xBezel - OUTDENT - 1;
  393. /* --- note: order is important, bottom, top --- */
  394. rc.bottom = rc.top + hhTerm->yChar;
  395. rc.top += OUTDENT;
  396. /* --- Paint top outside border --- */
  397. SelectObject(hdc, hhTerm->hWhitePen);
  398. MoveToEx(hdc, rc.left++, rc.top, NULL);
  399. LineTo(hdc, rc.right--, rc.top++);
  400. MoveToEx(hdc, rc.left++, rc.top, NULL);
  401. LineTo(hdc, rc.right--, rc.top++);
  402. /* --- Paint middle section --- */
  403. m = rc.bottom;
  404. rc.bottom = rc.top + n;
  405. FillRect(hdc, &rc, hhTerm->hbrushBackScrl);
  406. rc.bottom = m;
  407. rc.left += n;
  408. rc.top += n;
  409. rc.right -= n;
  410. /* --- Paint bottom border --- */
  411. SelectObject(hdc, hhTerm->hDkGrayPen);
  412. MoveToEx(hdc, rc.left++, rc.top, NULL);
  413. LineTo(hdc, rc.right--, rc.top++);
  414. SelectObject(hdc, hhTerm->hBlackPen);
  415. MoveToEx(hdc, rc.left++, rc.top, NULL);
  416. LineTo(hdc, rc.right, rc.top++);
  417. /* --- Fill in any space left below the bezel --- */
  418. FillRect(hdc, &rc, hhTerm->hbrushTerminal);
  419. if (min(hhTerm->ptBeg.y, hhTerm->ptEnd.y) < 0 &&
  420. max(hhTerm->ptBeg.y, hhTerm->ptEnd.y) > 0)
  421. {
  422. rc.left = hhTerm->xIndent;
  423. rc.left += (hhTerm->iHScrlPos) ? 0 : hhTerm->xBezel;
  424. rc.right -= hhTerm->xIndent;
  425. FillRect(hdc, &rc, hhTerm->hbrushHighlight);
  426. }
  427. }
  428. else
  429. {
  430. j = (hhTerm->yChar * -hhTerm->iVScrlPos);
  431. k = (hhTerm->yChar) / 3;
  432. // Create highlight brush if textmarking crosses divider
  433. if (min(hhTerm->ptBeg.y, hhTerm->ptEnd.y) < 0 &&
  434. max(hhTerm->ptBeg.y, hhTerm->ptEnd.y) > 0)
  435. {
  436. hBrush = hhTerm->hbrushHighlight;
  437. }
  438. else
  439. {
  440. hBrush = 0;
  441. }
  442. rc = ps.rcPaint;
  443. rc.top = j;
  444. rc.bottom = j + k + (hhTerm->yChar % 3);
  445. l = rc.right =
  446. ((hhTerm->iCols - hhTerm->iHScrlPos) * hhTerm->xChar)
  447. + hhTerm->xIndent + hhTerm->xIndent +
  448. hhTerm->xBezel + hhTerm->xBezel;
  449. FillRect(hdc, &rc, (hBrush != (HBRUSH)0) ?
  450. hBrush :
  451. hhTerm->hbrushBackScrl);
  452. rc.top = rc.bottom;
  453. rc.bottom = rc.top + k;
  454. rc.right = ps.rcPaint.right;
  455. FillRect(hdc, &rc, hhTerm->hbrushDivider);
  456. rc.top = rc.bottom;
  457. rc.bottom = j + hhTerm->yChar;
  458. rc.right = l;
  459. FillRect(hdc, &rc, (hBrush != (HBRUSH)0) ?
  460. hBrush :
  461. hhTerm->hbrushTerminal);
  462. }
  463. }
  464. /* -------------- Paint the active terminal portion. ------------- */
  465. xl = (hhTerm->iHScrlPos) ? 0 : hhTerm->xBezel;
  466. if (i < iPaintEnd)
  467. {
  468. j = (ps.rcPaint.left - hhTerm->xIndent - xl) / hhTerm->xChar;
  469. j = max(j, 0);
  470. k = (j * hhTerm->xChar) + hhTerm->xIndent + xl;
  471. j += hhTerm->iHScrlPos - (hhTerm->xBezel && hhTerm->iHScrlPos ? 1:0);
  472. l = min(hhTerm->iCols - j,
  473. (ps.rcPaint.right + hhTerm->xChar - 1 - k) / hhTerm->xChar);
  474. // Formulas to convert from terminal to buffer row and back.
  475. // b = (t - 1 + top) % rows
  476. // t = (b + rows - top) % rows
  477. // t is always between 1 and rows+1.
  478. iOffset = (i - 1 + hhTerm->iTopline) % MAX_EMUROWS;
  479. n = iScrlInc * (-hhTerm->iVScrlPos + i);
  480. for ( ; i < iPaintEnd ; i += 1, n += iScrlInc)
  481. {
  482. TextAttrOut(hhTerm, hdc, k, n, hhTerm->fplpstrTxt[iOffset]+j,
  483. hhTerm->fppstAttr[iOffset]+j, FALSE, l, i, j);
  484. if (++iOffset >= MAX_EMUROWS)
  485. iOffset = 0;
  486. }
  487. }
  488. /* --- Draw cursors --- */
  489. if (hhTerm->fHstCurOn)
  490. {
  491. hhTerm->fHstCurOn = FALSE;
  492. PaintHostCursor(hhTerm, TRUE, hdc);
  493. }
  494. if (hhTerm->fLclCurOn)
  495. {
  496. hhTerm->fLclCurOn = FALSE;
  497. PaintLocalCursor(hhTerm, TRUE, hdc);
  498. }
  499. /* --- cleanup time --- */
  500. SelectObject(hdc, GetStockObject(WHITE_BRUSH));
  501. SelectObject(hdc, GetStockObject(BLACK_PEN));
  502. SelectObject(hdc, hFont);
  503. EndPaint(hwnd, &ps);
  504. return;
  505. }
  506. /*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-
  507. * FUNCTION:
  508. * TextAttrOut
  509. *
  510. * DESCRIPTION:
  511. * Draws text and attributes on the terminal screen. Optimizes call to
  512. * TextOut based on attributes. For example, If attributes are all the
  513. * same for a given line, then only one call to TextOut is made.
  514. *
  515. * ARGUMENTS:
  516. * HHTERM hhTerm - internal terminal handle
  517. * HDC hdc - Device context from WM_PAINT
  518. * int x - x offset in pixels
  519. * int y - y offset in pixels
  520. * ECHAR *lpachText - long pointer to begining of text to print
  521. * PSTATTR apstAttrs - Array of pointers to attribute structures
  522. * int fForceRight - used for DBCS in the backscroll
  523. * int nCount - number of characters to draw.
  524. * int iRow - logical row being displayed
  525. * int iCol - logical col being displayed
  526. *
  527. * RETURNS:
  528. * void
  529. *
  530. */
  531. static void TextAttrOut(const HHTERM hhTerm,
  532. const HDC hdc,
  533. const int x,
  534. const int y,
  535. const ECHAR *lpachText,
  536. const PSTATTR apstAttrs,
  537. const int fForceRight,
  538. const int nCount,
  539. const int iRow,
  540. const int iCol)
  541. {
  542. int i = 0, // track of how many chars drawn.
  543. j, // number of characters in a run.
  544. k, // offset where run began.
  545. nXPos;
  546. int nXStart, nYStart; // screen pos where chars are drawn.
  547. #ifndef CHAR_NARROW
  548. int nByteCount = 0;
  549. #endif
  550. int nBegAdj = 0;
  551. int nEndAdj = 0;
  552. int nStrLen = 0;
  553. TCHAR achBuf[MAX_EMUCOLS * 2];
  554. ECHAR aechTmp[MAX_EMUCOLS + 1];
  555. PSTATTR pstAttr = 0;
  556. unsigned int uTxtclr, uBkclr;
  557. BOOL fUnderlnFont = FALSE;
  558. BOOL fSymbolFont = FALSE;
  559. BOOL fDblHiHi = FALSE;
  560. BOOL fDblHiLo = FALSE;
  561. BOOL fDblWiLf = FALSE;
  562. BOOL fDblWiRt = FALSE;
  563. BOOL fWiLf = FALSE;
  564. BOOL fWiRt = FALSE;
  565. BOOL fFirstPass = TRUE;
  566. RECT rc;
  567. DbgOutStr("TAO %d\r\n", iRow, 0, 0, 0, 0);
  568. while (i < nCount)
  569. {
  570. k = i; // save offset of where this run begins in k.
  571. if (iRow < 0)
  572. {
  573. int nCurPos;
  574. long l,
  575. lBeg,
  576. lEnd;
  577. BOOL fMarking = FALSE;
  578. // Store the positions of the 1st char to draw
  579. nCurPos = i;
  580. // This check is a speed tweak. If the marking and backscrl
  581. // locks are off, we know that no text is can be marked. This
  582. // would be the normal case when stuff is streaming into the
  583. // terminal so we save the work done of the else body by
  584. // by checking and thus speed up the display.
  585. // For Far East we have to force the backscroll to paint every
  586. // character individualy. This is becuase MicroSquish is not
  587. // able to provide fixed pitch fonts that are fixed pitch for
  588. // DBCS characters.
  589. //
  590. if (hhTerm->fMarkingLock == FALSE &&
  591. hhTerm->fBackscrlLock == FALSE &&
  592. hhTerm->iEvenFont == TRUE)
  593. {
  594. SetBkColor(hdc, hhTerm->crBackScrl);
  595. SetTextColor(hdc, hhTerm->crBackScrlTxt);
  596. i = j = nCount;
  597. }
  598. else
  599. {
  600. #ifdef CHAR_NARROW
  601. lBeg = hhTerm->ptBeg.y * hhTerm->iCols + hhTerm->ptBeg.x;
  602. lEnd = hhTerm->ptEnd.y * hhTerm->iCols + hhTerm->ptEnd.x;
  603. #else
  604. // Hack city man :)
  605. // In the mouse handling routines, we modify the selection
  606. // cursor position so that you can't put it into the middle
  607. // of a wide character. The problem is that at this
  608. // point the repeated characters have been removed.
  609. // Therefore we need to modify the cursor position to take
  610. // into account the number of repeated characters that
  611. // were removed from the string as of our current drawing
  612. // position into that string.
  613. // pant, pant, pant.
  614. lBeg = hhTerm->ptBeg.x;
  615. lEnd = hhTerm->ptEnd.x;
  616. if (hhTerm->ptBeg.y == iRow)
  617. {
  618. lBeg = MapCells(lpachText , hhTerm->iCols, hhTerm->ptBeg.x);
  619. }
  620. if (hhTerm->ptEnd.y == iRow)
  621. {
  622. lEnd = MapCells(lpachText , hhTerm->iCols, hhTerm->ptEnd.x);
  623. }
  624. if (hhTerm->iEvenFont)
  625. {
  626. nBegAdj = lBeg - hhTerm->ptBeg.x;
  627. nEndAdj = lEnd - hhTerm->ptEnd.x;
  628. }
  629. else
  630. {
  631. nBegAdj = 0;
  632. nEndAdj = 0;
  633. }
  634. lBeg = hhTerm->ptBeg.y * hhTerm->iCols + lBeg;
  635. lEnd = hhTerm->ptEnd.y * hhTerm->iCols + lEnd;
  636. #endif
  637. if (lBeg > lEnd)
  638. {
  639. l = lEnd;
  640. lEnd = lBeg;
  641. lBeg = l;
  642. }
  643. // IN_RANGE macro is inclusive so subtract one from sEnd
  644. // which at this point is known to be larger than sBeg
  645. lEnd -= 1;
  646. l = iRow * hhTerm->iCols + i + iCol;
  647. fMarking = (BOOL)IN_RANGE(l, lBeg, lEnd);
  648. if (fMarking)
  649. {
  650. SetBkColor(hdc, GetSysColor(COLOR_HIGHLIGHT));
  651. SetTextColor(hdc, GetSysColor(COLOR_HIGHLIGHTTEXT));
  652. }
  653. else
  654. {
  655. SetBkColor(hdc, hhTerm->crBackScrl);
  656. SetTextColor(hdc, hhTerm->crBackScrlTxt);
  657. }
  658. // For Far East we have to force the backscroll to paint every
  659. // character individualy. This is becuase MicroSquish is not
  660. // able to provide fixed pitch fonts that are fixed pitch for
  661. // DBCS characters.
  662. if (hhTerm->iEvenFont)
  663. {
  664. for (j = 0 ; i < nCount ; ++i, ++j, ++l)
  665. {
  666. if (fMarking != (BOOL)IN_RANGE(l, lBeg, lEnd))
  667. break;
  668. }
  669. }
  670. else
  671. {
  672. i++;
  673. j = 1;
  674. }
  675. }
  676. nXPos = k = i - j;
  677. #ifndef CHAR_NARROW
  678. if (nCurPos > 0) // Only copy the buffer if nCurPos > 0. REV: 04/11/2001.
  679. {
  680. MemCopy(aechTmp, lpachText , (unsigned)nCurPos * sizeof(ECHAR));
  681. nXPos = CnvrtECHARtoMBCS(achBuf, sizeof(achBuf), aechTmp, (unsigned)nCurPos * sizeof(ECHAR));
  682. //nXPos = StrCharGetByteCount(achBuf); // mrw;5/17/95
  683. }
  684. // 18-May-1995 DLW
  685. // Added for the case where a DBCS string is started with half of
  686. // the character, like when scrolling to the right
  687. if (fForceRight && fFirstPass)
  688. {
  689. fWiRt = TRUE;
  690. }
  691. else
  692. {
  693. if (fForceRight)
  694. nXPos = max(0, nXPos - 1);
  695. }
  696. #endif
  697. }
  698. // At this point we know were not painting in the backscrl area.
  699. // Since the terminal area has attributes that backscrl does not
  700. // have (ie. color, underlining, etc.) we need to do more work.
  701. //
  702. else
  703. {
  704. pstAttr = apstAttrs+i;
  705. uTxtclr = pstAttr->txtclr;
  706. uBkclr = pstAttr->bkclr;
  707. // Test for attributes
  708. if (pstAttr->revvid)
  709. {
  710. unsigned uTmp = uTxtclr;
  711. uTxtclr = uBkclr;
  712. uBkclr = uTmp;
  713. }
  714. if (pstAttr->hilite)
  715. {
  716. // Colors are arranged so that high intensity colors are
  717. // in the lower half of the color array (currently 16
  718. // colors corresponding to the IBM PC colors). This
  719. // guy sets the color to the opposite intensity.
  720. uTxtclr = (uTxtclr + (MAX_EMUCOLORS/2)) % MAX_EMUCOLORS;
  721. if (uTxtclr == uBkclr)
  722. uTxtclr = (uTxtclr + 1) % MAX_EMUCOLORS;
  723. }
  724. if (pstAttr->bklite)
  725. {
  726. uBkclr = (uBkclr + (MAX_EMUCOLORS/2)) % MAX_EMUCOLORS;
  727. if (uBkclr == uTxtclr)
  728. uBkclr = (uBkclr + 1) % MAX_EMUCOLORS;
  729. }
  730. if (pstAttr->blink)
  731. {
  732. int iBufRow;
  733. if (hhTerm->iBlink == 0)
  734. hhTerm->iBlink = 1;
  735. if (hhTerm->iBlink == -1)
  736. uTxtclr = uBkclr;
  737. iBufRow = (iRow - 1 + hhTerm->iTopline) % MAX_EMUROWS;
  738. hhTerm->abBlink[iBufRow] = (BYTE)TRUE;
  739. }
  740. if (pstAttr->undrln)
  741. fUnderlnFont = TRUE;
  742. if (pstAttr->blank)
  743. uTxtclr = uBkclr;
  744. // Only allow one double height attribute
  745. //
  746. if (pstAttr->dblhihi)
  747. fDblHiHi = TRUE;
  748. else if (pstAttr->dblhilo)
  749. fDblHiLo = TRUE;
  750. // Only allow one double wide attribute
  751. //
  752. if (pstAttr->dblwilf)
  753. fDblWiLf = TRUE;
  754. else if (pstAttr->dblwirt)
  755. fDblWiRt = TRUE;
  756. // Only allow one wide attribute
  757. //
  758. if (pstAttr->wilf)
  759. fWiLf = TRUE;
  760. else if (pstAttr->wirt)
  761. fWiRt = TRUE;
  762. // If the symbol attribute is on, use alternate font.
  763. //
  764. if (pstAttr->symbol)
  765. fSymbolFont = TRUE;
  766. // Find the longest run of characters with the same attributes.
  767. //
  768. for (j = 0 ; i < nCount ; ++i, ++j)
  769. {
  770. if (memcmp(pstAttr, apstAttrs+i, sizeof(STATTR)) != 0)
  771. break;
  772. }
  773. /* --- Set text and background colors --- */
  774. if (pstAttr->txtmrk)
  775. {
  776. SetBkColor(hdc, GetSysColor(COLOR_HIGHLIGHT));
  777. SetTextColor(hdc, GetSysColor(COLOR_HIGHLIGHTTEXT));
  778. }
  779. else
  780. {
  781. SetBkColor(hdc, hhTerm->pacrEmuColors[uBkclr]);
  782. SetTextColor(hdc, hhTerm->pacrEmuColors[uTxtclr]);
  783. }
  784. /* --- How hard can it be to pick a font? --- */
  785. if (fDblHiHi || fDblHiLo)
  786. {
  787. if (fDblWiLf || fDblWiRt)
  788. {
  789. if (fSymbolFont)
  790. {
  791. if (hhTerm->hSymDblHiWiFont == 0)
  792. hhTerm->hSymDblHiWiFont = termMakeFont(hhTerm, 0, 1, 1, 1);
  793. SelectObject(hdc, hhTerm->hSymDblHiWiFont);
  794. }
  795. else
  796. {
  797. if (hhTerm->hDblHiWiFont == 0)
  798. hhTerm->hDblHiWiFont = termMakeFont(hhTerm, 0, 1, 1, 0);
  799. SelectObject(hdc, hhTerm->hDblHiWiFont);
  800. }
  801. }
  802. else
  803. {
  804. if (fSymbolFont)
  805. {
  806. if (hhTerm->hSymDblHiFont == 0)
  807. hhTerm->hSymDblHiFont = termMakeFont(hhTerm, 0, 1, 0, 1);
  808. SelectObject(hdc, hhTerm->hSymDblHiFont);
  809. }
  810. else
  811. {
  812. if (hhTerm->hDblHiFont == 0)
  813. hhTerm->hDblHiFont = termMakeFont(hhTerm, 0, 1, 0, 0);
  814. SelectObject(hdc, hhTerm->hDblHiFont);
  815. }
  816. }
  817. }
  818. else if (fDblWiLf || fDblWiRt)
  819. {
  820. if (fSymbolFont)
  821. {
  822. if (hhTerm->hSymDblWiFont == 0)
  823. hhTerm->hSymDblWiFont = termMakeFont(hhTerm, 0, 0, 1, 1);
  824. SelectObject(hdc, hhTerm->hSymDblWiFont);
  825. }
  826. else
  827. {
  828. if (hhTerm->hDblWiFont == 0)
  829. hhTerm->hDblWiFont = termMakeFont(hhTerm, 0, 0, 1, 0);
  830. SelectObject(hdc, hhTerm->hDblWiFont);
  831. }
  832. }
  833. else if (fSymbolFont)
  834. {
  835. if (hhTerm->hSymFont == 0)
  836. hhTerm->hSymFont = termMakeFont(hhTerm, 0, 0, 0, 1);
  837. SelectObject(hdc, hhTerm->hSymFont);
  838. }
  839. nXPos = k = i - j;
  840. }
  841. // Ok, go ahead, paint that text, make my day...
  842. // Guess I better explain myself here. When Windows synthesizes
  843. // a font to get something like bold or italic, TextOut has a nasty
  844. // habit of adding a pixel to the end of the string (be it a
  845. // character or a run of characters). This is documented in the
  846. // TEXTMETRIC structure in the description of tmOverHang. This has
  847. // some unfortunate side effects (Don't believe me? Try defing the
  848. // old stuff back in, select a bold font and do some hightlighting
  849. // and scrolling). The solution is to explicitly clip so that text
  850. // is drawn only where I say it can draw. This amounts in extra
  851. // work but the end result seems no slower. - mrw
  852. //
  853. rc.left = x + (nXPos * hhTerm->xChar);
  854. #if defined(FAR_EAST)
  855. if (rc.left > (x + (hhTerm->iCols * hhTerm->xChar)))
  856. rc.left = x + (hhTerm->iCols * hhTerm->xChar);
  857. #endif
  858. rc.right = rc.left + ((j - nEndAdj) * hhTerm->xChar);
  859. if (rc.right > (x + (hhTerm->iCols * hhTerm->xChar)))
  860. rc.right = x + (hhTerm->iCols * hhTerm->xChar);
  861. rc.top = y;
  862. rc.bottom = y + hhTerm->yChar;
  863. // If we're painting the bottom half of a double high character,
  864. // we need to raise the origin of where the character is drawn
  865. // by an additional char height. The clipping rectangle insures
  866. // that only the cell portion is actually drawn.
  867. nYStart = (fDblHiHi) ? rc.bottom + hhTerm->yChar : rc.bottom;
  868. // More painting tricks. If we're painting double wide characters
  869. // we'll be painting them one at a time. Why you ask? Well, this
  870. // routine tries to paint the longest run of characters with the
  871. // same attributes. Just makes good windows sense. In the case
  872. // of double wide however, the attributes come as double-wide left,
  873. // double-wide right. Since the "double-wide" character has a
  874. // different attribute in its left side and right side, this
  875. // routine will paint each half one at a time (seperate calls to
  876. // ExtTextOut()). This is useful and wanted. Because we clip
  877. // the drawing area to the cell or cells region, we can draw the
  878. // right half by offsetting the x origin by one character cell
  879. // to the left. Windows clipping logic will only draw in the
  880. // actual cell region so we get the right half of the character.
  881. // Lot of explaination for one measely line of code.
  882. //
  883. nXStart = (fDblWiRt || fWiRt) ? rc.left - hhTerm->xChar : rc.left;
  884. /* --- Hero of the day, ExtTextOut! --- */
  885. MemCopy(aechTmp, lpachText + k, (unsigned int)j * sizeof(ECHAR));
  886. nStrLen = CnvrtECHARtoMBCS(achBuf, sizeof(achBuf), aechTmp,
  887. (unsigned)j * sizeof(ECHAR)); //mrw:5/17/95
  888. achBuf[nStrLen] = TEXT('\0');
  889. #if defined(FAR_EAST) // mrw:10/10/95 - ifdef'ed this code
  890. if (!hhTerm->iEvenFont && !(fForceRight && fFirstPass))
  891. {
  892. // If this is a DBCS character we are painting, then we want to paint 2 cells
  893. // instead of 1 (makes sense, DBCS characters are twice as wide as SBCS).
  894. if (IsDBCSLeadByte(*achBuf))
  895. {
  896. rc.right += hhTerm->xChar;
  897. rc.right = min(rc.right, x + (hhTerm->iCols * hhTerm->xChar));
  898. }
  899. }
  900. #endif
  901. ExtTextOut(hdc, nXStart, nYStart, ETO_CLIPPED | ETO_OPAQUE,
  902. &rc, achBuf, (unsigned)nStrLen, 0);
  903. // Experiment. Most terminals underline their fonts by placing
  904. // underscores under the characters. The Windows underline font
  905. // places a thin line through the baseline of the character.
  906. // Many hosts use underlining in conjunction with box draw chars
  907. // to envelop regions of the screen. The underscores complete
  908. // envelope and don't give the apperance of part of the characters
  909. // bleeding through. - mrw
  910. //
  911. if (fUnderlnFont)
  912. {
  913. // The double height makes the underscores too thick yet we
  914. // want to maintain the double-wide or symbol font we may be
  915. // using so check and recast the font to the samething without
  916. // the height component. - mrw
  917. //
  918. if (fDblHiHi || fDblHiLo)
  919. {
  920. if (fDblWiLf || fDblWiRt)
  921. {
  922. if (fSymbolFont)
  923. {
  924. if (hhTerm->hSymDblWiFont == 0)
  925. hhTerm->hSymDblWiFont = termMakeFont(hhTerm, 0, 0, 1, 1);
  926. SelectObject(hdc, hhTerm->hSymDblWiFont);
  927. }
  928. else
  929. {
  930. if (hhTerm->hDblWiFont == 0)
  931. hhTerm->hDblWiFont = termMakeFont(hhTerm, 0, 0, 1, 0);
  932. SelectObject(hdc, hhTerm->hDblWiFont);
  933. }
  934. }
  935. else if (fSymbolFont)
  936. {
  937. if (hhTerm->hSymFont == 0)
  938. hhTerm->hSymFont = termMakeFont(hhTerm, 0, 0, 0, 1);
  939. SelectObject(hdc, hhTerm->hSymFont);
  940. }
  941. else
  942. {
  943. SelectObject(hdc, hhTerm->hFont);
  944. }
  945. }
  946. // Set background to transparent so only the underscore
  947. // portion overpaints the character cell.
  948. //
  949. SetBkMode(hdc, TRANSPARENT);
  950. ExtTextOut(hdc, nXStart, nYStart, ETO_CLIPPED,
  951. &rc, hhTerm->underscores, (unsigned)j, 0);
  952. SetBkMode(hdc, OPAQUE);
  953. }
  954. /* --- Reselect the regular font only if we had to switch --- */
  955. if (fUnderlnFont || fDblHiHi || fDblHiLo || fDblWiLf || fDblWiRt
  956. || fSymbolFont)
  957. {
  958. SelectObject(hdc, hhTerm->hFont);
  959. fUnderlnFont = FALSE;
  960. fSymbolFont = FALSE;
  961. fDblHiHi = FALSE;
  962. fDblHiLo = FALSE;
  963. fDblWiLf = FALSE;
  964. fDblWiRt = FALSE;
  965. }
  966. fWiRt = FALSE;
  967. fWiLf = FALSE;
  968. fFirstPass = FALSE;
  969. }
  970. return;
  971. }
  972. /*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-
  973. * FUNCTION:
  974. * MapCells
  975. *
  976. * DESCRIPTION:
  977. * Maps screen cell position to internal screen image (echar image) position
  978. *
  979. * ARGUMENTS:
  980. * each - source string (does it start from beg of line?)
  981. * nStrLen - length in bytes
  982. * nCellPos - screen position to
  983. *
  984. * RETURNS:
  985. * void
  986. *
  987. */
  988. static int MapCells(const ECHAR *each, const int nStrLen, const int nCellPos)
  989. {
  990. int i, nCount;
  991. if (each == NULL)
  992. {
  993. assert(FALSE);
  994. return 0;
  995. }
  996. for (i = 0, nCount = 0; nCount < nCellPos && i < nStrLen; i++)
  997. {
  998. if (isDBCSChar(each[i]))
  999. {
  1000. nCount += 2;
  1001. }
  1002. else
  1003. {
  1004. nCount += 1;
  1005. }
  1006. }
  1007. return i;
  1008. }