viewprev.cpp 30 KB

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