// This is part of the Professional User Interface Suite library.
// Copyright (C) 2001-2004 FOSS Software, Inc.
// All rights reserved.
//
// http://www.prof-uis.com
// http://www.fossware.com
// mailto:support@fossware.com
//
// This source code can be used, modified and redistributed
// under the terms of the license agreement that is included
// in the Professional User Interface Suite package.
//
// Warranties and Disclaimers:
// THIS SOFTWARE IS PROVIDED "AS IS" WITHOUT WARRANTY OF ANY KIND
// INCLUDING, BUT NOT LIMITED TO, WARRANTIES OF MERCHANTABILITY,
// FITNESS FOR A PARTICULAR PURPOSE AND NON-INFRINGEMENT.
// IN NO EVENT WILL FOSS SOFTWARE INC. BE LIABLE FOR ANY DIRECT,
// INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY OR CONSEQUENTIAL DAMAGES,
// INCLUDING DAMAGES FOR LOSS OF PROFITS, LOSS OR INACCURACY OF DATA,
// INCURRED BY ANY PERSON FROM SUCH PERSON'S USAGE OF THIS SOFTWARE
// EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGES.

#if (!defined __EXT_TEMPL_H)
#define __EXT_TEMPL_H

#if (!defined __EXT_MFC_DEF_H)
	#include <ExtMfcDef.h>
#endif // __EXT_MFC_DEF_H

#if (!defined __EXT_MEMORY_DC_H)
	#include <../Src/ExtMemoryDC.h>
#endif

#if (!defined __EXT_PAINT_MANAGER_H)
	#include <ExtPaintManager.h>
#endif

#if (!defined __EXT_POPUP_MENU_WND_H)
	#include <ExtPopupMenuWnd.h>
#endif

/////////////////////////////////////////////////////////////////////////////
// CExtWFF template window extension (flicker free window)
//
// removes flicker effect caused by WM_ERASEBKGND or
// non-buffered painting, usefull for new win32 (not old win16)
// common controls such as listview or treeview
//

template <
	class CExtWFFBase = CWnd,
	bool _bExludeChildAreas = true,
	bool _bEat_WM_ERASEBKGND = true,
	bool _bEmulate_WM_ERASEBKGND = true
	>
class CExtWFF : public CExtWFFBase
{
protected:
	virtual LRESULT WindowProc( 
		UINT message, 
		WPARAM wParam, 
		LPARAM lParam
		)
	{
		switch( message )
		{
		case WM_ERASEBKGND:
			if( _bEat_WM_ERASEBKGND )
				return FALSE;
		break;
		case WM_PAINT:
			{
				CPaintDC dcPaint( this );
				if( _bExludeChildAreas )
				{
					CExtPaintManager::stat_ExcludeChildAreas(
						dcPaint.GetSafeHdc(),
						GetSafeHwnd()
						);
				}
				CRect rcClient;
				GetClientRect( &rcClient );
				CExtMemoryDC dc(
					&dcPaint,
					&rcClient
					);
				if( _bEmulate_WM_ERASEBKGND )
					DefWindowProc(
						WM_ERASEBKGND,
						WPARAM( dc.GetSafeHdc() ),
						LPARAM(0)
						);
				DefWindowProc(
					WM_PAINT,
					WPARAM( dc.GetSafeHdc() ),
					LPARAM(0)
					);
			}
			return TRUE;
		};
		return CExtWFFBase::WindowProc( message, wParam, lParam );
	};
}; // class CExtWFF

/////////////////////////////////////////////////////////////////////////////
// CExtWRB template window extension (window in resizable bar)
//
// adds thin nonclient area border according to paint manager;
// useful for windows inserted into resizable control bar
//

template <
	class CExtWRBBase = CWnd
	>
class CExtWRB : public CExtWRBBase
{
protected:
	virtual LRESULT WindowProc( 
		UINT message, 
		WPARAM wParam, 
		LPARAM lParam
		)
	{
		switch( message )
		{
		case WM_NCCALCSIZE:
			{
				NCCALCSIZE_PARAMS * pNCCSP =
					reinterpret_cast < NCCALCSIZE_PARAMS * > ( lParam );
				ASSERT( pNCCSP != NULL );
				
				CRect rcInBarWnd( pNCCSP->rgrc[0] );
				rcInBarWnd.DeflateRect(
					1, 1, 1, 1
					);
				::CopyRect( &(pNCCSP->rgrc[0]), rcInBarWnd );
				
				return 0;
			} // case WM_NCCALCSIZE
		case WM_NCPAINT:
			{
				CRect rcInBarWnd, rcInBarClient;
				GetWindowRect( &rcInBarWnd );
				GetClientRect( &rcInBarClient );
				ClientToScreen( &rcInBarClient );
				if( rcInBarWnd == rcInBarClient )
					return 0;
				CPoint ptDevOffset = -rcInBarWnd.TopLeft();
				rcInBarWnd.OffsetRect( ptDevOffset );
				rcInBarClient.OffsetRect( ptDevOffset );

				CWindowDC dc( this );
				ASSERT( dc.GetSafeHdc() != NULL );
				dc.ExcludeClipRect( &rcInBarClient );

				g_PaintManager->PaintResizableBarChildNcAreaRect(
					dc,
					rcInBarWnd,
					this
					);

				return 0;
			} // case WM_NCPAINT
		}; // switch( message )
		return CExtWRBBase::WindowProc( message, wParam, lParam );
	};
}; // class CExtWRB

/////////////////////////////////////////////////////////////////////////////
// CExtWS template window extension (styled window)
//
// adds current PaintManager's background style,
// load/save window position feature,
// right-bottom resizing gripper (default is off)
// and cool system menu for WS_POPUP windows
//

#ifdef GET_WM_CTLCOLOR_HDC
	#define __EXT_GET_WM_CTLCOLOR_HDC(wp,lp,msg) GET_WM_CTLCOLOR_HDC(wp,lp,msg)
#else
	#define __EXT_GET_WM_CTLCOLOR_HDC(wp,lp,msg) (HDC)(wp)
#endif
#ifdef GET_WM_CTLCOLOR_HWND
	#define __EXT_GET_WM_CTLCOLOR_HWND(wp,lp,msg) GET_WM_CTLCOLOR_HWND(wp,lp,msg)
#else
	#define __EXT_GET_WM_CTLCOLOR_HWND(wp,lp,msg) (HWND)(lp)
#endif
#ifdef GET_WM_CTLCOLOR_TYPE
	#define __EXT_GET_WM_CTLCOLOR_TYPE(wp,lp,msg) GET_WM_CTLCOLOR_TYPE(wp,lp,msg)
#else
	#define __EXT_GET_WM_CTLCOLOR_TYPE(wp,lp,msg) (WORD)(msg - WM_CTLCOLORMSGBOX)
#endif

template <
	class CExtWSBase
	, UINT nIdTimerSysMenuTracking = UINT(301)
	>
class CExtWS : public CExtWSBase
{
protected:
	CExtSafeString m_sSection; // section name and
	CExtSafeString m_sEntry;   // entry for save/restore
	bool m_bStyledWndInitDone : 1;
	bool m_bEnableSaveRestore : 1;
	bool m_bSysMenuTracking : 1;
	bool m_bShowResizingGripper : 1;
	CRect m_rcResizingGripper;
public:
	
	CExtWS()
		: m_bStyledWndInitDone( false )
		, m_bSysMenuTracking( false )
		, m_bEnableSaveRestore( false )
		, m_bShowResizingGripper( false )
		, m_rcResizingGripper( 0, 0, 0, 0 )
	{
	}
	
	CExtWS(
		UINT nIDTemplate,
		CWnd * pParentWnd
		)
		: CExtWSBase( nIDTemplate, pParentWnd )
	{
	}
	
	CExtWS(
		__EXT_MFC_SAFE_LPCTSTR lpszTemplateName,
		CWnd * pParentWnd
		)
		: CExtWSBase( lpszTemplateName, pParentWnd )
	{
	}
	
	CExtWS(
			UINT nIDTemplate,
			UINT nIDCaption = 0
			)
		: CExtWSBase( nIDTemplate, nIDCaption )
	{
	}
	
	CExtWS(
			__EXT_MFC_SAFE_LPCTSTR lpszTemplateName,
			UINT nIDCaption = 0
			)
		: CExtWSBase( lpszTemplateName, nIDCaption )
	{
	}
	
	CExtWS(
		UINT nIDCaption,
		CWnd *pParentWnd,
		UINT iSelectPage
		)
		: CExtWSBase( nIDCaption, pParentWnd, iSelectPage )
	{
	}
	
	CExtWS(
		__EXT_MFC_SAFE_LPCTSTR pszCaption,
		CWnd *pParentWnd,
		UINT iSelectPage
		)
		: CExtWSBase( pszCaption, pParentWnd, iSelectPage )
	{
	}
	
	virtual void ShowSizeGrip( BOOL bShow = TRUE )
	{
		bool _bShow = bShow ? true : false;
		if( m_bShowResizingGripper != _bShow )
		{
			m_bShowResizingGripper = _bShow;
			InvalidateRect( &m_rcResizingGripper );
		}
	}

	virtual void SaveWindowRect() const
	{
		CExtSafeString strWP;
		WINDOWPLACEMENT WindowPlacement;
		ZeroMemory( &WindowPlacement, sizeof(WINDOWPLACEMENT) );
		WindowPlacement.length = sizeof(WINDOWPLACEMENT);
		GetWindowPlacement( &WindowPlacement );
		RECT & rc = WindowPlacement.rcNormalPosition;
		strWP.Format(
			_T("%d,%d,%d,%d,%d,%d"),
			rc.left, rc.top, rc.right, rc.bottom,
			WindowPlacement.showCmd,
			WindowPlacement.flags
			);
		::AfxGetApp()->WriteProfileString(
			__EXT_MFC_SAFE_LPCTSTR( m_sSection ),
			__EXT_MFC_SAFE_LPCTSTR( m_sEntry ),
			__EXT_MFC_SAFE_LPCTSTR( strWP )
			);
	}

	virtual void LoadWindowRect(
		bool bForceHideWindow = false
		)
	{
		CExtSafeString strWP;
		WINDOWPLACEMENT WindowPlacement;
		strWP =
			::AfxGetApp()->
				GetProfileString(
					__EXT_MFC_SAFE_LPCTSTR( m_sSection ),
					__EXT_MFC_SAFE_LPCTSTR( m_sEntry )
					);
		if( strWP.IsEmpty() )
			return;
		ZeroMemory( &WindowPlacement, sizeof(WINDOWPLACEMENT) );
		WindowPlacement.length = sizeof(WINDOWPLACEMENT);
		GetWindowPlacement( &WindowPlacement );
		RECT & rc = WindowPlacement.rcNormalPosition;
		if( _stscanf(
				__EXT_MFC_SAFE_LPCTSTR( strWP ),
				__EXT_MFC_SAFE_LPCTSTR( _T("%d,%d,%d,%d,%d,%d") ),
				&rc.left, &rc.top, &rc.right, &rc.bottom,
				&WindowPlacement.showCmd,
				&WindowPlacement.flags
				) == 6
			)
		{
			if( bForceHideWindow )
				WindowPlacement.showCmd = SW_HIDE;
			SetWindowPlacement( &WindowPlacement );
		}
		RedrawWindow(
			NULL, NULL,
			RDW_INVALIDATE|RDW_ERASE|RDW_UPDATENOW
				|RDW_ALLCHILDREN|RDW_FRAME
			);
	}

	virtual void EnableSaveRestore(
			__EXT_MFC_SAFE_LPCTSTR pszSection,
			__EXT_MFC_SAFE_LPCTSTR pszEntry,
			bool bForceHideWindow = false
			)
	{
		m_sSection = pszSection;
		m_sEntry = pszEntry;

		m_bEnableSaveRestore = true;

		HWND hWndOwn = GetSafeHwnd();
		if(		hWndOwn != NULL
			&&	::IsWindow(hWndOwn)
			)
			LoadWindowRect( bForceHideWindow );
	}

	virtual BOOL _TrackWndSystemPopupMenu(
		CPoint * pPoint,
		BOOL bSelectAny
		)
	{
		if( (GetStyle() & WS_POPUP) == 0 )
			return FALSE;
		if(	CExtPopupMenuWnd::IsMenuTracking() )
			CExtPopupMenuWnd::CancelMenuTracking();
		m_bSysMenuTracking = false;

		CMenu * pSysMenu =
			GetSystemMenu( FALSE );
		if( pSysMenu == NULL )
			return FALSE;
		ASSERT( ::IsMenu(pSysMenu->GetSafeHmenu()) );
		CExtPopupMenuWnd * pPopup = new CExtPopupMenuWnd;
		if( !pPopup->CreatePopupMenu( GetSafeHwnd() ) )
		{
			ASSERT( FALSE );
			delete pPopup;
			return FALSE;
		}
		if( !pPopup->UpdateFromMenu(
				GetSafeHwnd(),
				pSysMenu,
				false
				)
			)
		{
			ASSERT( FALSE );
			delete pPopup;
			return FALSE;
		}

		CPoint point;
		if( pPoint != NULL)
			point = *pPoint;
		else
		{
			CRect rcWnd, rcClient, rcHelper;
			GetWindowRect( &rcWnd );
			GetClientRect( &rcClient );
			rcHelper = rcWnd;
			ScreenToClient( &rcHelper );
			ASSERT( rcHelper.top <= rcClient.top );
			int yDiff = rcClient.top - rcHelper.top;
			point = rcWnd.TopLeft();
			point.x += GetSystemMetrics(SM_CXFRAME);
			point.y += yDiff;
		}
		DWORD dwTrackFlags = TPMX_BOTTOMALIGN;
		if( bSelectAny )
			dwTrackFlags |= TPMX_SELECT_ANY;
		HWND hWndFocus = ::GetFocus();
		if(		hWndFocus != NULL
			&&	(!	(	hWndFocus == m_hWnd
					||	::IsChild( m_hWnd, hWndFocus )
				)	)
			)
			SetFocus();
		m_bSysMenuTracking =
			pPopup->TrackPopupMenu(
				dwTrackFlags,
				point.x,point.y,
				NULL
				) ? true : false;

		if( m_bSysMenuTracking )
			SetTimer( nIdTimerSysMenuTracking, 20, NULL );
		else
			delete pPopup;
		return m_bSysMenuTracking; //TRUE;
	}

	virtual BOOL PreTranslateMessage( MSG* pMsg )
	{
		if(		GetSafeHwnd() != NULL
			&&	::IsWindow( GetSafeHwnd() )
			&&	(	pMsg->message == WM_SYSKEYDOWN
				||	pMsg->message == WM_SYSKEYUP
				||	pMsg->message == WM_KEYDOWN
				//||	pMsg->message == WM_KEYUP
				)
			)
		{
			BOOL bSuccessRetVal = TRUE;
			if( ( GetStyle() & WS_POPUP ) == 0 )
			{
				//return FALSE;
				//return CExtWSBase::PreTranslateMessage(pMsg);
				bSuccessRetVal = FALSE;
			}
			bool bKeyUp =
				(	//pMsg->message == WM_KEYUP ||
					pMsg->message == WM_SYSKEYUP)
						? true
						: false
						;
			//BOOL bCtrl = GetKeyState(VK_CONTROL) & 0x80000000;
			//BOOL bShift = GetKeyState(VK_SHIFT) & 0x80000000;
			BOOL bAlt = HIWORD(pMsg->lParam) & KF_ALTDOWN;
			__EXT_MFC_SAFE_TCHAR vkTCHAR = (TCHAR)pMsg->wParam;
			if( bAlt && vkTCHAR == ((TCHAR)VK_SPACE) )
			{
				if( bKeyUp )
					return bSuccessRetVal; // TRUE;
				// allow child popup track it's system menu
				CWnd * pWnd = CWnd::GetActiveWindow();
				if( pWnd == NULL
					|| (! ::IsWindow(pWnd->GetSafeHwnd()))
					)
					return bSuccessRetVal; // TRUE;
				if( pWnd->GetSafeHwnd() != GetSafeHwnd()
					&& (pWnd->GetStyle() & WS_POPUP) != 0
					)
					return bSuccessRetVal; // TRUE;
				// track dialog system menu
				if(		(GetStyle() & WS_POPUP) != 0
					&&	CExtWSBase::GetSystemMenu( FALSE ) != NULL
					)
				{
					VERIFY( _TrackWndSystemPopupMenu( NULL, TRUE ) );
				}
				return bSuccessRetVal; // TRUE;
			} // if( bAlt && vkTCHAR == ((TCHAR)VK_SPACE) )
		}

		return CExtWSBase::PreTranslateMessage(pMsg);
	}

protected:

	virtual LRESULT WindowProc(
		UINT message,
		WPARAM wParam,
		LPARAM lParam
		) 
	{
		if( message == WM_SIZE )
		{
			bool bForceInvalidate =
				(	(GetStyle()&WS_VISIBLE) != 0
				&&	g_PaintManager->GetCb2DbTransparentMode(this)
				&&	CExtPaintManager::stat_GetBPP() > 8
				) ? true : false ;
			if(		m_bShowResizingGripper
				&&	(! m_rcResizingGripper.IsRectEmpty() )
				&&	(! bForceInvalidate)
				)
				InvalidateRect( &m_rcResizingGripper );
			LRESULT lResult = CExtWSBase::WindowProc(message,wParam,lParam);
			if( m_bShowResizingGripper )
			{
				GetClientRect( &m_rcResizingGripper );
				m_rcResizingGripper.left = m_rcResizingGripper.right - ::GetSystemMetrics( SM_CXVSCROLL );
				m_rcResizingGripper.top = m_rcResizingGripper.bottom - ::GetSystemMetrics( SM_CYHSCROLL );
				if(! bForceInvalidate)
					InvalidateRect( &m_rcResizingGripper );
			}
			if( bForceInvalidate )
				Invalidate();
			return lResult;
		} // if( message == WM_SIZE )

		if( message == WM_WINDOWPOSCHANGED )
		{
			LRESULT lResult = CExtWSBase::WindowProc(message,wParam,lParam);
			bool bForceInvalidate =
				(	(GetStyle()&WS_VISIBLE) != 0
				&&	g_PaintManager->GetCb2DbTransparentMode(this)
				&&	CExtPaintManager::stat_GetBPP() > 8
				) ? true : false ;
			if( bForceInvalidate )
				Invalidate();
			return lResult;
		} // if( message == WM_WINDOWPOSCHANGED )

		if( message == WM_NCHITTEST )
		{
			if( m_bShowResizingGripper )
			{
				CPoint ptClient( LOWORD(lParam), HIWORD(lParam) );
				ScreenToClient( &ptClient );
				if( m_rcResizingGripper.PtInRect(ptClient) )
					return HTBOTTOMRIGHT;
			} // if( m_bShowResizingGripper )
			
			return CExtWSBase::WindowProc(message,wParam,lParam);
		} // if( message == WM_NCHITTEST )

		if( message == WM_PAINT )
		{
			CPaintDC dc( this );
			if( g_PaintManager->GetCb2DbTransparentMode(this) )
			{
				CExtPaintManager::stat_ExcludeChildAreas(
					dc,
					GetSafeHwnd(),
					CExtPaintManager::stat_DefExcludeChildAreaCallback
					);
				g_PaintManager->PaintDockerBkgnd( dc, this );
			} // if( g_PaintManager->GetCb2DbTransparentMode(this) )
			if( !m_bShowResizingGripper || IsZoomed() )
				return 0;
			g_PaintManager->PaintResizingGripper(
				dc,
				m_rcResizingGripper,
				this
				);
			g_PaintManager->OnPaintSessionComplete( this );
			return 0;
		} // if( message == WM_PAINT )

		if( message == WM_ERASEBKGND )
		{
			if(		(GetStyle() & WS_CLIPCHILDREN) != 0
				&&	g_PaintManager->GetCb2DbTransparentMode(this)
				)
				return (!0);
			HDC hDC = reinterpret_cast < HDC > (wParam);
			ASSERT( hDC != NULL );
			CExtPaintManager::stat_ExcludeChildAreas(
				hDC,
				GetSafeHwnd(),
				CExtPaintManager::stat_DefExcludeChildAreaCallback
				);
			return CExtWSBase::WindowProc(message,wParam,lParam);
		} // if( message == WM_ERASEBKGND )

		if( message >= WM_CTLCOLORMSGBOX && message <= WM_CTLCOLORSTATIC )
		{
			HBRUSH hBrush = (HBRUSH)
				CExtWSBase::WindowProc(message,wParam,lParam);
			HDC hDC =
				__EXT_GET_WM_CTLCOLOR_HDC(wParam,lParam,message);
			HWND hWnd =
				__EXT_GET_WM_CTLCOLOR_HWND(wParam,lParam,message);
			ASSERT( hWnd != NULL );
			INT nCtlColor =
				__EXT_GET_WM_CTLCOLOR_TYPE(wParam,lParam,message);
			if(		nCtlColor == CTLCOLOR_DLG
				||	nCtlColor == CTLCOLOR_STATIC
				||	nCtlColor == CTLCOLOR_MSGBOX
				)
			{
				if( nCtlColor == CTLCOLOR_STATIC )
				{
					bool bDefaultProcessing = false;
					if( hWnd == NULL || (! ::IsWindow(hWnd) ) )
						bDefaultProcessing = true;
					else
					{
						CExtSafeString sClassName;
						::GetClassName(
							hWnd,
							sClassName.GetBuffer( _MAX_PATH+1 ),
							_MAX_PATH
							);
						sClassName.ReleaseBuffer();
						sClassName.MakeLower();
						if( sClassName != LPCTSTR( _T("static") ) )
							bDefaultProcessing = true;
						//else
						//{
						//	CWnd * pWnd = CWnd::FromHandlePermanent( hWnd );
						//	if(		pWnd == NULL
						//		||	(! pWnd->IsKindOf(RUNTIME_CLASS(CExtLabel)) )
						//		)
						//		bDefaultProcessing = true;
						//} // else from if( sClassName != LPCTSTR( _T("static") ) )
						if( bDefaultProcessing )
							return (LRESULT)hBrush;
					} // else from if( hWnd == NULL || (! ::IsWindow(hWnd) ) )
					::SetBkMode( hDC, TRANSPARENT );
					// (+ v.2.22) corrected by the Dmitry Yakovlev's advice
					if(		(GetStyle()&WS_CHILD) != 0
						&&	g_PaintManager->GetCb2DbTransparentMode(this)
						)
						return (LRESULT)::GetStockObject( NULL_BRUSH );
				}
				static CBrush brBackground;
				static COLORREF clrLast = (COLORREF)(-1L);
				COLORREF clrNew =
					g_PaintManager->GetColor(
						CExtPaintManager::CLR_3DFACE_OUT
						);
				if( clrLast != clrNew )
				{
					if( brBackground.GetSafeHandle() != NULL )
						brBackground.DeleteObject();
				}
				if( brBackground.GetSafeHandle() == NULL )
				{
					clrLast = clrNew;
					VERIFY(
						brBackground.CreateSolidBrush( clrLast )
						);
				} // if( brBackground.GetSafeHandle() == NULL )
				return (LRESULT)brBackground.GetSafeHandle();
			}
			return (LRESULT)hBrush;
		} // if( message >= WM_CTLCOLORMSGBOX && message <= WM_CTLCOLORSTATIC )

		if( message == WM_TIMER )
		{
			if( wParam == nIdTimerSysMenuTracking )
			{
				if( !CExtPopupMenuWnd::IsMenuTracking() )
				{
					m_bSysMenuTracking = false;
					KillTimer( nIdTimerSysMenuTracking );
				}
				return 0;
			}
			return CExtWSBase::WindowProc(message,wParam,lParam);
		} // if( message == WM_TIMER )

		if( message == WM_DESTROY )
		{
			if( m_bEnableSaveRestore )
				SaveWindowRect();
			return CExtWSBase::WindowProc(message,wParam,lParam);
		}

		if( (message == WM_NCLBUTTONUP && wParam == HTSYSMENU)
			|| (message == WM_NCRBUTTONUP && (wParam == HTCAPTION || wParam == HTSYSMENU))
			)
		{
			if( wParam == HTCAPTION )
			{
				CPoint point;
				if( ::GetCursorPos( &point ) )
					_TrackWndSystemPopupMenu(
						&point,
						FALSE
						);
			} // if( wParam == HTCAPTION )
			else
			{
				_TrackWndSystemPopupMenu(
					NULL,
					FALSE
					);
			} // else if if( wParam == HTCAPTION )
			return 0;
		}
		if( (message == WM_NCLBUTTONDOWN || message == WM_NCRBUTTONDOWN)
			&& wParam == HTSYSMENU
			)
			return 0;
		if( message == WM_NCRBUTTONDOWN && wParam == HTCAPTION )
		{
			CPoint point;
			if( ::GetCursorPos( &point ) )
				_TrackWndSystemPopupMenu(
					&point,
					FALSE
					);
			return 0;
		}

		return CExtWSBase::WindowProc(message,wParam,lParam);
	}

	virtual void PostNcDestroy()
	{
		m_bStyledWndInitDone = false;
		CExtWSBase::PostNcDestroy();
	}

}; // class CExtWS

/////////////////////////////////////////////////////////////////////////////
// CExtWA template window extension
//
// adds child anchoring support to any window;
// anchoring idea by Paolo Messina, copyright provided:
//
//
// Copyright (C) 2000 by Paolo Messina
// (ppescher@yahoo.com)
//

const SIZE __RDA_NONE	= {	 -1,	 -1 };
const SIZE __RDA_LT		= {	  0,	  0 };
const SIZE __RDA_RT		= {	100,	  0 };
const SIZE __RDA_LB		= {	  0,	100 };
const SIZE __RDA_RB		= {	100,	100 };

const SIZE __RDA_KEEP	= __RDA_LT;
const SIZE __RDA_X		= __RDA_RT;
const SIZE __RDA_Y		= __RDA_LB;
const SIZE __RDA_XY		= __RDA_RB;
const SIZE __RDA_BOTH	= __RDA_RB;


template < class CExtWABase >
class CExtWA : public CExtWABase
{
protected:
	bool m_bAnchoringInitDone : 1;
	bool m_bUseMaxTrack : 1;
	bool m_bUseMinTrack : 1;
	bool m_bUseMaxRect : 1;

	CPoint m_ptMinTrackSize;	// min tracking size
	CPoint m_ptMaxTrackSize;	// max tracking size
	CPoint m_ptMaxPos;			// maximized position
	CPoint m_ptMaxSize;			// maximized size

	struct RDI_t
	{
		// upper-left corner
		SIZE m_AnchLT;
		SIZE m_MargLT;
		// bottom-right corner
		SIZE m_AnchRB;
		SIZE m_MargRB;
	
		RDI_t(
			SIZE AnchLT = __RDA_LT,
			SIZE MargLT = CSize(0,0), 
			SIZE AnchRB = __RDA_LT,
			SIZE MargRB = CSize(0,0)
			)
			: m_AnchLT( AnchLT )
			, m_MargLT( MargLT )
			, m_AnchRB( AnchRB )
			, m_MargRB( MargRB )
		{
		};
		
		RDI_t(
			const RDI_t & other
			)
			: m_AnchLT( other.m_AnchLT )
			, m_MargLT( other.m_MargLT )
			, m_AnchRB( other.m_AnchRB )
			, m_MargRB( other.m_MargRB )
		{
		};
		
		RDI_t & operator=(
			const RDI_t & other
			)
		{
			m_AnchLT = other.m_AnchLT;
			m_MargLT = other.m_MargLT;
			m_AnchRB = other.m_AnchRB;
			m_MargRB = other.m_MargRB;
			return *this;
		};

	}; // struct RDI_t

	// map of repositionable controls
	CMap < HWND, HWND, RDI_t, RDI_t > m_mapRDI;

public:
	CExtWA()
		: m_bAnchoringInitDone( false )
		, m_bUseMinTrack( true )
		, m_bUseMaxTrack( false )
		, m_bUseMaxRect( false )
		, m_ptMinTrackSize( 0, 0 )
		, m_ptMaxTrackSize( 0, 0 )
		, m_ptMaxPos( 0, 0 )
		, m_ptMaxSize( 0, 0 )
	{
	}
	
	CExtWA(
		UINT nIDTemplate,
		CWnd * pParentWnd
		)
		: CExtWABase( nIDTemplate, pParentWnd )
		, m_bAnchoringInitDone( false )
		, m_bUseMinTrack( true )
		, m_bUseMaxTrack( false )
		, m_bUseMaxRect( false )
		, m_ptMinTrackSize( 0, 0 )
		, m_ptMaxTrackSize( 0, 0 )
		, m_ptMaxPos( 0, 0 )
		, m_ptMaxSize( 0, 0 )
	{
	}
	
	CExtWA(
		__EXT_MFC_SAFE_LPCTSTR lpszTemplateName,
		CWnd * pParentWnd
		)
		: CExtWABase( lpszTemplateName, pParentWnd )
		, m_bAnchoringInitDone( false )
		, m_bUseMinTrack( true )
		, m_bUseMaxTrack( false )
		, m_bUseMaxRect( false )
		, m_ptMinTrackSize( 0, 0 )
		, m_ptMaxTrackSize( 0, 0 )
		, m_ptMaxPos( 0, 0 )
		, m_ptMaxSize( 0, 0 )
	{
	}
	
	CExtWA(
			UINT nIDTemplate,
			UINT nIDCaption = 0
			)
		: CExtWABase( nIDTemplate, nIDCaption )
		, m_bAnchoringInitDone( false )
		, m_bUseMinTrack( true )
		, m_bUseMaxTrack( false )
		, m_bUseMaxRect( false )
		, m_ptMinTrackSize( 0, 0 )
		, m_ptMaxTrackSize( 0, 0 )
		, m_ptMaxPos( 0, 0 )
		, m_ptMaxSize( 0, 0 )
	{
	}
	
	CExtWA(
			__EXT_MFC_SAFE_LPCTSTR lpszTemplateName,
			UINT nIDCaption = 0
			)
		: CExtWABase( lpszTemplateName, nIDCaption )
		, m_bAnchoringInitDone( false )
		, m_bUseMinTrack( true )
		, m_bUseMaxTrack( false )
		, m_bUseMaxRect( false )
		, m_ptMinTrackSize( 0, 0 )
		, m_ptMaxTrackSize( 0, 0 )
		, m_ptMaxPos( 0, 0 )
		, m_ptMaxSize( 0, 0 )
	{
	}
	
	CExtWA(
		UINT nIDCaption,
		CWnd *pParentWnd,
		UINT iSelectPage
		)
		: CExtWABase( nIDCaption, pParentWnd, iSelectPage )
	{
	}
	
	CExtWA(
		__EXT_MFC_SAFE_LPCTSTR pszCaption,
		CWnd *pParentWnd,
		UINT iSelectPage
		)
		: CExtWABase( pszCaption, pParentWnd, iSelectPage )
	{
	}

	bool AddAnchor(
		UINT nDlgCtrlID,
		const CRect & rcAnch
		)
	{
		if(	GetSafeHwnd() == NULL
			|| (! ::IsWindow(GetSafeHwnd()) )
			)
		{
			ASSERT( FALSE );
			return false;
		}
		HWND hWnd = ::GetDlgItem( GetSafeHwnd(), nDlgCtrlID );
		if( hWnd == NULL || (! ::IsWindow(hWnd) ) )
		{
			ASSERT( FALSE );
			return false;
		}
		return AddAnchor( hWnd, rcAnch );
	}

	bool AddAnchor(
		HWND hWnd,
		const CRect & rcAnch
		)
	{
		if(	GetSafeHwnd() == NULL
			|| (! ::IsWindow( GetSafeHwnd() ) )
			)
		{
			ASSERT( FALSE );
			return false;
		}
		return
			AddAnchor(
				hWnd,
				CSize( rcAnch.left, rcAnch.top ),
				CSize( rcAnch.right, rcAnch.bottom )
				);
	}

	bool AddAnchor(
		UINT nDlgCtrlID,
		CSize AnchLT,
		CSize AnchRB = __RDA_NONE
		)
	{
		if( AnchLT == __RDA_NONE
			|| GetSafeHwnd() == NULL
			|| (! ::IsWindow( GetSafeHwnd() ) )
			)
		{
			ASSERT( FALSE );
			return false;
		}
		HWND hWnd = ::GetDlgItem( GetSafeHwnd(), nDlgCtrlID );
		if( hWnd == NULL || (! ::IsWindow(hWnd) ) )
		{
			ASSERT( FALSE );
			return false;
		}
		return AddAnchor( hWnd, AnchLT, AnchRB );
	}

	virtual bool AddAnchor(
		HWND hWnd,
		CSize AnchLT,
		CSize AnchRB = __RDA_NONE
		)
	{
		if( AnchLT == __RDA_NONE
			|| GetSafeHwnd() == NULL
			|| (! ::IsWindow( GetSafeHwnd() ) )
			|| (! ::IsChild( GetSafeHwnd(), hWnd ) )
			)
		{
			ASSERT( FALSE );
			return false;
		}

		CRect rcClient, rcItem;
		GetClientRect( &rcClient );
		int cx = rcClient.Width();
		int cy = rcClient.Height();
		::GetWindowRect( hWnd, &rcItem );
		ScreenToClient( &rcItem );
		
		CSize MargLT, MargRB;
		if( AnchRB == __RDA_NONE )
			AnchRB = AnchLT;
		
		// calculate margin for the top-left corner
		MargLT.cx = rcItem.left - cx*AnchLT.cx/100;
		MargLT.cy = rcItem.top - cy*AnchLT.cy/100;
		
		// calculate margin for the bottom-right corner
		MargRB.cx = rcItem.right - cx*AnchRB.cx/100;
		MargRB.cy = rcItem.bottom - cy*AnchRB.cy/100;

		// add to the list
		m_mapRDI.SetAt(
			hWnd,
			RDI_t( AnchLT, MargLT, AnchRB, MargRB )
			);

		return true;
	}

	virtual void ArrangeLayout(
		int cx = -1,
		int cy = -1
		)
	{
		if( cx < 0 || cy < 0 )
		{
			CRect rcClient;
			GetClientRect( &rcClient );
			cx = rcClient.Width();
			cy = rcClient.Height();
		} // if( cx < 0 || cy < 0 )
		HDWP _hDWP = ::BeginDeferWindowPos( (int)m_mapRDI.GetCount() );
		ASSERT( _hDWP != NULL );
		CList < HWND, HWND > listInvalidHWNDs;
		POSITION pos = m_mapRDI.GetStartPosition();
		for( ; pos != NULL; )
		{
			HWND _hWnd;
			RDI_t _rdi;
			m_mapRDI.GetNextAssoc( pos, _hWnd, _rdi );
			ASSERT( ::IsWindow( _hWnd ) );
			if( ! ::IsWindow( _hWnd ) )
			{
				listInvalidHWNDs.AddTail(_hWnd);
				continue;
			}
			int x  = _rdi.m_MargLT.cx + ::MulDiv(cx,_rdi.m_AnchLT.cx,100);
			int y  = _rdi.m_MargLT.cy + ::MulDiv(cy,_rdi.m_AnchLT.cy,100);
			int dx = _rdi.m_MargRB.cx + ::MulDiv(cx,_rdi.m_AnchRB.cx,100) - x;
			int dy = _rdi.m_MargRB.cy + ::MulDiv(cy,_rdi.m_AnchRB.cy,100) - y;
			if( CExtPaintManager::stat_DefIsHwndNeedsDirectRepaint(_hWnd) )
			{
				::MoveWindow(
					_hWnd,
					x,
					y,
					dx,
					dy,
					TRUE
					);
				CRect rcChild(
					0,  // x,
					0,  // y,
					dx, // x + dx,
					dy  // y + dy
					);
				::RedrawWindow(
					_hWnd, // GetSafeHwnd()
					&rcChild,
					NULL,
					RDW_INVALIDATE|RDW_UPDATENOW
						|RDW_ERASE|RDW_ERASENOW
						|RDW_ALLCHILDREN
						|RDW_NOFRAME //|RDW_FRAME
						|RDW_VALIDATE
					);
				continue;
			}
			_hDWP =
				::DeferWindowPos(
					_hDWP, _hWnd, NULL, x, y, dx, dy,
					SWP_NOZORDER|SWP_NOACTIVATE
					);
			ASSERT( _hDWP != NULL );
		} // for( ; pos != NULL; )
		VERIFY( ::EndDeferWindowPos( _hDWP ) );
		if( listInvalidHWNDs.GetCount() > 0 )
		{
			pos = listInvalidHWNDs.GetHeadPosition();
			for( ; pos != NULL; )
			{
				HWND hWnd = listInvalidHWNDs.GetNext(pos);
				m_mapRDI.RemoveKey( hWnd );
			} // for( ; pos != NULL; )
		} // if( listInvalidHWNDs.GetCount() > 0 )
	}

	void SetMaximizedRect(const CRect& rc)
	{
		m_bUseMaxRect = true;
		m_ptMaxPos = rc.TopLeft();
		m_ptMaxSize.x = rc.Width();
		m_ptMaxSize.y = rc.Height();
	}

	void ResetMaximizedRect()
	{
		m_bUseMaxRect = false;
	}

	void SetMinTrackSize(const CSize& size)
	{
		m_bUseMinTrack = true;
		m_ptMinTrackSize.x = size.cx;
		m_ptMinTrackSize.y = size.cy;
	}

	void ResetMinTrackSize()
	{
		m_bUseMinTrack = false;
	}

	void SetMaxTrackSize(const CSize& size)
	{
		m_bUseMaxTrack = true;
		m_ptMaxTrackSize.x = size.cx;
		m_ptMaxTrackSize.y = size.cy;
	}

	void ResetMaxTrackSize()
	{
		m_bUseMaxTrack = false;
	}

protected:

	virtual LRESULT WindowProc(
		UINT message,
		WPARAM wParam,
		LPARAM lParam
		) 
	{

		if( message == WM_GETMINMAXINFO )
		{
			if( !m_bAnchoringInitDone )
				return 0;
			LPMINMAXINFO lpMMI =
				reinterpret_cast < LPMINMAXINFO > ( lParam );
			if( m_bUseMinTrack )
				lpMMI->ptMinTrackSize = m_ptMinTrackSize;
			if( m_bUseMaxTrack )
				lpMMI->ptMaxTrackSize = m_ptMaxTrackSize;
			if( m_bUseMaxRect )
			{
				lpMMI->ptMaxPosition = m_ptMaxPos;
				lpMMI->ptMaxSize = m_ptMaxSize;
			}
			return 0;
		} // if( message == WM_GETMINMAXINFO )

		if( message == WM_SIZE )
		{
			LRESULT lResult = CExtWABase::WindowProc(message,wParam,lParam);

			if( !m_bAnchoringInitDone )
			{
				// gets the template size as the min track size
				CRect rc;
				GetWindowRect( &rc );
				m_ptMinTrackSize.x = rc.Width();
				m_ptMinTrackSize.y = rc.Height();

				m_bAnchoringInitDone = true;

				ArrangeLayout();
				return lResult;
			} // if( !m_bAnchoringInitDone )
			
			
			if( wParam == SIZE_MAXHIDE || wParam == SIZE_MAXSHOW )
				return lResult; // arrangement not needed

			if( m_bAnchoringInitDone )
				ArrangeLayout( LOWORD(lParam), HIWORD(lParam) );
			return lResult;
		} // if( message == WM_SIZE )
		
		
		return CExtWABase::WindowProc(message, wParam, lParam);
	}

}; // class CExtWAWnd

/////////////////////////////////////////////////////////////////////////////
// CExtADLG template adaptor for CDialog

template < class CExtADLGBase >
class CExtADLG : public CExtADLGBase
{
public:
	CExtADLG()
	{
	}
	
	CExtADLG(
		UINT nIDTemplate,
		CWnd * pParentWnd
		)
		: CExtADLGBase( nIDTemplate, pParentWnd )
	{
	}
	
	CExtADLG(
		__EXT_MFC_SAFE_LPCTSTR lpszTemplateName,
		CWnd * pParentWnd
		)
		: CExtADLGBase( lpszTemplateName, pParentWnd )
	{
	}
	
	CExtADLG(
			UINT nIDTemplate,
			UINT nIDCaption = 0
			)
	{
		// no such constructor in CDialog
		nIDTemplate;
		nIDCaption;
		ASSERT( FALSE );
	}
	
	CExtADLG(
			__EXT_MFC_SAFE_LPCTSTR lpszTemplateName,
			UINT nIDCaption = 0
			)
	{
		// no such constructor in CDialog
		lpszTemplateName;
		nIDCaption;
		ASSERT( FALSE );
	}
	
	CExtADLG(
		UINT nIDCaption,
		CWnd *pParentWnd,
		UINT iSelectPage
		)
	{
		// no such constructor in CDialog
		nIDCaption;
		pParentWnd;
		iSelectPage;
		ASSERT( FALSE );
	}
	
	CExtADLG(
		__EXT_MFC_SAFE_LPCTSTR pszCaption,
		CWnd *pParentWnd,
		UINT iSelectPage
		)
	{
		// no such constructor in CDialog
		pszCaption;
		pParentWnd;
		iSelectPage;
		ASSERT( FALSE );
	}
}; // class CExtADLG

/////////////////////////////////////////////////////////////////////////////
// CExtAPSH template adaptor for CPropertySheet

template < class CExtAPSHBase >
class CExtAPSH : public CExtAPSHBase
{
public:
	CExtAPSH()
	{
	}
	
	CExtAPSH(
		UINT nIDTemplate,
		CWnd * pParentWnd
		)
	{
		// no such constructor in CPropertySheet
		nIDTemplate;
		pParentWnd;
		ASSERT( FALSE );
	}
	
	CExtAPSH(
		__EXT_MFC_SAFE_LPCTSTR lpszTemplateName,
		CWnd * pParentWnd
		)
	{
		// no such constructor in CPropertySheet
		lpszTemplateName;
		pParentWnd;
		ASSERT( FALSE );
	}
	
	CExtAPSH(
			UINT nIDTemplate,
			UINT nIDCaption = 0
			)
	{
		// no such constructor in CPropertySheet
		nIDTemplate;
		nIDCaption;
		ASSERT( FALSE );
	}
	
	CExtAPSH(
			__EXT_MFC_SAFE_LPCTSTR lpszTemplateName,
			UINT nIDCaption = 0
			)
	{
		// no such constructor in CPropertySheet
		lpszTemplateName;
		nIDCaption;
		ASSERT( FALSE );
	}
	
	CExtAPSH(
		UINT nIDCaption,
		CWnd *pParentWnd,
		UINT iSelectPage
		)
		: CExtAPSHBase( nIDCaption, pParentWnd, iSelectPage )
	{
	}
	
	CExtAPSH(
		__EXT_MFC_SAFE_LPCTSTR pszCaption,
		CWnd *pParentWnd,
		UINT iSelectPage
		)
		: CExtAPSHBase( pszCaption, pParentWnd, iSelectPage )
	{
	}
}; // class CExtAPSH

/////////////////////////////////////////////////////////////////////////////
// CExtAPPG template adaptor for CPropertyPage

template < class CExtAPPGBase >
class CExtAPPG : public CExtAPPGBase
{
public:
	CExtAPPG()
	{
	}
	
	CExtAPPG(
		UINT nIDTemplate,
		CWnd * pParentWnd
		)
	{
		// no such constructor in CPropertyPage
		nIDTemplate;
		pParentWnd;
		ASSERT( FALSE );
	}
	
	CExtAPPG(
		__EXT_MFC_SAFE_LPCTSTR lpszTemplateName,
		CWnd * pParentWnd
		)
	{
		// no such constructor in CPropertyPage
		lpszTemplateName;
		pParentWnd;
		ASSERT( FALSE );
	}
	
	CExtAPPG(
			UINT nIDTemplate,
			UINT nIDCaption = 0
			)
		: CExtAPPGBase( nIDTemplate, nIDCaption )
	{
	}
	
	CExtAPPG(
			__EXT_MFC_SAFE_LPCTSTR lpszTemplateName,
			UINT nIDCaption = 0
			)
		: CExtAPPGBase( lpszTemplateName, nIDCaption )
	{
	}
	
	CExtAPPG(
		UINT nIDCaption,
		CWnd *pParentWnd,
		UINT iSelectPage
		)
	{
		// no such constructor in CPropertyPage
		nIDCaption;
		pParentWnd;
		iSelectPage;
		ASSERT( FALSE );
	}
	
	CExtAPPG(
		__EXT_MFC_SAFE_LPCTSTR pszCaption,
		CWnd *pParentWnd,
		UINT iSelectPage
		)
	{
		// no such constructor in CPropertyPage
		pszCaption;
		pParentWnd;
		iSelectPage;
		ASSERT( FALSE );
	}
}; // class CExtAPPG

/////////////////////////////////////////////////////////////////////////////
// CExtAGW template adaptor for generic window classes

template < class CExtAGWBase >
class CExtAGW : public CExtAGWBase
{
public:
	CExtAGW()
	{
	}
	
	CExtAGW(
		UINT nIDTemplate,
		CWnd * pParentWnd
		)
	{
		// should not have such constructor
		nIDTemplate;
		pParentWnd;
		ASSERT( FALSE );
	}
	
	CExtAGW(
		__EXT_MFC_SAFE_LPCTSTR lpszTemplateName,
		CWnd * pParentWnd
		)
	{
		// should not have such constructor
		lpszTemplateName;
		pParentWnd;
		ASSERT( FALSE );
	}
	
	CExtAGW(
			UINT nIDTemplate,
			UINT nIDCaption = 0
			)
		: CExtAGWBase( nIDTemplate, nIDCaption )
	{
		// should not have such constructor
		nIDTemplate;
		nIDCaption;
		ASSERT( FALSE );
	}
	
	CExtAGW(
			__EXT_MFC_SAFE_LPCTSTR lpszTemplateName,
			UINT nIDCaption = 0
			)
		: CExtAGWBase( lpszTemplateName, nIDCaption )
	{
		// should not have such constructor
		lpszTemplateName;
		nIDCaption;
		ASSERT( FALSE );
	}
	
	CExtAGW(
		UINT nIDCaption,
		CWnd *pParentWnd,
		UINT iSelectPage
		)
	{
		// should not have such constructor
		nIDCaption;
		pParentWnd;
		iSelectPage;
		ASSERT( FALSE );
	}
	
	CExtAGW(
		__EXT_MFC_SAFE_LPCTSTR pszCaption,
		CWnd *pParentWnd,
		UINT iSelectPage
		)
	{
		// should not have such constructor
		pszCaption;
		pParentWnd;
		iSelectPage;
		ASSERT( FALSE );
	}
}; // class CExtAGW

/////////////////////////////////////////////////////////////////////////////
// CExtAFV template adaptor for CFormView

template < class CExtAFVBase >
class CExtAFV : public CExtAFVBase
{
public:    
	CExtAFV()
	{
	}    
	CExtAFV(
		LPCTSTR lpszTemplateName,
		CWnd * pParentWnd
		)
		: CExtAFVBase( lpszTemplateName )
	{        
		pParentWnd;    
	}    
	CExtAFV(
		UINT nIDTemplate,
		CWnd * pParentWnd
		)
		: CExtAFVBase( nIDTemplate )
	{        
		pParentWnd;    
	}
}; // class CExtAFV

#endif // __EXT_TEMPL_H

