home *** CD-ROM | disk | FTP | other *** search
/ Liren Large Software Subsidy 7 / 07.iso / c / c480 / 18.ddi / MFC / SRC / VIEWPREV.CP_ / VIEWPREV.CP
Encoding:
Text File  |  1993-02-08  |  28.1 KB  |  1,022 lines

  1. // This is a part of the Microsoft Foundation Classes C++ library.
  2. // Copyright (C) 1992 Microsoft Corporation
  3. // All rights reserved.
  4. //
  5. // This source code is only intended as a supplement to the
  6. // Microsoft Foundation Classes Reference and Microsoft
  7. // QuickHelp and/or WinHelp documentation provided with the library.
  8. // See these sources for detailed information regarding the
  9. // Microsoft Foundation Classes product.
  10.  
  11. #include "stdafx.h"
  12.  
  13. #ifdef AFX_PRINT_SEG
  14. #pragma code_seg(AFX_PRINT_SEG)
  15. #endif
  16.  
  17. #ifdef _DEBUG
  18. #undef THIS_FILE
  19. static char BASED_CODE THIS_FILE[] = __FILE__;
  20. #endif
  21.  
  22. BOOL CALLBACK _AfxPreviewCloseProc(CFrameWnd* pFrameWnd);
  23.  
  24. /////////////////////////////////////////////////////////////////////////////
  25. // CPrintPreviewState helper structure
  26.  
  27. CPrintPreviewState::CPrintPreviewState()
  28. {
  29.     // set defaults
  30.     nIDMainPane = AFX_IDW_PANE_FIRST;
  31.     dwStates = AFX_CONTROLBAR_MASK(AFX_IDW_STATUS_BAR);
  32.                         // status bar visible if available
  33.     lpfnCloseProc = _AfxPreviewCloseProc;
  34.                         // set frame hook so closing the frame window
  35.                         //  when in preview state will just end the mode
  36.     hMenu = NULL;
  37.     pViewActiveOld = NULL;
  38.     hAccelTable = NULL;
  39. }
  40.  
  41. /////////////////////////////////////////////////////////////////////////////
  42. // CView's OnPrintPreview.  Here to force linkage
  43.  
  44. void CView::OnFilePrintPreview()
  45. {
  46.     // In derived classes, implement special window handling here
  47.     // Be sure to Unhook Frame Window close if hooked.
  48.  
  49.     // must not create this on the frame.  Must outlive this function
  50.     CPrintPreviewState* pState = new CPrintPreviewState;
  51.  
  52.     // DoPrintPreview's return value does not necessarily indicate that
  53.     // Print preview succeeded or failed, but rather what actions are necessary
  54.     // at this point.  If DoPrintPreview returns TRUE, it means that
  55.     // OnEndPrintPreview will be (or has already been) called and the
  56.     // pState structure will be/has been deleted.
  57.     // If DoPrintPreview returns FALSE, it means that OnEndPrintPreview
  58.     // WILL NOT be called and that cleanup, including deleting pState
  59.     // must be done here.
  60.  
  61.     if (!DoPrintPreview(AFX_IDD_PREVIEW_TOOLBAR, this,
  62.                             RUNTIME_CLASS(CPreviewView), pState))
  63.     {
  64.         // In derived classes, reverse special window handling here for
  65.         // Preview failure case
  66.  
  67.         TRACE0("Error: DoPrintPreview failed");
  68.         AfxMessageBox(AFX_IDP_COMMAND_FAILURE);
  69.         delete pState;      // preview failed to initialize, delete State now
  70.     }
  71. }
  72.  
  73. BOOL CView::DoPrintPreview(UINT nIDResource, CView* pPrintView,
  74.     CRuntimeClass* pPreviewViewClass, CPrintPreviewState* pState)
  75. {
  76.     ASSERT_VALID(pPrintView);
  77.     ASSERT(pPreviewViewClass != NULL);
  78.     ASSERT(pState != NULL);
  79.  
  80.     CFrameWnd* pParent = (CFrameWnd*) AfxGetApp()->m_pMainWnd;
  81.     ASSERT(pParent != NULL);
  82.     ASSERT(pParent->IsKindOf(RUNTIME_CLASS(CFrameWnd)));
  83.     ASSERT_VALID(pParent);
  84.  
  85.     CCreateContext context;
  86.     context.m_pCurrentFrame = pParent;
  87.     context.m_pCurrentDoc = GetDocument();
  88.     context.m_pLastView = this;
  89.  
  90.     // Create the preview view object
  91.     CPreviewView* pView = (CPreviewView*)pPreviewViewClass->CreateObject();
  92.     if (pView == NULL)
  93.     {
  94.         TRACE0("Error: Failed to create preview view\n");
  95.         return FALSE;
  96.     }
  97.     ASSERT(pView->IsKindOf(RUNTIME_CLASS(CPreviewView)));
  98.     pView->m_pPreviewState = pState;        // save pointer
  99.  
  100.     pParent->OnSetPreviewMode(TRUE, pState);    // Take over Frame Window
  101.  
  102.     // Create the toolbar from the dialog resource
  103.     pView->m_pToolBar = new CDialogBar;
  104.     if (!pView->m_pToolBar->Create(pParent, MAKEINTRESOURCE(nIDResource),
  105.                                             0, AFX_IDW_PREVIEW_BAR))
  106.     {
  107.         TRACE0("Error: Preview could not create toolbar dialog\n");
  108.         pParent->OnSetPreviewMode(FALSE, pState);   // restore Frame Window
  109.         delete pView->m_pToolBar;       // not autodestruct yet
  110.         pView->m_pPreviewState = NULL;  // do not delete state structure
  111.         delete pView;
  112.         return FALSE;
  113.     }
  114.     pView->m_pToolBar->m_bAutoDelete = TRUE;    // automatic cleanup
  115.  
  116.     // Create the preview view as a child of the App Main Window.  This
  117.     // is a sibling of this view if this is an SDI app.  This is NOT a sibling
  118.     // if this is an MDI app.
  119.  
  120.     if (!pView->Create(NULL, NULL, AFX_WS_DEFAULT_VIEW,
  121.         CRect(0,0,0,0), pParent, AFX_IDW_PANE_FIRST, &context))
  122.     {
  123.         TRACE0("Error: couldn't create preview view for frame\n");
  124.         pParent->OnSetPreviewMode(FALSE, pState);   // restore Frame Window
  125.         pView->m_pPreviewState = NULL;  // do not delete state structure
  126.         delete pView;
  127.         return FALSE;
  128.     }
  129.  
  130.     // Preview window shown now
  131.     pParent->RecalcLayout();            // position and size everything
  132.  
  133.     pState->pViewActiveOld = pParent->GetActiveView();
  134.  
  135.     if (!pView->SetPrintView(pPrintView))
  136.     {
  137.         pView->OnPreviewClose();
  138.         return TRUE;            // signal that OnEndPrintPreview was called
  139.     }
  140.         
  141.     pParent->SetActiveView(pView);  // set active view - even for MDI
  142.  
  143.     return TRUE;
  144. }
  145.  
  146. BOOL CALLBACK _AfxPreviewCloseProc(CFrameWnd* pFrameWnd)
  147. {
  148.     ASSERT_VALID(pFrameWnd);
  149.  
  150.     CPreviewView* pView = (CPreviewView*) pFrameWnd->GetDlgItem(AFX_IDW_PANE_FIRST);
  151.     ASSERT(pView->IsKindOf(RUNTIME_CLASS(CPreviewView)));
  152.  
  153.     pView->OnPreviewClose();
  154.     return FALSE;
  155. }
  156.  
  157. /////////////////////////////////////////////////////////////////////////////
  158. // Preview View
  159.  
  160. IMPLEMENT_DYNCREATE(CPreviewView, CScrollView)
  161.  
  162. BEGIN_MESSAGE_MAP(CPreviewView, CScrollView)
  163.     //{{AFX_MSG_MAP(CPreviewView)
  164.     ON_WM_SIZE()        // overriding CScrollView
  165.     ON_WM_CREATE()
  166.  
  167.     ON_COMMAND(AFX_ID_PREVIEW_CLOSE, OnPreviewClose)
  168.     ON_COMMAND(AFX_ID_PREVIEW_NUMPAGE, OnNumPageChange)
  169.     ON_COMMAND(AFX_ID_PREVIEW_NEXT, OnNextPage)
  170.     ON_COMMAND(AFX_ID_PREVIEW_PREV, OnPrevPage)
  171.     ON_COMMAND(AFX_ID_PREVIEW_PRINT, OnPreviewPrint)
  172.     ON_COMMAND(AFX_ID_PREVIEW_ZOOMIN, OnZoomIn)
  173.     ON_COMMAND(AFX_ID_PREVIEW_ZOOMOUT, OnZoomOut)
  174.  
  175.     ON_UPDATE_COMMAND_UI(AFX_ID_PREVIEW_NUMPAGE, OnUpdateNumPageChange)
  176.     ON_UPDATE_COMMAND_UI(AFX_ID_PREVIEW_NEXT, OnUpdateNextPage)
  177.     ON_UPDATE_COMMAND_UI(AFX_ID_PREVIEW_PREV, OnUpdatePrevPage)
  178.     ON_UPDATE_COMMAND_UI(AFX_ID_PREVIEW_ZOOMIN, OnUpdateZoomIn)
  179.     ON_UPDATE_COMMAND_UI(AFX_ID_PREVIEW_ZOOMOUT, OnUpdateZoomOut)
  180.  
  181.     ON_WM_VSCROLL()
  182.     ON_WM_HSCROLL()
  183.     ON_WM_LBUTTONDOWN()
  184.     ON_WM_ERASEBKGND()
  185.     ON_WM_SETCURSOR()
  186.     //}}AFX_MSG_MAP
  187. END_MESSAGE_MAP()
  188.  
  189. CPreviewView::CPreviewView()
  190. {
  191.     m_pPrintView = NULL;
  192.     m_pOrigView = NULL;
  193.     m_pPreviewInfo = NULL;
  194.     m_pPreviewDC = NULL;
  195.     m_pPreviewState = NULL;
  196.     m_hMagnifyCursor = NULL;
  197.     m_bPageNumDisplayed = FALSE;
  198.     m_nZoomState = ZOOM_OUT;
  199.  
  200.     // default to pointing to embedded array.  Allows for 2 pages
  201.     m_pPageInfo = m_pageInfoArray;
  202.     m_nMaxPages = 2;
  203.  
  204.     // initialize CScrollView members
  205.     m_bCenter = TRUE;                   // Center Zoomed output in Scrollview
  206.     m_nMapMode = MM_TEXT;
  207. }
  208.  
  209. CPreviewView::~CPreviewView()
  210. {
  211.     delete m_pPreviewInfo;      // get rid of preview info
  212.     delete m_pPreviewState;     // Get rid of preview state
  213.     delete m_pPreviewDC;        // Get rid of preview DC object
  214.  
  215.     if (m_hMagnifyCursor != NULL)
  216.         DestroyCursor(m_hMagnifyCursor);
  217. }
  218.  
  219. int CPreviewView::OnCreate(LPCREATESTRUCT lpCreateStruct)
  220. {
  221.     int retVal = CView::OnCreate(lpCreateStruct);
  222.     if (retVal == -1)
  223.         return -1;      // if -1 bag out
  224.  
  225.     CCreateContext* pContext = (CCreateContext*)
  226.         _AfxGetPtrFromFarPtr(lpCreateStruct->lpCreateParams);
  227.  
  228.     m_pOrigView = pContext->m_pLastView;
  229.     ASSERT(m_pOrigView != NULL);
  230.     ASSERT(m_pOrigView->IsKindOf(RUNTIME_CLASS(CView)));
  231.  
  232.     return retVal;
  233. }
  234.  
  235. BOOL CPreviewView::SetPrintView(CView* pPrintView)
  236. {
  237.     ASSERT_VALID(pPrintView);
  238.  
  239.     m_pPrintView = pPrintView;
  240.  
  241.     // allocate preview info
  242.     m_pPreviewInfo = new CPrintInfo;
  243.     m_pPreviewInfo->m_pPD->SetHelpID(AFX_IDD_PRINTSETUP);
  244.     m_pPreviewInfo->m_pPD->m_pd.Flags |= PD_PRINTSETUP;
  245.     m_pPreviewInfo->m_pPD->m_pd.Flags &= ~PD_RETURNDC;
  246.  
  247.     m_pPreviewInfo->m_bPreview = TRUE;  // signal that this is preview
  248.     ASSERT(m_pPreviewInfo->m_pPD != NULL);
  249.  
  250.     m_pPreviewDC = new CPreviewDC;      // must be created before any
  251.                                         // possible error returns
  252.  
  253.     if (!m_pPrintView->OnPreparePrinting(m_pPreviewInfo))
  254.         return FALSE;
  255.  
  256. #ifdef _DEBUG
  257.     if (m_pPreviewInfo->m_pPD->m_pd.hDC == NULL)
  258.     {
  259.         TRACE0("hDC not set for printing "
  260.             "(did you remember to call DoPreparePrinting?)\n");
  261.         ASSERT(FALSE);      // common mistake gets trapped here
  262.     }
  263. #endif //_DEBUG
  264.  
  265.     m_dcPrint.Attach(m_pPreviewInfo->m_pPD->m_pd.hDC);
  266.     m_pPreviewDC->SetAttribDC(m_pPreviewInfo->m_pPD->m_pd.hDC);
  267.     m_pPreviewDC->m_bPrinting = TRUE;
  268.     m_dcPrint.m_bPrinting = TRUE;
  269.  
  270.     int nSavedState = m_dcPrint.SaveDC();   // Save pristine state of DC
  271.  
  272.     HDC hDC = ::GetDC(m_hWnd);
  273.     m_pPreviewDC->SetOutputDC(hDC);
  274.     m_pPrintView->OnBeginPrinting(m_pPreviewDC, m_pPreviewInfo);
  275.     m_pPreviewDC->ReleaseOutputDC();
  276.     ::ReleaseDC(m_hWnd, hDC);
  277.  
  278.     m_dcPrint.RestoreDC(nSavedState);       // restore to untouched state
  279.  
  280.     // Get Pixels per inch from Printer
  281.     m_sizePrinterPPI.cx = m_dcPrint.GetDeviceCaps(LOGPIXELSX);
  282.     m_sizePrinterPPI.cy = m_dcPrint.GetDeviceCaps(LOGPIXELSY);
  283.  
  284.     m_nPages = m_pPreviewInfo->m_nNumPreviewPages;
  285.     if (m_nPages == 0)
  286.         m_nPages = 1;
  287.     else if (m_nPages > m_nMaxPages)
  288.         m_nPages = m_nMaxPages;     // Sanity Check!
  289.  
  290.     m_nZoomOutPages = m_nPages;
  291.  
  292.     SetScrollSizes(MM_TEXT, CSize(1, 1));   // initialize mapping mode only
  293.  
  294.     if (m_pPreviewInfo->GetMaxPage() < 0x8000 &&
  295.         m_pPreviewInfo->GetMaxPage() - m_pPreviewInfo->GetMinPage() <= 32767U)
  296.         SetScrollRange(SB_VERT, m_pPreviewInfo->GetMinPage(),
  297.                 m_pPreviewInfo->GetMaxPage(), FALSE);
  298.     else
  299.         ShowScrollBar(SB_VERT, FALSE);      // if no range specified, or too
  300.                                             // large don't show
  301.  
  302.     SetCurrentPage(m_pPreviewInfo->m_nCurPage, TRUE);
  303.     return TRUE;
  304. }
  305.  
  306. void CPreviewView::OnSize(UINT nType, int cx, int cy)
  307. {
  308.     // CScrollView handles everything if zoomed in.
  309.     if (m_nZoomState == ZOOM_OUT)
  310.     {
  311.         // Force recalc of scale ratios on next draw
  312.         for (UINT i = 0; i < m_nMaxPages; i++)
  313.             m_pPageInfo[i].sizeScaleRatio.cx = 0;           // zero scale ratios
  314.  
  315.         CView::OnSize(nType, cx, cy);       // No scroll functionality
  316.     }
  317.     else
  318.     {
  319.         // adjust scroll size to size of page
  320.         m_pageDev.cx = cx;
  321.         m_pageDev.cy = cy;
  322.         m_lineDev.cx = cx / 10;
  323.         m_lineDev.cy = cy / 10;
  324.         CScrollView::OnSize(nType, cx, cy);
  325.     }
  326. }
  327.  
  328. void CPreviewView::OnActivateView(BOOL bActivate,
  329.         CView*, CView*)
  330. {
  331.     if (bActivate)
  332.     {
  333.         CWnd* pFocusWnd = GetFocus();
  334.         // if focus is not already on a toolbar button - set it to one
  335.         if (pFocusWnd == NULL || !m_pToolBar->IsChild(pFocusWnd))
  336.             m_pToolBar->GetDlgItem(AFX_ID_PREVIEW_PRINT)->SetFocus();
  337.     }
  338. }
  339.  
  340.  
  341. void CPreviewView::OnPreviewClose()
  342. {
  343.     m_pToolBar->DestroyWindow();
  344.  
  345.     m_pPreviewInfo->m_nCurPage = m_nCurrentPage;
  346.     m_pOrigView->OnEndPrintPreview(m_pPreviewDC, m_pPreviewInfo,
  347.                                     CPoint(0, 0), this);
  348. }
  349.  
  350. #define PREVIEW_MARGIN  8
  351. #define PREVIEW_PAGEGAP 8
  352.  
  353. // Return is actually the fraction cx/cy. Simply using CSize for convenience
  354. CSize CPreviewView::CalcScaleRatio(CSize screenSize, CSize actualSize)
  355. {
  356.     // Test ratio based on vertical dimension to see if it is the one to use
  357.     int nNum = screenSize.cy;
  358.     int nDen = actualSize.cy;
  359.  
  360.     // If scaled width too large, choose width as primary dimension
  361.     if (MulDiv(actualSize.cx, nNum, nDen) > screenSize.cx)
  362.     {
  363.         // wrong ratio--base on width
  364.         nNum = screenSize.cx;
  365.         nDen = actualSize.cx;
  366.     }
  367.     CSize ratio(nNum, nDen);
  368.     return ratio;
  369. }
  370.  
  371. // Position Page...
  372. // Generate a Screen MM_TEXT rectangle to enclose each page.  Dimensions
  373. // of the rectangle must be 1 pixel Above and Left of the top/left corner
  374. // of the page and the rectangle width and height must be THREE pixels
  375. // larger than page in order to provide the correct placement of the
  376. // two pixel border.
  377. //
  378. // This routine is called once for each page with the preview DC set up for
  379. // that page
  380.  
  381. void CPreviewView::PositionPage(UINT nPage)
  382. {
  383.     CSize windowSize = CalcPageDisplaySize();
  384.  
  385.     VERIFY(m_dcPrint.Escape(GETPHYSPAGESIZE, 0, NULL,
  386.             (LPSTR)&m_pPageInfo[nPage].sizeUnscaled));
  387.  
  388.     CSize* pSize = &m_pPageInfo[nPage].sizeUnscaled;
  389.  
  390.     // Convert page size to screen coordinates
  391.     pSize->cx = MulDiv(pSize->cx, afxData.cxPixelsPerInch, m_sizePrinterPPI.cx);
  392.     pSize->cy = MulDiv(pSize->cy, afxData.cyPixelsPerInch, m_sizePrinterPPI.cy);
  393.  
  394.     m_pPageInfo[nPage].sizeZoomOutRatio = CalcScaleRatio(windowSize, *pSize);
  395.  
  396.     SetScaledSize(nPage);
  397. }
  398.  
  399. CSize CPreviewView::CalcPageDisplaySize()
  400.     // calculate the current page size
  401.     //  set 'm_nSecondPageOffset' to start of second page
  402.     // return size of current page less margins
  403. {
  404.     CSize windowSize, scrollSize;
  405.     GetTrueClientSize(windowSize, scrollSize);
  406.  
  407.     // subtract out vertical scrollbar if zoomed out and page range is known
  408.     // and there is more than one page.
  409.     if (m_nZoomState == ZOOM_OUT && (m_pPreviewInfo->GetMaxPage() != 0xffff) &&
  410.         (m_pPreviewInfo->GetMaxPage() - m_pPreviewInfo->GetMinPage() != 0))
  411.         windowSize.cx -= scrollSize.cx;
  412.  
  413.     m_nSecondPageOffset = (windowSize.cx - PREVIEW_MARGIN) / 2;
  414.  
  415.     windowSize.cx = (m_nPages == 2) ? (windowSize.cx - 3*PREVIEW_MARGIN) / 2 :
  416.                                     windowSize.cx - 2*PREVIEW_MARGIN;
  417.  
  418.     windowSize.cy -= 2*PREVIEW_MARGIN;
  419.     return windowSize;
  420. }
  421.  
  422. void CPreviewView::SetScaledSize(UINT nPage)
  423. {
  424.     CSize* pSize = &m_pPageInfo[nPage].sizeUnscaled;
  425.     CSize* pRatio = &m_pPageInfo[nPage].sizeScaleRatio;
  426.     CSize* pZoomOutRatio = &m_pPageInfo[nPage].sizeZoomOutRatio;
  427.     CSize windowSize = CalcPageDisplaySize();
  428.  
  429.     switch (m_nZoomState)
  430.     {
  431.     case ZOOM_OUT:
  432.         *pRatio = *pZoomOutRatio;
  433.         break;
  434.  
  435.     case ZOOM_MIDDLE:
  436.         // the middle zoom state is a ratio between cx/cy and
  437.         // 1/1 (or cy/cy).  It is, therefore:
  438.         //
  439.         // (cx + cy)/2
  440.         // -----------
  441.         //     cy
  442.         pRatio->cy = pZoomOutRatio->cy;
  443.         pRatio->cx = (pZoomOutRatio->cx + pRatio->cy) / 2;
  444.         break;
  445.  
  446.     case ZOOM_IN:
  447.         pRatio->cx = pRatio->cy = 1;
  448.         break;
  449.  
  450.     default:
  451.         ASSERT(FALSE);
  452.     }
  453.  
  454.     // Convert to scaled size
  455.     CSize scaledSize;
  456.     scaledSize.cx = MulDiv(pSize->cx, pRatio->cx, pRatio->cy);
  457.     scaledSize.cy = MulDiv(pSize->cy, pRatio->cx, pRatio->cy);
  458.  
  459.     CRect* pRect = &m_pPageInfo[nPage].rectScreen;
  460.     pRect->SetRect(PREVIEW_MARGIN, PREVIEW_MARGIN,
  461.                    scaledSize.cx + PREVIEW_MARGIN + 3,
  462.                    scaledSize.cy + PREVIEW_MARGIN + 3);
  463.  
  464.     if (m_nZoomState == ZOOM_OUT)
  465.     {
  466.         pRect->OffsetRect((windowSize.cx - pRect->Size().cx) / 2 - 1,
  467.                           (windowSize.cy - pRect->Size().cy) / 2 - 1);
  468.  
  469.         if (nPage == 1)
  470.             pRect->OffsetRect(m_nSecondPageOffset, 0);
  471.     }
  472.     else
  473.     {
  474.         // set up scroll size
  475.  
  476.         SetScrollSizes(MM_TEXT, pRect->Size() +
  477.                 CSize(PREVIEW_MARGIN * 2, PREVIEW_MARGIN * 2), windowSize);
  478.     }
  479. }
  480.  
  481.  
  482. // Only use the PrepareDC from CScrollView if we are zoomed in
  483. void CPreviewView::OnPrepareDC(CDC* pDC, CPrintInfo* pInfo)
  484. {
  485.     ASSERT_VALID(pDC);
  486.  
  487.     if (m_nZoomState == ZOOM_OUT)
  488.         CView::OnPrepareDC(pDC, pInfo);
  489.     else if (m_pPageInfo[0].sizeScaleRatio.cx != 0)
  490.         CScrollView::OnPrepareDC(pDC, pInfo);
  491. }
  492.  
  493. BOOL CPreviewView::OnEraseBkgnd(CDC* pDC)
  494. {
  495.     ASSERT_VALID(pDC);
  496.  
  497.     // Fill background with APPWORKSPACE
  498.     CBrush backBrush(GetSysColor(COLOR_APPWORKSPACE));
  499.     CBrush* pOldBrush = pDC->SelectObject(&backBrush);
  500.     CRect rect;
  501.     pDC->GetClipBox(&rect);     // Erase the area needed
  502.  
  503.     pDC->PatBlt(rect.left, rect.top, rect.Width(), rect.Height(), PATCOPY);
  504.     pDC->SelectObject(pOldBrush);
  505.     return TRUE;
  506. }
  507.  
  508. void CPreviewView::OnDraw(CDC* pDC)
  509. {
  510.     ASSERT_VALID(pDC);
  511.  
  512.     // don't do anything if not fully initialized
  513.     if (m_pPrintView == NULL || m_dcPrint.m_hDC == NULL)
  514.         return;
  515.  
  516.  
  517.     CRect rect;
  518.     GetClientRect(&rect);
  519.  
  520.     CPoint ViewportOrg = pDC->GetViewportOrg();
  521.  
  522.     CPen rectPen;
  523.     rectPen.CreatePen(PS_SOLID, 2, GetSysColor(COLOR_WINDOWFRAME));
  524.     CPen shadowPen;
  525.     shadowPen.CreatePen(PS_SOLID, 3, GetSysColor(COLOR_BTNSHADOW));
  526.  
  527.     m_pPreviewInfo->m_bContinuePrinting = TRUE;     // do this once each paint
  528.  
  529.     for (UINT nPage = 0; nPage < m_nPages; nPage++)
  530.     {
  531.         int nSavedState = m_dcPrint.SaveDC();       // Save pristine state of DC
  532.  
  533.         // Use paint DC for print preview output
  534.         m_pPreviewDC->SetOutputDC(pDC->GetSafeHdc());
  535.  
  536.         m_pPreviewInfo->m_nCurPage = m_nCurrentPage + nPage;
  537.  
  538.         // Only call PrepareDC if within page range, otherwise use default
  539.         // rect to draw page rectangle
  540.         if (m_nCurrentPage + nPage <= m_pPreviewInfo->GetMaxPage())
  541.             m_pPrintView->OnPrepareDC(m_pPreviewDC, m_pPreviewInfo);
  542.  
  543.         // Set up drawing rect to entire page (in logical coordinates)
  544.         m_pPreviewInfo->m_rectDraw.SetRect(0, 0,
  545.                                         m_pPreviewDC->GetDeviceCaps(HORZRES),
  546.                                         m_pPreviewDC->GetDeviceCaps(VERTRES));
  547.         m_pPreviewDC->DPtoLP(&m_pPreviewInfo->m_rectDraw);
  548.  
  549.         // Draw empty page on screen
  550.  
  551.         pDC->SaveDC();          // save the output dc state
  552.  
  553.         CSize* pRatio = &m_pPageInfo[nPage].sizeScaleRatio;
  554.         CRect* pRect = &m_pPageInfo[nPage].rectScreen;
  555.  
  556.         if (pRatio->cx == 0)
  557.         {   // page position has not been determined
  558.             PositionPage(nPage);    // compute page position
  559.             ASSERT(pRatio->cx != 0);
  560.             if (m_nZoomState != ZOOM_OUT)
  561.                 ViewportOrg = -GetDeviceScrollPosition();
  562.         }
  563.  
  564.         pDC->SetMapMode(MM_TEXT);   // Page Rectangle is in screen device coords
  565.         pDC->SetViewportOrg(ViewportOrg);
  566.         pDC->SetWindowOrg(0, 0);
  567.  
  568.         pDC->SelectObject(&rectPen);
  569.         pDC->Rectangle(pRect);
  570.  
  571.         pDC->SelectObject(&shadowPen);
  572.  
  573.         pDC->MoveTo(pRect->right + 1, pRect->top + 3);
  574.         pDC->LineTo(pRect->right + 1, pRect->bottom + 1);
  575.         pDC->MoveTo(pRect->left + 3, pRect->bottom + 1);
  576.         pDC->LineTo(pRect->right + 1, pRect->bottom + 1);
  577.  
  578.         pDC->RestoreDC(-1);     // restore to synchronized state
  579.  
  580.         if (!m_pPreviewInfo->m_bContinuePrinting ||
  581.                 m_nCurrentPage + nPage > m_pPreviewInfo->GetMaxPage())
  582.         {
  583.             m_pPreviewDC->ReleaseOutputDC();
  584.             m_dcPrint.RestoreDC(nSavedState);   // restore to untouched state
  585.  
  586.             // if the first page is not displayable, back up one page
  587.             // but never go below 1
  588.             if (nPage == 0 && m_nCurrentPage > 1)
  589.                 SetCurrentPage(m_nCurrentPage - 1, TRUE);
  590.             break;
  591.         }
  592.  
  593.         // Display page number
  594.         OnDisplayPageNumber(m_nCurrentPage, nPage + 1);
  595.  
  596.         // Set scale ratio for this page
  597.         m_pPreviewDC->SetScaleRatio(pRatio->cx, pRatio->cy);
  598.  
  599.         CSize PrintOffset;
  600.         VERIFY(m_pPreviewDC->Escape(GETPRINTINGOFFSET, 0, NULL, (LPSTR)&PrintOffset));
  601.         m_pPreviewDC->PrinterDPtoScreenDP((LPPOINT)&PrintOffset);
  602.         PrintOffset += (CSize)pRect->TopLeft();
  603.         PrintOffset += CSize(1, 1);
  604.         PrintOffset += (CSize)ViewportOrg;  // For Scrolling
  605.  
  606.         m_pPreviewDC->SetTopLeftOffset(PrintOffset);
  607.  
  608.         m_pPreviewDC->ClipToPage();
  609.         m_pPrintView->OnPrint(m_pPreviewDC, m_pPreviewInfo);
  610.  
  611.         m_pPreviewDC->ReleaseOutputDC();
  612.  
  613.         m_dcPrint.RestoreDC(nSavedState);   // restore to untouched state
  614.  
  615.     }
  616.  
  617.     rectPen.DeleteObject();
  618.     shadowPen.DeleteObject();
  619. }
  620.  
  621. void CPreviewView::OnHScroll(UINT nSBCode, UINT nPos, CScrollBar* pScrollBar)
  622. {
  623.     if (m_nZoomState != ZOOM_OUT)
  624.         CScrollView::OnHScroll(nSBCode, nPos, pScrollBar);
  625. }
  626.  
  627. void CPreviewView::OnVScroll(UINT nSBCode, UINT nPos, CScrollBar* pScrollBar)
  628. {
  629.     if (m_nZoomState != ZOOM_OUT)
  630.     {
  631.         CScrollView::OnVScroll(nSBCode, nPos, pScrollBar);
  632.         return;
  633.     }
  634.  
  635.     switch (nSBCode)
  636.     {
  637.     case SB_BOTTOM:
  638.         SetCurrentPage(m_pPreviewInfo->GetMaxPage(), TRUE);
  639.         break;
  640.  
  641.     case SB_TOP:
  642.         SetCurrentPage(m_pPreviewInfo->GetMinPage(), TRUE);
  643.         break;
  644.  
  645.     case SB_PAGEDOWN:
  646.         SetCurrentPage(m_nCurrentPage +
  647.             (m_pPreviewInfo->GetMaxPage() - m_pPreviewInfo->GetMinPage() + 9) / 10, TRUE);
  648.         break;
  649.  
  650.     case SB_PAGEUP:
  651.         SetCurrentPage(m_nCurrentPage -
  652.             (m_pPreviewInfo->GetMaxPage() - m_pPreviewInfo->GetMinPage() + 9) / 10, TRUE);
  653.         break;
  654.  
  655.     case SB_LINEDOWN:
  656.         SetCurrentPage(m_nCurrentPage + 1, TRUE);
  657.         break;
  658.  
  659.     case SB_LINEUP:
  660.         SetCurrentPage(m_nCurrentPage - 1, TRUE);
  661.         break;
  662.  
  663.     case SB_THUMBPOSITION:
  664.         SetCurrentPage(nPos, TRUE);
  665.         break;
  666.     }
  667. }
  668.  
  669. void CPreviewView::OnNumPageChange()
  670. {
  671.     ASSERT(m_nPages == 1 || m_nPages == 2);
  672.     m_nPages = 3 - m_nPages;    // Toggle between 1 and 2
  673.     AfxGetApp()->m_nNumPreviewPages = m_nPages;
  674.     m_nZoomOutPages = m_nPages;
  675.  
  676.     // Just do this to set the status correctly and invalidate
  677.     SetCurrentPage(m_nCurrentPage, TRUE);
  678. }
  679.  
  680. void CPreviewView::OnNextPage()
  681. {
  682.     SetCurrentPage(m_nCurrentPage + 1, TRUE);
  683. }
  684.  
  685. void CPreviewView::OnPrevPage()
  686. {
  687.     SetCurrentPage(m_nCurrentPage - 1, TRUE);
  688. }
  689.  
  690. void CPreviewView::OnPreviewPrint()
  691. {
  692.     CView* pOrigView = m_pOrigView;
  693.     OnPreviewClose();               // force close of Preview
  694.  
  695.     pOrigView->OnFilePrint();       // cause print
  696. }
  697.  
  698. // Finds page pointed to and convert to 1:1 screen device units
  699. BOOL CPreviewView::FindPageRect(CPoint& point, UINT& nPage)
  700. {
  701.     if (m_nZoomState != ZOOM_OUT)
  702.         point += (CSize) GetDeviceScrollPosition();
  703.  
  704.     for (nPage = 0; nPage < m_nPages; nPage++)
  705.     {
  706.         if (m_pPageInfo[nPage].rectScreen.PtInRect(point))
  707.         {
  708.             // adjust point for page position
  709.             point -= (CSize)m_pPageInfo[nPage].rectScreen.TopLeft();
  710.             // and for scroll position
  711.             point += (CSize)GetDeviceScrollPosition();
  712.  
  713.             // convert to 1:1
  714.             point.x = MulDiv(point.x, m_pPageInfo[nPage].sizeScaleRatio.cy,
  715.                                     m_pPageInfo[nPage].sizeScaleRatio.cx);
  716.             point.y = MulDiv(point.y, m_pPageInfo[nPage].sizeScaleRatio.cy,
  717.                                     m_pPageInfo[nPage].sizeScaleRatio.cx);
  718.             return TRUE;
  719.         }
  720.     }
  721.     return FALSE;
  722. }
  723.  
  724.  
  725. void CPreviewView::OnLButtonDown(UINT, CPoint point)
  726. {
  727.     UINT nPage;
  728.     if (!FindPageRect(point, nPage))
  729.         return;                         // Didn't click on a page
  730.  
  731.     // Set new zoom state
  732.     SetZoomState((m_nZoomState == ZOOM_IN) ? ZOOM_OUT : m_nZoomState + 1,
  733.                                 nPage, point);
  734. }
  735.  
  736. void CPreviewView::SetZoomState(UINT nNewState, UINT nPage, CPoint point)
  737. {
  738.     if (m_nZoomState != nNewState)
  739.     {
  740.         m_nZoomState = nNewState;
  741.         DoZoom(nPage, point);
  742.     }
  743. }
  744.  
  745. void CPreviewView::OnZoomIn()
  746. {
  747.     if (m_nZoomState != ZOOM_IN)
  748.         SetZoomState(m_nZoomState + 1, 0, CPoint(0, 0));
  749. }
  750.  
  751. void CPreviewView::OnZoomOut()
  752. {
  753.     if (m_nZoomState != ZOOM_OUT)
  754.         SetZoomState(m_nZoomState - 1, 0, CPoint(0, 0));
  755. }
  756.  
  757. // Actual zoom code.
  758. void CPreviewView::DoZoom(UINT nPage, CPoint point)
  759. {
  760.     if (m_nZoomState == ZOOM_OUT)
  761.     {
  762.         // taking over scroll bars
  763.         m_nPages = m_nZoomOutPages;
  764.         ShowScrollBar(SB_HORZ, FALSE);      //hide the horizontal bar
  765.  
  766.         BOOL bShowBar = m_pPreviewInfo->GetMaxPage() < 0x8000 &&
  767.             m_pPreviewInfo->GetMaxPage() - m_pPreviewInfo->GetMinPage() <= 32767U;
  768.  
  769.         ShowScrollBar(SB_VERT, bShowBar);       //Show the vertical bar
  770.  
  771.         if (bShowBar)
  772.         {
  773.             SetScrollRange(SB_VERT, m_pPreviewInfo->GetMinPage(),
  774.                                 m_pPreviewInfo->GetMaxPage(), FALSE);
  775.  
  776.             SetScrollPos(SB_VERT, m_nCurrentPage, TRUE);
  777.         }
  778.  
  779.         SetCurrentPage(m_nCurrentPage, TRUE);
  780.     }
  781.     else
  782.     {
  783.         m_nPages = 1;       // only one page in zoomed states
  784.  
  785.         m_pPageInfo[0].sizeZoomOutRatio = m_pPageInfo[nPage].sizeZoomOutRatio;
  786.         m_pPageInfo[0].sizeUnscaled = m_pPageInfo[nPage].sizeUnscaled;
  787.  
  788.         // Sets the printer page
  789.         SetCurrentPage(m_nCurrentPage + nPage, FALSE);
  790.  
  791.         SetScaledSize(0);
  792.  
  793.         CSize* pRatio = &m_pPageInfo[nPage].sizeScaleRatio;
  794.  
  795.         // convert Hit Point from screen 1:1
  796.         point.x = MulDiv(point.x, pRatio->cx, pRatio->cy);
  797.         point.y = MulDiv(point.y, pRatio->cx, pRatio->cy);
  798.  
  799.         // Adjust point for page position
  800.         point += (CSize)m_pPageInfo[0].rectScreen.TopLeft();
  801.  
  802.         // Scroll to center
  803.         CenterOnPoint(point);
  804.     }
  805. }
  806.  
  807. void CPreviewView::SetCurrentPage(UINT nPage, BOOL bClearRatios)
  808. {
  809.     m_nCurrentPage = nPage;
  810.     if (m_nCurrentPage > m_pPreviewInfo->GetMaxPage())
  811.         m_nCurrentPage = m_pPreviewInfo->GetMaxPage();
  812.     if (m_nCurrentPage < m_pPreviewInfo->GetMinPage())
  813.         m_nCurrentPage = m_pPreviewInfo->GetMinPage();
  814.         
  815.  
  816.     if (m_nZoomState == ZOOM_OUT)
  817.         SetScrollPos(SB_VERT, m_nCurrentPage);
  818.  
  819.     if (bClearRatios)
  820.     {
  821.         // Force Recalc of layout
  822.         for (UINT i = 0; i < m_nMaxPages; i++)
  823.             m_pPageInfo[i].sizeScaleRatio.cx = 0;           // zero scale ratios
  824.     }
  825.  
  826.     Invalidate(TRUE);
  827. }
  828.  
  829. void CPreviewView::OnDisplayPageNumber(UINT nPage, UINT nPagesDisplayed)
  830. {
  831.     UINT nEndPage = nPage + nPagesDisplayed - 1;
  832.  
  833.     CFrameWnd* pParent = (CFrameWnd*) AfxGetApp()->m_pMainWnd;
  834.     ASSERT(pParent->IsKindOf(RUNTIME_CLASS(CFrameWnd)));
  835.  
  836.     CString s;
  837.     if (AfxExtractSubString(s, m_pPreviewInfo->m_strPageDesc,
  838.                                                 nPagesDisplayed - 1))
  839.     {
  840.         char szBuf[80];
  841.         wsprintf(szBuf, s, nPage, nEndPage);
  842.         pParent->SendMessage(WM_SETMESSAGESTRING, 0, (LPARAM)(LPCSTR)szBuf);
  843.     }
  844.     else
  845.     {
  846.         TRACE1("Malformed Page Description string.  Could not get string %d\n",
  847.             nPagesDisplayed);
  848.     }
  849. }
  850.  
  851.  
  852. void CPreviewView::OnUpdateNumPageChange(CCmdUI* pCmdUI)
  853. {
  854.     if (m_nZoomState == ZOOM_OUT && m_nMaxPages != 1)
  855.     {
  856.         CString text;
  857.         VERIFY(text.LoadString((m_nPages == 1) ?
  858.             AFX_IDS_TWOPAGE : AFX_IDS_ONEPAGE));
  859.         pCmdUI->SetText(text);
  860.         pCmdUI->Enable(TRUE);
  861.     }
  862.     else
  863.     {
  864.         pCmdUI->Enable(FALSE);
  865.     }
  866. }
  867.  
  868. void CPreviewView::OnUpdateNextPage(CCmdUI* pCmdUI)
  869. {
  870.     // enable if not showing last page
  871.     pCmdUI->Enable(m_nCurrentPage+m_nPages-1 < m_pPreviewInfo->GetMaxPage());
  872. }
  873.  
  874. void CPreviewView::OnUpdatePrevPage(CCmdUI* pCmdUI)
  875. {
  876.     // enable if not showing First page
  877.     pCmdUI->Enable(m_nCurrentPage > m_pPreviewInfo->GetMinPage());
  878. }
  879.  
  880. void CPreviewView::OnUpdateZoomIn(CCmdUI* pCmdUI)
  881. {
  882.     pCmdUI->Enable(m_nZoomState != ZOOM_IN);
  883. }
  884.  
  885. void CPreviewView::OnUpdateZoomOut(CCmdUI* pCmdUI)
  886. {
  887.     pCmdUI->Enable(m_nZoomState != ZOOM_OUT);
  888. }
  889.  
  890.  
  891. BOOL CPreviewView::OnSetCursor(CWnd* pWnd, UINT nHitTest, UINT message)
  892. {
  893.     if (nHitTest != HTCLIENT)
  894.         return CScrollView::OnSetCursor(pWnd, nHitTest, message);
  895.  
  896.     CPoint point;
  897.     ::GetCursorPos(&point);
  898.     ScreenToClient(&point);     // client coordinates of mouse position
  899.  
  900.     UINT nPage;
  901.     if (m_nZoomState != ZOOM_IN && FindPageRect(point, nPage))
  902.     {                       // On a page and not zoomed all the way in
  903.         if (m_hMagnifyCursor == NULL)
  904.             m_hMagnifyCursor = ::LoadCursor(AfxGetInstanceHandle(),
  905.                                             MAKEINTRESOURCE(AFX_IDC_MAGNIFY));
  906.  
  907.         ::SetCursor(m_hMagnifyCursor);
  908.     }
  909.     else
  910.     {
  911.         ::SetCursor(::LoadCursor(NULL, IDC_ARROW));
  912.     }
  913.     return 0;
  914. }
  915.  
  916.     
  917.  
  918. /////////////////////////////////////////////////////////////////////////////
  919. // CPreviewView diagnostics
  920.  
  921. #ifdef _DEBUG
  922. void CPreviewView::AssertValid() const
  923. {
  924.     CView::AssertValid();
  925.     ASSERT_VALID(&m_dcPrint);
  926.     if (m_pPreviewDC != NULL)
  927.         ASSERT_VALID(m_pPreviewDC);
  928.  
  929.     switch (m_nZoomState)
  930.     {
  931.     case ZOOM_OUT:
  932.     case ZOOM_IN:
  933.     case ZOOM_MIDDLE:
  934.         break;
  935.     default:
  936.         ASSERT(FALSE); // unknown zoom state
  937.     }
  938.  
  939.     switch (m_nMapMode)
  940.     {
  941.     case MM_TEXT:
  942.     case MM_LOMETRIC:
  943.     case MM_HIMETRIC:
  944.     case MM_LOENGLISH:
  945.     case MM_HIENGLISH:
  946.     case MM_TWIPS:
  947.     case MM_ISOTROPIC:
  948.     case MM_ANISOTROPIC:
  949.         break;
  950.     default:
  951.         ASSERT(FALSE); // unknown mapping mode
  952.     }
  953. }
  954.  
  955. void CPreviewView::Dump(CDumpContext& dc) const
  956. {
  957.     CView::Dump(dc);
  958.     AFX_DUMP1(dc, "\nm_pPrintView = ", m_pPrintView);
  959.     AFX_DUMP1(dc, "\nm_pOrigView = ", m_pOrigView);
  960.     AFX_DUMP1(dc, "\nm_bPageNumDisplayed = ", m_bPageNumDisplayed);
  961.     AFX_DUMP1(dc, "\nm_bCenter = ", m_bCenter);
  962.     AFX_DUMP1(dc, "\nm_nPages = ", m_nPages);
  963.     AFX_DUMP1(dc, "\nm_nCurrentPage ", m_nCurrentPage);
  964.     AFX_DUMP1(dc, "\nm_nSecondPageOffset ", m_nSecondPageOffset);
  965.     AFX_DUMP1(dc, "\nm_nMaxPages = ", m_nMaxPages);
  966.     AFX_DUMP1(dc, "\nm_sizePrinterPPI = ", m_sizePrinterPPI);
  967.     AFX_DUMP1(dc, "\nm_ptCenterPoint = ", m_ptCenterPoint);
  968.     AFX_DUMP0(dc, "\nm_nZoomState = ");
  969.     switch (m_nZoomState)
  970.     {
  971.     case ZOOM_OUT:
  972.         AFX_DUMP0(dc, "ZOOM_OUT");
  973.         break;
  974.     case ZOOM_IN:
  975.         AFX_DUMP0(dc, "ZOOM_IN");
  976.         break;
  977.     case ZOOM_MIDDLE:
  978.         AFX_DUMP0(dc, "ZOOM_MIDDLE");
  979.         break;
  980.     default:
  981.         AFX_DUMP0(dc, "*unknown*");
  982.         break;
  983.     }
  984.     AFX_DUMP0(dc, "\nm_nMapMode = ");
  985.     switch (m_nMapMode)
  986.     {
  987.     case MM_TEXT:
  988.         AFX_DUMP0(dc, "MM_TEXT");
  989.         break;
  990.     case MM_LOMETRIC:
  991.         AFX_DUMP0(dc, "MM_LOMETRIC");
  992.         break;
  993.     case MM_HIMETRIC:
  994.         AFX_DUMP0(dc, "MM_HIMETRIC");
  995.         break;
  996.     case MM_LOENGLISH:
  997.         AFX_DUMP0(dc, "MM_LOENGLISH");
  998.         break;
  999.     case MM_HIENGLISH:
  1000.         AFX_DUMP0(dc, "MM_HIENGLISH");
  1001.         break;
  1002.     case MM_TWIPS:
  1003.         AFX_DUMP0(dc, "MM_TWIPS");
  1004.         break;
  1005.     case MM_ISOTROPIC:
  1006.         AFX_DUMP0(dc, "MM_ISOTROPIC");
  1007.         break;
  1008.     case MM_ANISOTROPIC:
  1009.         AFX_DUMP0(dc, "MM_ANISOTROPIC");
  1010.         break;
  1011.     default:
  1012.         AFX_DUMP0(dc, "*unknown*");
  1013.         break;
  1014.     }
  1015.     AFX_DUMP1(dc, "\nm_dcPrint = ", &m_dcPrint);
  1016.     if (m_pPreviewDC != NULL)
  1017.         AFX_DUMP1(dc, "\nm_pPreviewDC = ", m_pPreviewDC);
  1018. }
  1019. #endif //_DEBUG
  1020.  
  1021. /////////////////////////////////////////////////////////////////////////////
  1022.