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.

1406 lines
37 KiB

  1. /****************************** Module Header ******************************\
  2. * Module Name: draw.c
  3. *
  4. * Copyright (c) 1985 - 1999, Microsoft Corporation
  5. *
  6. * This module contains common drawing functions.
  7. *
  8. * History:
  9. * 12-Feb-1992 MikeKe Moved Drawtext to the client side
  10. \***************************************************************************/
  11. CONST WCHAR szRadio[] = L"nmlkji";
  12. CONST WCHAR szCheck[] = L"gfedcb";
  13. /***************************************************************************\
  14. * FlipUserTextOutW
  15. *
  16. * Flip the check mark if the hdc is mirrored otherwise it just calls UserTextOutW
  17. *
  18. \***************************************************************************/
  19. BOOL FlipUserTextOutW(HDC hdc, int x, int y, LPCWSTR ch, int nCount)
  20. {
  21. BOOL bRet;
  22. int iOldTextAlign, iGraphicsModeOld;
  23. if ((UserGetLayout(hdc) & LAYOUT_RTL) &&
  24. (nCount == 1) &&
  25. ((ch[0] == TEXT('a')) ||(ch[0] == TEXT('b')))
  26. )
  27. {
  28. bRet = FALSE;
  29. //Check mark then set the hdc in GM_COMPATIBLE to unmirror it.
  30. if (iGraphicsModeOld = UserSetGraphicsMode(hdc, GM_COMPATIBLE))
  31. {
  32. iOldTextAlign = UserGetTextAlign(hdc);
  33. if ((iOldTextAlign & TA_CENTER) != TA_CENTER)
  34. {
  35. UserSetTextAlign(hdc, iOldTextAlign^TA_RIGHT);
  36. }
  37. bRet = UserTextOutW(hdc, x, y, ch, nCount);
  38. UserSetGraphicsMode(hdc, iGraphicsModeOld);
  39. UserSetTextAlign(hdc, iOldTextAlign);
  40. }
  41. } else {
  42. bRet = UserTextOutW(hdc, x, y, ch, nCount);
  43. }
  44. return bRet;
  45. }
  46. /***************************************************************************\
  47. * FillRect
  48. *
  49. * Callable from either client or server contexts
  50. *
  51. * History:
  52. * 29-Oct-1990 MikeHar Ported from Windows.
  53. \***************************************************************************/
  54. int APIENTRY FillRect(
  55. HDC hdc,
  56. LPCRECT prc,
  57. HBRUSH hBrush)
  58. {
  59. ULONG_PTR iBrush;
  60. POLYPATBLT PolyData;
  61. iBrush = (ULONG_PTR)hBrush - 1;
  62. if (iBrush <= COLOR_ENDCOLORS) {
  63. hBrush = SYSHBRUSH(iBrush);
  64. }
  65. PolyData.x = prc->left;
  66. PolyData.y = prc->top;
  67. PolyData.cx = prc->right - prc->left;
  68. PolyData.cy = prc->bottom - prc->top;
  69. PolyData.BrClr.hbr = hBrush;
  70. /*
  71. * Win95 incompatibility: they return either hBrush or the brush that
  72. * was previosuly selected in hdc. Not documented this way though.
  73. */
  74. return UserPolyPatBlt(hdc, PATCOPY, &PolyData, 1, PPB_BRUSH);
  75. }
  76. /***************************************************************************\
  77. * InvertRect
  78. *
  79. * Can be called from either the client or server contexts.
  80. *
  81. * History:
  82. * 29-Oct-1990 MikeHar Ported from Windows.
  83. \***************************************************************************/
  84. BOOL APIENTRY InvertRect(
  85. HDC hdc,
  86. LPCRECT prc)
  87. {
  88. return UserPatBlt(hdc,
  89. prc->left,
  90. prc->top,
  91. prc->right - prc->left,
  92. prc->bottom - prc->top,
  93. DSTINVERT);
  94. }
  95. /***************************************************************************\
  96. * DrawDiagonalLine
  97. *
  98. * History:
  99. \***************************************************************************/
  100. DWORD DrawDiagonalLine(
  101. HDC hdc,
  102. LPRECT lprc,
  103. int iDirection,
  104. int iThickness,
  105. UINT flags)
  106. {
  107. RECT rc;
  108. LPINT py;
  109. int cx;
  110. int cy;
  111. int dx;
  112. int dy;
  113. LPINT pc;
  114. POLYPATBLT ppbData[8];
  115. int ppbCount = 0;
  116. if (IsRectEmpty(lprc))
  117. return 0L;
  118. rc = *lprc;
  119. /*
  120. * We draw slopes < 1 by varying y instead of x.
  121. */
  122. --iThickness;
  123. /*
  124. * See WinBug #139374
  125. */
  126. cy = rc.bottom - rc.top;
  127. cx = rc.right - rc.left;
  128. if (!flags && (cy != cx))
  129. cy -= iThickness * SYSMETRTL(CYBORDER);
  130. if (cy >= cx) {
  131. /*
  132. * "slope" is >= 1, so vary x by 1
  133. */
  134. cy /= cx;
  135. pc = &cy;
  136. cx = SYSMETRTL(CXBORDER);
  137. } else {
  138. /*
  139. * "slope" is < 1, so vary y by 1
  140. */
  141. cx /= cy;
  142. pc = &cx;
  143. cy = SYSMETRTL(CYBORDER);
  144. }
  145. dx = cx;
  146. dy = iDirection * cy;
  147. *pc = (*pc + iThickness) * SYSMETRTL(CYBORDER);
  148. rc.right -= cx;
  149. rc.bottom -= cy;
  150. /*
  151. * For negative slopes, start from opposite side.
  152. */
  153. py = ((iDirection < 0) ? &rc.top : &rc.bottom);
  154. while ((rc.left <= rc.right) && (rc.top <= rc.bottom)) {
  155. if (!(flags & BF_MIDDLE)) {
  156. /*
  157. * UserPatBlt(hdc, rc.left, *py, cx, cy, PATCOPY);
  158. */
  159. ppbData[ppbCount].x = rc.left;
  160. ppbData[ppbCount].y = *py;
  161. ppbData[ppbCount].cx = cx;
  162. ppbData[ppbCount].cy = cy;
  163. ppbData[ppbCount].BrClr.hbr = NULL;
  164. ppbCount++;
  165. } else {
  166. /*
  167. * Fill interior. We can determine vertex in interior
  168. * by vector define.
  169. */
  170. if (cy > SYSMETRTL(CYBORDER)) {
  171. if (flags & BF_LEFT) {
  172. /*
  173. * UserPatBlt(hdc, rc.left, lprc->top, cx, *py - lprc->top + cy, PATCOPY);
  174. */
  175. ppbData[ppbCount].x = rc.left;
  176. ppbData[ppbCount].y = lprc->top;
  177. ppbData[ppbCount].cx = cx;
  178. ppbData[ppbCount].cy = *py - lprc->top + cy;
  179. ppbData[ppbCount].BrClr.hbr = NULL;
  180. ppbCount++;
  181. } else {
  182. /*
  183. * UserPatBlt(hdc, rc.left, *py, cx, lprc->bottom - *py, PATCOPY);
  184. */
  185. ppbData[ppbCount].x = rc.left;
  186. ppbData[ppbCount].y = *py;
  187. ppbData[ppbCount].cx = cx;
  188. ppbData[ppbCount].cy = lprc->bottom - *py;
  189. ppbData[ppbCount].BrClr.hbr = NULL;
  190. ppbCount++;
  191. }
  192. } else {
  193. if (flags & BF_TOP) {
  194. /*
  195. * UserPatBlt(hdc, rc.left, *py, lprc->right - rc.left, cy, PATCOPY);
  196. */
  197. ppbData[ppbCount].x = rc.left;
  198. ppbData[ppbCount].y = *py;
  199. ppbData[ppbCount].cx = lprc->right - rc.left;
  200. ppbData[ppbCount].cy = cy;
  201. ppbData[ppbCount].BrClr.hbr = NULL;
  202. ppbCount++;
  203. } else {
  204. /*
  205. * UserPatBlt(hdc, lprc->left, *py, rc.left - lprc->left + cx, cy, PATCOPY);
  206. */
  207. ppbData[ppbCount].x = lprc->left;
  208. ppbData[ppbCount].y = *py;
  209. ppbData[ppbCount].cx = rc.left - lprc->left + cx;
  210. ppbData[ppbCount].cy = cy;
  211. ppbData[ppbCount].BrClr.hbr = NULL;
  212. ppbCount++;
  213. }
  214. }
  215. }
  216. rc.left += dx;
  217. *py -= dy;
  218. /*
  219. * do we need to flush PolyPatBlt ?
  220. */
  221. if (ppbCount == 8) {
  222. UserPolyPatBlt(hdc, PATCOPY, &ppbData[0], 8, PPB_BRUSH);
  223. ppbCount = 0;
  224. }
  225. }
  226. /*
  227. * any left-over PolyPatblt buffered operations?
  228. */
  229. if (ppbCount != 0) {
  230. UserPolyPatBlt(hdc, PATCOPY, &ppbData[0], ppbCount, PPB_BRUSH);
  231. }
  232. return MAKELONG(cx, cy);
  233. }
  234. /***************************************************************************\
  235. * FillTriangle
  236. *
  237. * Fills in the triangle whose sides are two rectangle edges and a
  238. * diagonal. The vertex in the interior can be determined from the
  239. * vector type.
  240. *
  241. * History:
  242. \***************************************************************************/
  243. BOOL FillTriangle(
  244. HDC hdc,
  245. LPRECT lprc,
  246. HBRUSH hbr,
  247. UINT flags)
  248. {
  249. HBRUSH hbrT;
  250. int nDirection;
  251. switch (flags & (BF_RECT | BF_DIAGONAL)) {
  252. case BF_DIAGONAL_ENDTOPLEFT:
  253. case BF_DIAGONAL_ENDBOTTOMRIGHT:
  254. nDirection = -1;
  255. break;
  256. default:
  257. nDirection = 1;
  258. break;
  259. }
  260. hbrT = UserSelectBrush(hdc, hbr);
  261. DrawDiagonalLine(hdc, lprc, nDirection, 1, flags);
  262. /*
  263. * Don't care if the above functions failed for a bad hdc
  264. */
  265. return (UserSelectBrush(hdc, hbrT) != NULL);
  266. }
  267. /***************************************************************************\
  268. * DrawDiagonal
  269. *
  270. * Called by DrawEdge() for BF_DIAGONAL edges.
  271. *
  272. * Draws line of slope 1, one of 4 different ones. The difference is
  273. * where the line starts and where the end point is. The BF_ flags for
  274. * BF_DIAGONAL specify where the end point is. For example, BF_DIAGONAL |
  275. * BF_TOP | BF_LEFT means to draw a line ending up at the top left corner.
  276. * So the origin must be bottom right, and the angle must be 3pi/4, or
  277. * 135 degrees.
  278. *
  279. * History:
  280. \***************************************************************************/
  281. BOOL DrawDiagonal(
  282. HDC hdc,
  283. LPRECT lprc,
  284. HBRUSH hbrTL,
  285. HBRUSH hbrBR,
  286. UINT flags)
  287. {
  288. HBRUSH hbrT;
  289. int nDirection;
  290. DWORD dAdjust;
  291. /*
  292. * Away from light source
  293. */
  294. hbrT = ((flags & BF_BOTTOM) ? hbrBR : hbrTL);
  295. switch (flags & (BF_RECT | BF_DIAGONAL)){
  296. case BF_DIAGONAL_ENDTOPLEFT:
  297. case BF_DIAGONAL_ENDBOTTOMRIGHT:
  298. nDirection = -1;
  299. break;
  300. default:
  301. nDirection = 1;
  302. break;
  303. }
  304. hbrT = UserSelectBrush(hdc, hbrT);
  305. dAdjust = DrawDiagonalLine(hdc, lprc, nDirection, 1, (flags & ~BF_MIDDLE));
  306. /*
  307. * Adjust rectangle for next border
  308. */
  309. if (flags & BF_TOP)
  310. lprc->left += LOWORD(dAdjust);
  311. else
  312. lprc->right -= LOWORD(dAdjust);
  313. if (flags & BF_RIGHT)
  314. lprc->top += HIWORD(dAdjust);
  315. else
  316. lprc->bottom -= HIWORD(dAdjust);
  317. /*
  318. * Moved this to the end to save a check for return value
  319. */
  320. return (UserSelectBrush(hdc, hbrT) != NULL);
  321. }
  322. /***************************************************************************\
  323. * DrawGrip
  324. *
  325. * History:
  326. \***************************************************************************/
  327. BOOL DrawGrip(
  328. HDC hdc,
  329. LPRECT lprc,
  330. UINT wState)
  331. {
  332. int x;
  333. int y;
  334. int c;
  335. HBRUSH hbrOld;
  336. DWORD rgbHilight;
  337. DWORD rgbShadow;
  338. DWORD rgbOld;
  339. POLYPATBLT PolyData;
  340. c = min((lprc->right - lprc->left), (lprc->bottom - lprc->top));
  341. x = lprc->right - c; // right justify
  342. y = lprc->bottom - c; // bottom justify
  343. /*
  344. * Setup colors
  345. */
  346. if (wState & (DFCS_FLAT | DFCS_MONO)) {
  347. hbrOld = SYSHBR(WINDOW);
  348. rgbHilight = SYSRGBRTL(WINDOWFRAME);
  349. rgbShadow = SYSRGBRTL(WINDOWFRAME);
  350. } else {
  351. hbrOld = SYSHBR(3DFACE);
  352. rgbHilight = SYSRGBRTL(3DHILIGHT);
  353. rgbShadow = SYSRGBRTL(3DSHADOW);
  354. }
  355. PolyData.x = lprc->left;
  356. PolyData.y = lprc->top;
  357. PolyData.cx = lprc->right-lprc->left;
  358. PolyData.cy = lprc->bottom-lprc->top;
  359. PolyData.BrClr.hbr = hbrOld;
  360. UserPolyPatBlt(hdc, PATCOPY, &PolyData, 1, PPB_BRUSH);
  361. rgbOld = UserSetTextColor(hdc, rgbHilight);
  362. if (wState & DFCS_SCROLLSIZEGRIPRIGHT) {
  363. UserTextOutW(hdc, x, y, L"x", 1);
  364. UserSetTextColor(hdc, rgbShadow);
  365. UserTextOutW(hdc, x, y, L"y", 1);
  366. } else {
  367. UserTextOutW(hdc, x, y, L"o", 1);
  368. UserSetTextColor(hdc, rgbShadow);
  369. UserTextOutW(hdc, x, y, L"p", 1);
  370. }
  371. UserSetTextColor(hdc, rgbOld);
  372. return TRUE;
  373. }
  374. /***************************************************************************\
  375. * DrawBox
  376. *
  377. * History:
  378. \***************************************************************************/
  379. BOOL DrawBox(
  380. HDC hdc,
  381. LPRECT lprc,
  382. UINT wControlState)
  383. {
  384. int cx;
  385. int cy;
  386. int c;
  387. int x;
  388. int y;
  389. LPCWSTR lp = szRadio;
  390. int i;
  391. BOOL fSkip0thItem;
  392. COLORREF clr[6];
  393. COLORREF clrOld;
  394. fSkip0thItem = ((wControlState & (DFCS_BUTTON3STATE | DFCS_PUSHED |
  395. DFCS_INACTIVE | DFCS_CHECKED)) == (DFCS_BUTTON3STATE | DFCS_CHECKED));
  396. /*
  397. * Don't need radio mask with marlett font!
  398. */
  399. if (wControlState & DFCS_BUTTONRADIOMASK) {
  400. clr[0] = clr[1] = clr[2] = clr[3] = clr[4] = 0L;
  401. FillRect(hdc, lprc, ghbrWhite);
  402. } else {
  403. /*
  404. * DFCS_BUTTONRADIOIMAGE
  405. */
  406. if (wControlState & (DFCS_MONO | DFCS_FLAT)) {
  407. clr[1] = clr[2] = clr[3] = clr[4] = SYSRGBRTL(WINDOWFRAME);
  408. } else {
  409. clr[1] = SYSRGBRTL(3DLIGHT);
  410. clr[2] = SYSRGBRTL(3DDKSHADOW);
  411. clr[3] = SYSRGBRTL(3DHILIGHT);
  412. clr[4] = SYSRGBRTL(3DSHADOW);
  413. }
  414. if (wControlState & (DFCS_PUSHED | DFCS_INACTIVE))
  415. clr[0] = SYSRGBRTL(3DFACE);
  416. else if (fSkip0thItem)
  417. clr[0] = SYSRGBRTL(3DHILIGHT);
  418. else
  419. clr[0] = SYSRGBRTL(WINDOW);
  420. if (wControlState & DFCS_BUTTONRADIOIMAGE)
  421. FillRect(hdc, lprc, ghbrBlack);
  422. else if (!(wControlState & DFCS_BUTTONRADIO))
  423. lp = szCheck;
  424. }
  425. cx = lprc->right - lprc->left;
  426. cy = lprc->bottom - lprc->top;
  427. c = min(cx,cy);
  428. x = lprc->left + ((cx - c) / 2); // - 1;
  429. y = lprc->top + ((cy - c) / 2);
  430. if (fSkip0thItem &&
  431. ((gpsi->BitCount < 8) || (SYSRGB(3DHILIGHT) == RGB(255,255,255)))) {
  432. COLORREF clrBk;
  433. POLYPATBLT PolyData;
  434. /*
  435. * Make the interior of a 3State checkbox which is just checked a
  436. * dither, just like an indeterminate push button which is pressed.
  437. */
  438. clrBk = UserSetBkColor(hdc, SYSRGB(3DHILIGHT));
  439. clrOld = UserSetTextColor(hdc, SYSRGB(3DFACE));
  440. PolyData.x = x;
  441. PolyData.y = y;
  442. PolyData.cx = cx;
  443. PolyData.cy = cy;
  444. PolyData.BrClr.hbr = gpsi->hbrGray;
  445. UserPolyPatBlt(hdc, PATCOPY, &PolyData, 1, PPB_BRUSH);
  446. UserSetBkColor(hdc, clrBk);
  447. } else {
  448. clrOld = UserSetTextColor(hdc, clr[0]);
  449. UserTextOutW(hdc, x, y, lp, 1);
  450. }
  451. lp++;
  452. for (i = 1; i < 5; i++) {
  453. UserSetTextColor(hdc, clr[i]);
  454. UserTextOutW(hdc, x, y, lp++, 1);
  455. }
  456. if (wControlState & DFCS_CHECKED) {
  457. COLORREF clrCheck;
  458. if (wControlState & (DFCS_BUTTON3STATE | DFCS_INACTIVE)) {
  459. clrCheck = SYSRGBRTL(3DSHADOW);
  460. } else if (wControlState & DFCS_HOT) {
  461. clrCheck = SYSRGBRTL(HOTLIGHT);
  462. } else {
  463. clrCheck = SYSRGBRTL(WINDOWTEXT);
  464. }
  465. UserSetTextColor(hdc, clrCheck);
  466. FlipUserTextOutW(hdc, x, y, lp, 1);
  467. }
  468. UserSetTextColor(hdc, clrOld);
  469. return TRUE;
  470. }
  471. /***************************************************************************\
  472. * GetCaptionChar
  473. *
  474. * History:
  475. * 04/02/97 GerardoB Created
  476. \***************************************************************************/
  477. WCHAR GetCaptionChar (UINT wState)
  478. {
  479. wState &= DFCS_CAPTIONALL;
  480. switch (wState) {
  481. case DFCS_CAPTIONCLOSE:
  482. return TEXT('r');
  483. case DFCS_CAPTIONMIN:
  484. return TEXT('0');
  485. case DFCS_CAPTIONMAX:
  486. return TEXT('1');
  487. case DFCS_CAPTIONRESTORE:
  488. return TEXT('2');
  489. /* case DFCS_CAPTIONHELP: */
  490. default:
  491. return TEXT('s');
  492. }
  493. }
  494. /***************************************************************************\
  495. * DrawMenuMark
  496. *
  497. * History:
  498. \***************************************************************************/
  499. BOOL DrawMenuMark(
  500. HDC hdc,
  501. LPRECT lprc,
  502. UINT wType,
  503. UINT wState)
  504. {
  505. COLORREF rgbOld;
  506. int x;
  507. int y;
  508. int c;
  509. int cx;
  510. int cy;
  511. WCHAR ch;
  512. cx = lprc->right - lprc->left;
  513. cy = lprc->bottom - lprc->top;
  514. c = min(cx,cy);
  515. x = lprc->left + ((cx - c) / 2) - ((cx > 0xb) ? 1 : 0);
  516. y = lprc->top + ((cy - c) / 2);
  517. FillRect(hdc, lprc, ghbrWhite);
  518. rgbOld = UserSetTextColor(hdc, 0L);
  519. if (wType == DFC_MENU) {
  520. if (wState & DFCS_MENUCHECK) {
  521. ch = TEXT('a');
  522. } else if (wState & DFCS_MENUBULLET) {
  523. ch = TEXT('h');
  524. } else if (wState & DFCS_MENUARROWRIGHT) {
  525. ch = TEXT('w');
  526. } else {
  527. ch = TEXT('8');
  528. }
  529. } else {
  530. UserAssert(wType == DFC_POPUPMENU);
  531. ch = GetCaptionChar(wState);
  532. }
  533. FlipUserTextOutW(hdc, x, y, &ch, 1);
  534. UserSetTextColor(hdc, rgbOld);
  535. return TRUE;
  536. }
  537. /***************************************************************************\
  538. * DrawIt
  539. *
  540. * History:
  541. \***************************************************************************/
  542. BOOL DrawIt(
  543. HDC hdc,
  544. LPRECT lprc,
  545. UINT wState,
  546. WCHAR ch)
  547. {
  548. COLORREF rgb;
  549. int x;
  550. int y;
  551. int c;
  552. int cx;
  553. int cy;
  554. BOOL fDrawDisabled = wState & DFCS_INACTIVE;
  555. cx = lprc->right - lprc->left;
  556. cy = lprc->bottom - lprc->top;
  557. c = min(cx,cy);
  558. x = lprc->left + ((cx - c) / 2);
  559. y = lprc->top + ((cy - c) / 2);
  560. if (fDrawDisabled) {
  561. rgb = SYSRGBRTL(3DHILIGHT);
  562. } else if (wState & DFCS_HOT) {
  563. rgb = SYSRGBRTL(HOTLIGHT);
  564. } else {
  565. rgb = SYSRGBRTL(BTNTEXT);
  566. }
  567. rgb = UserSetTextColor(hdc, rgb);
  568. if (wState & (DFCS_INACTIVE | DFCS_PUSHED)) {
  569. x++;
  570. y++;
  571. }
  572. UserTextOutW(hdc, x, y, &ch, 1);
  573. if (fDrawDisabled) {
  574. UserSetTextColor(hdc, SYSRGBRTL(3DSHADOW));
  575. UserTextOutW(hdc, x - 1, y - 1, &ch, 1);
  576. }
  577. UserSetTextColor(hdc, rgb);
  578. return TRUE;
  579. }
  580. /***************************************************************************\
  581. * DrawScrollArrow
  582. *
  583. * History:
  584. \***************************************************************************/
  585. BOOL DrawScrollArrow(
  586. HDC hdc,
  587. LPRECT lprc,
  588. UINT wControlState)
  589. {
  590. WCHAR ch = (wControlState & DFCS_SCROLLHORZ) ? TEXT('3') : TEXT('5');
  591. if (wControlState & DFCS_SCROLLMAX)
  592. ch++;
  593. return DrawIt(hdc, lprc, wControlState, ch);
  594. }
  595. /***************************************************************************\
  596. * DrawFrameControl
  597. *
  598. * History:
  599. * 03-March-2001 Mohamed Hooked API and created this wrapper.
  600. \***************************************************************************/
  601. FUNCLOG4(
  602. LOG_GENERAL,
  603. BOOL,
  604. DUMMYCALLINGTYPE,
  605. DrawFrameControl,
  606. HDC,
  607. hdc,
  608. LPRECT,
  609. lprc,
  610. UINT,
  611. wType,
  612. UINT,
  613. wState)
  614. BOOL DrawFrameControl(
  615. HDC hdc,
  616. LPRECT lprc,
  617. UINT wType,
  618. UINT wState)
  619. {
  620. /*
  621. * There is a note here about the use of _USERK_. DrawFrameControl is present
  622. * both in kernel and user mode. Kernel side is not aware of UAH and therefore
  623. * this directive protects the kernel side by eliminating all wrappers
  624. * and UAH-related code from the kernel version and only exposing it during
  625. * the build for user mode.
  626. */
  627. #ifndef _USERK_ // Eliminate UAH code in kernel build.
  628. BOOL bRet;
  629. BEGIN_USERAPIHOOK()
  630. bRet = guah.pfnDrawFrameControl(hdc, lprc, wType, wState);
  631. END_USERAPIHOOK()
  632. return bRet;
  633. }
  634. /***************************************************************************\
  635. * RealDrawFrameControl
  636. *
  637. * History:
  638. * 03-March-2001 Mohamed Hooked this API and changed to Real*
  639. \***************************************************************************/
  640. BOOL RealDrawFrameControl(
  641. HDC hdc,
  642. LPRECT lprc,
  643. UINT wType,
  644. UINT wState)
  645. {
  646. #endif // _USERK_
  647. RECT rc;
  648. HFONT hFont;
  649. HFONT hOldFont;
  650. BOOL fRet = TRUE;
  651. int iOldBk;
  652. int c;
  653. BOOL fButton = FALSE;
  654. LOGFONTW lfw;
  655. int iGraphicsModeOld = 0;
  656. int iOldTextAlign;
  657. rc = *lprc;
  658. /*
  659. * If the hdc is mirrored then set it in GM_ADVANCED mode
  660. * to enforce the text to be mirrored.
  661. */
  662. if (UserGetLayout(hdc) & LAYOUT_RTL) {
  663. if (iGraphicsModeOld = UserSetGraphicsMode(hdc, GM_ADVANCED))
  664. {
  665. iOldTextAlign = UserGetTextAlign(hdc);
  666. if ((iOldTextAlign & TA_CENTER) != TA_CENTER)
  667. {
  668. UserSetTextAlign(hdc, iOldTextAlign^TA_RIGHT);
  669. }
  670. }
  671. }
  672. /*
  673. * Enforce monochrome/flat
  674. */
  675. if (gpsi->BitCount == 1)
  676. wState |= DFCS_MONO;
  677. if (wState & DFCS_MONO)
  678. wState |= DFCS_FLAT;
  679. if ((wType != DFC_MENU)
  680. && (wType != DFC_POPUPMENU)
  681. && ((wType != DFC_BUTTON) || (wState & DFCS_BUTTONPUSH))
  682. && ((wType != DFC_SCROLL)
  683. || !(wState & (DFCS_SCROLLSIZEGRIP | DFCS_SCROLLSIZEGRIPRIGHT))))
  684. {
  685. UINT wBorder = BF_ADJUST;
  686. if (wType != DFC_SCROLL)
  687. wBorder |= BF_SOFT;
  688. UserAssert(DFCS_FLAT == BF_FLAT);
  689. UserAssert(DFCS_MONO == BF_MONO);
  690. wBorder |= (wState & (DFCS_FLAT | DFCS_MONO));
  691. DrawPushButton(hdc, &rc, wState, wBorder);
  692. if (wState & DFCS_ADJUSTRECT)
  693. *lprc = rc;
  694. fButton = TRUE;
  695. }
  696. iOldBk = UserSetBkMode(hdc, TRANSPARENT);
  697. if (!iOldBk) {
  698. /*
  699. * return FALSE if the hdc is bogus
  700. */
  701. if (iGraphicsModeOld) {
  702. UserSetGraphicsMode(hdc, iGraphicsModeOld);
  703. UserSetTextAlign(hdc, iOldTextAlign);
  704. }
  705. return FALSE;
  706. }
  707. c = min(rc.right - rc.left, rc.bottom - rc.top);
  708. if (c <= 0) {
  709. if (iGraphicsModeOld){
  710. UserSetGraphicsMode(hdc, iGraphicsModeOld);
  711. UserSetTextAlign(hdc, iOldTextAlign);
  712. }
  713. return FALSE;
  714. }
  715. RtlZeroMemory(&lfw, sizeof(lfw));
  716. lfw.lfHeight = c;
  717. lfw.lfWeight = FW_NORMAL;
  718. lfw.lfCharSet = SYMBOL_CHARSET;
  719. RtlCopyMemory(lfw.lfFaceName, L"Marlett", sizeof(L"Marlett"));
  720. hFont = UserCreateFontIndirectW(&lfw);
  721. hOldFont = UserSelectFont(hdc, hFont);
  722. if (!fButton) {
  723. if ((wType == DFC_MENU) || (wType == DFC_POPUPMENU)) {
  724. if (wState & (DFCS_MENUARROWUP | DFCS_MENUARROWDOWN)) {
  725. if (!(wState & DFCS_TRANSPARENT)) {
  726. POLYPATBLT ppbData;
  727. ppbData.x = lprc->left;
  728. ppbData.y = lprc->top;
  729. ppbData.cx = lprc->right - lprc->left;
  730. ppbData.cy = lprc->bottom - lprc->top;
  731. ppbData.BrClr.hbr = SYSHBR(MENU);
  732. UserPolyPatBlt(hdc, PATCOPY, &ppbData, 1, PPB_BRUSH);
  733. }
  734. DrawScrollArrow(hdc, &rc,
  735. (wState & (DFCS_HOT | DFCS_INACTIVE)) | ((wState & DFCS_MENUARROWUP) ? DFCS_SCROLLUP : DFCS_SCROLLDOWN));
  736. } else {
  737. DrawMenuMark(hdc, &rc, wType, wState);
  738. }
  739. } else if (wType == DFC_BUTTON) {
  740. DrawBox(hdc, &rc, wState);
  741. } else { // wType == DFC_SCROLL
  742. DrawGrip(hdc, lprc, wState);
  743. }
  744. } else if (wType == DFC_CAPTION) {
  745. DrawIt(hdc, &rc, wState, GetCaptionChar(wState));
  746. } else if (wType == DFC_SCROLL) {
  747. DrawScrollArrow(hdc, &rc, wState);
  748. } else if (wType != DFC_BUTTON) {
  749. fRet = FALSE;
  750. }
  751. if (iGraphicsModeOld){
  752. UserSetGraphicsMode(hdc, iGraphicsModeOld);
  753. UserSetTextAlign(hdc, iOldTextAlign);
  754. }
  755. UserSetBkMode(hdc, iOldBk);
  756. UserSelectFont(hdc, hOldFont);
  757. UserDeleteObject(hFont);
  758. return fRet;
  759. }
  760. /***************************************************************************\
  761. * DrawEdge
  762. *
  763. * Draws a 3D edge using 2 3D borders. Adjusts interior rectangle if desired
  764. * And fills it if requested.
  765. *
  766. * Returns:
  767. * FALSE if error
  768. *
  769. * History:
  770. * 30-Jan-1991 Laurabu Created.
  771. \***************************************************************************/
  772. BOOL DrawEdge(
  773. HDC hdc,
  774. LPRECT lprc,
  775. UINT edge,
  776. UINT flags)
  777. {
  778. HBRUSH hbrTL;
  779. HBRUSH hbrBR;
  780. RECT rc;
  781. UINT bdrType;
  782. POLYPATBLT ppbData[4];
  783. UINT ppbCount;
  784. BOOL fResult = TRUE;
  785. /*
  786. * Enforce monochromicity and flatness
  787. */
  788. if (gpsi->BitCount == 1)
  789. flags |= BF_MONO;
  790. if (flags & BF_MONO)
  791. flags |= BF_FLAT;
  792. rc = *lprc;
  793. /*
  794. * Draw the border segment(s), and calculate the remaining space as we
  795. * go.
  796. */
  797. if (bdrType = (edge & BDR_OUTER)) {
  798. DrawBorder:
  799. /*
  800. * Get brushes. Note the symmetry between raised outer,
  801. * sunken inner and sunken outer, raised inner.
  802. */
  803. if (flags & BF_FLAT) {
  804. if (flags & BF_MONO)
  805. hbrBR = (bdrType & BDR_OUTER) ? SYSHBR(WINDOWFRAME) : SYSHBR(WINDOW);
  806. else
  807. hbrBR = (bdrType & BDR_OUTER) ? SYSHBR(3DSHADOW) : SYSHBR(3DFACE);
  808. hbrTL = hbrBR;
  809. } else {
  810. /*
  811. * 5 == HILIGHT
  812. * 4 == LIGHT
  813. * 3 == FACE
  814. * 2 == SHADOW
  815. * 1 == DKSHADOW
  816. */
  817. switch (bdrType) {
  818. /*
  819. * +2 above surface
  820. */
  821. case BDR_RAISEDOUTER:
  822. hbrTL = ((flags & BF_SOFT) ? SYSHBR(3DHILIGHT) : SYSHBR(3DLIGHT));
  823. hbrBR = SYSHBR(3DDKSHADOW); // 1
  824. break;
  825. /*
  826. * +1 above surface
  827. */
  828. case BDR_RAISEDINNER:
  829. hbrTL = ((flags & BF_SOFT) ? SYSHBR(3DLIGHT) : SYSHBR(3DHILIGHT));
  830. hbrBR = SYSHBR(3DSHADOW); // 2
  831. break;
  832. /*
  833. * -1 below surface
  834. */
  835. case BDR_SUNKENOUTER:
  836. hbrTL = ((flags & BF_SOFT) ? SYSHBR(3DDKSHADOW) : SYSHBR(3DSHADOW));
  837. hbrBR = SYSHBR(3DHILIGHT); // 5
  838. break;
  839. /*
  840. * -2 below surface
  841. */
  842. case BDR_SUNKENINNER:
  843. hbrTL = ((flags & BF_SOFT) ? SYSHBR(3DSHADOW) : SYSHBR(3DDKSHADOW));
  844. hbrBR = SYSHBR(3DLIGHT); // 4
  845. break;
  846. default:
  847. return FALSE;
  848. }
  849. }
  850. /*
  851. * Draw the sides of the border. NOTE THAT THE ALGORITHM FAVORS THE
  852. * BOTTOM AND RIGHT SIDES, since the light source is assumed to be top
  853. * left. If we ever decide to let the user set the light source to a
  854. * particular corner, then change this algorithm.
  855. */
  856. if (flags & BF_DIAGONAL) {
  857. fResult = DrawDiagonal(hdc, &rc, hbrTL, hbrBR, flags);
  858. } else {
  859. /*
  860. * reset ppbData index
  861. */
  862. ppbCount = 0;
  863. /*
  864. * Bottom Right edges
  865. */
  866. /*
  867. * Right
  868. */
  869. if (flags & BF_RIGHT) {
  870. rc.right -= SYSMETRTL(CXBORDER);
  871. ppbData[ppbCount].x = rc.right;
  872. ppbData[ppbCount].y = rc.top;
  873. ppbData[ppbCount].cx = SYSMETRTL(CXBORDER);
  874. ppbData[ppbCount].cy = rc.bottom - rc.top;
  875. ppbData[ppbCount].BrClr.hbr = hbrBR;
  876. ppbCount++;
  877. }
  878. /*
  879. * Bottom
  880. */
  881. if (flags & BF_BOTTOM) {
  882. rc.bottom -= SYSMETRTL(CYBORDER);
  883. ppbData[ppbCount].x = rc.left;
  884. ppbData[ppbCount].y = rc.bottom;
  885. ppbData[ppbCount].cx = rc.right - rc.left;
  886. ppbData[ppbCount].cy = SYSMETRTL(CYBORDER);
  887. ppbData[ppbCount].BrClr.hbr = hbrBR;
  888. ppbCount++;
  889. }
  890. /*
  891. * Top Left edges
  892. */
  893. /*
  894. * Left
  895. */
  896. if (flags & BF_LEFT) {
  897. ppbData[ppbCount].x = rc.left;
  898. ppbData[ppbCount].y = rc.top;
  899. ppbData[ppbCount].cx = SYSMETRTL(CXBORDER);
  900. ppbData[ppbCount].cy = rc.bottom - rc.top;
  901. ppbData[ppbCount].BrClr.hbr = hbrTL;
  902. ppbCount++;
  903. rc.left += SYSMETRTL(CXBORDER);
  904. }
  905. /*
  906. * Top
  907. */
  908. if (flags & BF_TOP) {
  909. ppbData[ppbCount].x = rc.left;
  910. ppbData[ppbCount].y = rc.top;
  911. ppbData[ppbCount].cx = rc.right - rc.left;
  912. ppbData[ppbCount].cy = SYSMETRTL(CYBORDER);
  913. ppbData[ppbCount].BrClr.hbr = hbrTL;
  914. ppbCount++;
  915. rc.top += SYSMETRTL(CYBORDER);
  916. }
  917. /*
  918. * Send all queued PatBlts to GDI in one go
  919. */
  920. fResult = UserPolyPatBlt(hdc,PATCOPY,&ppbData[0],ppbCount,PPB_BRUSH);
  921. }
  922. }
  923. if (bdrType = (edge & BDR_INNER)) {
  924. /*
  925. * Strip this so the next time through, bdrType will be 0.
  926. * Otherwise, we'll loop forever.
  927. */
  928. edge &= ~BDR_INNER;
  929. goto DrawBorder;
  930. }
  931. /*
  932. * Select old brush back in, if we changed it.
  933. */
  934. /*
  935. * Fill the middle & clean up if asked
  936. */
  937. if (flags & BF_MIDDLE) {
  938. if (flags & BF_DIAGONAL)
  939. fResult = FillTriangle(hdc, &rc, ((flags & BF_MONO) ? (HBRUSH)SYSHBR(WINDOW) : (HBRUSH)SYSHBR(3DFACE)), flags);
  940. else
  941. fResult = FillRect(hdc, &rc, ((flags & BF_MONO) ? (HBRUSH)SYSHBR(WINDOW) : (HBRUSH)SYSHBR(3DFACE)));
  942. }
  943. if (flags & BF_ADJUST)
  944. *lprc = rc;
  945. return fResult;
  946. }
  947. /***************************************************************************\
  948. * DrawPushButton
  949. *
  950. * Draws a push style button in the given state. Adjusts passed in rectangle
  951. * if desired.
  952. *
  953. * Algorithm:
  954. * Depending on the state we either draw
  955. * * raised edge (undepressed)
  956. * * sunken edge with extra shadow (depressed)
  957. * If it is an option push button (a push button that is
  958. * really a check button or a radio button like buttons
  959. * in tool bars), and it is checked, then we draw it
  960. * depressed with a different fill in the middle.
  961. *
  962. * History:
  963. * 05-Feb-19 Laurabu Created.
  964. \***************************************************************************/
  965. VOID DrawPushButton(
  966. HDC hdc,
  967. LPRECT lprc,
  968. UINT state,
  969. UINT flags)
  970. {
  971. RECT rc;
  972. HBRUSH hbrMiddle;
  973. DWORD rgbBack;
  974. DWORD rgbFore;
  975. BOOL fDither;
  976. rc = *lprc;
  977. DrawEdge(hdc,
  978. &rc,
  979. (state & (DFCS_PUSHED | DFCS_CHECKED)) ? EDGE_SUNKEN : EDGE_RAISED,
  980. (UINT)(BF_ADJUST | BF_RECT | (flags & (BF_SOFT | BF_FLAT | BF_MONO))));
  981. /*
  982. * BOGUS
  983. * On monochrome, need to do something to make pushed buttons look
  984. * better.
  985. */
  986. /*
  987. * Fill in middle. If checked, use dither brush (gray brush) with
  988. * black becoming normal color.
  989. */
  990. fDither = FALSE;
  991. if (state & DFCS_CHECKED) {
  992. if ((gpsi->BitCount < 8) || (SYSRGBRTL(3DHILIGHT) == RGB(255,255,255))) {
  993. hbrMiddle = KHBRUSH_TO_HBRUSH(gpsi->hbrGray);
  994. rgbBack = UserSetBkColor(hdc, SYSRGBRTL(3DHILIGHT));
  995. rgbFore = UserSetTextColor(hdc, SYSRGBRTL(3DFACE));
  996. fDither = TRUE;
  997. } else {
  998. hbrMiddle = SYSHBR(3DHILIGHT);
  999. }
  1000. } else {
  1001. hbrMiddle = SYSHBR(3DFACE);
  1002. }
  1003. FillRect(hdc, &rc, hbrMiddle);
  1004. if (fDither) {
  1005. UserSetBkColor(hdc, rgbBack);
  1006. UserSetTextColor(hdc, rgbFore);
  1007. }
  1008. if (flags & BF_ADJUST)
  1009. *lprc = rc;
  1010. }
  1011. /***************************************************************************\
  1012. * DrawFrame
  1013. *
  1014. * History:
  1015. \***************************************************************************/
  1016. BOOL DrawFrame(
  1017. HDC hdc,
  1018. PRECT prc,
  1019. int clFrame,
  1020. int cmd)
  1021. {
  1022. int x;
  1023. int y;
  1024. int cx;
  1025. int cy;
  1026. int cxWidth;
  1027. int cyWidth;
  1028. HANDLE hbrSave;
  1029. LONG rop;
  1030. POLYPATBLT PolyData[4];
  1031. x = prc->left;
  1032. y = prc->top;
  1033. cxWidth = SYSMETRTL(CXBORDER) * clFrame;
  1034. cyWidth = SYSMETRTL(CYBORDER) * clFrame;
  1035. cx = prc->right - x - cxWidth;
  1036. cy = prc->bottom - y - cyWidth;
  1037. rop = ((cmd & DF_ROPMASK) ? PATINVERT : PATCOPY);
  1038. if ((cmd & DF_HBRMASK) == DF_GRAY) {
  1039. hbrSave = KHBRUSH_TO_HBRUSH(gpsi->hbrGray);
  1040. } else {
  1041. UserAssert(((cmd & DF_HBRMASK) >> 3) < COLOR_MAX);
  1042. hbrSave = SYSHBRUSH((cmd & DF_HBRMASK) >> 3);
  1043. }
  1044. PolyData[0].x = x;
  1045. PolyData[0].y = y;
  1046. PolyData[0].cx = cxWidth;
  1047. PolyData[0].cy = cy;
  1048. PolyData[0].BrClr.hbr = hbrSave;
  1049. PolyData[1].x = x + cxWidth;
  1050. PolyData[1].y = y;
  1051. PolyData[1].cx = cx;
  1052. PolyData[1].cy = cyWidth;
  1053. PolyData[1].BrClr.hbr = hbrSave;
  1054. PolyData[2].x = x;
  1055. PolyData[2].y = y + cy;
  1056. PolyData[2].cx = cx;
  1057. PolyData[2].cy = cyWidth;
  1058. PolyData[2].BrClr.hbr = hbrSave;
  1059. PolyData[3].x = x + cx;
  1060. PolyData[3].y = y + cyWidth;
  1061. PolyData[3].cx = cxWidth;
  1062. PolyData[3].cy = cy;
  1063. PolyData[3].BrClr.hbr = hbrSave;
  1064. UserPolyPatBlt(hdc, rop, &PolyData[0], 4, PPB_BRUSH);
  1065. return TRUE;
  1066. }
  1067. /***************************************************************************\
  1068. * GetSignFromMappingMode
  1069. *
  1070. * For the current mapping mode, find out the sign of x from left to right,
  1071. * and the sign of y from top to bottom.
  1072. *
  1073. * History:
  1074. \***************************************************************************/
  1075. BOOL GetSignFromMappingMode (
  1076. HDC hdc,
  1077. PPOINT pptSign)
  1078. {
  1079. SIZE sizeViewPortExt;
  1080. SIZE sizeWindowExt;
  1081. if (!UserGetViewportExtEx(hdc, &sizeViewPortExt)
  1082. || !UserGetWindowExtEx(hdc, &sizeWindowExt)) {
  1083. return FALSE;
  1084. }
  1085. pptSign->x = ((sizeViewPortExt.cx ^ sizeWindowExt.cx) < 0) ? -1 : 1;
  1086. pptSign->y = ((sizeViewPortExt.cy ^ sizeWindowExt.cy) < 0) ? -1 : 1;
  1087. return TRUE;
  1088. }
  1089. /***************************************************************************\
  1090. * ClientFrame
  1091. *
  1092. * Draw a rectangle
  1093. *
  1094. * History:
  1095. * 19-Jan-1993 MikeKe Created
  1096. \***************************************************************************/
  1097. BOOL ClientFrame(
  1098. HDC hDC,
  1099. LPCRECT pRect,
  1100. HBRUSH hBrush,
  1101. DWORD patOp,
  1102. int cxBorder,
  1103. int cyBorder)
  1104. {
  1105. int x;
  1106. int y;
  1107. POINT point;
  1108. POINT ptSign;
  1109. POLYPATBLT PolyData[4];
  1110. if (!GetSignFromMappingMode (hDC, &ptSign))
  1111. return FALSE;
  1112. y = pRect->bottom - (point.y = pRect->top);
  1113. if (y < 0) {
  1114. return FALSE;
  1115. }
  1116. x = pRect->right - (point.x = pRect->left);
  1117. /*
  1118. * Check width and height signs
  1119. */
  1120. if (((x ^ ptSign.x) < 0) || ((y ^ ptSign.y) < 0))
  1121. return FALSE;
  1122. /*
  1123. * Factor in the thickness of the rectangle to be drawn. This will
  1124. * automatically offset the edges so that the actual rectangle gets filled
  1125. * "in" as it becomes thicker.
  1126. */
  1127. ptSign.x *= cxBorder;
  1128. ptSign.y *= cyBorder;
  1129. // Top border
  1130. PolyData[0].x = point.x;
  1131. PolyData[0].y = point.y;
  1132. PolyData[0].cx = x;
  1133. PolyData[0].cy = ptSign.y;
  1134. PolyData[0].BrClr.hbr = hBrush;
  1135. // Bottom border
  1136. point.y = pRect->bottom - ptSign.y;
  1137. PolyData[1].x = point.x;
  1138. PolyData[1].y = point.y;
  1139. PolyData[1].cx = x;
  1140. PolyData[1].cy = ptSign.y;
  1141. PolyData[1].BrClr.hbr = hBrush;
  1142. /*
  1143. * Left Border
  1144. * Don't xor the corners twice
  1145. */
  1146. point.y = pRect->top + ptSign.y;
  1147. y -= 2 * ptSign.y;
  1148. PolyData[2].x = point.x;
  1149. PolyData[2].y = point.y;
  1150. PolyData[2].cx = ptSign.x;
  1151. PolyData[2].cy = y;
  1152. PolyData[2].BrClr.hbr = hBrush;
  1153. // Right Border
  1154. point.x = pRect->right - ptSign.x;
  1155. PolyData[3].x = point.x;
  1156. PolyData[3].y = point.y;
  1157. PolyData[3].cx = ptSign.x;
  1158. PolyData[3].cy = y;
  1159. PolyData[3].BrClr.hbr = hBrush;
  1160. return UserPolyPatBlt(hDC, patOp, PolyData, sizeof (PolyData) / sizeof (*PolyData), PPB_BRUSH);
  1161. }