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.

1765 lines
49 KiB

  1. //---------------------------------------------------------------------------------------
  2. // File : Pager.cpp
  3. // Description :
  4. // This file implements the pager control
  5. //---------------------------------------------------------------------------------------
  6. #include "ctlspriv.h"
  7. #include "pager.h"
  8. #define MINBUTTONSIZE 12
  9. //Timer Flags
  10. #define PGT_SCROLL 1
  11. void DrawScrollArrow(HDC hdc, LPRECT lprc, WORD wControlState);
  12. //Public Functions
  13. //---------------------------------------------------------------------------------------
  14. extern "C" {
  15. //This function registers the pager window class
  16. BOOL InitPager(HINSTANCE hinst)
  17. {
  18. WNDCLASS wc;
  19. TraceMsg(TF_PAGER, "Init Pager");
  20. wc.lpfnWndProc = CPager::PagerWndProc;
  21. wc.hCursor = LoadCursor(NULL, IDC_ARROW);
  22. wc.hIcon = NULL;
  23. wc.lpszMenuName = NULL;
  24. wc.hInstance = hinst;
  25. wc.lpszClassName = WC_PAGESCROLLER;
  26. wc.hbrBackground = (HBRUSH)(COLOR_BTNFACE + 1); // NULL;
  27. wc.style = CS_GLOBALCLASS;
  28. wc.cbWndExtra = sizeof(LPVOID);
  29. wc.cbClsExtra = 0;
  30. return (RegisterClass(&wc) || (GetLastError() == ERROR_CLASS_ALREADY_EXISTS));
  31. }
  32. }; // extern "C"
  33. //---------------------------------------------------------------------------------------
  34. CPager::CPager()
  35. {
  36. _clrBk = g_clrBtnFace;
  37. //Initialize Static Members
  38. _iButtonSize = (int) g_cxScrollbar * 3 / 4;
  39. if (_iButtonSize < MINBUTTONSIZE) {
  40. _iButtonSize = MINBUTTONSIZE;
  41. }
  42. _ptLastMove.x = -1;
  43. _ptLastMove.y = -1;
  44. _cLinesPerTimeout = 0;
  45. _cPixelsPerLine = 0;
  46. _cTimeout = GetDoubleClickTime() / 8;
  47. }
  48. //---------------------------------------------------------------------------------------
  49. // Static Pager Window Procedure
  50. LRESULT CPager::PagerWndProc(HWND hwnd, UINT uMsg, WPARAM wParam, LPARAM lParam)
  51. {
  52. CPager *pp = (CPager*)GetWindowPtr(hwnd, 0);
  53. if (uMsg == WM_CREATE) {
  54. ASSERT(!pp);
  55. pp = new CPager();
  56. if (!pp)
  57. return 0L;
  58. }
  59. if (pp) {
  60. return pp->v_WndProc(hwnd, uMsg, wParam, lParam);
  61. }
  62. return DefWindowProc(hwnd, uMsg, wParam, lParam);
  63. }
  64. //---------------------------------------------------------------------------------------
  65. LRESULT CPager::PagerDragCallback(HWND hwnd, UINT uMsg, WPARAM wParam, LPARAM lParam)
  66. {
  67. CPager *pp = (CPager*)GetWindowPtr(hwnd, 0);
  68. if (pp) {
  69. return pp->_DragCallback(hwnd, uMsg, wParam, lParam);
  70. }
  71. return -1;
  72. }
  73. //---------------------------------------------------------------------------------------
  74. // CControl Class Implementation
  75. //---------------------------------------------------------------------------------------
  76. LRESULT CControl::v_WndProc(HWND hwnd, UINT uMsg, WPARAM wParam, LPARAM lParam)
  77. {
  78. LRESULT lres = 0;
  79. if (uMsg == WM_THEMECHANGED) // Check for theme changes
  80. {
  81. if (_hTheme)
  82. CloseThemeData(_hTheme);
  83. _hTheme = OpenThemeData(ci.hwnd, GetThemeClass());
  84. InvalidateRect(ci.hwnd, NULL, TRUE);
  85. }
  86. switch (uMsg) {
  87. case WM_CREATE:
  88. SetWindowPtr(hwnd, 0, this);
  89. CIInitialize(&ci, hwnd, (CREATESTRUCT*)lParam);
  90. _hTheme = OpenThemeData(ci.hwnd, GetThemeClass());
  91. return v_OnCreate();
  92. case WM_NCCALCSIZE:
  93. if (v_OnNCCalcSize(wParam, lParam, &lres))
  94. break;
  95. goto DoDefault;
  96. case WM_SIZE:
  97. v_OnSize(GET_X_LPARAM(lParam), GET_Y_LPARAM(lParam));
  98. break;
  99. case WM_NOTIFYFORMAT:
  100. return CIHandleNotifyFormat(&ci, lParam);
  101. case WM_NOTIFY:
  102. return v_OnNotify(wParam, lParam);
  103. case WM_STYLECHANGED:
  104. v_OnStyleChanged(wParam, lParam);
  105. break;
  106. case WM_COMMAND:
  107. return v_OnCommand(wParam, lParam);
  108. case WM_NCPAINT:
  109. v_OnNCPaint();
  110. goto DoDefault;
  111. case WM_PRINTCLIENT:
  112. case WM_PAINT:
  113. _OnPaint((HDC)wParam);
  114. break;
  115. case WM_DESTROY:
  116. SetWindowLongPtr(hwnd, 0, 0);
  117. if (_hTheme)
  118. CloseThemeData(_hTheme);
  119. delete this;
  120. break;
  121. case TB_SETPARENT:
  122. {
  123. HWND hwndOld = ci.hwndParent;
  124. ci.hwndParent = (HWND)wParam;
  125. return (LRESULT)hwndOld;
  126. }
  127. default:
  128. if (CCWndProc(&ci, uMsg, wParam, lParam, &lres))
  129. return lres;
  130. DoDefault:
  131. return DefWindowProc(hwnd, uMsg, wParam, lParam);
  132. }
  133. return lres;
  134. }
  135. //---------------------------------------------------------------------------------------
  136. BOOL CControl::v_OnNCCalcSize(WPARAM wParam, LPARAM lParam, LRESULT *plres)
  137. {
  138. return FALSE;
  139. }
  140. //---------------------------------------------------------------------------------------
  141. DWORD CControl::v_OnStyleChanged(WPARAM wParam, LPARAM lParam)
  142. {
  143. LPSTYLESTRUCT lpss = (LPSTYLESTRUCT) lParam;
  144. DWORD dwChanged = 0;
  145. if (wParam == GWL_STYLE) {
  146. ci.style = lpss->styleNew;
  147. dwChanged = (lpss->styleOld ^ lpss->styleNew);
  148. } else if (wParam == GWL_EXSTYLE) {
  149. //
  150. // Save the new ex-style bits
  151. //
  152. dwChanged = (lpss->styleOld ^ lpss->styleNew);
  153. ci.dwExStyle = lpss->styleNew;
  154. }
  155. TraceMsg(TF_PAGER, "cctl.v_osc: style=%x ret dwChged=%x", ci.style, dwChanged);
  156. return dwChanged;
  157. }
  158. //---------------------------------------------------------------------------------------
  159. void CControl::_OnPaint(HDC hdc)
  160. {
  161. if (hdc)
  162. {
  163. v_OnPaint(hdc);
  164. }
  165. else
  166. {
  167. PAINTSTRUCT ps;
  168. hdc = BeginPaint(ci.hwnd, &ps);
  169. v_OnPaint(hdc);
  170. EndPaint(ci.hwnd, &ps);
  171. }
  172. }
  173. //---------------------------------------------------------------------------------------
  174. // CPager Class Implementation
  175. //---------------------------------------------------------------------------------------
  176. inline int CPager::_GetButtonSize()
  177. {
  178. return _iButtonSize;
  179. }
  180. //---------------------------------------------------------------------------------------
  181. LRESULT CPager::_DragCallback(HWND hwnd, UINT code, WPARAM wp, LPARAM lp)
  182. {
  183. LRESULT lres = -1;
  184. switch (code)
  185. {
  186. case DPX_DRAGHIT:
  187. if (lp)
  188. {
  189. POINT pt;
  190. int iButton;
  191. pt.x = ((POINTL *)lp)->x;
  192. pt.y = ((POINTL *)lp)->y;
  193. MapWindowPoints(NULL, ci.hwnd, &pt, 1);
  194. iButton = _HitTest(pt.x, pt.y);
  195. if (iButton >= 0)
  196. {
  197. if(!_fTimerSet)
  198. {
  199. _fTimerSet = TRUE;
  200. _iButtonTrack = iButton;
  201. SetTimer(ci.hwnd, PGT_SCROLL, _cTimeout, NULL);
  202. }
  203. } else {
  204. _KillTimer();
  205. _iButtonTrack = -1;
  206. }
  207. }
  208. else
  209. lres = -1;
  210. break;
  211. case DPX_LEAVE:
  212. _KillTimer();
  213. _iButtonTrack = -1;
  214. break;
  215. default:
  216. lres = -1;
  217. break;
  218. }
  219. return lres;
  220. }
  221. //---------------------------------------------------------------------------------------
  222. void CPager::_NeedScrollbars(RECT rc)
  223. {
  224. int parentheight;
  225. int childheight;
  226. POINT ptPos = _ptPos;
  227. if( ci.style & PGS_HORZ ) {
  228. FlipRect(&rc);
  229. FlipPoint(&ptPos);
  230. }
  231. //Get Parent Window height
  232. parentheight = RECTHEIGHT(rc);
  233. //Get Child Window height
  234. rc = _rcChildIdeal;
  235. if (ci.style & PGS_HORZ ) {
  236. FlipRect(&rc);
  237. }
  238. childheight = RECTHEIGHT(rc);
  239. TraceMsg(TF_PAGER, "cps.nsb: cyChild=%d cyParent=%d _yPos=%d", childheight, parentheight, ptPos.y);
  240. if (childheight < parentheight )
  241. {
  242. ptPos.y = 0;
  243. }
  244. int iButton = _HitTestCursor();
  245. //See if we need top scrollbar
  246. if (ptPos.y > 0 ) {
  247. // if this button is the one that is hot tracked and the style is not PGS_AUTOSCROLL
  248. // then we set the state to PGF_HOT otherwise the state is set to PGF_NORMAL
  249. _dwState[PGB_TOPORLEFT] |= PGF_NORMAL;
  250. _dwState[PGB_TOPORLEFT] &= ~PGF_GRAYED;
  251. } else {
  252. if (!(ci.style & PGS_AUTOSCROLL) && (iButton == PGB_TOPORLEFT || _iButtonTrack == PGB_TOPORLEFT)) {
  253. _dwState[PGB_TOPORLEFT] |= PGF_GRAYED;
  254. } else {
  255. _dwState[PGB_TOPORLEFT] = PGF_INVISIBLE;
  256. }
  257. }
  258. if (_dwState[PGB_TOPORLEFT] != PGF_INVISIBLE)
  259. {
  260. parentheight -= _GetButtonSize();
  261. }
  262. //See if we need botton scrollbar
  263. if ((childheight - ptPos.y) > parentheight ) {
  264. //We need botton scroll bar
  265. // if this button is the one that is hot tracked and the style is not PGS_AUTOSCROLL
  266. // then we set the state to PGF_HOT otherwise the state is set to PGF_NORMAL
  267. _dwState[PGB_BOTTOMORRIGHT] |= PGF_NORMAL;
  268. _dwState[PGB_BOTTOMORRIGHT] &= ~PGF_GRAYED;
  269. } else {
  270. if (!(ci.style & PGS_AUTOSCROLL) && (iButton == PGB_BOTTOMORRIGHT || _iButtonTrack == PGB_BOTTOMORRIGHT)) {
  271. _dwState[PGB_BOTTOMORRIGHT] |= PGF_GRAYED;
  272. } else {
  273. _dwState[PGB_BOTTOMORRIGHT] = PGF_INVISIBLE;
  274. }
  275. }
  276. }
  277. //---------------------------------------------------------------------------------------
  278. BOOL CPager::v_OnNCCalcSize(WPARAM wParam, LPARAM lParam, LRESULT *plres)
  279. {
  280. *plres = DefWindowProc(ci.hwnd, WM_NCCALCSIZE, wParam, lParam ) ;
  281. if (wParam) {
  282. BOOL bHorzMirror = ((ci.dwExStyle & RTL_MIRRORED_WINDOW) && (ci.style & PGS_HORZ));
  283. DWORD dwStateOld[2];
  284. NCCALCSIZE_PARAMS* pnp = (NCCALCSIZE_PARAMS*)lParam;
  285. _rcDefClient = pnp->rgrc[0];
  286. InflateRect(&_rcDefClient, -_iBorder, -_iBorder);
  287. _GetChildSize();
  288. dwStateOld[0] = _dwState[0];
  289. dwStateOld[1] = _dwState[1];
  290. _NeedScrollbars(pnp->rgrc[0]);
  291. // invalidate only if something has changed to force a new size
  292. if ((dwStateOld[0] != _dwState[0] && (dwStateOld[0] == PGF_INVISIBLE || _dwState[0] == PGF_INVISIBLE)) ||
  293. (dwStateOld[1] != _dwState[1] && (dwStateOld[1] == PGF_INVISIBLE || _dwState[1] == PGF_INVISIBLE))
  294. ) {
  295. RedrawWindow(ci.hwnd, NULL,NULL,RDW_INVALIDATE|RDW_ERASE);
  296. }
  297. // Check and change for horizontal mode
  298. if( ci.style & PGS_HORZ ) {
  299. FlipRect(&(pnp->rgrc[0]));
  300. }
  301. if( _dwState[PGB_TOPORLEFT] != PGF_INVISIBLE ) {
  302. //
  303. // Check for RTL mirrored window
  304. //
  305. if (bHorzMirror)
  306. pnp->rgrc[0].bottom -= _GetButtonSize();
  307. else
  308. pnp->rgrc[0].top += _GetButtonSize();
  309. } else
  310. pnp->rgrc[0].top += _iBorder;
  311. if( _dwState[PGB_BOTTOMORRIGHT] != PGF_INVISIBLE ) {
  312. //
  313. // Check for RTL mirrored window
  314. //
  315. if (bHorzMirror)
  316. pnp->rgrc[0].top += _GetButtonSize();
  317. else
  318. pnp->rgrc[0].bottom -= _GetButtonSize();
  319. } else
  320. pnp->rgrc[0].bottom -= _iBorder;
  321. if (pnp->rgrc[0].bottom < pnp->rgrc[0].top)
  322. pnp->rgrc[0].bottom = pnp->rgrc[0].top;
  323. //Change back
  324. if( ci.style & PGS_HORZ ) {
  325. FlipRect(&(pnp->rgrc[0]));
  326. }
  327. }
  328. return TRUE;
  329. }
  330. int CPager::_HitTestCursor()
  331. {
  332. POINT pt;
  333. GetCursorPos(&pt);
  334. return _HitTestScreen(&pt);
  335. }
  336. int CPager::_HitTestScreen(POINT* ppt)
  337. {
  338. RECT rc, rc1;
  339. GetWindowRect(ci.hwnd, &rc);
  340. if (!PtInRect(&rc, *ppt)) {
  341. return -1;
  342. }
  343. //Get the button Rects;
  344. rc = _GetButtonRect(PGB_TOPORLEFT);
  345. rc1 = _GetButtonRect(PGB_BOTTOMORRIGHT);
  346. if (PtInRect(&rc, *ppt)) {
  347. return (_dwState[PGB_TOPORLEFT] != PGF_INVISIBLE ? PGB_TOPORLEFT : -1);
  348. }else if (PtInRect(&rc1, *ppt)) {
  349. return (_dwState[PGB_BOTTOMORRIGHT] != PGF_INVISIBLE ? PGB_BOTTOMORRIGHT : -1);
  350. }
  351. return -1;
  352. }
  353. //---------------------------------------------------------------------------------------
  354. int CPager::_HitTest(int x, int y)
  355. {
  356. POINT pt;
  357. pt.x = x;
  358. pt.y = y;
  359. ClientToScreen(ci.hwnd, &pt);
  360. return _HitTestScreen(&pt);
  361. }
  362. //---------------------------------------------------------------------------------------
  363. // _DrawBlank is theme aware
  364. void CPager::_DrawBlank(HDC hdc, int button)
  365. {
  366. RECT rc;
  367. UINT uFlags = 0;
  368. int iHeight;
  369. BOOL fRelDC = FALSE;
  370. if (!_hTheme)
  371. {
  372. if (hdc == NULL) {
  373. hdc = GetWindowDC(ci.hwnd);
  374. fRelDC = TRUE;
  375. }
  376. GetWindowRect(ci.hwnd, &rc);
  377. MapWindowRect(NULL, ci.hwnd, &rc);
  378. // client to window coordinates
  379. OffsetRect(&rc, -rc.left, -rc.top);
  380. //Check for horizontal mode
  381. if( ci.style & PGS_HORZ ) {
  382. FlipRect(&rc);
  383. }
  384. iHeight = _dwState[button] == PGF_INVISIBLE ? _iBorder : _GetButtonSize();
  385. switch(button) {
  386. case PGB_TOPORLEFT:
  387. rc.bottom = rc.top + iHeight;
  388. break;
  389. case PGB_BOTTOMORRIGHT:
  390. rc.top = rc.bottom - iHeight;
  391. break;
  392. }
  393. if( ci.style & PGS_HORZ ) {
  394. FlipRect(&rc);
  395. }
  396. FillRectClr(hdc, &rc, _clrBk);
  397. if (fRelDC)
  398. ReleaseDC(ci.hwnd, hdc);
  399. }
  400. }
  401. //---------------------------------------------------------------------------------------
  402. // _DrawButton is theme aware
  403. void CPager::_DrawButton(HDC hdc, int button)
  404. {
  405. RECT rc;
  406. UINT uFlags = 0;
  407. BOOL fRelDC = FALSE;
  408. GetWindowRect(ci.hwnd, &rc);
  409. MapWindowRect(NULL, ci.hwnd, &rc);
  410. int state = _dwState[button];
  411. int iPartId;
  412. int iStateId;
  413. if (state == PGF_INVISIBLE)
  414. return;
  415. if (hdc == NULL) {
  416. hdc = GetWindowDC(ci.hwnd);
  417. fRelDC = TRUE;
  418. }
  419. // All states for all Pager parts are the same enumeration value for
  420. // their meaning. Use the UP part version for all parts
  421. iStateId = UPS_NORMAL;
  422. if (state & PGF_GRAYED ) {
  423. uFlags |= DCHF_INACTIVE;
  424. iStateId = UPS_DISABLED;
  425. } else if (state & PGF_DEPRESSED ) {
  426. uFlags |= DCHF_PUSHED;
  427. iStateId = UPS_PRESSED;
  428. } else if (state & PGF_HOT ) {
  429. uFlags |= DCHF_HOT;
  430. iStateId = UPS_HOT;
  431. }
  432. // screen to window coordinates
  433. OffsetRect(&rc, -rc.left, -rc.top);
  434. //Check for horizontal mode
  435. if( ci.style & PGS_HORZ ) {
  436. FlipRect(&rc);
  437. }
  438. if( ci.style & PGS_HORZ )
  439. uFlags |= DCHF_HORIZONTAL;
  440. if (button == PGB_BOTTOMORRIGHT)
  441. uFlags |= DCHF_FLIPPED;
  442. switch(button) {
  443. case PGB_TOPORLEFT:
  444. rc.bottom = rc.top + _GetButtonSize();
  445. rc.left += _iBorder;
  446. rc.right -= _iBorder;
  447. if (_hTheme)
  448. {
  449. iPartId = (ci.style & PGS_HORZ) ? PGRP_DOWNHORZ : PGRP_DOWN;
  450. rc.bottom += 1;
  451. }
  452. break;
  453. case PGB_BOTTOMORRIGHT:
  454. rc.top = rc.bottom - _GetButtonSize();
  455. rc.left += _iBorder;
  456. rc.right -= _iBorder;
  457. if (_hTheme)
  458. {
  459. iPartId = (ci.style & PGS_HORZ) ? PGRP_UPHORZ : PGRP_UP;
  460. rc.top -= 1;
  461. }
  462. break;
  463. default:
  464. if (_hTheme)
  465. iPartId = PGRP_UP;
  466. ASSERT(FALSE);
  467. }
  468. if( ci.style & PGS_HORZ ) {
  469. FlipRect(&rc);
  470. }
  471. if (_hTheme)
  472. {
  473. DrawThemeBackground(_hTheme, hdc, iPartId, iStateId, &rc, 0);
  474. }
  475. else
  476. {
  477. SetBkColor(hdc, _clrBk);
  478. DrawScrollArrow(hdc, &rc, uFlags, CLR_INVALID);
  479. }
  480. if (fRelDC)
  481. ReleaseDC(ci.hwnd, hdc);
  482. }
  483. //---------------------------------------------------------------------------------------
  484. void CPager::v_OnNCPaint()
  485. {
  486. HDC hdc = GetWindowDC(ci.hwnd);
  487. _DrawBlank(hdc, PGB_TOPORLEFT);
  488. _DrawButton(hdc, PGB_TOPORLEFT);
  489. _DrawBlank(hdc, PGB_BOTTOMORRIGHT);
  490. _DrawButton(hdc, PGB_BOTTOMORRIGHT);
  491. ReleaseDC(ci.hwnd, hdc);
  492. }
  493. //---------------------------------------------------------------------------------------
  494. void CPager::v_OnPaint(HDC hdc)
  495. {
  496. }
  497. //---------------------------------------------------------------------------------------
  498. BOOL CPager::_OnPrint(HDC hdc, UINT uFlags)
  499. {
  500. //We'll be partying with the hdc in this function so save it.
  501. int iDC = SaveDC(hdc);
  502. //Print only the Non Client Area.
  503. if (uFlags & PRF_NONCLIENT) {
  504. int cx = 0;
  505. int cy = 0;
  506. RECT rc;
  507. //Draw the top/left button
  508. _DrawBlank(hdc, PGB_TOPORLEFT);
  509. _DrawButton(hdc, PGB_TOPORLEFT);
  510. //Draw the bottom/left button
  511. _DrawBlank(hdc, PGB_BOTTOMORRIGHT);
  512. _DrawButton(hdc, PGB_BOTTOMORRIGHT);
  513. //Is the top button visible
  514. if (_dwState[PGB_TOPORLEFT] != PGF_INVISIBLE) {
  515. //yes, find the space taken
  516. if ( ci.style & PGS_HORZ ) {
  517. cx = _GetButtonSize();
  518. }else {
  519. cy = _GetButtonSize();
  520. }
  521. }
  522. //Restrict the child draw area to our client area
  523. GetClientRect(ci.hwnd, &rc);
  524. IntersectClipRect(hdc, cx, cy, cx + RECTWIDTH(rc), cy + RECTHEIGHT(rc));
  525. //Since We have drawn the non client area, Nuke the PRF_NONCLIENT flag
  526. uFlags &= ~PRF_NONCLIENT;
  527. }
  528. //Pass it to the def window proc for default processing
  529. DefWindowProc(ci.hwnd, WM_PRINT, (WPARAM)hdc, (LPARAM)uFlags);
  530. //Restore the saved DC
  531. RestoreDC(hdc, iDC);
  532. return TRUE;
  533. }
  534. //---------------------------------------------------------------------------------------
  535. LRESULT CPager::v_OnCommand(WPARAM wParam, LPARAM lParam)
  536. {
  537. // forward to parent
  538. return SendMessage(ci.hwndParent, WM_COMMAND, wParam, lParam);
  539. }
  540. //---------------------------------------------------------------------------------------
  541. LRESULT CPager::v_OnNotify(WPARAM wParam, LPARAM lParam)
  542. {
  543. // forward to parent
  544. LPNMHDR lpNmhdr = (LPNMHDR)lParam;
  545. return SendNotifyEx(ci.hwndParent, (HWND) -1,
  546. lpNmhdr->code, lpNmhdr, ci.bUnicode);
  547. }
  548. //---------------------------------------------------------------------------------------
  549. DWORD CPager::v_OnStyleChanged(WPARAM wParam, LPARAM lParam)
  550. {
  551. DWORD dwChanged = CControl::v_OnStyleChanged(wParam, lParam);
  552. if (dwChanged & PGS_DRAGNDROP) {
  553. if ((ci.style & PGS_DRAGNDROP) && !_hDragProxy) {
  554. _hDragProxy = CreateDragProxy(ci.hwnd, PagerDragCallback, TRUE);
  555. } else if (! (ci.style & PGS_DRAGNDROP) && _hDragProxy) {
  556. DestroyDragProxy(_hDragProxy);
  557. }
  558. }
  559. if (dwChanged)
  560. CCInvalidateFrame(ci.hwnd); // SWP_FRAMECHANGED etc.
  561. return dwChanged;
  562. }
  563. //---------------------------------------------------------------------------------------
  564. LRESULT CPager::v_OnCreate()
  565. {
  566. if (ci.style & PGS_DRAGNDROP)
  567. _hDragProxy = CreateDragProxy(ci.hwnd, PagerDragCallback, TRUE);
  568. return TRUE;
  569. }
  570. //---------------------------------------------------------------------------------------
  571. void CPager::_GetChildSize()
  572. {
  573. if (_hwndChild) {
  574. RECT rc;
  575. NMPGCALCSIZE nmpgcalcsize;
  576. int width , height;
  577. rc = _rcDefClient;
  578. if( ci.style & PGS_HORZ ) {
  579. nmpgcalcsize.dwFlag = PGF_CALCWIDTH;
  580. } else {
  581. nmpgcalcsize.dwFlag = PGF_CALCHEIGHT;
  582. }
  583. nmpgcalcsize.iWidth = RECTWIDTH(rc); // pager width
  584. nmpgcalcsize.iHeight = RECTHEIGHT(rc); // best-guess for child
  585. CCSendNotify(&ci, PGN_CALCSIZE, &nmpgcalcsize.hdr);
  586. if( ci.style & PGS_HORZ ) {
  587. width = nmpgcalcsize.iWidth;
  588. height = RECTHEIGHT(rc);
  589. } else {
  590. width = RECTWIDTH(rc);
  591. height = nmpgcalcsize.iHeight;
  592. }
  593. GetWindowRect(_hwndChild, &rc);
  594. MapWindowRect(NULL, ci.hwnd, &rc);
  595. if( ci.style & PGS_HORZ ) {
  596. rc.top = _iBorder;
  597. } else {
  598. rc.left = _iBorder;
  599. }
  600. rc.right = rc.left + width;
  601. rc.bottom = rc.top + height;
  602. _rcChildIdeal = rc;
  603. }
  604. }
  605. //---------------------------------------------------------------------------------------
  606. void CPager::v_OnSize(int x, int y)
  607. {
  608. if (_hwndChild) {
  609. RECT rc = _rcChildIdeal;
  610. _SetChildPos(&rc, 0); // SetWindowPos
  611. }
  612. }
  613. //---------------------------------------------------------------------------------------
  614. //*** _SetChildPos -- SetWindowPos of child, w/ validation
  615. // NOTES
  616. // 'validation' means in sane state -- min size, and not off end.
  617. // WARNING: we don't update *prcChild.
  618. void CPager::_SetChildPos(IN RECT * prcChild, UINT uFlags)
  619. {
  620. POINT ptPos = _ptPos;
  621. RECT rcChild = *prcChild;
  622. RECT rcPager;
  623. ASSERT(!(uFlags & SWP_NOMOVE)); // won't work
  624. ASSERT(IS_VALID_HANDLE(_hwndChild, WND));
  625. rcPager = _rcDefClient;
  626. if ( ci.style & PGS_HORZ ) {
  627. FlipPoint(&ptPos);
  628. FlipRect(&rcChild);
  629. FlipRect(&rcPager);
  630. }
  631. int yNew = ptPos.y;
  632. if (RECTHEIGHT(rcChild) < RECTHEIGHT(rcPager)) {
  633. // force to min height
  634. // this handles the case where: i have an ISFBand that fills up the
  635. // whole pager, i stretch the pager width, and the ISFBand reformats
  636. // to take less height, so it shrinks its height and ends up shorter
  637. // than the pager.
  638. TraceMsg(TF_PAGER, "cps.s: h=%d h'=%d", RECTHEIGHT(rcChild), RECTHEIGHT(rcPager));
  639. ASSERT(!(uFlags & SWP_NOSIZE)); // won't work
  640. rcChild.bottom = rcChild.top + RECTHEIGHT(rcPager);
  641. yNew = 0;
  642. }
  643. // Maximum we can scroll is child height minus pager height.
  644. // Here rcPager also includes scrollbutton so we need to add that also
  645. /*
  646. ___________ Button Width
  647. |
  648. V ---------------- Max we can scroll (yMax)
  649. __ |
  650. / \V
  651. - ---------pager-----------
  652. | |-------------------------|--------------------------------
  653. | || | |
  654. | || child | |
  655. | |-------------------------|--------------------------------
  656. - -------------------------
  657. \/\/
  658. Border | |
  659. <----- -------------->We need to take care of this gap.
  660. \-----------------------------/
  661. ^
  662. |______ RECTHEIGHT(rcChild) - RECTHEIGHT(rcPager)
  663. rcPager
  664. We need to add the difference between the button size and border to
  665. */
  666. int yMax = RECTHEIGHT(rcChild) - RECTHEIGHT(rcPager) + (_GetButtonSize() - _iBorder);
  667. // make sure we don't end up off the top/end, and we always show
  668. // at least 1 page worth (if we have that much)
  669. // n.b. pager can override client's policy
  670. if (yNew < 0) {
  671. // 1st page
  672. yNew = 0;
  673. } else if (yNew > yMax) {
  674. // last page
  675. yNew = yMax;
  676. }
  677. int yOffset = yNew;
  678. // When the top button is grayed we do not want to display our child away from the button .
  679. // it should be drawn right below the button. For this we tweak the position of the child window.
  680. //Check for the condition of grayed top button in which case we need to set position even behind
  681. // so that the child window falls below the grayed button
  682. if( _dwState[PGB_TOPORLEFT] & PGF_GRAYED )
  683. {
  684. yOffset += (_GetButtonSize() - _iBorder);
  685. }
  686. //yOffset is the tweaked value. Its just for making the child window to appear below the grayed button
  687. OffsetRect(&rcChild, 0, -yOffset - rcChild.top);
  688. //yNew is the actual logical positon of the window .
  689. ptPos.y = yNew;
  690. if (ci.style & PGS_HORZ) {
  691. // restore for copy and SWP
  692. FlipPoint(&ptPos);
  693. FlipRect(&rcChild);
  694. }
  695. _ptPos = ptPos;
  696. SetWindowPos(_hwndChild, NULL, rcChild.left, rcChild.top, RECTWIDTH(rcChild), RECTHEIGHT(rcChild), uFlags);
  697. return;
  698. }
  699. //---------------------------------------------------------------------------------------
  700. //*** PGFToPGNDirection -- convert PGB_TOPORLEFT/btmorright to up/down/left/right
  701. // NOTES
  702. // REARCHIT maybe PGN_* should we just take the PGF flags?
  703. DWORD CPager::_PGFToPGNDirection(DWORD dwDir)
  704. {
  705. ASSERT(dwDir == PGB_TOPORLEFT || dwDir == PGB_BOTTOMORRIGHT);
  706. if (ci.style & PGS_HORZ) {
  707. return (dwDir == PGB_TOPORLEFT) ? PGF_SCROLLLEFT : PGF_SCROLLRIGHT;
  708. }
  709. else {
  710. return (dwDir == PGB_TOPORLEFT) ? PGF_SCROLLUP : PGF_SCROLLDOWN;
  711. }
  712. }
  713. //---------------------------------------------------------------------------------------
  714. void CPager::_Scroll(DWORD dwDirection)
  715. {
  716. RECT rc;
  717. NMPGSCROLL nmpgscroll;
  718. int iXoffset =0, iYoffset=0;
  719. WORD fwKeys = 0;
  720. int iNewPos ;
  721. // if grayed, you can't scroll.
  722. if (_dwState[dwDirection] & PGF_GRAYED)
  723. return;
  724. if (GetKeyState(VK_CONTROL) < 0 )
  725. fwKeys |= PGK_CONTROL;
  726. if (GetKeyState(VK_SHIFT) < 0 )
  727. fwKeys |= PGK_SHIFT;
  728. if (GetKeyState(VK_MENU) < 0 )
  729. fwKeys |= PGK_MENU;
  730. dwDirection = _PGFToPGNDirection(dwDirection);
  731. // set some defaults
  732. GetClientRect(ci.hwnd, &rc);
  733. nmpgscroll.fwKeys = fwKeys;
  734. nmpgscroll.rcParent = rc;
  735. nmpgscroll.iXpos = _ptPos.x;
  736. nmpgscroll.iYpos = _ptPos.y;
  737. nmpgscroll.iDir = dwDirection;
  738. int iScroll = (ci.style & PGS_HORZ) ? RECTWIDTH(rc) : RECTHEIGHT(rc);
  739. if (_cLinesPerTimeout)
  740. iScroll = _cLinesPerTimeout * _cPixelsPerLine;
  741. nmpgscroll.iScroll = iScroll;
  742. // let client override
  743. CCSendNotify(&ci, PGN_SCROLL, &nmpgscroll.hdr);
  744. // do it
  745. switch (dwDirection)
  746. {
  747. case PGF_SCROLLDOWN:
  748. iNewPos = _ptPos.y + nmpgscroll.iScroll;
  749. break;
  750. case PGF_SCROLLUP:
  751. iNewPos = _ptPos.y - nmpgscroll.iScroll;
  752. break;
  753. case PGF_SCROLLRIGHT:
  754. iNewPos = _ptPos.x + nmpgscroll.iScroll;
  755. break;
  756. case PGF_SCROLLLEFT:
  757. iNewPos = _ptPos.x - nmpgscroll.iScroll;
  758. break;
  759. }
  760. _OnSetPos(iNewPos);
  761. }
  762. //---------------------------------------------------------------------------------------
  763. void CPager::_OnLButtonChange(UINT uMsg,LPARAM lParam)
  764. {
  765. POINT pt;
  766. int iButton;
  767. pt.x = GET_X_LPARAM(lParam);
  768. pt.y = GET_Y_LPARAM(lParam);
  769. iButton = _HitTest(pt.x, pt.y);
  770. if( uMsg == WM_LBUTTONDOWN ) {
  771. // Check the button is valid and is not grayed
  772. // if it is grayed then dont do anything
  773. if (iButton >= 0) {
  774. SetCapture(ci.hwnd);
  775. _fOwnsButtonDown = TRUE;
  776. _iButtonTrack = iButton;
  777. _dwState[iButton] |= PGF_DEPRESSED;
  778. _DrawButton(NULL, iButton);
  779. _Scroll(iButton);
  780. SetTimer(ci.hwnd, PGT_SCROLL, _cTimeout * 4, NULL);
  781. }
  782. } else {
  783. if (_iButtonTrack >= 0) {
  784. _dwState[_iButtonTrack] &= ~PGF_DEPRESSED;
  785. _DrawButton(NULL, _iButtonTrack);
  786. _iButtonTrack = -1;
  787. }
  788. _KillTimer();
  789. if (iButton < 0)
  790. _OnMouseLeave();
  791. }
  792. }
  793. //---------------------------------------------------------------------------------------
  794. RECT CPager :: _GetButtonRect(int iButton)
  795. {
  796. RECT rc;
  797. GetWindowRect(ci.hwnd, &rc);
  798. if( ci.style & PGS_HORZ ) {
  799. FlipRect(&rc);
  800. }
  801. //
  802. // Mirror the rects if the parent is mirrored
  803. //
  804. if (((ci.dwExStyle & RTL_MIRRORED_WINDOW) && (ci.style & PGS_HORZ))) {
  805. switch (iButton) {
  806. case PGB_TOPORLEFT:
  807. iButton = PGB_BOTTOMORRIGHT;
  808. break;
  809. case PGB_BOTTOMORRIGHT:
  810. iButton = PGB_TOPORLEFT;
  811. break;
  812. }
  813. }
  814. switch(iButton) {
  815. case PGB_TOPORLEFT:
  816. rc.bottom = rc.top + _GetButtonSize();
  817. rc.left += _iBorder;
  818. rc.right -= _iBorder;
  819. break;
  820. case PGB_BOTTOMORRIGHT:
  821. rc.top = rc.bottom - _GetButtonSize();
  822. rc.left += _iBorder;
  823. rc.right -= _iBorder;
  824. break;
  825. }
  826. if( ci.style & PGS_HORZ ) {
  827. FlipRect(&rc);
  828. }
  829. return rc;
  830. }
  831. //---------------------------------------------------------------------------------------
  832. void CPager :: _OnMouseLeave()
  833. {
  834. //Whether we leave the window (WM_MOUSELEAVE) or Leave one of the scroll buttons (WM_MOUSEMOVE)
  835. // We do the same thing.
  836. // We are leaving the pager window.
  837. if (GetCapture() == ci.hwnd) {
  838. CCReleaseCapture(&ci);
  839. }
  840. // if we are tracking some button then release that mouse and that button
  841. if (_iButtonTrack >= 0) {
  842. _iButtonTrack = -1;
  843. }
  844. int iButton = _HitTest(_ptLastMove.x, _ptLastMove.y);
  845. _OnHotItemChange(iButton, FALSE);
  846. if (_dwState[PGB_TOPORLEFT] & (PGF_HOT | PGF_DEPRESSED)) {
  847. _dwState[PGB_TOPORLEFT] &= ~(PGF_HOT | PGF_DEPRESSED);
  848. _DrawButton(NULL, PGB_TOPORLEFT);
  849. }
  850. if (_dwState[PGB_BOTTOMORRIGHT] & (PGF_HOT | PGF_DEPRESSED)) {
  851. _dwState[PGB_BOTTOMORRIGHT] &= ~(PGF_HOT | PGF_DEPRESSED);
  852. _DrawButton(NULL, PGB_BOTTOMORRIGHT);
  853. }
  854. _KillTimer();
  855. _fOwnsButtonDown = FALSE;
  856. //If any of the button is in gray state then it needs to be removed.
  857. if ((_dwState[PGB_TOPORLEFT] & PGF_GRAYED) || (_dwState[PGB_BOTTOMORRIGHT] & PGF_GRAYED)) {
  858. //This forces a recalc for scrollbars and removes those that are not needed
  859. CCInvalidateFrame(ci.hwnd);
  860. }
  861. }
  862. //---------------------------------------------------------------------------------------
  863. void CPager::_OnMouseMove(WPARAM wParam, LPARAM lparam)
  864. {
  865. RECT rc;
  866. POINT pt;
  867. int iButton;
  868. pt.x = GET_X_LPARAM(lparam);
  869. pt.y = GET_Y_LPARAM(lparam);
  870. // Ignore zero-mouse moves
  871. if (pt.x == _ptLastMove.x && pt.y == _ptLastMove.y)
  872. return;
  873. _ptLastMove = pt;
  874. iButton = _HitTest(pt.x, pt.y);
  875. if (_iButtonTrack >= 0 )
  876. {
  877. if (_dwState[_iButtonTrack] != PGF_INVISIBLE)
  878. {
  879. //Some Button is pressed right now
  880. ClientToScreen(ci.hwnd, &pt);
  881. rc = _GetButtonRect(_iButtonTrack);
  882. DWORD dwOldState = _dwState[_iButtonTrack];
  883. if (PtInRect(&rc, pt))
  884. {
  885. _dwState[_iButtonTrack] |= PGF_DEPRESSED;
  886. }
  887. else
  888. {
  889. _dwState[_iButtonTrack] &= ~PGF_DEPRESSED;
  890. }
  891. if (dwOldState != _dwState[_iButtonTrack])
  892. _DrawButton(NULL, _iButtonTrack);
  893. }
  894. // if we were tracking it, but the mouse is up and gone
  895. if (GetCapture() == ci.hwnd && !((wParam & MK_LBUTTON) || (ci.style & PGS_AUTOSCROLL)) && iButton != _iButtonTrack)
  896. _OnMouseLeave();
  897. }
  898. else
  899. {
  900. // No button is pressed .
  901. if( iButton >= 0 )
  902. {
  903. //Capture the mouse so that we can keep track of when the mouse is leaving our button
  904. SetCapture(ci.hwnd);
  905. // notify parent that we entered a scroll button
  906. _OnHotItemChange(iButton, TRUE);
  907. // if the style is PGS_AUTOSCROLL then we dont make the button hot when hovering
  908. // over button.
  909. //Is PGS_AUTOSCROLL set
  910. _dwState[iButton] |= PGF_HOT;
  911. if (ci.style & PGS_AUTOSCROLL)
  912. {
  913. _dwState[iButton] |= PGF_DEPRESSED;
  914. }
  915. //If the lbutton is down and the mouse is over one of the button then
  916. // someone is trying to do drag and drop so autoscroll to help them.
  917. // Make sure the lbutton down did not happen in the button before scrolling
  918. if ( ((wParam & MK_LBUTTON) &&
  919. (_iButtonTrack < 0)) ||
  920. (ci.style & PGS_AUTOSCROLL) )
  921. {
  922. _iButtonTrack = iButton;
  923. SetTimer(ci.hwnd, PGT_SCROLL, _cTimeout, NULL);
  924. }
  925. _DrawButton(NULL, iButton);
  926. }
  927. else
  928. {
  929. //Mouse is not over any button or it has left one of the scroll buttons.
  930. //In either case call _OnMouseLeave
  931. _OnMouseLeave();
  932. }
  933. }
  934. }
  935. //---------------------------------------------------------------------------------------
  936. void CPager::_OnSetChild(HWND hwnd, HWND hwndChild)
  937. {
  938. ASSERT(IS_VALID_HANDLE(hwndChild, WND));
  939. RECT rc;
  940. _hwndChild = hwndChild;
  941. _ptPos.x = 0;
  942. _ptPos.y = 0;
  943. _fReCalcSend = FALSE;
  944. if (GetCapture() == ci.hwnd)
  945. {
  946. CCReleaseCapture(&ci);
  947. }
  948. _iButtonTrack = -1;
  949. GetClientRect(hwnd, &rc);
  950. _OnReCalcSize();
  951. }
  952. //---------------------------------------------------------------------------------------
  953. void CPager::_OnReCalcSize()
  954. {
  955. RECT rc;
  956. CCInvalidateFrame(ci.hwnd); // SWP_FRAMECHANGED etc.
  957. _fReCalcSend = FALSE;
  958. rc = _rcChildIdeal;
  959. _SetChildPos(&rc, 0); // SetWindowPos
  960. }
  961. //---------------------------------------------------------------------------------------
  962. void CPager::_OnSetPos(int iPos)
  963. {
  964. RECT rc = _rcChildIdeal;
  965. if( ci.style & PGS_HORZ ) {
  966. FlipRect(&rc);
  967. FlipPoint(&_ptPos);
  968. }
  969. int height;
  970. if (iPos < 0)
  971. iPos = 0;
  972. height = RECTHEIGHT(rc);
  973. if( iPos < 0 || iPos > height || _ptPos.y == iPos ) {
  974. //Invalid Position specified or no change . Igonore it.
  975. return;
  976. }
  977. _ptPos.y = iPos;
  978. if( ci.style & PGS_HORZ ) {
  979. FlipRect(&rc);
  980. FlipPoint(&_ptPos);
  981. }
  982. CCInvalidateFrame(ci.hwnd);
  983. _SetChildPos(&rc , 0);
  984. }
  985. //---------------------------------------------------------------------------------------
  986. int CPager::_OnGetPos()
  987. {
  988. if( ci.style & PGS_HORZ ) {
  989. return _ptPos.x;
  990. }else{
  991. return _ptPos.y;
  992. }
  993. }
  994. //---------------------------------------------------------------------------------------
  995. DWORD CPager::_GetButtonState(int iButton)
  996. {
  997. DWORD dwState = 0;
  998. // Is the button id valid ?
  999. if ((iButton == PGB_TOPORLEFT) || (iButton == PGB_BOTTOMORRIGHT))
  1000. {
  1001. //yes , Get the current state of the button
  1002. dwState = _dwState[iButton];
  1003. }
  1004. return dwState;
  1005. }
  1006. //---------------------------------------------------------------------------------------
  1007. void CPager::_OnTimer(UINT id)
  1008. {
  1009. switch (id)
  1010. {
  1011. case PGT_SCROLL:
  1012. if (_iButtonTrack >= 0)
  1013. {
  1014. // set it again because we do it faster every subsequent time
  1015. SetTimer(ci.hwnd, PGT_SCROLL, _cTimeout, NULL);
  1016. if (_HitTestCursor() == _iButtonTrack)
  1017. {
  1018. _Scroll(_iButtonTrack);
  1019. }
  1020. else if (!_fOwnsButtonDown)
  1021. {
  1022. // if we don't own the mouse tracking (ie, the user didn't button down on us to begin with,
  1023. // then we're done once we leave the button
  1024. _OnMouseLeave();
  1025. }
  1026. }
  1027. break;
  1028. }
  1029. }
  1030. void CPager::_KillTimer()
  1031. {
  1032. KillTimer(ci.hwnd, PGT_SCROLL);
  1033. _fTimerSet = FALSE;
  1034. }
  1035. //---------------------------------------------------------------------------------------
  1036. int CPager::_OnSetBorder(int iBorder)
  1037. {
  1038. int iOld = _iBorder;
  1039. int iNew = iBorder;
  1040. //Border can't be negative
  1041. if (iNew < 0 )
  1042. {
  1043. iNew = 0;
  1044. }
  1045. //Border can't be bigger than the button size
  1046. if (iNew > _GetButtonSize())
  1047. {
  1048. iNew = _GetButtonSize();
  1049. }
  1050. _iBorder = iNew;
  1051. CCInvalidateFrame(ci.hwnd);
  1052. RECT rc = _rcChildIdeal;
  1053. _SetChildPos(&rc, 0); // SetWindowPos
  1054. return iOld;
  1055. }
  1056. //---------------------------------------------------------------------------------------
  1057. int CPager::_OnSetButtonSize(int iSize)
  1058. {
  1059. int iOldSize = _iButtonSize;
  1060. _iButtonSize = iSize;
  1061. if (_iButtonSize < MINBUTTONSIZE)
  1062. {
  1063. _iButtonSize = MINBUTTONSIZE;
  1064. }
  1065. // Border can't be bigger than button size
  1066. if (_iBorder > _iButtonSize)
  1067. {
  1068. _iBorder = _iButtonSize;
  1069. }
  1070. CCInvalidateFrame(ci.hwnd);
  1071. RECT rc = _rcChildIdeal;
  1072. _SetChildPos(&rc, 0); // SetWindowPos
  1073. return iOldSize;
  1074. }
  1075. //---------------------------------------------------------------------------------------
  1076. void CPager::_OnHotItemChange(int iButton, BOOL fEnter)
  1077. {
  1078. NMPGHOTITEM nmhot = {0};
  1079. if (fEnter)
  1080. {
  1081. nmhot.idNew = iButton;
  1082. nmhot.dwFlags = HICF_ENTERING;
  1083. }
  1084. else
  1085. {
  1086. nmhot.idOld = iButton;
  1087. nmhot.dwFlags = HICF_LEAVING;
  1088. }
  1089. CCSendNotify(&ci, PGN_HOTITEMCHANGE, &nmhot.hdr);
  1090. }
  1091. //---------------------------------------------------------------------------------------
  1092. LRESULT CPager::v_WndProc(HWND hwnd, UINT uMsg, WPARAM wParam, LPARAM lParam)
  1093. {
  1094. switch (uMsg) {
  1095. case PGM_GETDROPTARGET:
  1096. if (!_hDragProxy)
  1097. _hDragProxy = CreateDragProxy(ci.hwnd, PagerDragCallback, FALSE);
  1098. GetDragProxyTarget(_hDragProxy, (IDropTarget**)lParam);
  1099. break;
  1100. case PGM_SETSCROLLINFO:
  1101. _cLinesPerTimeout = LOWORD(lParam);
  1102. _cPixelsPerLine = HIWORD(lParam);
  1103. _cTimeout = (UINT)wParam;
  1104. break;
  1105. case PGM_SETCHILD:
  1106. _OnSetChild(hwnd, (HWND)lParam);
  1107. break;
  1108. case PGM_RECALCSIZE:
  1109. if (!_fReCalcSend )
  1110. {
  1111. _fReCalcSend = TRUE;
  1112. PostMessage(hwnd, PGMP_RECALCSIZE, wParam, lParam);
  1113. }
  1114. break;
  1115. case PGMP_RECALCSIZE:
  1116. _OnReCalcSize();
  1117. break;
  1118. case PGM_FORWARDMOUSE:
  1119. // forward mouse messages
  1120. _fForwardMouseMsgs = BOOLIFY(wParam);
  1121. break;
  1122. case PGM_SETBKCOLOR:
  1123. {
  1124. COLORREF clr = _clrBk;
  1125. if ((COLORREF) lParam == CLR_DEFAULT)
  1126. _clrBk = g_clrBtnFace;
  1127. else
  1128. _clrBk = (COLORREF)lParam;
  1129. _fBkColorSet = TRUE;
  1130. CCInvalidateFrame(ci.hwnd);
  1131. //Force a paint
  1132. RedrawWindow(ci.hwnd, NULL,NULL,RDW_INVALIDATE|RDW_ERASE);
  1133. return clr;
  1134. }
  1135. case PGM_GETBKCOLOR:
  1136. return (LRESULT)_clrBk;
  1137. case PGM_SETBORDER:
  1138. return _OnSetBorder((int)lParam);
  1139. case PGM_GETBORDER:
  1140. return (LRESULT)_iBorder;
  1141. case PGM_SETPOS:
  1142. _OnSetPos((int)lParam);
  1143. break;
  1144. case PGM_GETPOS:
  1145. return _OnGetPos();
  1146. case PGM_SETBUTTONSIZE:
  1147. return _OnSetButtonSize((int)lParam);
  1148. case PGM_GETBUTTONSIZE:
  1149. return _GetButtonSize();
  1150. case PGM_GETBUTTONSTATE:
  1151. return _GetButtonState((int)lParam);
  1152. case WM_PRINTCLIENT:
  1153. CCForwardPrint(&ci, (HDC)wParam);
  1154. return 0;
  1155. case WM_PRINT:
  1156. return _OnPrint((HDC)wParam, (UINT)lParam);
  1157. case WM_NCHITTEST:
  1158. {
  1159. POINT pt;
  1160. pt.x = GET_X_LPARAM(lParam);
  1161. pt.y = GET_Y_LPARAM(lParam);
  1162. if (_HitTestScreen(&pt) == -1)
  1163. return HTTRANSPARENT;
  1164. return HTCLIENT;
  1165. }
  1166. case WM_SYSCOLORCHANGE:
  1167. if (!_fBkColorSet)
  1168. {
  1169. InitGlobalColors();
  1170. _clrBk = g_clrBtnFace;
  1171. CCInvalidateFrame(ci.hwnd);
  1172. }
  1173. break;
  1174. case WM_SETFOCUS:
  1175. SetFocus(_hwndChild);
  1176. return 0;
  1177. case WM_LBUTTONDOWN:
  1178. //Fall Through
  1179. case WM_LBUTTONUP:
  1180. if(!(ci.style & PGS_AUTOSCROLL)) {
  1181. _OnLButtonChange(uMsg,lParam);
  1182. }
  1183. break;
  1184. case WM_MOUSEMOVE:
  1185. // Only forward if the point is within the client rect of pager.
  1186. if (_fForwardMouseMsgs && _hwndChild)
  1187. {
  1188. POINT pt;
  1189. RECT rcClient;
  1190. GetClientRect(ci.hwnd, &rcClient);
  1191. pt.x = GET_X_LPARAM(lParam);
  1192. pt.y = GET_Y_LPARAM(lParam);
  1193. // Is this point in our client rect?
  1194. if (PtInRect(&rcClient, pt))
  1195. {
  1196. // Yes; then convert coords and forward it
  1197. pt.x += _ptPos.x;
  1198. pt.y += _ptPos.y;
  1199. SendMessage(_hwndChild, WM_MOUSEMOVE, wParam, MAKELPARAM(pt.x, pt.y));
  1200. }
  1201. }
  1202. _OnMouseMove(wParam,lParam);
  1203. break;
  1204. case WM_MOUSELEAVE :
  1205. _OnMouseLeave();
  1206. break;
  1207. case WM_ERASEBKGND:
  1208. {
  1209. LRESULT lres = CCForwardEraseBackground(ci.hwnd, (HDC) wParam);
  1210. if (_iBorder) {
  1211. // paint the borders
  1212. RECT rc;
  1213. RECT rc2;
  1214. GetClientRect(ci.hwnd, &rc);
  1215. rc2 = rc;
  1216. if( ci.style & PGS_HORZ ) {
  1217. FlipRect(&rc2);
  1218. }
  1219. rc2.right = rc2.left + _iBorder + 1;
  1220. if( ci.style & PGS_HORZ ) {
  1221. FlipRect(&rc2);
  1222. }
  1223. FillRectClr((HDC)wParam, &rc2, _clrBk);
  1224. rc2 = rc;
  1225. if( ci.style & PGS_HORZ ) {
  1226. FlipRect(&rc2);
  1227. }
  1228. rc2.left = rc2.right - _iBorder - 1;
  1229. if( ci.style & PGS_HORZ ) {
  1230. FlipRect(&rc2);
  1231. }
  1232. FillRectClr((HDC)wParam, &rc2, _clrBk);
  1233. }
  1234. return TRUE;
  1235. }
  1236. case WM_TIMER:
  1237. _OnTimer((UINT)wParam);
  1238. return 0;
  1239. case WM_SETTINGCHANGE:
  1240. InitGlobalMetrics(wParam);
  1241. _iButtonSize = (int) g_cxScrollbar * 3 / 4;
  1242. if (_iButtonSize < MINBUTTONSIZE) {
  1243. _iButtonSize = MINBUTTONSIZE;
  1244. }
  1245. break;
  1246. case WM_DESTROY:
  1247. if (_hDragProxy)
  1248. DestroyDragProxy(_hDragProxy);
  1249. break;
  1250. }
  1251. return CControl::v_WndProc(hwnd, uMsg, wParam, lParam);
  1252. }
  1253. //---------------------------------------------------------------------------------------
  1254. // call with cyCh == 0 to specify auto vsizing
  1255. BOOL DrawChar(HDC hdc, LPRECT lprc, UINT wState, TCHAR ch, UINT cyCh, BOOL fAlwaysGrayed, BOOL fTopAlign, COLORREF rgbOveride)
  1256. {
  1257. COLORREF rgb;
  1258. BOOL fDrawDisabled = !fAlwaysGrayed && (wState & DCHF_INACTIVE);
  1259. BOOL fDrawPushed = wState & DCHF_PUSHED;
  1260. // Bad UI to have a pushed disabled button
  1261. ASSERT (!fDrawDisabled || !fDrawPushed);
  1262. RECT rc = *lprc;
  1263. UINT uFormat = DT_CENTER | DT_SINGLELINE;
  1264. if (fAlwaysGrayed)
  1265. rgb = g_clrBtnShadow;
  1266. else if (fDrawDisabled)
  1267. rgb = g_clrBtnHighlight;
  1268. else
  1269. rgb = g_clrBtnText;
  1270. if (rgbOveride != CLR_INVALID)
  1271. {
  1272. rgb = rgbOveride;
  1273. }
  1274. rgb = SetTextColor(hdc, rgb);
  1275. if (cyCh)
  1276. {
  1277. if (fTopAlign)
  1278. rc.bottom = rc.top + cyCh;
  1279. else
  1280. {
  1281. rc.top += ((RECTHEIGHT(rc) - cyCh) / 2);
  1282. rc.bottom = rc.top + cyCh;
  1283. }
  1284. uFormat |= DT_BOTTOM;
  1285. }
  1286. else
  1287. uFormat |= DT_VCENTER;
  1288. if (fDrawDisabled || fDrawPushed)
  1289. OffsetRect(&rc, 1, 1);
  1290. DrawText(hdc, &ch, 1, &rc, uFormat);
  1291. if (fDrawDisabled)
  1292. {
  1293. OffsetRect(&rc, -1, -1);
  1294. SetTextColor(hdc, g_clrBtnShadow);
  1295. DrawText(hdc, &ch, 1, &rc, uFormat);
  1296. }
  1297. SetTextColor(hdc, rgb);
  1298. return(TRUE);
  1299. }
  1300. void DrawBlankButton(HDC hdc, LPRECT lprc, DWORD wControlState)
  1301. {
  1302. BOOL fAdjusted;
  1303. if (wControlState & (DCHF_HOT | DCHF_PUSHED) &&
  1304. !(wControlState & DCHF_NOBORDER)) {
  1305. COLORSCHEME clrsc;
  1306. clrsc.dwSize = 1;
  1307. if (GetBkColor(hdc) == g_clrBtnShadow) {
  1308. clrsc.clrBtnHighlight = g_clrBtnHighlight;
  1309. clrsc.clrBtnShadow = g_clrBtnText;
  1310. } else
  1311. clrsc.clrBtnHighlight = clrsc.clrBtnShadow = CLR_DEFAULT;
  1312. // if button is both DCHF_HOT and DCHF_PUSHED, DCHF_HOT wins here
  1313. CCDrawEdge(hdc, lprc, (wControlState & DCHF_HOT) ? BDR_RAISEDINNER : BDR_SUNKENOUTER,
  1314. (UINT) (BF_ADJUST | BF_RECT), &clrsc);
  1315. fAdjusted = TRUE;
  1316. } else {
  1317. fAdjusted = FALSE;
  1318. }
  1319. if (!(wControlState & DCHF_TRANSPARENT))
  1320. FillRectClr(hdc, lprc, GetBkColor(hdc));
  1321. if (!fAdjusted)
  1322. InflateRect(lprc, -g_cxBorder, -g_cyBorder);
  1323. }
  1324. //---------------------------------------------------------------------------------------
  1325. void DrawCharButton(HDC hdc, LPRECT lprc, UINT wControlState, TCHAR ch, UINT cyCh, BOOL fAlwaysGrayed, BOOL fTopAlign, COLORREF rgbOveride)
  1326. {
  1327. RECT rc;
  1328. CopyRect(&rc, lprc);
  1329. DrawBlankButton(hdc, &rc, wControlState);
  1330. if ((RECTWIDTH(rc) <= 0) || (RECTHEIGHT(rc) <= 0))
  1331. return;
  1332. int iOldBk = SetBkMode(hdc, TRANSPARENT);
  1333. DrawChar(hdc, &rc, wControlState, ch, cyCh, fAlwaysGrayed, fTopAlign, rgbOveride);
  1334. SetBkMode(hdc, iOldBk);
  1335. }
  1336. // --------------------------------------------------------------------------------------
  1337. //
  1338. // DrawScrollArrow
  1339. //
  1340. // --------------------------------------------------------------------------------------
  1341. void DrawScrollArrow(HDC hdc, LPRECT lprc, UINT wControlState, COLORREF rgbOveride)
  1342. {
  1343. #define szfnMarlett TEXT("MARLETT")
  1344. TCHAR ch = (wControlState & DCHF_HORIZONTAL) ? TEXT('3') : TEXT('5');
  1345. //
  1346. // Flip the direction arrow in case of a RTL mirrored DC,
  1347. // since it won't be flipped automatically (textout!)
  1348. //
  1349. if (IS_DC_RTL_MIRRORED(hdc) && (wControlState & DCHF_HORIZONTAL))
  1350. wControlState ^= DCHF_FLIPPED;
  1351. LONG lMin = min(RECTWIDTH(*lprc), RECTHEIGHT(*lprc)) - (2 * g_cxBorder); // g_cxBorder fudge notches font size down
  1352. HFONT hFont = CreateFont(lMin, 0, 0, 0, FW_NORMAL, 0, 0, 0, SYMBOL_CHARSET, 0, 0, 0, 0, szfnMarlett);
  1353. HFONT hOldFont = (HFONT)SelectObject(hdc, hFont);
  1354. if (wControlState & DCHF_FLIPPED)
  1355. ch++;
  1356. DrawCharButton(hdc, lprc, wControlState, ch, 0, FALSE, FALSE, rgbOveride);
  1357. SelectObject(hdc, hOldFont);
  1358. DeleteObject(hFont);
  1359. }
  1360. //---------------------------------------------------------------------------------------
  1361. #define CX_INCREMENT 1
  1362. #define CX_DECREMENT (-CX_INCREMENT)
  1363. #define MIDPOINT(x1, x2) ((x1 + x2) / 2)
  1364. #define CHEVRON_WIDTH(dSeg) (4 * dSeg)
  1365. // DrawChevron is theme-aware
  1366. void DrawChevron(HTHEME hTheme, int iPartId, HDC hdc, LPRECT lprc, DWORD dwFlags)
  1367. {
  1368. RECT rc;
  1369. CopyRect(&rc, lprc);
  1370. if (hTheme)
  1371. {
  1372. // Get state id from dwFlags
  1373. int iStateId = CHEVS_NORMAL;
  1374. if (dwFlags & DCHF_HOT)
  1375. iStateId = CHEVS_HOT;
  1376. if (dwFlags & DCHF_PUSHED)
  1377. iStateId = CHEVS_PRESSED;
  1378. DrawThemeBackground(hTheme, hdc, iPartId, iStateId, &rc, 0);
  1379. }
  1380. else
  1381. {
  1382. // draw the border and background
  1383. DrawBlankButton(hdc, &rc, dwFlags);
  1384. // offset the arrow if pushed
  1385. if (dwFlags & DCHF_PUSHED)
  1386. OffsetRect(&rc, CX_INCREMENT, CX_INCREMENT);
  1387. // draw the arrow
  1388. HBRUSH hbrSave = SelectBrush(hdc, GetSysColorBrush(COLOR_BTNTEXT));
  1389. int dSeg = (g_cxVScroll / 7);
  1390. dSeg = max(2, dSeg);
  1391. if (dwFlags & DCHF_HORIZONTAL)
  1392. {
  1393. // horizontal arrow
  1394. int x = MIDPOINT(rc.left, rc.right - CHEVRON_WIDTH(dSeg));
  1395. int yBase;
  1396. if (dwFlags & DCHF_TOPALIGN)
  1397. yBase = rc.top + (3 * dSeg);
  1398. else
  1399. yBase = MIDPOINT(rc.top, rc.bottom);
  1400. for (int y = -dSeg; y <= dSeg; y++)
  1401. {
  1402. PatBlt(hdc, x, yBase + y, dSeg, CX_INCREMENT, PATCOPY);
  1403. PatBlt(hdc, x + (dSeg * 2), yBase + y, dSeg, CX_INCREMENT, PATCOPY);
  1404. x += (y < 0) ? CX_INCREMENT : CX_DECREMENT;
  1405. }
  1406. }
  1407. else
  1408. {
  1409. // vertical arrow
  1410. int y = rc.top + CX_INCREMENT;
  1411. int xBase = MIDPOINT(rc.left, rc.right);
  1412. for (int x = -dSeg; x <= dSeg; x++)
  1413. {
  1414. PatBlt(hdc, xBase + x, y, CX_INCREMENT, dSeg, PATCOPY);
  1415. PatBlt(hdc, xBase + x, y + (dSeg * 2), CX_INCREMENT, dSeg, PATCOPY);
  1416. y += (x < 0) ? CX_INCREMENT : CX_DECREMENT;
  1417. }
  1418. }
  1419. // clean up
  1420. SelectBrush(hdc, hbrSave);
  1421. }
  1422. }