Source code of Windows XP (NT5)
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.

902 lines
23 KiB

  1. /*++
  2. Copyright (C) 1996-1999 Microsoft Corporation
  3. Module Name:
  4. hatchwnd.h
  5. Abstract:
  6. Implementation of the CHatchWin class. CHatchWin when used
  7. as a parent window creates a thin hatch border around
  8. the child window.
  9. --*/
  10. #include <windows.h>
  11. #include <oleidl.h>
  12. #include "hatchwnd.h"
  13. #include "resource.h"
  14. #include "globals.h"
  15. // Hit codes for computing handle code (Y_CODE + 3 * X_CODE)
  16. #define Y_TOP 0
  17. #define Y_MIDDLE 1
  18. #define Y_BOTTOM 2
  19. #define X_LEFT 0
  20. #define X_MIDDLE 1
  21. #define X_RIGHT 2
  22. #define NO_HIT -1
  23. // Sizing flags
  24. #define SIZING_TOP 0x0001
  25. #define SIZING_BOTTOM 0x0002
  26. #define SIZING_LEFT 0x0004
  27. #define SIZING_RIGHT 0x0008
  28. #define SIZING_ALL 0x0010
  29. // Sizing flags lookup (indexed by handle code)
  30. static UINT uSizingTable[9] = {
  31. SIZING_LEFT | SIZING_TOP, SIZING_TOP, SIZING_RIGHT | SIZING_TOP,
  32. SIZING_LEFT, SIZING_ALL, SIZING_RIGHT,
  33. SIZING_LEFT | SIZING_BOTTOM, SIZING_BOTTOM, SIZING_BOTTOM | SIZING_RIGHT };
  34. // Cursor ID lookup (indexed by handle code)
  35. static UINT uCursIDTable[9] = {
  36. IDC_CURS_NWSE, IDC_CURS_NS, IDC_CURS_NESW,
  37. IDC_CURS_WE, IDC_CURS_MOVE, IDC_CURS_WE,
  38. IDC_CURS_NESW, IDC_CURS_NS, IDC_CURS_NWSE };
  39. // Cursors (indexed by cursor ID)
  40. static HCURSOR hCursTable[IDC_CURS_MAX - IDC_CURS_MIN + 1];
  41. #define IDTIMER_DEBOUNCE 1
  42. #define MIN_SIZE 8
  43. // Brush patterns
  44. static WORD wHatchBmp[]={0x11, 0x22, 0x44, 0x88, 0x11, 0x22, 0x44, 0x88};
  45. static WORD wGrayBmp[]={0x55, 0xaa, 0x55, 0xaa, 0x55, 0xaa, 0x55, 0xaa};
  46. static HBRUSH hBrHatch;
  47. static HBRUSH hBrGray;
  48. // System parameters
  49. static INT iBorder;
  50. static INT iDragMinDist;
  51. static INT iDragDelay;
  52. static INT fLocalInit = FALSE;
  53. // Forward refs
  54. void DrawShading(HDC, LPRECT);
  55. void DrawHandles (HDC, LPRECT);
  56. void DrawDragRgn (HWND, HRGN);
  57. HRGN CreateDragRgn(LPRECT);
  58. TCHAR szHatchWinClassName[] = TEXT("Hatchwin") ;
  59. /*
  60. * CHatchWin:CHatchWin
  61. * CHatchWin::~CHatchWin
  62. *
  63. * Constructor Parameters:
  64. * hInst HINSTANCE of the application we're in.
  65. */
  66. CHatchWin::CHatchWin(
  67. VOID
  68. )
  69. {
  70. m_hWnd = NULL;
  71. m_hWndParent = NULL;
  72. m_hWndKid = NULL;
  73. m_hWndAssociate = NULL;
  74. m_hRgnDrag = NULL;
  75. m_iBorder = 0;
  76. m_uID = 0;
  77. m_uDragMode = DRAG_IDLE;
  78. m_bResizeInProgress = FALSE;
  79. SetRect(&m_rcPos, 0, 0, 0, 0);
  80. SetRect(&m_rcClip, 0, 0, 0, 0);
  81. return;
  82. }
  83. CHatchWin::~CHatchWin(void)
  84. {
  85. if (NULL != m_hWnd)
  86. DestroyWindow(m_hWnd);
  87. return;
  88. }
  89. /*
  90. * CHatchWin::Init
  91. *
  92. * Purpose:
  93. * Instantiates a hatch window within a given parent with a
  94. * default rectangle. This is not initially visible.
  95. *
  96. * Parameters:
  97. * hWndParent HWND of the parent of this window
  98. * uID UINT identifier for this window (send in
  99. * notifications to associate window).
  100. * hWndAssoc HWND of the initial associate.
  101. *
  102. * Return Value:
  103. * BOOL TRUE if the function succeeded, FALSE otherwise.
  104. */
  105. BOOL CHatchWin::Init(HWND hWndParent, UINT uID, HWND hWndAssoc)
  106. {
  107. INT i;
  108. HBITMAP hBM;
  109. WNDCLASS wc;
  110. LONG_PTR lptrID = 0;
  111. BEGIN_CRITICAL_SECTION
  112. // If first time through
  113. if (pstrRegisteredClasses[HATCH_WNDCLASS] == NULL) {
  114. // Register the hatch window class
  115. wc.style = CS_HREDRAW | CS_VREDRAW | CS_DBLCLKS;
  116. wc.hInstance = g_hInstance;
  117. wc.cbClsExtra = 0;
  118. wc.lpfnWndProc = (WNDPROC)HatchWndProc;
  119. wc.cbWndExtra = CBHATCHWNDEXTRA;
  120. wc.hIcon = NULL;
  121. wc.hCursor = NULL;
  122. wc.hbrBackground = (HBRUSH)GetStockObject(WHITE_BRUSH);
  123. wc.lpszMenuName = NULL;
  124. wc.lpszClassName = szHatchWinClassName;
  125. if (RegisterClass(&wc)) {
  126. // Save class name for later unregistering
  127. pstrRegisteredClasses[HATCH_WNDCLASS] = szHatchWinClassName;
  128. // Get system metrics
  129. iBorder = GetProfileInt(TEXT("windows"),
  130. TEXT("OleInPlaceBorderWidth"), 4);
  131. iDragMinDist = GetProfileInt(TEXT("windows"),
  132. TEXT("DragMinDist"), DD_DEFDRAGMINDIST);
  133. iDragDelay = GetProfileInt(TEXT("windows"),
  134. TEXT("DragDelay"), DD_DEFDRAGDELAY);
  135. // Load the arrow cursors
  136. for (i = IDC_CURS_MIN; i <= IDC_CURS_MAX; i++) {
  137. hCursTable[i - IDC_CURS_MIN] = LoadCursor(g_hInstance, MAKEINTRESOURCE(i));
  138. }
  139. // Create brushes for hatching and drag region
  140. hBM = CreateBitmap(8, 8, 1, 1, wHatchBmp);
  141. if ( NULL != hBM ) {
  142. hBrHatch = CreatePatternBrush(hBM);
  143. DeleteObject(hBM);
  144. }
  145. hBM = CreateBitmap(8, 8, 1, 1, wGrayBmp);
  146. if ( NULL != hBM ) {
  147. hBrGray = CreatePatternBrush(hBM);
  148. DeleteObject(hBM);
  149. }
  150. }
  151. }
  152. END_CRITICAL_SECTION
  153. if (pstrRegisteredClasses[HATCH_WNDCLASS] == NULL)
  154. return FALSE;
  155. lptrID = uID;
  156. m_hWnd = CreateWindowEx(
  157. WS_EX_NOPARENTNOTIFY,
  158. szHatchWinClassName,
  159. szHatchWinClassName,
  160. WS_CHILD | WS_CLIPSIBLINGS | WS_CLIPCHILDREN,
  161. 0,
  162. 0,
  163. 100,
  164. 100,
  165. hWndParent,
  166. (HMENU)lptrID,
  167. g_hInstance,
  168. this);
  169. m_uID = uID;
  170. m_hWndAssociate = hWndAssoc;
  171. m_hWndParent = hWndParent;
  172. return (NULL != m_hWnd);
  173. }
  174. /*
  175. * CHatchWin::HwndAssociateSet
  176. * CHatchWin::HwndAssociateGet
  177. *
  178. * Purpose:
  179. * Sets (Set) or retrieves (Get) the associate window of the
  180. * hatch window.
  181. *
  182. * Parameters: (Set only)
  183. * hWndAssoc HWND to set as the associate.
  184. *
  185. * Return Value:
  186. * HWND Previous (Set) or current (Get) associate
  187. * window.
  188. */
  189. HWND CHatchWin::HwndAssociateSet(HWND hWndAssoc)
  190. {
  191. HWND hWndT = m_hWndAssociate;
  192. m_hWndAssociate = hWndAssoc;
  193. return hWndT;
  194. }
  195. HWND CHatchWin::HwndAssociateGet(void)
  196. {
  197. return m_hWndAssociate;
  198. }
  199. /*
  200. * CHatchWin::RectsSet
  201. *
  202. * Purpose:
  203. * Changes the size and position of the hatch window and the child
  204. * window within it using a position rectangle for the child and
  205. * a clipping rectangle for the hatch window and child. The hatch
  206. * window occupies prcPos expanded by the hatch border and clipped
  207. * by prcClip. The child window is fit to prcPos to give the
  208. * proper scaling, but it clipped to the hatch window which
  209. * therefore clips it to prcClip without affecting the scaling.
  210. *
  211. * Parameters:
  212. * prcPos LPRECT providing the position rectangle.
  213. * prcClip LPRECT providing the clipping rectangle.
  214. *
  215. * Return Value:
  216. * None
  217. */
  218. void CHatchWin::RectsSet(LPRECT prcPos, LPRECT prcClip)
  219. {
  220. RECT rc;
  221. RECT rcPos;
  222. UINT uPosFlags = SWP_NOZORDER | SWP_NOACTIVATE;
  223. BOOL bChanged = TRUE;
  224. // If new rectangles, save them
  225. if (prcPos != NULL) {
  226. bChanged = !EqualRect ( prcPos, &m_rcPos );
  227. m_rcPos = *prcPos;
  228. // If clipping rect supplied, use it
  229. // else just use the position rect again
  230. if (prcClip != NULL) {
  231. if ( !bChanged )
  232. bChanged = !EqualRect ( prcClip, &m_rcClip );
  233. m_rcClip = *prcClip;
  234. } else {
  235. m_rcClip = m_rcPos;
  236. }
  237. }
  238. if ( bChanged ) {
  239. // Expand position rect to include hatch border
  240. rcPos = m_rcPos;
  241. InflateRect(&rcPos, m_iBorder, m_iBorder);
  242. // Clip with clipping rect to get actual window rect
  243. IntersectRect(&rc, &rcPos, &m_rcClip);
  244. // Save hatch wnd origin relative to clipped window
  245. m_ptHatchOrg.x = rcPos.left - rc.left;
  246. m_ptHatchOrg.y = rcPos.top - rc.top;
  247. // Set flag to avoid reentrant call from window proc
  248. m_bResizeInProgress = TRUE;
  249. // Offset child window from hatch rect by border width
  250. // (maintaining its original size)
  251. SetWindowPos(m_hWndKid, NULL, m_ptHatchOrg.x + m_iBorder, m_ptHatchOrg.y + m_iBorder,
  252. m_rcPos.right - m_rcPos.left, m_rcPos.bottom - m_rcPos.top, uPosFlags);
  253. // Position the hatch window
  254. SetWindowPos(m_hWnd, NULL, rc.left, rc.top, rc.right - rc.left,
  255. rc.bottom - rc.top, uPosFlags);
  256. m_bResizeInProgress = FALSE;
  257. }
  258. // This is here to ensure that the control background gets redrawn
  259. // On a UI deactivate, the VC test container erases the control window
  260. // between the WM_ERASEBKGND and WM_PAINT, so the background ends up
  261. // the container color instead of the control color
  262. if (m_iBorder == 0)
  263. InvalidateRect(m_hWndKid, NULL, TRUE);
  264. return;
  265. }
  266. /*
  267. * CHatchWin::ChildSet
  268. *
  269. * Purpose:
  270. * Assigns a child window to this hatch window.
  271. *
  272. * Parameters:
  273. * hWndKid HWND of the child window.
  274. *
  275. * Return Value:
  276. * None
  277. */
  278. void CHatchWin::ChildSet(HWND hWndKid)
  279. {
  280. m_hWndKid = hWndKid;
  281. if (NULL != hWndKid)
  282. {
  283. SetParent(hWndKid, m_hWnd);
  284. //Insure this is visible when the hatch window becomes visible.
  285. ShowWindow(hWndKid, SW_SHOW);
  286. }
  287. return;
  288. }
  289. void CHatchWin::OnLeftDown(INT x, INT y)
  290. {
  291. m_ptDown.x = x;
  292. m_ptDown.y = y;
  293. SetCapture(m_hWnd);
  294. m_uDragMode = DRAG_PENDING;
  295. SetTimer(m_hWnd, IDTIMER_DEBOUNCE, iDragDelay, NULL);
  296. }
  297. void CHatchWin::OnLeftUp(void)
  298. {
  299. switch (m_uDragMode) {
  300. case DRAG_PENDING:
  301. KillTimer(m_hWnd, IDTIMER_DEBOUNCE);
  302. ReleaseCapture();
  303. break;
  304. case DRAG_ACTIVE:
  305. // Erase and release drag region
  306. if ( NULL != m_hRgnDrag ) {
  307. DrawDragRgn(m_hWndParent, m_hRgnDrag);
  308. DeleteObject(m_hRgnDrag);
  309. m_hRgnDrag = NULL;
  310. }
  311. ReleaseCapture();
  312. // Inform associated window of change
  313. if ( !EqualRect(&m_rectNew, &m_rcPos) ) {
  314. SendMessage(m_hWndAssociate, WM_COMMAND,
  315. MAKEWPARAM(m_uID, HWN_RESIZEREQUESTED),
  316. (LPARAM)&m_rectNew);
  317. }
  318. break;
  319. }
  320. m_uDragMode = DRAG_IDLE;
  321. }
  322. void CHatchWin::OnMouseMove(INT x, INT y)
  323. {
  324. INT dx, dy;
  325. HRGN hRgnNew, hRgnDiff;
  326. UINT uResizeFlags;
  327. INT iWidth, iHeight;
  328. INT xHit, yHit;
  329. static INT xPrev, yPrev;
  330. if (x == xPrev && y == yPrev)
  331. return;
  332. xPrev = x;
  333. yPrev = y;
  334. switch (m_uDragMode)
  335. {
  336. case DRAG_IDLE:
  337. // Adjust to hatch window coordinates
  338. x -= m_ptHatchOrg.x;
  339. y -= m_ptHatchOrg.y;
  340. iWidth = m_rcPos.right - m_rcPos.left + 2 * m_iBorder;
  341. iHeight = m_rcPos.bottom - m_rcPos.top + 2 * m_iBorder;
  342. // Determine if x is within a handle
  343. if (x <= m_iBorder)
  344. xHit = X_LEFT;
  345. else if (x >= iWidth - m_iBorder)
  346. xHit = X_RIGHT;
  347. else if (x >= (iWidth - m_iBorder)/2 && x <= (iWidth + m_iBorder)/2)
  348. xHit = X_MIDDLE;
  349. else
  350. xHit = NO_HIT;
  351. // Determine is y within a handle
  352. if (y <= m_iBorder)
  353. yHit = Y_TOP;
  354. else if (y >= iHeight - m_iBorder)
  355. yHit = Y_BOTTOM;
  356. else if (y > (iHeight - m_iBorder)/2 && y < (iHeight + m_iBorder)/2)
  357. yHit = Y_MIDDLE;
  358. else
  359. yHit = NO_HIT;
  360. // Compute handle code
  361. // if no handle hit, set to 4 (drag full object)
  362. if (xHit != NO_HIT && yHit != NO_HIT)
  363. m_uHdlCode = xHit + 3 * yHit;
  364. else
  365. m_uHdlCode = 4;
  366. // Set cursor to match handle
  367. SetCursor(hCursTable[uCursIDTable[m_uHdlCode] - IDC_CURS_MIN]);
  368. break;
  369. case DRAG_PENDING:
  370. // Start resize if movement threshold exceeded
  371. dx = (x >= m_ptDown.x) ? (x - m_ptDown.x) : (m_ptDown.x - x);
  372. dy = (y >= m_ptDown.y) ? (y - m_ptDown.y) : (m_ptDown.y - y);
  373. if (dx > iDragMinDist || dy > iDragMinDist) {
  374. KillTimer(m_hWnd, IDTIMER_DEBOUNCE);
  375. // Create and display initial drag region
  376. m_hRgnDrag = CreateDragRgn(&m_rcPos);
  377. if ( NULL != m_hRgnDrag ) {
  378. DrawDragRgn(m_hWndParent, m_hRgnDrag);
  379. // Initialize new rect
  380. m_rectNew = m_rcPos;
  381. m_uDragMode = DRAG_ACTIVE;
  382. }
  383. }
  384. break;
  385. case DRAG_ACTIVE:
  386. dx = x - m_ptDown.x;
  387. dy = y - m_ptDown.y;
  388. // Compute new rect by applying deltas to selected edges
  389. // of original position rect
  390. uResizeFlags = uSizingTable[m_uHdlCode];
  391. if (uResizeFlags & SIZING_ALL) {
  392. m_rectNew.left = m_rcPos.left + dx;
  393. m_rectNew.top = m_rcPos.top + dy;
  394. m_rectNew.right = m_rcPos.right + dx;
  395. m_rectNew.bottom = m_rcPos.bottom + dy;
  396. } else {
  397. if (uResizeFlags & SIZING_TOP) {
  398. m_rectNew.top = m_rcPos.top + dy;
  399. if (m_rectNew.bottom - m_rectNew.top < MIN_SIZE)
  400. m_rectNew.top = m_rectNew.bottom - MIN_SIZE;
  401. }
  402. if (uResizeFlags & SIZING_BOTTOM) {
  403. m_rectNew.bottom = m_rcPos.bottom + dy;
  404. if (m_rectNew.bottom - m_rectNew.top < MIN_SIZE)
  405. m_rectNew.bottom = m_rectNew.top + MIN_SIZE;
  406. }
  407. if (uResizeFlags & SIZING_LEFT) {
  408. m_rectNew.left = m_rcPos.left + dx;
  409. if (m_rectNew.right - m_rectNew.left < MIN_SIZE)
  410. m_rectNew.left = m_rectNew.right - MIN_SIZE;
  411. }
  412. if (uResizeFlags & SIZING_RIGHT) {
  413. m_rectNew.right = m_rcPos.right + dx;
  414. if (m_rectNew.right - m_rectNew.left < MIN_SIZE)
  415. m_rectNew.right = m_rectNew.left + MIN_SIZE;
  416. }
  417. }
  418. // Compute new drag region
  419. hRgnNew = CreateDragRgn(&m_rectNew);
  420. if ( NULL != hRgnNew ) {
  421. // Repaint difference between old and new regions (No Flicker!)
  422. hRgnDiff = CreateRectRgn(0,0,0,0);
  423. if ( NULL != m_hRgnDrag
  424. && NULL != hRgnDiff ) {
  425. CombineRgn(hRgnDiff, m_hRgnDrag, hRgnNew, RGN_XOR);
  426. DrawDragRgn(m_hWndParent, hRgnDiff);
  427. } else {
  428. DrawDragRgn(m_hWndParent, hRgnNew);
  429. }
  430. if ( NULL != hRgnDiff ) {
  431. DeleteObject ( hRgnDiff );
  432. }
  433. // Update current region
  434. if ( NULL != m_hRgnDrag ) {
  435. DeleteObject(m_hRgnDrag);
  436. }
  437. m_hRgnDrag = hRgnNew;
  438. }
  439. }
  440. }
  441. void CHatchWin::OnTimer()
  442. {
  443. if ( DRAG_PENDING == m_uDragMode ) {
  444. KillTimer(m_hWnd, IDTIMER_DEBOUNCE);
  445. // Create and display initial drag region
  446. m_hRgnDrag = CreateDragRgn(&m_rcPos);
  447. if ( NULL != m_hRgnDrag ) {
  448. DrawDragRgn(m_hWndParent, m_hRgnDrag);
  449. // Initialize new rect
  450. m_rectNew = m_rcPos;
  451. m_uDragMode = DRAG_ACTIVE;
  452. }
  453. }
  454. }
  455. void CHatchWin::OnPaint()
  456. {
  457. HDC hDC;
  458. RECT rc;
  459. PAINTSTRUCT ps;
  460. INT iWidth, iHeight;
  461. hDC = BeginPaint(m_hWnd, &ps);
  462. // setup hatch rect in window's coord system
  463. iWidth = m_rcPos.right - m_rcPos.left + 2 * m_iBorder;
  464. iHeight = m_rcPos.bottom - m_rcPos.top + 2 * m_iBorder;
  465. SetRect(&rc, m_ptHatchOrg.x, m_ptHatchOrg.y,
  466. m_ptHatchOrg.x + iWidth,
  467. m_ptHatchOrg.y + iHeight);
  468. DrawShading(hDC, &rc);
  469. DrawHandles(hDC, &rc);
  470. EndPaint(m_hWnd, &ps);
  471. }
  472. /*
  473. * CHatchWin::ShowHatch
  474. *
  475. * Purpose:
  476. * Turns hatching on and off; turning the hatching off changes
  477. * the size of the window to be exactly that of the child, leaving
  478. * everything else the same. The result is that we don't have
  479. * to turn off drawing because our own WM_PAINT will never be
  480. * called.
  481. *
  482. * Parameters:
  483. * fHatch BOOL indicating to show (TRUE) or hide (FALSE)
  484. the hatching.
  485. *
  486. * Return Value:
  487. * None
  488. */
  489. void CHatchWin::ShowHatch(BOOL fHatch)
  490. {
  491. /*
  492. * All we have to do is set the border to zero and
  493. * call SetRects again with the last rectangles the
  494. * child sent to us.
  495. */
  496. m_iBorder = fHatch ? iBorder : 0;
  497. RectsSet(NULL, NULL);
  498. return;
  499. }
  500. /*
  501. * CHatchWin::Window
  502. *
  503. * Purpose:
  504. * Returns the window handle associated with this object.
  505. *
  506. * Return Value:
  507. * HWND Window handle for this object
  508. */
  509. HWND CHatchWin::Window(void)
  510. {
  511. return m_hWnd;
  512. }
  513. /*
  514. * HatchWndProc
  515. *
  516. * Purpose:
  517. * Standard window procedure for the Hatch Window
  518. */
  519. LRESULT APIENTRY HatchWndProc(HWND hWnd, UINT iMsg
  520. , WPARAM wParam, LPARAM lParam)
  521. {
  522. PCHatchWin phw;
  523. phw = (PCHatchWin)GetWindowLongPtr(hWnd, HWWL_STRUCTURE);
  524. switch (iMsg)
  525. {
  526. case WM_CREATE:
  527. phw = (PCHatchWin)((LPCREATESTRUCT)lParam)->lpCreateParams;
  528. SetWindowLongPtr(hWnd, HWWL_STRUCTURE, (INT_PTR)phw);
  529. break;
  530. case WM_DESTROY:
  531. phw->m_hWnd = NULL;
  532. break;
  533. case WM_PAINT:
  534. phw->OnPaint();
  535. break;
  536. case WM_SIZE:
  537. // If this resize is not due to RectsSet then forward it
  538. // to adjust our internal control window
  539. if (!phw->m_bResizeInProgress)
  540. {
  541. RECT rc;
  542. POINT pt;
  543. // Get new rect in container coords
  544. GetWindowRect(hWnd, &rc);
  545. // Convert to parent client coords
  546. pt.x = pt.y = 0;
  547. ClientToScreen(GetParent(hWnd), &pt);
  548. OffsetRect(&rc,-pt.x, -pt.y);
  549. // Resize control
  550. phw->RectsSet(&rc, NULL);
  551. }
  552. break;
  553. case WM_MOUSEMOVE:
  554. phw->OnMouseMove((short)LOWORD(lParam),(short)HIWORD(lParam));
  555. break;
  556. case WM_LBUTTONDOWN:
  557. phw->OnLeftDown((short)LOWORD(lParam),(short)HIWORD(lParam));
  558. break;
  559. case WM_LBUTTONUP:
  560. phw->OnLeftUp();
  561. break;
  562. case WM_TIMER:
  563. phw->OnTimer();
  564. break;
  565. case WM_SETFOCUS:
  566. //We need this since the container will SetFocus to us.
  567. if (NULL != phw->m_hWndKid)
  568. SetFocus(phw->m_hWndKid);
  569. break;
  570. case WM_LBUTTONDBLCLK:
  571. /*
  572. * If the double click was within m_dBorder of an
  573. * edge, send the HWN_BORDERDOUBLECLICKED notification.
  574. *
  575. * Because we're always sized just larger than our child
  576. * window by the border width, we can only *get* this
  577. * message when the mouse is on the border. So we can
  578. * just send the notification.
  579. */
  580. if (NULL!=phw->m_hWndAssociate)
  581. {
  582. SendMessage(phw->m_hWndAssociate, WM_COMMAND,
  583. MAKEWPARAM(phw->m_uID,HWN_BORDERDOUBLECLICKED),
  584. (LPARAM)hWnd);
  585. }
  586. break;
  587. default:
  588. return DefWindowProc(hWnd, iMsg, wParam, lParam);
  589. }
  590. return 0L;
  591. }
  592. HRGN CreateDragRgn(LPRECT pRect)
  593. {
  594. HRGN hRgnIn;
  595. HRGN hRgnOut;
  596. HRGN hRgnRet = NULL;
  597. if ( NULL != pRect ) {
  598. hRgnRet = CreateRectRgn(0,0,0,0);
  599. hRgnIn = CreateRectRgn(pRect->left, pRect->top,pRect->right, pRect->bottom);
  600. hRgnOut = CreateRectRgn(pRect->left - iBorder, pRect->top - iBorder,
  601. pRect->right + iBorder, pRect->bottom + iBorder);
  602. if ( NULL != hRgnOut
  603. && NULL != hRgnIn
  604. && NULL != hRgnRet ) {
  605. CombineRgn(hRgnRet, hRgnOut, hRgnIn, RGN_DIFF);
  606. }
  607. if ( NULL != hRgnIn ) {
  608. DeleteObject(hRgnIn);
  609. }
  610. if ( NULL != hRgnOut ) {
  611. DeleteObject(hRgnOut);
  612. }
  613. }
  614. return hRgnRet;
  615. }
  616. void DrawDragRgn(HWND hWnd, HRGN hRgn)
  617. {
  618. LONG lWndStyle;
  619. INT iMapMode;
  620. HDC hDC;
  621. RECT rc;
  622. HBRUSH hBr;
  623. COLORREF crText;
  624. // Turn off clipping by children
  625. lWndStyle = GetWindowLong(hWnd, GWL_STYLE);
  626. SetWindowLong(hWnd, GWL_STYLE, lWndStyle & ~WS_CLIPCHILDREN);
  627. // Prepare DC
  628. hDC = GetDC(hWnd);
  629. if ( NULL != hDC ) {
  630. iMapMode = SetMapMode(hDC, MM_TEXT);
  631. hBr = (HBRUSH)SelectObject(hDC, hBrGray);
  632. crText = SetTextColor(hDC, RGB(255, 255, 255));
  633. SelectClipRgn(hDC, hRgn);
  634. GetClipBox(hDC, &rc);
  635. PatBlt(hDC, rc.left, rc.top, rc.right - rc.left, rc.bottom - rc.top, PATINVERT);
  636. // Restore DC
  637. SelectObject(hDC, hBr);
  638. SetTextColor(hDC, crText);
  639. SetMapMode(hDC, iMapMode);
  640. SelectClipRgn(hDC, NULL);
  641. ReleaseDC(hWnd, hDC);
  642. }
  643. SetWindowLong(hWnd, GWL_STYLE, lWndStyle);
  644. }
  645. /*
  646. * DrawShading
  647. *
  648. * Purpose:
  649. * Draw a hatch border ourside the rectable given.
  650. *
  651. * Parameters:
  652. * prc LPRECT containing the rectangle.
  653. * hDC HDC on which to draw.
  654. * cWidth UINT width of the border to draw. Ignored
  655. * if dwFlags has UI_SHADE_FULLRECT.
  656. *
  657. * Return Value:
  658. * None
  659. */
  660. void DrawShading(HDC hDC, LPRECT prc)
  661. {
  662. HBRUSH hBROld;
  663. RECT rc;
  664. UINT cx, cy;
  665. COLORREF crText;
  666. COLORREF crBk;
  667. const DWORD dwROP = 0x00A000C9L; //DPa
  668. if (NULL==prc || NULL==hDC)
  669. return;
  670. hBROld = (HBRUSH)SelectObject(hDC, hBrHatch);
  671. rc = *prc;
  672. cx = rc.right - rc.left;
  673. cy = rc.bottom - rc.top;
  674. crText = SetTextColor(hDC, RGB(255, 255, 255));
  675. crBk = SetBkColor(hDC, RGB(0, 0, 0));
  676. PatBlt(hDC, rc.left, rc.top, cx, iBorder, dwROP);
  677. PatBlt(hDC, rc.left, rc.top, iBorder, cy, dwROP);
  678. PatBlt(hDC, rc.right-iBorder, rc.top, iBorder, cy, dwROP);
  679. PatBlt(hDC, rc.left, rc.bottom-iBorder, cx, iBorder, dwROP);
  680. SetTextColor(hDC, crText);
  681. SetBkColor(hDC, crBk);
  682. SelectObject(hDC, hBROld);
  683. return;
  684. }
  685. void DrawHandles (HDC hDC, LPRECT prc)
  686. {
  687. HPEN hPenOld;
  688. HBRUSH hBROld;
  689. INT left,right,top,bottom;
  690. #define DrawHandle(x,y) Rectangle(hDC, x, y, (x) + iBorder + 1, (y) + iBorder + 1)
  691. hPenOld = (HPEN)SelectObject(hDC, (HPEN)GetStockObject(BLACK_PEN));
  692. hBROld = (HBRUSH)SelectObject(hDC, (HBRUSH)GetStockObject(BLACK_BRUSH));
  693. left = prc->left;
  694. right = prc->right - iBorder;
  695. top = prc->top;
  696. bottom = prc->bottom - iBorder;
  697. DrawHandle(left, top);
  698. DrawHandle(left, (top + bottom)/2);
  699. DrawHandle(left, bottom);
  700. DrawHandle(right, top);
  701. DrawHandle(right, (top + bottom)/2);
  702. DrawHandle(right, bottom);
  703. DrawHandle((left + right)/2, top);
  704. DrawHandle((left + right)/2, bottom);
  705. SelectObject(hDC, hPenOld);
  706. SelectObject(hDC, hBROld);
  707. }