home *** CD-ROM | disk | FTP | other *** search
/ Supercompiler 1997 / SUPERCOMPILER97.iso / MS_VC.50 / VC / MFC / SRC / VIEWSCRL.CPP < prev    next >
Encoding:
C/C++ Source or Header  |  1996-12-12  |  27.2 KB  |  1,074 lines

  1. // This is a part of the Microsoft Foundation Classes C++ library.
  2. // Copyright (C) 1992-1997 Microsoft Corporation
  3. // All rights reserved.
  4. //
  5. // This source code is only intended as a supplement to the
  6. // Microsoft Foundation Classes Reference and related
  7. // electronic documentation provided with the library.
  8. // See these sources for detailed information regarding the
  9. // Microsoft Foundation Classes product.
  10.  
  11. #include "stdafx.h"
  12.  
  13. #ifdef AFX_CORE2_SEG
  14. #pragma code_seg(AFX_CORE2_SEG)
  15. #endif
  16.  
  17. #ifdef _DEBUG
  18. #undef THIS_FILE
  19. static char THIS_FILE[] = __FILE__;
  20. #endif
  21.  
  22. /////////////////////////////////////////////////////////////////////////////
  23. // CScrollView
  24.  
  25. BEGIN_MESSAGE_MAP(CScrollView, CView)
  26.     //{{AFX_MSG_MAP(CScrollView)
  27.     ON_WM_SIZE()
  28.     ON_WM_HSCROLL()
  29.     ON_WM_VSCROLL()
  30.     ON_WM_MOUSEWHEEL()
  31.     //}}AFX_MSG_MAP
  32. END_MESSAGE_MAP()
  33.  
  34. // Special mapping modes just for CScrollView implementation
  35. #define MM_NONE             0
  36. #define MM_SCALETOFIT       (-1)
  37.     // standard GDI mapping modes are > 0
  38.  
  39. #ifndef _MAC
  40. UINT _AfxGetMouseScrollLines(BOOL bForceFresh = FALSE);
  41.  
  42. UINT _AfxGetMouseScrollLines(BOOL bForceFresh /* = FALSE */)
  43. {
  44.     // if we've already got it and we're not refreshing,
  45.     // return what we've already got
  46.  
  47.     static BOOL bGotScrollLines = FALSE;
  48.     static UINT uCachedScrollLines = 0;
  49.  
  50.     if (!bForceFresh && bGotScrollLines)
  51.         return uCachedScrollLines;
  52.  
  53.     // see if we can find the mouse window
  54.  
  55.     bGotScrollLines = TRUE;
  56.  
  57.     static UINT msgGetScrollLines = 0;
  58.     static WORD nRegisteredMessage = 0;
  59.  
  60.     if (nRegisteredMessage == 0)
  61.     {
  62.         msgGetScrollLines = ::RegisterWindowMessage(MSH_SCROLL_LINES);
  63.         if (msgGetScrollLines == 0)
  64.             nRegisteredMessage = 1;     // couldn't register!  never try again
  65.         else
  66.             nRegisteredMessage = 2;     // it worked: use it
  67.     }
  68.  
  69.     if (nRegisteredMessage == 2)
  70.     {
  71.         HWND hwMouseWheel = NULL;
  72.         hwMouseWheel = FindWindow(MSH_WHEELMODULE_CLASS, MSH_WHEELMODULE_TITLE);
  73.         if (hwMouseWheel && msgGetScrollLines)
  74.         {
  75.             uCachedScrollLines = (UINT)
  76.                 ::SendMessage(hwMouseWheel, msgGetScrollLines, 0, 0);
  77.             return uCachedScrollLines;
  78.         }
  79.     }
  80.  
  81.     // couldn't use the window -- try system settings
  82.  
  83.     OSVERSIONINFO ver;
  84.     memset(&ver, 0, sizeof(ver));
  85.     ver.dwOSVersionInfoSize = sizeof(ver);
  86.  
  87.     uCachedScrollLines = 3; // reasonable default
  88.     if (!::GetVersionEx(&ver))
  89.         return uCachedScrollLines;
  90.  
  91.     if ((ver.dwPlatformId == VER_PLATFORM_WIN32_WINDOWS ||
  92.           ver.dwPlatformId == VER_PLATFORM_WIN32_NT)
  93.         && ver.dwMajorVersion < 4)
  94.     {
  95.         HKEY hKey;
  96.         if (RegOpenKeyEx(HKEY_CURRENT_USER,  _T("Control Panel\\Desktop"),
  97.                 0, KEY_QUERY_VALUE, &hKey) == ERROR_SUCCESS)
  98.         {
  99.             TCHAR szData[128];
  100.             DWORD dwKeyDataType;
  101.             DWORD dwDataBufSize = _countof(szData);
  102.  
  103.             if (RegQueryValueEx(hKey, _T("WheelScrollLines"), NULL, &dwKeyDataType,
  104.                     (LPBYTE) &szData, &dwDataBufSize) == ERROR_SUCCESS)
  105.             {
  106.                 uCachedScrollLines = _tcstoul(szData, NULL, 10);
  107.             }
  108.             RegCloseKey(hKey);
  109.         }
  110.     }
  111.     else if (ver.dwPlatformId == VER_PLATFORM_WIN32_NT && ver.dwMajorVersion >= 4)
  112.     {
  113.         ::SystemParametersInfo(SPI_GETWHEELSCROLLLINES, 0, &uCachedScrollLines, 0);
  114.     }
  115.  
  116.     return uCachedScrollLines;
  117. }
  118. #endif
  119.  
  120. /////////////////////////////////////////////////////////////////////////////
  121. // CScrollView construction/destruction
  122.  
  123. CScrollView::CScrollView()
  124. {
  125.     // Init everything to zero
  126.     AFX_ZERO_INIT_OBJECT(CView);
  127.  
  128.     m_nMapMode = MM_NONE;
  129. }
  130.  
  131. CScrollView::~CScrollView()
  132. {
  133. }
  134.  
  135. /////////////////////////////////////////////////////////////////////////////
  136. // CScrollView painting
  137.  
  138. void CScrollView::OnPrepareDC(CDC* pDC, CPrintInfo* pInfo)
  139. {
  140.     ASSERT_VALID(pDC);
  141.  
  142. #ifdef _DEBUG
  143.     if (m_nMapMode == MM_NONE)
  144.     {
  145.         TRACE0("Error: must call SetScrollSizes() or SetScaleToFitSize()");
  146.         TRACE0("\tbefore painting scroll view.\n");
  147.         ASSERT(FALSE);
  148.         return;
  149.     }
  150. #endif //_DEBUG
  151.     ASSERT(m_totalDev.cx >= 0 && m_totalDev.cy >= 0);
  152.     switch (m_nMapMode)
  153.     {
  154.     case MM_SCALETOFIT:
  155.         pDC->SetMapMode(MM_ANISOTROPIC);
  156.         pDC->SetWindowExt(m_totalLog);  // window is in logical coordinates
  157.         pDC->SetViewportExt(m_totalDev);
  158.         if (m_totalDev.cx == 0 || m_totalDev.cy == 0)
  159.             TRACE0("Warning: CScrollView scaled to nothing.\n");
  160.         break;
  161.  
  162.     default:
  163.         ASSERT(m_nMapMode > 0);
  164.         pDC->SetMapMode(m_nMapMode);
  165.         break;
  166.     }
  167.  
  168.     CPoint ptVpOrg(0, 0);       // assume no shift for printing
  169.     if (!pDC->IsPrinting())
  170.     {
  171.         ASSERT(pDC->GetWindowOrg() == CPoint(0,0));
  172.  
  173.         // by default shift viewport origin in negative direction of scroll
  174.         ptVpOrg = -GetDeviceScrollPosition();
  175.  
  176.         if (m_bCenter)
  177.         {
  178.             CRect rect;
  179.             GetClientRect(&rect);
  180.  
  181.             // if client area is larger than total device size,
  182.             // override scroll positions to place origin such that
  183.             // output is centered in the window
  184.             if (m_totalDev.cx < rect.Width())
  185.                 ptVpOrg.x = (rect.Width() - m_totalDev.cx) / 2;
  186.             if (m_totalDev.cy < rect.Height())
  187.                 ptVpOrg.y = (rect.Height() - m_totalDev.cy) / 2;
  188.         }
  189.     }
  190.     pDC->SetViewportOrg(ptVpOrg);
  191.  
  192.     CView::OnPrepareDC(pDC, pInfo);     // For default Printing behavior
  193. }
  194.  
  195. /////////////////////////////////////////////////////////////////////////////
  196. // Set mode and scaling/scrolling sizes
  197.  
  198. void CScrollView::SetScaleToFitSize(SIZE sizeTotal)
  199. {
  200.     // Note: It is possible to set sizeTotal members to negative values to
  201.     //  effectively invert either the X or Y axis.
  202.  
  203.     ASSERT(m_hWnd != NULL);
  204.     m_nMapMode = MM_SCALETOFIT;     // special internal value
  205.     m_totalLog = sizeTotal;
  206.  
  207.     // reset and turn any scroll bars off
  208.     if (m_hWnd != NULL && (GetStyle() & (WS_HSCROLL|WS_VSCROLL)))
  209.     {
  210.         SetScrollPos(SB_HORZ, 0);
  211.         SetScrollPos(SB_VERT, 0);
  212.         EnableScrollBarCtrl(SB_BOTH, FALSE);
  213.         ASSERT((GetStyle() & (WS_HSCROLL|WS_VSCROLL)) == 0);
  214.     }
  215.  
  216.     CRect rectT;
  217.     GetClientRect(rectT);
  218.     m_totalDev = rectT.Size();
  219.  
  220.     if (m_hWnd != NULL)
  221.     {
  222.         // window has been created, invalidate
  223.         UpdateBars();
  224.         Invalidate(TRUE);
  225.     }
  226. }
  227.  
  228. const AFX_DATADEF SIZE CScrollView::sizeDefault = {0,0};
  229.  
  230. void CScrollView::SetScrollSizes(int nMapMode, SIZE sizeTotal,
  231.     const SIZE& sizePage, const SIZE& sizeLine)
  232. {
  233.     ASSERT(sizeTotal.cx >= 0 && sizeTotal.cy >= 0);
  234.     ASSERT(nMapMode > 0);
  235.     ASSERT(nMapMode != MM_ISOTROPIC && nMapMode != MM_ANISOTROPIC);
  236.  
  237.     int nOldMapMode = m_nMapMode;
  238.     m_nMapMode = nMapMode;
  239.     m_totalLog = sizeTotal;
  240.  
  241.     //BLOCK: convert logical coordinate space to device coordinates
  242.     {
  243.         CWindowDC dc(NULL);
  244.         ASSERT(m_nMapMode > 0);
  245.         dc.SetMapMode(m_nMapMode);
  246.  
  247.         // total size
  248.         m_totalDev = m_totalLog;
  249.         dc.LPtoDP((LPPOINT)&m_totalDev);
  250.         m_pageDev = sizePage;
  251.         dc.LPtoDP((LPPOINT)&m_pageDev);
  252.         m_lineDev = sizeLine;
  253.         dc.LPtoDP((LPPOINT)&m_lineDev);
  254.         if (m_totalDev.cy < 0)
  255.             m_totalDev.cy = -m_totalDev.cy;
  256.         if (m_pageDev.cy < 0)
  257.             m_pageDev.cy = -m_pageDev.cy;
  258.         if (m_lineDev.cy < 0)
  259.             m_lineDev.cy = -m_lineDev.cy;
  260.     } // release DC here
  261.  
  262.     // now adjust device specific sizes
  263.     ASSERT(m_totalDev.cx >= 0 && m_totalDev.cy >= 0);
  264.     if (m_pageDev.cx == 0)
  265.         m_pageDev.cx = m_totalDev.cx / 10;
  266.     if (m_pageDev.cy == 0)
  267.         m_pageDev.cy = m_totalDev.cy / 10;
  268.     if (m_lineDev.cx == 0)
  269.         m_lineDev.cx = m_pageDev.cx / 10;
  270.     if (m_lineDev.cy == 0)
  271.         m_lineDev.cy = m_pageDev.cy / 10;
  272.  
  273.     if (m_hWnd != NULL)
  274.     {
  275.         // window has been created, invalidate now
  276.         UpdateBars();
  277.         if (nOldMapMode != m_nMapMode)
  278.             Invalidate(TRUE);
  279.     }
  280. }
  281.  
  282. /////////////////////////////////////////////////////////////////////////////
  283. // Getting information
  284.  
  285. CPoint CScrollView::GetScrollPosition() const   // logical coordinates
  286. {
  287.     if (m_nMapMode == MM_SCALETOFIT)
  288.     {
  289.         return CPoint(0, 0);    // must be 0,0
  290.     }
  291.  
  292.     CPoint pt = GetDeviceScrollPosition();
  293.     // pt may be negative if m_bCenter is set
  294.  
  295.     if (m_nMapMode != MM_TEXT)
  296.     {
  297.         ASSERT(m_nMapMode > 0); // must be set
  298.         CWindowDC dc(NULL);
  299.         dc.SetMapMode(m_nMapMode);
  300.         dc.DPtoLP((LPPOINT)&pt);
  301.     }
  302.     return pt;
  303. }
  304.  
  305. void CScrollView::ScrollToPosition(POINT pt)    // logical coordinates
  306. {
  307.     ASSERT(m_nMapMode > 0);     // not allowed for shrink to fit
  308.     if (m_nMapMode != MM_TEXT)
  309.     {
  310.         CWindowDC dc(NULL);
  311.         dc.SetMapMode(m_nMapMode);
  312.         dc.LPtoDP((LPPOINT)&pt);
  313.     }
  314.  
  315.     // now in device coordinates - limit if out of range
  316.     int xMax = GetScrollLimit(SB_HORZ);
  317.     int yMax = GetScrollLimit(SB_VERT);
  318.     if (pt.x < 0)
  319.         pt.x = 0;
  320.     else if (pt.x > xMax)
  321.         pt.x = xMax;
  322.     if (pt.y < 0)
  323.         pt.y = 0;
  324.     else if (pt.y > yMax)
  325.         pt.y = yMax;
  326.  
  327.     ScrollToDevicePosition(pt);
  328. }
  329.  
  330. CPoint CScrollView::GetDeviceScrollPosition() const
  331. {
  332.     CPoint pt(GetScrollPos(SB_HORZ), GetScrollPos(SB_VERT));
  333.     ASSERT(pt.x >= 0 && pt.y >= 0);
  334.  
  335.     if (m_bCenter)
  336.     {
  337.         CRect rect;
  338.         GetClientRect(&rect);
  339.  
  340.         // if client area is larger than total device size,
  341.         // the scroll positions are overridden to place origin such that
  342.         // output is centered in the window
  343.         // GetDeviceScrollPosition() must reflect this
  344.  
  345.         if (m_totalDev.cx < rect.Width())
  346.             pt.x = -((rect.Width() - m_totalDev.cx) / 2);
  347.         if (m_totalDev.cy < rect.Height())
  348.             pt.y = -((rect.Height() - m_totalDev.cy) / 2);
  349.     }
  350.  
  351.     return pt;
  352. }
  353.  
  354. void CScrollView::GetDeviceScrollSizes(int& nMapMode, SIZE& sizeTotal,
  355.             SIZE& sizePage, SIZE& sizeLine) const
  356. {
  357.     if (m_nMapMode <= 0)
  358.         TRACE0("Warning: CScrollView::GetDeviceScrollSizes returning invalid mapping mode.\n");
  359.     nMapMode = m_nMapMode;
  360.     sizeTotal = m_totalDev;
  361.     sizePage = m_pageDev;
  362.     sizeLine = m_lineDev;
  363. }
  364.  
  365. void CScrollView::ScrollToDevicePosition(POINT ptDev)
  366. {
  367.     ASSERT(ptDev.x >= 0);
  368.     ASSERT(ptDev.y >= 0);
  369.  
  370.     // Note: ScrollToDevicePosition can and is used to scroll out-of-range
  371.     //  areas as far as CScrollView is concerned -- specifically in
  372.     //  the print-preview code.  Since OnScrollBy makes sure the range is
  373.     //  valid, ScrollToDevicePosition does not vector through OnScrollBy.
  374.  
  375.     int xOrig = GetScrollPos(SB_HORZ);
  376.     SetScrollPos(SB_HORZ, ptDev.x);
  377.     int yOrig = GetScrollPos(SB_VERT);
  378.     SetScrollPos(SB_VERT, ptDev.y);
  379.     ScrollWindow(xOrig - ptDev.x, yOrig - ptDev.y);
  380. }
  381.  
  382. /////////////////////////////////////////////////////////////////////////////
  383. // Other helpers
  384.  
  385. void CScrollView::FillOutsideRect(CDC* pDC, CBrush* pBrush)
  386. {
  387.     ASSERT_VALID(pDC);
  388.     ASSERT_VALID(pBrush);
  389.  
  390.     // fill rect outside the image
  391.     CRect rect;
  392.     GetClientRect(rect);
  393.     ASSERT(rect.left == 0 && rect.top == 0);
  394.     rect.left = m_totalDev.cx;
  395.     if (!rect.IsRectEmpty())
  396.         pDC->FillRect(rect, pBrush);    // vertical strip along the side
  397.     rect.left = 0;
  398.     rect.right = m_totalDev.cx;
  399.     rect.top = m_totalDev.cy;
  400.     if (!rect.IsRectEmpty())
  401.         pDC->FillRect(rect, pBrush);    // horizontal strip along the bottom
  402. }
  403.  
  404. void CScrollView::ResizeParentToFit(BOOL bShrinkOnly)
  405. {
  406.     // adjust parent rect so client rect is appropriate size
  407.     ASSERT(m_nMapMode != MM_NONE);  // mapping mode must be known
  408.  
  409.     // determine current size of the client area as if no scrollbars present
  410.     CRect rectClient;
  411.     GetWindowRect(rectClient);
  412.     CRect rect = rectClient;
  413.     CalcWindowRect(rect);
  414.     rectClient.left += rectClient.left - rect.left;
  415.     rectClient.top += rectClient.top - rect.top;
  416.     rectClient.right -= rect.right - rectClient.right;
  417.     rectClient.bottom -= rect.bottom - rectClient.bottom;
  418.     rectClient.OffsetRect(-rectClient.left, -rectClient.top);
  419.     ASSERT(rectClient.left == 0 && rectClient.top == 0);
  420.  
  421.     // determine desired size of the view
  422.     CRect rectView(0, 0, m_totalDev.cx, m_totalDev.cy);
  423.     if (bShrinkOnly)
  424.     {
  425.         if (rectClient.right <= m_totalDev.cx)
  426.             rectView.right = rectClient.right;
  427.         if (rectClient.bottom <= m_totalDev.cy)
  428.             rectView.bottom = rectClient.bottom;
  429.     }
  430.     CalcWindowRect(rectView, CWnd::adjustOutside);
  431.     rectView.OffsetRect(-rectView.left, -rectView.top);
  432.     ASSERT(rectView.left == 0 && rectView.top == 0);
  433.     if (bShrinkOnly)
  434.     {
  435.         if (rectClient.right <= m_totalDev.cx)
  436.             rectView.right = rectClient.right;
  437.         if (rectClient.bottom <= m_totalDev.cy)
  438.             rectView.bottom = rectClient.bottom;
  439.     }
  440.  
  441.     // dermine and set size of frame based on desired size of view
  442.     CRect rectFrame;
  443.     CFrameWnd* pFrame = GetParentFrame();
  444.     ASSERT_VALID(pFrame);
  445.     pFrame->GetWindowRect(rectFrame);
  446.     CSize size = rectFrame.Size();
  447.     size.cx += rectView.right - rectClient.right;
  448.     size.cy += rectView.bottom - rectClient.bottom;
  449.     pFrame->SetWindowPos(NULL, 0, 0, size.cx, size.cy,
  450.         SWP_NOMOVE|SWP_NOZORDER|SWP_NOACTIVATE);
  451. }
  452.  
  453. /////////////////////////////////////////////////////////////////////////////
  454.  
  455. void CScrollView::OnSize(UINT nType, int cx, int cy)
  456. {
  457.     CView::OnSize(nType, cx, cy);
  458.     if (m_nMapMode == MM_SCALETOFIT)
  459.     {
  460.         // force recalculation of scale to fit parameters
  461.         SetScaleToFitSize(m_totalLog);
  462.     }
  463.     else
  464.     {
  465.         // UpdateBars() handles locking out recursion
  466.         UpdateBars();
  467.     }
  468. }
  469.  
  470. /////////////////////////////////////////////////////////////////////////////
  471. // Scrolling Helpers
  472.  
  473. void CScrollView::CenterOnPoint(CPoint ptCenter) // center in device coords
  474. {
  475.     CRect rect;
  476.     GetClientRect(&rect);           // find size of client window
  477.  
  478.     int xDesired = ptCenter.x - rect.Width() / 2;
  479.     int yDesired = ptCenter.y - rect.Height() / 2;
  480.  
  481.     DWORD dwStyle = GetStyle();
  482.  
  483.     if ((dwStyle & WS_HSCROLL) == 0 || xDesired < 0)
  484.     {
  485.         xDesired = 0;
  486.     }
  487.     else
  488.     {
  489.         int xMax = GetScrollLimit(SB_HORZ);
  490.         if (xDesired > xMax)
  491.             xDesired = xMax;
  492.     }
  493.  
  494.     if ((dwStyle & WS_VSCROLL) == 0 || yDesired < 0)
  495.     {
  496.         yDesired = 0;
  497.     }
  498.     else
  499.     {
  500.         int yMax = GetScrollLimit(SB_VERT);
  501.         if (yDesired > yMax)
  502.             yDesired = yMax;
  503.     }
  504.  
  505.     ASSERT(xDesired >= 0);
  506.     ASSERT(yDesired >= 0);
  507.  
  508.     int xOrig = GetScrollPos(SB_HORZ);
  509.     SetScrollPos(SB_HORZ, xDesired);
  510.     int yOrig = GetScrollPos(SB_VERT);
  511.     SetScrollPos(SB_VERT, yDesired);
  512. }
  513.  
  514. /////////////////////////////////////////////////////////////////////////////
  515. // Tie to scrollbars and CWnd behaviour
  516.  
  517. void CScrollView::GetScrollBarSizes(CSize& sizeSb)
  518. {
  519.     sizeSb.cx = sizeSb.cy = 0;
  520.     DWORD dwStyle = GetStyle();
  521.  
  522.     if (GetScrollBarCtrl(SB_VERT) == NULL)
  523.     {
  524.         // vert scrollbars will impact client area of this window
  525.         sizeSb.cx = afxData.cxVScroll;
  526.         if (dwStyle & WS_BORDER)
  527.             sizeSb.cx -= CX_BORDER;
  528.     }
  529.     if (GetScrollBarCtrl(SB_HORZ) == NULL)
  530.     {
  531.         // horz scrollbars will impact client area of this window
  532.         sizeSb.cy = afxData.cyHScroll;
  533.         if (dwStyle & WS_BORDER)
  534.             sizeSb.cy -= CY_BORDER;
  535.     }
  536. }
  537.  
  538. BOOL CScrollView::GetTrueClientSize(CSize& size, CSize& sizeSb)
  539.     // return TRUE if enough room to add scrollbars if needed
  540. {
  541.     CRect rect;
  542.     GetClientRect(&rect);
  543.     ASSERT(rect.top == 0 && rect.left == 0);
  544.     size.cx = rect.right;
  545.     size.cy = rect.bottom;
  546.     DWORD dwStyle = GetStyle();
  547.  
  548.     // first get the size of the scrollbars for this window
  549.     GetScrollBarSizes(sizeSb);
  550.  
  551.     // first calculate the size of a potential scrollbar
  552.     // (scroll bar controls do not get turned on/off)
  553.     if (sizeSb.cx != 0 && (dwStyle & WS_VSCROLL))
  554.     {
  555.         // vert scrollbars will impact client area of this window
  556.         size.cx += sizeSb.cx;   // currently on - adjust now
  557.     }
  558.     if (sizeSb.cy != 0 && (dwStyle & WS_HSCROLL))
  559.     {
  560.         // horz scrollbars will impact client area of this window
  561.         size.cy += sizeSb.cy;   // currently on - adjust now
  562.     }
  563.  
  564.     // return TRUE if enough room
  565.     return (size.cx > sizeSb.cx && size.cy > sizeSb.cy);
  566. }
  567.  
  568. // helper to return the state of the scrollbars without actually changing
  569. //  the state of the scrollbars
  570. void CScrollView::GetScrollBarState(CSize sizeClient, CSize& needSb,
  571.     CSize& sizeRange, CPoint& ptMove, BOOL bInsideClient)
  572. {
  573.     // get scroll bar sizes (the part that is in the client area)
  574.     CSize sizeSb;
  575.     GetScrollBarSizes(sizeSb);
  576.  
  577.     // enough room to add scrollbars
  578.     sizeRange = m_totalDev - sizeClient;
  579.         // > 0 => need to scroll
  580.     ptMove = GetDeviceScrollPosition();
  581.         // point to move to (start at current scroll pos)
  582.  
  583.     BOOL bNeedH = sizeRange.cx > 0;
  584.     if (!bNeedH)
  585.         ptMove.x = 0;                       // jump back to origin
  586.     else if (bInsideClient)
  587.         sizeRange.cy += sizeSb.cy;          // need room for a scroll bar
  588.  
  589.     BOOL bNeedV = sizeRange.cy > 0;
  590.     if (!bNeedV)
  591.         ptMove.y = 0;                       // jump back to origin
  592.     else if (bInsideClient)
  593.         sizeRange.cx += sizeSb.cx;          // need room for a scroll bar
  594.  
  595.     if (bNeedV && !bNeedH && sizeRange.cx > 0)
  596.     {
  597.         ASSERT(bInsideClient);
  598.         // need a horizontal scrollbar after all
  599.         bNeedH = TRUE;
  600.         sizeRange.cy += sizeSb.cy;
  601.     }
  602.  
  603.     // if current scroll position will be past the limit, scroll to limit
  604.     if (sizeRange.cx > 0 && ptMove.x >= sizeRange.cx)
  605.         ptMove.x = sizeRange.cx;
  606.     if (sizeRange.cy > 0 && ptMove.y >= sizeRange.cy)
  607.         ptMove.y = sizeRange.cy;
  608.  
  609.     // now update the bars as appropriate
  610.     needSb.cx = bNeedH;
  611.     needSb.cy = bNeedV;
  612.  
  613.     // needSb, sizeRange, and ptMove area now all updated
  614. }
  615.  
  616. void CScrollView::UpdateBars()
  617. {
  618.     // UpdateBars may cause window to be resized - ignore those resizings
  619.     if (m_bInsideUpdate)
  620.         return;         // Do not allow recursive calls
  621.  
  622.     // Lock out recursion
  623.     m_bInsideUpdate = TRUE;
  624.  
  625.     // update the horizontal to reflect reality
  626.     // NOTE: turning on/off the scrollbars will cause 'OnSize' callbacks
  627.     ASSERT(m_totalDev.cx >= 0 && m_totalDev.cy >= 0);
  628.  
  629.     CRect rectClient;
  630.     BOOL bCalcClient = TRUE;
  631.  
  632.     // allow parent to do inside-out layout first
  633.     CWnd* pParentWnd = GetParent();
  634.     if (pParentWnd != NULL)
  635.     {
  636.         // if parent window responds to this message, use just
  637.         //  client area for scroll bar calc -- not "true" client area
  638.         if ((BOOL)pParentWnd->SendMessage(WM_RECALCPARENT, 0,
  639.             (LPARAM)(LPCRECT)&rectClient) != 0)
  640.         {
  641.             // use rectClient instead of GetTrueClientSize for
  642.             //  client size calculation.
  643.             bCalcClient = FALSE;
  644.         }
  645.     }
  646.  
  647.     CSize sizeClient;
  648.     CSize sizeSb;
  649.  
  650.     if (bCalcClient)
  651.     {
  652.         // get client rect
  653.         if (!GetTrueClientSize(sizeClient, sizeSb))
  654.         {
  655.             // no room for scroll bars (common for zero sized elements)
  656.             CRect rect;
  657.             GetClientRect(&rect);
  658.             if (rect.right > 0 && rect.bottom > 0)
  659.             {
  660.                 // if entire client area is not invisible, assume we have
  661.                 //  control over our scrollbars
  662.                 EnableScrollBarCtrl(SB_BOTH, FALSE);
  663.             }
  664.             m_bInsideUpdate = FALSE;
  665.             return;
  666.         }
  667.     }
  668.     else
  669.     {
  670.         // let parent window determine the "client" rect
  671.         GetScrollBarSizes(sizeSb);
  672.         sizeClient.cx = rectClient.right - rectClient.left;
  673.         sizeClient.cy = rectClient.bottom - rectClient.top;
  674.     }
  675.  
  676.     // enough room to add scrollbars
  677.     CSize sizeRange;
  678.     CPoint ptMove;
  679.     CSize needSb;
  680.  
  681.     // get the current scroll bar state given the true client area
  682.     GetScrollBarState(sizeClient, needSb, sizeRange, ptMove, bCalcClient);
  683.     if (needSb.cx)
  684.         sizeClient.cy -= sizeSb.cy;
  685.     if (needSb.cy)
  686.         sizeClient.cx -= sizeSb.cx;
  687.  
  688.     // first scroll the window as needed
  689.     ScrollToDevicePosition(ptMove); // will set the scroll bar positions too
  690.  
  691.     // this structure needed to update the scrollbar page range
  692.     SCROLLINFO info;
  693.     info.fMask = SIF_PAGE|SIF_RANGE;
  694.     info.nMin = 0;
  695.  
  696.     // now update the bars as appropriate
  697.     EnableScrollBarCtrl(SB_HORZ, needSb.cx);
  698.     if (needSb.cx)
  699.     {
  700.         info.nPage = sizeClient.cx;
  701.         info.nMax = m_totalDev.cx-1;
  702.         if (!SetScrollInfo(SB_HORZ, &info, TRUE))
  703.             SetScrollRange(SB_HORZ, 0, sizeRange.cx, TRUE);
  704.     }
  705.     EnableScrollBarCtrl(SB_VERT, needSb.cy);
  706.     if (needSb.cy)
  707.     {
  708.         info.nPage = sizeClient.cy;
  709.         info.nMax = m_totalDev.cy-1;
  710.         if (!SetScrollInfo(SB_VERT, &info, TRUE))
  711.             SetScrollRange(SB_VERT, 0, sizeRange.cy, TRUE);
  712.     }
  713.  
  714.     // remove recursion lockout
  715.     m_bInsideUpdate = FALSE;
  716. }
  717.  
  718. void CScrollView::CalcWindowRect(LPRECT lpClientRect, UINT nAdjustType)
  719. {
  720.     if (nAdjustType == adjustOutside)
  721.     {
  722.         // allow for special client-edge style
  723.         ::AdjustWindowRectEx(lpClientRect, 0, FALSE, GetExStyle());
  724.  
  725.         if (m_nMapMode != MM_SCALETOFIT)
  726.         {
  727.             // if the view is being used in-place, add scrollbar sizes
  728.             //  (scollbars should appear on the outside when in-place editing)
  729.             CSize sizeClient(
  730.                 lpClientRect->right - lpClientRect->left,
  731.                 lpClientRect->bottom - lpClientRect->top);
  732.  
  733.             CSize sizeRange = m_totalDev - sizeClient;
  734.                 // > 0 => need to scroll
  735.  
  736.             // get scroll bar sizes (used to adjust the window)
  737.             CSize sizeSb;
  738.             GetScrollBarSizes(sizeSb);
  739.  
  740.             // adjust the window size based on the state
  741.             if (sizeRange.cy > 0)
  742.             {   // vertical scroll bars take up horizontal space
  743.                 lpClientRect->right += sizeSb.cx;
  744.             }
  745.             if (sizeRange.cx > 0)
  746.             {   // horizontal scroll bars take up vertical space
  747.                 lpClientRect->bottom += sizeSb.cy;
  748.             }
  749.         }
  750.     }
  751.     else
  752.     {
  753.         // call default to handle other non-client areas
  754.         ::AdjustWindowRectEx(lpClientRect, GetStyle(), FALSE,
  755.             GetExStyle() & ~(WS_EX_CLIENTEDGE));
  756.     }
  757. }
  758.  
  759. /////////////////////////////////////////////////////////////////////////////
  760. // CScrollView scrolling
  761.  
  762. void CScrollView::OnHScroll(UINT nSBCode, UINT nPos, CScrollBar* pScrollBar)
  763. {
  764.     if (pScrollBar != NULL && pScrollBar->SendChildNotifyLastMsg())
  765.         return;     // eat it
  766.  
  767.     // ignore scroll bar msgs from other controls
  768.     if (pScrollBar != GetScrollBarCtrl(SB_HORZ))
  769.         return;
  770.  
  771.     OnScroll(MAKEWORD(nSBCode, -1), nPos);
  772. }
  773.  
  774. void CScrollView::OnVScroll(UINT nSBCode, UINT nPos, CScrollBar* pScrollBar)
  775. {
  776.     if (pScrollBar != NULL && pScrollBar->SendChildNotifyLastMsg())
  777.         return;     // eat it
  778.  
  779.     // ignore scroll bar msgs from other controls
  780.     if (pScrollBar != GetScrollBarCtrl(SB_VERT))
  781.         return;
  782.  
  783.     OnScroll(MAKEWORD(-1, nSBCode), nPos);
  784. }
  785.  
  786. BOOL CScrollView::OnMouseWheel(UINT fFlags, short zDelta, CPoint point)
  787. {
  788.     // we don't handle anything but scrolling just now
  789.     if (fFlags & (MK_SHIFT | MK_CONTROL))
  790.         return FALSE;
  791.  
  792.     // if the parent is a splitter, it will handle the message
  793.     if (GetParentSplitter(this, TRUE))
  794.         return FALSE;
  795.  
  796.     // we can't get out of it--perform the scroll ourselves
  797.     return DoMouseWheel(fFlags, zDelta, point);
  798. }
  799.  
  800. // This function isn't virtual. If you need to override it,
  801. // you really need to override OnMouseWheel() here or in
  802. // CSplitterWnd.
  803.  
  804. BOOL CScrollView::DoMouseWheel(UINT fFlags, short zDelta, CPoint point)
  805. {
  806.     UNUSED_ALWAYS(point);
  807.     UNUSED_ALWAYS(fFlags);
  808.  
  809.     // if we have a vertical scroll bar, the wheel scrolls that
  810.     // if we have _only_ a horizontal scroll bar, the wheel scrolls that
  811.     // otherwise, don't do any work at all
  812.  
  813.     DWORD dwStyle = GetStyle();
  814.     CScrollBar* pBar = GetScrollBarCtrl(SB_VERT);
  815.     BOOL bHasVertBar = ((pBar != NULL) && pBar->IsWindowEnabled()) ||
  816.                     (dwStyle & WS_VSCROLL);
  817.  
  818.     pBar = GetScrollBarCtrl(SB_HORZ);
  819.     BOOL bHasHorzBar = ((pBar != NULL) && pBar->IsWindowEnabled()) ||
  820.                     (dwStyle & WS_HSCROLL);
  821.  
  822.     if (!bHasVertBar && !bHasHorzBar)
  823.         return FALSE;
  824.  
  825.     BOOL bResult = FALSE;
  826.     UINT uWheelScrollLines = _AfxGetMouseScrollLines();
  827.     int nToScroll;
  828.     int nDisplacement;
  829.  
  830.     if (bHasVertBar)
  831.     {
  832.         nToScroll = ::MulDiv(-zDelta, uWheelScrollLines, WHEEL_DELTA);
  833.         if (nToScroll == -1 || uWheelScrollLines == WHEEL_PAGESCROLL)
  834.         {
  835.             nDisplacement = m_pageDev.cy;
  836.             if (zDelta > 0)
  837.                 nDisplacement = -nDisplacement;
  838.         }
  839.         else
  840.         {
  841.             nDisplacement = nToScroll * m_lineDev.cy;
  842.             nDisplacement = min(nDisplacement, m_pageDev.cy);
  843.         }
  844.         bResult = OnScrollBy(CSize(0, nDisplacement), TRUE);
  845.     }
  846.     else if (bHasHorzBar)
  847.     {
  848.         nToScroll = ::MulDiv(-zDelta, uWheelScrollLines, WHEEL_DELTA);
  849.         if (nToScroll == -1 || uWheelScrollLines == WHEEL_PAGESCROLL)
  850.         {
  851.             nDisplacement = m_pageDev.cx;
  852.             if (zDelta > 0)
  853.                 nDisplacement = nDisplacement;
  854.         }
  855.         else
  856.         {
  857.             nDisplacement = nToScroll * m_lineDev.cx;
  858.             nDisplacement = min(nDisplacement, m_pageDev.cx);
  859.         }
  860.         bResult = OnScrollBy(CSize(nDisplacement, 0), TRUE);
  861.     }
  862.  
  863.     if (bResult)
  864.         UpdateWindow();
  865.  
  866.     return bResult;
  867. }
  868.  
  869.  
  870. BOOL CScrollView::OnScroll(UINT nScrollCode, UINT nPos, BOOL bDoScroll)
  871. {
  872.     // calc new x position
  873.     int x = GetScrollPos(SB_HORZ);
  874.     int xOrig = x;
  875.  
  876.     switch (LOBYTE(nScrollCode))
  877.     {
  878.     case SB_TOP:
  879.         x = 0;
  880.         break;
  881.     case SB_BOTTOM:
  882.         x = INT_MAX;
  883.         break;
  884.     case SB_LINEUP:
  885.         x -= m_lineDev.cx;
  886.         break;
  887.     case SB_LINEDOWN:
  888.         x += m_lineDev.cx;
  889.         break;
  890.     case SB_PAGEUP:
  891.         x -= m_pageDev.cx;
  892.         break;
  893.     case SB_PAGEDOWN:
  894.         x += m_pageDev.cx;
  895.         break;
  896.     case SB_THUMBTRACK:
  897.         x = nPos;
  898.         break;
  899.     }
  900.  
  901.     // calc new y position
  902.     int y = GetScrollPos(SB_VERT);
  903.     int yOrig = y;
  904.  
  905.     switch (HIBYTE(nScrollCode))
  906.     {
  907.     case SB_TOP:
  908.         y = 0;
  909.         break;
  910.     case SB_BOTTOM:
  911.         y = INT_MAX;
  912.         break;
  913.     case SB_LINEUP:
  914.         y -= m_lineDev.cy;
  915.         break;
  916.     case SB_LINEDOWN:
  917.         y += m_lineDev.cy;
  918.         break;
  919.     case SB_PAGEUP:
  920.         y -= m_pageDev.cy;
  921.         break;
  922.     case SB_PAGEDOWN:
  923.         y += m_pageDev.cy;
  924.         break;
  925.     case SB_THUMBTRACK:
  926.         y = nPos;
  927.         break;
  928.     }
  929.  
  930.     BOOL bResult = OnScrollBy(CSize(x - xOrig, y - yOrig), bDoScroll);
  931.     if (bResult && bDoScroll)
  932.         UpdateWindow();
  933.  
  934.     return bResult;
  935. }
  936.  
  937. BOOL CScrollView::OnScrollBy(CSize sizeScroll, BOOL bDoScroll)
  938. {
  939.     int xOrig, x;
  940.     int yOrig, y;
  941.  
  942.     // don't scroll if there is no valid scroll range (ie. no scroll bar)
  943.     CScrollBar* pBar;
  944.     DWORD dwStyle = GetStyle();
  945.     pBar = GetScrollBarCtrl(SB_VERT);
  946.     if ((pBar != NULL && !pBar->IsWindowEnabled()) ||
  947.         (pBar == NULL && !(dwStyle & WS_VSCROLL)))
  948.     {
  949.         // vertical scroll bar not enabled
  950.         sizeScroll.cy = 0;
  951.     }
  952.     pBar = GetScrollBarCtrl(SB_HORZ);
  953.     if ((pBar != NULL && !pBar->IsWindowEnabled()) ||
  954.         (pBar == NULL && !(dwStyle & WS_HSCROLL)))
  955.     {
  956.         // horizontal scroll bar not enabled
  957.         sizeScroll.cx = 0;
  958.     }
  959.  
  960.     // adjust current x position
  961.     xOrig = x = GetScrollPos(SB_HORZ);
  962.     int xMax = GetScrollLimit(SB_HORZ);
  963.     x += sizeScroll.cx;
  964.     if (x < 0)
  965.         x = 0;
  966.     else if (x > xMax)
  967.         x = xMax;
  968.  
  969.     // adjust current y position
  970.     yOrig = y = GetScrollPos(SB_VERT);
  971.     int yMax = GetScrollLimit(SB_VERT);
  972.     y += sizeScroll.cy;
  973.     if (y < 0)
  974.         y = 0;
  975.     else if (y > yMax)
  976.         y = yMax;
  977.  
  978.     // did anything change?
  979.     if (x == xOrig && y == yOrig)
  980.         return FALSE;
  981.  
  982.     if (bDoScroll)
  983.     {
  984.         // do scroll and update scroll positions
  985.         ScrollWindow(-(x-xOrig), -(y-yOrig));
  986.         if (x != xOrig)
  987.             SetScrollPos(SB_HORZ, x);
  988.         if (y != yOrig)
  989.             SetScrollPos(SB_VERT, y);
  990.     }
  991.     return TRUE;
  992. }
  993.  
  994. /////////////////////////////////////////////////////////////////////////////
  995. // CScrollView diagnostics
  996.  
  997. #ifdef _DEBUG
  998. void CScrollView::Dump(CDumpContext& dc) const
  999. {
  1000.     CView::Dump(dc);
  1001.  
  1002.     dc << "m_totalLog = " << m_totalLog;
  1003.     dc << "\nm_totalDev = " << m_totalDev;
  1004.     dc << "\nm_pageDev = " << m_pageDev;
  1005.     dc << "\nm_lineDev = " << m_lineDev;
  1006.     dc << "\nm_bCenter = " << m_bCenter;
  1007.     dc << "\nm_bInsideUpdate = " << m_bInsideUpdate;
  1008.     dc << "\nm_nMapMode = ";
  1009.     switch (m_nMapMode)
  1010.     {
  1011.     case MM_NONE:
  1012.         dc << "MM_NONE";
  1013.         break;
  1014.     case MM_SCALETOFIT:
  1015.         dc << "MM_SCALETOFIT";
  1016.         break;
  1017.     case MM_TEXT:
  1018.         dc << "MM_TEXT";
  1019.         break;
  1020.     case MM_LOMETRIC:
  1021.         dc << "MM_LOMETRIC";
  1022.         break;
  1023.     case MM_HIMETRIC:
  1024.         dc << "MM_HIMETRIC";
  1025.         break;
  1026.     case MM_LOENGLISH:
  1027.         dc << "MM_LOENGLISH";
  1028.         break;
  1029.     case MM_HIENGLISH:
  1030.         dc << "MM_HIENGLISH";
  1031.         break;
  1032.     case MM_TWIPS:
  1033.         dc << "MM_TWIPS";
  1034.         break;
  1035.     default:
  1036.         dc << "*unknown*";
  1037.         break;
  1038.     }
  1039.  
  1040.     dc << "\n";
  1041. }
  1042.  
  1043. void CScrollView::AssertValid() const
  1044. {
  1045.     CView::AssertValid();
  1046.  
  1047.     switch (m_nMapMode)
  1048.     {
  1049.     case MM_NONE:
  1050.     case MM_SCALETOFIT:
  1051.     case MM_TEXT:
  1052.     case MM_LOMETRIC:
  1053.     case MM_HIMETRIC:
  1054.     case MM_LOENGLISH:
  1055.     case MM_HIENGLISH:
  1056.     case MM_TWIPS:
  1057.         break;
  1058.     case MM_ISOTROPIC:
  1059.     case MM_ANISOTROPIC:
  1060.         ASSERT(FALSE); // illegal mapping mode
  1061.     default:
  1062.         ASSERT(FALSE); // unknown mapping mode
  1063.     }
  1064. }
  1065. #endif //_DEBUG
  1066.  
  1067. #ifdef AFX_INIT_SEG
  1068. #pragma code_seg(AFX_INIT_SEG)
  1069. #endif
  1070.  
  1071. IMPLEMENT_DYNAMIC(CScrollView, CView)
  1072.  
  1073. /////////////////////////////////////////////////////////////////////////////
  1074.