home *** CD-ROM | disk | FTP | other *** search
- // This is a part of the Microsoft Foundation Classes C++ library.
- // Copyright (C) 1992-1998 Microsoft Corporation
- // All rights reserved.
- //
- // This source code is only intended as a supplement to the
- // Microsoft Foundation Classes Reference and related
- // electronic documentation provided with the library.
- // See these sources for detailed information regarding the
- // Microsoft Foundation Classes product.
-
- #include "stdafx.h"
-
- #ifdef AFX_CORE2_SEG
- #pragma code_seg(AFX_CORE2_SEG)
- #endif
-
- #ifdef _DEBUG
- #undef THIS_FILE
- static char THIS_FILE[] = __FILE__;
- #endif
-
- /////////////////////////////////////////////////////////////////////////////
- // CScrollView
-
- BEGIN_MESSAGE_MAP(CScrollView, CView)
- //{{AFX_MSG_MAP(CScrollView)
- ON_WM_SIZE()
- ON_WM_HSCROLL()
- ON_WM_VSCROLL()
- ON_WM_MOUSEWHEEL()
- //}}AFX_MSG_MAP
- END_MESSAGE_MAP()
-
- // Special mapping modes just for CScrollView implementation
- #define MM_NONE 0
- #define MM_SCALETOFIT (-1)
- // standard GDI mapping modes are > 0
-
- extern BOOL _afxGotScrollLines; // defined in wincore.cpp
-
- UINT PASCAL _AfxGetMouseScrollLines()
- {
- static UINT uCachedScrollLines;
-
- // if we've already got it and we're not refreshing,
- // return what we've already got
-
- if (_afxGotScrollLines)
- return uCachedScrollLines;
-
- // see if we can find the mouse window
-
- _afxGotScrollLines = TRUE;
-
- static UINT msgGetScrollLines;
- static WORD nRegisteredMessage;
-
- if (nRegisteredMessage == 0)
- {
- msgGetScrollLines = ::RegisterWindowMessage(MSH_SCROLL_LINES);
- if (msgGetScrollLines == 0)
- nRegisteredMessage = 1; // couldn't register! never try again
- else
- nRegisteredMessage = 2; // it worked: use it
- }
-
- if (nRegisteredMessage == 2)
- {
- HWND hwMouseWheel = NULL;
- hwMouseWheel = FindWindow(MSH_WHEELMODULE_CLASS, MSH_WHEELMODULE_TITLE);
- if (hwMouseWheel && msgGetScrollLines)
- {
- uCachedScrollLines = (UINT)
- ::SendMessage(hwMouseWheel, msgGetScrollLines, 0, 0);
- return uCachedScrollLines;
- }
- }
-
- // couldn't use the window -- try system settings
- uCachedScrollLines = 3; // reasonable default
- if (!afxData.bWin4)
- {
- HKEY hKey;
- if (RegOpenKeyEx(HKEY_CURRENT_USER, _T("Control Panel\\Desktop"),
- 0, KEY_QUERY_VALUE, &hKey) == ERROR_SUCCESS)
- {
- TCHAR szData[128];
- DWORD dwKeyDataType;
- DWORD dwDataBufSize = _countof(szData);
-
- if (RegQueryValueEx(hKey, _T("WheelScrollLines"), NULL, &dwKeyDataType,
- (LPBYTE) &szData, &dwDataBufSize) == ERROR_SUCCESS)
- {
- uCachedScrollLines = _tcstoul(szData, NULL, 10);
- }
- RegCloseKey(hKey);
- }
- }
- else if (!afxData.bWin95)
- {
- ::SystemParametersInfo(SPI_GETWHEELSCROLLLINES, 0, &uCachedScrollLines, 0);
- }
-
- return uCachedScrollLines;
- }
-
- /////////////////////////////////////////////////////////////////////////////
- // CScrollView construction/destruction
-
- CScrollView::CScrollView()
- {
- // Init everything to zero
- AFX_ZERO_INIT_OBJECT(CView);
-
- m_nMapMode = MM_NONE;
- }
-
- CScrollView::~CScrollView()
- {
- }
-
- /////////////////////////////////////////////////////////////////////////////
- // CScrollView painting
-
- void CScrollView::OnPrepareDC(CDC* pDC, CPrintInfo* pInfo)
- {
- ASSERT_VALID(pDC);
-
- #ifdef _DEBUG
- if (m_nMapMode == MM_NONE)
- {
- TRACE0("Error: must call SetScrollSizes() or SetScaleToFitSize()");
- TRACE0("\tbefore painting scroll view.\n");
- ASSERT(FALSE);
- return;
- }
- #endif //_DEBUG
- ASSERT(m_totalDev.cx >= 0 && m_totalDev.cy >= 0);
- switch (m_nMapMode)
- {
- case MM_SCALETOFIT:
- pDC->SetMapMode(MM_ANISOTROPIC);
- pDC->SetWindowExt(m_totalLog); // window is in logical coordinates
- pDC->SetViewportExt(m_totalDev);
- if (m_totalDev.cx == 0 || m_totalDev.cy == 0)
- TRACE0("Warning: CScrollView scaled to nothing.\n");
- break;
-
- default:
- ASSERT(m_nMapMode > 0);
- pDC->SetMapMode(m_nMapMode);
- break;
- }
-
- CPoint ptVpOrg(0, 0); // assume no shift for printing
- if (!pDC->IsPrinting())
- {
- ASSERT(pDC->GetWindowOrg() == CPoint(0,0));
-
- // by default shift viewport origin in negative direction of scroll
- ptVpOrg = -GetDeviceScrollPosition();
-
- if (m_bCenter)
- {
- CRect rect;
- GetClientRect(&rect);
-
- // if client area is larger than total device size,
- // override scroll positions to place origin such that
- // output is centered in the window
- if (m_totalDev.cx < rect.Width())
- ptVpOrg.x = (rect.Width() - m_totalDev.cx) / 2;
- if (m_totalDev.cy < rect.Height())
- ptVpOrg.y = (rect.Height() - m_totalDev.cy) / 2;
- }
- }
- pDC->SetViewportOrg(ptVpOrg);
-
- CView::OnPrepareDC(pDC, pInfo); // For default Printing behavior
- }
-
- /////////////////////////////////////////////////////////////////////////////
- // Set mode and scaling/scrolling sizes
-
- void CScrollView::SetScaleToFitSize(SIZE sizeTotal)
- {
- // Note: It is possible to set sizeTotal members to negative values to
- // effectively invert either the X or Y axis.
-
- ASSERT(m_hWnd != NULL);
- m_nMapMode = MM_SCALETOFIT; // special internal value
- m_totalLog = sizeTotal;
-
- // reset and turn any scroll bars off
- if (m_hWnd != NULL && (GetStyle() & (WS_HSCROLL|WS_VSCROLL)))
- {
- SetScrollPos(SB_HORZ, 0);
- SetScrollPos(SB_VERT, 0);
- EnableScrollBarCtrl(SB_BOTH, FALSE);
- ASSERT((GetStyle() & (WS_HSCROLL|WS_VSCROLL)) == 0);
- }
-
- CRect rectT;
- GetClientRect(rectT);
- m_totalDev = rectT.Size();
-
- if (m_hWnd != NULL)
- {
- // window has been created, invalidate
- UpdateBars();
- Invalidate(TRUE);
- }
- }
-
- const AFX_DATADEF SIZE CScrollView::sizeDefault = {0,0};
-
- void CScrollView::SetScrollSizes(int nMapMode, SIZE sizeTotal,
- const SIZE& sizePage, const SIZE& sizeLine)
- {
- ASSERT(sizeTotal.cx >= 0 && sizeTotal.cy >= 0);
- ASSERT(nMapMode > 0);
- ASSERT(nMapMode != MM_ISOTROPIC && nMapMode != MM_ANISOTROPIC);
-
- int nOldMapMode = m_nMapMode;
- m_nMapMode = nMapMode;
- m_totalLog = sizeTotal;
-
- //BLOCK: convert logical coordinate space to device coordinates
- {
- CWindowDC dc(NULL);
- ASSERT(m_nMapMode > 0);
- dc.SetMapMode(m_nMapMode);
-
- // total size
- m_totalDev = m_totalLog;
- dc.LPtoDP((LPPOINT)&m_totalDev);
- m_pageDev = sizePage;
- dc.LPtoDP((LPPOINT)&m_pageDev);
- m_lineDev = sizeLine;
- dc.LPtoDP((LPPOINT)&m_lineDev);
- if (m_totalDev.cy < 0)
- m_totalDev.cy = -m_totalDev.cy;
- if (m_pageDev.cy < 0)
- m_pageDev.cy = -m_pageDev.cy;
- if (m_lineDev.cy < 0)
- m_lineDev.cy = -m_lineDev.cy;
- } // release DC here
-
- // now adjust device specific sizes
- ASSERT(m_totalDev.cx >= 0 && m_totalDev.cy >= 0);
- if (m_pageDev.cx == 0)
- m_pageDev.cx = m_totalDev.cx / 10;
- if (m_pageDev.cy == 0)
- m_pageDev.cy = m_totalDev.cy / 10;
- if (m_lineDev.cx == 0)
- m_lineDev.cx = m_pageDev.cx / 10;
- if (m_lineDev.cy == 0)
- m_lineDev.cy = m_pageDev.cy / 10;
-
- if (m_hWnd != NULL)
- {
- // window has been created, invalidate now
- UpdateBars();
- if (nOldMapMode != m_nMapMode)
- Invalidate(TRUE);
- }
- }
-
- /////////////////////////////////////////////////////////////////////////////
- // Getting information
-
- CPoint CScrollView::GetScrollPosition() const // logical coordinates
- {
- if (m_nMapMode == MM_SCALETOFIT)
- {
- return CPoint(0, 0); // must be 0,0
- }
-
- CPoint pt = GetDeviceScrollPosition();
- // pt may be negative if m_bCenter is set
-
- if (m_nMapMode != MM_TEXT)
- {
- ASSERT(m_nMapMode > 0); // must be set
- CWindowDC dc(NULL);
- dc.SetMapMode(m_nMapMode);
- dc.DPtoLP((LPPOINT)&pt);
- }
- return pt;
- }
-
- void CScrollView::ScrollToPosition(POINT pt) // logical coordinates
- {
- ASSERT(m_nMapMode > 0); // not allowed for shrink to fit
- if (m_nMapMode != MM_TEXT)
- {
- CWindowDC dc(NULL);
- dc.SetMapMode(m_nMapMode);
- dc.LPtoDP((LPPOINT)&pt);
- }
-
- // now in device coordinates - limit if out of range
- int xMax = GetScrollLimit(SB_HORZ);
- int yMax = GetScrollLimit(SB_VERT);
- if (pt.x < 0)
- pt.x = 0;
- else if (pt.x > xMax)
- pt.x = xMax;
- if (pt.y < 0)
- pt.y = 0;
- else if (pt.y > yMax)
- pt.y = yMax;
-
- ScrollToDevicePosition(pt);
- }
-
- CPoint CScrollView::GetDeviceScrollPosition() const
- {
- CPoint pt(GetScrollPos(SB_HORZ), GetScrollPos(SB_VERT));
- ASSERT(pt.x >= 0 && pt.y >= 0);
-
- if (m_bCenter)
- {
- CRect rect;
- GetClientRect(&rect);
-
- // if client area is larger than total device size,
- // the scroll positions are overridden to place origin such that
- // output is centered in the window
- // GetDeviceScrollPosition() must reflect this
-
- if (m_totalDev.cx < rect.Width())
- pt.x = -((rect.Width() - m_totalDev.cx) / 2);
- if (m_totalDev.cy < rect.Height())
- pt.y = -((rect.Height() - m_totalDev.cy) / 2);
- }
-
- return pt;
- }
-
- void CScrollView::GetDeviceScrollSizes(int& nMapMode, SIZE& sizeTotal,
- SIZE& sizePage, SIZE& sizeLine) const
- {
- if (m_nMapMode <= 0)
- TRACE0("Warning: CScrollView::GetDeviceScrollSizes returning invalid mapping mode.\n");
- nMapMode = m_nMapMode;
- sizeTotal = m_totalDev;
- sizePage = m_pageDev;
- sizeLine = m_lineDev;
- }
-
- void CScrollView::ScrollToDevicePosition(POINT ptDev)
- {
- ASSERT(ptDev.x >= 0);
- ASSERT(ptDev.y >= 0);
-
- // Note: ScrollToDevicePosition can and is used to scroll out-of-range
- // areas as far as CScrollView is concerned -- specifically in
- // the print-preview code. Since OnScrollBy makes sure the range is
- // valid, ScrollToDevicePosition does not vector through OnScrollBy.
-
- int xOrig = GetScrollPos(SB_HORZ);
- SetScrollPos(SB_HORZ, ptDev.x);
- int yOrig = GetScrollPos(SB_VERT);
- SetScrollPos(SB_VERT, ptDev.y);
- ScrollWindow(xOrig - ptDev.x, yOrig - ptDev.y);
- }
-
- /////////////////////////////////////////////////////////////////////////////
- // Other helpers
-
- void CScrollView::FillOutsideRect(CDC* pDC, CBrush* pBrush)
- {
- ASSERT_VALID(pDC);
- ASSERT_VALID(pBrush);
-
- // fill rect outside the image
- CRect rect;
- GetClientRect(rect);
- ASSERT(rect.left == 0 && rect.top == 0);
- rect.left = m_totalDev.cx;
- if (!rect.IsRectEmpty())
- pDC->FillRect(rect, pBrush); // vertical strip along the side
- rect.left = 0;
- rect.right = m_totalDev.cx;
- rect.top = m_totalDev.cy;
- if (!rect.IsRectEmpty())
- pDC->FillRect(rect, pBrush); // horizontal strip along the bottom
- }
-
- void CScrollView::ResizeParentToFit(BOOL bShrinkOnly)
- {
- // adjust parent rect so client rect is appropriate size
- ASSERT(m_nMapMode != MM_NONE); // mapping mode must be known
-
- // determine current size of the client area as if no scrollbars present
- CRect rectClient;
- GetWindowRect(rectClient);
- CRect rect = rectClient;
- CalcWindowRect(rect);
- rectClient.left += rectClient.left - rect.left;
- rectClient.top += rectClient.top - rect.top;
- rectClient.right -= rect.right - rectClient.right;
- rectClient.bottom -= rect.bottom - rectClient.bottom;
- rectClient.OffsetRect(-rectClient.left, -rectClient.top);
- ASSERT(rectClient.left == 0 && rectClient.top == 0);
-
- // determine desired size of the view
- CRect rectView(0, 0, m_totalDev.cx, m_totalDev.cy);
- if (bShrinkOnly)
- {
- if (rectClient.right <= m_totalDev.cx)
- rectView.right = rectClient.right;
- if (rectClient.bottom <= m_totalDev.cy)
- rectView.bottom = rectClient.bottom;
- }
- CalcWindowRect(rectView, CWnd::adjustOutside);
- rectView.OffsetRect(-rectView.left, -rectView.top);
- ASSERT(rectView.left == 0 && rectView.top == 0);
- if (bShrinkOnly)
- {
- if (rectClient.right <= m_totalDev.cx)
- rectView.right = rectClient.right;
- if (rectClient.bottom <= m_totalDev.cy)
- rectView.bottom = rectClient.bottom;
- }
-
- // dermine and set size of frame based on desired size of view
- CRect rectFrame;
- CFrameWnd* pFrame = GetParentFrame();
- ASSERT_VALID(pFrame);
- pFrame->GetWindowRect(rectFrame);
- CSize size = rectFrame.Size();
- size.cx += rectView.right - rectClient.right;
- size.cy += rectView.bottom - rectClient.bottom;
- pFrame->SetWindowPos(NULL, 0, 0, size.cx, size.cy,
- SWP_NOMOVE|SWP_NOZORDER|SWP_NOACTIVATE);
- }
-
- /////////////////////////////////////////////////////////////////////////////
-
- void CScrollView::OnSize(UINT nType, int cx, int cy)
- {
- CView::OnSize(nType, cx, cy);
- if (m_nMapMode == MM_SCALETOFIT)
- {
- // force recalculation of scale to fit parameters
- SetScaleToFitSize(m_totalLog);
- }
- else
- {
- // UpdateBars() handles locking out recursion
- UpdateBars();
- }
- }
-
- /////////////////////////////////////////////////////////////////////////////
- // Scrolling Helpers
-
- void CScrollView::CenterOnPoint(CPoint ptCenter) // center in device coords
- {
- CRect rect;
- GetClientRect(&rect); // find size of client window
-
- int xDesired = ptCenter.x - rect.Width() / 2;
- int yDesired = ptCenter.y - rect.Height() / 2;
-
- DWORD dwStyle = GetStyle();
-
- if ((dwStyle & WS_HSCROLL) == 0 || xDesired < 0)
- {
- xDesired = 0;
- }
- else
- {
- int xMax = GetScrollLimit(SB_HORZ);
- if (xDesired > xMax)
- xDesired = xMax;
- }
-
- if ((dwStyle & WS_VSCROLL) == 0 || yDesired < 0)
- {
- yDesired = 0;
- }
- else
- {
- int yMax = GetScrollLimit(SB_VERT);
- if (yDesired > yMax)
- yDesired = yMax;
- }
-
- ASSERT(xDesired >= 0);
- ASSERT(yDesired >= 0);
-
- SetScrollPos(SB_HORZ, xDesired);
- SetScrollPos(SB_VERT, yDesired);
- }
-
- /////////////////////////////////////////////////////////////////////////////
- // Tie to scrollbars and CWnd behaviour
-
- void CScrollView::GetScrollBarSizes(CSize& sizeSb)
- {
- sizeSb.cx = sizeSb.cy = 0;
- DWORD dwStyle = GetStyle();
-
- if (GetScrollBarCtrl(SB_VERT) == NULL)
- {
- // vert scrollbars will impact client area of this window
- sizeSb.cx = afxData.cxVScroll;
- if (dwStyle & WS_BORDER)
- sizeSb.cx -= CX_BORDER;
- }
- if (GetScrollBarCtrl(SB_HORZ) == NULL)
- {
- // horz scrollbars will impact client area of this window
- sizeSb.cy = afxData.cyHScroll;
- if (dwStyle & WS_BORDER)
- sizeSb.cy -= CY_BORDER;
- }
- }
-
- BOOL CScrollView::GetTrueClientSize(CSize& size, CSize& sizeSb)
- // return TRUE if enough room to add scrollbars if needed
- {
- CRect rect;
- GetClientRect(&rect);
- ASSERT(rect.top == 0 && rect.left == 0);
- size.cx = rect.right;
- size.cy = rect.bottom;
- DWORD dwStyle = GetStyle();
-
- // first get the size of the scrollbars for this window
- GetScrollBarSizes(sizeSb);
-
- // first calculate the size of a potential scrollbar
- // (scroll bar controls do not get turned on/off)
- if (sizeSb.cx != 0 && (dwStyle & WS_VSCROLL))
- {
- // vert scrollbars will impact client area of this window
- size.cx += sizeSb.cx; // currently on - adjust now
- }
- if (sizeSb.cy != 0 && (dwStyle & WS_HSCROLL))
- {
- // horz scrollbars will impact client area of this window
- size.cy += sizeSb.cy; // currently on - adjust now
- }
-
- // return TRUE if enough room
- return (size.cx > sizeSb.cx && size.cy > sizeSb.cy);
- }
-
- // helper to return the state of the scrollbars without actually changing
- // the state of the scrollbars
- void CScrollView::GetScrollBarState(CSize sizeClient, CSize& needSb,
- CSize& sizeRange, CPoint& ptMove, BOOL bInsideClient)
- {
- // get scroll bar sizes (the part that is in the client area)
- CSize sizeSb;
- GetScrollBarSizes(sizeSb);
-
- // enough room to add scrollbars
- sizeRange = m_totalDev - sizeClient;
- // > 0 => need to scroll
- ptMove = GetDeviceScrollPosition();
- // point to move to (start at current scroll pos)
-
- BOOL bNeedH = sizeRange.cx > 0;
- if (!bNeedH)
- ptMove.x = 0; // jump back to origin
- else if (bInsideClient)
- sizeRange.cy += sizeSb.cy; // need room for a scroll bar
-
- BOOL bNeedV = sizeRange.cy > 0;
- if (!bNeedV)
- ptMove.y = 0; // jump back to origin
- else if (bInsideClient)
- sizeRange.cx += sizeSb.cx; // need room for a scroll bar
-
- if (bNeedV && !bNeedH && sizeRange.cx > 0)
- {
- ASSERT(bInsideClient);
- // need a horizontal scrollbar after all
- bNeedH = TRUE;
- sizeRange.cy += sizeSb.cy;
- }
-
- // if current scroll position will be past the limit, scroll to limit
- if (sizeRange.cx > 0 && ptMove.x >= sizeRange.cx)
- ptMove.x = sizeRange.cx;
- if (sizeRange.cy > 0 && ptMove.y >= sizeRange.cy)
- ptMove.y = sizeRange.cy;
-
- // now update the bars as appropriate
- needSb.cx = bNeedH;
- needSb.cy = bNeedV;
-
- // needSb, sizeRange, and ptMove area now all updated
- }
-
- void CScrollView::UpdateBars()
- {
- // UpdateBars may cause window to be resized - ignore those resizings
- if (m_bInsideUpdate)
- return; // Do not allow recursive calls
-
- // Lock out recursion
- m_bInsideUpdate = TRUE;
-
- // update the horizontal to reflect reality
- // NOTE: turning on/off the scrollbars will cause 'OnSize' callbacks
- ASSERT(m_totalDev.cx >= 0 && m_totalDev.cy >= 0);
-
- CRect rectClient;
- BOOL bCalcClient = TRUE;
-
- // allow parent to do inside-out layout first
- CWnd* pParentWnd = GetParent();
- if (pParentWnd != NULL)
- {
- // if parent window responds to this message, use just
- // client area for scroll bar calc -- not "true" client area
- if ((BOOL)pParentWnd->SendMessage(WM_RECALCPARENT, 0,
- (LPARAM)(LPCRECT)&rectClient) != 0)
- {
- // use rectClient instead of GetTrueClientSize for
- // client size calculation.
- bCalcClient = FALSE;
- }
- }
-
- CSize sizeClient;
- CSize sizeSb;
-
- if (bCalcClient)
- {
- // get client rect
- if (!GetTrueClientSize(sizeClient, sizeSb))
- {
- // no room for scroll bars (common for zero sized elements)
- CRect rect;
- GetClientRect(&rect);
- if (rect.right > 0 && rect.bottom > 0)
- {
- // if entire client area is not invisible, assume we have
- // control over our scrollbars
- EnableScrollBarCtrl(SB_BOTH, FALSE);
- }
- m_bInsideUpdate = FALSE;
- return;
- }
- }
- else
- {
- // let parent window determine the "client" rect
- GetScrollBarSizes(sizeSb);
- sizeClient.cx = rectClient.right - rectClient.left;
- sizeClient.cy = rectClient.bottom - rectClient.top;
- }
-
- // enough room to add scrollbars
- CSize sizeRange;
- CPoint ptMove;
- CSize needSb;
-
- // get the current scroll bar state given the true client area
- GetScrollBarState(sizeClient, needSb, sizeRange, ptMove, bCalcClient);
- if (needSb.cx)
- sizeClient.cy -= sizeSb.cy;
- if (needSb.cy)
- sizeClient.cx -= sizeSb.cx;
-
- // first scroll the window as needed
- ScrollToDevicePosition(ptMove); // will set the scroll bar positions too
-
- // this structure needed to update the scrollbar page range
- SCROLLINFO info;
- info.fMask = SIF_PAGE|SIF_RANGE;
- info.nMin = 0;
-
- // now update the bars as appropriate
- EnableScrollBarCtrl(SB_HORZ, needSb.cx);
- if (needSb.cx)
- {
- info.nPage = sizeClient.cx;
- info.nMax = m_totalDev.cx-1;
- if (!SetScrollInfo(SB_HORZ, &info, TRUE))
- SetScrollRange(SB_HORZ, 0, sizeRange.cx, TRUE);
- }
- EnableScrollBarCtrl(SB_VERT, needSb.cy);
- if (needSb.cy)
- {
- info.nPage = sizeClient.cy;
- info.nMax = m_totalDev.cy-1;
- if (!SetScrollInfo(SB_VERT, &info, TRUE))
- SetScrollRange(SB_VERT, 0, sizeRange.cy, TRUE);
- }
-
- // remove recursion lockout
- m_bInsideUpdate = FALSE;
- }
-
- void CScrollView::CalcWindowRect(LPRECT lpClientRect, UINT nAdjustType)
- {
- if (nAdjustType == adjustOutside)
- {
- // allow for special client-edge style
- ::AdjustWindowRectEx(lpClientRect, 0, FALSE, GetExStyle());
-
- if (m_nMapMode != MM_SCALETOFIT)
- {
- // if the view is being used in-place, add scrollbar sizes
- // (scollbars should appear on the outside when in-place editing)
- CSize sizeClient(
- lpClientRect->right - lpClientRect->left,
- lpClientRect->bottom - lpClientRect->top);
-
- CSize sizeRange = m_totalDev - sizeClient;
- // > 0 => need to scroll
-
- // get scroll bar sizes (used to adjust the window)
- CSize sizeSb;
- GetScrollBarSizes(sizeSb);
-
- // adjust the window size based on the state
- if (sizeRange.cy > 0)
- { // vertical scroll bars take up horizontal space
- lpClientRect->right += sizeSb.cx;
- }
- if (sizeRange.cx > 0)
- { // horizontal scroll bars take up vertical space
- lpClientRect->bottom += sizeSb.cy;
- }
- }
- }
- else
- {
- // call default to handle other non-client areas
- ::AdjustWindowRectEx(lpClientRect, GetStyle(), FALSE,
- GetExStyle() & ~(WS_EX_CLIENTEDGE));
- }
- }
-
- /////////////////////////////////////////////////////////////////////////////
- // CScrollView scrolling
-
- void CScrollView::OnHScroll(UINT nSBCode, UINT nPos, CScrollBar* pScrollBar)
- {
- if (pScrollBar != NULL && pScrollBar->SendChildNotifyLastMsg())
- return; // eat it
-
- // ignore scroll bar msgs from other controls
- if (pScrollBar != GetScrollBarCtrl(SB_HORZ))
- return;
-
- OnScroll(MAKEWORD(nSBCode, -1), nPos);
- }
-
- void CScrollView::OnVScroll(UINT nSBCode, UINT nPos, CScrollBar* pScrollBar)
- {
- if (pScrollBar != NULL && pScrollBar->SendChildNotifyLastMsg())
- return; // eat it
-
- // ignore scroll bar msgs from other controls
- if (pScrollBar != GetScrollBarCtrl(SB_VERT))
- return;
-
- OnScroll(MAKEWORD(-1, nSBCode), nPos);
- }
-
- BOOL CScrollView::OnMouseWheel(UINT fFlags, short zDelta, CPoint point)
- {
- // we don't handle anything but scrolling just now
- if (fFlags & (MK_SHIFT | MK_CONTROL))
- return FALSE;
-
- // if the parent is a splitter, it will handle the message
- if (GetParentSplitter(this, TRUE))
- return FALSE;
-
- // we can't get out of it--perform the scroll ourselves
- return DoMouseWheel(fFlags, zDelta, point);
- }
-
- // This function isn't virtual. If you need to override it,
- // you really need to override OnMouseWheel() here or in
- // CSplitterWnd.
-
- BOOL CScrollView::DoMouseWheel(UINT fFlags, short zDelta, CPoint point)
- {
- UNUSED_ALWAYS(point);
- UNUSED_ALWAYS(fFlags);
-
- // if we have a vertical scroll bar, the wheel scrolls that
- // if we have _only_ a horizontal scroll bar, the wheel scrolls that
- // otherwise, don't do any work at all
-
- DWORD dwStyle = GetStyle();
- CScrollBar* pBar = GetScrollBarCtrl(SB_VERT);
- BOOL bHasVertBar = ((pBar != NULL) && pBar->IsWindowEnabled()) ||
- (dwStyle & WS_VSCROLL);
-
- pBar = GetScrollBarCtrl(SB_HORZ);
- BOOL bHasHorzBar = ((pBar != NULL) && pBar->IsWindowEnabled()) ||
- (dwStyle & WS_HSCROLL);
-
- if (!bHasVertBar && !bHasHorzBar)
- return FALSE;
-
- BOOL bResult = FALSE;
- UINT uWheelScrollLines = _AfxGetMouseScrollLines();
- int nToScroll;
- int nDisplacement;
-
- if (bHasVertBar)
- {
- nToScroll = ::MulDiv(-zDelta, uWheelScrollLines, WHEEL_DELTA);
- if (nToScroll == -1 || uWheelScrollLines == WHEEL_PAGESCROLL)
- {
- nDisplacement = m_pageDev.cy;
- if (zDelta > 0)
- nDisplacement = -nDisplacement;
- }
- else
- {
- nDisplacement = nToScroll * m_lineDev.cy;
- nDisplacement = min(nDisplacement, m_pageDev.cy);
- }
- bResult = OnScrollBy(CSize(0, nDisplacement), TRUE);
- }
- else if (bHasHorzBar)
- {
- nToScroll = ::MulDiv(-zDelta, uWheelScrollLines, WHEEL_DELTA);
- if (nToScroll == -1 || uWheelScrollLines == WHEEL_PAGESCROLL)
- {
- nDisplacement = m_pageDev.cx;
- if (zDelta > 0)
- nDisplacement = -nDisplacement;
- }
- else
- {
- nDisplacement = nToScroll * m_lineDev.cx;
- nDisplacement = min(nDisplacement, m_pageDev.cx);
- }
- bResult = OnScrollBy(CSize(nDisplacement, 0), TRUE);
- }
-
- if (bResult)
- UpdateWindow();
-
- return bResult;
- }
-
-
- BOOL CScrollView::OnScroll(UINT nScrollCode, UINT nPos, BOOL bDoScroll)
- {
- // calc new x position
- int x = GetScrollPos(SB_HORZ);
- int xOrig = x;
-
- switch (LOBYTE(nScrollCode))
- {
- case SB_TOP:
- x = 0;
- break;
- case SB_BOTTOM:
- x = INT_MAX;
- break;
- case SB_LINEUP:
- x -= m_lineDev.cx;
- break;
- case SB_LINEDOWN:
- x += m_lineDev.cx;
- break;
- case SB_PAGEUP:
- x -= m_pageDev.cx;
- break;
- case SB_PAGEDOWN:
- x += m_pageDev.cx;
- break;
- case SB_THUMBTRACK:
- x = nPos;
- break;
- }
-
- // calc new y position
- int y = GetScrollPos(SB_VERT);
- int yOrig = y;
-
- switch (HIBYTE(nScrollCode))
- {
- case SB_TOP:
- y = 0;
- break;
- case SB_BOTTOM:
- y = INT_MAX;
- break;
- case SB_LINEUP:
- y -= m_lineDev.cy;
- break;
- case SB_LINEDOWN:
- y += m_lineDev.cy;
- break;
- case SB_PAGEUP:
- y -= m_pageDev.cy;
- break;
- case SB_PAGEDOWN:
- y += m_pageDev.cy;
- break;
- case SB_THUMBTRACK:
- y = nPos;
- break;
- }
-
- BOOL bResult = OnScrollBy(CSize(x - xOrig, y - yOrig), bDoScroll);
- if (bResult && bDoScroll)
- UpdateWindow();
-
- return bResult;
- }
-
- BOOL CScrollView::OnScrollBy(CSize sizeScroll, BOOL bDoScroll)
- {
- int xOrig, x;
- int yOrig, y;
-
- // don't scroll if there is no valid scroll range (ie. no scroll bar)
- CScrollBar* pBar;
- DWORD dwStyle = GetStyle();
- pBar = GetScrollBarCtrl(SB_VERT);
- if ((pBar != NULL && !pBar->IsWindowEnabled()) ||
- (pBar == NULL && !(dwStyle & WS_VSCROLL)))
- {
- // vertical scroll bar not enabled
- sizeScroll.cy = 0;
- }
- pBar = GetScrollBarCtrl(SB_HORZ);
- if ((pBar != NULL && !pBar->IsWindowEnabled()) ||
- (pBar == NULL && !(dwStyle & WS_HSCROLL)))
- {
- // horizontal scroll bar not enabled
- sizeScroll.cx = 0;
- }
-
- // adjust current x position
- xOrig = x = GetScrollPos(SB_HORZ);
- int xMax = GetScrollLimit(SB_HORZ);
- x += sizeScroll.cx;
- if (x < 0)
- x = 0;
- else if (x > xMax)
- x = xMax;
-
- // adjust current y position
- yOrig = y = GetScrollPos(SB_VERT);
- int yMax = GetScrollLimit(SB_VERT);
- y += sizeScroll.cy;
- if (y < 0)
- y = 0;
- else if (y > yMax)
- y = yMax;
-
- // did anything change?
- if (x == xOrig && y == yOrig)
- return FALSE;
-
- if (bDoScroll)
- {
- // do scroll and update scroll positions
- ScrollWindow(-(x-xOrig), -(y-yOrig));
- if (x != xOrig)
- SetScrollPos(SB_HORZ, x);
- if (y != yOrig)
- SetScrollPos(SB_VERT, y);
- }
- return TRUE;
- }
-
- /////////////////////////////////////////////////////////////////////////////
- // CScrollView diagnostics
-
- #ifdef _DEBUG
- void CScrollView::Dump(CDumpContext& dc) const
- {
- CView::Dump(dc);
-
- dc << "m_totalLog = " << m_totalLog;
- dc << "\nm_totalDev = " << m_totalDev;
- dc << "\nm_pageDev = " << m_pageDev;
- dc << "\nm_lineDev = " << m_lineDev;
- dc << "\nm_bCenter = " << m_bCenter;
- dc << "\nm_bInsideUpdate = " << m_bInsideUpdate;
- dc << "\nm_nMapMode = ";
- switch (m_nMapMode)
- {
- case MM_NONE:
- dc << "MM_NONE";
- break;
- case MM_SCALETOFIT:
- dc << "MM_SCALETOFIT";
- break;
- case MM_TEXT:
- dc << "MM_TEXT";
- break;
- case MM_LOMETRIC:
- dc << "MM_LOMETRIC";
- break;
- case MM_HIMETRIC:
- dc << "MM_HIMETRIC";
- break;
- case MM_LOENGLISH:
- dc << "MM_LOENGLISH";
- break;
- case MM_HIENGLISH:
- dc << "MM_HIENGLISH";
- break;
- case MM_TWIPS:
- dc << "MM_TWIPS";
- break;
- default:
- dc << "*unknown*";
- break;
- }
-
- dc << "\n";
- }
-
- void CScrollView::AssertValid() const
- {
- CView::AssertValid();
-
- switch (m_nMapMode)
- {
- case MM_NONE:
- case MM_SCALETOFIT:
- case MM_TEXT:
- case MM_LOMETRIC:
- case MM_HIMETRIC:
- case MM_LOENGLISH:
- case MM_HIENGLISH:
- case MM_TWIPS:
- break;
- case MM_ISOTROPIC:
- case MM_ANISOTROPIC:
- ASSERT(FALSE); // illegal mapping mode
- default:
- ASSERT(FALSE); // unknown mapping mode
- }
- }
- #endif //_DEBUG
-
- #ifdef AFX_INIT_SEG
- #pragma code_seg(AFX_INIT_SEG)
- #endif
-
- IMPLEMENT_DYNAMIC(CScrollView, CView)
-
- /////////////////////////////////////////////////////////////////////////////
-