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.

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