// ==========================================================================
// 						Class Specification : COXZoomView
// ==========================================================================

// Header file : OXZoomView.h

// Version: 9.3

// This software along with its related components, documentation and files ("The Libraries")
// is © 1994-2007 The Code Project (1612916 Ontario Limited) and use of The Libraries is
// governed by a software license agreement ("Agreement").  Copies of the Agreement are
// available at The Code Project (www.codeproject.com), as part of the package you downloaded
// to obtain this file, or directly from our office.  For a copy of the license governing
// this software, you may contact us at legalaffairs@codeproject.com, or by calling 416-849-8900.                      
                         
// //////////////////////////////////////////////////////////////////////////
// 
// Properties:
//	YES	Abstract class (does not have any objects)
//	YES	Derived from CView

//	YES	Is a Cwnd.                     
//	YES	Two stage creation (constructor & Create())
//	YES Has a message map
//	NO  Needs a resource (template)

//	YES	Persistent objects (saveable on disk)      
//	YES Uses exceptions

// //////////////////////////////////////////////////////////////////////////

// Desciption :         
//	
//		COXZoomView - a virtual base class for views that need zooming and scrolling.
//		It's based on CScrollView, but significantly modified and enhanced
//		Additions/Alterations to CScrollView: 
//		- Handles MM_ANISOTROPIC.
//		- Scrollsizes now definable in percent of the client area, updated on resizing.
//		- ScrollToPosition allows the anchor to be the upper left corner, or additionally
//		  the lower left corner or the center of the window. 
//		- Accepts a CRect for the document size, so the origin can be located in the 
//		  lower left corner or the center or any arbitrary point of the document. You don't
//		  need to handle negative y-coords any more ! 
//		- Zoom level can vary between 10% and 1000%
//		- When zooming, either keeps the upper left window corner, the lower left window
//		  corner or keeps the center.
//		- Allows zooming up to a rectangle (in client coords).
//		- After zooming, the rectangle can be justified to either the upper left or
//		  lower left corner or to the window center.
//		- Allows zooming to the window size (so the scrollbars just disappear).
//		- Output can be aligned to the bottom of the view, when the view's height is 
//		  bigger than the document's.
//
	

// Remark:
//		MM_SCALETOFIT not supported (no need, use CScrollView).
//		Placement in splitter windows not supported (how to handle different zoom levels?).
//		RESTRICTION: the users display shouldn't have more than 3200 pixels in either
//		direction, iow. the viewport extents cannot exceed some 32000 units.

// Prerequisites (necessary conditions):
//		

/////////////////////////////////////////////////////////////////////////////

#ifndef __ZOOMVIEW_H__
#define __ZOOMVIEW_H__ 

#if _MSC_VER >= 1000
#pragma once
#endif // _MSC_VER >= 1000

#include "OXDllExt.h"

#ifdef OXZOOMVIEW_USE_RULER
#include "OXRulerOrganizer.h"
#endif	//	OXZOOMVIEW_USE_RULER

#define ID_MULTICOEF		10

class OX_CLASS_DECL COXZoomView : public CView
{
	DECLARE_DYNAMIC(COXZoomView)

protected:
	COXZoomView();
	virtual ~COXZoomView();

// Data Members
public:

	#ifdef WIN32
		static AFX_DATA const SIZE sizeDefault;
	#else
		static const SIZE AFXAPI_DATA sizeDefault;
	#endif

	// used to specify default calculated page and line sizes
		
    enum ZoomAlignment { ZV_DEFAULT, ZV_TOPLEFT, ZV_BOTTOMLEFT, ZV_CENTER };
    enum { MINZOOM = 10, MAXZOOM = 1000 };

protected:
	int				m_nMapMode;
	CSize			m_totalLog;
	CRect			m_rectLog;
	CSize			m_totalDev;
	CSize			m_pageDev;
	CSize			m_lineDev;
	CSize			m_sizeDev;
	BOOL			m_bCenter;
	BOOL			m_bInsideUpdate;
	int				m_nZoomLevel;
	BOOL			m_bAlignToBottom;
	int				m_nPagePercent;
	int				m_nLinePercent;
	BOOL			m_bUseRelativeScrollSizes;
	ZoomAlignment	m_align;

#ifdef OXZOOMVIEW_USE_RULER
	// ruller object
	COXRulerOrganizer m_ruler;
#endif	//	OXZOOMVIEW_USE_RULER

// Member Functions
public:

	// --- In: pDC: device context in which the filling is to be done
	//		   pBrush: brush with which the area is to be filled
	// --- Out: none
	// --- Returns: none
	// --- Effect: fills the area of the view that appears outside of the scrolling
	//			   area. Use FillOutsideRect in your scroll view’s OnEraseBkgnd handler
	//			   function to prevent excessive background repainting.
	void FillOutsideRect(CDC* pDC, CBrush* pBrush);


	// --- In: none
	// --- Out: none
	// --- Returns: whether alignment to bottom is active or not
	// --- Effect: none
    BOOL GetAlignToBottom() const;

	// --- In: 
	// --- Out:
	// --- Returns: whether centering of the contents is active or not
	// --- Effect: none
    BOOL IsCentered() const;

	
	// --- In: none
	// --- Out: none
	// --- Returns: The horizontal and vertical positions (in device units) of the
	//				scroll boxes as a CPoint object. (in device units)
	// --- Effect: Call GetDeviceScrollPosition when you need the current horizontal and
	//			   vertical positions of the scroll boxes in the scroll bars. This coordinate pair
	//			   corresponds to the location in the document to which the upper-left corner of
	//			   the view has been scrolled. This is useful for offsetting mouse-device positions
	//			   to scroll-view device positions.
	CPoint GetDeviceScrollPosition() const;


	// --- In: none
	// --- Out: nMapMode: the current mapping mode for this view. For a list of possible values,
	//					 see SetScrollSizes.
	//		    sizeTotal: the current total size of the scroll view in device units.
	//		    sizePage: the current horizontal and vertical amounts to scroll in each direction in response
	//					  to a mouse click in a scroll-bar shaft.
	//		    sizeLine: the current horizontal and vertical amounts to scroll in each direction in
	//					  response to a mouse click in a scroll arrow.
	// --- Returns: none
	// --- Effect: Gets the current mapping mode, the total size, and the line and page sizes of the
	//			   scrollable view. Sizes are in device units. This member function is rarely called.
	void GetDeviceScrollSizes(int& nMapMode, SIZE& sizeTotal, SIZE& sizePage, SIZE& sizeLine) const;


	// --- In : align: the alignement of 
	// --- Out : none
	// --- Returns : The horizontal and vertical positions (in device units) of the
	//				scroll boxes as a CPoint object. (logical units)
	// --- Effect :  This call takes an alignment argument, in order to get back the
	//				 position of one of the alignment reference points.
	CPoint GetScrollPosition(ZoomAlignment Align = ZV_DEFAULT) const; 

	
	// --- In : none
	// --- Out : none
	// --- Returns : the logical size
	// --- Effect :
	CSize GetTotalSize() const;


	// --- In: none
	// --- Out: none
	// --- Returns: the state of the zoom alignment
	// --- Effect: none
    ZoomAlignment GetZoomAlign();


	// --- In : none
	// --- Out : none
	// --- Returns : the current zoom level in percent.
	// --- Effect :
	int GetZoomLevel() const;

// maintained for backward compatibility with CScrollView

	// --- In  : nMapMode: the mapping mode to set for this view
	//			 sizeTotal: The total size of the zoom view. The cx member contains
	//						the horizontal extent. The cy member contains the vertical
	//						extent. Sizes are in logical units. Both cx and cy must be
	//						greater than or equal to 0.
	//			 sizePage:	The horizontal and vertical amounts to scroll in each
	//						direction in response to a mouse click in a scroll-bar shaft.
	//			 sizeLine:  The horizontal and vertical amounts to scroll in each
	//						direction in response to a mouse click in a scroll arrow.
	// --- Out : none
	// --- Returns : none
	// --- Effect : Use this to set TEXT, ENGLISH or METRIC mapping modes. You have
	//				to specify the mode and the size of the document. If you are not
	//				using MM_TEXT make the rectangles top member bigger than the bottom
	//				member, because these modes assume that the y coords are getting
	//				bigger downside up. If you make top 0 and bottom negative you'll get
	//				normal CScrollView behaviour, having y always negative ore 0. If you
	//				make bottom 0 and top positive, you y coords are always positive.
	//				You can even shift the origin to the center of your doc by
	//				specifying the proper rectangle.
	void SetScrollSizes(int nMapMode, SIZE sizeTotal,
					    const SIZE& sizePage = sizeDefault,
						const SIZE& sizeLine = sizeDefault);


// three overloaded enhanced Versions to set the sizes
// allows control of logical origin

	// --- In  : nMapMode: the mapping mode to set for this view
	//			 rectDoc: the total size of the document.
	//			 nPagePercent: the amount to scroll in response to a mouse click in a
	//						   scroll-bar shaft
	//			 nLinePercent: the amount to scroll in response to a mouse click in a
	//						   scroll arrow
	// --- Out : none
	// --- Returns : none
	// --- Effect : Use this to set TEXT, ENGLISH or METRIC mapping modes. You have
	//				to specify the mode and the size of the document. If you are not
	//				using MM_TEXT make the rectangles top member bigger than the bottom
	//				member, because these modes assume that the y coords are getting
	//				bigger downside up. If you make top 0 and bottom negative you'll get
	//				normal CScrollView behaviour, having y always negative ore 0. If you
	//				make bottom 0 and top positive, you y coords are always positive.
	//				You can even shift the origin to the center of your doc by
	//				specifying the proper rectangle.
	void SetDeviceScrollSizesRelative(int nMapMode, const CRect& rectDoc, int nPagePercent = 25, int nLinePercent = 5);

	// --- In  : sizeDevice: size of the view in pixels
	//			 rectDoc: the total size of the document.
	//			 nPagePercent: the amount to scroll in response to a mouse click in a
	//						   scroll-bar shaft
	//			 nLinePercent: the amount to scroll in response to a mouse click in a
	//						   scroll arrow
	// --- Out : none
	// --- Returns : none
	// --- Effect : Use this for MM_ANISOTROPIC. You specify the document rectangle
	//				as usual and the corresponding size of the view in pixels. cx and
	//				cy of the size have to be positive, COXZoomView will invert cy if
	//				necessary.
	void SetDeviceScrollSizesRelative(SIZE sizeDevice, const CRect& rectDoc, int nPagePercent = 25, int nLinePercent = 5);

	// --- In  : nMapMode: the mapping mode to set for this view
	//			 sizeTotal: The total size of the zoom view. The cx member contains
	//						the horizontal extent. The cy member contains the vertical
	//						extent. Sizes are in logical units. Both cx and cy must be
	//						greater than or equal to 0.
	//			 nPagePercent: The amount to scroll in response to a mouse click in a
	//						   scroll-bar shaft.
	//			 nLinePercent: The amount to scroll in response to a mouse click in a
	//						   scroll arrow.
	// --- Out : none
	// --- Returns : none
	// --- Effect : this is the most compatible version to CScrollView. This Call will
	//				synthesize a rect based on the passed SIZE and the mapping mode.
	void SetDeviceScrollSizesRelative(int nMapMode, SIZE sizeTotal,	int nPagePercent, int nLinePercent);


	// --- In : bAlignToBottom:
	// --- Out : none
	// --- Returns : none
	// --- Effect : If you call this API with TRUE, COXZoomView will display your data
	//				aligned to the bottom, if the size of the view is bigger than it
	//				has to be to display the whole document.
	void SetAlignToBottom(BOOL bAlignToBottom);

	// --- In : bCenter:
	// --- Out : none
	// --- Returns : none
	// --- Effect : If you call this API with TRUE, COXZoomView will display your data
	//				centered in the screen, if the size of the view is bigger than it
	//				has to be to display the whole document.
	void Center( BOOL bCenter );



	// --- In : align:
	// --- Out : none
	// --- Returns : none
	// --- Effect : This sets the default ZoomAlignment for your view, you can specify
	//				one of the enumerated values: ZV_TOPLEFT, ZV_BOTTOMLEFT, ZV_CENTER.
	void SetZoomAlign(ZoomAlignment align);


	// --- In : nNewLevel: the new zoom level in percent.
	//			align: the new default ZoomAlignment for your view (ZV_TOPLEFT,
	//				   ZV_BOTTOMLEFT, ZV_CENTER)
	// --- Out : none
	// --- Returns : the previous zoom level inpercent
	// --- Effect : Sets the new zoom level and updates the window, using one of the alignment
	//				reference points.
	int SetZoomLevel(int nNewLevel, ZoomAlignment Align = ZV_DEFAULT);


	// --- In: pt: the point to scroll to, in logical units; the cx member must be
	//			   a positive value (greater than or equal to 0, up to the total size
	//			   of the view); the same is true for the cy member when the mapping
	//			   mode is MM_TEXT;
	//			   the cy member is negative in mapping modes other than MM_TEXT.
	//		   align: the new default ZoomAlignment for your view (ZV_TOPLEFT,
	//				  ZV_BOTTOMLEFT, ZV_CENTER)
	// --- Out: none
	// --- Returns: none
	// --- Effect: Scrolls one of the alignment reference points to the desired POINT
	//			   position. If you specify ZV_DEFAULT it uses the value set up with
	//			  SetZoomAlignment.
	void ScrollToPosition(POINT pt, ZoomAlignment Align = ZV_DEFAULT);    

	// --- In: none
	// --- Out: none
	// --- Returns: none
	// --- Effect: Fits the view into the current window and updates the zoom
	//			   level accordingly.
	void ZoomToWindow();


	// --- In: rectZoom: the rectangle you want to zoom out
	//		   align: the new default ZoomAlignment for your view (ZV_TOPLEFT,
	//				   ZV_BOTTOMLEFT, ZV_CENTER)
	// --- Out: none
	// --- Returns: none
	// --- Effect: Zooms the view up, so that the passed rectangle in client coords fills
	//			   the window as much as possible, using one of the reference points.
	void ZoomToRectangle(CRect rectZoom, ZoomAlignment Align = ZV_DEFAULT);


	// helper for mouse wheel support
	BOOL DoMouseWheel(UINT fFlags, short zDelta, CPoint point);


#ifdef OXZOOMVIEW_USE_RULER
	// --- In  :	bHorzRuler	-	horizontal ruler band will be displayed
	//				bVertRuler	-	vertical ruler band will be displayed
	// --- Out : 
	// --- Returns:	TRUE if COXRulerOrganizer object was successfully attached
	// --- Effect:	attaches to COXRulerOrganizer object which is responsible
	//				for displaying ruler bars
	inline BOOL AttachRuler(BOOL bHorzRuler=TRUE, BOOL bVertRuler=TRUE) { 
		if(m_ruler.IsAttached())
		{
			SetShowHorzRulerBar(bHorzRuler);
			SetShowVertRulerBar(bVertRuler);
			return TRUE;
		}
		return m_ruler.Attach(this,bHorzRuler,bVertRuler);
	}

	// --- In  :	
	// --- Out : 
	// --- Returns:	
	// --- Effect:	detaches the attached COXRulerOrganizer object which is responsible
	//				for displaying ruler bars
	inline void DetachRuler() { m_ruler.Detach(); }


	// --- In  :
	// --- Out : 
	// --- Returns:	pointer to the internal COXRulerOrganizer object that is used to 
	//				draw ruler bars
	// --- Effect:	retrieves the pointer to the internal COXRulerOrganizer object 
	//				that is used to draw ruler bars
	inline COXRulerOrganizer* GetRulerOrganizer() { return &m_ruler; }


	// --- In  :	bShowVertRulerBar	-	if TRUE then vertical ruler bar will
	//										be displayed
	// --- Out : 
	// --- Returns:	
	// --- Effect:	sets the flag that specifies whether to display the 
	//				vertical ruler bar or not
 	inline void SetShowVertRulerBar(BOOL bShowVertRulerBar) {
		m_ruler.SetShowVertRulerBar(bShowVertRulerBar);
	}

	// --- In  :	
	// --- Out : 
	// --- Returns:	TRUE if vertical ruler bar is displayed or FALSE otherwise
	// --- Effect:	retrieves the flag that specifies whether to display the 
	//				vertical ruler bar or not
	inline BOOL GetShowVertRulerBar() const { return m_ruler.GetShowVertRulerBar(); }


	// --- In  :	bShowHorzRulerBar	-	if TRUE then horizontal ruler bar will
	//										be displayed
	// --- Out : 
	// --- Returns:	
	// --- Effect:	sets the flag that specifies whether to display the 
	//				horizontal ruler bar or not
	inline void SetShowHorzRulerBar(BOOL bShowHorzRulerBar) {
		m_ruler.SetShowHorzRulerBar(bShowHorzRulerBar);
	}

	// --- In  :	
	// --- Out : 
	// --- Returns:	TRUE if horizontal ruler bar is displayed or FALSE otherwise
	// --- Effect:	retrieves the flag that specifies whether to display the 
	//				horizontal ruler bar or not
	inline BOOL GetShowHorzRulerBar() const { return m_ruler.GetShowHorzRulerBar(); }

#endif	//	OXZOOMVIEW_USE_RULER


#ifdef _DEBUG
	virtual void Dump(CDumpContext&) const;
	virtual void AssertValid() const;
#endif //_DEBUG

protected:

	// virtual function, used to initialize the COXScrollWnd object after 
	// it was created or was used to subclass created window
	virtual BOOL Initialize();

	void ScrollToDevicePosition(POINT ptDev); // explicit scrolling no checking
	
	// helper functions for zooming
	void SetMapMode(CDC* pDC) const;
	void ScaleViewport(CDC* pDC) const { pDC->ScaleViewportExt(m_nZoomLevel, 100, m_nZoomLevel, 100); }

	virtual void OnDraw(CDC* pDC) = 0;      // pass on pure virtual

	void UpdateBars(BOOL bSendRecalc = TRUE); // adjust scrollbars etc
	BOOL GetTrueClientSize(CSize& size, CSize& sizeSb);
		// size with no bars
	void GetScrollBarSizes(CSize& sizeSb);
	void GetScrollBarState(CSize sizeClient, CSize& needSb,
		CSize& sizeRange, CPoint& ptMove, BOOL bInsideClient);

	virtual void CalcWindowRect(LPRECT lpClientRect, UINT nAdjustType = adjustBorder);
	virtual void OnPrepareDC(CDC* pDC, CPrintInfo* pInfo = NULL);

	// scrolling implementation support for OLE 2.0
	virtual BOOL OnScroll(UINT nScrollCode, UINT nPos, BOOL bDoScroll = TRUE);
	virtual BOOL OnScrollBy(CSize sizeScroll, BOOL bDoScroll = TRUE);

	static UINT GetMouseScrollLines();

	//{{AFX_MSG(COXZoomView)
	afx_msg void OnSize(UINT nType, int cx, int cy);
	afx_msg void OnHScroll(UINT nSBCode, UINT nPos, CScrollBar* pScrollBar);
	afx_msg void OnVScroll(UINT nSBCode, UINT nPos, CScrollBar* pScrollBar);
	afx_msg BOOL OnMouseWheel(UINT fFlags, short zDelta, CPoint point);
	afx_msg int OnCreate(LPCREATESTRUCT lpCreateStruct);
	//}}AFX_MSG
	DECLARE_MESSAGE_MAP()

private:
};

// little helper class for zooming to a rectangle
// DON'T comment on this !!
class OX_CLASS_DECL CZoomRect
{
public:
	BOOL TrackTheMouse(UINT uMessageEnd, CWnd *pWnd, CRect& rectZoom, CPoint ptAnchor);
protected:
	void RetrieveMsg(MSG* pmsg);
	BOOL ProcessMsg(MSG* pmsg, CWnd* pWnd);
	void UpdateRectangle(CWnd* pWnd, CPoint& pt);
	void DrawZoomRect(CDC* pDC);
	BOOL m_bFirstMove;
	BOOL m_bSuccess;
	UINT m_uMessageEnd;
	CPoint m_ptOrig;
	CPoint m_ptLast;
};

#include "OXZoomVw.inl"

#endif // __ZOOMVIEW_H__
