// MultiPagePreview.cpp
#include "stdafx.h"
#include "MultiPagePreview.h"
#include "MultiPagePrintPreview.h"
#include "resource.h"
#ifdef _DEBUG
#define new DEBUG_NEW
#undef THIS_FILE
static char THIS_FILE[] = __FILE__;
#endif
IMPLEMENT_DYNCREATE(CMultiPagePreviewView, CPreviewView)
CMultiPagePreviewView::CMultiPagePreviewView()
{
// replace the PAGE_INFO array with our one to make sure its large enough
m_pPageInfo = m_pageInfoArray2;
m_Across = 2 ; // default number of pages across the screen
m_Down = 1 ; // default number of pages down the screen
m_nPages = 2 ;
}
CMultiPagePreviewView::~CMultiPagePreviewView()
{
}
BEGIN_MESSAGE_MAP(CMultiPagePreviewView, CPreviewView)
//{{AFX_MSG_MAP(CMultiPagePreviewView)
ON_COMMAND(AFX_ID_PREVIEW_NUMPAGE, OnNumPageChange)
ON_COMMAND(AFX_ID_PREVIEW_ZOOMIN, OnZoomIn)
ON_COMMAND(AFX_ID_PREVIEW_ZOOMOUT, OnZoomOut)
ON_UPDATE_COMMAND_UI(AFX_ID_PREVIEW_NUMPAGE, OnUpdateNumPageChange)
ON_UPDATE_COMMAND_UI(AFX_ID_PREVIEW_ZOOMIN, OnUpdateZoomIn)
ON_UPDATE_COMMAND_UI(AFX_ID_PREVIEW_ZOOMOUT, OnUpdateZoomOut)
ON_WM_CREATE()
ON_WM_LBUTTONDOWN()
ON_WM_SETCURSOR()
//}}AFX_MSG_MAP
ON_WM_VSCROLL()
ON_COMMAND(ID_PREVIEW_PAGES, OnPreviewPages)
ON_COMMAND(IDC_LANDSCAPE, OnLandscape)
END_MESSAGE_MAP()
BOOL CMultiPagePreviewView::PreCreateWindow(CREATESTRUCT& cs)
{
if (cs.lpszClass == NULL)
cs.lpszClass = AfxRegisterWndClass(CS_DBLCLKS|CS_HREDRAW|CS_VREDRAW|CS_BYTEALIGNCLIENT);
return CView::PreCreateWindow(cs);
}
#ifdef _DEBUG
void CMultiPagePreviewView::AssertValid() const
{
// Bug nearby Article ID: Q192853
// CPreviewView::AssertValid();
}
void CMultiPagePreviewView::Dump(CDumpContext& dc) const
{
TRACE("Dump\n") ;
CPreviewView::Dump(dc);
}
#endif //_DEBUG
BOOL CMultiPagePreviewView::OnSetCursor(CWnd* pWnd, UINT nHitTest, UINT message)
{
if (nHitTest != HTCLIENT)
return CScrollView::OnSetCursor(pWnd, nHitTest, message);
CPoint point;
::GetCursorPos(&point);
ScreenToClient(&point); // client coordinates of mouse position
UINT nPage;
if (m_nZoomState != ZOOM_IN_400 &&
FindPageRect(point, nPage))
{ // On a page and not zoomed all the way in
if (m_hMagnifyCursor == NULL)
{
HINSTANCE hInst = AfxFindResourceHandle(
MAKEINTRESOURCE(AFX_IDC_MAGNIFY), RT_GROUP_CURSOR);
m_hMagnifyCursor = ::LoadCursor(hInst,
MAKEINTRESOURCE(AFX_IDC_MAGNIFY));
}
::SetCursor(m_hMagnifyCursor);
}
else
{
::SetCursor(::LoadCursor(NULL, IDC_ARROW));
}
return 0;
}
void CMultiPagePreviewView::OnLButtonDown(UINT, CPoint point)
{
UINT nPage;
if (!FindPageRect(point, nPage))
{
return; // Didn't click on a page
}
// Set new zoom state
SetZoomState((m_nZoomState == ZOOM_IN_400) ? ZOOM_OUT : m_nZoomState + 1, nPage, point);
if (m_nZoomState == ZOOM_OUT)
{
// make sure the current page does not cause blank pages to be shown
if (m_nCurrentPage >= m_pPreviewInfo->GetMaxPage() - m_nPages)
m_nCurrentPage = m_pPreviewInfo->GetMaxPage() - m_nPages + 1;
if (m_nCurrentPage < 0)
m_nCurrentPage = 0 ;
}
}
void CMultiPagePreviewView::SetZoomState(UINT nNewState, UINT nPage, CPoint point)
{
if (m_nZoomState != nNewState)
{
m_nZoomState = nNewState;
DoZoom(nPage, point);
}
}
// Actual zoom code.
void CMultiPagePreviewView::DoZoom(UINT nPage, CPoint point)
{
if (m_nZoomState == ZOOM_OUT)
{
// taking over scroll bars
m_nPages = m_nZoomOutPages;
ShowScrollBar(SB_HORZ, FALSE); // hide the horizontal bar
BOOL bShowBar = m_pPreviewInfo->GetMaxPage() < 0x8000 &&
m_pPreviewInfo->GetMaxPage() -
m_pPreviewInfo->GetMinPage() <= 32767U;
ShowScrollBar(SB_VERT, bShowBar); // Show the vertical bar
if (bShowBar)
{
SCROLLINFO info;
info.fMask = SIF_PAGE | SIF_RANGE;
info.nMin = m_pPreviewInfo->GetMinPage();
info.nMax = m_pPreviewInfo->GetMaxPage();
info.nPage = 1;
if (!SetScrollInfo(SB_VERT, &info, FALSE))
SetScrollRange(SB_VERT, info.nMin, info.nMax, FALSE);
}
SetCurrentPage(m_nCurrentPage, TRUE);
SetupScrollbar() ;
}
else
{
m_nPages = 1; // only one page in zoomed states
m_pPageInfo[0].sizeZoomOutRatio = m_pPageInfo[nPage].sizeZoomOutRatio;
m_pPageInfo[0].sizeUnscaled = m_pPageInfo[nPage].sizeUnscaled;
// Sets the printer page
SetCurrentPage(m_nCurrentPage + nPage, FALSE);
SetScaledSize(0);
CSize* pRatio = &m_pPageInfo[nPage].sizeScaleRatio;
// convert Hit Point from screen 1:1
point.x = MulDiv(point.x, pRatio->cx, pRatio->cy);
point.y = MulDiv(point.y, pRatio->cx, pRatio->cy);
// Adjust point for page position
point += (CSize)m_pPageInfo[0].rectScreen.TopLeft();
// Scroll to center
CenterOnPoint(point);
}
}
void CMultiPagePreviewView::PositionPage(UINT nPage)
{
CSize windowSize = CalcPageDisplaySize();
VERIFY(m_dcPrint.Escape(GETPHYSPAGESIZE, 0, NULL, (LPVOID)&m_pPageInfo[nPage].sizeUnscaled));
CSize* pSize = &m_pPageInfo[nPage].sizeUnscaled;
// Convert page size to screen coordinates
pSize->cx = MulDiv(pSize->cx, afxData.cxPixelsPerInch, m_sizePrinterPPI.cx);
pSize->cy = MulDiv(pSize->cy, afxData.cyPixelsPerInch, m_sizePrinterPPI.cy);
m_pPageInfo[nPage].sizeZoomOutRatio = CalcScaleRatio(windowSize, *pSize);
SetScaledSize(nPage);
}
#define PREVIEW_MARGIN 8
#define PREVIEW_PAGEGAP 8
void CMultiPagePreviewView::SetScaledSize(UINT nPage)
{
CSize* pSize = &m_pPageInfo[nPage].sizeUnscaled;
CSize* pRatio = &m_pPageInfo[nPage].sizeScaleRatio;
CSize* pZoomOutRatio = &m_pPageInfo[nPage].sizeZoomOutRatio;
CSize windowSize = CalcPageDisplaySize();
BOOL bPaperLarger = pZoomOutRatio->cx < pZoomOutRatio->cy;
// whether the paper is larger than the screen, or vice versa
switch (m_nZoomState)
{
case ZOOM_OUT:
*pRatio = *pZoomOutRatio;
break;
case ZOOM_MIDDLE:
// the middle zoom state is a ratio between cx/cy and
// 1/1 (or cy/cy). It is, therefore:
//
// (cx + cy)/2
// -----------
// cy
//
// if the paper is larger than the screen, or
//
// (3*cx - cy)/2
// -------------
// cy
//
// if the paper is smaller than the screen.
if (bPaperLarger)
{
pRatio->cy = pZoomOutRatio->cy;
pRatio->cx = (pZoomOutRatio->cx + pRatio->cy) / 2;
}
else
{
pRatio->cy = pZoomOutRatio->cy;
pRatio->cx = (3*pZoomOutRatio->cx - pRatio->cy) / 2;
}
break;
case ZOOM_IN:
if (bPaperLarger)
{
pRatio->cx = pRatio->cy = 1;
}
else
{
// if the paper is smaller than the screen space we're displaying
// it in, then using a ratio of 1/1 will result in a smaller image
// on the screen, not a larger one. To get a larger image in this
// case we double the zoom out ratio.
pRatio->cy = pZoomOutRatio->cy;
pRatio->cx = 2*pZoomOutRatio->cx - pZoomOutRatio->cy;
}
break;
case ZOOM_IN_150:
pRatio->cx = 15;
pRatio->cy = 10;
break;
case ZOOM_IN_200:
pRatio->cx = 25;
pRatio->cy = 10;
break;
case ZOOM_IN_400:
pRatio->cx = 4;
pRatio->cy = 1;
break;
default:
ASSERT(FALSE);
}
// Convert to scaled size
CSize scaledSize;
scaledSize.cx = MulDiv(pSize->cx, pRatio->cx, pRatio->cy);
scaledSize.cy = MulDiv(pSize->cy, pRatio->cx, pRatio->cy);
CRect* pRect = &m_pPageInfo[nPage].rectScreen;
pRect->SetRect(PREVIEW_MARGIN, PREVIEW_MARGIN,
scaledSize.cx + PREVIEW_MARGIN + 3,
scaledSize.cy + PREVIEW_MARGIN + 3);
if (m_nZoomState == ZOOM_OUT)
{
pRect->OffsetRect((windowSize.cx - pRect->Size().cx) / 2 - 1, (windowSize.cy - pRect->Size().cy) / 2 - 1);
// we need to offste the page multiple times
int local = nPage % m_Across ;
while (local-- >= 1)
{
pRect->OffsetRect(m_PageOffset.x, 0);
}
local = nPage / m_Across ;
while (local-- > 0)
{
pRect->OffsetRect(0, m_PageOffset.y);
}
}
else
{
// set up scroll size
SetScrollSizes(MM_TEXT, pRect->Size() +
CSize(PREVIEW_MARGIN * 2, PREVIEW_MARGIN * 2), windowSize);
}
}
/////////////////////////////////////////////////////////////////////////////
// CMultiPagePreviewView
void CMultiPagePreviewView::OnUpdateNumPageChange(CCmdUI* pCmdUI)
{
// button has been removed from toolbar
//UINT nPages = m_nZoomState == ZOOM_OUT ? m_nPages : m_nZoomOutPages;
//pCmdUI->Enable(m_nZoomState == ZOOM_OUT && m_nMaxPages != 1 && (m_pPreviewInfo->GetMaxPage() > 1 || m_nPages > 1));
// CPreviewView::OnUpdateNumPageChange(pCmdUI);
}
void CMultiPagePreviewView::OnUpdateZoomIn(CCmdUI* pCmdUI)
{
pCmdUI->Enable(m_nZoomState != ZOOM_IN_400);
}
void CMultiPagePreviewView::OnUpdateZoomOut(CCmdUI* pCmdUI)
{
pCmdUI->Enable(m_nZoomState != ZOOM_OUT);
}
void CMultiPagePreviewView::OnNumPageChange()
{
// doesn't do anything any more
// button has been removed from toolbar
}
void CMultiPagePreviewView::OnZoomIn()
{
if (m_nZoomState != ZOOM_IN_400)
SetZoomState(m_nZoomState + 1, 0, CPoint(0, 0));
}
void CMultiPagePreviewView::OnZoomOut()
{
if (m_nZoomState != ZOOM_OUT)
SetZoomState(m_nZoomState - 1, 0, CPoint(0, 0));
}
int CMultiPagePreviewView::OnCreate(LPCREATESTRUCT lpCreateStruct)
{
if (CPreviewView::OnCreate(lpCreateStruct) == -1)
return -1;
m_pToolBar->EnableToolTips( TRUE );
// make the buttons on the dialog bar bitmap buttons
m_print.AutoLoad( AFX_ID_PREVIEW_PRINT, m_pToolBar, IDB_PREV_PRINT );
m_next.AutoLoad( AFX_ID_PREVIEW_NEXT, m_pToolBar, IDB_PREV_NEXT );
m_previous.AutoLoad( AFX_ID_PREVIEW_PREV, m_pToolBar, IDB_PREV_PREVIOUS );
m_zoomIn.AutoLoad( AFX_ID_PREVIEW_ZOOMIN, m_pToolBar, IDB_PREV_ZOOMIN );
m_zoomOut.AutoLoad( AFX_ID_PREVIEW_ZOOMOUT, m_pToolBar, IDB_PREV_ZOOMOUT );
m_pages.AutoLoad(ID_PREVIEW_PAGES, m_pToolBar, IDB_PAGES );
return 0;
}
CSize CMultiPagePreviewView::CalcPageDisplaySize()
// calculate the current page size
// MFC used to set 'm_nSecondPageOffset' to start of second page
// as we have multiple pages we use m_PageOffset which holds the
// diferences across and down the pages
// return size of current page less margins
{
// just checking...
ASSERT(m_Down >= 1) ;
ASSERT(m_Across >= 1) ;
ASSERT(m_nPages >= 1) ;
CSize windowSize, scrollSize;
GetTrueClientSize(windowSize, scrollSize);
// subtract out vertical scrollbar if zoomed out and page range is known
// and there is more than one page.
if (m_nZoomState == ZOOM_OUT && (m_pPreviewInfo->GetMaxPage() != 0xffff) && (m_pPreviewInfo->GetMaxPage() - m_pPreviewInfo->GetMinPage() != 0))
windowSize.cx -= scrollSize.cx;
m_PageOffset.y = 0 ;
if (m_Down > 1)
{
// we need to make room for more pages under the first
windowSize.cy = (windowSize.cy - (PREVIEW_MARGIN * (m_Down - 1))) / m_Down ;
m_PageOffset.y = windowSize.cy + PREVIEW_MARGIN ;
}
else
{
// its a single page down, it uses all the area previouslyy calculated
}
if (m_Across <= 2)
m_PageOffset.x = (windowSize.cx - PREVIEW_MARGIN) / 2;
else
m_PageOffset.x = (windowSize.cx - PREVIEW_MARGIN) / m_Across ;
// make sure all pages across fit in the screen area
windowSize.cx = (windowSize.cx - ((m_Across + 1) * PREVIEW_MARGIN)) / m_Across ;
//windowSize.cx = (m_nPages == 2) ? (windowSize.cx - 3*PREVIEW_MARGIN) / 2 :
// windowSize.cx - 2*PREVIEW_MARGIN;
windowSize.cy -= 2*PREVIEW_MARGIN;
return windowSize;
}
void CMultiPagePreviewView::OnPreviewPages()
{
CPoint point ;
CRect rect ;
CWnd *pWnd = m_pToolBar->GetDlgItem(ID_PREVIEW_PAGES) ;
if (pWnd != NULL)
{
// place the menu just below the button
pWnd->GetWindowRect(&rect) ;
point = CPoint(rect.left, rect.bottom) ;
}
else
::GetCursorPos(&point) ; // failed to get window, use the mouse position
CMenu menu ;
CMenu *pSub ;
// popup a menu to get the number of pages to display
VERIFY(menu.LoadMenu(IDR_PREVIEW_PAGES)) ;
pSub = menu.GetSubMenu(0) ;
int command = pSub->TrackPopupMenu(TPM_LEFTALIGN | TPM_LEFTBUTTON | TPM_RETURNCMD, point.x, point.y, this) ;
switch (command)
{
case ID_PAGES_1PAGE :
m_Across = 1 ;
m_Down = 1 ;
m_nPages = 1 ;
break ;
case ID_PAGES_2PAGES :
m_Across = 2 ;
m_Down = 1 ;
m_nPages = 2 ;
break ;
case ID_PAGES_3PAGES :
m_Across = 3 ;
m_Down = 1 ;
m_nPages = 3 ;
break ;
case ID_PAGES_4PAGES :
m_Across = 2 ;
m_Down = 2 ;
m_nPages = 4 ;
break ;
case ID_PAGES_6PAGES :
m_Across = 3 ;
m_Down = 2 ;
m_nPages = 6 ;
break ;
case ID_PAGES_9PAGES :
m_Across = 3 ;
m_Down = 3 ;
m_nPages = 9 ;
break ;
default :
return ;
}
AfxGetApp()->m_nNumPreviewPages = m_nPages;
m_nZoomOutPages = m_nPages;
m_nMaxPages = m_nPages ;
if (m_nZoomState == ZOOM_OUT)
{
// make sure the current page does not cause blank pages to be shown
if (m_nCurrentPage >= m_pPreviewInfo->GetMaxPage() - m_nPages)
m_nCurrentPage = m_pPreviewInfo->GetMaxPage() - m_nPages + 1;
if (m_nCurrentPage < 0)
m_nCurrentPage = 0 ;
}
// Just do this to set the status correctly and invalidate
SetCurrentPage(m_nCurrentPage, TRUE);
SetupScrollbar() ;
}
void CMultiPagePreviewView::SetupScrollbar()
{
// this procedure makes sure that the scroll bar does not allow us to scroll the window
// such that we end up displaying blank pages
// correctly range the scroll bars
if (m_pPreviewInfo->GetMaxPage() < 0x8000 && m_pPreviewInfo->GetMaxPage() - m_pPreviewInfo->GetMinPage() <= 32767U)
{
SCROLLINFO info;
info.fMask = SIF_PAGE|SIF_RANGE;
info.nMin = m_pPreviewInfo->GetMinPage();
info.nMax = m_pPreviewInfo->GetMaxPage() - (m_nPages - 1) ;
info.nPage = 1;
if (!SetScrollInfo(SB_VERT, &info, FALSE))
SetScrollRange(SB_VERT, info.nMin, info.nMax, FALSE);
}
else
ShowScrollBar(SB_VERT, FALSE); // if no range specified, or too
}
void CMultiPagePreviewView::OnVScroll(UINT nSBCode, UINT nPos, CScrollBar* pScrollBar)
{
if (m_nZoomState != ZOOM_OUT)
{
CScrollView::OnVScroll(nSBCode, nPos, pScrollBar);
return;
}
SetupScrollbar() ;
switch (nSBCode)
{
case SB_BOTTOM:
SetCurrentPage(m_pPreviewInfo->GetMaxPage(), TRUE);
break;
case SB_TOP:
SetCurrentPage(m_pPreviewInfo->GetMinPage(), TRUE);
break;
case SB_PAGEDOWN:
SetCurrentPage(m_nCurrentPage +
(m_pPreviewInfo->GetMaxPage() - m_pPreviewInfo->GetMinPage() + 9) / 10, TRUE);
break;
case SB_PAGEUP:
SetCurrentPage(m_nCurrentPage -
(m_pPreviewInfo->GetMaxPage() - m_pPreviewInfo->GetMinPage() + 9) / 10, TRUE);
break;
case SB_LINEDOWN:
if (m_nCurrentPage <= m_pPreviewInfo->GetMaxPage() - m_nPages)
SetCurrentPage(m_nCurrentPage + 1, TRUE);
break;
case SB_LINEUP:
if (m_nCurrentPage > 0)
SetCurrentPage(m_nCurrentPage - 1, TRUE);
break;
case SB_THUMBPOSITION:
SetCurrentPage(nPos, TRUE);
break;
}
}
void CMultiPagePreviewView::OnLandscape()
{
// switch the preview DC between lanscape and portraite mode.
// we also need to setup the app printer defaults to switch between portrait and
// landscape, so any print action will use the correct settings
// we need to delete the current printer DC and setup a new one after changing the print mode bewteen landscape / portrait
CWnd *pWnd = m_pToolBar->GetDlgItem(IDC_LANDSCAPE) ;
ASSERT(pWnd) ; // the item should exist in the toolbar. If this assert check your resources
CButton *pButton = static_cast<CButton*>(pWnd) ; // get a pointer to the button
ASSERT(pButton) ; // not a button object? If it asserts, then wrong control type in toolbar resource
int state = pButton->GetCheck() ; // portrait or landscape mode?
// get the current CPrintInfo object
CPrintInfo *pInfo = m_pPreviewInfo ;
m_pPreviewInfo = NULL ;
// switch the print mode
CWinApp *pApp = AfxGetApp() ;
CMultiPagePrintPreviewApp *pOurApp = static_cast<CMultiPagePrintPreviewApp*>(pApp) ;
ASSERT(pOurApp) ;
pOurApp->SetPrintOrientation(state ? DMORIENT_LANDSCAPE : DMORIENT_PORTRAIT) ;
m_dcPrint.Detach(); // print DC is deleted by CPrintInfo destructor
delete pInfo ;
SetPrintView(m_pPrintView) ;
}