pager.cpp
Upload User: xhy777
Upload Date: 2007-02-14
Package Size: 24088k
Code Size: 48k
Category:

Windows Kernel

Development Platform:

Visual C++

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