GME  13
ScrollZoomView.cpp
Go to the documentation of this file.
00001 // SrollZoomView.cpp : implementation file
00002 //
00003 
00004 
00005 #include "stdafx.h"
00006 #include "ScrollZoomView.h"
00007 #include <afxpriv.h>
00008 //#include "GMEApp.h"
00009 //#include "Mainfrm.h"
00010 //
00011 
00012 #ifdef _DEBUG
00013 #define new DEBUG_NEW
00014 #undef THIS_FILE
00015 static char THIS_FILE[] = __FILE__;
00016 #endif
00017 
00018 #define CX_BORDER   1
00019 #define CY_BORDER   1
00020 
00022 // CScrollZoomView
00023 IMPLEMENT_DYNAMIC(CScrollZoomView, CView)
00024 BEGIN_MESSAGE_MAP(CScrollZoomView, CView)
00025         //{{AFX_MSG_MAP(CScrollZoomView)
00026         ON_WM_SIZE()
00027         ON_WM_HSCROLL()
00028         ON_WM_VSCROLL()
00029         ON_WM_MOUSEWHEEL()
00030         //}}AFX_MSG_MAP
00031 END_MESSAGE_MAP()
00032 
00033 // Special mapping modes just for CScrollZoomView implementation
00034 #define MM_NONE             0
00035 #define MM_SCALETOFIT       (-1)
00036         // standard GDI mapping modes are > 0
00037 
00038 
00039 UINT PASCAL _AfxGetMouseScrollLines()
00040 {
00041         static UINT uCachedScrollLines;
00042 
00043         // if we've already got it and we're not refreshing,
00044         // return what we've already got
00045 
00046         static UINT msgGetScrollLines;
00047         static WORD nRegisteredMessage;
00048 
00049         if (nRegisteredMessage == 0)
00050         {
00051                 msgGetScrollLines = ::RegisterWindowMessage(MSH_SCROLL_LINES);
00052                 if (msgGetScrollLines == 0)
00053                         nRegisteredMessage = 1;     // couldn't register!  never try again
00054                 else
00055                         nRegisteredMessage = 2;     // it worked: use it
00056         }
00057 
00058         if (nRegisteredMessage == 2)
00059         {
00060                 HWND hwMouseWheel = NULL;
00061                 hwMouseWheel = FindWindow(MSH_WHEELMODULE_CLASS, MSH_WHEELMODULE_TITLE);
00062                 if (hwMouseWheel && msgGetScrollLines)
00063                 {
00064                         uCachedScrollLines = (UINT)
00065                                 ::SendMessage(hwMouseWheel, msgGetScrollLines, 0, 0);
00066                         return uCachedScrollLines;
00067                 }
00068         }
00069 
00070         // couldn't use the window -- try system settings
00071         uCachedScrollLines = 3; // reasonable default
00072         DWORD dwVersion = ::GetVersion();
00073         bool bWin95 = (dwVersion & 0x80000000) != 0;
00074         bool bWin4 = (BYTE)dwVersion >= 4;
00075         if (!bWin4)
00076         {
00077                 HKEY hKey;
00078                 if (RegOpenKeyEx(HKEY_CURRENT_USER,  _T("Control Panel\\Desktop"),
00079                                 0, KEY_QUERY_VALUE, &hKey) == ERROR_SUCCESS)
00080                 {
00081                         TCHAR szData[128];
00082                         DWORD dwKeyDataType;
00083                         DWORD dwDataBufSize = sizeof(szData)/sizeof(TCHAR);
00084 
00085                         if (RegQueryValueEx(hKey, _T("WheelScrollLines"), NULL, &dwKeyDataType,
00086                                         (LPBYTE) &szData, &dwDataBufSize) == ERROR_SUCCESS)
00087                         {
00088                                 uCachedScrollLines = _tcstoul(szData, NULL, 10);
00089                         }
00090                         RegCloseKey(hKey);
00091                 }
00092         }
00093         else if (!bWin95)
00094         {
00095                 ::SystemParametersInfo(SPI_GETWHEELSCROLLLINES, 0, &uCachedScrollLines, 0);
00096         }
00097 
00098         return uCachedScrollLines;
00099 }
00100 
00102 // CScrollZoomView construction/destruction
00103 
00104 CScrollZoomView::CScrollZoomView()
00105 {
00106         // Init everything to zero
00107         AFX_ZERO_INIT_OBJECT(CView);
00108 
00109         m_nMapMode = MM_NONE;
00110         m_zoomP.x = m_zoomP.y = 0;
00111         m_zoomScroll = false;
00112         m_noHscroll = true; // hack terge
00113         m_noVscroll = true; // hack terge
00114 
00115 }
00116 
00117 CScrollZoomView::~CScrollZoomView()
00118 {
00119 }
00120 
00122 // CScrollZoomView painting
00123 
00124 void CScrollZoomView::OnPrepareDC(CDC* pDC, CPrintInfo* pInfo)
00125 {
00126         ASSERT_VALID(pDC);
00127 
00128 #ifdef _DEBUG
00129         if (m_nMapMode == MM_NONE)
00130         {
00131                 TRACE0("Error: must call SetScrollSizes() or SetScaleToFitSize()");
00132                 TRACE0("\tbefore painting scroll view.\n");
00133                 ASSERT(FALSE);
00134                 return;
00135         }
00136 #endif //_DEBUG
00137         ASSERT(m_totalDev.cx >= 0 && m_totalDev.cy >= 0);
00138         switch (m_nMapMode)
00139         {
00140         case MM_SCALETOFIT:
00141                 pDC->SetMapMode(MM_ANISOTROPIC);
00142                 pDC->SetWindowExt(m_totalLog);  // window is in logical coordinates
00143                 pDC->SetViewportExt(m_totalDev);
00144                 if (m_totalDev.cx == 0 || m_totalDev.cy == 0)
00145                         TRACE0("Warning: CScrollZoomView scaled to nothing.\n");
00146                 break;
00147 
00148         case MM_ISOTROPIC:
00149                 pDC->SetMapMode(m_nMapMode);
00150                 pDC->SetWindowExt(100,100);
00151                 pDC->SetViewportExt(m_scalePercent, m_scalePercent);
00152                 break;
00153         default:
00154                 ASSERT(m_nMapMode > 0);
00155                 pDC->SetMapMode(m_nMapMode);
00156                 break;
00157         }
00158 
00159         CPoint ptVpOrg(0, 0);       // assume no shift for printing
00160         if (!pDC->IsPrinting())
00161         {
00162                 ASSERT(pDC->GetWindowOrg() == CPoint(0,0));
00163 
00164                 // by default shift viewport origin in negative direction of scroll
00165                 ptVpOrg = -GetDeviceScrollPosition();
00166 
00167                 if (m_bCenter)
00168                 {
00169                         CRect rect;
00170                         GetClientRect(&rect);
00171 
00172                         // if client area is larger than total device size,
00173                         // override scroll positions to place origin such that
00174                         // output is centered in the window
00175                         if (m_totalDev.cx < rect.Width())
00176                                 ptVpOrg.x = (rect.Width() - m_totalDev.cx) / 2;
00177                         if (m_totalDev.cy < rect.Height())
00178                                 ptVpOrg.y = (rect.Height() - m_totalDev.cy) / 2;
00179                 }
00180         }
00181         pDC->SetViewportOrg(ptVpOrg); 
00182 
00183         CView::OnPrepareDC(pDC, pInfo);     // For default Printing behavior
00184 }
00185 
00187 // Set mode and scaling/scrolling sizes
00188 
00189 void CScrollZoomView::SetScaleToFitSize(SIZE sizeTotal)
00190 {
00191         // Note: It is possible to set sizeTotal members to negative values to
00192         //  effectively invert either the X or Y axis.
00193 
00194         ASSERT(m_hWnd != NULL);
00195         m_nMapMode = MM_SCALETOFIT;     // special internal value
00196         m_totalLog = sizeTotal;
00197 
00198         // reset and turn any scroll bars off
00199         if (m_hWnd != NULL && (GetStyle() & (WS_HSCROLL|WS_VSCROLL)))
00200         {
00201                 SetScrollPos(SB_HORZ, 0);
00202                 SetScrollPos(SB_VERT, 0);
00203                 EnableScrollBarCtrl(SB_BOTH, FALSE);
00204                 m_noHscroll = true; // hack terge
00205                 m_noVscroll = true; // hack terge
00206                 SetScrollRange(SB_HORZ, 0, 0, TRUE);
00207                 SetScrollRange(SB_VERT, 0, 0, TRUE);
00208                 ASSERT((GetStyle() & (WS_HSCROLL|WS_VSCROLL)) == 0);
00209         }
00210 
00211         CRect rectT;
00212         GetClientRect(rectT);
00213         m_totalDev = rectT.Size();
00214 
00215         if (m_hWnd != NULL)
00216         {
00217                 // window has been created, invalidate
00218                 UpdateBars();
00219                 Invalidate(TRUE);
00220         }
00221 }
00222 
00223 const AFX_DATADEF SIZE CScrollZoomView::sizeDefault = {0,0};
00224 
00225 void CScrollZoomView::SetScrollSizes(int nMapMode, SIZE sizeTotal, int scalePercent, 
00226         const SIZE& sizePage, const SIZE& sizeLine)
00227 {
00228         ASSERT(sizeTotal.cx >= 0 && sizeTotal.cy >= 0);
00229         ASSERT(nMapMode > 0);
00230         ASSERT(nMapMode != MM_ANISOTROPIC);
00231 
00232         int nOldMapMode = m_nMapMode;
00233         m_nMapMode = nMapMode;
00234         m_totalLog = sizeTotal;
00235         m_scalePercent = scalePercent;
00236 
00237         //BLOCK: convert logical coordinate space to device coordinates
00238         {
00239                 CWindowDC dc(NULL);
00240                 ASSERT(m_nMapMode > 0);
00241                 dc.SetMapMode(m_nMapMode);
00242                 if (m_nMapMode == MM_ISOTROPIC) {
00243                         dc.SetWindowExt(100,100);
00244                         dc.SetViewportExt(scalePercent, scalePercent);
00245                 }
00246 
00247                 // total size
00248                 m_totalDev = m_totalLog;
00249                 dc.LPtoDP((LPPOINT)&m_totalDev);
00250                 m_pageDev = sizePage;
00251                 dc.LPtoDP((LPPOINT)&m_pageDev);
00252                 m_lineDev = sizeLine;
00253                 dc.LPtoDP((LPPOINT)&m_lineDev);
00254                 if (m_totalDev.cy < 0)
00255                         m_totalDev.cy = -m_totalDev.cy;
00256                 if (m_pageDev.cy < 0)
00257                         m_pageDev.cy = -m_pageDev.cy;
00258                 if (m_lineDev.cy < 0)
00259                         m_lineDev.cy = -m_lineDev.cy;
00260         } // release DC here
00261 
00262         // now adjust device specific sizes
00263         ASSERT(m_totalDev.cx >= 0 && m_totalDev.cy >= 0);
00264         if (m_pageDev.cx == 0)
00265                 m_pageDev.cx = m_totalDev.cx / 10;
00266         if (m_pageDev.cy == 0)
00267                 m_pageDev.cy = m_totalDev.cy / 10;
00268         if (m_lineDev.cx == 0)
00269                 m_lineDev.cx = m_pageDev.cx / 10;
00270         if (m_lineDev.cy == 0)
00271                 m_lineDev.cy = m_pageDev.cy / 10;
00272 
00273         if (m_hWnd != NULL)
00274         {
00275                 // set scroll position after zoom
00276                 // window has been created, invalidate now
00277                 UpdateBars();
00278                 if (nOldMapMode != m_nMapMode)
00279                         Invalidate(TRUE);
00280         }
00281 }
00282 
00284 // Getting information
00285 
00286 CPoint CScrollZoomView::GetScrollPosition() const   // logical coordinates
00287 {
00288         if (m_nMapMode == MM_SCALETOFIT)
00289         {
00290                 return CPoint(0, 0);    // must be 0,0
00291         }
00292 
00293         CPoint pt = GetDeviceScrollPosition();
00294         // pt may be negative if m_bCenter is set
00295 
00296         if (m_nMapMode != MM_TEXT)
00297         {
00298                 ASSERT(m_nMapMode > 0); // must be set
00299                 CWindowDC dc(NULL);
00300                 dc.SetMapMode(m_nMapMode);
00301                 if (m_nMapMode == MM_ISOTROPIC) {
00302                         dc.SetWindowExt(100,100);
00303                         dc.SetViewportExt(m_scalePercent, m_scalePercent);
00304                 }
00305                 dc.DPtoLP((LPPOINT)&pt);
00306         }
00307         return pt;
00308 }
00309 
00310 void CScrollZoomView::ScrollToPosition(POINT pt)    // logical coordinates
00311 {
00312         ASSERT(m_nMapMode > 0);     // not allowed for shrink to fit
00313         if (m_nMapMode != MM_TEXT)
00314         {
00315                 CWindowDC dc(NULL);
00316                 dc.SetMapMode(m_nMapMode);
00317                 if (m_nMapMode == MM_ISOTROPIC) {
00318                         dc.SetWindowExt(100,100);
00319                         dc.SetViewportExt(m_scalePercent, m_scalePercent);
00320                 }
00321                 dc.LPtoDP((LPPOINT)&pt);
00322         }
00323 
00324         // now in device coordinates - limit if out of range
00325         int xMax = GetScrollLimit(SB_HORZ);
00326         int yMax = GetScrollLimit(SB_VERT);
00327 //      int xMin, xMax, yMin, yMax;
00328 //      GetScrollRange(SB_HORZ, &xMin, &xMax); // it does not work correctly ?? !!
00329 //      GetScrollRange(SB_VERT, &yMin, &yMax);
00330         if (m_noHscroll)   // hack terge
00331         {
00332                 xMax = 0;
00333         }
00334         if (m_noVscroll)   // hack terge
00335         {
00336                 yMax = 0;
00337         }
00338 
00339         // terge ?? szar van
00340 
00341         if (pt.x < 0)
00342                 pt.x = 0;
00343         else if (pt.x > xMax)
00344                 pt.x = xMax;
00345         if (pt.y < 0)
00346                 pt.y = 0;
00347         else if (pt.y > yMax)
00348                 pt.y = yMax;
00349 
00350         ScrollToDevicePosition(pt);
00351 }
00352 
00353 CPoint CScrollZoomView::GetDeviceScrollPosition() const
00354 {
00355         CPoint pt(GetScrollPos(SB_HORZ), GetScrollPos(SB_VERT));
00356         ASSERT(pt.x >= 0 && pt.y >= 0);
00357 
00358         if (m_bCenter)
00359         {
00360                 CRect rect;
00361                 GetClientRect(&rect);
00362 
00363                 // if client area is larger than total device size,
00364                 // the scroll positions are overridden to place origin such that
00365                 // output is centered in the window
00366                 // GetDeviceScrollPosition() must reflect this
00367 
00368                 if (m_totalDev.cx < rect.Width())
00369                         pt.x = -((rect.Width() - m_totalDev.cx) / 2);
00370                 if (m_totalDev.cy < rect.Height())
00371                         pt.y = -((rect.Height() - m_totalDev.cy) / 2);
00372         }
00373 
00374         return pt;
00375 }
00376 
00377 void CScrollZoomView::GetDeviceScrollSizes(int& nMapMode, SIZE& sizeTotal,
00378                         SIZE& sizePage, SIZE& sizeLine) const
00379 {
00380         if (m_nMapMode <= 0)
00381                 TRACE0("Warning: CScrollZoomView::GetDeviceScrollSizes returning invalid mapping mode.\n");
00382         nMapMode = m_nMapMode;
00383         sizeTotal = m_totalDev;
00384         sizePage = m_pageDev;
00385         sizeLine = m_lineDev;
00386 }
00387 
00388 void CScrollZoomView::notifyPanning(CPoint pt)
00389 {
00390 //      CMainFrame* main = (CMainFrame*)AfxGetMainWnd();
00391 //      CMainFrame* main = (CMainFrame*)theApp.m_pMainWnd;
00392 
00393 //      if (!main || !main->m_panningWindow.IsVisible())
00394 //              return;
00395         CRect client;
00396         GetClientRect(&client);
00397         CWindowDC dc(NULL);
00398         dc.SetMapMode(MM_ISOTROPIC);
00399         dc.SetWindowExt(100,100);
00400         dc.SetViewportExt(m_scalePercent, m_scalePercent);
00401         dc.DPtoLP((LPPOINT)&pt);
00402         dc.DPtoLP(&client);
00403         CRect pannw(pt.x, pt.y, pt.x+client.Width(), pt.y+client.Height());
00404         pannw.NormalizeRect();
00405 
00406 //      main->m_panningWindow.SetViewRect(pannw);
00407 }
00408 
00409 void CScrollZoomView::ScrollToDevicePosition(POINT ptDev)
00410 {
00411         ASSERT(ptDev.x >= 0);
00412         ASSERT(ptDev.y >= 0);
00413         int maxh = GetScrollLimit(SB_HORZ);
00414         int maxv = GetScrollLimit(SB_VERT);
00415 //      int xMin, yMin;
00416 //      GetScrollRange(SB_HORZ, &xMin, &maxh);
00417 //      GetScrollRange(SB_VERT, &yMin, &maxv);
00418         if (maxh == 0  &&  maxv == 0)
00419         {
00420                 TRACE("notifyPanning from ScrollToDevicePosition - maxh == 0  &&  maxv == 0\n");
00421                 notifyPanning(ptDev);
00422                 return;
00423         }
00424 
00425         // Note: ScrollToDevicePosition can and is used to scroll out-of-range
00426         //  areas as far as CScrollZoomView is concerned -- specifically in
00427         //  the print-preview code.  Since OnScrollBy makes sure the range is
00428         //  valid, ScrollToDevicePosition does not vector through OnScrollBy.
00429 
00430         int xOrig = GetScrollPos(SB_HORZ);
00431         SetScrollPos(SB_HORZ, ptDev.x);
00432         int yOrig = GetScrollPos(SB_VERT);
00433         SetScrollPos(SB_VERT, ptDev.y);
00434         ptDev.x = (maxh<ptDev.x)? maxh: ptDev.x; 
00435         ptDev.y = (maxv<ptDev.y)? maxv: ptDev.y;
00436         TRACE("notifyPanning from ScrollToDevicePosition\n");
00437         notifyPanning(ptDev);
00438 //      ScrollWindow(xOrig - ptDev.x, yOrig - ptDev.y);
00439         ScrollWindow((ptDev.x -xOrig), (ptDev.y -yOrig) );
00440 }
00441 
00443 // Other helpers
00444 
00445 void CScrollZoomView::FillOutsideRect(CDC* pDC, CBrush* pBrush)
00446 {
00447         ASSERT_VALID(pDC);
00448         ASSERT_VALID(pBrush);
00449 
00450         // fill rect outside the image
00451         CRect rect;
00452         GetClientRect(rect);
00453         ASSERT(rect.left == 0 && rect.top == 0);
00454         rect.left = m_totalDev.cx;
00455         if (!rect.IsRectEmpty())
00456                 pDC->FillRect(rect, pBrush);    // vertical strip along the side
00457         rect.left = 0;
00458         rect.right = m_totalDev.cx;
00459         rect.top = m_totalDev.cy;
00460         if (!rect.IsRectEmpty())
00461                 pDC->FillRect(rect, pBrush);    // horizontal strip along the bottom
00462 }
00463 
00464 void CScrollZoomView::ResizeParentToFit(BOOL bShrinkOnly)
00465 {
00466         // adjust parent rect so client rect is appropriate size
00467         ASSERT(m_nMapMode != MM_NONE);  // mapping mode must be known
00468 
00469         // determine current size of the client area as if no scrollbars present
00470         CRect rectClient;
00471         GetWindowRect(rectClient);
00472         CRect rect = rectClient;
00473         CalcWindowRect(rect);
00474         rectClient.left += rectClient.left - rect.left;
00475         rectClient.top += rectClient.top - rect.top;
00476         rectClient.right -= rect.right - rectClient.right;
00477         rectClient.bottom -= rect.bottom - rectClient.bottom;
00478         rectClient.OffsetRect(-rectClient.left, -rectClient.top);
00479         ASSERT(rectClient.left == 0 && rectClient.top == 0);
00480 
00481         // determine desired size of the view
00482         CRect rectView(0, 0, m_totalDev.cx, m_totalDev.cy);
00483         if (bShrinkOnly)
00484         {
00485                 if (rectClient.right <= m_totalDev.cx)
00486                         rectView.right = rectClient.right;
00487                 if (rectClient.bottom <= m_totalDev.cy)
00488                         rectView.bottom = rectClient.bottom;
00489         }
00490         CalcWindowRect(rectView, CView::adjustOutside);
00491         rectView.OffsetRect(-rectView.left, -rectView.top);
00492         ASSERT(rectView.left == 0 && rectView.top == 0);
00493         if (bShrinkOnly)
00494         {
00495                 if (rectClient.right <= m_totalDev.cx)
00496                         rectView.right = rectClient.right;
00497                 if (rectClient.bottom <= m_totalDev.cy)
00498                         rectView.bottom = rectClient.bottom;
00499         }
00500 
00501         // dermine and set size of frame based on desired size of view
00502         CRect rectFrame;
00503         CFrameWnd* pFrame = GetParentFrame();
00504         ASSERT_VALID(pFrame);
00505         pFrame->GetWindowRect(rectFrame);
00506         CSize size = rectFrame.Size();
00507         size.cx += rectView.right - rectClient.right;
00508         size.cy += rectView.bottom - rectClient.bottom;
00509         pFrame->SetWindowPos(NULL, 0, 0, size.cx, size.cy,
00510                 SWP_NOMOVE|SWP_NOZORDER|SWP_NOACTIVATE);
00511 }
00512 
00514 
00515 void CScrollZoomView::OnSize(UINT nType, int cx, int cy)
00516 {
00517         CView::OnSize(nType, cx, cy);
00518         if (m_nMapMode == MM_SCALETOFIT)
00519         {
00520                 // force recalculation of scale to fit parameters
00521                 SetScaleToFitSize(m_totalLog);
00522         }
00523         else
00524         {
00525                 // UpdateBars() handles locking out recursion
00526                 UpdateBars();
00527         }
00528 }
00529 
00531 // Scrolling Helpers
00532 
00533 void CScrollZoomView::CenterOnPoint(CPoint ptCenter) // center in device coords
00534 {
00535         CRect rect;
00536         GetClientRect(&rect);           // find size of client window
00537 
00538         int xDesired = ptCenter.x - rect.Width() / 2;
00539         int yDesired = ptCenter.y - rect.Height() / 2;
00540 
00541         DWORD dwStyle = GetStyle();
00542 
00543         if ((dwStyle & WS_HSCROLL) == 0 || xDesired < 0)
00544         {
00545                 xDesired = 0;
00546         }
00547         else
00548         {
00549 //              int xMin, xMax;
00550 //              GetScrollRange(SB_HORZ, &xMin, &xMax);
00551                 int xMax = GetScrollLimit(SB_HORZ);
00552                 if (xDesired > xMax)
00553                         xDesired = xMax;
00554         }
00555 
00556         if ((dwStyle & WS_VSCROLL) == 0 || yDesired < 0)
00557         {
00558                 yDesired = 0;
00559         }
00560         else
00561         {
00562 //              int yMin, yMax;
00563 //              GetScrollRange(SB_VERT, &yMin, &yMax);
00564                 int yMax = GetScrollLimit(SB_VERT);
00565                 if (yDesired > yMax)
00566                         yDesired = yMax;
00567         }
00568 
00569         ASSERT(xDesired >= 0);
00570         ASSERT(yDesired >= 0);
00571 
00572         SetScrollPos(SB_HORZ, xDesired);
00573         SetScrollPos(SB_VERT, yDesired);
00574 }
00575 
00577 // Tie to scrollbars and CView behaviour
00578 
00579 void CScrollZoomView::GetScrollBarSizes(CSize& sizeSb)
00580 {
00581         sizeSb.cx = sizeSb.cy = 0;
00582         DWORD dwStyle = GetStyle();
00583 
00584         if (GetScrollBarCtrl(SB_VERT) == NULL)
00585         {
00586                 // vert scrollbars will impact client area of this window
00587                 sizeSb.cx = GetSystemMetrics(SM_CXVSCROLL) + CX_BORDER;
00588                 if (dwStyle & WS_BORDER)
00589                         sizeSb.cx -= CX_BORDER;
00590         }
00591         if (GetScrollBarCtrl(SB_HORZ) == NULL)
00592         {
00593                 // horz scrollbars will impact client area of this window
00594                 sizeSb.cy = GetSystemMetrics(SM_CYHSCROLL) + CY_BORDER;
00595                 if (dwStyle & WS_BORDER)
00596                         sizeSb.cy -= CY_BORDER;
00597         }
00598 }
00599 
00600 BOOL CScrollZoomView::GetTrueClientSize(CSize& size, CSize& sizeSb)
00601         // return TRUE if enough room to add scrollbars if needed
00602 {
00603         CRect rect;
00604         GetClientRect(&rect);
00605         ASSERT(rect.top == 0 && rect.left == 0);
00606         size.cx = rect.right;
00607         size.cy = rect.bottom;
00608         DWORD dwStyle = GetStyle();
00609 
00610         // first get the size of the scrollbars for this window
00611         GetScrollBarSizes(sizeSb);
00612 
00613         // first calculate the size of a potential scrollbar
00614         // (scroll bar controls do not get turned on/off)
00615         if (sizeSb.cx != 0 && (dwStyle & WS_VSCROLL))
00616         {
00617                 // vert scrollbars will impact client area of this window
00618                 size.cx += sizeSb.cx;   // currently on - adjust now
00619         }
00620         if (sizeSb.cy != 0 && (dwStyle & WS_HSCROLL))
00621         {
00622                 // horz scrollbars will impact client area of this window
00623                 size.cy += sizeSb.cy;   // currently on - adjust now
00624         }
00625 
00626         // return TRUE if enough room
00627         return (size.cx > sizeSb.cx && size.cy > sizeSb.cy);
00628 }
00629 
00630 // helper to return the state of the scrollbars without actually changing
00631 //  the state of the scrollbars
00632 void CScrollZoomView::GetScrollBarState(CSize sizeClient, CSize& needSb,
00633         CSize& sizeRange, CPoint& ptMove, BOOL bInsideClient)
00634 {
00635         // get scroll bar sizes (the part that is in the client area)
00636         CSize sizeSb;
00637         GetScrollBarSizes(sizeSb);
00638 
00639         // enough room to add scrollbars
00640         sizeRange = m_totalDev - sizeClient;
00641                 // > 0 => need to scroll
00642         ptMove = GetDeviceScrollPosition();
00643                 // point to move to (start at current scroll pos)
00644 
00645         BOOL bNeedH = sizeRange.cx > 0;
00646         if (!bNeedH)
00647                 ptMove.x = 0;                       // jump back to origin
00648         else if (bInsideClient)
00649                 sizeRange.cy += sizeSb.cy;          // need room for a scroll bar
00650 
00651         BOOL bNeedV = sizeRange.cy > 0;
00652         if (!bNeedV)
00653                 ptMove.y = 0;                       // jump back to origin
00654         else if (bInsideClient)
00655                 sizeRange.cx += sizeSb.cx;          // need room for a scroll bar
00656 
00657         if (bNeedV && !bNeedH && sizeRange.cx > 0)
00658         {
00659                 ASSERT(bInsideClient);
00660                 // need a horizontal scrollbar after all
00661                 bNeedH = TRUE;
00662                 sizeRange.cy += sizeSb.cy;
00663         }
00664 
00665         // if current scroll position will be past the limit, scroll to limit
00666         if (sizeRange.cx > 0 && ptMove.x >= sizeRange.cx)
00667                 ptMove.x = sizeRange.cx;
00668         if (sizeRange.cy > 0 && ptMove.y >= sizeRange.cy)
00669                 ptMove.y = sizeRange.cy;
00670 
00671         // now update the bars as appropriate
00672         needSb.cx = bNeedH;
00673         needSb.cy = bNeedV;
00674 
00675         // needSb, sizeRange, and ptMove area now all updated
00676 }
00677 
00678 void CScrollZoomView::UpdateBars()
00679 {
00680         // UpdateBars may cause window to be resized - ignore those resizings
00681         if (m_bInsideUpdate)
00682                 return;         // Do not allow recursive calls
00683 
00684         // Lock out recursion
00685         m_bInsideUpdate = TRUE;
00686 
00687         // update the horizontal to reflect reality
00688         // NOTE: turning on/off the scrollbars will cause 'OnSize' callbacks
00689         ASSERT(m_totalDev.cx >= 0 && m_totalDev.cy >= 0);
00690 
00691         CRect rectClient;
00692         BOOL bCalcClient = TRUE;
00693 
00694         // allow parent to do inside-out layout first
00695         CWnd* pParentWnd = GetParent();
00696         if (pParentWnd != NULL)
00697         {
00698                 // if parent window responds to this message, use just
00699                 //  client area for scroll bar calc -- not "true" client area
00700                 if ((BOOL)pParentWnd->SendMessage(WM_RECALCPARENT, 0,
00701                         (LPARAM)(LPCRECT)&rectClient) != 0)
00702                 {
00703                         // use rectClient instead of GetTrueClientSize for
00704                         //  client size calculation.
00705                         bCalcClient = FALSE;
00706                 }
00707         }
00708 
00709         CSize sizeClient;
00710         CSize sizeSb;
00711 
00712         if (bCalcClient)
00713         {
00714                 // get client rect
00715                 if (!GetTrueClientSize(sizeClient, sizeSb))
00716                 {
00717                         // no room for scroll bars (common for zero sized elements)
00718                         CRect rect;
00719                         GetClientRect(&rect);
00720                         if (rect.right > 0 && rect.bottom > 0)
00721                         {
00722                                 // if entire client area is not invisible, assume we have
00723                                 //  control over our scrollbars
00724                                 SetScrollPos(SB_HORZ, 0);
00725                                 SetScrollPos(SB_VERT, 0);
00726                                 EnableScrollBarCtrl(SB_BOTH, FALSE);
00727                                 m_noHscroll = true; // hack terge
00728                                 m_noVscroll = true; // hack terge
00729                                 SetScrollRange(SB_HORZ, 0, 0, TRUE);
00730                                 SetScrollRange(SB_VERT, 0, 0, TRUE);
00731                         }
00732                         m_bInsideUpdate = FALSE;
00733 //                      notifyPanning(CPoint(0,0)); // ??
00734                         return;
00735                 }
00736         }
00737         else
00738         {
00739                 // let parent window determine the "client" rect
00740                 GetScrollBarSizes(sizeSb);
00741                 sizeClient.cx = rectClient.right - rectClient.left;
00742                 sizeClient.cy = rectClient.bottom - rectClient.top;
00743         }
00744 
00745         // enough room to add scrollbars
00746         CSize sizeRange;
00747         CPoint ptMove;
00748         CSize needSb;
00749 
00750         // get the current scroll bar state given the true client area
00751         GetScrollBarState(sizeClient, needSb, sizeRange, ptMove, bCalcClient);
00752         if (needSb.cx)
00753                 sizeClient.cy -= sizeSb.cy;
00754         if (needSb.cy)
00755                 sizeClient.cx -= sizeSb.cx;
00756 
00757         // first scroll the window as needed
00758         if (!m_zoomScroll)
00759         {
00760                 ScrollToDevicePosition(ptMove); // will set the scroll bar positions too
00761         }
00762 
00763         // this structure needed to update the scrollbar page range
00764         SCROLLINFO info;
00765         info.fMask = SIF_PAGE|SIF_RANGE;
00766         info.nMin = 0;
00767 
00768         // now update the bars as appropriate
00769         EnableScrollBarCtrl(SB_HORZ, needSb.cx);
00770         if (needSb.cx)
00771         {
00772                 m_noHscroll = false; // hack terge
00773                 info.nPage = sizeClient.cx;
00774                 info.nMax = m_totalDev.cx-1;
00775                 if (!SetScrollInfo(SB_HORZ, &info, TRUE)) 
00776                         SetScrollRange(SB_HORZ, 0, sizeRange.cx, TRUE);
00777         }
00778         else
00779         {
00780                 m_noHscroll = true; // hack terge
00781 //              DWORD err = 0;
00782 //              BOOL ret = TRUE;
00783                 SetScrollPos(SB_HORZ, 0);
00784                 SetScrollRange(SB_HORZ, 0, 0, TRUE);
00785 /*              CScrollBar* pScrollBar;
00786                 if ((pScrollBar = GetScrollBarCtrl(SB_HORZ)) != NULL)
00787                         pScrollBar->SetScrollRange(0, 0, TRUE);
00788                 else
00789                 {
00790                         ret = ::SetScrollRange(m_hWnd, SB_HORZ, 0, 0, TRUE);
00791                         if (!ret)
00792                                 err = GetLastError();
00793                 }*/
00794 //              int lxMin, lxMax;
00795 //              GetScrollRange(SB_HORZ, &lxMin, &lxMax);
00796         }
00797         EnableScrollBarCtrl(SB_VERT, needSb.cy);
00798 //      int ixMin, ixMax;
00799 //      GetScrollRange(SB_HORZ, &ixMin, &ixMax);
00800         if (needSb.cy)
00801         {
00802                 m_noVscroll = false; // hack terge
00803                 info.nPage = sizeClient.cy;
00804                 info.nMax = m_totalDev.cy-1;
00805                 if (!SetScrollInfo(SB_VERT, &info, TRUE))
00806                         SetScrollRange(SB_VERT, 0, sizeRange.cy, TRUE);
00807         }
00808         else
00809         {
00810                 m_noVscroll = true; // hack terge
00811                 SetScrollPos(SB_VERT, 0);
00812 //              int jxMin, jxMax;
00813 //              GetScrollRange(SB_HORZ, &jxMin, &jxMax);
00814                 SetScrollRange(SB_VERT, 0, 0, TRUE);
00815         }
00816 //      int pxMin, pxMax, pyMin, pyMax;
00818 //      GetScrollRange(SB_VERT, &pyMin, &pyMax);
00819         if (m_zoomScroll)
00820         {
00821                 ScrollToPosition(m_zoomP);    // logical coordinates
00822                 m_zoomP.x = m_zoomP.y = 0;
00823                 m_zoomScroll = false;
00824         }
00825 
00826         // remove recursion lockout
00827         m_bInsideUpdate = FALSE;
00828 }
00829 
00830 void CScrollZoomView::CalcWindowRect(LPRECT lpClientRect, UINT nAdjustType)
00831 {
00832         if (nAdjustType == adjustOutside)
00833         {
00834                 // allow for special client-edge style
00835                 ::AdjustWindowRectEx(lpClientRect, 0, FALSE, GetExStyle());
00836 
00837                 if (m_nMapMode != MM_SCALETOFIT)
00838                 {
00839                         // if the view is being used in-place, add scrollbar sizes
00840                         //  (scollbars should appear on the outside when in-place editing)
00841                         CSize sizeClient(
00842                                 lpClientRect->right - lpClientRect->left,
00843                                 lpClientRect->bottom - lpClientRect->top);
00844 
00845                         CSize sizeRange = m_totalDev - sizeClient;
00846                                 // > 0 => need to scroll
00847 
00848                         // get scroll bar sizes (used to adjust the window)
00849                         CSize sizeSb;
00850                         GetScrollBarSizes(sizeSb);
00851 
00852                         // adjust the window size based on the state
00853                         if (sizeRange.cy > 0)
00854                         {   // vertical scroll bars take up horizontal space
00855                                 lpClientRect->right += sizeSb.cx;
00856                         }
00857                         if (sizeRange.cx > 0)
00858                         {   // horizontal scroll bars take up vertical space
00859                                 lpClientRect->bottom += sizeSb.cy;
00860                         }
00861                 }
00862         }
00863         else
00864         {
00865                 // call default to handle other non-client areas
00866                 ::AdjustWindowRectEx(lpClientRect, GetStyle(), FALSE,
00867                         GetExStyle() & ~(WS_EX_CLIENTEDGE));
00868         }
00869 }
00870 
00872 // CScrollZoomView scrolling
00873 
00874 void CScrollZoomView::OnHScroll(UINT nSBCode, UINT nPos, CScrollBar* pScrollBar)
00875 {
00876         if (pScrollBar != NULL && pScrollBar->SendChildNotifyLastMsg())
00877                 return;     // eat it
00878 
00879         // ignore scroll bar msgs from other controls
00880         if (pScrollBar != NULL  &&  pScrollBar != GetScrollBarCtrl(SB_HORZ))
00881                 return;
00882 
00883         OnScroll(MAKEWORD(nSBCode, -1), nPos);
00884 }
00885 
00886 void CScrollZoomView::OnVScroll(UINT nSBCode, UINT nPos, CScrollBar* pScrollBar)
00887 {
00888         if (pScrollBar != NULL && pScrollBar->SendChildNotifyLastMsg())
00889                 return;     // eat it
00890 
00891         // ignore scroll bar msgs from other controls
00892         if (pScrollBar != NULL  &&  pScrollBar != GetScrollBarCtrl(SB_VERT))
00893                 return;
00894 
00895         OnScroll(MAKEWORD(-1, nSBCode), nPos);
00896 }
00897 
00898 BOOL CScrollZoomView::OnMouseWheel(UINT fFlags, short zDelta, CPoint point)
00899 {
00900         // we don't handle anything but scrolling just now
00901         if (fFlags & (MK_SHIFT | MK_CONTROL))
00902                 return FALSE;
00903 
00904         // we can't get out of it--perform the scroll ourselves
00905         return DoMouseWheel(fFlags, zDelta, point);
00906 }
00907 
00908 // This function isn't virtual. If you need to override it,
00909 // you really need to override OnMouseWheel() here or in
00910 // CSplitterWnd.
00911 
00912 BOOL CScrollZoomView::DoMouseWheel(UINT fFlags, short zDelta, CPoint point)
00913 {
00914         UNUSED_ALWAYS(point);
00915         UNUSED_ALWAYS(fFlags);
00916 
00917         // if we have a vertical scroll bar, the wheel scrolls that
00918         // if we have _only_ a horizontal scroll bar, the wheel scrolls that
00919         // otherwise, don't do any work at all
00920 
00921         DWORD dwStyle = GetStyle();
00922         CScrollBar* pBar = GetScrollBarCtrl(SB_VERT);
00923         BOOL bHasVertBar = ((pBar != NULL) && pBar->IsWindowEnabled()) ||
00924                                         (dwStyle & WS_VSCROLL);
00925 
00926         pBar = GetScrollBarCtrl(SB_HORZ);
00927         BOOL bHasHorzBar = ((pBar != NULL) && pBar->IsWindowEnabled()) ||
00928                                         (dwStyle & WS_HSCROLL);
00929 
00930         if (!bHasVertBar && !bHasHorzBar)
00931                 return FALSE;
00932 
00933         BOOL bResult = FALSE;
00934         UINT uWheelScrollLines = _AfxGetMouseScrollLines();
00935         int nToScroll;
00936         int nDisplacement;
00937 
00938         if (bHasVertBar)
00939         {
00940                 nToScroll = ::MulDiv(-zDelta, uWheelScrollLines, WHEEL_DELTA);
00941                 if (nToScroll == -1 || uWheelScrollLines == WHEEL_PAGESCROLL)
00942                 {
00943                         nDisplacement = m_pageDev.cy;
00944                         if (zDelta > 0)
00945                                 nDisplacement = -nDisplacement;
00946                 }
00947                 else
00948                 {
00949                         nDisplacement = nToScroll * m_lineDev.cy;
00950                         nDisplacement = (nDisplacement<m_pageDev.cy)? nDisplacement: m_pageDev.cy;
00951                 }
00952                 bResult = OnScrollBy(CSize(0, nDisplacement), TRUE);
00953         }
00954         else if (bHasHorzBar)
00955         {
00956                 nToScroll = ::MulDiv(-zDelta, uWheelScrollLines, WHEEL_DELTA);
00957                 if (nToScroll == -1 || uWheelScrollLines == WHEEL_PAGESCROLL)
00958                 {
00959                         nDisplacement = m_pageDev.cx;
00960                         if (zDelta > 0)
00961                                 nDisplacement = -nDisplacement;
00962                 }
00963                 else
00964                 {
00965                         nDisplacement = nToScroll * m_lineDev.cx;
00966                         nDisplacement = (nDisplacement<m_pageDev.cx)? nDisplacement: m_pageDev.cx;
00967                 }
00968                 bResult = OnScrollBy(CSize(nDisplacement, 0), TRUE);
00969         }
00970 
00971         if (bResult)
00972                 UpdateWindow();
00973 
00974         return bResult;
00975 }
00976 
00977 
00978 BOOL CScrollZoomView::OnScroll(UINT nScrollCode, UINT nPos, BOOL bDoScroll)
00979 {
00980         // calc new x position
00981         int x = GetScrollPos(SB_HORZ);
00982         int xOrig = x;
00983 
00984         switch (LOBYTE(nScrollCode))
00985         {
00986         case SB_TOP:
00987                 x = 0;
00988                 break;
00989         case SB_BOTTOM:
00990                 x = INT_MAX;
00991                 break;
00992         case SB_LINEUP:
00993                 x -= m_lineDev.cx;
00994                 break;
00995         case SB_LINEDOWN:
00996                 x += m_lineDev.cx;
00997                 break;
00998         case SB_PAGEUP:
00999                 x -= m_pageDev.cx;
01000                 break;
01001         case SB_PAGEDOWN:
01002                 x += m_pageDev.cx;
01003                 break;
01004         case SB_THUMBTRACK:
01005                 x = nPos;
01006                 break;
01007         }
01008 
01009         // calc new y position
01010         int y = GetScrollPos(SB_VERT);
01011         int yOrig = y;
01012 
01013         switch (HIBYTE(nScrollCode))
01014         {
01015         case SB_TOP:
01016                 y = 0;
01017                 break;
01018         case SB_BOTTOM:
01019                 y = INT_MAX;
01020                 break;
01021         case SB_LINEUP:
01022                 y -= m_lineDev.cy;
01023                 break;
01024         case SB_LINEDOWN:
01025                 y += m_lineDev.cy;
01026                 break;
01027         case SB_PAGEUP:
01028                 y -= m_pageDev.cy;
01029                 break;
01030         case SB_PAGEDOWN:
01031                 y += m_pageDev.cy;
01032                 break;
01033         case SB_THUMBTRACK:
01034                 y = nPos;
01035                 break;
01036         }
01037 
01038         BOOL bResult = OnScrollBy(CSize(x - xOrig, y - yOrig), bDoScroll);
01039         if (bResult && bDoScroll)
01040                 UpdateWindow();
01041 
01042         return bResult;
01043 }
01044 
01045 BOOL CScrollZoomView::OnScrollBy(CSize sizeScroll, BOOL bDoScroll)
01046 {
01047         int xOrig, x;
01048         int yOrig, y;
01049 
01050         // don't scroll if there is no valid scroll range (ie. no scroll bar)
01051         CScrollBar* pBar;
01052         DWORD dwStyle = GetStyle();
01053         pBar = GetScrollBarCtrl(SB_VERT);
01054         if ((pBar != NULL && !pBar->IsWindowEnabled()) ||
01055                 (pBar == NULL && !(dwStyle & WS_VSCROLL)))
01056         {
01057                 // vertical scroll bar not enabled
01058                 sizeScroll.cy = 0;
01059         }
01060         pBar = GetScrollBarCtrl(SB_HORZ);
01061         if ((pBar != NULL && !pBar->IsWindowEnabled()) ||
01062                 (pBar == NULL && !(dwStyle & WS_HSCROLL)))
01063         {
01064                 // horizontal scroll bar not enabled
01065                 sizeScroll.cx = 0;
01066         }
01067 
01068         // adjust current x position
01069         xOrig = x = GetScrollPos(SB_HORZ);
01070 //      int xMax, xMin;
01071 //      GetScrollRange(SB_HORZ, &xMin, &xMax);
01072         int xMax = GetScrollLimit(SB_HORZ);
01073         x += sizeScroll.cx;
01074         if (x < 0)
01075                 x = 0;
01076         else if (x > xMax)
01077                 x = xMax;
01078 
01079         // adjust current y position
01080         yOrig = y = GetScrollPos(SB_VERT);
01081 //      int yMin, yMax;
01082 //      GetScrollRange(SB_VERT, &yMin, &yMax);
01083         int yMax = GetScrollLimit(SB_VERT);
01084         y += sizeScroll.cy;
01085         if (y < 0)
01086                 y = 0;
01087         else if (y > yMax)
01088                 y = yMax;
01089 
01090         // did anything change?
01091         if (x == xOrig && y == yOrig)
01092                 return FALSE;
01093 
01094         if (bDoScroll)
01095         {
01096                 // do scroll and update scroll positions
01097                 ScrollWindow(-(x-xOrig), -(y-yOrig));
01098                 if (x != xOrig)
01099                         SetScrollPos(SB_HORZ, x);
01100                 if (y != yOrig)
01101                         SetScrollPos(SB_VERT, y);
01102         }
01103 
01104         // terge
01105         TRACE("notifyPanning from OnScrollBy\n");
01106         notifyPanning(GetDeviceScrollPosition());
01107 
01108         return TRUE;
01109 }
01110 
01112 // CScrollZoomView diagnostics
01113 
01114 #ifdef _DEBUG
01115 void CScrollZoomView::Dump(CDumpContext& dc) const
01116 {
01117         CView::Dump(dc);
01118 
01119         dc << "m_totalLog = " << m_totalLog;
01120         dc << "\nm_totalDev = " << m_totalDev;
01121         dc << "\nm_pageDev = " << m_pageDev;
01122         dc << "\nm_lineDev = " << m_lineDev;
01123         dc << "\nm_bCenter = " << m_bCenter;
01124         dc << "\nm_bInsideUpdate = " << m_bInsideUpdate;
01125         dc << "\nm_nMapMode = ";
01126         switch (m_nMapMode)
01127         {
01128         case MM_NONE:
01129                 dc << "MM_NONE";
01130                 break;
01131         case MM_SCALETOFIT:
01132                 dc << "MM_SCALETOFIT";
01133                 break;
01134         case MM_TEXT:
01135                 dc << "MM_TEXT";
01136                 break;
01137         case MM_LOMETRIC:
01138                 dc << "MM_LOMETRIC";
01139                 break;
01140         case MM_HIMETRIC:
01141                 dc << "MM_HIMETRIC";
01142                 break;
01143         case MM_LOENGLISH:
01144                 dc << "MM_LOENGLISH";
01145                 break;
01146         case MM_HIENGLISH:
01147                 dc << "MM_HIENGLISH";
01148                 break;
01149         case MM_TWIPS:
01150                 dc << "MM_TWIPS";
01151                 break;
01152         case MM_ISOTROPIC:
01153                 dc << "MM_ISOTROPIC";
01154                 break;
01155         default:
01156                 dc << "*unknown*";
01157                 break;
01158         }
01159 
01160         dc << "\n";
01161 }
01162 
01163 void CScrollZoomView::AssertValid() const
01164 {
01165         CView::AssertValid();
01166 
01167         switch (m_nMapMode)
01168         {
01169         case MM_NONE:
01170         case MM_SCALETOFIT:
01171         case MM_TEXT:
01172         case MM_LOMETRIC:
01173         case MM_HIMETRIC:
01174         case MM_LOENGLISH:
01175         case MM_HIENGLISH:
01176         case MM_TWIPS:
01177         case MM_ISOTROPIC:
01178                 break;
01179         case MM_ANISOTROPIC:
01180                 ASSERT(FALSE); // illegal mapping mode
01181         default:
01182                 ASSERT(FALSE); // unknown mapping mode
01183         }
01184 }
01185 #endif //_DEBUG
01186