Click here to Skip to main content
15,893,814 members
Articles / Desktop Programming / MFC

MFC Extension library : Enhanced print preview plug-in

Rate me:
Please Sign up or sign in to vote.
4.65/5 (9 votes)
24 May 2004CPOL8 min read 67.8K   1.8K   49  
MFC Extension library : Enhanced print preview plug-in
// MultiPagePreview.cpp 

#include "stdafx.h"
#include "MultiPagePreview.h"
#include "resource.h"
#include "MyDialogBar.h"

#ifdef _DEBUG
#define new DEBUG_NEW
#undef THIS_FILE
static char THIS_FILE[] = __FILE__;
#endif

extern HINSTANCE	hDLLInstance;

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;
	
	// NOTE : If you change m_nPages outside of this code you will also need to modify
	// the m_Across and m_Down member vars to get the pages to show correctly
	m_pMaps = NULL;
	m_MapCount = 0;

	CPlugInApp *pApp = static_cast<CPlugInApp*>(AfxGetApp());
    // get our pointers to any plug in maps
	m_pMaps = pApp->GetMessageMaps(this, m_MapCount);
}

CMultiPagePreviewView::~CMultiPagePreviewView()
{
	// release message map pointers
	for (int i = 0; i < m_MapCount; ++i)
	{
		delete m_pMaps[i];
		m_pMaps[i] = NULL;
	}
	delete []m_pMaps;
	m_pMaps = NULL;
	m_state.SetDestroyed();
}

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()
	ON_WM_MOUSEWHEEL()
	//}}AFX_MSG_MAP
	ON_WM_VSCROLL()
	ON_COMMAND(ID_PREVIEW_PAGES, OnPreviewPages)
	ON_COMMAND(IDC_LANDSCAPE, OnLandscape)
	ON_NOTIFY_EX(TTN_NEEDTEXT, 0, OnToolTipNotify)
    ON_COMMAND(IDC_PRINT_SETUP, OnPrintSetup)
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));
	}
	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;
	}
}

int CMultiPagePreviewView::OnCreate(LPCREATESTRUCT lpCreateStruct) 
{
	if (CPreviewView::OnCreate(lpCreateStruct) == -1)
	{
		return -1;
	}
	
	CWinApp *pApp = AfxGetApp();
	CPlugInApp *pOurApp = static_cast<CPlugInApp*>(pApp);
	ASSERT(pOurApp);
	
	// Switch to our CDialogBar derived class to get the mouse wheel working
	m_pToolBar->DestroyWindow();
	m_pToolBar = NULL;
	m_pToolBar = new CMyDialogBar;
	CFrameWnd* pParent = STATIC_DOWNCAST(CFrameWnd, AfxGetMainWnd());
	if (!m_pToolBar->Create(pParent, MAKEINTRESOURCE(IDD_PREVIEW),	CBRS_TOP, AFX_IDW_PREVIEW_BAR))
	{
		TRACE0("Error: Preview could not create toolbar dialog.\n");
		delete m_pToolBar;       // not autodestruct yet
		m_pToolBar = NULL;
		return FALSE;
	}
	CMyDialogBar *pMyDialogBar = static_cast<CMyDialogBar*>(m_pToolBar);
	ASSERT(pMyDialogBar);
	pMyDialogBar->SetViewPointer(this);	// so we can get mouse wheel messages
	m_pToolBar->m_bAutoDelete = TRUE;    // automatic cleanup
	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_printSetup.AutoLoad(IDC_PRINT_SETUP, m_pToolBar, IDB_PREV_PRINT_SETUP);
	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 );
	
	if (GetPrintOrientation() == DMORIENT_LANDSCAPE)
	{
		// check the landscape button
		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
		pButton->SetCheck(1);								// set the check mark
	}
	
	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);
	
	// NOTE : If you need to enable or disable the menu items in this list based on the number of
	// pages in your printout, you can either do it here before the menu is diaplyed, or write a handler
	// for the WM_INITMENUPOPUP message and configure the enabled/disabled state at that point.
	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 portrait 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?
	
	int		old_page = m_nCurrentPage;					// save page number as it gets reset
	
    // call the OnEndPrinting as required
//    m_pPrintView->OnEndPrinting(m_pPreviewDC, m_pPreviewInfo);

    // get the current CPrintInfo object
	m_dcPrint.Detach();									// print DC is deleted by CPrintInfo destructor
	delete m_pPreviewInfo;
	m_pPreviewInfo = NULL;
	delete m_pPreviewDC;
	m_pPreviewDC = NULL;
	
    // switch the print mode
	SetPrintOrientation(state ? DMORIENT_LANDSCAPE : DMORIENT_PORTRAIT);
	SetPrintView(m_pPrintView);						// sets up new DC's and print info structure
	m_nCurrentPage = old_page;							// restore as gets reset
	SetupScrollbar();
}

// use the mouse wheel to scroll either through the pages
// or scroll through the zoomed in page.
BOOL CMultiPagePreviewView::OnMouseWheel(UINT nFlags, short zDelta, CPoint pt) 
{
	CPoint	position;
	
	if (m_nZoomState != ZOOM_OUT)
	{
		position = GetScrollPosition();
		// scrolling up / down
		position -= CPoint(0, zDelta);
		CPreviewView::ScrollToPosition(position);
	}
	else
	{
		// scroll selected pages
		if (zDelta > 0 && m_nCurrentPage > 1)
		{
			OnPrevPage();
		}
		else if (zDelta < 0 && m_nCurrentPage < m_pPreviewInfo->GetMaxPage() - (m_nPages - 1))
		{
			OnNextPage();
		}
	}
	return TRUE;
}

BOOL CMultiPagePreviewView::OnToolTipNotify(UINT, NMHDR *pNMHDR, LRESULT*)
{
    TOOLTIPTEXT *pTTT = (TOOLTIPTEXT *)pNMHDR;
	
    if (pTTT->uFlags & TTF_IDISHWND)
	{
        // idFrom is actually the HWND of the tool
        UINT nID = ::GetDlgCtrlID((HWND)pNMHDR->idFrom);
		
		pTTT->lpszText = NULL;
		
		switch (nID)
		{
		case AFX_ID_PREVIEW_PRINT :
			pTTT->lpszText = "Print the report";
			break;
		case AFX_ID_PREVIEW_NEXT :
			pTTT->lpszText = "Move to next page";
			break;
		case AFX_ID_PREVIEW_PREV :
			pTTT->lpszText = "Move to previous page";
			break;
		case ID_PREVIEW_PAGES :
			pTTT->lpszText = "Select the number of pages to preview at a time";
			break;
		case AFX_ID_PREVIEW_ZOOMIN :
			pTTT->lpszText = "Zoom in";
			break;
		case AFX_ID_PREVIEW_ZOOMOUT :
			pTTT->lpszText = "Zoom out";
			break;
		case AFX_ID_PREVIEW_CLOSE :
			pTTT->lpszText = "Close print preview mode";
			break;
		case IDC_LANDSCAPE :
			pTTT->lpszText = "Switch between portrait and landscape print orientation";
			break;
        case IDC_PRINT_SETUP:
            pTTT->lpszText = "Print setup";
            break;
		default :
			pTTT->lpszText = "Unrecognised control ID";
			break;
		}
		return TRUE;
	}
	
	return FALSE;
}

BOOL CMultiPagePreviewView::OnCmdMsg(UINT nID, int nCode, void* pExtra, AFX_CMDHANDLERINFO* pHandlerInfo) 
{
	// check to see whether any of the plug-in DLL's
	// want to intercept this message and process it before the application class
	CPlugInApp *pApp = static_cast<CPlugInApp*>(AfxGetApp());
	CPIState	stateCopy(m_state);

	ASSERT(pApp);
	BOOL ret_pre = FALSE;
	BOOL ret_app = FALSE;
	BOOL ret_post = FALSE;
	m_bSuppressThisMessage = false;
	
	// allow DLL's to process this message before the exe
	ret_pre = pApp->ProcessCommandMessageMaps(stateCopy, true, &m_bSuppressThisMessage, m_pMaps, m_MapCount, nID, nCode, pExtra, pHandlerInfo);
	if (!m_bSuppressThisMessage)
		{
		// allow the exe to process the message is it hasn't been suppressed by a DLL
		ret_app = CPreviewView::OnCmdMsg(nID, nCode, pExtra, pHandlerInfo);
		}
	// allow DLL to process the message after the exe
	// note that DLLs get to do this whether the message has been supressed or not
	if (!stateCopy.IsDestroyed())
	{
		ret_post = pApp->ProcessCommandMessageMaps(stateCopy, false, &m_bSuppressThisMessage, m_pMaps, m_MapCount, nID, nCode, pExtra, pHandlerInfo);
	}

	if (ret_pre || ret_app || ret_post)
		return  TRUE;
	return FALSE;
}

BOOL CMultiPagePreviewView::OnWndMsg(UINT message, WPARAM wParam, LPARAM lParam, LRESULT* pResult)
{
	LRESULT	lResult;
	// special case for commands
	if (message == WM_COMMAND)
		{
		if (OnCommand(wParam, lParam))
			{
			lResult = 1;
			if (pResult != NULL)
				*pResult = lResult;
			return TRUE;
			}
		return FALSE;
		}

	// special case for notifies
	if (message == WM_NOTIFY)
		{
		NMHDR* pNMHDR = (NMHDR*)lParam;
		if (pNMHDR->hwndFrom != NULL && OnNotify(wParam, lParam, &lResult))
			{
			if (pResult != NULL)
				*pResult = lResult;
			return TRUE;
			}
		return FALSE;
		}

	// check to see whether any of the plug-in DLL's
	// want to intercept this message and process it before the application class
	CPlugInApp *pApp = static_cast<CPlugInApp*>(AfxGetApp());
	ASSERT(pApp);
	CPIState	stateCopy(m_state);
	BOOL ret_pre = FALSE;
	BOOL ret_app = FALSE;
	BOOL ret_post = FALSE;
	m_bSuppressThisMessage = false;
	// allow DLL's to process this message before the exe
	ret_pre = pApp->ProcessWindowMessageMaps(stateCopy, true, &m_bSuppressThisMessage, m_pMaps, m_MapCount, message, wParam, lParam, pResult);
	if (!m_bSuppressThisMessage)
		{
		// allow the exe to process the message is it hasn't been suppressed by a DLL
		ret_app = CPreviewView::OnWndMsg(message, wParam, lParam, pResult);
		}
	if (!stateCopy.IsDestroyed())
	{
		// allow DLL to process the message after the exe
		// note that DLLs get to do this whether the message has been supressed or not
		ret_pre = pApp->ProcessWindowMessageMaps(stateCopy, false, &m_bSuppressThisMessage, m_pMaps, m_MapCount, message, wParam, lParam, pResult);
	}

	if (ret_pre || ret_app || ret_post)
		return  TRUE;
	return FALSE;
}

int CMultiPagePreviewView::GetPrintOrientation() const
{
    PRINTDLG	pd;
    int         orientation;

    pd.lStructSize = (DWORD)sizeof(PRINTDLG);
    BOOL bRet = AfxGetApp()->GetPrinterDeviceDefaults(&pd);
    if (bRet)
    {
        // protect memory handle with ::GlobalLock and ::GlobalUnlock
        DEVMODE *pDevMode = (DEVMODE*)::GlobalLock(pd.hDevMode);
        orientation = pDevMode->dmOrientation;
        ::GlobalUnlock(pd.hDevMode);
    }
    return orientation;
}

bool CMultiPagePreviewView::SetPrintOrientation(int mode) const
{
    PRINTDLG	pd;

    pd.lStructSize = (DWORD)sizeof(PRINTDLG);
    BOOL bRet = AfxGetApp()->GetPrinterDeviceDefaults(&pd);

    if (bRet)
    {
        switch (mode)
	        {
	        case DMORIENT_PORTRAIT :
			        {
			        // portrait mode
			        LPDEVMODE pDevMode = (LPDEVMODE)::GlobalLock(pd.hDevMode) ;
			        // set orientation to portrait
			        pDevMode->dmOrientation = DMORIENT_PORTRAIT ;
			        ::GlobalUnlock(pd.hDevMode) ;
			        }
			        break ;
	        case DMORIENT_LANDSCAPE :
			        {
			        // landscape mode
			        LPDEVMODE pDevMode = (LPDEVMODE)::GlobalLock(pd.hDevMode) ;
			        // set orientation to landscape
			        pDevMode->dmOrientation = DMORIENT_LANDSCAPE ;
			        ::GlobalUnlock(pd.hDevMode) ;
			        }
			        break ;
	        default :	
			        ASSERT(FALSE) ;		// invalid parameter
			        return false ;
	        }
        return true ;
    }
    return false;
}

void CMultiPagePreviewView::OnPrintSetup()
{
    CWinApp *pApp = AfxGetApp();
    CPrintDialog pd(TRUE);
    if (pApp->DoPrintDialog(&pd))
    {
        // call the OnEndPrinting as required
//        m_pPrintView->OnEndPrinting(m_pPreviewDC, m_pPreviewInfo);

        CPrintInfo *pInfo = m_pPreviewInfo;
        m_pPreviewInfo = NULL;

        m_dcPrint.Detach(); // print DC is deleted by CPrintInfo destructor
        delete pInfo;
        SetPrintView(m_pPrintView);

	    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
	    if (GetPrintOrientation() == DMORIENT_LANDSCAPE)
	    {
		    // check the landscape button
		    pButton->SetCheck(1);								// set the check mark
	    }
        else
        {
		    pButton->SetCheck(0);								// clear the check mark
        }
    }
}

By viewing downloads associated with this article you agree to the Terms of Service and the article's licence.

If a file you wish to view isn't highlighted, and is a text file (not binary), please let us know and we'll add colourisation support for it.

License

This article, along with any associated source code and files, is licensed under The Code Project Open License (CPOL)


Written By
Software Developer (Senior) Sirius Analytical Instruments
United Kingdom United Kingdom
A research and development programmer working for a pharmaceutical instrument company for the past 17 years.

I am one of those lucky people who enjoys his work and spends more time than he should either doing work or reseaching new stuff. I can also be found on playing DDO on the Cannith server (Send a tell to "Maetrim" who is my current main)

I am also a keep fit fanatic, doing cross country running and am seriously into [url]http://www.ryushinkan.co.uk/[/url] Karate at this time of my life, training from 4-6 times a week and recently achieved my 1st Dan after 6 years.

Comments and Discussions