// ==========================================================================
//						   Class Specification : 
//							COXTabViewContainer
// ==========================================================================

// 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.
                          
// //////////////////////////////////////////////////////////////////////////

/*

For most applications it's not enough to use only one window to provide its all output. 
There are different solutions for this problem like splitters or docking windows. 
But they usually have common inconvenience: all windows are shown at the same time.
They take a precious screen space while could be rarely used. 

COXShortcutBar control can be used in order to show a number of child windows while
keeping active (fully displayed) only one at a time. But COXShortcutBar was primarily 
designed to show icons and have a set of notifications that make sense only while
using such controls as treeview or listview.

Very good example of how the problem could be resolved can be found in Developer Studio
IDE. For instance "Output" window (with "Build", "Debug", "Find in Files..." panes) or 
"Result List" window (with "Search", "Lookup", "See Also" and "History" panes). We call 
them TabViews.

TabViews can be a good alternative for splitter window when you need to have more than 
one view per document. Also TabViews can be used within docking window and used as a 
container for associated windows that usually implemented as dialog bars.

So we designed new class that implements TabViews: COXTabViewContainer.

COXTabViewContainer is easy to use. If you previously worked with splitter windows,
the implementation of TabViews will be familiar to you. 

Here is the list of steps that should be taken in order to deploy TabViews in 
your application:

	First Case:		COXTabViewContainer will be used as a container for document view(s).

		1)	Embed a COXTabViewContainer member variable in the parent frame (main frame
			window for SDI application, MDIChild window for MDI application).
		2)	Override the parent frame's CFrameWnd::OnCreateClient member function.
		3)	From within the overridden OnCreateClient, call the Create member function 
			of COXTabViewContainer. In this function you have to specify the parent 
			window and optionally you can specify the initial rectangle, window styles
			and window ID.
		4)	After COXTabViewContainer window was successfully created you can populate
			it with window objects using AddPage or InsertPage function. If you are
			inserting view object you have to specify runtime class and context 
			information in order not to break document/view architecture. If you are
			adding window object that is not a document view then you have to create 
			it before adding to COXTabViewContainer window. In AddPage or InsertPage
			functions you can specify text that will be used as page title in tab button.

	Example:

	BOOL CChildFrame::OnCreateClient(LPCREATESTRUCT lpcs, CCreateContext* pContext) 
	{
		// TODO: Add your specialized code here and/or call the base class

		UNREFERENCED_PARAMETER(lpcs);

		if(!m_TabViewContainer.Create(this))
			return FALSE;

		if(!m_TabViewContainer.AddPage(pContext->m_pNewViewClass,
			pContext,_T("Primary View")))
			return FALSE;
		if(!m_TabViewContainer.AddPage(RUNTIME_CLASS(CMyView2),
			pContext,_T("View2")))
			return FALSE;
		
		m_TabViewContainer.SetActivePageIndex(0);
	
		return TRUE;
	}




	Second Case:	COXTabViewContainer will be used as a container for windows within
					control bar.

		1)	Create your own CControlBar-derived class (you can use our 
			COXSizeControlBar as parent class if you need sizable docking windows).
			Let's call CMyControlBar.
		2)	Embed a COXTabViewContainer member variable in this class.
		3)	Override  CMyControlBar::OnCreate member function.
		4)	From within the overridden OnCreate, call the Create member function 
			of COXTabViewContainer. In this function you have to specify the parent 
			window and optionally you can specify the initial rectangle, window styles
			and window ID.
		5)	After COXTabViewContainer window was successfully created you can populate
			it with window objects using AddPage or InsertPage function. You have to 
			create window object before adding it to COXTabViewContainer. In AddPage or 
			InsertPage functions you can specify text that will be used as page title 
			in tab button.
		6)	Override  CMyControlBar::OnSize member function and resize in it 
			COXTabViewContainer object as appropriate


	Example:

	int CMyControlBar::OnCreate(LPCREATESTRUCT lpCreateStruct) 
	{
		if (COXSizeControlBar::OnCreate(lpCreateStruct) == -1)
			return -1;

		if(!m_TabViewContainer.Create(this,rect))
			return -1;

		// edit control
		if(!edit.Create(WS_CHILD|ES_MULTILINE|ES_AUTOHSCROLL|
			ES_AUTOVSCROLL|WS_HSCROLL|WS_VSCROLL,CRect(0,0,0,0),
			&m_TabViewContainer,1))
			return -1;
		m_TabViewContainer.AddPage(&edit,_T("Edit"));

		// list box
		if(!listBox.Create(WS_CHILD|WS_HSCROLL|WS_VSCROLL,
			CRect(0,0,0,0),&m_TabViewContainer,2))
			return -1;
		m_TabViewContainer.AddPage(&listBox,_T("ListBox"));

		// list control
		if(!listCtrl.Create(WS_CHILD|LVS_REPORT,
			CRect(0,0,0,0),&m_TabViewContainer,3))
			return -1;
		m_TabViewContainer.AddPage(&listCtrl,_T("List"));

		// tree control
		if(!treeCtrl.Create(WS_CHILD|TVS_HASLINES|TVS_LINESATROOT|TVS_HASBUTTONS,
			CRect(0,0,0,0),&m_TabViewContainer,4))
			return -1;
		m_TabViewContainer.AddPage(&treeCtrl,_T("Tree"));

		m_TabViewContainer.SetActivePageIndex(0);
	
		return 0;					
	}



The most challenging problem was to support scrolling functionality for windows
that would be used as COXTabViewContainer pages. Unfortunately, different windows
object that support scrolling (CEdit, CTreeCtrl, CListBox, CListCtrl, CRichEditCtrl,
CEditView, CTreeView, CListView, CScrollView to name just the standrad ones)
implement it in a different way and anyway the handling of scrolling happens
internally in these objects so in order to control it we should have provided 
derivations for all of above mentioned classes. Luckily we managed to resolve this
problem in different way so it doesn't require any efforts from programmer's side.
Actually, the only thing you have to do is to declare the class of window object 
that is going to be used as COXTabViewContainer page in a specific way.

If you declare you class as follows:
	class CMyView : public CEditView

now you have to do that in the following way:
	class CMyView : public COXTabViewPage<CEditView>


or if you don't derive your own class and just use an object of existing one, e.g.:

	CEdit m_edit;

instead you have to define it as:

	COXTabViewPage<CEdit> m_edit;


COXTabViewPage is internal template based Ultimate Toolbox class that was designed 
specifically to provide smooth integration of scrolling functionality for any
window within COXTabViewContainer object. All the details of implementation is hidden 
for different type of windows is hidden. There is no any public functions that you 
should specifically use. 

But there is one limitation. The base class that is used for derivation has to have 
default constructor. Some classes doesn't have it (e.g. CFormView). You can resolve 
this problem through using intermediate class that will be derived from the one 
that doesn't have default constructor and implement it. Then you just derive your 
window  object class that will be used as COXTabViewContainer page from this 
intermediate class. Out of standard only CFormView doesn't have default constructor.
Below you will find the steps that should be taken in order to derive classes from 
CFormView class.

1)	Use Class Wizard to build CFormView derived class on the base of dialog template 
	as you usually do (let's call it CMyFormView)
2)	CMyFormView will have default constructor which uses CFormView constructor with 
	dialog ID specified.
3)	define another class that will be used as view in your application:
	
		class CMyFormTabView : public COXTabViewPage<CMyFormView>
		{
		protected: // create from serialization only
		DECLARE_DYNCREATE(CMyFormView)
		};




The steps that should be taken in order to implement COXTabViewContainer in CControlBar
derived window can be applied in general case too. We just decided to show it using 
CControlBar derived window because we feel like it's going to be used as parent window
for COXTabViewContainer in most cases.

Above we described the process of creating and populating of COXTabViewContainer object.
In most cases that would be all the code you need. For those who need to change 
dynamically the contents of COXTabViewContainer object we provide a set of the 
following functions.

In order to remove any page at run time you have to use DeletePage function.

To access scroll bar objects that we use internally in order to provide scrolling
functionality for COXTabViewContainer pages you have to call GetHorzScrollBar and
GetVertScrollBar functions.

To set/retrieve page title that is displayed in corresponding tab button use 
GetPageTitle and SetPageTitle functions.

To set/retrive active page index call GetActivePageIndex and SetActivepageIndex 
functions.

Refer to the class reference for list and description of all public functions.


Also take look at the following samples that can be found in .\samples\gui 
subdirectory of your ultimate Toolbox directory:

  TabViews			-	text editor with three panes: text editor, hex viewer, 
						list view with statistics on number of unique symbols 
						found in text.
  Dynamic TabViews	-	MDI application that shows how to add/remove pages
						dynamically

#include "OXTabView.h"


*/

#ifndef _TABVIEW_H
#define _TABVIEW_H

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

#include "OXDllExt.h"


#ifndef __AFXCMN_H__
#include <afxcmn.h>
#define __AFXCMN_H__
#endif

#ifndef __AFXEXT_H__
#include <afxext.h>
#define __AFXEXT_H__
#endif

#ifndef __AFXTEMPL_H__
#include <afxtempl.h>
#define __AFXTEMPL_H__
#endif

#ifndef __AFXPRIV_H__
#include <afxpriv.h>
#define __AFXPRIV_H__
#endif

#ifndef __OXMFCIMPL_H__
#if _MFC_VER < 0x0700
	#include <..\src\afximpl.h>
#else
	#include <..\src\mfc\afximpl.h>
#endif

#define __OXMFCIMPL_H__
#endif

#ifndef __AFXCVIEW_H__
#include <afxcview.h>		// MFC Common controls
#define __AFXCVIEW_H__
#endif

#ifndef __AFXRICH_H__
#include <afxrich.h>		
#define __AFXRICH_H__
#endif

#include "UTB64Bit.h"


typedef struct _tagPAGEINFO
{
	CWnd* pWnd;
	CString sTitle;
	BOOL bHasScrollHorz;
	BOOL bHasScrollVert;
	SCROLLINFO scrlInfoHorz;
	SCROLLINFO scrlInfoVert;

	// constructor
	_tagPAGEINFO()
	{
		pWnd=NULL;
		sTitle=_T("");
		bHasScrollHorz=FALSE;
		bHasScrollVert=FALSE;
	}

	// copy constructor
	_tagPAGEINFO(const _tagPAGEINFO& pi)
	{
		ASSERT(pi.pWnd!=NULL);
		pWnd=pi.pWnd;
		sTitle=pi.sTitle;
		bHasScrollHorz=pi.bHasScrollHorz;
		bHasScrollVert=pi.bHasScrollVert;
		scrlInfoHorz=pi.scrlInfoHorz;
		scrlInfoVert=pi.scrlInfoVert;
	}

    // assignment operator
	_tagPAGEINFO& operator=(const _tagPAGEINFO& pi)
	{
		if(this==&pi)
		{
			return *this;
		}
		
		ASSERT(pi.pWnd!=NULL);
		pWnd=pi.pWnd;
		sTitle=pi.sTitle;
		bHasScrollHorz=pi.bHasScrollHorz;
		bHasScrollVert=pi.bHasScrollVert;
		scrlInfoHorz=pi.scrlInfoHorz;
		scrlInfoVert=pi.scrlInfoVert;
		return *this;
	}

	void GetScrollInfo(CWnd* pWnd, BOOL bHorzScrlBar)
	{
		ASSERT_VALID(pWnd);

		if(bHorzScrlBar)
		{
			scrlInfoHorz.cbSize=sizeof(SCROLLINFO);
			pWnd->GetScrollInfo(SB_HORZ,&scrlInfoHorz);
			if(bHasScrollVert)
			{
				scrlInfoHorz.nMax-=::GetSystemMetrics(SM_CXVSCROLL);
//				scrlInfoHorz.nPage-=::GetSystemMetrics(SM_CXVSCROLL);
				if(scrlInfoHorz.nPos+(int)scrlInfoHorz.nPage>scrlInfoHorz.nMax)
				{
					scrlInfoHorz.nPos=scrlInfoHorz.nMax-scrlInfoHorz.nPage;
				}
				if(scrlInfoHorz.nTrackPos+(int)scrlInfoHorz.nPage>scrlInfoHorz.nMax)
				{
					scrlInfoHorz.nTrackPos=scrlInfoHorz.nMax-scrlInfoHorz.nPage;
				}
			}
			if(scrlInfoHorz.nMax==0 || scrlInfoHorz.nPage==0)
			{
				bHasScrollHorz=FALSE;
			}
		}
		else
		{
			scrlInfoVert.cbSize=sizeof(SCROLLINFO);
			pWnd->GetScrollInfo(SB_VERT,&scrlInfoVert);
			if(bHasScrollHorz)
			{
				scrlInfoVert.nMax-=1;
//				scrlInfoVert.nPage-=1;
				if(scrlInfoVert.nPos+(int)scrlInfoVert.nPage>scrlInfoVert.nMax)
				{
					scrlInfoVert.nPos=scrlInfoVert.nMax-scrlInfoVert.nPage;
				}
				if(scrlInfoVert.nTrackPos+(int)scrlInfoVert.nPage>scrlInfoVert.nMax)
				{
					scrlInfoVert.nTrackPos=scrlInfoVert.nMax-scrlInfoVert.nPage;
				}
			}
			if(scrlInfoVert.nMax==0 || scrlInfoVert.nPage==0)
			{
				bHasScrollVert=FALSE;
			}
		}
	}

} PAGEINFO;


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


#define ID_TABVIEWCONTAINER_SIGN	0x3a7b4567

#define ID_SPLITTERWIDTH			6

#define ID_TABBTNOVERLAPSIZE		5
#define ID_TABBTNGAPSIZE			3

#define ID_MINSCROLLBARWIDTH		60
#define ID_INITABBTNAREAWIDTH		200
#define ID_SCROLLTABBTNAREASTEP		15

#define IDT_SCROLLPAGE_TIMER		122
#define ID_SCROLLPAGE_DELAY			200

#define IDT_CHECKSCROLLINFO_TIMER	123
#define ID_CHECKSCROLLINFO_PERIOD	1000


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

/////////////////////////////////////////////////////////////////////////////
// COXTabViewContainer window

class OX_CLASS_DECL COXTabViewContainer : public CWnd
{
	DECLARE_DYNCREATE(COXTabViewContainer)
// Construction
public:
	// --- In  :
	// --- Out : 
	// --- Returns:
	// --- Effect : Constructs the object
	COXTabViewContainer();

// Attributes
public:

	typedef enum _tagHITTEST
	{
		SCROLLBARHORZ=-1,
		SCROLLBARVERT=-2,
		SCRLSTARTBTN=-3,
		SCRLBACKWARDBTN=-4,
		SCRLFORWARDBTN=-5,
		SCRLENDBTN=-6,
		SPLITTER=-7,
		PAGE=-8,
		TABBTNAREA=-9,
		SIZEBAR=-10,
		NONE=-11
	} HITTEST;


protected:

	// rectangle for TabView Container
	//
	
	// scroll buttons rectangles
	CRect m_rectScrollToStartBtn;
	CRect m_rectScrollBackwardBtn;
	CRect m_rectScrollForwardBtn;
	CRect m_rectScrollToEndBtn;

	// tab button area origin
	int m_nTabBtnAreaOrigin;
	// the rectangle of the area that is covered by tab buttons
	CRect m_rectTabBtnArea;
	// tab buttons rectangles (coordinates relative to the top/left
	// of m_rectTabBtnArea + m_nTabBtnAreaOrigin)
	CArray<CRect,CRect&> m_arrTabBtnRects;
	// last saved width of tab buttons area
	int m_nLastTabBtnAreaWidth;

	// scroll bars rectangles
	CRect m_rectScrollBarHorz;
	CRect m_rectScrollBarVert;

	// rect for splitter
	CRect m_rectSplitter;

	// rect for size bar
	CRect m_rectSizeBar;

	// rect for page
	CRect m_rectPage;
	//
	/////////////////////////////////////////

	/////////////////////////////////////////
	// array of pages
	CArray<PAGEINFO,PAGEINFO> m_arrPages;
	// index of currently active page
	int m_nActivePageIndex;
	/////////////////////////////////////////

	// scroll style of the container (internal)
	DWORD m_dwScrollStyle;

	// internal array of unique IDs
	CArray<DWORD,DWORD> m_arrUniqueIDs;

	// scroll bars controls
	CScrollBar m_scrlBarHorz;
	CScrollBar m_scrlBarVert;

	// the ID of last scroll button that was pressed
	HITTEST m_nPressedScrlBtn;
	// flag that specifies if last pressed scroll button is still pressed 
	BOOL m_bIsScrlBtnPressed;
	// timer for tab buttons scrolling operations
	INT_PTR m_nScrollPageTimer;

	// flag that specifies that splitter has been pressed
	BOOL m_bIsSplitterPressed;

	// fonts to draw text in tab buttons
	CFont m_fontTabBtnText;
	CFont m_fontActiveTabBtnText;

// Operations

public:
	// --- In  :	lpszClassName	-	ignored
	//				lpszWindowName	-	ignored
	//				dwStyle			-	The TabView container's style.
	//				rect			-	window rectangle
	//				pParentWnd		-	Pointer to the window that is the 
	//									TabView container's parent.
	//				nID				-	The TabView container's ID.
	//				pContext		-	ignored
	// --- Out : 
	// --- Returns:	TRUE if TabView container was successfully created, 
	//				or FALSE otherwise
	// --- Effect : Creates the TabView container. Implemented in order to 
	//				support dynamic creation of the object.
	virtual BOOL Create(LPCTSTR lpszClassName, LPCTSTR lpszWindowName, 
		DWORD dwStyle, const RECT& rect, CWnd* pParentWnd, UINT nID,
		CCreateContext* pContext=NULL);

	// --- In  :	pParentWnd	-	Pointer to the window that is the 
	//								TabView container's parent.
	//				rect		-	window rectangle
	//				dwStyle		-	The TabView container's style.
	//				nID			-	The TabView container's ID.
	// --- Out : 
	// --- Returns:	TRUE if TabView container was successfully created, 
	//				or FALSE otherwise
	// --- Effect : Creates the TabView container
	virtual BOOL Create(CWnd* pParentWnd, CRect rect=CRect(0,0,0,0), 
		DWORD dwStyle=WS_CHILD|WS_VISIBLE, UINT nID=AFX_IDW_PANE_FIRST);


	// --- In  :	pClass		-	pointer to runtime class information of
	//								the new window to be added as new page
	//				pContext	-	pointer to context info (refer to the
	//								description of CCreateContext class)
	//				lpszTitle	-	text that will be used as page title in
	//								tab button
	// --- Out : 
	// --- Returns: TRUE if new page was successfully added, or FALSE otherwise
	// --- Effect : Adds new page to TabView container. Use this version of
	//				function if you have to add CView derived class which is
	//				part of document/view architecture of your application
	inline BOOL AddPage(
		CRuntimeClass* pClass, CCreateContext* pContext, LPCTSTR lpszTitle=NULL) 
	{
		return InsertPage(GetPageCount(),pClass,pContext,lpszTitle);
	}

	// --- In  :	pWnd		-	pointer to created window to be added 
	//								as new page
	//				lpszTitle	-	text that will be used as page title in
	//								tab button
	// --- Out : 
	// --- Returns: TRUE if new page was successfully added, or FALSE otherwise
	// --- Effect : Adds new page to TabView container. Use this version of
	//				function if you have to add any generic window into the 
	//				TabView container.
	inline BOOL AddPage(CWnd* pWnd, LPCTSTR lpszTitle=NULL) 
	{ 
		return InsertPage(GetPageCount(),pWnd,lpszTitle); 
	}

	// --- In  :	nIndex		-	zero-based index of the new page
	//				pClass		-	pointer to runtime class information of
	//								the new window to be added as new page
	//				pContext	-	pointer to context info (refer to the
	//								description of CCreateContext class)
	//				lpszTitle	-	text that will be used as page title in
	//								tab button
	// --- Out : 
	// --- Returns: TRUE if new page was successfully inserted, or FALSE otherwise
	// --- Effect : Inserts new page to TabView container. Use this version of
	//				function if you have to insert CView derived class which is
	//				part of document/view architecture of your application
	virtual BOOL InsertPage(int nIndex, CRuntimeClass* pClass, 
		CCreateContext* pContext, LPCTSTR lpszTitle=NULL);

	// --- In  :	nIndex		-	zero-based index of the new page
	//				pWnd		-	pointer to created window to be inserted 
	//								as new page
	//				lpszTitle	-	text that will be used as page title in
	//								tab button
	// --- Out : 
	// --- Returns: TRUE if new page was successfully inserted, or FALSE otherwise
	// --- Effect : Inserts new page to TabView container. Use this version of
	//				function if you have to add any generic window into the 
	//				TabView container.
	virtual BOOL InsertPage(int nIndex, CWnd* pWnd, LPCTSTR lpszTitle=NULL);


	// --- In  :	pWnd		-	pointer to the page to be deleted
	//				bDestroy	-	flag that specifies if window has to be 
	//								destroyed
	// --- Out : 
	// --- Returns: TRUE if the specified page was successfully deleted, 
	//				or FALSE otherwise
	// --- Effect : Deletes existing page from TabView container.
	BOOL DeletePage(CWnd* pWnd, BOOL bDestroy=TRUE);
	
	// --- In  :	nIndex		-	zero-based index of the page to be deleted
	//				bDestroy	-	flag that specifies if window has to be 
	//								destroyed
	// --- Out : 
	// --- Returns: TRUE if the specified page was successfully deleted, 
	//				or FALSE otherwise
	// --- Effect : Deletes existing page from TabView container.
	virtual BOOL DeletePage(int nIndex, BOOL bDestroy=TRUE);


	// --- In  :	nIndex		-	zero-based index of the page to be retrieved
	// --- Out : 
	// --- Returns: pointer to the corresponding page, or NULL if out of range
	//				index was specified
	// --- Effect : Retrieves pointer to the page with specified index
	inline CWnd* GetPage(int nIndex) const 
	{
		ASSERT(nIndex>=0 && nIndex<GetPageCount());
		if(nIndex>=0 && nIndex<GetPageCount())
		{
			return m_arrPages[nIndex].pWnd;
		}
		return NULL;
	}


	// --- In  :	pWnd		-	pointer to the page which title
	//								is to be retrieved
	// --- Out : 
	// --- Returns: title of the corresponding page
	// --- Effect : Retrieves title of the specified page
	inline CString GetPageTitle(CWnd* pWnd) const 
	{
		ASSERT(pWnd!=NULL);
		if(pWnd==NULL)
		{
			return _T("");
		}
		int nIndex=-1;
		if(!FindPage(pWnd,nIndex) || nIndex==-1)
		{
			return _T("");
		}
		return GetPageTitle(nIndex);
	}

	// --- In  :	nIndex		-	zero-based index of the page which title
	//								is to be retrieved
	// --- Out : 
	// --- Returns: title of the corresponding page
	// --- Effect : Retrieves title of the page with specified index
	inline CString GetPageTitle(int nIndex) const 
	{
		ASSERT(nIndex>=0 && nIndex<GetPageCount());
		if(nIndex>=0 && nIndex<GetPageCount())
		{
			return m_arrPages[nIndex].sTitle;
		}
		return _T("");
	}


	// --- In  :	pWnd		-	pointer to the page which title
	//								is to be set
	//				lpszTitle	-	text that will be used as page title in
	//								tab button
	// --- Out : 
	// --- Returns: 
	// --- Effect : Sets the title of the specified page
	inline BOOL SetPageTitle(CWnd* pWnd, LPCTSTR lpszTitle) 
	{
		ASSERT(pWnd!=NULL);
		if(pWnd==NULL)
		{
			return FALSE;
		}
		int nIndex=-1;
		if(!FindPage(pWnd,nIndex) || nIndex==-1)
		{
			return FALSE;
		}
		return SetPageTitle(nIndex,lpszTitle);
	}

	// --- In  :	nIndex		-	zero-based index of the page which title
	//								is to be set
	//				lpszTitle	-	text that will be used as page title in
	//								tab button
	// --- Out : 
	// --- Returns: 
	// --- Effect : Sets title of the page with specified index
	BOOL SetPageTitle(int nIndex, LPCTSTR lpszTitle);


	// --- In  :	
	// --- Out : 
	// --- Returns: number of pages in the Tab View container
	// --- Effect : Retrieves the number of pages in the Tab View container
	inline int GetPageCount() const { return PtrToInt(m_arrPages.GetSize()); }


	// --- In  :	pTestWnd	-	pointer to the window to be tested
	//								as Tab View container's page
	//				hTestWnd	-	handle of the window to be tested
	//								as Tab View container's page
	// --- Out :	nIndex		-	reference to the variable where zero-based 
	//								index of the found page will be saved
	// --- Returns: TRUE if specified window is Tab View container's page,
	//				or FALSE otherwise
	// --- Effect : Retrieves the flag that specifies whether the specified
	//				window is Tab View container's page and if it is TRUE then
	//				save the index of found page into nIndex
	inline BOOL FindPage(CWnd* pTestWnd, int& nIndex) const 
	{
		ASSERT(pTestWnd!=NULL);
		if(pTestWnd!=NULL)
		{
			return FindPage(pTestWnd->m_hWnd,nIndex);
		}
		return FALSE;
	}
	inline BOOL FindPage(HWND hTestWnd, int& nIndex) const 
	{
		BOOL bResult=FALSE;
		for(nIndex=0; nIndex<GetPageCount(); nIndex++)
		{
			if(m_arrPages[nIndex].pWnd->m_hWnd==hTestWnd)
			{
				bResult=TRUE;
				break;
			}
		}
		return bResult;
	}


	// --- In  :	pTestWnd	-	pointer to the window to be tested
	//								as Tab View container's page
	//				hTestWnd	-	handle of the window to be tested
	//								as Tab View container's page
	// --- Out :	
	// --- Returns: TRUE if specified window is Tab View container's page,
	//				or FALSE otherwise
	// --- Effect : Retrieves the flag that specifies whether the specified
	//				window is Tab View container's page
	inline BOOL IsPage(HWND hTestWnd) const 
	{
		int nIndex=-1;
		return FindPage(hTestWnd,nIndex);
	}
	inline BOOL IsPage(CWnd* pTestWnd) const 
	{
		int nIndex=-1;
		return FindPage(pTestWnd,nIndex);
	}


	// --- In  :	pTestWnd	-	pointer to the window to be tested as 
	//								currently active Tab View container's page
	//				hTestWnd	-	handle of the window to be tested as 
	//								currently active Tab View container's page
	// --- Out :	
	// --- Returns: TRUE if specified window is currently active Tab View 
	//				container's page, or FALSE otherwise
	// --- Effect : Retrieves the flag that specifies whether the specified
	//				window is currently active Tab View container's page
	inline BOOL IsActivePage(HWND hTestWnd) const 
	{
		int nIndex=-1;
		if(FindPage(hTestWnd,nIndex) && GetActivePageIndex()==nIndex)
		{
			return TRUE;
		}
		return FALSE;
	}
	inline BOOL IsActivePage(CWnd* pTestWnd) const 
	{
		int nIndex=-1;
		if(FindPage(pTestWnd,nIndex) && GetActivePageIndex()==nIndex)
		{
			return TRUE;
		}
		return FALSE;
	}


	// --- In  :	
	// --- Out :	
	// --- Returns: index of currently active Tab View container's page
	// --- Effect : Retrieves the index of currently active Tab View 
	//				container's page
	inline int GetActivePageIndex() const { return m_nActivePageIndex; }

	// --- In  :	
	// --- Out :	
	// --- Returns: pointer to currently active Tab View container's page
	// --- Effect : Retrieves the pointer to currently active Tab View 
	//				container's page
	inline CWnd* GetActivePage() const 
	{ 
		if(m_nActivePageIndex>=0 && m_nActivePageIndex<GetPageCount())
		{
			return m_arrPages[m_nActivePageIndex].pWnd;
		}
		return NULL;
	}


	// --- In  :	pWnd		-	pointer to the page to be set as active
	// --- Out : 
	// --- Returns: TRUE is specified page was successfully set as active
	// --- Effect : Sets the specified page as active one
	inline BOOL SetActivePage(CWnd* pWnd) 
	{
		ASSERT(pWnd!=NULL);
		if(pWnd!=NULL)
		{
			int nIndex=-1;
			if(FindPage(pWnd,nIndex))
			{
				return SetActivePageIndex(nIndex);
			}
		}
		return FALSE;
	}

	// --- In  :	nIndex		-	index of the page to be set as active
	// --- Out : 
	// --- Returns: TRUE is page with specified index was successfully set 
	//				as active
	// --- Effect : Sets the page with specified index as active one
	virtual BOOL SetActivePageIndex(int nIndex);


	// --- In  :	
	// --- Out : 
	// --- Returns: pointer to the horizontal scroll bar control
	// --- Effect : Retrieves pointer to the horizontal scroll bar control
	inline CScrollBar* GetHorzScrollBar() 
	{ 
		if(::IsWindow(m_scrlBarHorz.GetSafeHwnd()))
		{
			return &m_scrlBarHorz; 
		}
		else
		{
			return NULL; 
		}
	}

	// --- In  :	
	// --- Out : 
	// --- Returns: pointer to the vertical scroll bar control
	// --- Effect : Retrieves pointer to the vertical scroll bar control
	inline CScrollBar* GetVertScrollBar() 
	{ 
		if(::IsWindow(m_scrlBarVert.GetSafeHwnd()))
		{
			return &m_scrlBarVert; 
		}
		else
		{
			return NULL; 
		}
	}


	// --- In  :	lpszProfileName	-	name of hive in registry where
	//									all information about COXTabViewContainer
	//									will be saved. 
	// --- Out : 
	// --- Returns:	TRUE if succeeds, or FALSE otherwise.
	// --- Effect : Saves COXTabViewContainer state into registry
	virtual BOOL SaveState(LPCTSTR lpszProfileName) ;

	// --- In  :	lpszProfileName	-	name of hive in registry where
	//									all information about COXTabViewContainer
	//									was saved. 
	// --- Out : 
	// --- Returns:	TRUE if succeeds, or FALSE otherwise.
	// --- Effect : Loads COXTabViewContainer state from registry
	virtual BOOL LoadState(LPCTSTR lpszProfileName);


// Overrides
	// ClassWizard generated virtual function overrides
	//{{AFX_VIRTUAL(CMainFrame)
	//}}AFX_VIRTUAL

protected:
	// sets the scroll style of the Tab View container. 
	// dwScrollStyle can be zero or any combination of WS_VSCROLL
	// and WS_HSCROLL styles
	virtual void SetScrollStyle(DWORD dwScrollStyle, BOOL bForceToRebuild=FALSE);
	// retrieves the scroll style of the Tab View container. 
	// It can be zero or any combination of WS_VSCROLL and WS_HSCROLL styles
	inline DWORD GetScrollStyle() const { return m_dwScrollStyle; }

	// initialize internal PAGEINFO structure with scroll info for currently
	// active page
	void IniScrollInfo();

	// calculates position of all Tab View container elements
	virtual void CalcLayout();
	// calculates position of all tab buttons
	virtual void CalcTabBtnRects();
	// resize scroll bar controls
	void UpdateScrollSizes();

	// retrieves unique ID for newly added page
	virtual DWORD GetUniqueId();

	// empties all internal position info of all Tab View container elements 
	void EmptyRects();

	// redraw the specified scroll button.
	void RedrawScrollButton(HITTEST hitTest);
	// redraw tab buttons area
	inline void RedrawTabBtnArea() 
	{ 
		ASSERT(::IsWindow(GetSafeHwnd()));
		RedrawWindow(m_rectTabBtnArea); 
	}
	// redraw splitter
	inline void RedrawSplitter() 
	{ 
		ASSERT(::IsWindow(GetSafeHwnd()));
		RedrawWindow(m_rectSplitter); 
	}
	// redraw all Tab View container elements 
	inline void RedrawContainer() 
	{
		CRect rect=m_rectScrollToStartBtn;
		rect.right=m_rectSplitter.right;
		RedrawWindow(rect);
		RedrawWindow(m_rectSizeBar);
	}

	// the following virtual routines are responsible for drawing
	// corresponding Tab View container elements 
	virtual void DrawScrollButtons(CDC* pDC);
	virtual void DrawTabBtnArea(CDC* pDC);
	virtual void DrawSplitter(CDC* pDC);
	virtual void DrawSizeBar(CDC* pDC);
	/////////////////////////////////////////////////////////////

	// draws specified scroll button
	virtual void DrawButton(CDC* pDC, CRect rect, HITTEST nButtonType) const;
	// draws tab button for the page with specified index
	virtual void DrawTabButton(CDC* pDC, int nIndex) const;

	// starts handling "move splitter" or "scroll tab buttons" operation
	void StartTracking(const CPoint& point);
	// stops "move splitter" or "scroll tab buttons" operation
	void StopTracking(const CPoint& point);

	// the following test functions return the flag that specifies
	// if corresponding scroll tab button operation can be accomplished
	//
	inline BOOL CanScrollToStart() const 
	{ 
		ASSERT(m_nTabBtnAreaOrigin<=0);
		return (m_nTabBtnAreaOrigin<0 && 
			m_rectTabBtnArea.right>m_rectTabBtnArea.left); 
	}
	inline BOOL CanScrollBackward() const { return CanScrollToStart(); }
	inline BOOL CanScrollForward() const { return CanScrollToEnd(); }
	inline BOOL CanScrollToEnd() const 
	{
		ASSERT(m_nTabBtnAreaOrigin<=0);
		if(GetPageCount()>0 && 
			m_rectTabBtnArea.right>m_rectTabBtnArea.left)
		{
			ASSERT(GetPageCount()==m_arrTabBtnRects.GetSize());
			CRect rect=m_arrTabBtnRects[GetPageCount()-1];
			rect+=m_rectTabBtnArea.TopLeft();
			return (rect.right+m_nTabBtnAreaOrigin>m_rectTabBtnArea.right);
		}
		return FALSE;
	}

	
	void EnsureTabBtnVisible(int nIndex, BOOL bPartialOk=FALSE);

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

// Implementation
public:
	// --- In  :	
	// --- Out : 
	// --- Returns:
	// --- Effect : Destructs the object
	virtual ~COXTabViewContainer();


	// --- In  :	
	// --- Out : 
	// --- Returns:
	// --- Effect : Updates scroll info for currently active page
	void UpdateScrollInfo();

	// --- In  :	
	// --- Out : 
	// --- Returns:
	// --- Effect : Updates scroll state for currently active page
	void UpdateScrollState();


	// --- In  :	point	-	point in Tab View container client coordinates
	//							to be tested
	// --- Out : 
	// --- Returns:	if equals or more than zero then the return value specifies 
	//				the corresponding index of tab button, otherwise it can be
	//				one of the following value:
	//
	//				SCROLLBARHORZ	-	horizontal scroll bar control
	//				SCROLLBARVERT	-	vertical scroll bar control
	//				SCRLSTARTBTN	-	scroll button "scroll to start"
	//				SCRLBACKWARDBTN	-	scroll button "scroll backward"
	//				SCRLFORWARDBTN	-	scroll button "scroll forward"
	//				SCRLENDBTN		-	scroll button "scroll to end"
	//				SPLITTER		-	splitter
	//				PAGE			-	currently active page
	//				TABBTNAREA		-	tab buttons area
	//				SIZEBAR			-	sizebar
	//				NONE			-	out of Tab View container
	//
	// --- Effect : Retrieves the element of Tab View container over which
	//				the specified point is located
	int HitTest(const CPoint& point) const;


	// --- In  :	nScrlBtn	-	scroll button identifier. it can be one 
	//								of the following:
	//
	//				SCRLSTARTBTN	-	scroll button "scroll to start"
	//				SCRLBACKWARDBTN	-	scroll button "scroll backward"
	//				SCRLFORWARDBTN	-	scroll button "scroll forward"
	//				SCRLENDBTN		-	scroll button "scroll to end"
	//
	// --- Out : 
	// --- Returns:	
	// --- Effect : Scroll tab btn area in the specified direction
	void ScrollPage(HITTEST nScrlBtn);

protected:

	// special command routing to frame
	virtual BOOL OnCommand(WPARAM wParam, LPARAM lParam);
	virtual BOOL OnNotify(WPARAM wParam, LPARAM lParam, LRESULT* pResult);

	// Generated message map functions
protected:
	// overwrite standard handlers to overcome some problems with MFC
	// standard painting routine
	//{{AFX_MSG(COXTabViewContainer)
	afx_msg void OnSize(UINT nType, int cx, int cy);
	afx_msg void OnPaint();
	afx_msg void OnMouseMove(UINT nFlags, CPoint point);
	afx_msg void OnLButtonDown(UINT nFlags, CPoint point);
	afx_msg void OnLButtonUp(UINT nFlags, CPoint point);
	afx_msg void OnTimer(UINT nIDEvent);
	afx_msg BOOL OnSetCursor(CWnd* pWnd, UINT nHitTest, UINT message);
	afx_msg BOOL OnEraseBkgnd(CDC* pDC);
	afx_msg void OnCancelMode();
	afx_msg void OnDestroy();
	afx_msg void OnHScroll(UINT nSBCode, UINT nPos, CScrollBar* pScrollBar);
	afx_msg void OnVScroll(UINT nSBCode, UINT nPos, CScrollBar* pScrollBar);
	afx_msg void OnSettingChange(UINT uFlags, LPCTSTR lpszSection);
	//}}AFX_MSG

	DECLARE_MESSAGE_MAP()
};



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


// --- In  :	pWnd		-	pointer to valid window
//				bOnlyActive	-	if it is TRUE then the function will return
//								non-NULL value only if specified window 
//								is current active page of parent TabView 
//								container
// --- Out : 
// --- Returns:	pointer to parent TabView container, or NULL if parent of
//				the specified window is not TabView container
// --- Effect : Retrieves parent TabView container foor specified window
OX_API_DECL COXTabViewContainer* PASCAL 
GetParentTabViewContainer(CWnd* pWnd, BOOL bOnlyActive=TRUE);


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


template<class PARENTWND>
class COXTabViewPage : public PARENTWND
{
public:
	// Contruction
	COXTabViewPage();
	COXTabViewPage(UINT nIDTemplate); // Use this constructor for form views

// Scrolling Functions
	virtual CScrollBar* GetScrollBarCtrl(int nBar) const;
			// return sibling scrollbar control (or NULL if none)


	// --- In  :	pMsg	-	Points to a MSG structure that contains the 
	//							message to process
	// --- Out : 
	// --- Returns:	Nonzero if the message was translated and should not be 
	//				dispatched; 0 if the message was not translated and should be 
	//				dispatched.
	// --- Effect :	Used by class CWinApp to translate window messages before 
	//				they are dispatched to the TranslateMessage() and 
	//				DispatchMessage() Windows functions
	virtual BOOL PreTranslateMessage(MSG* pMsg);

protected:
	// timer for checking scroll info of currently active page
	INT_PTR m_nCheckScrollInfoTimer;
	BOOL m_bCurrentlyScrolling;
	BOOL m_bHasInternalScrollBars;
	BOOL m_bNeedsInternalRedrawing;

	int m_nLastHorzPos;
	int m_nLastVertPos;

protected:
	// --- In  :	msg	-	message ID
	//				wp	-	WPARAM
	//				lp	-	LPARAM
	// --- Out : 
	// --- Returns:	result of message handling. Different for different messages.
	// --- Effect :	Handle all messages that go to the window
	virtual LRESULT WindowProc(UINT msg, WPARAM wp, LPARAM lp);	

	// call this function to force the control to check its scroll state
	virtual void CheckScrollInfo();
};


template<class PARENTWND>
COXTabViewPage<PARENTWND>::COXTabViewPage()
{
	m_nCheckScrollInfoTimer=-1;
	m_bCurrentlyScrolling=FALSE;
	m_bHasInternalScrollBars=PARENTWND::IsKindOf(RUNTIME_CLASS(CEdit)) ||
		PARENTWND::IsKindOf(RUNTIME_CLASS(CEditView)) ||
		PARENTWND::IsKindOf(RUNTIME_CLASS(CListBox)) ||
		PARENTWND::IsKindOf(RUNTIME_CLASS(CTreeCtrl)) ||
		PARENTWND::IsKindOf(RUNTIME_CLASS(CTreeView)) ||
		PARENTWND::IsKindOf(RUNTIME_CLASS(CListCtrl)) ||
		PARENTWND::IsKindOf(RUNTIME_CLASS(CListView)) ||
		PARENTWND::IsKindOf(RUNTIME_CLASS(CRichEditCtrl)) ||
		PARENTWND::IsKindOf(RUNTIME_CLASS(CRichEditView));
	m_bNeedsInternalRedrawing=PARENTWND::IsKindOf(RUNTIME_CLASS(CEdit)) ||
		PARENTWND::IsKindOf(RUNTIME_CLASS(CEditView)) ||
		PARENTWND::IsKindOf(RUNTIME_CLASS(CListBox));

	m_nLastHorzPos=0;
	m_nLastVertPos=0;
}

template<class PARENTWND>
COXTabViewPage<PARENTWND>::COXTabViewPage(UINT nIDTemplate) :
	PARENTWND(nIDTemplate)
{
	ASSERT(PARENTWND::IsKindOf(RUNTIME_CLASS(CFormView)));

	m_nCheckScrollInfoTimer=-1;
	m_bCurrentlyScrolling=FALSE;
	m_bHasInternalScrollBars=FALSE;

	m_nLastHorzPos=0;
	m_nLastVertPos=0;
}

template<class PARENTWND>
CScrollBar* COXTabViewPage<PARENTWND>::GetScrollBarCtrl(int nBar) const
{
	COXTabViewContainer* pContainer=GetParentTabViewContainer((CWnd*)this);
	if(pContainer!=NULL)
	{
		ASSERT(nBar==SB_HORZ || nBar==SB_VERT);
		CScrollBar* pScrlBar=NULL;
		if(nBar==SB_HORZ)
		{
			if((GetStyle()&WS_HSCROLL)!=WS_HSCROLL)
			{
				pScrlBar=pContainer->GetHorzScrollBar();
			}
		}
		else if(nBar==SB_VERT)
		{
			if((GetStyle()&WS_VSCROLL)!=WS_VSCROLL)
			{
				pScrlBar=pContainer->GetVertScrollBar();
			}
		}

		if(pScrlBar!=NULL)
		{
			return pScrlBar;
		}
	}

	return PARENTWND::GetScrollBarCtrl(nBar);
}


template<class PARENTWND>
LRESULT COXTabViewPage<PARENTWND>::WindowProc(UINT msg, WPARAM wp, LPARAM lp)
{
#if defined (_WINDLL)
#if defined (_AFXDLL)
	AFX_MANAGE_STATE(AfxGetAppModuleState());
#else
	AFX_MANAGE_STATE(AfxGetStaticModuleState());
#endif
#endif

	ASSERT_VALID(this);

	static BOOL g_bIgnoreResize=FALSE;

	switch(msg) 
	{
	case WM_CREATE:
		{
			LRESULT lResult=PARENTWND::WindowProc(msg,wp,lp);
			if(lResult==-1)
				return -1;

			if(m_bHasInternalScrollBars)
			{
				m_nCheckScrollInfoTimer=SetTimer(IDT_CHECKSCROLLINFO_TIMER,
					ID_CHECKSCROLLINFO_PERIOD,NULL);
				if(m_nCheckScrollInfoTimer==-1)
				{
					return -1;
				}
			}

			return 0;
		}

	case WM_DESTROY:
		{
			if(m_nCheckScrollInfoTimer!=-1)
			{
				KillTimer(m_nCheckScrollInfoTimer);
				m_nCheckScrollInfoTimer=-1;
			}
			break;
		}

	case WM_TIMER:
		{
			if((int)wp==m_nCheckScrollInfoTimer)
			{
				if(m_bCurrentlyScrolling || ::GetCapture()==GetSafeHwnd())
				{
					return 0;
				}

				COXTabViewContainer* pContainer=GetParentTabViewContainer(this);
				if(pContainer!=NULL)
				{
					ASSERT(m_bHasInternalScrollBars);

					if(m_bNeedsInternalRedrawing)
					{
						pContainer->UpdateScrollState();
						pContainer->UpdateScrollInfo();
					}
					else
					{
						g_bIgnoreResize=TRUE;
						pContainer->UpdateScrollState();
						pContainer->UpdateScrollInfo();
						g_bIgnoreResize=FALSE;
					}
				}
				return 0;
			}
			break;
		}

	case WM_HSCROLL:
	case WM_VSCROLL:
		{
			if(LOWORD(wp)==SB_ENDSCROLL)
			{
				m_bCurrentlyScrolling=FALSE;
				m_nLastHorzPos=GetScrollPos(SB_HORZ);
				m_nLastVertPos=GetScrollPos(SB_VERT);
			}
			else
			{
				m_bCurrentlyScrolling=TRUE;
			}

			COXTabViewContainer* pContainer=GetParentTabViewContainer(this);
			if(pContainer!=NULL && m_bHasInternalScrollBars)
			{
				// set current scroll info to the window
				SCROLLINFO scrollInfo={ sizeof(SCROLLINFO) };
				GetScrollInfo((msg==WM_HSCROLL ? SB_HORZ : SB_VERT),&scrollInfo);

				BOOL bHandled=FALSE;
				if(PARENTWND::IsKindOf(RUNTIME_CLASS(CListCtrl)) ||
					PARENTWND::IsKindOf(RUNTIME_CLASS(CListView)))
				{
					bHandled=TRUE;
					switch(LOWORD(wp))
					{
					case SB_THUMBTRACK:
						{
							CListCtrl* pListCtrl=(CListCtrl*)this;
							CRect rectItem;
							pListCtrl->GetItemRect(0,rectItem,LVIR_BOUNDS);

							int nPos=HIWORD(wp);
							if(msg==WM_HSCROLL && nPos!=m_nLastHorzPos)
							{
								SendMessage(LVM_SCROLL,(nPos-m_nLastHorzPos),0);
								m_nLastHorzPos=GetScrollPos(SB_HORZ);
							}
							else if(msg==WM_VSCROLL && nPos!=m_nLastVertPos)
							{
								SendMessage(LVM_SCROLL,0,
									(nPos-m_nLastVertPos)*rectItem.Height());
								m_nLastVertPos=GetScrollPos(SB_VERT);
							}
						}
						break;

					default:
						{
							bHandled=FALSE;
						}
						break;
					}
				}

				if(!bHandled)
				{
					if(m_bNeedsInternalRedrawing)
					{
						PARENTWND::WindowProc(msg,wp,lp);
						pContainer->UpdateScrollInfo();
					}
					else 
					{
						PARENTWND::WindowProc(msg,wp,lp);
						g_bIgnoreResize=TRUE;
						pContainer->UpdateScrollInfo();
						g_bIgnoreResize=FALSE;
					}
				}
			}
			else
			{
				if(pContainer!=NULL && PARENTWND::IsKindOf(RUNTIME_CLASS(CScrollView)))
				{
					((CScrollView*)this)->OnScroll((msg==WM_HSCROLL ? 
						MAKEWORD(LOWORD(wp),-1) : MAKEWORD(-1,LOWORD(wp))),HIWORD(wp));
				}
				else
				{
					PARENTWND::WindowProc(msg,wp,lp);
				}
			}
			return 0;
		}

	case WM_SIZE:
		{
			COXTabViewContainer* pContainer=GetParentTabViewContainer(this);
			if(pContainer!=NULL)
			{
				if(g_bIgnoreResize)
				{
					return 0;
				}

				if((GetStyle()&WS_VISIBLE)!=WS_VISIBLE)
				{
					PARENTWND::WindowProc(msg,wp,lp);
				}
				else if(PARENTWND::IsKindOf(RUNTIME_CLASS(CRichEditView)) ||
					PARENTWND::IsKindOf(RUNTIME_CLASS(CRichEditCtrl)))
				{
					if(!m_bCurrentlyScrolling)
					{
						g_bIgnoreResize=TRUE;
						pContainer->UpdateScrollState();
						pContainer->UpdateScrollInfo();
						ModifyStyle(WS_VISIBLE,NULL);
						PARENTWND::WindowProc(msg,wp,lp);
						ShowScrollBar(SB_HORZ,FALSE);
						ShowScrollBar(SB_VERT,FALSE);
						ModifyStyle(NULL,WS_VISIBLE);
						Invalidate();
						g_bIgnoreResize=FALSE;
					}
				}
				else if(m_bNeedsInternalRedrawing)
				{
					int nTopIndex=CB_ERR;
					if(PARENTWND::IsKindOf(RUNTIME_CLASS(CListBox)))
						nTopIndex=((CListBox*)this)->GetTopIndex();
				
					pContainer->UpdateScrollState();
					pContainer->UpdateScrollInfo();
					PARENTWND::WindowProc(msg,wp,lp);
					
					if(PARENTWND::IsKindOf(RUNTIME_CLASS(CListBox)))
					{
						if(((CListBox*)this)->GetTopIndex()!=nTopIndex)
							RedrawWindow();
					}
				}
				else if(!m_bHasInternalScrollBars)
				{
					ModifyStyle(WS_VISIBLE,NULL);
					pContainer->GetHorzScrollBar()->
						ModifyStyle(WS_VISIBLE,NULL);
					pContainer->GetVertScrollBar()->
						ModifyStyle(WS_VISIBLE,NULL);
					PARENTWND::WindowProc(msg,wp,lp);
					ShowScrollBar(SB_HORZ,FALSE);
					ShowScrollBar(SB_VERT,FALSE);
					pContainer->GetHorzScrollBar()->
						ModifyStyle(NULL,WS_VISIBLE);
					pContainer->GetVertScrollBar()->
						ModifyStyle(NULL,WS_VISIBLE);
					ModifyStyle(NULL,WS_VISIBLE);
				}
				else
				{
					CSize sizeScrollPos(-1,-1);
					if(PARENTWND::IsKindOf(RUNTIME_CLASS(CTreeCtrl)))
					{
						sizeScrollPos.cx=pContainer->GetHorzScrollBar()->
							GetScrollPos();
						sizeScrollPos.cy=pContainer->GetVertScrollBar()->
							GetScrollPos();
					}
				
					g_bIgnoreResize=TRUE;
					pContainer->UpdateScrollState();
					pContainer->UpdateScrollInfo();
					ModifyStyle(WS_VISIBLE,NULL);
					PARENTWND::WindowProc(msg,wp,lp);
					ShowScrollBar(SB_HORZ,FALSE);
					g_bIgnoreResize=FALSE;
					ShowScrollBar(SB_VERT,FALSE);
					ModifyStyle(NULL,WS_VISIBLE);

					if(PARENTWND::IsKindOf(RUNTIME_CLASS(CTreeCtrl)))
					{
						if(sizeScrollPos.cx!=pContainer->GetHorzScrollBar()->
							GetScrollPos() || 
							sizeScrollPos.cy!=pContainer->GetVertScrollBar()->
							GetScrollPos())
						{
							RedrawWindow();
						}
					}
				}

				return 0;
			}
			break;
		}

	default:
		{
			if(m_bHasInternalScrollBars)
			{
				if(msg==WM_SYSCOMMAND || msg==WM_SHOWWINDOW ||
					(msg>=WM_KEYFIRST && msg<=WM_KEYLAST) || 
					(msg>=WM_SYSKEYFIRST && msg<=WM_SYSKEYLAST) || 
					(msg>=WM_MOUSEFIRST && msg<=WM_MOUSELAST && msg!=WM_MOUSEMOVE))
				{
					CheckScrollInfo();
				}
			}
			break;
		}
	}

	// I don't handle it: pass along
	return PARENTWND::WindowProc(msg,wp,lp);
}


template<class PARENTWND>
BOOL COXTabViewPage<PARENTWND>::PreTranslateMessage(MSG* pMsg)
{
	if(m_bHasInternalScrollBars && pMsg->hwnd!=GetSafeHwnd() && 
		(pMsg->message==WM_SYSCOMMAND || pMsg->message==WM_SHOWWINDOW ||
		(pMsg->message>=WM_KEYFIRST && pMsg->message<=WM_KEYLAST) || 
		(pMsg->message>=WM_SYSKEYFIRST && pMsg->message<=WM_SYSKEYLAST) || 
		(pMsg->message>=WM_MOUSEFIRST && pMsg->message<=WM_MOUSELAST && 
		pMsg->message!=WM_MOUSEMOVE)))
	{
		CheckScrollInfo();
	}

	return PARENTWND::PreTranslateMessage(pMsg);
}


template<class PARENTWND>
void COXTabViewPage<PARENTWND>::CheckScrollInfo()
{
	ASSERT(::IsWindow(GetSafeHwnd()));
	PostMessage(WM_TIMER,m_nCheckScrollInfoTimer);
}


#endif // _TABVIEW_H

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