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