Click here to Skip to main content
15,897,371 members
Articles / Desktop Programming / MFC

Professional User Interface Suite

Rate me:
Please Sign up or sign in to vote.
4.99/5 (174 votes)
13 Jan 200423 min read 1.5M   23.6K   641  
MFC extension library enabling software to be provided with a professional UI
// This is part of the Professional User Interface Suite library.
// Copyright (C) 2001-2002 FOSS Software, Inc.
// All rights reserved.
//
// http://www.fossware.com
// mailto:foss@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.

// ExtPopupMenuWnd.cpp : implementation file
//

#include "stdafx.h"

#define _AFX_NO_OLE_SUPPORT

#ifndef __AFXPRIV_H__
	#include <AfxPriv.h>
#endif

#include <math.h>

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

#if (!defined __EXT_TOOLCONTROLBAR_H)
	#include <ExtToolControlBar.h>
#endif

#if (!defined __ExtCmdManager_H)
	#include <ExtCmdManager.h>
#endif

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

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

#if (!defined __EXT_LOCALIZATION_H)
	#include <../Src/ExtLocalization.h>
#endif

#include <../profuisdll/resource.h>

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

#ifdef _DEBUG
	static int g_nPopupCount = 0;
	//#define __VPC_VERIFY_0 ASSERT( g_nPopupCount == 0 )
	#define __VPC_VERIFY_0 { }
	#define __VPC_INC g_nPopupCount++
	#define __VPC_DEC g_nPopupCount--
#else // _DEBUG
	#define __VPC_VERIFY_0 { }
	#define __VPC_INC { }
	#define __VPC_DEC { }
#endif // _DEBUG

#define ID_TIMER_ANIMATION 666
#define ID_PERIOD_ANIMATION 30 // 20

#define ID_TIMER_ITEM_FOCUS_DELAY 667
#define ID_PERIOD_ITEM_FOCUS_DELAY 500

#define ID_TIMER_SCROLLING 668
#define ID_PERIOD_SCROLLING 15

#define ID_TIMER_DELAY_SHOW 669
#define ID_PERIOD_DELAY_SHOW 1000

#define ID_TIMER_DELAY_EXPAND 670
#define ID_FREQ_DELAY_EXPAND 50
#define ID_TOTAL_DELAY_EXPAND 1500

#define __SCROLLING_PIXEL_STEP 5

static const int g_nAnimStepMetric = 20;
static clock_t g_nLastAnimTime = 0;

#define __ANIM_CY 15

#define __EXCLUDE_AREA_GAP_DX 3
#define __EXCLUDE_AREA_GAP_DY __EXCLUDE_AREA_GAP_DX

#define __MI_HORZ_GAP_TO_BORDER 1

#define __BOX_ANIM_METRIC 32 // for __AT_BOXES,__AT_CIRCLES animation

CExtPopupMenuSite CExtPopupMenuSite::g_DefPopupMenuSite;

bool CExtPopupMenuWnd::g_bMenuWithShadows = true; // allow shadows
bool CExtPopupMenuWnd::g_bMenuExpanding = true; // allow hide rarely used
bool CExtPopupMenuWnd::g_bMenuHighlightRarely = true; // display rarely used in different style
bool CExtPopupMenuWnd::g_bMenuShowCoolTips = true; // allow display cool tooltips
bool CExtPopupMenuWnd::g_bMenuExpandAnimation = true; // allow animation when show rarely used
bool CExtPopupMenuWnd::g_bUseStretchOnExpandAnimation = false; // use StretchBlt() instead of BitBlt() for painting menu expand amimation

bool CExtPopupBaseWnd::g_bUseDesktopWorkArea = true; // align to desktop work area (false - to screen area)

bool CExtPopupBaseWnd::g_bEnableOnIdleCalls = false;

CExtPopupBaseWnd::e_animation_type_t
	CExtPopupBaseWnd::g_DefAnimationType =
		CExtPopupBaseWnd::__AT_FADE; // __AT_RANDOM

static inline int _GetMenuShadowSize()
{
	if( !CExtPopupMenuWnd::g_bMenuWithShadows )
		return 0;
//int nBitsPerPixel = CExtPaintManager::stat_GetBPP();
//	if( nBitsPerPixel <= 8 )
//		return 0;
	return g_PaintManager->GetMenuShadowSize();
};

UINT CExtPopupMenuWnd::g_nMsgPrepareMenu =
	::RegisterWindowMessage(
		_T("CExtPopupMenuWnd::g_nMsgPrepareMenu")
		);
UINT CExtPopupMenuWnd::g_nMsgPopupNext =
	::RegisterWindowMessage(
		_T("CExtPopupMenuWnd::g_nMsgPopupNext")
		);
UINT CExtPopupMenuWnd::g_nMsgPopupPrev =
	::RegisterWindowMessage(
		_T("CExtPopupMenuWnd::g_nMsgPopupPrev")
		);
UINT CExtPopupMenuWnd::g_nMsgNotifyMenuExpanded =
	::RegisterWindowMessage(
		_T("CExtPopupMenuWnd::g_nMsgNotifyMenuExpanded")
		);
UINT CExtPopupMenuWnd::g_nMsgNotifyMenuClosed =
	::RegisterWindowMessage(
		_T("CExtPopupMenuWnd::g_nMsgNotifyMenuClosed")
		);
UINT CExtPopupMenuWnd::g_nMsgPopupDrawItem =
	::RegisterWindowMessage(
		_T("CExtPopupMenuWnd::g_nMsgPopupDrawItem")
		);
UINT CExtPopupMenuWnd::g_nMsgPopupDrawLeftArea =
	::RegisterWindowMessage(
		_T("CExtPopupMenuWnd::g_nMsgPopupDrawLeftArea")
		);

#define __POPUP_WNDCLASS_STYLES__ \
	( CS_SAVEBITS )
//	( CS_SAVEBITS \
//		|CS_HREDRAW \
//		|CS_VREDRAW \
//		|CS_NOCLOSE \
//	)

/////////////////////////////////////////////////////////////////////////////
// CExtSoundPlayer

CExtSoundPlayer::CExtSoundPlayerAutoPtr g_SoundPlayer;

IMPLEMENT_DYNAMIC( CExtSoundPlayer, CObject );

CEvent CExtSoundPlayer::InternalSoundThredadParms_t::g_EventPlaySnd(
	TRUE,
	FALSE,
	_T("CExtSoundPlayer__InternalSoundThredadParms_t")
	);

CCriticalSection CExtSoundPlayer::InternalSoundThredadParms_t::g_CsPlaySnd;

DWORD CExtSoundPlayer::InternalSoundThredadParms_t::stat_ParallelPlayerProc(
	CExtSoundPlayer::InternalSoundThredadParms_t * pParms
	)
{
	ASSERT( pParms != NULL );
	pParms->PlaySound();
	g_EventPlaySnd.SetEvent();
	return 0;
}

void CExtSoundPlayer::InternalSoundThredadParms_t::PlaySound()
{
CString sSoundSpecBuffer( m_sSoundSpecBuffer );
HANDLE hModule = m_hModule;
DWORD dwPlayerFlags = m_dwPlayerFlags;
	if( m_pEventInitDone != NULL )
		m_pEventInitDone->SetInitDone();
	::PlaySound(
		LPCTSTR( sSoundSpecBuffer ),
		(HMODULE)hModule,
		dwPlayerFlags
		);
	if( (m_dwPlayerFlags & SND_SYNC) != 0 )
		::PlaySound( NULL, NULL, SND_PURGE );
}

void CExtSoundPlayer::InternalSoundThredadParms_t::PlaySoundParallel()
{
	ASSERT( m_hThread == NULL );
CSingleLock slCs( &g_CsPlaySnd );
	slCs.Lock();
HANDLE hEvent = (HANDLE)g_EventPlaySnd;
	ASSERT( hEvent != NULL );
	if( ::WaitForSingleObject(hEvent,0) == WAIT_OBJECT_0 )
	{
		ASSERT( m_pEventInitDone == NULL );
		InternalSoundEventInitDone_t EventInitDone;
		m_pEventInitDone = &EventInitDone;
		m_hThread =
			::CreateThread(
				NULL,
				0,
				*this,
				this,
				CREATE_SUSPENDED,
				&m_dwThreadID
				);
		ASSERT( m_hThread != NULL );
		if( m_hThread != NULL )
		{
			VERIFY(
				::SetThreadPriority(
					m_hThread,
					THREAD_PRIORITY_BELOW_NORMAL
					)
				);
			::ResumeThread( m_hThread );
			EventInitDone.WaitInitDone();
		} // if( m_hThread != NULL )
		else
			g_EventPlaySnd.SetEvent();
	} // if( ::WaitForSingleObject(hEvent,0) == WAIT_OBJECT_0 )
	slCs.Unlock();
}

CExtSoundPlayer::CExtSoundPlayerAutoPtr::CExtSoundPlayerAutoPtr()
{
	m_pPlayer = new CExtSoundPlayer;
}

CExtSoundPlayer::CExtSoundPlayerAutoPtr::~CExtSoundPlayerAutoPtr()
{
	if( m_pPlayer != NULL )
		delete m_pPlayer;
}

void CExtSoundPlayer::CExtSoundPlayerAutoPtr::InstallSoundPlayer(
	CExtSoundPlayer * pPlayer
	)
{
	ASSERT( pPlayer != NULL );
	ASSERT_VALID( pPlayer );
	ASSERT_KINDOF( CExtSoundPlayer, m_pPlayer );
	if( m_pPlayer != NULL )
		delete m_pPlayer;
	m_pPlayer = pPlayer;
}

CExtSoundPlayer::CExtSoundPlayer()
{
}

CExtSoundPlayer::~CExtSoundPlayer()
{
}

void CExtSoundPlayer::PlaySound(
	CExtSoundPlayer::e_ui_sounds_t eSoundID
	)
{
	ASSERT_VALID( this );
	switch( eSoundID )
	{
	case __NO_SOUND:
		return;
	case __ON_MENU_EXPAND_CLICKED:
	case __ON_MENU_POPUP_DISPLAYED:
		{
			InternalSoundThredadParms_t _istp( _T("MenuPopup") );
			_istp.PlaySoundParallel();
			return;
		}
	case __ON_MENU_CMD_CLICKED:
		{
			InternalSoundThredadParms_t _istp( _T("MenuCommand") );
			_istp.PlaySoundParallel();
			return;
		}
	} // switch( eSoundID )
}

/////////////////////////////////////////////////////////////////////////////
// CExtPopupMenuSite

CExtPopupMenuSite::CExtPopupMenuSite()
	: m_pTopMenu( NULL )
	, m_pWndCapture( NULL )
	, m_pWndAnimation( NULL )
	, m_bShutdownMode( false )
	, m_hMouseHook( NULL )
	, m_hKeyboardHook( NULL )
	, m_lpnResultCmdID( NULL )
{
}

CExtPopupMenuSite::~CExtPopupMenuSite()
{
	_Done();
}

CExtPopupMenuWnd * CExtPopupMenuSite::GetCapture()
{
	ASSERT( !IsEmpty() );
	ASSERT( !IsShutdownMode() );
	return m_pWndCapture;
}

void CExtPopupMenuSite::SetCapture(
	CExtPopupMenuWnd * pNewPopup // = NULL
	)
{
	ASSERT( !IsEmpty() );
	ASSERT( !IsShutdownMode() );

#ifdef _DEBUG
	if( pNewPopup != NULL )
	{
		ASSERT_VALID( pNewPopup );
	}
#endif // _DEBUG
	m_pWndCapture = pNewPopup;
}

void CExtPopupMenuSite::SetInstance(
	CExtPopupMenuWnd * pTopMenu // = NULL
	)
{
	ASSERT( !IsShutdownMode() );
	if( !IsEmpty() )
	{
		ASSERT( m_pTopMenu != NULL );
		ASSERT_VALID( m_pTopMenu );
		ASSERT( m_pTopMenu->m_bTopLevel );
		if( m_pTopMenu == pTopMenu )
			return;
		if( m_pTopMenu != pTopMenu )
			_Done();
	}
	ASSERT( m_pTopMenu == NULL );
	if( pTopMenu != NULL )
	{
		ASSERT_VALID( pTopMenu );
		ASSERT( pTopMenu->m_bTopLevel );
		m_pTopMenu = pTopMenu;
		_Hook( true );
	}
}

CExtPopupMenuWnd * CExtPopupMenuSite::GetAnimated()
{
	ASSERT( !IsEmpty() );
	ASSERT( !IsShutdownMode() );
	return m_pWndAnimation;
}

void CExtPopupMenuSite::SetAnimated(
	CExtPopupMenuWnd * pNewPopup // = NULL
	)
{
	ASSERT( !IsEmpty() );
	ASSERT( !IsShutdownMode() );
	m_pWndAnimation = pNewPopup;
}

CExtPopupMenuWnd * CExtPopupMenuSite::GetInstance()
{
	return m_pTopMenu;
}

void CExtPopupMenuSite::SetTargetCmdIdPtr(
	UINT * lpnResultCmdID // = NULL
	)
{
	m_lpnResultCmdID = lpnResultCmdID;
}

UINT * CExtPopupMenuSite::GetTargetCmdIdPtr()
{
	return m_lpnResultCmdID;
}

void CExtPopupMenuSite::DoneInstance()
{
	_Done();
}

bool CExtPopupMenuSite::IsTopPupup(
	CExtPopupMenuWnd * pTopMenu
	) const
{
	ASSERT( !IsEmpty() );
	ASSERT( !IsShutdownMode() );
	ASSERT_VALID( pTopMenu );
	return (pTopMenu==m_pTopMenu) ? true : false;
}

void CExtPopupMenuSite::_Done()
{
	ASSERT( !m_bShutdownMode );
	m_bShutdownMode = true;
	m_pWndCapture = NULL;
	m_pWndAnimation = NULL;
	m_lpnResultCmdID = NULL;
	if( m_pTopMenu != NULL )
	{
		ASSERT( m_pTopMenu->m_bTopLevel );
		VERIFY( m_pTopMenu->_BuildItems( NULL, true ) );
		if( m_pTopMenu->GetSafeHwnd() != NULL
			&& ::IsWindow( m_pTopMenu->GetSafeHwnd() )
			)
		{
			m_pTopMenu->DestroyWindow();
			CExtPopupMenuWnd::PassMsgLoop( CExtPopupBaseWnd::g_bEnableOnIdleCalls );
		}
		ASSERT( m_pTopMenu->GetSafeHwnd() == NULL );
		delete m_pTopMenu;
		m_pTopMenu = NULL;
	}
	_Hook( false );
	__VPC_VERIFY_0;
	m_bShutdownMode = false;
}

LRESULT CALLBACK CExtPopupMenuSite::_HookMouseProc(
	int nCode,      // hook code
	WPARAM wParam,  // message identifier
	LPARAM lParam   // mouse coordinates
	)
{

MOUSEHOOKSTRUCT* lpMS = (MOUSEHOOKSTRUCT*)lParam;
	ASSERT( lpMS != NULL );

	if( !g_DefPopupMenuSite.IsEmpty() && !g_DefPopupMenuSite.IsShutdownMode() )
	{
		CExtPopupMenuWnd * pWndCapture =
			g_DefPopupMenuSite.GetCapture();
		if( pWndCapture != NULL
			&& ::IsWindow( pWndCapture->GetSafeHwnd() )
			)
		{
			ASSERT_VALID( pWndCapture );
			switch( wParam )
			{
			//case WM_MOUSEACTIVATE:
			//	if( lpMS->hwnd != pWndCapture->GetSafeHwnd() )
			//		return 1;
			//break;

			case WM_MOUSEMOVE:
			{
				CPoint pt( lpMS->pt );
				pWndCapture->ScreenToClient( &pt );
				if(	pWndCapture->
					_OnMouseMove(
						wParam,
						pt
						)
					)
					return 1; // eat!
			}
			break;

			case WM_MOUSEWHEEL:
				return 1; // eat!

			case WM_NCLBUTTONDOWN:
			case WM_NCRBUTTONDOWN:
			case WM_NCMBUTTONDOWN:
			case WM_LBUTTONDOWN:
			case WM_RBUTTONDOWN:
			case WM_MBUTTONDOWN:

			case WM_NCMBUTTONUP:
			case WM_MBUTTONUP:
			case WM_NCRBUTTONUP:
			case WM_RBUTTONUP:

			{

				CPoint pt( lpMS->pt );
				//pWndCapture->ScreenToClient( &pt );
				CExtPopupMenuWnd * pPopup = pWndCapture;
				for( ; pPopup != NULL; pPopup = pPopup->m_pWndParentMenu )
				{
					CRect wrMenuFrame;
					pPopup->GetWindowRect( &wrMenuFrame );
					if( wrMenuFrame.PtInRect(pt) )
						return 1; // eat!
				}
				pPopup = CExtPopupMenuSite::g_DefPopupMenuSite.GetInstance();
				ASSERT_VALID( pPopup );
				ASSERT( ::IsWindow(pPopup->GetSafeHwnd()) );
				pPopup->_OnCancelMode();

			if(		wParam != WM_LBUTTONDOWN
				&&	wParam != WM_RBUTTONDOWN
				&&	wParam != WM_MBUTTONDOWN
				)
				// currently NC areas are not safe on MDI apps
				return 1; // eat!

			}
			break;

			case WM_NCLBUTTONUP:
			//case WM_NCRBUTTONUP:
			//case WM_NCMBUTTONUP:
			case WM_LBUTTONUP:
			//case WM_RBUTTONUP:
			//case WM_MBUTTONUP:
			{
				//CRect rcWndCapture;
				//_pWndCapture->GetWindowRect( &rcWndCapture );
				//if( !rcWndCapture.PtInRect(lpMS->pt) )
				//	break;
				CPoint pt( lpMS->pt );
				pWndCapture->ScreenToClient( &pt );

				if(	pWndCapture->_OnMouseClick( wParam, pt ) )
					return 1; // eat!
			}
			break;

			//default:
			//	return 1; // eat!
			} // switch( wParam )
		} // if( pWndCapture != NULL ....
		else
			return 1; // eat
	} // if( !g_DefPopupMenuSite.IsEmpty() && !g_DefPopupMenuSite.IsShutdownMode() )
	return
		::CallNextHookEx(
			g_DefPopupMenuSite.m_hMouseHook,
			nCode,
			wParam,
			lParam
			);
}

LRESULT CALLBACK CExtPopupMenuSite::_HookKeyboardProc(
	int nCode,      // hook code
	WPARAM wParam,  // virtual-key code
	LPARAM lParam   // keystroke-message information
	)
{

	if( !g_DefPopupMenuSite.IsEmpty() && !g_DefPopupMenuSite.IsShutdownMode() )
	{
		CExtPopupMenuWnd * pWndCapture =
			g_DefPopupMenuSite.GetCapture();
		if(	pWndCapture->GetSafeHwnd() != NULL
			&& ::IsWindow( pWndCapture->GetSafeHwnd() )
			)
		{
			ASSERT_VALID( pWndCapture );
			if(
				(lParam & (1<<31)) == 0 )
			{
				// clocks allows to fix problem with
				// duplicated fast key hook calls
				static clock_t _clock_step =
					CLOCKS_PER_SEC / 50; // 1/50 of second
				static clock_t _clock_last =
					0; //clock();
				clock_t _clock_curr =
					clock();
				//ASSERT( _clock_curr >= _clock_last );
				clock_t _clock_diff =
					abs(_clock_curr - _clock_last);
				if( _clock_diff >= _clock_step )
				{
					_clock_last = _clock_curr;
					if(	pWndCapture->
							_OnKeyDown(
								wParam,
								LOWORD(lParam),
								HIWORD(lParam)
								)
						)
						return 1; // eat!
					if( pWndCapture != NULL )
						return 1; // eat!
				}
			}
		}
//		if( !CExtToolControlBar::g_bMenuTracking )
//			return 1; // eat!
	} // if( !g_DefPopupMenuSite.IsEmpty() && !g_DefPopupMenuSite.IsShutdownMode() )

	if(		(!CExtToolControlBar::g_bMenuTracking)
		&&	CExtPopupMenuWnd::IsCmdKeyActivation( lParam )
		&&	( lParam & (1<<31) ) != 0
		)
	{
		CExtPopupMenuWnd::CancelMenuTracking();
		return
			::CallNextHookEx(
				g_DefPopupMenuSite.m_hKeyboardHook,
				nCode,
				wParam,
				lParam
				);
	}

	return
		::CallNextHookEx(
			g_DefPopupMenuSite.m_hKeyboardHook,
			nCode,
			wParam,
			lParam
			);
}

void CExtPopupMenuSite::_Hook(
	bool bHook // = true
	)
{
	if( bHook )
	{
		if( m_hMouseHook == NULL )
		{
			m_hMouseHook =
				::SetWindowsHookEx(
					WH_MOUSE,
					_HookMouseProc, 
					0,
					::GetCurrentThreadId()
					);
			ASSERT( m_hMouseHook != NULL );
		}
		if( m_hKeyboardHook == NULL )
		{
			m_hKeyboardHook =
				::SetWindowsHookEx(
					WH_KEYBOARD,
					_HookKeyboardProc, 
					0,
					::GetCurrentThreadId()
					);
			ASSERT( m_hKeyboardHook != NULL );
		}
	} // if( bHook )
	else
	{
		if( m_hMouseHook != NULL )
		{
			::UnhookWindowsHookEx( m_hMouseHook );
			m_hMouseHook = NULL;
		}
		if( m_hKeyboardHook != NULL )
		{
			::UnhookWindowsHookEx( m_hKeyboardHook );
			m_hKeyboardHook = NULL;
		}
	} // else from if( bHook )
}

/////////////////////////////////////////////////////////////////////////////
// CExtWndShadow

CExtWndShadow::CExtWndShadow()
{
	Destroy();
}

CExtWndShadow::~CExtWndShadow()
{
	Destroy();
}

void CExtWndShadow::_DoPixelOvershadow(
	int nMakeSpec,
	int nPosX,
	int nPosY
	)
{
	ASSERT( nMakeSpec >= 0 && nMakeSpec <= 100 );
	ASSERT( !m_rcWndArea.IsRectEmpty() );
	ASSERT( nPosX < m_rcWndArea.Width() + INT(m_nShadowSize) );
	ASSERT( nPosY < m_rcWndArea.Height() + INT(m_nShadowSize) );
	ASSERT( m_pHelperDibSurface != NULL );
int nTotalWidth = m_rcWndArea.Width()+m_nShadowSize;
int nTotalHeight = m_rcWndArea.Height()+m_nShadowSize;
COLORREF * ptr =
		m_pHelperDibSurface
		+nPosX+(nTotalHeight-nPosY)*nTotalWidth;
	*ptr =
		RGB(
			(( nMakeSpec * int(GetRValue(*ptr)) ) / 100),
			(( nMakeSpec * int(GetGValue(*ptr)) ) / 100),
			(( nMakeSpec * int(GetBValue(*ptr)) ) / 100)
			);
}

bool CExtWndShadow::Restore( CDC & dc )
{
	ASSERT( m_nShadowSize >= 0 );
	if( m_nShadowSize == 0 || m_rcWndArea.IsRectEmpty () )
		return true;
	if(		m_bmp0.GetSafeHandle() == NULL
		||	m_bmp1.GetSafeHandle() == NULL
		)
		return false;

INT nWndAreaDX = m_rcWndArea.Width ();
INT nWndAreaDY = m_rcWndArea.Height ();
	ASSERT( nWndAreaDX > 0 && nWndAreaDY > 0 );
CDC dcmm;
	if( !dcmm.CreateCompatibleDC(&dc) )
	{
		ASSERT( FALSE );
		return false;
	}
CBitmap * pbmpold = dcmm.SelectObject( &m_bmp0 );
	ASSERT( pbmpold != NULL );
	dc.BitBlt(
		m_rcWndArea.right, m_rcWndArea.top,
		m_nShadowSize, nWndAreaDY+m_nShadowSize,
		&dcmm,
		0, 0,
		SRCCOPY
		);
	dcmm.SelectObject( &m_bmp1 );
	dc.BitBlt(
		m_rcWndArea.left, m_rcWndArea.bottom,
		nWndAreaDX+m_nShadowSize, m_nShadowSize,
		&dcmm,
		0, 0,
		SRCCOPY
		);
	dcmm.SelectObject( pbmpold );
	return true;
}

bool CExtWndShadow::Paint(
	CDC & dc,
	const CRect & rcWndArea,
	const CRect & rc1stArea, // = CRect(0,0,0,0)
	const CRect & rc2ndArea, // = CRect(0,0,0,0)
	UINT nShadowSize, // = DEF_SHADOW_SIZE
	UINT nBr0, // = DEF_BRIGHTNESS_MIN
	UINT nBr1, // = DEF_BRIGHTNESS_MAX
	bool bEnablePhotos // = true
	)
{
	m_rcWndArea = rcWndArea;
	m_rc1stArea = rc1stArea;
	m_rc2ndArea = rc2ndArea;
	m_nShadowSize = nShadowSize;
	m_nBr0 = nBr0;
	m_nBr1 = nBr1;
	m_bEnablePhotos = bEnablePhotos;
	return Paint( dc );
}

bool CExtWndShadow::Paint( CDC & dc )
{
	ASSERT( m_nShadowSize >= 0 );
	ASSERT( !m_rcWndArea.IsRectEmpty() );
	if( m_nShadowSize == 0 || m_rcWndArea.IsRectEmpty() )
		return true;

	if( Restore( dc ) )
		return true;

	if( CExtPaintManager::stat_GetBPP() > 8 )
		return _PaintHi( dc );
	return _PaintLo( dc );
}

bool CExtWndShadow::_PaintLo( CDC & dc )
{
INT nWndAreaDX = m_rcWndArea.Width();
INT nWndAreaDY = m_rcWndArea.Height();
	ASSERT(
			m_bmp0.GetSafeHandle() == NULL
		&&	m_bmp1.GetSafeHandle() == NULL
		);
static int _Pattern[] =
{
	~0xAA,
	~0x55,
	~0xAA,
	~0x55,
	~0xAA,
	~0x55,
	~0xAA,
	~0x55
};
CBitmap bmpsh;
CBrush brsh;
	if(		!bmpsh.CreateBitmap(8, 8, 1, 1, _Pattern)
		||	!brsh.CreatePatternBrush( &bmpsh )
		)
		return false;
CExtMemoryDC dcmm(
		&dc,
		NULL,
		CExtMemoryDC::MDCOPT_TO_MEMORY
		);
	ASSERT( dcmm.GetSafeHdc() != NULL );
	if( dcmm.GetSafeHdc() == NULL )
		return false;
CPalette * pOldPalette = NULL;
    if( dcmm.GetDeviceCaps(RASTERCAPS) & RC_PALETTE )
	{
        pOldPalette =
			dcmm.SelectPalette( &g_PaintManager->m_PaletteWide, FALSE );
        dcmm.RealizePalette();
    }
	dcmm.BitBlt(
		m_rcWndArea.left, m_rcWndArea.top,
		nWndAreaDX+m_nShadowSize, nWndAreaDY+m_nShadowSize,
		&dc,
		m_rcWndArea.left, m_rcWndArea.top,
		SRCCOPY
		);
UINT nPaintShadowSize =
		( m_nShadowSize > 4 )
			? 4
			: m_nShadowSize;
CRect rV(
		 m_rcWndArea.right,
		 m_rcWndArea.top+nPaintShadowSize,
		 m_rcWndArea.right+nPaintShadowSize,
		 m_rcWndArea.bottom
		 );
CRect rH(
		 m_rcWndArea.left+nPaintShadowSize,
		 m_rcWndArea.bottom,
		 m_rcWndArea.right+nPaintShadowSize,
		 m_rcWndArea.bottom+nPaintShadowSize
		 );
CBrush * pbrold = dcmm.SelectObject( &brsh );
	dcmm.PatBlt( rH.left, rH.top, rH.Width(), rH.Height(), 0xA000C9 );
	dcmm.PatBlt( rV.left, rV.top, rV.Width(), rV.Height(), 0xA000C9 );
	dcmm.SelectObject( pbrold );
	dc.BitBlt(
		m_rcWndArea.left, m_rcWndArea.top,
		nWndAreaDX+m_nShadowSize, nWndAreaDY+m_nShadowSize, 
		&dcmm,
		m_rcWndArea.left, m_rcWndArea.top,
		SRCCOPY
		);
	if( m_bEnablePhotos )
	{
		if( !_MakePhotos(dc,dcmm) )
		{
			ASSERT( FALSE );
			return false;
		}
	}
	if( pOldPalette != NULL )
		dcmm.SelectPalette( pOldPalette, FALSE );
	dcmm.__Flush( FALSE );
	return true;
}

bool CExtWndShadow::_PaintHi( CDC & dc )
{
INT nWndAreaDX = m_rcWndArea.Width();
INT nWndAreaDY = m_rcWndArea.Height();
	ASSERT(
			m_bmp0.GetSafeHandle() == NULL
		&&	m_bmp1.GetSafeHandle() == NULL
		);
CDC dcmm;
	if( !dcmm.CreateCompatibleDC( &dc ) )
	{
		ASSERT( FALSE );
		return false;
	}

BITMAPINFOHEADER bih;
	bih.biSize = sizeof(BITMAPINFOHEADER);
	bih.biWidth = nWndAreaDX+m_nShadowSize;
	bih.biHeight = nWndAreaDY+m_nShadowSize;
	bih.biPlanes = 1;
	bih.biBitCount = 32;
	bih.biCompression = BI_RGB;
	bih.biSizeImage = (nWndAreaDX+m_nShadowSize) * (nWndAreaDY+m_nShadowSize);
	bih.biXPelsPerMeter = 0;
	bih.biYPelsPerMeter = 0;
	bih.biClrUsed = 0;
	bih.biClrImportant = 0;

	ASSERT( m_pHelperDibSurface == NULL );
HBITMAP hDIB =
		::CreateDIBSection(
			dcmm.GetSafeHdc(),
			(LPBITMAPINFO)&bih,
			DIB_RGB_COLORS,
			(void **)&m_pHelperDibSurface,
			NULL,
			NULL
			);
	if( hDIB == NULL || m_pHelperDibSurface == NULL )
	{
		ASSERT( FALSE );
		return false;
	}

	dcmm.SelectObject( hDIB );
	dcmm.BitBlt(
		0, 0,
		nWndAreaDX+m_nShadowSize, nWndAreaDY+m_nShadowSize,
		&dc,
		m_rcWndArea.left, m_rcWndArea.top,
		SRCCOPY
		);

UINT nBrDiff = m_nBr1-m_nBr0;
LONG n2nd, nStep, nDist, nDist1;
LONG nDist2 = m_nShadowSize*m_nShadowSize;
INT nMakeSpec;
bool	bCmbaV = false, bCmbaH = false,
		bCmbaVrt = false, bCmbaVrb = false,
		bCmbaHrb = false, bCmbaHlb = false,
		bCmbaLA = false;
INT		nX0 = 0, nX1 = nWndAreaDX,
		nY0 = 0, nY1 = nWndAreaDY,
		nLa0 = 0, nLa1 = 0;
	if( !( m_rc1stArea.IsRectEmpty() || m_rc2ndArea.IsRectEmpty() ) )
	{
		bool bCmbaDetected = false;
		if( m_rc1stArea.right == m_rc2ndArea.right )
		{ // vertical-right combining
			bCmbaDetected = true;
			if( m_rc1stArea.top < m_rc2ndArea.top )
				bCmbaVrb = true;
			else
				bCmbaVrt = true;
		} // vertical-right combining
		if( (!bCmbaDetected) &&
			m_rc1stArea.left == m_rc2ndArea.left )
		{ // vertical-left combining
			if( m_rc2ndArea.bottom >= m_rc1stArea.top-1
				&& m_rc2ndArea.top < m_rc1stArea.top
				)
			{
				if( m_rc2ndArea.right >= m_rc1stArea.right )
				{
					bCmbaDetected = true;
					bCmbaV = true;
				}
			}
			if(	(!bCmbaDetected)
				&& m_rc1stArea.bottom >= m_rc2ndArea.top-1 
				&& m_rc1stArea.top < m_rc2ndArea.top
				)
			{
				if( m_rc1stArea.right >= m_rc2ndArea.right )
				{
					bCmbaDetected = true;
					bCmbaH = true;
					nX0 =
						m_rcWndArea.right  -
						(m_rc1stArea.right - m_rc2ndArea.right);
				}
			}
		} // vertical-left combining
		if( (!bCmbaDetected) &&
			m_rc1stArea.bottom == m_rc2ndArea.bottom
			)
		{ // horizontal-bottom combining
			bCmbaDetected = true;
			if( m_rc1stArea.left < m_rc2ndArea.left )
				bCmbaHrb = true;
			else
				bCmbaHlb = true;
		} // horizontal-bottom combining
		if( (!bCmbaDetected) &&
			m_rc1stArea.right == m_rc2ndArea.left+1
			)
		{
			bCmbaDetected = true;
			bCmbaLA = true;
			nLa0 = m_rcWndArea.top
				+ m_rc2ndArea.bottom - m_rc1stArea.top;
			nLa1 = nLa0 + m_nShadowSize;
		}
		if( (!bCmbaDetected) &&
			m_rc1stArea.left == m_rc2ndArea.right-1
			)
		{
			bCmbaDetected = true;
			bCmbaH = true;
		}
		bCmbaDetected;
	} // if( !( m_rc1stArea.IsRectEmpty() || m_rc2ndArea.IsRectEmpty() ) )
	for( nStep = 0; ULONG(nStep) < m_nShadowSize; nStep++ )
	{
		nMakeSpec = m_nBr0+(nStep*nBrDiff)/m_nShadowSize;
		for(	n2nd = nX0
					+ m_nShadowSize*2+1
					- ( bCmbaH ? (m_nShadowSize*2-nStep) : 0 )
					- ( bCmbaHlb ? m_nShadowSize : 0 )
					;
				n2nd < LONG(nX1) + (bCmbaHrb ? LONG(m_nShadowSize) : 0);
				n2nd++
				)
			_DoPixelOvershadow(
				nMakeSpec,
				n2nd,
				nY1+nStep
				);
		for(	n2nd = nY0
					+ m_nShadowSize*2+1
					- ( bCmbaV ? (m_nShadowSize*2-nStep) : 0 )
					- ( bCmbaVrt ? m_nShadowSize : 0 )
					;
				n2nd < LONG(nY1) + (bCmbaVrb ? LONG(m_nShadowSize) : 0);
				n2nd++
				)
		{
			if( bCmbaLA
				&& n2nd >= nLa0
				&& n2nd < LONG(nLa1) - (LONG(m_nShadowSize) - nStep)
				)
			{
				continue;
			}
			_DoPixelOvershadow(
				nMakeSpec,
				nX1+nStep,
				n2nd
				);
		}
		nDist1 = nStep*nStep;
		for( n2nd = 0; ULONG(n2nd) < m_nShadowSize; n2nd++ )
		{
			nDist = nDist1 + n2nd*n2nd;
			if( nDist > nDist2 )
				continue;
			nDist = (LONG)::sqrt( double(nDist) );
			nMakeSpec = m_nBr0+(nDist*nBrDiff)/m_nShadowSize;
			if( !(bCmbaVrb || bCmbaHrb) )
				_DoPixelOvershadow(
					nMakeSpec,
					nX1+nStep,
					nY1+n2nd
					);
			if( !(bCmbaH || bCmbaHlb) )
				_DoPixelOvershadow(
					nMakeSpec,
					m_nShadowSize+(m_nShadowSize-nStep),
					nY1+n2nd
					);
			if( !(bCmbaV || bCmbaVrt) )
				_DoPixelOvershadow(
					nMakeSpec,
					nX1+nStep,
					m_nShadowSize+(m_nShadowSize-n2nd)
					);
		} // for( n2nd = 0; ULONG(n2nd) < m_nShadowSize; n2nd++ )
	} // for( nStep = 0; ULONG(nStep) < m_nShadowSize; nStep++ )
	dc.BitBlt(
		m_rcWndArea.left, m_rcWndArea.top,
		nWndAreaDX+m_nShadowSize, nWndAreaDY+m_nShadowSize, 
		&dcmm,
		0, 0,
		SRCCOPY
		);

	if( m_bEnablePhotos )
	{
		if( !_MakePhotos(dc,dcmm) )
		{
			ASSERT( FALSE );
			return false;
		}
	}

	::DeleteObject( hDIB );
	m_pHelperDibSurface = NULL;

	return true;
}

bool CExtWndShadow::_MakePhotos( CDC & dc, CDC & dcmm )
{
	ASSERT( m_nShadowSize >= 0 );
	ASSERT( !m_rcWndArea.IsRectEmpty() );
INT nWndAreaDX = m_rcWndArea.Width();
INT nWndAreaDY = m_rcWndArea.Height();
	ASSERT(
			m_bmp0.GetSafeHandle() == NULL
		&&	m_bmp1.GetSafeHandle() == NULL
		);
	if(	!m_bmp0.CreateCompatibleBitmap(
			&dc, m_nShadowSize, nWndAreaDY+m_nShadowSize
			)
		)
	{
		ASSERT( FALSE );
		return false;
	}
	dcmm.SelectObject( &m_bmp0 );
	if(	!dcmm.BitBlt(
			0, 0, m_nShadowSize, nWndAreaDY+m_nShadowSize,
			&dc,
			m_rcWndArea.right, m_rcWndArea.top,
			SRCCOPY
			)
		)
	{
		ASSERT( FALSE );
		return false;
	}
	if(	!m_bmp1.CreateCompatibleBitmap(
			&dc, nWndAreaDX+m_nShadowSize, m_nShadowSize
			)
		)
	{
		ASSERT( FALSE );
		return false;
	}
	dcmm.SelectObject( &m_bmp1 );
	if(	!dcmm.BitBlt(
			0, 0, nWndAreaDX+m_nShadowSize, m_nShadowSize,
			&dc,
			m_rcWndArea.left, m_rcWndArea.bottom,
			SRCCOPY
			)
		)
	{
		ASSERT( FALSE );
		return false;
	}
	return true;
}

void CExtWndShadow::_FreeWinObjects()
{
	if( m_bmp0.GetSafeHandle() != NULL )
		m_bmp0.DeleteObject();
	if( m_bmp1.GetSafeHandle() != NULL )
		m_bmp1.DeleteObject();
	m_pHelperDibSurface = NULL;
}

void CExtWndShadow::Destroy()
{
	_FreeWinObjects();
	m_rcWndArea.SetRectEmpty();
	m_bEnablePhotos = false;
}

/////////////////////////////////////////////////////////////////////////////
// CExtPopupMenuWnd::MENUITEMDATA

CExtPopupMenuWnd::MENUITEMDATA::MENUITEMDATA()
{
	// self constant type assertion
	ASSERT( TYPE_SEPARATOR==ID_SEPARATOR );
	m_pWndChild = NULL;
	m_nItemIndex = -100;
	m_nCmdID = TYPE_SEPARATOR;
	m_sPopupText = m_sPopupAccelText = _T("");
	m_hIconPopup = NULL;
	m_size.cx = m_size.cy = 0;
	m_bSelected
		= m_bDisplayed
		= m_bForceDisplayed
		= false;
	m_cAccelChar = 0;
	m_hWndSpecCmdReciever = NULL;
}

CExtPopupMenuWnd::MENUITEMDATA::~MENUITEMDATA()
{
	// DestroyPopup();
}

void CExtPopupMenuWnd::MENUITEMDATA::AccelCharInit()
{
	m_cAccelChar = 0;
	CString sDisplayText( GetText() );
	if( sDisplayText.IsEmpty() )
		return;
	int nIndex = sDisplayText.Find( _T('&') );
	if( nIndex + 1 == sDisplayText.GetLength() )
	{
		TRACE(_T("warning : & is bad position, access key is invalid.\n"));
		return;
	}
	if( nIndex < 0 )
	{
		if( !CExtPopupMenuWnd::g_bAllowNonAccelPositioning )
			return;
		m_cAccelChar = sDisplayText[0];
	}
	else
		m_cAccelChar = sDisplayText[nIndex + 1]; // -1 + 1 = 0; it's ok
	TCHAR szChar[2] = { m_cAccelChar, _T('\0') };
	::CharUpper( szChar );
	m_cAccelChar = szChar[0];
}

TCHAR CExtPopupMenuWnd::MENUITEMDATA::AccelCharGet() const
{
	return m_cAccelChar;
}

bool CExtPopupMenuWnd::MENUITEMDATA::AccelCharIsSet() const
{
	return (m_cAccelChar == 0) ? false : true;
}

bool CExtPopupMenuWnd::MENUITEMDATA::UpdateCmdManagerCommand(
	CExtCmdManager::cmd_t * p_cmd,
	int nItemIndex
	)
{
	ASSERT( p_cmd != NULL );
	ASSERT( !IsPopup() );
	ASSERT( m_pWndChild == NULL );
	m_sPopupText.Empty();
	m_nCmdID = p_cmd->m_nCmdID;
	if( !CExtCmdManager::IsCommand(m_nCmdID) )
	{
		m_nCmdID = TYPE_SEPARATOR;
		m_nItemIndex = -100;
		ASSERT( FALSE );
		return false;
	}
	if( nItemIndex >= 0 )
		m_nItemIndex = nItemIndex;
	MeasureItem();
	return true;
}

CExtCmdManager::cmd_t * CExtPopupMenuWnd::MENUITEMDATA::GetCmd() const
{
	if( IsPopup() || IsSeparator() )
		return NULL;
	CExtCmdManager::cmd_t * p_cmd =
		g_CmdManager->CmdGetPtr(
			g_CmdManager->ProfileNameFromWnd( GetCmdReciever() ),
			m_nCmdID
			);
	ASSERT( p_cmd != NULL );
	return p_cmd;
}

void CExtPopupMenuWnd::MENUITEMDATA::MeasureItem()
{
	AccelCharInit();
	if( IsSeparator() )
	{
		m_size.cx = 0;
		m_size.cy = __DEF_MENU_SEPARATOR_HEIGHT;
		return;
	}
	CString sMeasureText( GetText() );
	sMeasureText += GetAccelText();
	sMeasureText.Replace( _T("&"), _T("") );
	CWindowDC dc(NULL);
	CFont * pOldFont =
		dc.SelectObject( &(g_PaintManager->m_FontNormal) );
	ASSERT( pOldFont != NULL );
	CRect rect(0,0,0,0);
	m_size.cy = DrawText(
		dc.GetSafeHdc(),
		(LPCTSTR)sMeasureText,
		sMeasureText.GetLength(),
		&rect,
		DT_CALCRECT|DT_SINGLELINE
			|DT_LEFT|DT_VCENTER
		);
	m_size.cx = rect.Width();
	dc.SelectObject( pOldFont );
	m_size.cx +=
		__DEF_MENU_ICON_CX
		+ __DEF_MENU_GAP*6 // + __DEF_MENU_GAP*5
		+ __DEF_MENU_POPUP_ARROW_AREA_DX
		;
	if( m_size.cy < __DEF_MENU_HEIGHT )
		m_size.cy = __DEF_MENU_HEIGHT;
}

bool CExtPopupMenuWnd::MENUITEMDATA::UpdateFromMenu(
	HWND hWndCmdProfileInfo,
	CMenu * pTrackMenu,
	int nItemIndex
	)
{
	ASSERT( pTrackMenu != NULL );
	ASSERT( pTrackMenu->GetSafeHmenu() != NULL );
	
#ifdef _DEBUG
	int	nMenuItemCount = pTrackMenu->GetMenuItemCount();
	ASSERT( nMenuItemCount > 0 );
	ASSERT( nItemIndex >= 0 && nItemIndex<nMenuItemCount );
#endif // _DEBUG

	MENUITEMINFO mii;
	::memset(&mii,0,sizeof(MENUITEMINFO));
	mii.cbSize = sizeof(MENUITEMINFO);
	mii.fMask =
		MIIM_CHECKMARKS
		|MIIM_DATA
		|MIIM_ID
		|MIIM_STATE
		|MIIM_SUBMENU
		|MIIM_TYPE
		;
	mii.cch = __MAX_UI_ITEM_TEXT;
	mii.dwTypeData =
		m_sPopupText.GetBuffer(__MAX_UI_ITEM_TEXT);
	ASSERT( mii.dwTypeData != NULL );
	if( mii.dwTypeData == NULL )
	{
		ASSERT( FALSE );
		return false;
	}
	if( !pTrackMenu->GetMenuItemInfo(
			nItemIndex,
			&mii,
			TRUE
			)
		)
	{
		m_sPopupText.ReleaseBuffer();
		ASSERT( FALSE );
		return false;
	}
	m_sPopupText.ReleaseBuffer();

	m_nItemIndex = nItemIndex;
	if( (mii.fType&MFT_SEPARATOR) != 0 )
	{
		m_sPopupText.Empty();
		m_nCmdID = TYPE_SEPARATOR;
		MeasureItem();
		return true;
	}
	if( mii.hSubMenu != NULL )
	{
		if( !ConstructPopup() )
		{
			ASSERT( FALSE );
			return false;
		}
		m_nCmdID = (UINT)TYPE_POPUP;
		MeasureItem();
		return true;
	}

	m_sPopupText.Empty(); // we no need longer this text
	if( !CExtCmdManager::IsCommand(mii.wID) )
	{
		ASSERT( FALSE );
		return false;
	}
	m_nCmdID = mii.wID;
	CExtCmdManager::cmd_t * p_cmd =
		g_CmdManager->CmdGetPtr(
			g_CmdManager->ProfileNameFromWnd( hWndCmdProfileInfo ),
			m_nCmdID
			);
	ASSERT( p_cmd != NULL );
	if( p_cmd == NULL )
		return false;
	MeasureItem();
	return true;
}

/////////////////////////////////////////////////////////////////////////////
// CExtPopupBaseWnd

IMPLEMENT_DYNCREATE(CExtPopupBaseWnd, __BaseClassOfCExtPopupBaseWnd)

CExtPopupBaseWnd::CExtPopupBaseWnd()
{
	m_clrFadeBitsSrc
		= m_clrFadeBitsDst
		= m_clrFadeBitsTmp
		= NULL;
	m_AnimationType = g_DefAnimationType;
	_InitAnimation();
	m_ePlaySoundOnAnimationFinished =
		CExtSoundPlayer::__NO_SOUND;

	m_sizeFullItems.cx = m_sizeFullItems.cy = 1;

	m_bExcludeAreaSpec
		= m_bCombineWithEA
		= false;
	m_rcExcludeArea.SetRectEmpty();
	m_ptTrack.x = m_ptTrack.y;
}

CExtPopupBaseWnd::~CExtPopupBaseWnd()
{
}

void CExtPopupBaseWnd::_InitAnimation()
{
	ASSERT_VALID( this );

	m_nAnimPercent = m_nAnimPercentOld = 0;
	//m_AnimationType = g_DefAnimationType;

	if( (m_AnimationType < 0
			|| m_AnimationType > __AT_MAX_VALID_VALUE)
		&&
		m_AnimationType != __AT_CONTENT_DISPLAY
		&&
		m_AnimationType != __AT_CONTENT_EXPAND
		)
		m_AnimationType = __AT_NONE;

	if( m_AnimationType == __AT_RANDOM )
	{
		int nRand = rand() % (__AT_MAX_VALID_VALUE+1);
		ASSERT( nRand >= 0 && nRand <= __AT_MAX_VALID_VALUE );
		if( nRand == __AT_NONE || nRand == __AT_RANDOM )
			nRand = __AT_FADE; // most cool of all effects
		m_AnimationType = (e_animation_type_t)nRand;
	}

int nBitsPerPixel = CExtPaintManager::stat_GetBPP();
	if( nBitsPerPixel <= 8
		&&
		m_AnimationType != __AT_CONTENT_EXPAND
		&&
		m_AnimationType != __AT_CONTENT_DISPLAY
		)
	{
		m_AnimationType = __AT_NONE;
		m_bAnimFinished = true;
	}

	else
	{
		m_bAnimFinished =
			(m_AnimationType == __AT_NONE) ? true : false;
	}

	ASSERT(
			m_bmpScreenDst.GetSafeHandle() == NULL
		&&	m_bmpScreenSrc.GetSafeHandle() == NULL
		&&	m_bmpScreenTmp.GetSafeHandle() == NULL
		&&	m_clrFadeBitsSrc == NULL
		&&	m_clrFadeBitsDst == NULL
		&&	m_clrFadeBitsTmp == NULL
		);
}

void CExtPopupBaseWnd::_StartAnimation()
{
	ASSERT_VALID( this );
	_InitAnimation();
	if( m_AnimationType != __AT_NONE )
	{
		SetTimer( ID_TIMER_ANIMATION, ID_PERIOD_ANIMATION, NULL );
		g_nLastAnimTime = clock();
	}
}

void CExtPopupMenuWnd::_StartAnimation()
{
	ASSERT_VALID( this );
	_ItemFocusDelay();
	_CoolTipHide( false );
	CExtPopupBaseWnd::_StartAnimation();
	GetSite().SetAnimated(
		m_bAnimFinished ? NULL : this
		);
}

BEGIN_MESSAGE_MAP(CExtPopupBaseWnd, __BaseClassOfCExtPopupBaseWnd)
	//{{AFX_MSG_MAP(CExtPopupBaseWnd)
	ON_WM_MOUSEACTIVATE()
	ON_WM_ERASEBKGND()
	ON_WM_PAINT()
	ON_WM_NCPAINT()
	ON_WM_NCCALCSIZE()
	ON_WM_SIZE()
	ON_WM_ACTIVATEAPP()
	ON_WM_CANCELMODE()
	ON_WM_SETCURSOR()
	ON_WM_TIMER()
	//}}AFX_MSG_MAP
END_MESSAGE_MAP()

void CExtPopupBaseWnd::OnPaint() 
{
	ASSERT_VALID( this );

	if( !(::IsWindow(GetSafeHwnd())) )
		return;
	if( !(::IsWindowVisible(GetSafeHwnd())) )
		return;
CPaintDC dc(this); // device context for painting
//	_BitsSave( dc );

	if( !m_bAnimFinished )
		_DrawAnimatedState( dc );
	else
		_DoPaint( dc );
}

void CExtPopupBaseWnd::_DrawAnimatedState( CDC & dc )
{
	ASSERT_VALID( this );

	_DoPaint( dc );
}

void CExtPopupMenuWnd::_DrawAnimatedState( CDC & dc )
{
	ASSERT_VALID( this );

	if( !(::IsWindow(GetSafeHwnd())) )
		return;
CRect rcClient;
	GetClientRect( &rcClient );

int cx = rcClient.Width();
int cy = rcClient.Height();

CDC * pPaintDC = &dc;

CPalette * pOldPalette = NULL;
    if( pPaintDC->GetDeviceCaps(RASTERCAPS) & RC_PALETTE )
    {
        pOldPalette =
			pPaintDC->SelectPalette( &g_PaintManager->m_PaletteWide, FALSE );
        pPaintDC->RealizePalette();
    }

CDC dcmm;
	VERIFY( dcmm.CreateCompatibleDC(pPaintDC) );
bool bFail = false;
	if( m_bmpScreenDst.GetSafeHandle() == NULL )
	{
		ASSERT( m_bmpScreenSrc.GetSafeHandle() == NULL );
		ASSERT( m_bmpScreenTmp.GetSafeHandle() == NULL );
		
		int nBitsPerPixel = CExtPaintManager::stat_GetBPP();
		CBitmap * pBmpOld = NULL;
		if(	(m_AnimationType == __AT_FADE
				&& nBitsPerPixel > 8 )
			|| m_AnimationType == __AT_CONTENT_EXPAND
			|| m_AnimationType == __AT_CONTENT_DISPLAY
			|| m_AnimationType == __AT_ROLL
			|| m_AnimationType == __AT_SLIDE
			|| m_AnimationType == __AT_ROLL_AND_STRETCH
			|| m_AnimationType == __AT_SLIDE_AND_STRETCH
			|| m_AnimationType == __AT_NOISE
			|| m_AnimationType == __AT_BOXES
			|| m_AnimationType == __AT_CIRCLES
			|| m_AnimationType == __AT_HOLES
			)
		{
			BITMAPINFOHEADER bih;
			bih.biSize = sizeof(BITMAPINFOHEADER);
			bih.biWidth = cx;
			bih.biHeight = cy;
			bih.biPlanes = 1;
			bih.biBitCount = 32;
			bih.biCompression = BI_RGB;
			bih.biSizeImage = cx * cy;
			bih.biXPelsPerMeter = 0;
			bih.biYPelsPerMeter = 0;
			bih.biClrUsed = 0;
			bih.biClrImportant = 0;

			HBITMAP hDIB =
				::CreateDIBSection(
					dcmm.GetSafeHdc(),
					(LPBITMAPINFO)&bih,
					DIB_RGB_COLORS,
					(void **)&m_clrFadeBitsSrc,
					NULL,
					NULL
					);
			if( hDIB != NULL && m_clrFadeBitsSrc != NULL )
			{
				m_bmpScreenSrc.Attach( hDIB );

				hDIB =
					::CreateDIBSection(
						dcmm.GetSafeHdc(),
						(LPBITMAPINFO)&bih,
						DIB_RGB_COLORS,
						(void **)&m_clrFadeBitsDst,
						NULL,
						NULL
						);
				if( hDIB != NULL && m_clrFadeBitsDst != NULL )
				{
					m_bmpScreenDst.Attach( hDIB );

					hDIB =
						::CreateDIBSection(
							dcmm.GetSafeHdc(),
							(LPBITMAPINFO)&bih,
							DIB_RGB_COLORS,
							(void **)&m_clrFadeBitsTmp,
							NULL,
							NULL
							);
					if( hDIB != NULL && m_clrFadeBitsTmp != NULL )
					{
						m_bmpScreenTmp.Attach( hDIB );

						pBmpOld =
							dcmm.SelectObject( &m_bmpScreenSrc );
						dcmm.BitBlt(
							0, 0, cx, cy, pPaintDC,
							rcClient.left,
							rcClient.top,
							SRCCOPY
							);

						::memcpy(
							m_clrFadeBitsDst,
							m_clrFadeBitsSrc,
							sizeof(COLORREF)*cx*cy
							);
						dcmm.SelectObject( &m_bmpScreenDst );
					} // if( hDIB != NULL && m_clrFadeBitsTmp != NULL )
					else
					{
						m_bmpScreenSrc.DeleteObject();
						m_bmpScreenDst.DeleteObject();
						//return;
						bFail = true;
					} // else from if( hDIB != NULL && m_clrFadeBitsTmp != NULL )
				} // if( hDIB != NULL && m_clrFadeBitsDst != NULL )
				else
				{
					m_bmpScreenSrc.DeleteObject();
					//return;
					bFail = true;
				} // else from if( hDIB != NULL && m_clrFadeBitsDst != NULL )
			} // if( hDIB != NULL && m_clrFadeBitsSrc != NULL )
		}
		else
		{
			m_bmpScreenDst.CreateCompatibleBitmap(
				pPaintDC,
				cx,
				cy
				);
			pBmpOld =
				dcmm.SelectObject( &m_bmpScreenDst );
		}

		if( !bFail )
			_DoPaint( dcmm, false );
		dcmm.SetViewportOrg( CPoint(0,0) );
		dcmm.SelectObject( pBmpOld );
	} // if( m_bmpScreenDst.GetSafeHandle() == NULL )

CBitmap * pBmpOld = NULL;
	if( !bFail )
	{
		COLORREF * src = m_clrFadeBitsSrc;
		COLORREF * dst = m_clrFadeBitsDst;
		COLORREF * tmp = m_clrFadeBitsTmp;

		switch( m_AnimationType )
		{
		case __AT_BOXES:
		case __AT_CIRCLES:
		case __AT_HOLES:
			if( tmp!= NULL && src!=NULL && dst != NULL )
			{
				ASSERT(
					m_nAnimPercent >= 0 && m_nAnimPercent <= 100
					&&
					m_nAnimPercentOld >= 0 && m_nAnimPercentOld <= 100
					&&
					m_nAnimPercentOld <= m_nAnimPercent
					);
				ASSERT( __BOX_ANIM_METRIC > 0 ); // self assert
				if( m_nAnimPercentOld != m_nAnimPercent )
				{
					pBmpOld = dcmm.SelectObject( &m_bmpScreenTmp );
					if( m_AnimationType == __AT_BOXES )
					{ // do boxes animation
						for( int y=0; y<cy; y++ )
						{
							int _y0 = y % __BOX_ANIM_METRIC;
							int _yPercent = 100 -
								(_y0 * 100) / __BOX_ANIM_METRIC;
							if( _yPercent < m_nAnimPercent )
							{
								::memcpy(
									tmp,
									src,
									cx*sizeof(COLORREF)
									);
								tmp += cx;
								src += cx;
								dst += cx;
								continue;
							}
							for( int x=0; x<cx; x++ )
							{
								int _x0 = x % __BOX_ANIM_METRIC;
								int _xPercent =
									(_x0 * 100) / __BOX_ANIM_METRIC;
								if( _xPercent < m_nAnimPercent )
									*tmp = *dst;
								else
									*tmp = *src;
								tmp++; src++; dst++;
							}
						} // for( int y=0; y<cy; y++ )
					} // do boxes animation
					else
					{ // do circles/holes animation
						double radius = 0;
						if( m_AnimationType == __AT_HOLES )
							radius = 
								((((double)(__BOX_ANIM_METRIC)) / 2) * (100-m_nAnimPercent))
								/ 100;
						else
							radius = 
								((((double)(__BOX_ANIM_METRIC)) / 2) * m_nAnimPercent)
								/ 100;
						if( radius > 0 )
						{
							for( int y=0; y<cy; y++ )
							{
								int _y0 = y % __BOX_ANIM_METRIC;
								int _y1 = y - _y0;
								//int _y2 = _y1 + __BOX_ANIM_METRIC;
								int _yCenter = _y1 + __BOX_ANIM_METRIC/2;
								int _yDist = abs( y - _yCenter );
								double _yDist2 = (double)_yDist*_yDist;
								for( int x=0; x<cx; x++ )
								{
									int _x0 = x % __BOX_ANIM_METRIC;
									int _x1 = x - _x0;
									//int _x2 = _x1 + __BOX_ANIM_METRIC;
									int _xCenter = _x1 + __BOX_ANIM_METRIC/2;
									int _xDist = abs( x - _xCenter );
									double _xDist2 = (double)_xDist*_xDist;

									double nDispance =
										::sqrt(_yDist2+_xDist2);
									if( m_AnimationType == __AT_HOLES )
									{ // holes
										if( nDispance >= radius )
											*tmp = *dst;
										else
											*tmp = *src;
									} // holes
									else
									{ // circles
										if( nDispance < radius )
											*tmp = *dst;
										else
											*tmp = *src;
									} // circles
									tmp++; src++; dst++;
								}
							} // for( int y=0; y<cy; y++ )
						} // if( radius > 0 )
					} // do circles/holes animation

					int nMenuShadowSize =
						_GetMenuShadowSize();
					if( m_bCombineWithEA )
					{ // paint combined area AS IS
						ASSERT( !m_rcExcludeArea.IsRectEmpty() );
						CRect rcExcludeArea( m_rcExcludeArea );
						ScreenToClient( &rcExcludeArea );
						pBmpOld = dcmm.SelectObject( &m_bmpScreenDst );
						pPaintDC->BitBlt(
							rcExcludeArea.left, rcExcludeArea.top,
							rcExcludeArea.Width(), rcExcludeArea.Height(), 
							&dcmm,
							rcExcludeArea.left, rcExcludeArea.top,
							SRCCOPY
							);
						dcmm.SelectObject( pBmpOld );
						pBmpOld = NULL;
						if( m_eCombineAlign != __CMBA_NONE )
						{
//							int nMenuShadowSize =
//								_GetMenuShadowSize();
							rcExcludeArea.InflateRect(
								(m_eCombineAlign == __CMBA_RIGHT) ?
									0 : nMenuShadowSize,
								(m_eCombineAlign == __CMBA_BOTTOM) ?
									0 : nMenuShadowSize,
								(m_eCombineAlign == __CMBA_LEFT) ?
									0 : nMenuShadowSize,
								(m_eCombineAlign == __CMBA_TOP) ?
									0 : nMenuShadowSize
								);
						} // if( m_eCombineAlign != __CMBA_NONE )
						pPaintDC->ExcludeClipRect(
							&rcExcludeArea
							);
					} // paint combined area AS IS
					if( nMenuShadowSize > 0 )
					{
						CRect rcExcludeArea( rcClient );
						rcExcludeArea.left =
							rcExcludeArea.right
							- nMenuShadowSize;
						pPaintDC->ExcludeClipRect(
							&rcExcludeArea
							);
						rcExcludeArea = rcClient ;
						rcExcludeArea.top =
							rcExcludeArea.bottom
							- nMenuShadowSize;
						pPaintDC->ExcludeClipRect(
							&rcExcludeArea
							);
					}
					
					pPaintDC->BitBlt(
						rcClient.left, rcClient.top, cx, cy, 
						&dcmm,
						0,
						0,
						SRCCOPY
						);

					if( nMenuShadowSize > 0 || m_bCombineWithEA )
						pPaintDC->SelectClipRgn( NULL );
				} // if( m_nAnimPercentOld != m_nAnimPercent )
			}
		break; // cases __AT_BOXES,__AT_CIRCLES,__AT_HOLES
		case __AT_NOISE:
			if( tmp!= NULL && src!=NULL && dst != NULL )
			{
				ASSERT(
					m_nAnimPercent >= 0 && m_nAnimPercent <= 100
					&&
					m_nAnimPercentOld >= 0 && m_nAnimPercentOld <= 100
					&&
					m_nAnimPercentOld <= m_nAnimPercent
					);
				if( m_nAnimPercentOld != m_nAnimPercent )
				{
					int nDiff =
						m_nAnimPercent - m_nAnimPercentOld;
					ASSERT( nDiff > 0 );
					int nRandHalf = nDiff / 2 + 1;
					ASSERT( nRandHalf > 0 );
					pBmpOld = dcmm.SelectObject( &m_bmpScreenTmp );
					for( int pixel = 0; pixel < cx * cy; pixel++ )
					{
						int nRandValue = 
							rand() % nDiff;
						if( nRandValue > nRandHalf )
							*tmp = *dst;
//						else
//							*tmp = *src;
						tmp++; src++; dst++;
					} // for( int pixel = 0; pixel < cx * cy; pixel++ )

					int nMenuShadowSize =
						_GetMenuShadowSize();
					if( m_bCombineWithEA )
					{ // paint combined area AS IS
						ASSERT( !m_rcExcludeArea.IsRectEmpty() );
						CRect rcExcludeArea( m_rcExcludeArea );
						ScreenToClient( &rcExcludeArea );
						pBmpOld = dcmm.SelectObject( &m_bmpScreenDst );
						pPaintDC->BitBlt(
							rcExcludeArea.left, rcExcludeArea.top,
							rcExcludeArea.Width(), rcExcludeArea.Height(), 
							&dcmm,
							rcExcludeArea.left, rcExcludeArea.top,
							SRCCOPY
							);
						dcmm.SelectObject( pBmpOld );
						pBmpOld = NULL;
						if( m_eCombineAlign != __CMBA_NONE )
						{
//							int nMenuShadowSize =
//								_GetMenuShadowSize();
							rcExcludeArea.InflateRect(
								(m_eCombineAlign == __CMBA_RIGHT) ?
									0 : nMenuShadowSize,
								(m_eCombineAlign == __CMBA_BOTTOM) ?
									0 : nMenuShadowSize,
								(m_eCombineAlign == __CMBA_LEFT) ?
									0 : nMenuShadowSize,
								(m_eCombineAlign == __CMBA_TOP) ?
									0 : nMenuShadowSize
								);
						} // if( m_eCombineAlign != __CMBA_NONE )
						pPaintDC->ExcludeClipRect(
							&rcExcludeArea
							);
					} // paint combined area AS IS
					if( nMenuShadowSize > 0 )
					{
						CRect rcExcludeArea( rcClient );
						rcExcludeArea.left =
							rcExcludeArea.right
							- nMenuShadowSize;
						pPaintDC->ExcludeClipRect(
							&rcExcludeArea
							);
						rcExcludeArea = rcClient ;
						rcExcludeArea.top =
							rcExcludeArea.bottom
							- nMenuShadowSize;
						pPaintDC->ExcludeClipRect(
							&rcExcludeArea
							);
					}
					
					pPaintDC->BitBlt(
						rcClient.left, rcClient.top, cx, cy, 
						&dcmm,
						0,
						0,
						SRCCOPY
						);

					if( nMenuShadowSize > 0 || m_bCombineWithEA )
						pPaintDC->SelectClipRgn( NULL );
				} // if( m_nAnimPercentOld != m_nAnimPercent )
			}
		break; // case __AT_NOISE
		case __AT_SLIDE:
		case __AT_ROLL:
		case __AT_ROLL_AND_STRETCH:
		case __AT_SLIDE_AND_STRETCH:
			if( tmp!= NULL && src!=NULL && dst != NULL )
			{
				ASSERT(
					m_nAnimPercent >= 0 && m_nAnimPercent <= 100
					&&
					m_nAnimPercentOld >= 0 && m_nAnimPercentOld <= 100
					&&
					m_nAnimPercentOld <= m_nAnimPercent
					);

				CRect _rcClient;
				_GetClientRect( &_rcClient );

				if( m_bCombineWithEA )
				{ // paint combined area AS IS
					ASSERT( !m_rcExcludeArea.IsRectEmpty() );
					CRect rcExcludeArea( m_rcExcludeArea );
					ScreenToClient( &rcExcludeArea );
					pBmpOld = dcmm.SelectObject( &m_bmpScreenDst );
					pPaintDC->BitBlt(
						rcExcludeArea.left, rcExcludeArea.top,
						rcExcludeArea.Width(), rcExcludeArea.Height(), 
						&dcmm,
						rcExcludeArea.left, rcExcludeArea.top,
						SRCCOPY
						);
					dcmm.SelectObject( pBmpOld );
					pBmpOld = NULL;
					if( m_eCombineAlign != __CMBA_NONE )
					{
						int nMenuShadowSize =
							_GetMenuShadowSize();
						rcExcludeArea.InflateRect(
							(m_eCombineAlign == __CMBA_RIGHT) ?
								0 : nMenuShadowSize,
							(m_eCombineAlign == __CMBA_BOTTOM) ?
								0 : nMenuShadowSize,
							(m_eCombineAlign == __CMBA_LEFT) ?
								0 : nMenuShadowSize,
							(m_eCombineAlign == __CMBA_TOP) ?
								0 : nMenuShadowSize
							);
					} // if( m_eCombineAlign != __CMBA_NONE )
					pPaintDC->ExcludeClipRect(
						&rcExcludeArea
						);
				} // paint combined area AS IS

				pBmpOld = dcmm.SelectObject( &m_bmpScreenDst );
				int cx =
					_rcClient.Width();
				int cy =
					_rcClient.Height();
				if( m_AnimationType == __AT_ROLL
					||
					m_AnimationType == __AT_SLIDE
					)
				{ // non-stratchable variants
					int _cx = 0;
					if( m_AnimationType == __AT_ROLL )
						_cx = (cx * (100-m_nAnimPercent)) / 100;
					int _cy =
						(cy * (100-m_nAnimPercent)) / 100;
					pPaintDC->BitBlt(
						_rcClient.left-_cx, _rcClient.top-_cy, cx, cy, 
						&dcmm,
						_rcClient.left, _rcClient.top,
						SRCCOPY
						);
				} // non-stratchable variants
				else
				{ // stratchable variants
					int _cx = cx;
					if( m_AnimationType == __AT_ROLL_AND_STRETCH )
						_cx = (cx * m_nAnimPercent) / 100;
					int _cy =
						(cy * m_nAnimPercent) / 100;
					pPaintDC->StretchBlt(
						_rcClient.left, _rcClient.top, _cx, _cy, 
						&dcmm,
						_rcClient.left, _rcClient.top, cx, cy, 
						SRCCOPY
						);
				} // stratchable variants

				if( m_bCombineWithEA )
					pPaintDC->SelectClipRgn( NULL );
			}
		break; // cases __AT_ROLL, __AT_SLIDE, __AT_ROLL_AND_STRETCH, __AT_ROLL_AND_STRETCH

		case __AT_CONTENT_EXPAND:
			if( tmp!= NULL && src!=NULL && dst != NULL )
			{
				ASSERT(
					m_nAnimPercent >= 0 && m_nAnimPercent <= 100
					&&
					m_nAnimPercentOld >= 0 && m_nAnimPercentOld <= 100
					&&
					m_nAnimPercentOld <= m_nAnimPercent
					);

				CRect _rcClient;
				_GetClientRect( &_rcClient );

				if( m_bCombineWithEA )
				{ // paint combined area AS IS
					ASSERT( !m_rcExcludeArea.IsRectEmpty() );
					CRect rcExcludeArea( m_rcExcludeArea );
					ScreenToClient( &rcExcludeArea );
					pBmpOld = dcmm.SelectObject( &m_bmpScreenDst );
					pPaintDC->BitBlt(
						rcExcludeArea.left, rcExcludeArea.top,
						rcExcludeArea.Width(), rcExcludeArea.Height(), 
						&dcmm,
						rcExcludeArea.left, rcExcludeArea.top,
						SRCCOPY
						);
					dcmm.SelectObject( pBmpOld );
					pBmpOld = NULL;
				} // paint combined area AS IS

				pBmpOld = dcmm.SelectObject( &m_bmpScreenDst );
				int cx =
					_rcClient.Width();
				int cy =
					_rcClient.Height();
				int _cx = cx;
				int _cy =
					(cy * m_nAnimPercent) / 100;

				visible_items_t v;
					_GetVisibleItems( dcmm /*dc*/, v );
				if( v.GetSize() == 0 )
				{ // if menu is empty
					pPaintDC->StretchBlt(
						_rcClient.left, _rcClient.top, _cx, _cy, 
						&dcmm,
						_rcClient.left, _rcClient.top, cx, cy,
						SRCCOPY
						);
				} // if menu is empty
				else
				{ // if menu is NOT empty
					int y_pos_src = _rcClient.top;
					int y_pos_dst = _rcClient.top;
					INT vis_iter = 0;
					int nItemIndex = 0;
					int nItemCount = v.GetSize();
					ASSERT( nItemCount > 0 );
					expand_effect_rects_container_t vRects;
					
					for( ; vis_iter < v.GetSize(); ++vis_iter, ++nItemIndex )
					{ // calc rects for visible items
						VisibleItemDefinion_t & vi = v[vis_iter];
#ifdef _DEBUG
						ASSERT(
							vi.m_nIndex >= 0
							&&
							vi.m_nIndex < m_items_all.GetSize()
							);
//						ASSERT( !vi.m_rcItem.IsRectEmpty() );
//						ASSERT( dc.RectVisible(&vi.m_rcItem) );
						MENUITEMDATA & mi =
							m_items_all[vi.m_nIndex];
						ASSERT( mi.IsDisplayed() );
						ASSERT( mi.GetCmdID() == vi.m_nHelperCmdID );
#endif // _DEBUG

						CRect rcItemSrc( vi.m_rcItem );
						rcItemSrc.left = _rcClient.left;
						rcItemSrc.right = _rcClient.right;
						if( nItemIndex == 0 )
							rcItemSrc.top = _rcClient.top;
						else if( nItemIndex == (nItemCount-1) )
							rcItemSrc.bottom = _rcClient.bottom;

						int y_pos_src_next = 
							y_pos_src + rcItemSrc.Height();
						CRect rcItemDst( rcItemSrc );
						rcItemDst.OffsetRect(
							0,
							y_pos_dst - rcItemDst.top
							);
						if( vi.m_bRarelyUsed )
							rcItemDst.bottom =
								rcItemDst.top
								+
								(rcItemDst.Height() * m_nAnimPercent)
									/ 100;
						int y_pos_dst_next = 
							y_pos_dst + rcItemDst.Height();
						
						ExpandEffectRects_t _eert(
							rcItemSrc,
							rcItemDst
							);
						vRects.Add( _eert );
						y_pos_dst = y_pos_dst_next;
						y_pos_src = y_pos_src_next;
					} // calc rects for visible items

					// y_pos_dst is now equal to size of
					// all compressed itsms
					ASSERT( y_pos_dst <= y_pos_src );
					if( m_bCombineWithEA
						&&
						m_eCombineAlign == __CMBA_BOTTOM
						&&
						y_pos_dst != y_pos_src
						)
					{ // expand from bottom to top
						INT iter_rects = 0;
						int nDstOffset =
							y_pos_src - y_pos_dst;
						for( ; iter_rects < vRects.GetSize(); ++iter_rects )
						{ // adjust destination rects
							ExpandEffectRects_t & eerc =
								vRects[ iter_rects ];
							eerc.m_rcDst.OffsetRect(
								0,
								nDstOffset
								);
						} // adjust destination rects
					} // expand from bottom to top

					INT iter_rects = 0;
					for( ; iter_rects < vRects.GetSize(); ++iter_rects )
					{ // paint visible items
						ExpandEffectRects_t & eerc =
							vRects[ iter_rects ];
						if( eerc.m_rcDst.IsRectEmpty() )
							continue;
						if( g_bUseStretchOnExpandAnimation )
							// something better then Office XP
							pPaintDC->StretchBlt(
								eerc.m_rcDst.left, eerc.m_rcDst.top,
								eerc.m_rcDst.Width(), eerc.m_rcDst.Height(), 
								&dcmm,
								eerc.m_rcSrc.left, eerc.m_rcSrc.top,
								eerc.m_rcSrc.Width(), eerc.m_rcSrc.Height(), 
								SRCCOPY
								);
						else
							// somthing really like Office XP
							pPaintDC->BitBlt(
								eerc.m_rcDst.left, eerc.m_rcDst.top,
								eerc.m_rcDst.Width(), eerc.m_rcDst.Height(), 
								&dcmm,
								eerc.m_rcSrc.left, eerc.m_rcSrc.top,
								SRCCOPY
								);
					} // paint visible items
				} // if menu is NOT empty

			}
		break; // case __AT_CONTENT_EXPAND

		case __AT_CONTENT_DISPLAY:
			if( tmp!= NULL && src!=NULL && dst != NULL )
			{
				pBmpOld = dcmm.SelectObject( &m_bmpScreenDst );
				pPaintDC->BitBlt(
					rcClient.left, rcClient.top, cx, cy, 
					&dcmm,
					0,
					0,
					SRCCOPY
					);
			}
		break; // case __AT_CONTENT_DISPLAY

		case __AT_FADE:
			if( tmp!= NULL && src!=NULL && dst != NULL )
			{
				ASSERT(
					m_nAnimPercent >= 0 && m_nAnimPercent <= 100
					&&
					m_nAnimPercentOld >= 0 && m_nAnimPercentOld <= 100
					&&
					m_nAnimPercentOld <= m_nAnimPercent
					);
				pBmpOld = dcmm.SelectObject( &m_bmpScreenTmp );
				for( int pixel = 0; pixel < cx * cy; pixel++ )
				{
					COLORREF c0 = *dst++;
					COLORREF c1 = *src++;
					*tmp++ =
						RGB(
							(m_nAnimPercent*long(GetRValue(c0)) + (100L-m_nAnimPercent)*long(GetRValue(c1)) ) / 100L,
							(m_nAnimPercent*long(GetGValue(c0)) + (100L-m_nAnimPercent)*long(GetGValue(c1)) ) / 100L,
							(m_nAnimPercent*long(GetBValue(c0)) + (100L-m_nAnimPercent)*long(GetBValue(c1)) ) / 100L
							);
				} // for( int pixel = 0; pixel < cx * cy; pixel++ )
				pPaintDC->BitBlt(
					rcClient.left, rcClient.top, cx, cy, 
					&dcmm,
					0,
					0,
					SRCCOPY
					);
			}
		break; // case __AT_FADE

#ifdef _DEBUG
		default:
			ASSERT( FALSE );
		break; // default
#endif // _DEBUG
		} // switch( m_AnimationType )
	} // if( !bFail )

	if( pBmpOld != NULL )
		dcmm.SelectObject( pBmpOld );

	if( pOldPalette != NULL )
		pPaintDC->SelectPalette( pOldPalette, FALSE );
}

void CExtPopupBaseWnd::_DoPaint( CDC & dcPaint, bool bUseBackBuffer /*= true*/ )
{
	ASSERT_VALID( this );

	dcPaint;
	bUseBackBuffer;
}

void CExtPopupBaseWnd::OnTimer(UINT nIDEvent) 
{
	ASSERT_VALID( this );

	switch( nIDEvent )
	{
	case ID_TIMER_DELAY_SHOW:
	{
		VERIFY( KillTimer(ID_TIMER_DELAY_SHOW) );
		ShowWindow( SW_SHOWNA );
		Invalidate( FALSE );
		UpdateWindow();
		return;
	}
	// case ID_TIMER_DELAY_SHOW

	case ID_TIMER_ANIMATION:
		if( !m_bAnimFinished )
		{
			clock_t nCurrAnimTime = clock();
			int nDuration =
				nCurrAnimTime - g_nLastAnimTime;
			int nSteps = (int)
				(0.5 + (float) nDuration / ID_PERIOD_ANIMATION);
			switch( m_AnimationType )
			{
			case __AT_CONTENT_DISPLAY:
				m_bAnimFinished = true;
			break;
			case __AT_FADE:
			case __AT_CONTENT_EXPAND:
			case __AT_ROLL:
			case __AT_SLIDE:
			case __AT_ROLL_AND_STRETCH:
			case __AT_SLIDE_AND_STRETCH:
			case __AT_NOISE:
			case __AT_BOXES:
			case __AT_CIRCLES:
			case __AT_HOLES:
				m_nAnimPercentOld = m_nAnimPercent;
				m_nAnimPercent += g_nAnimStepMetric;
				if( m_nAnimPercent >
						100 + nSteps * g_nAnimStepMetric
					)
					m_nAnimPercent = 101;
				if( m_nAnimPercent > 100 )
					m_bAnimFinished = true;
			break;
#ifdef _DEBUG
			default:
				ASSERT( FALSE );
			break;
#endif // _DEBUG
			} // switch( m_AnimationType )

			if( m_bAnimFinished )
			{
				g_SoundPlayer->PlaySound(
					m_ePlaySoundOnAnimationFinished
					);
				m_ePlaySoundOnAnimationFinished =
					CExtSoundPlayer::__NO_SOUND;
				KillTimer(ID_TIMER_ANIMATION);
				m_AnimationType = g_DefAnimationType;
			} // if( m_bAnimFinished )

			if( GetSafeHwnd() != NULL )
			{
				if( m_bAnimFinished )
					_EndAnimation();
				else
					Invalidate( FALSE );
				g_nLastAnimTime = nCurrAnimTime;
			}
		} // if( !m_bAnimFinished )
		
		if( m_bAnimFinished )
			if( IsKindOf(RUNTIME_CLASS(CExtPopupMenuWnd)) )
				((CExtPopupMenuWnd *)this)->
					GetSite().SetAnimated( NULL );

		return;
	// case ID_TIMER_ANIMATION
	default:
		__BaseClassOfCExtPopupBaseWnd::OnTimer(nIDEvent);
	break; // default
	} // switch( nIDEvent )
}

int CExtPopupBaseWnd::OnMouseActivate(CWnd* pDesktopWnd, UINT nHitTest, UINT message) 
{
	ASSERT_VALID( this );

	pDesktopWnd;
	nHitTest;
	message;
	return MA_NOACTIVATE;
	//return CExtPopupBaseWnd::OnMouseActivate(pDesktopWnd, nHitTest, message);
}

BOOL CExtPopupBaseWnd::OnEraseBkgnd(CDC* pDC) 
{
	ASSERT_VALID( this );

	pDC;
	return TRUE;
}

void CExtPopupBaseWnd::OnNcPaint() 
{
	ASSERT_VALID( this );

	// TODO: Add your message handler code here
	// Do not call __BaseClassOfCExtPopupBaseWnd::OnNcPaint() for painting messages
}

void CExtPopupBaseWnd::OnNcCalcSize(BOOL bCalcValidRects, NCCALCSIZE_PARAMS FAR* lpncsp) 
{
	ASSERT_VALID( this );

	bCalcValidRects;
	lpncsp;
///	__BaseClassOfCExtPopupBaseWnd::OnNcCalcSize(bCalcValidRects, lpncsp);
}

void CExtPopupBaseWnd::OnSize(UINT nType, int cx, int cy) 
{
	ASSERT_VALID( this );

	__BaseClassOfCExtPopupBaseWnd::OnSize(nType, cx, cy);
	Invalidate(FALSE);
}

BOOL CExtPopupBaseWnd::DestroyWindow()
{
	ASSERT_VALID( this );

	if( !(::IsWindow(GetSafeHwnd())) )
		return TRUE;
	return __BaseClassOfCExtPopupBaseWnd::DestroyWindow();
}

void CExtPopupBaseWnd::PostNcDestroy() 
{
	ASSERT_VALID( this );
}

void CExtPopupMenuWnd::PostNcDestroy() 
{
	ASSERT_VALID( this );
	if( m_bTopLevel )
	{
		ASSERT( m_hWndCmdReciever != NULL );
		if( ::IsWindow(m_hWndCmdReciever) )
			::SendMessage(
				m_hWndCmdReciever,
				g_nMsgNotifyMenuClosed,
				0,
				LPARAM( this )
				);
		CExtPopupMenuSite & _site = GetSite();
		ASSERT( !_site.IsEmpty() );
		if( //!_site.IsEmpty() &&
			!_site.IsShutdownMode()
			)
		{
			_site.DoneInstance();
			ASSERT( _site.IsEmpty() );
			ASSERT( !_site.IsShutdownMode() );
		}
	} // if( m_bTopLevel )
}

BOOL CExtPopupBaseWnd::OnSetCursor(CWnd* pWnd, UINT nHitTest, UINT message) 
{
	ASSERT_VALID( this );

	return __BaseClassOfCExtPopupBaseWnd::OnSetCursor(pWnd, nHitTest, message);
}

/////////////////////////////////////////////////////////////////////////////
// CExtPopupMenuTipWnd

IMPLEMENT_DYNCREATE(CExtPopupMenuTipWnd, CExtPopupBaseWnd)

CExtPopupMenuTipWnd::CExtPopupMenuTipWnd()
{
	m_hIcon = NULL;
	m_IconSize.cx = m_IconSize.cy = 0;
	m_sText = _T("");
	m_bFlipHorz = false;
	m_bFlipVert = false;

	m_hIcon = ::LoadIcon(NULL,IDI_INFORMATION);
	m_IconSize.cx = m_IconSize.cy = 16;

	m_bAnimFinished = true;
	m_AnimationType = __AT_NONE;
}

CExtPopupMenuTipWnd::~CExtPopupMenuTipWnd()
{
}

BEGIN_MESSAGE_MAP(CExtPopupMenuTipWnd, CExtPopupBaseWnd)
	//{{AFX_MSG_MAP(CExtPopupMenuTipWnd)
	//}}AFX_MSG_MAP
END_MESSAGE_MAP()

#define CX_ROUNDED				12		// Tip horizontal roundness
#define CY_ROUNDED				10		// Tip vertical roundness
#define CX_LEADER				25		// Width of tip lead
#define CY_LEADER				25		// Height of tip lead
#define CX_ICON_MARGIN			5		// Width of margin between icon and tip text

#define __TIP_OVER_METRIC 12

bool CExtPopupMenuTipWnd::GetWindowRegion(
	CDC* pDC,
	HRGN* hRegion,
	CSize *Size /* = NULL */
	)
{
	ASSERT_VALID( this );

CRect	rcWnd(0,0,0,0);
POINT	ptLeader[3];
CRgn	LeaderRegion;
CRgn	CaptionRegion;
CFont	*pSysFont;
	
	ASSERT( pDC != NULL );
	ASSERT( hRegion != NULL );

	// Calculate the are for the tip text
	pSysFont =
		(CFont *)pDC->SelectObject(
			&(g_PaintManager->m_FontNormal)
			);
	pDC->DrawText(m_sText, &rcWnd, DT_CALCRECT);
	//if( pSysFont != NULL )
		pDC->SelectObject(pSysFont);

	// Adjust for the rounded corners
	rcWnd.InflateRect(CX_ROUNDED, CY_ROUNDED);

	// Adjust for icon
	if (m_hIcon != NULL)
		rcWnd.right = rcWnd.right + m_IconSize.cx + CX_ICON_MARGIN;
	if (rcWnd.Height() < m_IconSize.cy)
		rcWnd.bottom = rcWnd.top + m_IconSize.cy;

	// Calculate the leader triangle coordinates

	ptLeader[0].x = rcWnd.Width() - CX_ROUNDED;
	ptLeader[0].y = rcWnd.Height() - CY_ROUNDED;

	ptLeader[1].x = ptLeader[0].x;
	ptLeader[1].y = ptLeader[0].y + CY_LEADER;

	ptLeader[2].x = ptLeader[0].x - CX_LEADER;
	ptLeader[2].y = rcWnd.Height() - CY_ROUNDED;

CRect rcRoundRectRgn(CPoint(0,0),rcWnd.Size());
CRect rcRectRgn( 0, 0, rcWnd.Width(), rcWnd.Height() + CY_LEADER );
	m_bFlipHorz = false;
	m_bFlipVert = false;

CRect rcDesktop = _CalcDesktopRect();

	if( m_ptTrack.x - rcWnd.Width() < rcDesktop.left )
	{
		m_bFlipHorz = true;
		ptLeader[0].x = CX_ROUNDED;
		ptLeader[0].y = rcWnd.Height() - CY_ROUNDED;
		ptLeader[1].x = ptLeader[0].x;
		ptLeader[1].y = ptLeader[0].y + CY_LEADER;
		ptLeader[2].x = ptLeader[0].x + CX_LEADER;
		ptLeader[2].y = ptLeader[0].y;
	}

	if( m_ptTrack.y - rcWnd.Height() - CY_ROUNDED*2 < rcDesktop.top )
	{
		m_bFlipVert = true;
		ptLeader[0].y -= rcWnd.Height() - CY_ROUNDED*2;
		ptLeader[1].y = ptLeader[0].y - CY_LEADER;
		ptLeader[2].y -= ptLeader[0].y;
	}

	// Create the caption region
	CaptionRegion.CreateRoundRectRgn(
		rcRoundRectRgn.left,rcRoundRectRgn.top,rcRoundRectRgn.right,rcRoundRectRgn.bottom,
		CX_ROUNDED, CY_ROUNDED
		);
	// Create the leader region
	LeaderRegion.CreatePolygonRgn(ptLeader, 3, ALTERNATE);
	// Create window region
	*hRegion =  ::CreateRectRgn(
		rcRectRgn.left,rcRectRgn.top,rcRectRgn.right,rcRectRgn.bottom
		);
	// Combine the regions
	CombineRgn(*hRegion, CaptionRegion.operator HRGN(), LeaderRegion.operator HRGN(), RGN_OR);

	if( m_bFlipVert )
		OffsetRgn(*hRegion,0,CY_LEADER);

	// Set the window size
	if (Size != NULL)
	{
		Size->cx	= rcWnd.Width();
		Size->cy	= rcWnd.Height() + CY_LEADER;
	}

	return true;
}

void CExtPopupMenuTipWnd::_DoPaint( CDC & dcPaint, bool bUseBackBuffer /*= true*/ )
{
	ASSERT_VALID( this );

	bUseBackBuffer;
CDC & dc = dcPaint;

CRect	rc;
CBrush	WindowBrush;
CBrush	FrameBrush;
CBrush	InnerFrameBrush;
HRGN	hRegion;
CRgn	*pRegion;
CFont	*pSysFont;

	// Get the client rectangle
	GetClientRect(rc);

	// Create the brushes
	InnerFrameBrush.CreateSolidBrush(
		//::GetSysColor(COLOR_SCROLLBAR)
		g_PaintManager->GetColor(COLOR_3DFACE)
		);
	FrameBrush.CreateSolidBrush(
		//::GetSysColor(COLOR_WINDOWTEXT)
		g_PaintManager->GetColor(COLOR_3DDKSHADOW)
		);
	WindowBrush.CreateSolidBrush(
		//::GetSysColor(COLOR_WINDOW)
		g_PaintManager->GetColor(COLOR_INFOBK)
		);

	// Get the window region
	hRegion = CreateRectRgnIndirect(&rc);
	GetWindowRgn(hRegion);
	pRegion = CRgn::FromHandle(hRegion);

	// Draw the frame
	dc.FillRgn(pRegion, &WindowBrush);
	dc.FrameRgn(pRegion, &InnerFrameBrush, 3, 3);
	dc.FrameRgn(pRegion, &FrameBrush, 1, 1);

	// Adjust the area for the icon
	rc.DeflateRect(CX_ROUNDED, CY_ROUNDED, 0, 0);
	if( m_hIcon != NULL )
		rc.left += m_IconSize.cx + CX_ICON_MARGIN;
	
	// Set the font
	pSysFont = (CFont *)dc.SelectObject(
		&(g_PaintManager->m_FontNormal)
		);
	// Draw the tip text	
	dc.SetBkMode( TRANSPARENT );

int nIconVertPos = CY_ROUNDED;
	if( m_bFlipVert )
	{
		rc.OffsetRect(0,CY_LEADER);
		nIconVertPos += CY_LEADER;
	}

COLORREF clrOltTextColor =
		dc.SetTextColor(
			g_PaintManager->GetColor(COLOR_INFOTEXT)
			);
	dc.DrawText( m_sText, &rc, DT_TOP | DT_LEFT );
	dc.SetTextColor( clrOltTextColor );

	// Draw the icon
	if( m_hIcon != NULL )
		DrawIconEx(
			dc.GetSafeHdc(),
			CX_ROUNDED,
			nIconVertPos,
			m_hIcon,
			m_IconSize.cx,
			m_IconSize.cy,
			0,
			NULL,
			DI_NORMAL
			);

	// Clean up GDI
	::DeleteObject(hRegion);
	//if( pSysFont != NULL )
		dc.SelectObject(pSysFont);
}

void CExtPopupMenuTipWnd::SetText(LPCTSTR lpszText)
{
	ASSERT_VALID( this );

	m_sText = (lpszText==NULL) ? _T("") : lpszText;
	m_sText.TrimLeft();
	m_sText.TrimRight();
}

void CExtPopupMenuTipWnd::SetIcon(HICON hIcon) 
{
	ASSERT_VALID( this );

ICONINFO IconInfo;
	m_hIcon = hIcon; 
	if( hIcon == NULL )
	{
		m_IconSize = CSize( 0, 0 );
		return;
	}
	
	// Get the icon sizes	
	ZeroMemory( &IconInfo, sizeof(ICONINFO) );
	::GetIconInfo(m_hIcon, &IconInfo);

	m_IconSize.cx = (BYTE)(IconInfo.xHotspot * 2);
	m_IconSize.cy = (BYTE)(IconInfo.yHotspot * 2);
    
	::DeleteObject(IconInfo.hbmMask);
	::DeleteObject(IconInfo.hbmColor);

	if( ::IsWindow(m_hWnd) )
		RedrawWindow();
}

bool CExtPopupMenuTipWnd::Show(
	CWnd * pWndParent,
	const RECT & rcExcludeArea // = CExtPopupMenuTipWnd::rcNoExcludeArea
	)
{
	ASSERT_VALID( this );

	ASSERT_VALID( pWndParent );
	ASSERT( pWndParent->GetSafeHwnd() != NULL );

HCURSOR hCursor = ::LoadCursor(NULL, IDC_ARROW);
	ASSERT( hCursor != NULL );

	if( GetSafeHwnd() == NULL )
	{
		CString strClassName =
			::AfxRegisterWndClass (
				__POPUP_WNDCLASS_STYLES__,
				hCursor,
				(HBRUSH)(COLOR_BTNFACE + 1),
				NULL
				);
		BOOL bCreateResult =
			CWnd::CreateEx(
				WS_EX_TOPMOST, // 0,
				(LPCTSTR)strClassName,
				NULL,
				WS_POPUP,
				0, 0, 0, 0,
				pWndParent->GetSafeHwnd(),
				NULL,
				NULL
				);
		ASSERT( bCreateResult );
		if( !bCreateResult )
			return false;
	} // if( GetSafeHwnd() == NULL )
#ifdef _DEBUG
	else
	{
		ASSERT_VALID( pWndParent );
		ASSERT( ::IsWindow( pWndParent->GetSafeHwnd() ) );
//		CWnd * pExistingParent = GetParent();
//		ASSERT( pWndParent == pExistingParent );
	} // else from if( GetSafeHwnd() == NULL )
#endif // _DEBUG

	ASSERT_VALID( this );

	m_rcExcludeArea = rcExcludeArea;
	m_rcExcludeArea.NormalizeRect();
CPoint ptTipTarget( m_rcExcludeArea.TopLeft() );
	ptTipTarget += CSize( __TIP_OVER_METRIC/2, __TIP_OVER_METRIC/2 );
	m_ptTrack = ptTipTarget;

CDC * pDC = GetDC();
	ASSERT_VALID( pDC );
HRGN	hRegion;
CSize WindowSize;
	VERIFY( GetWindowRegion(pDC, &hRegion, &WindowSize) );
	ReleaseDC(pDC);
	VERIFY(
		::SetWindowRgn(
			m_hWnd,
			hRegion,
			TRUE
			)
		);

	if( m_bFlipHorz )
		m_ptTrack.x +=
			m_rcExcludeArea.Width() - __TIP_OVER_METRIC
			+ WindowSize.cx - CX_ROUNDED*2
			;
	if( m_bFlipVert )
		m_ptTrack.y += 
			m_rcExcludeArea.Height() - __TIP_OVER_METRIC
			+ WindowSize.cy - CX_ROUNDED*2
			;

CPoint ptWndPos(
		m_ptTrack.x - WindowSize.cx + CX_ROUNDED,
		m_ptTrack.y - WindowSize.cy + CY_ROUNDED
		);
	SetWindowPos(
		&wndTop,
		ptWndPos.x,
		ptWndPos.y,
		WindowSize.cx,
		WindowSize.cy,
		SWP_NOACTIVATE //| SWP_SHOWWINDOW
		);
CRect rcWnd(ptWndPos,WindowSize);
	MoveWindow(&rcWnd);
//	ASSERT( IsWindowVisible() );
	::SetCursor(hCursor);

//	Invalidate( FALSE );
//	UpdateWindow();
	SetTimer( ID_TIMER_DELAY_SHOW, ID_PERIOD_DELAY_SHOW, NULL );

	return true;
}

void CExtPopupMenuTipWnd::Hide()
{
	ASSERT_VALID( this );

	if( GetSafeHwnd() != NULL )
	{
		KillTimer( ID_TIMER_DELAY_SHOW );
		ShowWindow( SW_HIDE );
//VERIFY( DestroyWindow() );
	}
	m_rcExcludeArea.SetRectEmpty();
}

/////////////////////////////////////////////////////////////////////////////
// CExtPopupMenuWnd

// is allowed menu item positioning without
// using only & - marked text
bool CExtPopupMenuWnd::g_bAllowNonAccelPositioning = false;

IMPLEMENT_DYNCREATE(CExtPopupMenuWnd, CExtPopupBaseWnd)

CExtPopupMenuWnd::CExtPopupMenuWnd()
	: m_pWndParentMenu( NULL )
	, m_hWndCmdReciever( m_hWndCmdReciever )
	, m_nLeftAreaWidth( 0 )
{
	__VPC_INC;
	_Init();
}

CExtPopupMenuWnd::~CExtPopupMenuWnd()
{
	_OnCancelMode( true );
	if( m_bTopLevel )
	{
		VERIFY( _BuildItems( NULL, true ) );
	}
	__VPC_DEC;
#ifdef _DEBUG
	if( m_bTopLevel )
	{
		__VPC_VERIFY_0;
	}
#endif // _DEBUG
}

void CExtPopupMenuWnd::_Init()
{
	ASSERT_VALID( this );

	_InitAnimation();

	m_nDyScrollOffset = 0;
	m_bTopLevel
		= m_bScrollingAvailable
		= m_bExpandAvailable
		= m_bExpandWasPressed
		= m_bCombineWithEA 
		= false;
	m_dwTrackFlags = 0;
	m_nWaitingExpandTickCount = 0;
	m_nCurIndex
		= m_nDelayedFocusItemIndex
		= IDX_NOTHING;

	m_nScrollingDirection = 0;
	m_rcScrollTop.SetRectEmpty();
	m_rcScrollBottom.SetRectEmpty();
	m_rcExpandBtn.SetRectEmpty();

	m_eCombineAlign = __CMBA_NONE;

	m_pCbPaintCombinedCookie = NULL;
	m_pCbPaintCombinedContent = NULL;
}

int CExtPopupMenuWnd::_GetCurIndex() const
{
	ASSERT_VALID( this );

	return m_nCurIndex;
}

int CExtPopupMenuWnd::_GetSpecBtnHeight()
{
int nHeight = ::GetSystemMetrics(SM_CYMENUCHECK);
	return nHeight;
}

void CExtPopupMenuWnd::_RecalcLayoutImpl()
{
	ASSERT_VALID( this );

CRect rcClient;
	_GetClientRect( &rcClient );
int nScrollBtnDy =
		_GetSpecBtnHeight();
int nMenuBorderSize =
		g_PaintManager->GetMenuBorderSize();
int nMenuShadowSize = 0;
//		_GetMenuShadowSize();

int nScrollBottomOffsetDy = 0;
	if( m_bExpandAvailable )
	{
		m_rcExpandBtn.left =
			rcClient.left + nMenuBorderSize;
		m_rcExpandBtn.right =
			rcClient.right - (nMenuBorderSize + nMenuShadowSize);
		m_rcExpandBtn.bottom =
			rcClient.bottom - (nMenuBorderSize + nMenuShadowSize);
		m_rcExpandBtn.top =
			m_rcExpandBtn.bottom - nScrollBtnDy;
		nScrollBottomOffsetDy =
			- m_rcExpandBtn.Height();
		m_rcExpandBtn.DeflateRect(
			__MI_HORZ_GAP_TO_BORDER,
			0
			);
		m_rcExpandBtn.left += m_nLeftAreaWidth;
	} // if( m_bExpandAvailable )

	if( m_bScrollingAvailable )
	{
		m_rcScrollTop.left = m_rcScrollBottom.left =
			rcClient.left + nMenuBorderSize;
		m_rcScrollTop.right = m_rcScrollBottom.right =
			rcClient.right - (nMenuBorderSize + nMenuShadowSize);

		m_rcScrollTop.top =
			rcClient.top + nMenuBorderSize;
		m_rcScrollTop.bottom =
			m_rcScrollTop.top + nScrollBtnDy;
		
		m_rcScrollBottom.bottom =
			rcClient.bottom - (nMenuBorderSize + nMenuShadowSize);
		m_rcScrollBottom.top =
			m_rcScrollBottom.bottom - nScrollBtnDy;

		m_rcScrollBottom.OffsetRect(0,nScrollBottomOffsetDy);
		m_rcScrollTop.DeflateRect(
			__MI_HORZ_GAP_TO_BORDER,
			0
			);
		m_rcScrollBottom.DeflateRect(
			__MI_HORZ_GAP_TO_BORDER,
			0
			);
		m_rcScrollTop.left += m_nLeftAreaWidth;
		m_rcScrollBottom.left += m_nLeftAreaWidth;
	} // if( m_bScrollingAvailable )

}

class CExtPopupMenuWnd::CExtPopupMenuCmdUI : public CCmdUI
{
public: // re-implementations only
	CExtPopupMenuWnd * m_pPopup;

	virtual void Enable(BOOL bOn)
	{
		m_bEnableChanged = TRUE;
		ASSERT( m_pPopup != NULL );
		ASSERT(
			::AfxIsValidAddress(
				m_pPopup,
				sizeof(CExtPopupMenuWnd)
				)
			);
		ASSERT_VALID( m_pPopup );
		ASSERT( m_nIndex >= 0 && INT(m_nIndex) < m_pPopup->ItemGetCount() );
		CExtPopupMenuWnd::MENUITEMDATA & mi =
			m_pPopup->_GetItemRef(m_nIndex);
		if( mi.IsPopup() )
			return;
		ASSERT( m_pPopup != NULL );
		CExtCmdManager::cmd_t * p_cmd =
			g_CmdManager->CmdGetPtr(
				g_CmdManager->ProfileNameFromWnd( mi.GetCmdReciever() ),
				mi.GetCmdID()
				);
		if( p_cmd == NULL )
			return;
		p_cmd->StateEnable( bOn ? true : false );
	};

	virtual void SetRadio(BOOL bOn)
	{
		ASSERT( m_pPopup != NULL );
		ASSERT(
			::AfxIsValidAddress(
				m_pPopup,
				sizeof(CExtPopupMenuWnd)
				)
			);
		ASSERT_VALID( m_pPopup );
		ASSERT( m_nIndex >= 0 && INT(m_nIndex) < m_pPopup->ItemGetCount() );
		CExtPopupMenuWnd::MENUITEMDATA & mi =
			m_pPopup->_GetItemRef(m_nIndex);
		if( mi.IsPopup() )
			return;
		CExtCmdManager::cmd_t * p_cmd =
			g_CmdManager->CmdGetPtr(
				g_CmdManager->ProfileNameFromWnd( mi.GetCmdReciever() ),
				mi.GetCmdID()
				);
		if( p_cmd == NULL )
			return;
		p_cmd->StateSetRadio( bOn ? true : false );
	};

	virtual void SetCheck(int nCheck)
	{
		ASSERT( m_pPopup != NULL );
		ASSERT(
			::AfxIsValidAddress(
				m_pPopup,
				sizeof(CExtPopupMenuWnd)
				)
			);
		ASSERT_VALID( m_pPopup );
		ASSERT( m_nIndex >= 0 && INT(m_nIndex) < m_pPopup->ItemGetCount() );
		CExtPopupMenuWnd::MENUITEMDATA & mi =
			m_pPopup->_GetItemRef(m_nIndex);
		if( mi.IsPopup() )
			return;
		CExtCmdManager::cmd_t * p_cmd =
			g_CmdManager->CmdGetPtr(
				g_CmdManager->ProfileNameFromWnd( mi.GetCmdReciever() ),
				mi.GetCmdID()
				);
		if( p_cmd == NULL )
			return;
		p_cmd->StateSetCheck( nCheck ? true : false );
	};

	virtual void SetText(LPCTSTR lpszText)
	{
		if( lpszText == NULL )
			return;
		ASSERT( m_pPopup != NULL );
		ASSERT(
			::AfxIsValidAddress(
				m_pPopup,
				sizeof(CExtPopupMenuWnd)
				)
			);
		ASSERT_VALID( m_pPopup );
		ASSERT( m_nIndex >= 0 && INT(m_nIndex) < m_pPopup->ItemGetCount() );
		CExtPopupMenuWnd::MENUITEMDATA & mi =
			m_pPopup->_GetItemRef(m_nIndex);
		if( mi.IsPopup() )
			return;
		CExtCmdManager::cmd_t * p_cmd =
			g_CmdManager->CmdGetPtr(
				g_CmdManager->ProfileNameFromWnd( mi.GetCmdReciever() ),
				mi.GetCmdID()
				);
		if( p_cmd == NULL )
			return;
		p_cmd->m_sMenuText = lpszText;
	};

}; // class CExtPopupMenuWnd::CExtPopupMenuCmdUI

void CExtPopupMenuWnd::_UpdateCmdUI()
{
	ASSERT_VALID( this );

	if( m_bTopLevel )
		if( (m_dwTrackFlags&TPMX_NO_CMD_UI) != 0 )
			return;

INT iter = 0;

BOOL bDisableIfNoHndler = TRUE;
CExtPopupMenuCmdUI state;
	state.m_pPopup = this;
	state.m_pOther = NULL; // menu
	state.m_nIndexMax = (UINT)ItemGetCount();
	state.m_nIndex = 0;

	for( ; iter < m_items_all.GetSize(); iter++, state.m_nIndex++ )
	{
		MENUITEMDATA & mi = m_items_all[ iter ];
		if( mi.IsSeparator() )
			continue;
		if( mi.IsPopup() )
		{
			mi.GetPopup()->_UpdateCmdUI();
			continue;
		}
		if(	CExtCmdManager::IsCommandNeedsSpecUpdate(
				mi.GetCmdID() )
			)
			continue;
		HWND hWndCmdReciever =
			mi.GetCmdReciever();
		ASSERT( hWndCmdReciever != NULL );
		ASSERT( ::IsWindow(hWndCmdReciever) );
		CWnd * pWndCmdReciever =
			CWnd::FromHandle( hWndCmdReciever );
		ASSERT_VALID( pWndCmdReciever );
		state.m_nID = mi.GetCmdID();
		state.DoUpdate(pWndCmdReciever, bDisableIfNoHndler);
	} // for( ; iter < m_items_all.GetSize(); iter++, state.m_nIndex++ )
}

bool CExtPopupMenuWnd::MENUITEMDATA::ConstructPopup()
{
	ASSERT( m_hIconPopup == NULL );
	ASSERT( m_pWndChild == NULL );
	m_pWndChild = new CExtPopupMenuWnd;
	
	ASSERT( m_hWndSpecCmdReciever != NULL );
	ASSERT( ::IsWindow(m_hWndSpecCmdReciever) );
	m_pWndChild->m_hWndCmdReciever = m_hWndSpecCmdReciever;
	
	return true;
}

void CExtPopupMenuWnd::MENUITEMDATA::DestroyPopup()
{
	VERIFY( SetPopupIcon(NULL) );
	if( m_pWndChild == NULL )
		return;
	if( m_pWndChild->GetSafeHwnd() != NULL
		&& ::IsWindow( m_pWndChild->GetSafeHwnd() )
		)
		m_pWndChild->DestroyWindow();
//	else
//		delete m_pWndChild;
	delete m_pWndChild;
	m_pWndChild = NULL;
}

bool CExtPopupMenuWnd::_BuildItems(
	CMenu * pBuildMenu,
	bool bTopLevel
	)
{
	ASSERT_VALID( this );
#ifdef _DEBUG
	if( pBuildMenu != NULL )
	{
		ASSERT( m_hWndCmdReciever != NULL );
		ASSERT( ::IsWindow(m_hWndCmdReciever) );
	}
#endif // _DEBUG
INT iter = 0;
	for( ; iter < m_items_all.GetSize(); iter++)
	{
		MENUITEMDATA & mi = m_items_all[ iter ];
		if( mi.IsPopup() )
		{
			mi.GetPopup()->m_hWndCmdReciever = m_hWndCmdReciever;
			mi.GetPopup()->_OnCancelMode();
			VERIFY( mi.GetPopup()->_BuildItems( NULL, false ) );
			mi.DestroyPopup();
		}
	} // for( ; iter < m_items_all.GetSize(); iter++)
	m_items_all.RemoveAll();

	if( pBuildMenu == NULL )
		return true;
	ASSERT( pBuildMenu->GetSafeHmenu() != NULL );

	m_bTopLevel = bTopLevel;
	if( m_bTopLevel )
		m_pWndParentMenu = NULL;

	// build items loop
bool bPrevWasSeparator = false;
int nMruUpdateIndex = -1, nInsertedIndex = 0;
int	nMenuItemCount = pBuildMenu->GetMenuItemCount();
	ASSERT( nMenuItemCount > 0 );
	m_items_all.RemoveAll();
	for( int nItemIndex=0; nItemIndex<nMenuItemCount; nItemIndex++ )
	{
		UINT nMenuItemID =
			pBuildMenu->GetMenuItemID( nItemIndex );
		if( ID_FILE_MRU_FIRST <= nMenuItemID
			&&
			nMenuItemID <= ID_FILE_MRU_LAST
			)
		{
			if( nMruUpdateIndex < 0 )
				nMruUpdateIndex = nInsertedIndex;
			continue;
		}
		MENUITEMDATA mi;
		mi.SetCmdReciever( m_hWndCmdReciever );
		VERIFY(
			mi.UpdateFromMenu(
				m_hWndCmdReciever,
				pBuildMenu,
				nItemIndex
				)
			);
		bool bIsSeparator = mi.IsSeparator();
		if( bPrevWasSeparator && bIsSeparator )
				continue;
		bPrevWasSeparator = bIsSeparator;
		
		if( mi.IsPopup() )
		{
			CMenu * pSubMenu =
					pBuildMenu->GetSubMenu(nItemIndex);
			ASSERT( pSubMenu != NULL );
			ASSERT( pSubMenu->GetSafeHmenu() != NULL );
			mi.GetPopup()->m_hWndCmdReciever = m_hWndCmdReciever;
			mi.GetPopup()->_BuildItems( pSubMenu, false );
			mi.GetPopup()->m_pWndParentMenu = this;
		}
		_InsertItem( -1, mi );
		nInsertedIndex++;
	} // for( int nItemIndex=0; nItemIndex<nMenuItemCount; nItemIndex++ )
	ASSERT( m_items_all.GetSize() <= nMenuItemCount );

int nMruInsertCount = 0;
	if( nMruUpdateIndex >= 0 )
	{ // insert recently opened file items
		ASSERT( nMruUpdateIndex < nMenuItemCount );
		CRecentFileList * pRecentFileList =
			InternalFriendlyWinApp::_GetFriendlyApp()->
				_GetRecentFileList();
		if( pRecentFileList != NULL )
		{ // can be null !?
			int nRecentCount =
				pRecentFileList->GetSize();
			TCHAR sCurrDir[_MAX_PATH+1];
			::memset(sCurrDir,0,sizeof(sCurrDir));
			::GetCurrentDirectory(_MAX_PATH,sCurrDir);
			int nLenCurDir = _tcslen(sCurrDir);
			for( nItemIndex=0; nItemIndex<nRecentCount; nItemIndex++ )
			{
				CString sDisplayName( _T("") );
				if(	!pRecentFileList->GetDisplayName(
						sDisplayName,
						nItemIndex,
						sCurrDir,
						nLenCurDir,
						TRUE
						)
					)
					continue;
				ASSERT( !sDisplayName.IsEmpty() );
				UINT nCmdID = ID_FILE_MRU_FIRST + nItemIndex;
				ASSERT( nCmdID <= ID_FILE_MRU_LAST );
				CExtCmdManager::cmd_t * p_cmd =
					g_CmdManager->CmdGetPtr(
						g_CmdManager->ProfileNameFromWnd( m_hWndCmdReciever ),
						nCmdID
						);
				if( p_cmd == NULL )
					p_cmd =
						g_CmdManager->CmdAllocPtr(
							g_CmdManager->ProfileNameFromWnd( m_hWndCmdReciever ),
							nCmdID
							);
				ASSERT( p_cmd != NULL );
				if( p_cmd == NULL )
					return false;
				int nDisplayIndex = nItemIndex+1;
				if( nDisplayIndex < 10 )
					p_cmd->m_sMenuText.Format(
						_T("&%d %s"),
						nDisplayIndex,
						(LPCTSTR)sDisplayName
						);
				else
					p_cmd->m_sMenuText.Format(
						_T("%d&%d %s"),
						nDisplayIndex/10,
						nDisplayIndex%10,
						(LPCTSTR)sDisplayName
						);
				
#if (defined _AFXDLL && !defined __STATPROFUIS_WITH_DLLMFC__)
				CExtLocalResourceHelper _LRH;
#endif // #if (defined _AFXDLL && !defined __STATPROFUIS_WITH_DLLMFC__)
				
				CString sRecentFileFmt1,sRecentFileFmt2;
				if( !sRecentFileFmt1.LoadString(IDS_RECENT_FILE_FMT_1) )
				{
#if (defined _AFXDLL && !defined __STATPROFUIS_WITH_DLLMFC__)
					ASSERT( FALSE );
#endif // #if (defined _AFXDLL && !defined __STATPROFUIS_WITH_DLLMFC__)
					sRecentFileFmt1 = _T("Recent file %d");
				}
				if( !sRecentFileFmt2.LoadString(IDS_RECENT_FILE_FMT_2) )
				{
#if (defined _AFXDLL && !defined __STATPROFUIS_WITH_DLLMFC__)
					ASSERT( FALSE );
#endif // #if (defined _AFXDLL && !defined __STATPROFUIS_WITH_DLLMFC__)
					sRecentFileFmt2 = _T("Recent file %d (\"%s\")");
				}
				p_cmd->m_sToolbarText.Format(
					sRecentFileFmt1,
					nItemIndex + 1
					);
				p_cmd->m_sTipTool.Format(
					sRecentFileFmt2,
					nItemIndex + 1,
					(LPCTSTR)sDisplayName
					);
				p_cmd->m_sTipStatus = p_cmd->m_sTipTool;

				BOOL bInsRetVal =
					ItemInsert(
						nCmdID,
						nMruUpdateIndex + nItemIndex
						);
				
				if( !bInsRetVal )
				{
					ASSERT( FALSE );
					return false;
				}
				nMruInsertCount++;
			} // for( nItemIndex=0; nItemIndex<nRecentCount; nItemIndex++ )
		} // can be null !?
		if( nMruInsertCount > 0 )
		{
			if( !ItemInsert(
					ID_SEPARATOR,
					nMruUpdateIndex + nMruInsertCount
					)
				)
			{
				ASSERT( FALSE );
				return false;
			}
			nMruInsertCount++;
		} // if( nMruInsertCount > 0 )
	} // insert recently opened file items

	_SyncItems();
	return true;
}

void CExtPopupMenuWnd::_GetClientRect(RECT * pRectClient)
{
	ASSERT_VALID( this );

	ASSERT( pRectClient != NULL );
	ASSERT( GetSafeHwnd() != NULL );

	*pRectClient = m_rcClient;

	ASSERT( pRectClient->top <= pRectClient->bottom );
	ASSERT( pRectClient->left <= pRectClient->right );
}

int CExtPopupMenuWnd::_HitTest(const CPoint & point )
{
	ASSERT_VALID( this );

	if( GetSafeHwnd() == NULL )
		return IDX_NOTHING;

CRect rcClient;
	_GetClientRect( &rcClient );
	if( !rcClient.PtInRect(point) )
		return IDX_NOTHING;

	if( m_bScrollingAvailable )
	{
		CRect rcItem;
		if( m_nDyScrollOffset != 0 )
		{
			_GetItemRect(IDX_SCROLL_TOP,rcItem);
			if( rcItem.PtInRect(point) )
				return IDX_SCROLL_TOP;
		}
		int nMaxScrollPos = _GetMaxScrollPos();
		if( m_nDyScrollOffset != nMaxScrollPos )
		{
			_GetItemRect(IDX_SCROLL_BOTTOM,rcItem);
			if( rcItem.PtInRect(point) )
				return IDX_SCROLL_BOTTOM;
		}
	}
	if( m_bExpandAvailable )
	{
		CRect rcExpand;
		_GetItemRect(IDX_EXPAND,rcExpand);
		if( rcExpand.PtInRect(point) )
			return IDX_EXPAND;
	}

//int nMenuBorderSize =
//		g_PaintManager->GetMenuBorderSize();

//int y = m_nDyScrollOffset + nMenuBorderSize;

INT iter = 0;
int nIndex = 0;
	for( ; iter < m_items_all.GetSize(); iter++,nIndex++ )
	{
		MENUITEMDATA & mi = m_items_all[ iter ];
		if( !mi.IsDisplayed() )
			continue;

		CRect rcItem;
		_GetItemRect( nIndex, rcItem );
		if( rcItem.PtInRect(point) )
		{
			int nRetIndex = mi.GetIndex();
			ASSERT(
				nRetIndex >= 0
				&&
				nRetIndex < m_items_all.GetSize()
				);
			return nRetIndex;
		}
	} // for( ; iter < m_items_all.GetSize(); iter++,nIndex++ )
	return IDX_NOTHING;
};


BEGIN_MESSAGE_MAP(CExtPopupMenuWnd, CExtPopupBaseWnd)
	//{{AFX_MSG_MAP(CExtPopupMenuWnd)
	ON_WM_ACTIVATEAPP()
	ON_WM_CANCELMODE()
	ON_WM_TIMER()
	//}}AFX_MSG_MAP
	ON_WM_MOUSEMOVE()
	ON_WM_LBUTTONDOWN()
	ON_WM_LBUTTONUP()
	ON_WM_LBUTTONDBLCLK()
	ON_WM_MBUTTONDOWN()
	ON_WM_MBUTTONUP()
	ON_WM_MBUTTONDBLCLK()
	ON_WM_RBUTTONDOWN()
	ON_WM_RBUTTONUP()
	ON_WM_RBUTTONDBLCLK()
	ON_WM_KEYDOWN()
	ON_WM_KEYUP()
	ON_WM_SYSKEYDOWN()
	ON_WM_SYSKEYUP()
	ON_WM_SYSDEADCHAR()
	ON_WM_CHAR()
END_MESSAGE_MAP()

/////////////////////////////////////////////////////////////////////////////
// CExtPopupMenuWnd message handlers

BOOL CExtPopupMenuWnd::LoadMenu( 
	HWND hWndCmdRecv,
	UINT nIDResource,
	bool bPopupMenu // = true
	)
{
	ASSERT_VALID( this );

CMenu menu;
	if( !menu.LoadMenu(nIDResource) )
	{
		ASSERT( FALSE );
		return FALSE;
	}
	return
		UpdateFromMenu(
			hWndCmdRecv,
			&menu,
			bPopupMenu
			);
}

BOOL CExtPopupMenuWnd::UpdateMdiWindowsMenu(
	CWnd * pWndStartSearchMdiFrameWnd // = NULL
	)
{
	ASSERT_VALID( this );

	ASSERT( m_hWndCmdReciever != NULL );
	ASSERT( ::IsWindow(m_hWndCmdReciever) );
CMDIFrameWnd * pFrame = NULL;
CWnd * pWnd =
		(pWndStartSearchMdiFrameWnd != NULL)
			? pWndStartSearchMdiFrameWnd
			: FromHandle(m_hWndCmdReciever) // ::AfxGetMainWnd()
			;
	while( true )
	{
		ASSERT( pWnd != NULL );
		ASSERT_VALID( pWnd );
		pFrame =
			DYNAMIC_DOWNCAST(
				CMDIFrameWnd,
				pWnd
				);
		if( pFrame != NULL )
			break;
		pWnd = pWnd->GetParentFrame();
		if( pWnd == NULL )
			return FALSE;
	} // while( true )
	if( pFrame == NULL )
		return FALSE;
int nItemIndex = ItemGetCount();
	if( nItemIndex > 0 )
	{
		MENUITEMDATA & mi = _GetItemRef(nItemIndex-1);
		if( !mi.IsSeparator() )
		{
			ItemInsert(ID_SEPARATOR);
			nItemIndex++;
			ASSERT( nItemIndex == ItemGetCount() );
		}
	}

HWND m_hWndMDIClient = pFrame->m_hWndMDIClient;
	ASSERT( m_hWndMDIClient != NULL );
	ASSERT( ::IsWindow(m_hWndMDIClient) );
HWND hWndActiveChildFrame =
		(HWND)::SendMessage(
			m_hWndMDIClient,
			WM_MDIGETACTIVE,
			0,
			NULL
			);
int nCmdID = __ID_MDIWNDLIST_FIRST;
	for( int iWin=1; true; iWin++,nCmdID++ )
	{
		HWND hWndChildFrame =
			::GetDlgItem(m_hWndMDIClient, nCmdID);
		if( hWndChildFrame == NULL )
			break;

		if( iWin <= __ID_MDIWNDLIST_COUNT )
		{ // if head of MDI windows list
			ASSERT( ::IsWindow(hWndChildFrame) );
			CString sWinName( _T("") );
			CWnd::FromHandle(hWndChildFrame)->
				GetWindowText(sWinName);
			CExtCmdManager::cmd_t * p_cmd =
				g_CmdManager->CmdGetPtr(
					g_CmdManager->ProfileNameFromWnd( pWndStartSearchMdiFrameWnd->GetSafeHwnd() ),
					nCmdID
					);
			if( p_cmd == NULL )
				p_cmd =
				g_CmdManager->CmdAllocPtr(
					g_CmdManager->ProfileNameFromWnd( pWndStartSearchMdiFrameWnd->GetSafeHwnd() ),
					nCmdID
					);
			ASSERT( p_cmd != NULL );
			if( p_cmd == NULL )
				return FALSE;
			p_cmd->m_sMenuText.Format(
				_T("&%d %s"),
				iWin,
				(LPCTSTR)sWinName
				);
			p_cmd->m_sToolbarText = p_cmd->m_sMenuText;
			
#if (defined _AFXDLL && !defined __STATPROFUIS_WITH_DLLMFC__)
			CExtLocalResourceHelper _LRH;
#endif // #if (defined _AFXDLL && !defined __STATPROFUIS_WITH_DLLMFC__)
			
			CString sDocumentNameFmt;
			if( !sDocumentNameFmt.LoadString(IDS_DOCUMENT_NAME_FMT) )
			{
#if (defined _AFXDLL && !defined __STATPROFUIS_WITH_DLLMFC__)
				ASSERT( FALSE );
#endif // #if (defined _AFXDLL && !defined __STATPROFUIS_WITH_DLLMFC__)
				sDocumentNameFmt = _T("Document \"%s\"");
			}
			p_cmd->m_sTipTool.Format(
				sDocumentNameFmt,
				(LPCTSTR)sWinName
				);
			p_cmd->m_sTipStatus = p_cmd->m_sTipTool;
			p_cmd->StateSetRadio(
				(hWndChildFrame == hWndActiveChildFrame) ?
					true : false
				);
			if( !ItemInsert(nCmdID) )
			{
				ASSERT( FALSE );
				return FALSE;
			}
		} // if head of MDI windows list
		else
		{ // MDI windows list enough long, trim it
			if( !ItemInsert(TYPE_SEPARATOR) )
			{
				ASSERT( FALSE );
				return FALSE;
			}
			HWND hWndSearch = pWndStartSearchMdiFrameWnd->GetSafeHwnd();
			ASSERT( hWndSearch != NULL );
			ASSERT( ::IsWindow(hWndSearch) );
			CExtCmdManager::cmd_t * p_cmd =
				g_CmdManager->CmdGetPtr(
					g_CmdManager->ProfileNameFromWnd( hWndSearch ),
					__ID_MDIWND_DLGWINDOWS
					);
			if( p_cmd == NULL )
				p_cmd =
				g_CmdManager->CmdAllocPtr(
					g_CmdManager->ProfileNameFromWnd( hWndSearch ),
					__ID_MDIWND_DLGWINDOWS
					);
			ASSERT( p_cmd != NULL );
			if( p_cmd == NULL )
				return FALSE;
			
#if (defined _AFXDLL && !defined __STATPROFUIS_WITH_DLLMFC__)
			CExtLocalResourceHelper _LRH;
#endif // #if (defined _AFXDLL && !defined __STATPROFUIS_WITH_DLLMFC__)
			
			CString sMoreWindows,sManageWindows;
			if( !sMoreWindows.LoadString(IDS_MDI_MORE_WINDOWS) )
			{
#if (defined _AFXDLL && !defined __STATPROFUIS_WITH_DLLMFC__)
				ASSERT( FALSE );
#endif // #if (defined _AFXDLL && !defined __STATPROFUIS_WITH_DLLMFC__)
				sMoreWindows = _T("More Windows");
			}
			if( !sManageWindows.LoadString(IDS_MDI_MANAGE_OPENED_WINDOWS) )
			{
#if (defined _AFXDLL && !defined __STATPROFUIS_WITH_DLLMFC__)
				ASSERT( FALSE );
#endif // #if (defined _AFXDLL && !defined __STATPROFUIS_WITH_DLLMFC__)
				sManageWindows = _T("Manage opened document windows");
			}
			p_cmd->m_sMenuText = sMoreWindows;
			p_cmd->m_sToolbarText = p_cmd->m_sMenuText;
			p_cmd->m_sTipTool = sManageWindows;
			p_cmd->m_sTipStatus = p_cmd->m_sTipTool;
			if( !ItemInsert(nCmdID) )
			{
				ASSERT( FALSE );
				return FALSE;
			}
			break;
		} // MDI windows list enough long, trim it
	} // for( int iWin=1; true; iWin++,nCmdID++ )
	
	_SyncItems();
	return TRUE;
}

HMENU CExtPopupMenuWnd::ExportToMenu(
	BOOL bDeep // = TRUE
	) const
{
	ASSERT_VALID( this );

CMenu menu;
	if( !menu.CreatePopupMenu() )
	{
		ASSERT( FALSE );
		return NULL;
	}

OSVERSIONINFO ov;
    ov.dwOSVersionInfoSize = sizeof(OSVERSIONINFO);
	VERIFY( ::GetVersionEx( &ov ) );
bool bStupidNT4XX =
		(
		( ov.dwPlatformId == VER_PLATFORM_WIN32_NT )
		&&
		( ov.dwMajorVersion < 5 )
		);

int nCount = ItemGetCount();
	for( int nItem = 0; nItem < nCount; nItem++ )
	{
		const MENUITEMDATA & mi =
			_GetItemRef( nItem );

		if( mi.IsPopup() )
		{
			CString sMiText( mi.GetText() );
			CString sMiAccelText( mi.GetAccelText() );
			if( !sMiAccelText.IsEmpty() )
			{
				sMiText += _T("\t");
				sMiText += sMiAccelText;
			}
			const CExtPopupMenuWnd * pPopup = mi.GetPopup();
			ASSERT( pPopup != NULL );
			HMENU hPopupData;
			if( bDeep )
				hPopupData = pPopup->ExportToMenu();
			else
				hPopupData = ::CreatePopupMenu();
			if( ( ! (::IsMenu(hPopupData)) )
				||
				(!	menu.AppendMenu(
						MF_STRING|MF_POPUP,
						UINT(hPopupData),
						sMiText
						)
					)
				)
			{
				ASSERT( FALSE );
				//continue;
			}
			if( bStupidNT4XX )
			{
				VERIFY( ::DestroyMenu( hPopupData ) );
			}
			continue;
		} // if( mi.IsPopup() )

		if( mi.IsSeparator() )
		{
			VERIFY( menu.AppendMenu( MF_SEPARATOR ) );
			continue;
		} // if( mi.IsSeparator() )

		CString sMiText( mi.GetText() );
		CString sMiAccelText( mi.GetAccelText() );
		if( !sMiAccelText.IsEmpty() )
		{
			sMiText += _T("\t");
			sMiText += sMiAccelText;
		}
		VERIFY(
			menu.AppendMenu(
				MF_STRING,
				mi.GetCmdID(),
				sMiText
				)
			);

	} // for( int nItem = 0; nItem < nCount; nItem++ )

	return menu.Detach();
}

BOOL CExtPopupMenuWnd::UpdateFromMenu( 
	HWND hWndCmdRecv,
	CMenu * pBuildMenu,
	bool bPopupMenu, // = true
	bool bTopLevel // = true
	)
{
	ASSERT_VALID( this );

	if( hWndCmdRecv != NULL )
		m_hWndCmdReciever = hWndCmdRecv;
	ASSERT( m_hWndCmdReciever != NULL );
	ASSERT( ::IsWindow(m_hWndCmdReciever) );

	if( pBuildMenu == NULL
		|| (!(::IsMenu(pBuildMenu->GetSafeHmenu())))
		)
	{
		ASSERT( FALSE );
		return false;
	}
	if( bPopupMenu )
	{
		pBuildMenu = pBuildMenu->GetSubMenu(0);
		if( pBuildMenu == NULL
			|| (!(::IsMenu(pBuildMenu->GetSafeHmenu())))
			)
		{
			ASSERT( FALSE );
			return false;
		}
	}

	if(	!g_CmdManager->UpdateFromMenu(
			g_CmdManager->ProfileNameFromWnd( m_hWndCmdReciever ),
			pBuildMenu->GetSafeHmenu()
			)
		)
	{
		ASSERT( FALSE );
		return false;
	}

	if( !_BuildItems( pBuildMenu, bTopLevel ) )
		return FALSE;
	return TRUE;
}

CExtPopupMenuSite & CExtPopupMenuWnd::GetSite() const
{
	return CExtPopupMenuSite::g_DefPopupMenuSite;
}

CExtPopupMenuWnd * CExtPopupMenuWnd::GetTrackingMenu()
{
CExtPopupMenuWnd * pPopup =
		CExtPopupMenuSite::g_DefPopupMenuSite.GetInstance();
	if( !(::IsWindow(pPopup->GetSafeHwnd())) )
		return NULL;
	ASSERT_VALID( pPopup );
	return pPopup;
}

void CExtPopupMenuWnd::CancelMenuTracking()
{
	if( !CExtPopupMenuSite::g_DefPopupMenuSite.IsEmpty()
		&& !CExtPopupMenuSite::g_DefPopupMenuSite.IsShutdownMode()
		)
	{
		CExtPopupMenuSite::g_DefPopupMenuSite.DoneInstance();
		ASSERT( CExtPopupMenuSite::g_DefPopupMenuSite.IsEmpty() );
		ASSERT( !CExtPopupMenuSite::g_DefPopupMenuSite.IsShutdownMode() );
	}
}

BOOL CExtPopupMenuWnd::IsMenuTracking()
{
	if( CExtPopupMenuSite::g_DefPopupMenuSite.IsEmpty()
		//|| CExtPopupMenuSite::g_DefPopupMenuSite.GetCapture() == NULL
		)
		return FALSE;
	return TRUE;
}

BOOL CExtPopupMenuWnd::TrackPopupMenu(
	DWORD dwTrackFlags,
	int x,
	int y,
	LPCRECT lpRect, // = NULL
	LPVOID pCbPaintCombinedCookie, // = NULL
	pCbPaintCombinedContent pCbPaintCombinedContent, // = NULL
	UINT * lpnResultCmdID // = NULL
	)
{
	ASSERT_VALID( this );

CExtPopupMenuSite & _site = GetSite();
bool bSiteWasEmpty = _site.IsEmpty();
	if( !bSiteWasEmpty )
	{
		if( _site.IsShutdownMode() )
			return FALSE;
		_site.DoneInstance();
	}

//bool bCaptureChanged = false;
HWND hWndCapture = ::GetCapture();
CWnd * pWndCapture = FromHandlePermanent( hWndCapture );
	if( pWndCapture != NULL )
	{
		ReleaseCapture();
		if( ::IsWindow(hWndCapture) )
		{
			ASSERT_VALID( pWndCapture );
			pWndCapture->SendMessage(WM_CANCELMODE);
		}
//		bCaptureChanged = true;
	}

	ASSERT( _site.IsEmpty() );
	ASSERT( !_site.IsShutdownMode() );

	ASSERT( m_hWndCmdReciever != NULL );
	ASSERT( ::IsWindow(m_hWndCmdReciever) );

//	if( !bSiteWasEmpty
//		|| CExtToolControlBar::g_bMenuTracking
//		|| bCaptureChanged
//		)
//	{
//		PassMsgLoop( CExtPopupBaseWnd::g_bEnableOnIdleCalls );
//		if( ! ::IsWindow(m_hWndCmdReciever) )
//			return FALSE;
//	}
//	if( !_site.IsEmpty() )
//		return FALSE;

	ASSERT( m_bTopLevel );
	ASSERT( _site.IsEmpty() );

	_site.SetInstance( this );
	if( lpnResultCmdID != NULL )
	_site.SetTargetCmdIdPtr( lpnResultCmdID );

	m_dwTrackFlags = dwTrackFlags;

	_UpdateCmdUI();

	if(	! _TrackPopupMenu(
			dwTrackFlags,
			x,
			y,
			lpRect,
			pCbPaintCombinedCookie,
			pCbPaintCombinedContent
			)
		)
	{
		//ASSERT( FALSE );
		_site.DoneInstance();
		ASSERT( _site.IsEmpty() );
		ASSERT( !_site.IsShutdownMode() );
		return FALSE;
	}
	if( (dwTrackFlags&TPMX_DO_MESSAGE_LOOP) == 0 )
		return TRUE;
	// do popup menu message loop
	while( IsMenuTracking() )
	{
		WaitMessage();
		HWND hWndThis = GetSafeHwnd();
		CExtPopupMenuWnd::PassMsgLoop( CExtPopupBaseWnd::g_bEnableOnIdleCalls );
		if( !::IsWindow(hWndThis) )
			break;
	} // while( IsMenuTracking() )
	_site.DoneInstance();
	ASSERT( _site.IsEmpty() );
	ASSERT( !_site.IsShutdownMode() );
	return TRUE;
}

void CExtPopupMenuWnd::PassMsgLoop(
	bool bEnableOnIdleCalls
	)
{
#ifdef _USRDLL
	// If this is a DLL, need to set up MFC state
	AFX_MANAGE_STATE(AfxGetStaticModuleState());
#endif
MSG msg;
	// Process all the messages in the message queue
	while( PeekMessage(&msg, NULL, 0, 0, PM_NOREMOVE) )
	{
		if( !AfxGetApp()->PumpMessage() )
		{
			PostQuitMessage(0);
			return;
		} // if( !AfxGetApp()->PumpMessage() )
	} // while( PeekMessage(&msg, NULL, 0, 0, PM_NOREMOVE) )
	if( bEnableOnIdleCalls )
	{
		LONG lIdle = 0;
		while( AfxGetApp()->OnIdle(lIdle++) );
	}
}

CSize CExtPopupMenuWnd::_CalcTrackSize()
{
	ASSERT_VALID( this );

int nMenuShadowSize =
		_GetMenuShadowSize();
int nMenuBorderSize =
		g_PaintManager->GetMenuBorderSize();
int nXtraSz =
		nMenuBorderSize*2 + nMenuShadowSize;
CSize _size(m_sizeFullItems);
	if( m_bExpandAvailable )
		_size.cy += _GetSpecBtnHeight(); // xpand btn
	_size +=
		CSize(
			nXtraSz + m_nLeftAreaWidth,
			nXtraSz
			);
	return _size;
}

CRect CExtPopupMenuWnd::_CalcTrackRect()
{
	ASSERT_VALID( this );

	m_eCombineAlign = __CMBA_NONE;

	if( IsKeyPressed(VK_CONTROL) )
	{
		int i=1;
		i;
	}

CRect rcDesktop = _CalcDesktopRect();

CSize _size = _CalcTrackSize();
int nMenuShadowSize =
		_GetMenuShadowSize();
int nMenuBorderSize =
		g_PaintManager->GetMenuBorderSize();
int nGapShift = 0;
	if( !m_bCombineWithEA )
		nGapShift = nMenuBorderSize + nMenuShadowSize;

CRect wr(m_ptTrack,_size);
//	wr.NormalizeRect();
int nCombineOffset = 0;
	if(	m_bCombineWithEA )
	{
		if( (m_dwTrackFlags&TPMX_ALIGN_MASK)
				== TPMX_TOPALIGN )
		{
			nCombineOffset = 1;
			wr.OffsetRect(0,-nCombineOffset);
		}
		if( (m_dwTrackFlags&TPMX_ALIGN_MASK)
				== TPMX_LEFTALIGN )
		{
			nCombineOffset = 1;
			wr.OffsetRect(-nCombineOffset,0);
		}
		if( (m_dwTrackFlags&TPMX_ALIGN_MASK)
				== TPMX_BOTTOMALIGN )
		{
			nCombineOffset =
				-nMenuShadowSize - 1;
			wr.OffsetRect(0,-nCombineOffset);
		}
		if( (m_dwTrackFlags&TPMX_ALIGN_MASK)
				== TPMX_RIGHTALIGN )
		{
			nCombineOffset =
				-nMenuShadowSize - 1;
			wr.OffsetRect(-nCombineOffset,0);
		}
	} // if(	m_bCombineWithEA )

	if(wr.bottom > rcDesktop.bottom)
	{
		if( m_bExcludeAreaSpec )
		{
			wr.OffsetRect(
				0,
				-wr.Height()
					+ m_rcExcludeArea.Height()
					+ nGapShift
					+ (m_bCombineWithEA ?
						nMenuShadowSize : 0)
				);
		} // if( m_bExcludeAreaSpec )
		if(wr.bottom > rcDesktop.bottom)
			wr.OffsetRect(
				0,
				m_bExcludeAreaSpec
					? -(wr.bottom - rcDesktop.bottom)
					: - wr.Height()
				);
	} // if(wr.bottom > rcDesktop.bottom)
	if(wr.top < rcDesktop.top)
		wr.OffsetRect( 0, rcDesktop.top - wr.top );

	if(wr.right > rcDesktop.right)
	{
		if( !m_bTopLevel && m_bExcludeAreaSpec )
			wr.OffsetRect(
				-wr.Width() - m_rcExcludeArea.Width(),
				0
				);
		if(wr.right > rcDesktop.right)
			wr.OffsetRect(
				m_bExcludeAreaSpec
					? -(wr.right - rcDesktop.right)
					: -wr.Width(),
				0
				);
	} // if(wr.right > rcDesktop.right)
	if(wr.left < rcDesktop.left)
	{
		if( !m_bTopLevel && m_bExcludeAreaSpec )
			wr.OffsetRect(
				wr.Width() + m_rcExcludeArea.Width(),
				0
				);
		if(wr.left < rcDesktop.left)
			wr.OffsetRect( rcDesktop.left - wr.left, 0 );
	} // if(wr.left < rcDesktop.left)

	if( m_bExcludeAreaSpec || m_bCombineWithEA )
	{
		CRect rcIntersection;
		if(	rcIntersection.IntersectRect(
				&wr,
				&m_rcExcludeArea
				)
			|| m_bCombineWithEA
			)
		{ // if need adjust with exclude area
			CRect rcFree(0,0,0,0);
			if( m_rcExcludeArea.left > rcDesktop.left )
				rcFree.left =
					m_rcExcludeArea.left - rcDesktop.left;
			if( m_rcExcludeArea.right < rcDesktop.right )
				rcFree.right =
					rcDesktop.right - m_rcExcludeArea.right;
			if( m_rcExcludeArea.top > rcDesktop.top )
				rcFree.top =
					m_rcExcludeArea.top - rcDesktop.top;
			if( m_rcExcludeArea.bottom < rcDesktop.bottom )
				rcFree.bottom =
					rcDesktop.bottom - m_rcExcludeArea.bottom;
			if( (m_dwTrackFlags&TPMX_ALIGN_MASK)
					== TPMX_LEFTALIGN
				&& rcFree.right > wr.Width()
				)
				wr.OffsetRect(
					wr.left - m_rcExcludeArea.right
						+ (m_bCombineWithEA ?
							nCombineOffset : 0)
						,
					0
					);
			if( (m_dwTrackFlags&TPMX_ALIGN_MASK)
					== TPMX_RIGHTALIGN
				&& rcFree.left > wr.Width()
				)
				wr.OffsetRect(
					m_rcExcludeArea.left - wr.right
						- (m_bCombineWithEA ?
							nCombineOffset : 0)
						,
					0
					);

//			if( (m_dwTrackFlags&TPMX_ALIGN_MASK)
//					== TPMX_TOPALIGN
//				&& rcFree.bottom > wr.Height()
//				)
//				wr.OffsetRect(
//					0,
//					wr.top - m_rcExcludeArea.bottom
//						+ (m_bCombineWithEA ?
//							nCombineOffset : 0)
//					);

			if( (m_dwTrackFlags&TPMX_ALIGN_MASK)
					== TPMX_TOPALIGN
				)
			{
				if( rcFree.bottom > wr.Height() )
					wr.OffsetRect(
						0,
						wr.top - m_rcExcludeArea.bottom
							+ (m_bCombineWithEA ?
								nCombineOffset : 0)
						);
				else
				{
					if( ::IsWindow(GetSafeHwnd()) )
					{
						CRect rcWndOld;
						GetWindowRect( &rcWndOld );
						ShowWindow( SW_HIDE );
						_FreeWinObjects();
						HWND hWndThis = GetSafeHwnd();
						bool bWasCreated =
							(hWndThis != NULL && ::IsWindow(hWndThis))
								? true : false;
						CExtPopupMenuWnd::PassMsgLoop( CExtPopupBaseWnd::g_bEnableOnIdleCalls );
						if( bWasCreated && !::IsWindow(hWndThis) )
							return CRect(0,0,0,0);
						if( !rcWndOld.IsRectEmpty() )
						{
							CWnd * pWndTLP = GetTopLevelParent();
							if( pWndTLP != NULL )
							{
								ASSERT_VALID( pWndTLP );
								if( pWndTLP->IsWindowVisible() )
								{
									CRect rcTLP;
									pWndTLP->GetWindowRect( &rcTLP );
									if( !rcTLP.IsRectEmpty() )
									{
										CRect rcIntersection;
										if(	rcIntersection.IntersectRect(
												&rcTLP,
												&rcWndOld
												)
											)
											pWndTLP->UpdateWindow();
									} // if( !rcTLP.IsRectEmpty() )
								} // if( pWndTLP->IsWindowVisible() )
							} // if( pWndTLP != NULL )
						} // if( !rcWndOld.IsRectEmpty() )
					}
					m_dwTrackFlags &= ~TPMX_ALIGN_MASK;
					m_dwTrackFlags |= TPMX_BOTTOMALIGN;
					return _CalcTrackRect();
				}

			}

			if( (m_dwTrackFlags&TPMX_ALIGN_MASK)
					== TPMX_BOTTOMALIGN
					&& rcFree.top > wr.Height()
				)
				wr.OffsetRect(
					0,
					m_rcExcludeArea.top - wr.bottom
						- (m_bCombineWithEA ?
							nCombineOffset : 0)
					);
		} // if need adjust with exclude area
	} // if( m_bExcludeAreaSpec || m_bCombineWithEA )

	if(wr.right > rcDesktop.right)
	{
		wr.OffsetRect( -(wr.right - rcDesktop.right), 0 );
		if( m_bTopLevel )
		{
			m_bExcludeAreaSpec = false;
			m_bCombineWithEA = false;
		}
	} // if(wr.right > rcDesktop.right)
	if(wr.left < rcDesktop.left)
	{
		wr.OffsetRect( rcDesktop.left - wr.left, 0 );
		if( m_bTopLevel )
		{
			m_bExcludeAreaSpec = false;
			m_bCombineWithEA = false;
		}
	} // if(wr.left < rcDesktop.left)
	if(wr.bottom > rcDesktop.bottom)
	{
		wr.OffsetRect( 0, -(wr.bottom - rcDesktop.bottom) );
		if( m_bTopLevel )
		{
			m_bExcludeAreaSpec = false;
			m_bCombineWithEA = false;
		}
	} // if(wr.bottom > rcDesktop.bottom)
	if(wr.top < rcDesktop.top)
	{
		wr.OffsetRect( 0, rcDesktop.top - wr.top );
		if( m_bTopLevel )
		{
			m_bExcludeAreaSpec = false;
			m_bCombineWithEA = false;
		}
	} // if(wr.top < rcDesktop.top)
	if(wr.bottom > rcDesktop.bottom)
	{
		wr.bottom = rcDesktop.bottom;
		m_bScrollingAvailable = true;
	}

	if( m_bCombineWithEA )
	{
		ASSERT( m_bTopLevel );
		ASSERT( m_bExcludeAreaSpec );
		if( wr.bottom == m_rcExcludeArea.top - nCombineOffset )
			m_eCombineAlign = __CMBA_BOTTOM;
		if( wr.top == m_rcExcludeArea.bottom  - nCombineOffset )
			m_eCombineAlign = __CMBA_TOP;
		if( wr.left == m_rcExcludeArea.right - nCombineOffset )
			m_eCombineAlign = __CMBA_LEFT;
		if( wr.right == m_rcExcludeArea.left - nCombineOffset  )
			m_eCombineAlign = __CMBA_RIGHT;
		if( m_eCombineAlign == __CMBA_NONE )
		{
			m_bCombineWithEA = false;
			return _CalcTrackRect();
		} // if( m_eCombineAlign == __CMBA_NONE )
		// init window region
		if( m_rgnWnd.GetSafeHandle() != NULL )
		{
			VERIFY(
				m_rgnWnd.DeleteObject()
				);
		}
		CRect rcExcludeArea(m_rcExcludeArea);
		rcExcludeArea.InflateRect(
			0,
			0,
			nMenuShadowSize,
			nMenuShadowSize
			);
		CRect rcFullWnd(
			min(wr.left,rcExcludeArea.left),
			min(wr.top,rcExcludeArea.top),
			max(wr.right,rcExcludeArea.right),
			max(wr.bottom,rcExcludeArea.bottom)
			);
		CRgn rgnAreaWnd,rgnAreaExclude;
		if(	(!m_rgnWnd.CreateRectRgnIndirect(
				&rcFullWnd ))
			||
			(!rgnAreaExclude.CreateRectRgnIndirect(
				&rcExcludeArea ))
			||
			(!rgnAreaWnd.CreateRectRgnIndirect(
				&wr ))
			||
			m_rgnWnd.CombineRgn(
				&rgnAreaWnd,
				&rgnAreaExclude,
				RGN_OR
				) == ERROR
			||
			m_rgnWnd.OffsetRgn(
				-rcFullWnd.TopLeft()
				) == ERROR
			)
		{
			if( m_rgnWnd.GetSafeHandle() != NULL )
			{
				VERIFY(
					m_rgnWnd.DeleteObject()
					);
			}
			m_bCombineWithEA = false;
			return _CalcTrackRect();
		}
		ASSERT( m_rgnWnd.GetSafeHandle() != NULL );
		
//		VERIFY( m_rgnWnd.DeleteObject() );
//		VERIFY(
//			m_rgnWnd.CreateRectRgnIndirect(
//				&rcFullWnd
//				)
//			);

		m_rcClient = wr;
		m_rcClient.OffsetRect( -rcFullWnd.TopLeft() );
		m_rcClient.DeflateRect(
			0,
			0,
			nMenuShadowSize,
			nMenuShadowSize
			);
		ASSERT( m_rcClient.top <= m_rcClient.bottom );
		ASSERT( m_rcClient.left <= m_rcClient.right );

		return rcFullWnd;
	} // if( m_bCombineWithEA )

	m_rcClient = wr;
	m_rcClient.OffsetRect( -wr.TopLeft() );
	m_rcClient.DeflateRect(
		0,
		0,
		nMenuShadowSize,
		nMenuShadowSize
		);
	ASSERT( m_rcClient.top <= m_rcClient.bottom );
	ASSERT( m_rcClient.left <= m_rcClient.right );

	return wr;
}

CRect CExtPopupBaseWnd::_CalcDesktopRect()
{
	ASSERT_VALID( this );

CRect rcDesktop;
	if( g_bUseDesktopWorkArea )
	{
		VERIFY(
			::SystemParametersInfo(
				SPI_GETWORKAREA,
				0,
				PVOID(&rcDesktop),
				0
				)
			);
		return rcDesktop;
	} // if( g_bMenuUsingDesktopWorkArea )
	rcDesktop.SetRect(0,0,800,600);
	return rcDesktop;
}

BOOL CExtPopupMenuWnd::_TrackPopupMenu(
	DWORD dwTrackFlags,
	int x,
	int y,
	LPCRECT lpRect,
	LPVOID pCbPaintCombinedCookie, // = NULL
	pCbPaintCombinedContent pCbPaintCombinedContent // = NULL
	)
{
	ASSERT_VALID( this );

bool bForceExpandRarelyUsed = (dwTrackFlags&TPMX_NO_HIDE_RARELY)
		? true : false;
	if( !g_bMenuExpanding )
		bForceExpandRarelyUsed = true;

	ASSERT( m_hWndCmdReciever != NULL );
	ASSERT( ::IsWindow(m_hWndCmdReciever) );

	ASSERT( GetSafeHwnd() == NULL );

CExtPopupMenuSite & _site = GetSite();

	if( _site.IsTopPupup(this) )
	{
		ASSERT( m_bTopLevel );
		MsgPrepareMenuData_t _mpmd( this );
		_mpmd.SendMessage( m_hWndCmdReciever );
		if( _mpmd.m_bMenuCanceled )
			return FALSE;
		if( _mpmd.m_bMenuChanged )
		{
			_UpdateCmdUI();
		}
		ASSERT( m_bTopLevel );
		ASSERT( _site.IsTopPupup(this) );
	}

	{ // BLOCK: update system commands
		INT iter = 0;
		for(; iter < m_items_all.GetSize(); ++iter )
		{
			MENUITEMDATA & mi = m_items_all[ iter ];
			if( mi.IsSeparator() )
				continue;
			UINT nCmdID = mi.GetCmdID();
			if( !CExtCmdManager::IsSystemCommand(nCmdID))
				continue;
			WINDOWPLACEMENT wndpl;
			::memset(&wndpl,0,sizeof(WINDOWPLACEMENT));
			wndpl.length = sizeof(WINDOWPLACEMENT);
			VERIFY(
				::GetWindowPlacement(
					mi.GetCmdReciever(),
					&wndpl
					)
				);
			bool bSysCmdEnabled = false;
			switch( nCmdID )
			{
			case SC_CLOSE:
				bSysCmdEnabled = true;
			break;
			case SC_SIZE:
			case SC_MOVE:
				if( wndpl.showCmd != SW_SHOWMINIMIZED
					&&
					wndpl.showCmd != SW_SHOWMAXIMIZED
					)
					bSysCmdEnabled = true;
			break;
			case SC_MINIMIZE:
				if( wndpl.showCmd != SW_SHOWMINIMIZED )
					bSysCmdEnabled = true;
			break;
			case SC_MAXIMIZE:
				if( wndpl.showCmd != SW_SHOWMAXIMIZED )
					bSysCmdEnabled = true;
			break;
			case SC_RESTORE:
				if( wndpl.showCmd == SW_SHOWMAXIMIZED
					||
					wndpl.showCmd == SW_SHOWMINIMIZED
					//||
					//wndpl.showCmd == SW_SHOWNORMAL
					)
					bSysCmdEnabled = true;
			break;
			case SC_CONTEXTHELP:
				if( GetWindowLong(
						mi.GetCmdReciever(),
						GWL_EXSTYLE
						) & WS_EX_CONTEXTHELP
					)
					bSysCmdEnabled = true;
			break;
//			case SC_NEXTWINDOW:
//			case SC_PREVWINDOW:
//			case SC_VSCROLL:
//			case SC_HSCROLL:
//			case SC_MOUSEMENU:
//			case SC_KEYMENU:
//			case SC_ARRANGE:
//			case SC_TASKLIST:
//			case SC_SCREENSAVE:
//#if(WINVER >= 0x0400)
//			case SC_DEFAULT:
//			case SC_MONITORPOWER:
//			case SC_SEPARATOR:
//#endif /* WINVER >= 0x0400 */
			case SC_HOTKEY:
			default:
				continue;
			} // switch( nCmdID )
			CExtCmdManager::cmd_t * p_cmd =
				g_CmdManager->CmdGetPtr(
					g_CmdManager->ProfileNameFromWnd( m_hWndCmdReciever ),
					nCmdID
					);
			ASSERT( p_cmd != NULL );
			p_cmd->StateEnable( bSysCmdEnabled );
		} // for(; iter < m_items_all.end(); ++iter )
	} // BLOCK: update system commands

CWnd * pWndCmdReciever =
		CWnd::FromHandle( m_hWndCmdReciever );
	ASSERT_VALID( pWndCmdReciever );
//	pWndCmdReciever->ActivateTopParent();
//	pWndCmdReciever->BringWindowToTop();
//	pWndCmdReciever->SetFocus();
	
	//_site._Hook( true );

	// adjust own data
bool bOldTopLevel = m_bTopLevel;
bool bOldExpandAvailable = m_bExpandAvailable;
	_Init();
	m_bTopLevel = bOldTopLevel;
	m_bExpandAvailable = bOldExpandAvailable;
	m_dwTrackFlags = dwTrackFlags;
	m_pCbPaintCombinedCookie = pCbPaintCombinedCookie;
	m_pCbPaintCombinedContent = pCbPaintCombinedContent;
	if( !m_bTopLevel )
	{
		ASSERT( m_pWndParentMenu != NULL );
		if( m_pWndParentMenu->m_bExpandWasPressed )
		{
			if( m_bExpandAvailable )
			{
				m_bExpandAvailable = false;
				m_bExpandWasPressed = true;
				_SyncItems();
			}
			else
				m_bExpandWasPressed = true;
		}
	} // if( !m_bTopLevel )
	else
	{
		if( bForceExpandRarelyUsed )
		{
			if( m_bExpandAvailable )
			{
				m_bExpandAvailable = false;
				m_bExpandWasPressed = true;
				_SyncItems();
			}
			else
				m_bExpandWasPressed = true;
		} // if( bForceExpandRarelyUsed )
	} // else from if( !m_bTopLevel )

	// adjust screen position
	m_ptTrack.x = x;
	m_ptTrack.y = y;
	if( m_ptTrack.x < 0 || m_ptTrack.y < 0 )
	{
		VERIFY( ::GetCursorPos(&m_ptTrack) );
	}

	if( lpRect != NULL )
	{
		m_rcExcludeArea = *lpRect;
		m_bExcludeAreaSpec = true;
	}
	else
	{
		m_bExcludeAreaSpec = false;
		m_rcExcludeArea.left = m_ptTrack.x - __EXCLUDE_AREA_GAP_DX;
		m_rcExcludeArea.right = m_ptTrack.x + __EXCLUDE_AREA_GAP_DX;
		m_rcExcludeArea.top = m_ptTrack.y - __EXCLUDE_AREA_GAP_DY;
		m_rcExcludeArea.bottom = m_ptTrack.y + __EXCLUDE_AREA_GAP_DY;
	}

	// adjust combine with exclude area mode
	m_bCombineWithEA = false;
	if( m_bTopLevel && m_bExcludeAreaSpec )
	{
		switch( (dwTrackFlags&TPMX_COMBINE_MASK) )
		{
		case TPMX_COMBINE_ANY_SUITABLE:
			m_bCombineWithEA = true;
		break;
		case TPMX_COMBINE_DEFAULT:
			m_bCombineWithEA =
				g_PaintManager->
					IsMenuMustCombineExcludeArea();
		break;
		} // switch( (dwTrackFlags&TPMX_COMBINE_MASK) )
	} // if( m_bTopLevel && m_bExcludeAreaSpec )

CSize _size = _CalcTrackSize();
bool bPointAdjusted = true;
	if( m_bExcludeAreaSpec )
	{
		switch( (m_dwTrackFlags & TPMX_ALIGN_MASK) )
		{
		case TPMX_LEFTALIGN:
			m_ptTrack.x = m_rcExcludeArea.right;
			m_ptTrack.y = m_rcExcludeArea.top;
		break;
		case TPMX_RIGHTALIGN:
			m_ptTrack.x = m_rcExcludeArea.left - _size.cx;
			m_ptTrack.y = m_rcExcludeArea.top;
		break;
		case TPMX_TOPALIGN:
			m_ptTrack.x = m_rcExcludeArea.left;
			m_ptTrack.y = m_rcExcludeArea.bottom;
		break;
		case TPMX_BOTTOMALIGN:
			m_ptTrack.x = m_rcExcludeArea.left;
			m_ptTrack.y = m_rcExcludeArea.top - _size.cy;
		break;
		default:
			bPointAdjusted = false;
		break;
		} // switch( (m_dwTrackFlags & TPMX_ALIGN_MASK) )
	} // if( m_bExcludeAreaSpec )
	if( !bPointAdjusted )
	{
		if( (m_dwTrackFlags & TPMX_ALIGN_MASK)
				== TPMX_RIGHTALIGN )
			m_ptTrack.x -= _size.cx;
		else
		{
			if( (m_dwTrackFlags & TPMX_ALIGN_MASK)
					== TPMX_CENTERALIGN )
				m_ptTrack.x -= _size.cx/2;
		}
		if( (m_dwTrackFlags & TPMX_ALIGN_MASK)
				== TPMX_BOTTOMALIGN )
			m_ptTrack.y -= _size.cy;
		else
		{
			if( (m_dwTrackFlags & TPMX_ALIGN_MASK)
					== TPMX_VCENTERALIGN )
				m_ptTrack.y -= _size.cy/2;
		}
	} // if( !bPointAdjusted )

//#ifdef _DEBUG
bool bCreateResult =
//#endif // _DEBUG
		_CreateHelper( pWndCmdReciever );
	//ASSERT( bCreateResult );
	if( !bCreateResult )
	{
		//_OnCancelMode();
		return FALSE;
	}

	if( dwTrackFlags&TPMX_SELECT_ANY )
	{
		int nItem = _GetNextItem(__NI_ANY);
		if( nItem >= 0 )
			_ItemFocusSet(
				nItem,
				FALSE,
				FALSE
				);
	}

	m_AnimationType = g_DefAnimationType;
	if( CExtToolControlBar::g_bMenuTracking )
		m_AnimationType = __AT_NONE;

	m_ePlaySoundOnAnimationFinished =
		CExtSoundPlayer::__ON_MENU_POPUP_DISPLAYED;
	_StartAnimation();
	if( m_AnimationType == __AT_NONE )
	{
		m_AnimationType = __AT_CONTENT_DISPLAY;
		_StartAnimation();
		ASSERT( m_AnimationType == __AT_CONTENT_DISPLAY );
	}

	if( m_rgnWnd.GetSafeHandle() != NULL )
	{
		ASSERT( m_bExcludeAreaSpec );
		ASSERT( m_bCombineWithEA );
		ASSERT( m_eCombineAlign != __CMBA_NONE );
		CRgn rgnTmp;
		VERIFY( rgnTmp.CreateRectRgn(0,0,0,0) );
		rgnTmp.CopyRgn( &m_rgnWnd );
		ASSERT( rgnTmp.GetSafeHandle() != NULL );
		VERIFY(
			SetWindowRgn(
				(HRGN)rgnTmp.Detach(),
				FALSE
				)
			);
	} // if( m_rgnWnd.GetSafeHandle() != NULL )
	SetWindowPos(
		&wndTop,
		-1, -1, -1, -1,
		SWP_NOACTIVATE
			|SWP_NOMOVE|SWP_NOSIZE
			|SWP_SHOWWINDOW
			//|SWP_NOREDRAW //|SWP_NOSENDCHANGING
			|SWP_NOZORDER //|SWP_NOOWNERZORDER
			//|SWP_NOCOPYBITS
		);
//	_BitsSave();

	ASSERT( IsWindowVisible() );

	_SetCapture();

	return TRUE;
}

bool CExtPopupMenuWnd::_CreateHelper(
	CWnd * pWndCmdReciever
	)
{
	ASSERT_VALID( this );

CRect wr = _CalcTrackRect();
	if( wr.IsRectEmpty() )
		return false;

HCURSOR hCursor = ::LoadCursor(NULL, IDC_ARROW);
	ASSERT( hCursor != NULL );
CString strMenuClassName =
		::AfxRegisterWndClass(
			__POPUP_WNDCLASS_STYLES__,
			hCursor,
			(HBRUSH)(COLOR_BTNFACE + 1),
			NULL
			);
	ASSERT( !strMenuClassName.IsEmpty() );

BOOL bCreateResult =
		__BaseClassOfCExtPopupBaseWnd::CreateEx(
			WS_EX_TOPMOST, // 0,
			strMenuClassName,
			NULL,
			WS_POPUP,
			wr,
			pWndCmdReciever,
			0 // IDC_STATIC
			);
	if( !bCreateResult )
	{
		ASSERT( FALSE );
		return false;
	}

	_RecalcLayoutImpl();

	::SetCursor( hCursor );

//HWND hWndOwn = GetSafeHwnd();
//	ASSERT( hWndOwn != NULL );
//	ASSERT( ::IsWindow(hWndOwn) );
//	PassMsgLoop( CExtPopupBaseWnd::g_bEnableOnIdleCalls ); // update all bottom
//	if( !::IsWindow(hWndOwn) )
//		return false;

	return true;
}

void CExtPopupMenuWnd::_GetItemRect(
	int nIndex,
	RECT & rectItem
	)
{
	ASSERT_VALID( this );

CRect rcClient;
	_GetClientRect( &rcClient );

	rcClient.left += m_nLeftAreaWidth;

	if( m_bScrollingAvailable )
	{
		ASSERT( !m_rcScrollTop.IsRectEmpty() );
		ASSERT( !m_rcScrollBottom.IsRectEmpty() );
		if( nIndex == IDX_SCROLL_TOP )
		{
			rectItem = m_rcScrollTop;
			return;
		}
		if( nIndex == IDX_SCROLL_BOTTOM )
		{
			rectItem = m_rcScrollBottom;
			return;
		}
	}
	if( m_bExpandAvailable
		&& nIndex == IDX_EXPAND
		)
	{
		rectItem = m_rcExpandBtn;
		return;
	}

int nCountOfItems = m_items_all.GetSize();
	if( nCountOfItems == 0 )
	{
		((CRect *)(&rectItem))->SetRectEmpty();
		return;
	}
	ASSERT(
		nIndex >= 0
		&&
		nIndex < nCountOfItems
		);
MENUITEMDATA & mi =
		m_items_all[nIndex];
	if( !mi.IsDisplayed() )
	{
		((CRect *)(&rectItem))->SetRectEmpty();
		return;
	}

int nMenuBorderSize =
		g_PaintManager->GetMenuBorderSize();
int y = m_nDyScrollOffset + nMenuBorderSize;

CRect rcItem;
	rcItem.SetRectEmpty();
	rcItem.left =
		nMenuBorderSize
			+ 1
		;
	rcItem.right =
		m_sizeFullItems.cx
			+ nMenuBorderSize
			- 1
		;

INT iter = 0;
	for(	int i = 0;
			i < nIndex
				&& iter != m_items_all.GetSize();
			i++, iter++
			)
	{
		MENUITEMDATA & mi = m_items_all[ iter ];
		if( !mi.IsDisplayed() )
			continue;
		const RECT & rcBase =
			mi.GetBaseRect();
		y +=  rcBase.bottom - rcBase.top;
	}
	ASSERT( iter != m_items_all.GetSize() );
	rcItem.OffsetRect(0,y);
	mi = m_items_all[ iter ];
	ASSERT( mi.IsDisplayed() );
const RECT & rcBase = mi.GetBaseRect();
	rcItem.bottom =
		rcItem.top + rcBase.bottom - rcBase.top;
	
	// FIX for combined exclude area
	rcItem.OffsetRect( rcClient.TopLeft() );
	
	rectItem = rcItem;
}

void CExtPopupMenuWnd::_GetVisibleItems(
	CDC & dc,
	visible_items_t & v
	)
{
	ASSERT_VALID( this );

	v.RemoveAll();
INT iter = 0;
	for(	int nIndex = 0;
			iter != m_items_all.GetSize();
			iter++, nIndex++
			)
	{ // find visible items
		MENUITEMDATA & mi = m_items_all[ iter ];
		if( !mi.IsDisplayed() )
			continue;
		CRect rcItem;
		_GetItemRect( nIndex, rcItem );
		if( rcItem.IsRectEmpty() )
			continue;
		if( !dc.RectVisible( &rcItem ) )
			continue;
		VisibleItemDefinion_t vi;
		vi.m_nIndex = nIndex;
		vi.m_nHelperCmdID = mi.GetCmdID();
		vi.m_rcItem = rcItem;
		if( mi.IsSeparator() )
		{
			vi.m_bHelperIsSeparator = true;
			v.Add( vi );
			continue;
		}
		if( mi.IsPopup() )
		{
			vi.m_bHelperIsPopup = true;
			vi.m_bRarelyUsed =
				mi.IsAllItemsRarelyUsed()
				&& !mi.IsForceDisplayed()
				;
			v.Add( vi );
			continue;
		}
		CExtCmdManager::cmd_t * p_cmd =
			mi.GetCmd();
		ASSERT( p_cmd != NULL );
		vi.m_bRarelyUsed =
			p_cmd->StateIsRarelyUsed();
		v.Add( vi );
	} // find visible items
INT vis_iter = 0;
	for( ; vis_iter < v.GetSize(); ++vis_iter )
	{ // setup prev/next rarely used flags
		VisibleItemDefinion_t & vi = v[ vis_iter ];
		INT iter_prev = vis_iter;
		INT iter_next = vis_iter;
		if( vis_iter != 0 )
		{
			--iter_prev;
			if( v[iter_prev].m_bRarelyUsed )
				vi.m_bRarelyUsedPrev = true;
		} // if( vis_iter != v.begin() )
		++iter_next;
		if( iter_next != v.GetSize() )
		{
			if( v[iter_next].m_bRarelyUsed )
				vi.m_bRarelyUsedNext = true;
		} // if( iter_next != v.end() )

		if( vi.m_bHelperIsSeparator )
		{
			if(	vi.m_bRarelyUsedPrev
				&& vi.m_bRarelyUsedNext
				)
			{
				vi.m_bRarelyUsed = true;
				ASSERT( vis_iter != 0 );
				v[iter_prev].m_bRarelyUsedNext = true;
				ASSERT( iter_next != 0 );
				v[iter_next].m_bRarelyUsedPrev = true;
			}
		}
	} // setup prev/next rarely used flags
}

void CExtPopupMenuWnd::DRAWITEMDATA::PaintDefault(
	bool bForceNoIcon, // = false
	bool bForceNoText, // = false
	bool bForceNoCheck, // = false
	bool bForceEnabled, // = false
	bool bForceUnselected // = false
	)
{
	ASSERT( m_pDC != NULL );
	ASSERT( m_pDC->GetSafeHdc() != NULL );
	ASSERT( m_pRectItem != NULL );
	ASSERT( m_pItemData != NULL );
	ASSERT( m_pPopup != NULL );
	g_PaintManager->PaintMenuItem(
		*m_pDC,
		CRect( *m_pRectItem ),
		bForceNoText ? _T("") : m_pItemData->GetText(),
		bForceNoText ? _T("") : m_pItemData->GetAccelText(),
		bForceNoIcon ? NULL : HICON( *this ),
		m_bPopupItem,
		bForceUnselected ? false : m_pItemData->IsSelected(),
		bForceNoCheck ? false : m_pItemData->GetCheck(),
		bForceNoCheck ? false : m_pItemData->GetRadio(),
		m_pItemData->GetIndeterminate(),
		bForceEnabled || m_pItemData->IsEnabled(),
		m_bRarelyUsed,
		m_bRarelyUsedPreviouse,
		m_bRarelyUsedNext,
		m_pItemData->GetCmdID()
		);
}

bool CExtPopupMenuWnd::DRAWITEMDATA::DoOwnerDrawPainting()
{
	ASSERT( m_pDC != NULL );
	ASSERT( m_pDC->GetSafeHdc() != NULL );
	ASSERT( m_pRectItem != NULL );
	ASSERT( m_pItemData != NULL );
	ASSERT( m_pPopup != NULL );
	HWND hWndNotify =
		m_pPopup->m_hWndCmdReciever;
	ASSERT( hWndNotify != NULL );
	ASSERT( ::IsWindow(hWndNotify) );
	LRESULT lResult =
		::SendMessage(
			hWndNotify,
			CExtPopupMenuWnd::g_nMsgPopupDrawItem,
			0,
			LPARAM( *this )
			);
	return lResult ? true : false;
}

bool CExtPopupMenuWnd::DRAWLEFTAREADATA::DoOwnerDrawPainting()
{
	ASSERT( m_pDC != NULL );
	ASSERT( m_pDC->GetSafeHdc() != NULL );
	ASSERT( m_pRectLeftArea != NULL );
	ASSERT( m_pPopup != NULL );
	HWND hWndNotify =
		m_pPopup->m_hWndCmdReciever;
	ASSERT( hWndNotify != NULL );
	ASSERT( ::IsWindow(hWndNotify) );
	LRESULT lResult =
		::SendMessage(
			hWndNotify,
			CExtPopupMenuWnd::g_nMsgPopupDrawLeftArea,
			0,
			LPARAM( *this )
			);
	return lResult ? true : false;
}

void CExtPopupMenuWnd::_DoPaint(
	CDC & dcPaint,
	bool bUseBackBuffer // = true
	)
{
	ASSERT_VALID( this );

	ASSERT_VALID( (&dcPaint) );
	ASSERT( dcPaint.GetSafeHdc() != NULL );

	ASSERT( m_hWndCmdReciever != NULL );
	ASSERT( ::IsWindow(m_hWndCmdReciever) );

CRect rcRealClient;
	GetClientRect( &rcRealClient );
CRect rcClient;
	_GetClientRect( &rcClient );

CPalette * pOldPalette = NULL, * pOldPalette2 = NULL;
    if( dcPaint.GetDeviceCaps(RASTERCAPS) & RC_PALETTE )
    {
        pOldPalette =
			dcPaint.SelectPalette( &g_PaintManager->m_PaletteWide, FALSE );
        dcPaint.RealizePalette();
    }

//bUseBackBuffer = false;
//bUseBackBuffer = true;
	//dcPaint.SetViewportOrg( CPoint(0,0) );
CExtMemoryDC mdc;
	if( bUseBackBuffer )
	{
		mdc.__InitMemoryDC(
			&dcPaint,
			&rcClient // &rcRealClient
			);
		//mdc.SetViewportOrg( CPoint(0,0) );
		if( pOldPalette != NULL )
		{
			pOldPalette2 =
				mdc.SelectPalette( &g_PaintManager->m_PaletteWide, FALSE );
			mdc.RealizePalette();
		}
	}
CDC & dcDummyRef = mdc;
CDC & dc = bUseBackBuffer ? dcDummyRef : dcPaint;

CFont * pOldFont = (CFont *)
		dc.SelectObject(
			&g_PaintManager->m_FontNormal
			);

	dc.FillSolidRect(
		&rcClient,
		g_PaintManager->GetMenuFrameFillColor()
		);

	g_PaintManager->PaintMenuBorder(
		dc,
		&rcClient
		);

CRect rcExpand;
	if( m_bExpandAvailable )
	{
		_GetItemRect(
			IDX_EXPAND,
			rcExpand
			);
		CRect rcExcludePart( rcExpand );
		rcExcludePart.InflateRect( 0, 1 );
		rcExcludePart.left = rcRealClient.left;
		rcExcludePart.right = rcRealClient.right;
		dc.ExcludeClipRect( rcExcludePart );
	}
CRect rcScrollTop,rcScrollBottom;
int nMaxScrollPos = 0;
	if( m_bScrollingAvailable )
	{
		if( m_nDyScrollOffset != 0 )
		{
			_GetItemRect(
				IDX_SCROLL_TOP,
				rcScrollTop
				);
			CRect rcExcludePart( rcScrollTop );
			rcExcludePart.InflateRect( 0, 1 );
			rcExcludePart.left = rcRealClient.left;
			rcExcludePart.right = rcRealClient.right;
			dc.ExcludeClipRect( rcExcludePart );
		}
		nMaxScrollPos = _GetMaxScrollPos();
		if( m_nDyScrollOffset != nMaxScrollPos )
		{
			_GetItemRect(
				IDX_SCROLL_BOTTOM,
				rcScrollBottom
				);
			CRect rcExcludePart( rcScrollBottom );
			rcExcludePart.InflateRect( 0, 1 );
			rcExcludePart.left = rcRealClient.left;
			rcExcludePart.right = rcRealClient.right;
			dc.ExcludeClipRect( rcExcludePart );
		}
	}
int nMenuBorderSize =
		g_PaintManager->GetMenuBorderSize();
int nMenuShadowSize =
		_GetMenuShadowSize();

//	if( rcClient.left >= rcRealClient.left )
//	{
//		CRect rcExcludePart(rcRealClient);
//		rcExcludePart.right =
//			rcClient.left + nMenuBorderSize;
//		dc.ExcludeClipRect( rcExcludePart );
//	}
//	if( rcClient.right <= rcRealClient.right )
//	{
//		CRect rcExcludePart(rcRealClient);
//		rcExcludePart.left =
//			rcClient.right - nMenuBorderSize;
//		dc.ExcludeClipRect( rcExcludePart );
//	}

	if( rcClient.top >= rcRealClient.top )
	{
		CRect rcExcludePart(rcRealClient);
		rcExcludePart.bottom =
			rcClient.top + nMenuBorderSize;
		dc.ExcludeClipRect( rcExcludePart );
	}
	if( rcClient.bottom <= rcRealClient.bottom )
	{
		CRect rcExcludePart(rcRealClient);
		rcExcludePart.top =
			rcClient.bottom - nMenuBorderSize;
		dc.ExcludeClipRect( rcExcludePart );
	}

visible_items_t v;
	_GetVisibleItems( dc, v );
INT vis_iter = 0;
	for( ; vis_iter < v.GetSize(); ++vis_iter )
	{ // paint visible items
		VisibleItemDefinion_t & vi = v[ vis_iter ];
		ASSERT(
			vi.m_nIndex >= 0
			&&
			vi.m_nIndex < m_items_all.GetSize()
			);
		ASSERT( !vi.m_rcItem.IsRectEmpty() );
		ASSERT( dc.RectVisible(&vi.m_rcItem) );
		MENUITEMDATA & mi =
			m_items_all[vi.m_nIndex];
		ASSERT( mi.IsDisplayed() );
		ASSERT( mi.GetCmdID() == vi.m_nHelperCmdID );
		if( vi.m_bHelperIsSeparator )
		{
			ASSERT( mi.IsSeparator() );
			g_PaintManager->PaintMenuSeparator(
				dc,
				vi.m_rcItem,
				g_bMenuHighlightRarely && vi.m_bRarelyUsed
				);
			continue;
		}
		ASSERT( !mi.IsSeparator() );
		ASSERT( mi.IsPopup() == vi.m_bHelperIsPopup );
		
		DRAWITEMDATA _DrawItemData(
			&dc,
			&vi.m_rcItem,
			&mi,
			this,
			( GetSite()->m_dwTrackFlags&TPMX_OWNERDRAW_FIXED ) ? true : false,
			vi.m_bHelperIsPopup,
			g_bMenuHighlightRarely && vi.m_bRarelyUsed,
			g_bMenuHighlightRarely && vi.m_bRarelyUsedPrev,
			g_bMenuHighlightRarely && vi.m_bRarelyUsedNext
			);
		
		bool bPainted =
			(_DrawItemData.m_bMenuOwnderDrawFixed)
				? _DrawItemData.DoOwnerDrawPainting()
				: false
				;
		if( !bPainted )
			_DrawItemData.PaintDefault();

	} // paint visible items

CPoint point;
	VERIFY( ::GetCursorPos(&point) );
	ScreenToClient( &point );
	dc.SelectClipRgn( NULL );

	if( m_bExpandAvailable )
	{
		bool bHover =
			(rcExpand.PtInRect(point))? true : false;
		bool bPushed = bHover;
		g_PaintManager->PaintMenuExpandButton(
			dc,
			rcExpand,
			bHover,
			bPushed
			);
	} // if( m_bExpandAvailable )

	if( m_bScrollingAvailable )
	{
		if( m_nDyScrollOffset != 0 )
		{
			bool bHover =
				(rcScrollTop.PtInRect(point))? true : false;
			bool bPushed =
				(m_nScrollingDirection>0)? true : false;
			bPushed = bPushed || bHover;
			g_PaintManager->PaintPushButton(
				dc,
				true,
				rcScrollTop,
				_T("t"), // up arrow
				NULL,
				true,false/*bHover*/,bPushed,false,
				true,true,false,false,
				CExtPaintManager::__ALIGN_HORIZ_CENTER
					| CExtPaintManager::__ALIGN_VERT,
				&(g_PaintManager->m_FontMarlett)
				);
		}
		if( m_nDyScrollOffset != nMaxScrollPos )
		{
			bool bHover =
				(rcScrollBottom.PtInRect(point))? true : false;
			bool bPushed =
				(m_nScrollingDirection<0)? true : false;
			bPushed = bPushed || bHover;
			g_PaintManager->PaintPushButton(
				dc,
				true,
				rcScrollBottom,
				_T("u"), // down arrow
				NULL,
				true,false/*bHover*/,bPushed,false,
				true,true,false,false,
				CExtPaintManager::__ALIGN_HORIZ_CENTER
					| CExtPaintManager::__ALIGN_VERT,
				&(g_PaintManager->m_FontMarlett)
				);
		}
	} // if( m_bScrollingAvailable )

	if( m_nLeftAreaWidth > 0 )
	{
		CRect rcLeftArea( rcClient );
		rcLeftArea.right = rcLeftArea.left + m_nLeftAreaWidth;
		rcLeftArea.OffsetRect( nMenuBorderSize, 0 );
		rcLeftArea.DeflateRect( 0, nMenuBorderSize );
		DRAWLEFTAREADATA _DrawLeftAreaData( &dc, &rcLeftArea, this );
		_DrawLeftAreaData.DoOwnerDrawPainting();
	}

	if( m_bCombineWithEA )
	{
		ASSERT( m_eCombineAlign != __CMBA_NONE );
		dc.SelectClipRgn(NULL);
		CRect rcExcludeClient( m_rcExcludeArea );
		ScreenToClient( &rcExcludeClient );
		g_PaintManager->PaintMenuCombinedArea(
			dc,
			rcExcludeClient,
			rcClient,
			m_eCombineAlign
			);
		if( m_pCbPaintCombinedContent != NULL )
			m_pCbPaintCombinedContent(
				m_pCbPaintCombinedCookie,
				dc,
				*this,
				m_rcExcludeArea,
				m_eCombineAlign
				);
	} // if( m_bCombineWithEA )

	dc.SelectObject( pOldFont );
	if( bUseBackBuffer )
	{
		ASSERT( mdc.GetSafeHdc() != NULL );
		if( pOldPalette2 != NULL )
			mdc.SelectPalette( pOldPalette2, FALSE );
		mdc.__Flush();
	}

	if( CExtPopupMenuWnd::g_bMenuWithShadows
		&& m_bAnimFinished
		&& nMenuShadowSize > 0
		)
	{ // if we need to paint shadow for client area (and combined exclude area)
		dcPaint.SelectClipRgn(NULL);
		CRect
			rcExcludeClient( 0,0,0,0 ),
			rcExcludeScreen( 0,0,0,0 ),
			rcBaseScreen( 0,0,0,0 );
		if( m_bCombineWithEA )
		{
			if( CExtPopupMenuWnd::g_bMenuWithShadows
				&& m_bAnimFinished
				&& nMenuShadowSize > 0
				)
			{ // if we need to paint shadow for combined exclude area
				rcExcludeScreen = m_rcExcludeArea;
				rcExcludeClient = rcExcludeScreen;
				ScreenToClient( &rcExcludeClient );
				dcPaint.ExcludeClipRect( &rcClient );
				rcBaseScreen = rcClient;
				ClientToScreen( &rcBaseScreen );
				VERIFY(
					m_ShadowCMBA.Paint(
						dcPaint,
						rcExcludeClient,
						rcExcludeScreen,
						rcBaseScreen,
						nMenuShadowSize
						)
					);
				dcPaint.SelectClipRgn(NULL);
			} // if we need to paint shadow for combined exclude area

			CRect rcExcludePart( m_rcExcludeArea );
			ScreenToClient( &rcExcludePart );
			dcPaint.ExcludeClipRect( &rcExcludePart );
		} // if( m_bCombineWithEA )
		VERIFY(
			m_ShadowMain.Paint(
				dcPaint,
				rcClient,
				rcBaseScreen,
				rcExcludeScreen,
				nMenuShadowSize
				)
			);
	} // if we need to paint shadow for client area (and combined exclude area)

	if( pOldPalette != NULL )
		dcPaint.SelectPalette( pOldPalette, FALSE );
}

#if _MFC_VER < 0x700
void CExtPopupMenuWnd::OnActivateApp(BOOL bActive, HTASK hTask) 
#else
void CExtPopupMenuWnd::OnActivateApp(BOOL bActive, DWORD hTask) 
#endif
{
	ASSERT_VALID( this );
	bActive;
	hTask;
	_OnCancelMode();
}

bool CExtPopupMenuWnd::_StartScrolling(int nButtonIndex)
{
	ASSERT_VALID( this );

	if( GetSafeHwnd() == NULL )
		return FALSE;

	if( (nButtonIndex == IDX_SCROLL_TOP
			|| nButtonIndex == IDX_SCROLL_BOTTOM)
//		&& m_nCurIndex != nButtonIndex
		)
	{
		ASSERT( m_bScrollingAvailable );
		_ItemFocusDelay();
		_ItemFocusCancel( FALSE );
		m_nCurIndex = nButtonIndex;
		Invalidate( FALSE );
		SetTimer(
			ID_TIMER_SCROLLING,
			ID_PERIOD_SCROLLING,
			NULL
			);
		_SetCapture();
		return true;
	}
	return false;
}

bool CExtPopupMenuWnd::_OnMouseClick(UINT nFlags, CPoint point)
{
	ASSERT_VALID( this );

	if( GetSafeHwnd() == NULL )
		return false;

	if( !m_bAnimFinished )
		return true;

CExtPopupMenuSite & _site = GetSite();
	if(	_site.IsShutdownMode()
		|| _site.IsEmpty()
		|| _site.GetAnimated() != NULL
		)
		return true;

CRect rectWindow;
	GetWindowRect( &rectWindow );
	ScreenToClient( &rectWindow );
	if( !rectWindow.PtInRect(point) )
	{
		if( m_pWndParentMenu != NULL
			&& m_pWndParentMenu->GetSafeHwnd() != NULL
			)
		{
			ASSERT_VALID( m_pWndParentMenu );
			ClientToScreen( &point );
			m_pWndParentMenu->ScreenToClient( &point );

			HWND hWndOwn = GetSafeHwnd();
			ASSERT( hWndOwn != NULL );
			ASSERT( ::IsWindow(hWndOwn) );
			CExtPopupMenuWnd * pWndParentMenu = m_pWndParentMenu;
			if(	pWndParentMenu->_OnMouseClick(
					nFlags,
					point
					)
				)
			{
				if( ::IsWindow(hWndOwn) )
					_OnCancelMode();
				return true;
			}
			return false;
		}

		// fixed in v. 2.20
		if( nFlags == WM_RBUTTONUP
			|| nFlags == WM_LBUTTONUP
			)
		{
			return true;
		}

		_OnCancelMode();
		return false;
	}

int nHitTest = _HitTest( point );
	if( _StartScrolling(nHitTest) )
		return true;

	if( nHitTest < 0 )
	{
		if( (nHitTest == IDX_SCROLL_TOP
				|| nHitTest == IDX_SCROLL_BOTTOM)
			//&& m_nCurIndex != nHitTest
			)
		{
			return true;
		}

		if( nHitTest == IDX_EXPAND )
		{
			if(	(!m_bExpandWasPressed)
				&& m_bExpandAvailable
				)
				_DoExpand();
			return true;
		}

		// fixed in v. 2.20
		if( nFlags != WM_RBUTTONUP
			&& nFlags != WM_LBUTTONUP
			)
		//if( nFlags != WM_RBUTTONUP )
		{
			_OnCancelMode();
			return true;
		}

		return false;
	}
	ASSERT( nHitTest < m_items_all.GetSize() );

MENUITEMDATA & mi = _GetItemRef(nHitTest);
	if( (!mi.IsEnabled()) || mi.IsSeparator() )
		//return false;
		return true;
	if( mi.IsPopup() )
	{
		if( mi.GetPopup()->GetSafeHwnd() != NULL )
			return false;
		_ItemFocusSet(
			nHitTest,
			TRUE,
			TRUE
			);
		return true;
	}

	if( mi.IsExecutableCmdID() )
		_EndSequence( mi.GetCmdID(), mi.GetCmdReciever() );
	else
		_OnCancelMode();
//	return false;
	return true;
}

void CExtPopupMenuWnd::_EndSequence(
	UINT nCmdID, // = 0
	HWND hWndDeliver // = NULL
	)
{
	ASSERT_VALID( this );

#ifdef _DEBUG
	if( hWndDeliver != NULL )
	{
		ASSERT( ::IsWindow(hWndDeliver) );
	}
#endif // _DEBUG
	ASSERT( m_hWndCmdReciever != NULL );
	ASSERT( ::IsWindow(m_hWndCmdReciever) );

CExtPopupMenuSite & _site = GetSite();
UINT * lpnResultCmdID = _site.GetTargetCmdIdPtr();
	if( lpnResultCmdID != NULL )

		*lpnResultCmdID = nCmdID;
CExtCmdManager::cmd_t * p_cmd = NULL;
	if( nCmdID > 0 && ((m_dwTrackFlags&TPMX_NO_WM_COMMAND)==0) )
	{
		p_cmd =
			g_CmdManager->CmdGetPtr(
				g_CmdManager->ProfileNameFromWnd( m_hWndCmdReciever ),
				nCmdID
				);
		ASSERT( p_cmd != NULL );
	} // if( nCmdID > 0 && ((m_dwTrackFlags&TPMX_NO_WM_COMMAND)==0) )

CExtPopupMenuWnd * pTopPopup = _site.GetInstance();
	ASSERT_VALID( pTopPopup );
HWND hWndTopPopup = pTopPopup->GetSafeHwnd();
	ASSERT(
		hWndTopPopup != NULL
		&& ::IsWindow( hWndTopPopup )
		);

	if( hWndDeliver == NULL )
		hWndDeliver = m_hWndCmdReciever;

CWnd * pTopLevelParent = GetTopLevelParent();
HWND hWndTopLevelParent = pTopLevelParent->GetSafeHwnd();

CRect rcBkUpdate( 0, 0, 0, 0 );
	// hide all sequence
	CExtPopupMenuWnd * pPopup = this;
	for( ; pPopup != NULL; pPopup = pPopup->m_pWndParentMenu )
	{
		ASSERT_VALID( pPopup );
		ASSERT( pPopup->GetSafeHwnd() != NULL );
		ASSERT( ::IsWindow( pPopup->GetSafeHwnd() ) );
		CRect rcPopup;
		pPopup->GetWindowRect( &rcPopup );
		if( rcBkUpdate.IsRectEmpty() )
			rcBkUpdate = rcPopup;
		else
		{
			CRect rcPrev( rcBkUpdate );
			rcBkUpdate.UnionRect( &rcPrev, &rcPopup );
		}
		if(	pPopup->m_wndToolTip.GetSafeHwnd() != NULL
			&& ::IsWindow( pPopup->m_wndToolTip.GetSafeHwnd() )
			&& pPopup->m_wndToolTip.IsWindowVisible()
			)
		{
			CRect rcToolTip;
			pPopup->m_wndToolTip.GetWindowRect( &rcToolTip );
			CRect rcPrev( rcBkUpdate );
			rcBkUpdate.UnionRect( &rcPrev, &rcToolTip );
		}
		pPopup->ShowWindow( SW_HIDE );
	} // for( ; pPopup != NULL; pPopup = pPopup->m_pWndParentMenu )

	// allow bottom windows repaint
	if(	!rcBkUpdate.IsRectEmpty()
		&&	hWndTopLevelParent != NULL
		&& ::IsWindow(hWndTopLevelParent)
		)
	{
		::ScreenToClient(
			hWndTopLevelParent, (LPPOINT)&rcBkUpdate);
		::ScreenToClient(
			hWndTopLevelParent, ((LPPOINT)&rcBkUpdate)+1
			);
		if(		(	(DWORD)
					::GetWindowLong(
						hWndTopLevelParent,
						GWL_EXSTYLE
						)
				) & WS_EX_LAYOUTRTL
			)
			CRect::SwapLeftRight( &rcBkUpdate );
		::RedrawWindow(
			hWndTopLevelParent,
			&rcBkUpdate,
			NULL,
			RDW_INVALIDATE|RDW_ERASE
				|RDW_UPDATENOW|RDW_ERASENOW
				|RDW_VALIDATE
				|RDW_FRAME|RDW_ALLCHILDREN
			);
	}

	// top popup (and all children) finally must be closed
	if( ::IsWindow( hWndTopPopup ) )
		::PostMessage( hWndTopPopup, WM_CLOSE, 0, 0 );

	if( p_cmd != NULL && ::IsWindow(hWndDeliver) )
	{
		// if command target still exists -> deliver command to it
		VERIFY( p_cmd->Deliver(hWndDeliver) );
		g_SoundPlayer->PlaySound(
			CExtSoundPlayer::__ON_MENU_CMD_CLICKED
			);
	} // if( p_cmd != NULL && ::IsWindow(hWndDeliver) )
	if( CExtToolControlBar::g_bMenuTracking )
		CExtToolControlBar::_CloseTrackingMenus();
}

//
//void CExtPopupMenuWnd::OnMouseMove(UINT nFlags, CPoint point) 
//{
//	//CExtPopupBaseWnd::OnMouseMove(nFlags, point);
//	if( _GetCapture() == this )
//		_OnMouseMove(nFlags, point);
//}
//void CExtPopupMenuWnd::OnLButtonDown(UINT nFlags, CPoint point)
//{
//	//CExtPopupBaseWnd::OnLButtonDown(nFlags, point);
//	if( _GetCapture() == this )
//		_OnMouseClick(nFlags,point);
//}
//void CExtPopupMenuWnd::OnLButtonUp(UINT nFlags, CPoint point) 
//{
//	//CExtPopupBaseWnd::OnLButtonUp(nFlags, point);
//}
//void CExtPopupMenuWnd::OnLButtonDblClk(UINT nFlags, CPoint point) 
//{
//	//CExtPopupBaseWnd::OnLButtonDblClk(nFlags, point);
//}
//void CExtPopupMenuWnd::OnMButtonDown(UINT nFlags, CPoint point) 
//{
//	OnLButtonDown(nFlags, point);
//}
//void CExtPopupMenuWnd::OnMButtonUp(UINT nFlags, CPoint point) 
//{
//	OnLButtonUp(nFlags, point);
//}
//void CExtPopupMenuWnd::OnMButtonDblClk(UINT nFlags, CPoint point) 
//{
//	OnLButtonDblClk(nFlags, point);
//}
//void CExtPopupMenuWnd::OnRButtonDown(UINT nFlags, CPoint point) 
//{
//	OnLButtonDown(nFlags, point);
//}
//void CExtPopupMenuWnd::OnRButtonUp(UINT nFlags, CPoint point) 
//{
//	OnLButtonUp(nFlags, point);
//}
//void CExtPopupMenuWnd::OnRButtonDblClk(UINT nFlags, CPoint point) 
//{
//	OnLButtonDblClk(nFlags, point);
//}
//  
//void CExtPopupMenuWnd::OnKeyDown(UINT nChar, UINT nRepCnt, UINT nFlags) 
//{
//	//CExtPopupBaseWnd::OnKeyDown(nChar, nRepCnt, nFlags);
//	if( _GetCapture() == this )
//		_OnKeyDown(nChar, nRepCnt, nFlags);
//}
//void CExtPopupMenuWnd::OnKeyUp(UINT nChar, UINT nRepCnt, UINT nFlags) 
//{
//	//CExtPopupBaseWnd::OnKeyUp(nChar, nRepCnt, nFlags);
//}
//void CExtPopupMenuWnd::OnSysKeyDown(UINT nChar, UINT nRepCnt, UINT nFlags) 
//{
//	//CExtPopupBaseWnd::OnSysKeyDown(nChar, nRepCnt, nFlags);
//}
//void CExtPopupMenuWnd::OnSysKeyUp(UINT nChar, UINT nRepCnt, UINT nFlags) 
//{
//	//CExtPopupBaseWnd::OnSysKeyUp(nChar, nRepCnt, nFlags);
//}
//void CExtPopupMenuWnd::OnSysDeadChar(UINT nChar, UINT nRepCnt, UINT nFlags) 
//{
//	//CExtPopupBaseWnd::OnSysDeadChar(nChar, nRepCnt, nFlags);
//}
//void CExtPopupMenuWnd::OnChar(UINT nChar, UINT nRepCnt, UINT nFlags) 
//{
//	//CExtPopupBaseWnd::OnChar(nChar, nRepCnt, nFlags);
//}
//

void CExtPopupMenuWnd::OnCancelMode() 
{
	ASSERT_VALID( this );
	//_OnCancelMode();
CExtPopupMenuSite & _site = GetSite();
	_site.DoneInstance();
	ASSERT( _site.IsEmpty() );
	ASSERT( !_site.IsShutdownMode() );
}

void CExtPopupMenuWnd::_FreeWinObjects()
{
	ASSERT_VALID( this );

	if( m_rgnWnd.GetSafeHandle() != NULL )
	{
		VERIFY(
			m_rgnWnd.DeleteObject()
			);
	}
	m_ShadowMain.Destroy();
	m_ShadowCMBA.Destroy();
	_SurfacesDelete();
	if( !(::IsWindow(GetSafeHwnd())) )
		return;
	KillTimer(ID_TIMER_ANIMATION);
	//KillTimer(ID_TIMER_DELAY_SHOW);
	//KillTimer(ID_TIMER_ITEM_FOCUS_DELAY);
	//KillTimer(ID_TIMER_SCROLLING);
}

void CExtPopupMenuWnd::_OnCancelMode(
	bool bNcDestroy // = false
	) 
{
	ASSERT_VALID( this );

	_FreeWinObjects();
	_ReleaseCapture();

INT iter = 0;
	for( ; iter < m_items_all.GetSize(); iter++ )
	{
		MENUITEMDATA & mi = m_items_all[ iter ];
		mi.SetSelected( false );

		if( mi.IsPopup() )
		{
			if( mi.GetPopup()->GetSafeHwnd() != NULL )
				mi.GetPopup()->_OnCancelMode();
		}
	}
	m_nCurIndex = IDX_NOTHING;

	if( bNcDestroy )
		return;

	if( ! ::IsWindow(GetSafeHwnd()) )
		return;
	ShowWindow( SW_HIDE );
	PostMessage( WM_CLOSE );

	if( CExtToolControlBar::g_bMenuTracking )
	{
		if( m_bTopLevel )
			CExtToolControlBar::_CloseTrackingMenus();
	}
}

void CExtPopupMenuWnd::_ItemFocusSet(
	int nCurIndex,
	BOOL bEnableDropChild,
	BOOL bRepaint
	)
{
	ASSERT_VALID( this );

	if( m_nCurIndex != nCurIndex )
	{
		_ItemFocusCancel( FALSE );
		ASSERT( m_nCurIndex < 0 );
		m_nCurIndex = nCurIndex;
		if( m_nCurIndex < 0 )
			return;
	}

bool bWasSet = false;
MENUITEMDATA & mi = _GetItemRef(m_nCurIndex);
	if( mi.IsEnabled() && mi.IsDisplayed() )
	{
		mi.SetSelected( true );
		bWasSet = true;

		// adjust scrolling
		int nMenuBorderSize =
			g_PaintManager->GetMenuBorderSize();
		if( m_bScrollingAvailable )
		{
			int nMetric;
			int nMaxScrollPos = _GetMaxScrollPos();
			CRect rcItem,rcClient,
				rcScrollBtnUp,rcScrollBtnDown;
			_GetItemRect( IDX_SCROLL_TOP, rcScrollBtnUp );
			_GetItemRect( IDX_SCROLL_BOTTOM, rcScrollBtnDown );
			_GetClientRect( rcClient );
			_GetItemRect( m_nCurIndex, rcItem );

			nMetric = rcClient.bottom;
			if( m_nDyScrollOffset != nMaxScrollPos )
			{
				nMetric -= rcScrollBtnDown.Height();
				if( m_bExpandAvailable )
				{
					CRect rcExpand;
					_GetItemRect( IDX_EXPAND, rcExpand );
					nMetric -= rcExpand.Height();
				}
			}
			if( rcItem.bottom >= nMetric )
			{
				m_nDyScrollOffset -=
					rcItem.bottom - nMetric
					+ nMenuBorderSize*2;
			}

			nMetric = rcClient.top;
			if( m_nDyScrollOffset != 0 )
			{
				nMetric += rcScrollBtnUp.Height();
			}
			if( rcItem.top <= nMetric )
			{
				m_nDyScrollOffset +=
					nMetric - rcItem.top
					+ nMenuBorderSize*2;
			}

			if( m_nDyScrollOffset > 0 )
				m_nDyScrollOffset = 0;
			else
			{
				if( m_nDyScrollOffset < nMaxScrollPos )
					m_nDyScrollOffset = nMaxScrollPos;
			}
		} // if( m_bScrollingAvailable )

	}
	if( bWasSet )
	{
		// update status bar message
		CWnd * pWndOwner = GetOwner();
		if( pWndOwner != NULL )
		{
			ASSERT_VALID( pWndOwner );
			WPARAM iStatusUpdateValue = (WPARAM)AFX_IDS_IDLEMESSAGE;
			UINT nCmdID = mi.GetCmdID();
			if( CExtCmdManager::IsCommand(nCmdID) )
				iStatusUpdateValue = (WPARAM)nCmdID;
			pWndOwner->SendMessage(
				WM_SETMESSAGESTRING,
				iStatusUpdateValue
				);
		} // if( pWndOwner != NULL )
	} // if( bWasSet )
	
	if( bRepaint && ::IsWindowVisible(GetSafeHwnd()) )
	{
//		if( m_rgnWnd.GetSafeHandle() != NULL )
//			RedrawWindow(
//				NULL,
//				&m_rgnWnd,
//				RDW_INVALIDATE|RDW_UPDATENOW|RDW_NOERASE
//					|RDW_INTERNALPAINT
//				);
//		else
//		{
			CClientDC dc( this );
			_DoPaint( dc );
//		}
	}
	
	if( bWasSet
		&& bEnableDropChild
		&& mi.IsPopup()
		&& mi.GetPopup()->GetSafeHwnd() == NULL
		)
	{ // if new popup tracking
		_ReleaseCapture();
		CRect rectItem;
		_GetItemRect(
			m_nCurIndex,
			rectItem
			);
		rectItem.left -= m_nLeftAreaWidth;
		CPoint point;
		point.x = rectItem.right;
		point.y = rectItem.top,
		ClientToScreen(&point);
		ClientToScreen( &rectItem );
		ASSERT( mi.GetPopup()->m_pWndParentMenu == this );
		if(	mi.GetPopup()->_TrackPopupMenu(
				0,
				point.x,point.y,
				&rectItem
				)
			)
		{ // if track-popup succeeded
			int nCountOfPopupItems =
				mi.GetPopup()->m_items_all.GetSize();
			if( nCountOfPopupItems > 0 )
			{
				int nIndex = mi.GetPopup()->_GetNextItem(__NI_ANY);
				if( nIndex >= 0 )
					mi.GetPopup()->_ItemFocusSet(
						nIndex,
						FALSE,
						( GetSite().GetAnimated() == NULL ) ?
							TRUE : FALSE
						);
			}
		} // if track-popup succeeded
	} // if new popup tracking
}

bool CExtPopupMenuWnd::_CoolTipIsVisible()
{
	ASSERT_VALID( this );

	if( !(::IsWindow(GetSafeHwnd())) )
		return false;
	if( CExtPopupMenuSite::g_DefPopupMenuSite.GetCapture() != this )
		return false;
HWND hWndToolTip =
		m_wndToolTip.GetSafeHwnd();
	if(	hWndToolTip != NULL
		&&
		::IsWindow( hWndToolTip )
		&&
		::IsWindowVisible( hWndToolTip )
		)
		return true;
	return false;
}

void CExtPopupMenuWnd::_CoolTipHide(
	bool bAdvOperation // = true
	)
{
	ASSERT_VALID( this );

	if( !(::IsWindow(GetSafeHwnd())) )
		return;

HWND hWndToolTip =
		m_wndToolTip.GetSafeHwnd();
	if(	hWndToolTip == NULL
		||
		(!(::IsWindow(hWndToolTip)))
		)
		return;
	
	if( bAdvOperation && ( GetSite().GetAnimated() == NULL ) )
	{
		m_AnimationType = __AT_CONTENT_DISPLAY;
		_StartAnimation();
	}
	m_wndToolTip.Hide();

}

void CExtPopupMenuWnd::_ItemFocusCancel( BOOL bRepaint )
{
	ASSERT_VALID( this );

	_CoolTipHide();

	if( m_nCurIndex < 0 )
	{
		m_nCurIndex = IDX_NOTHING;
	} // if( m_nCurIndex < 0 )
	else
	{
		ASSERT( m_nCurIndex < m_items_all.GetSize() );
		MENUITEMDATA & mi = _GetItemRef(m_nCurIndex);
		mi.SetSelected( false );
		m_nCurIndex = IDX_NOTHING;

		if( mi.IsPopup() )
			mi.GetPopup()->_OnCancelMode();
	} // else from if( m_nCurIndex < 0 )
	
	if( bRepaint && ::IsWindowVisible(GetSafeHwnd()) )
	{
		CClientDC dc( this );
		_DoPaint( dc );
	}
}

bool CExtPopupMenuWnd::_OnMouseMove(UINT nFlags, CPoint point)
{
	ASSERT_VALID( this );

	if( GetSafeHwnd() == NULL )
		return false;

	if( !m_bAnimFinished )
		return true;

CExtPopupMenuSite & _site = GetSite();
	if(	_site.IsShutdownMode()
		|| _site.IsEmpty()
		|| _site.GetAnimated() != NULL
		)
		return true;

CRect rectWindow;
	GetWindowRect( &rectWindow );
	ScreenToClient( &rectWindow );
	if( !rectWindow.PtInRect(point) )
	{
//		_ItemFocusCancel( TRUE );
		if( m_pWndParentMenu != NULL
			&& m_pWndParentMenu->GetSafeHwnd() != NULL
			)
		{
			ASSERT_VALID( m_pWndParentMenu );
			ClientToScreen( &point );
			m_pWndParentMenu->ScreenToClient( &point );
			if( m_pWndParentMenu->_OnMouseMove(nFlags, point) )
			{
				_OnCancelMode();
				return true;
			}
		}
		return false;
	}

int nCurIndex = _HitTest(point);
	if( nCurIndex == IDX_EXPAND )
	{
		_ItemFocusCancel( TRUE );
		_SetCapture();
		if( m_nWaitingExpandTickCount == 0 )
		{
			SetTimer(
				ID_TIMER_DELAY_EXPAND,
				ID_TOTAL_DELAY_EXPAND/ID_FREQ_DELAY_EXPAND,
				NULL
				);
			m_nWaitingExpandTickCount = 1;
		}
		return true;
	}
	if( _StartScrolling(nCurIndex) )
		return true;

	if( nCurIndex >= 0 )
	{
#ifdef _DEBUG
		int nCountOfItems = m_items_all.GetSize();
		ASSERT( nCurIndex < nCountOfItems );
#endif // _DEBUG
		MENUITEMDATA & mi = _GetItemRef(nCurIndex);
		if( (!mi.IsEnabled()) || mi.IsSeparator() )
			return false;
		int nOldCurIndex = m_nCurIndex; 
		if( nOldCurIndex != nCurIndex )
		{
			_ItemFocusDelay();
			_SetCapture();
			_ItemFocusSet(
				nCurIndex,
				FALSE,
				TRUE
				);
			MENUITEMDATA & mi = _GetItemRef(nCurIndex);
			if( mi.IsPopup() )
			{
				m_wndToolTip.Hide();
				if( mi.GetPopup()->GetSafeHwnd() == NULL )
					_ItemFocusDelay( nCurIndex );
				return true;
			}
			if(	g_bMenuShowCoolTips
				&& nCurIndex != nOldCurIndex
				&& GetSite().GetCapture() == this
				)
			{
				CString sTipText = mi.GetTip();
				if( !sTipText.IsEmpty() )
				{
					CRect rcItem;
					_GetItemRect(nCurIndex,rcItem);
					ClientToScreen( &rcItem );
					m_wndToolTip.SetText( (LPCTSTR)sTipText );
					VERIFY(
						m_wndToolTip.Show(
							this,
							rcItem
							)
						);
				} // if( !sTipText.IsEmpty() )
			} // if( g_bMenuShowCoolTips ....
		} // if( nOldCurIndex != nCurIndex )

		return (nOldCurIndex == nCurIndex) ? false : true;
	} // if( nCurIndex >= 0 )

	return false;
}

void CExtPopupMenuWnd::_ItemFocusDelay(
	int nItemIndex // = IDX_NOTHING
	)
{
	ASSERT_VALID( this );

	if( !(::IsWindow(GetSafeHwnd())) )
		return;
	if( m_nDelayedFocusItemIndex != nItemIndex )
	{
		if( m_nDelayedFocusItemIndex >= 0 )
			KillTimer( ID_TIMER_ITEM_FOCUS_DELAY );
		//m_nDelayedFocusItemIndex = IDX_NOTHING;
	}
	if( nItemIndex < 0 )
	{
		m_nDelayedFocusItemIndex = IDX_NOTHING;
		return;
	}
	if( m_nDelayedFocusItemIndex == nItemIndex )
		return;
	ASSERT( nItemIndex>=0 && nItemIndex<m_items_all.GetSize() );
	m_nDelayedFocusItemIndex = nItemIndex;
	ASSERT( _GetItemRef(m_nDelayedFocusItemIndex).IsPopup() );
	SetTimer(
		ID_TIMER_ITEM_FOCUS_DELAY,
		ID_PERIOD_ITEM_FOCUS_DELAY,
		NULL
		);
}

int CExtPopupMenuWnd::_GetMaxScrollPos()
{
	ASSERT_VALID( this );

	ASSERT( m_bScrollingAvailable );
CRect rcClient;
	_GetClientRect( &rcClient );
int nClientHeight =
		rcClient.Height();
int nMenuBorderSize =
		g_PaintManager->GetMenuBorderSize();
int nMenuShadowSize =
		_GetMenuShadowSize();
int nMaxScrollPos = m_sizeFullItems.cy;
	nMaxScrollPos += nMenuBorderSize*2;
	nMaxScrollPos += nMenuShadowSize;
	nMaxScrollPos -= nClientHeight;
	ASSERT( nMaxScrollPos > 0 );
	if( m_bExpandAvailable )
		nMaxScrollPos += _GetSpecBtnHeight(); // xpand btn
	return -nMaxScrollPos;
}

void CExtPopupMenuWnd::OnTimer(UINT nIDEvent) 
{
	ASSERT_VALID( this );

	switch( nIDEvent )
	{
	case ID_TIMER_DELAY_EXPAND:
	{
		if( m_nWaitingExpandTickCount <
				ID_TOTAL_DELAY_EXPAND
			)
		{
			if( m_nWaitingExpandTickCount <= 1 )
				m_nWaitingExpandTickCount = 0;
			m_nWaitingExpandTickCount +=
				ID_FREQ_DELAY_EXPAND;
			return;
		}
		VERIFY( KillTimer(ID_TIMER_DELAY_EXPAND) );
		m_nWaitingExpandTickCount = 0;
		if( m_bExpandAvailable
			&& (!m_bExpandWasPressed)
			&& ( GetSite().GetAnimated() == NULL )
			)
		{ // if expand can be performed
			CPoint point;
			VERIFY( ::GetCursorPos(&point) );
			ScreenToClient( &point );
			CRect rcExpand;
			_GetItemRect( IDX_EXPAND, rcExpand );
			if( rcExpand.PtInRect(point) )
				_DoExpand();
		} // if expand can be performed
		return;
	}
	//case ID_TIMER_DELAY_EXPAND

	case ID_TIMER_SCROLLING:
	{
		_ItemFocusDelay();
		if( m_nCurIndex >= 0 )
			_ItemFocusCancel(TRUE);

		CPoint point;
		VERIFY( ::GetCursorPos(&point) );
		ScreenToClient( &point );

		m_nScrollingDirection = 0;

		CRect rcItem;
		_GetItemRect(IDX_SCROLL_TOP,rcItem);
		if( rcItem.PtInRect(point) )
			m_nScrollingDirection = __SCROLLING_PIXEL_STEP;
		else
		{
			_GetItemRect(IDX_SCROLL_BOTTOM,rcItem);
			if( rcItem.PtInRect(point) )
				m_nScrollingDirection = (-__SCROLLING_PIXEL_STEP);
		}

		m_nDyScrollOffset += m_nScrollingDirection;

		bool bKillThisTimer =
			(m_nScrollingDirection == 0) ? true : false;
		if( m_nDyScrollOffset > 0 )
		{
			m_nDyScrollOffset = 0;
			bKillThisTimer = true;
		}
		else
		{
			int nMaxScrollPos = _GetMaxScrollPos();
			if( m_nDyScrollOffset < nMaxScrollPos )
			{
				m_nDyScrollOffset = nMaxScrollPos;
				bKillThisTimer = true;
			}
		}

		if( bKillThisTimer )
		{
			VERIFY( KillTimer(ID_TIMER_SCROLLING) );
		}
		Invalidate( FALSE );
		return;
	}
	// case ID_TIMER_SCROLLING

	case ID_TIMER_ITEM_FOCUS_DELAY:
	{
		if( GetSite().GetAnimated() != NULL )
			return;
		KillTimer( ID_TIMER_ITEM_FOCUS_DELAY );
		if( m_nDelayedFocusItemIndex >= 0 )
		{
			ASSERT( m_nDelayedFocusItemIndex>=0 && m_nDelayedFocusItemIndex<m_items_all.GetSize() );
			ASSERT( _GetItemRef(m_nDelayedFocusItemIndex).IsPopup() );
			CRect rcItem;
			_GetItemRect(m_nDelayedFocusItemIndex,rcItem);
			CPoint point;
			VERIFY( ::GetCursorPos( &point ) );
			ScreenToClient( &point );
			if( rcItem.PtInRect(point) )
			{
				_ItemFocusSet(
					m_nDelayedFocusItemIndex,
					TRUE,
					TRUE
					);
			}
		} // if( m_nDelayedFocusItemIndex >= 0 )
		m_nDelayedFocusItemIndex = IDX_NOTHING;
		return;
	}
	// case ID_TIMER_ITEM_FOCUS_DELAY
	
	default:
		CExtPopupBaseWnd::OnTimer(nIDEvent);
	break; // default
	} // switch( nIDEvent )
}

CExtPopupMenuWnd * CExtPopupMenuWnd::_GetCapture()
{
	return GetSite().GetCapture();
}

void CExtPopupMenuWnd::_SetCapture()
{
	ASSERT_VALID( this );

CExtPopupMenuSite & _site = GetSite();
	if( GetSafeHwnd() != NULL )
	{
		ASSERT( ::IsWindow(GetSafeHwnd()) );
		_site.SetCapture( this );
	}
	else
		_site.SetCapture( NULL );
}

void CExtPopupMenuWnd::_ReleaseCapture()
{
	ASSERT_VALID( this );

CExtPopupMenuSite & _site = GetSite();
	if( _site.IsEmpty()
		|| _site.IsShutdownMode()
		)
		return;
	if( _site.GetCapture() == this )
		_site.SetCapture( NULL );
}

int CExtPopupMenuWnd::_GetNextItem(
	next_item_t nit
	)
{
	ASSERT_VALID( this );

int nCountOfItems = m_items_all.GetSize();
bool bCanExpand = false;
	if( m_bExpandAvailable
		&& (!m_bExpandWasPressed)
		)
	{
		if( IsAllItemsRarelyUsed() )
			return IDX_EXPAND;
		bCanExpand = true;
	}
	if( nit == __NI_NOTHING ||  nCountOfItems == 0 )
	{
		if( bCanExpand )
			return IDX_EXPAND;
		return IDX_NOTHING;
	}

	if( nit == __NI_ANY && m_nCurIndex >= 0 )
		return m_nCurIndex;

	if( m_nCurIndex < 0 )
	{
		INT iter = 0;
		for( ; iter < m_items_all.GetSize(); ++iter )
		{
			MENUITEMDATA & mi = m_items_all[ iter ];
			if( mi.IsEnabled() && mi.IsDisplayed() )
				return mi.GetIndex();
		}
		if( bCanExpand )
			return IDX_EXPAND;
		return IDX_NOTHING;
	}

	if( nit == __NI_NEXT )
	{
		if( nCountOfItems < 2 )
		{
			if( bCanExpand )
				return IDX_EXPAND;
			return IDX_NOTHING;
		}

		INT iter = m_nCurIndex + 1;
		for( ; iter < m_items_all.GetSize(); ++iter )
		{
			MENUITEMDATA & mi = m_items_all[ iter ];
			if( mi.IsEnabled() && mi.IsDisplayed() )
				return mi.GetIndex();
		}
		if( bCanExpand )
			return IDX_EXPAND;
		if( m_nCurIndex == 0 )
			return IDX_NOTHING;
		iter = 0;
		INT iter2 = m_nCurIndex - 1;
		do
		{
			MENUITEMDATA & mi = m_items_all[ iter ];
			if( mi.IsEnabled() && mi.IsDisplayed() )
				return mi.GetIndex();
			iter++;
		} while( iter != iter2 );
		return IDX_NOTHING;
	}
	if( nit == __NI_PREV )
	{
		if( nCountOfItems < 2 )
			return IDX_NOTHING;

		if( m_nCurIndex != 0 )
		{
			int nIndex = m_nCurIndex - 1;
			INT iter = nIndex;
			for( ; true;  )
			{
				MENUITEMDATA & mi = m_items_all[ iter ];
				if( mi.IsEnabled() && mi.IsDisplayed() )
					return mi.GetIndex();
				if( nIndex == 0 )
					break;
				--iter;
				--nIndex;
			}
		}
		int nIndex = m_nCurIndex + 1;
		INT iter2 = nIndex;
		INT iter = m_items_all.GetSize() - 1;
		do
		{
			MENUITEMDATA & mi = m_items_all[ iter ];
			if( mi.IsEnabled() && mi.IsDisplayed() )
				return mi.GetIndex();
			iter--;
		} while( iter != iter2 );

		return IDX_NOTHING;
	}

	return IDX_NOTHING;
}

bool CExtPopupMenuWnd::_OnKeyDown(UINT nChar, UINT nRepCnt, UINT nFlags)
{
	ASSERT_VALID( this );

	ASSERT( m_hWndCmdReciever != NULL );
	ASSERT( ::IsWindow(m_hWndCmdReciever) );

	nRepCnt;
	if( GetSafeHwnd() == NULL )
		return true;

	if( !m_bAnimFinished )
		return true;

CExtPopupMenuSite & _site = GetSite();
	if(	_site.IsShutdownMode()
		|| _site.IsEmpty()
		|| _site.GetAnimated() != NULL
		)
		return true;

next_item_t nit = __NI_NOTHING;
	switch( nChar )
	{
	case VK_MENU:
		_EndSequence();
		return true;
	case VK_RETURN:
	case VK_SPACE:
	{
		if( m_nCurIndex < 0 )
			return true; // break;
		MENUITEMDATA & mi = _GetItemRef(m_nCurIndex);
		if( mi.IsExecutableCmdID() )
		{
			_EndSequence( mi.GetCmdID(), mi.GetCmdReciever() );
			return true; // break;
		}
	} // case VK_SPACE or VK_RETURN

	case VK_RIGHT:
	{
		bool bSendChangeMenu = false;
		if( m_nCurIndex < 0 )
		{
			if( m_items_all.GetSize() == 0 )
				return true; // false;
//			nit = __NI_ANY;
			bSendChangeMenu = true;
		}
		else
		{
			MENUITEMDATA & mi = _GetItemRef(m_nCurIndex);
			if( !mi.IsPopup() )
			{
				bSendChangeMenu = true;
			}
			else
			{
				if( mi.GetPopup()->GetSafeHwnd() == NULL )
				{
					_ItemFocusDelay();
					_ItemFocusSet(
						m_nCurIndex,
						TRUE,
						TRUE
						);
				}
			}
		}
		if( bSendChangeMenu && nChar==VK_RIGHT )
		{
			ASSERT( m_hWndCmdReciever != NULL );
			ASSERT( ::IsWindow(m_hWndCmdReciever) );
			if( CExtToolControlBar::g_bMenuTracking )
				::PostMessage(
					m_hWndCmdReciever,
					CExtPopupMenuWnd::g_nMsgPopupNext,
					0,
					LPARAM( this )
					);
			return true;
		}
	}
	break; // case VK_RIGHT

	case VK_LEFT:
		if( m_pWndParentMenu == NULL )
		{
			if( CExtToolControlBar::g_bMenuTracking )
				::PostMessage(
					m_hWndCmdReciever,
					CExtPopupMenuWnd::g_nMsgPopupPrev,
					0,
					LPARAM( this )
					);
			return true;
		}
		else
		{
			ASSERT( !m_bTopLevel );
			int nParentCurIndex =
				m_pWndParentMenu->m_nCurIndex;
			ASSERT(
				nParentCurIndex >= 0
				&&
				nParentCurIndex <=
					m_pWndParentMenu->m_items_all.GetSize()
				);
			m_pWndParentMenu->_ItemFocusCancel(
				FALSE
				);
			m_pWndParentMenu->_ItemFocusSet(
				nParentCurIndex,
				FALSE,
				TRUE
				);
			m_pWndParentMenu->_SetCapture();
			return true;
		}

	case VK_ESCAPE:
		_EndSequence();
		return true;
	// case VK_ESCAPE
	
	case VK_UP:
		nit = __NI_PREV;
	break; // case VK_UP
	case VK_DOWN:
		if( IsKeyPressed( VK_CONTROL ) )
		{
			if( m_bExpandAvailable )
				_DoExpand();
			return true;
		}
		nit = __NI_NEXT;
	break; // case VK_DOWN
	case VK_NEXT:
		nit = __NI_PAGE_DOWN;
	break; // case VK_NEXT
	case VK_PRIOR:
		nit = __NI_PAGE_UP;
	break; // case VK_PRIOR

	default:
	//if( _istalnum(nChar) )
	{ // BLOCK: try analyze quick char access
		if( IsKeyPressed(VK_SHIFT)
			|| IsKeyPressed(VK_CONTROL)
			|| IsKeyPressed(VK_MENU)
			|| ( (nFlags & (1<<29)) != 0 ) // ALT pressed?
			)
			return false;
		BYTE lpKeyState[256];
		::GetKeyboardState( lpKeyState );
		UINT wScanCode = ::MapVirtualKey( nChar, 0 );
		HKL hKeyboardLayout =
			::GetKeyboardLayout(
				( ::AfxGetThread() ) -> m_nThreadID
				);
#if (defined _UNICODE)
		TCHAR szChar[2] = { _T('\0'), _T('\0') };
		::ToUnicodeEx(
			nChar,
			wScanCode,
			lpKeyState,
			szChar, 1,
			1,
			hKeyboardLayout
			);
		WORD nMapped = WORD( szChar[0] );
#else
		WORD nMapped = 0;
		::ToAsciiEx(
			nChar,
			wScanCode,
			lpKeyState,
			&nMapped,
			1,
			hKeyboardLayout
			);
		//TCHAR szChar[2] = { (TCHAR)nMapped, _T('\0') };
#endif
		INT nNextIdx =
			ItemFindByAccessChar(
				(TCHAR)nMapped,
				m_nCurIndex // (m_nCurIndex >= 0) ? m_nCurIndex : -1
				);
		if(		nNextIdx < 0
			&&	m_nCurIndex >= 0
			&&	ItemFindByAccessChar( (TCHAR)nMapped, -1 )
					== m_nCurIndex
			)
		{ // if only 1 with this char
			MENUITEMDATA & mi =
				_GetItemRef( m_nCurIndex );
			if( mi.IsExecutableCmdID() )
			{
				_EndSequence( mi.GetCmdID(), mi.GetCmdReciever() );
				return true;
			} // if( mi.IsExecutableCmdID() )
		} // if only 1 with this char
		if( m_nCurIndex != nNextIdx
			&& nNextIdx >= 0
			)
		{
			_ItemFocusSet( nNextIdx, TRUE, TRUE );
			if( ItemFindByAccessChar(
					(TCHAR)nMapped,
					nNextIdx
					) < 0
				)
			{ // if only 1 with this char
				MENUITEMDATA & mi =
					_GetItemRef( nNextIdx );
				if( mi.IsExecutableCmdID() )
				{
					_EndSequence( mi.GetCmdID(), mi.GetCmdReciever() );
					return true;
				} // if( mi.IsExecutableCmdID() )
			} // if only 1 with this char
			return true;
		}

	} // BLOCK: try analyze quick char access

	} // switch( nChar )

	if( nit != __NI_NOTHING )
	{
		int nItemIndex = _GetNextItem(nit);
		if( m_items_all.GetSize() > 0
			&& nItemIndex >= 0
			&& nItemIndex != m_nCurIndex
			)
		{
			_ItemFocusSet(
				nItemIndex,
				FALSE,
				TRUE
				);
			return true; // false;
		}
		if( nItemIndex == IDX_EXPAND )
		{
			ASSERT( m_bExpandAvailable );
			ASSERT( !m_bExpandWasPressed );
			int nItemIndex = m_nCurIndex;
			_DoExpand();
			if( nItemIndex >= 0 )
			{
				_ItemFocusSet(
					nItemIndex,
					FALSE,
					//m_bAnimFinished
					( GetSite().GetAnimated() == NULL )
						? TRUE : FALSE
					);
				int i = _GetNextItem(__NI_NEXT);
				_ItemFocusSet(
					(i>0) ? i : nItemIndex,
					FALSE,
					//m_bAnimFinished
					( GetSite().GetAnimated() == NULL )
						? TRUE : FALSE
					);
			}
			return true;
		}
	} // if( nit != __NI_NOTHING )

	return false;
}

INT CExtPopupMenuWnd::ItemFindByText(
	LPCTSTR sText,
	INT nStartIdx, // = -1
	BOOL bRestartAt0 // = TRUE
	) const
{
	bRestartAt0;
	ASSERT_VALID( this );

	if( sText == NULL || sText[0] == _T('\0') )
	{
		ASSERT( FALSE );
		return -1;
	}

int nCount = m_items_all.GetSize(); //ItemGetCount();
int nIdx = (nStartIdx >= 0) ? (nStartIdx + 1) : 0;
	for( ; nIdx < nCount; nIdx++ )
	{
		const MENUITEMDATA & mi = _GetItemRef(nIdx);
//		if( !mi.AccelCharIsSet() )
//			continue;
//		if( !mi.IsDisplayed() )
//			continue;
//		if( !mi.IsEnabled() )
//			continue;
		if( _tcscmp( sText, mi.GetText() ) == 0 )
		{
			if( nStartIdx != nIdx )
				return nIdx;
		}
	} // for( nIdx = nStartIdx; nIdx < nCount; nIdx++ )
	if( nStartIdx == 0 )
		return -1;
	for( nIdx = 0; nIdx<nStartIdx; nIdx++ )
	{
		const MENUITEMDATA & mi = _GetItemRef(nIdx);
//		if( !mi.AccelCharIsSet() )
//			continue;
//		if( !mi.IsDisplayed() )
//			continue;
//		if( !mi.IsEnabled() )
//			continue;
		if( _tcscmp( sText, mi.GetText() ) == 0 )
		{
			if( nStartIdx != nIdx )
				return nIdx;
		}
	} // for( nIdx = 0; nIdx<nStartIdx; nIdx++ )
	return -1;
}


INT CExtPopupMenuWnd::ItemFindByAccessChar(
	TCHAR chrAccess,
	INT nStartIdx, // = -1
	BOOL bRestartAt0 // = TRUE
	) const
{
	ASSERT_VALID( this );

	bRestartAt0;
	if( chrAccess == 0 )
		return -1;
TCHAR szChar[2] = { chrAccess, _T('\0') };
	::CharUpper( szChar );

int cAccelSearch = szChar[0]; //toupper(nChar);
	if( cAccelSearch == 0 )
		return -1;
int nCount = m_items_all.GetSize(); //ItemGetCount();
int nIdx = (nStartIdx >= 0) ? (nStartIdx + 1) : 0;
	for( ; nIdx < nCount; nIdx++ )
	{
		const MENUITEMDATA & mi = _GetItemRef(nIdx);
		if( !mi.AccelCharIsSet() )
			continue;
		if( !mi.IsDisplayed() )
			continue;
		if( !mi.IsEnabled() )
			continue;
		TCHAR cAccel = mi.AccelCharGet();
		if( cAccelSearch ==
				cAccel // _totupper(cAccel)
			)
		{
			if( nStartIdx != nIdx )
				return nIdx;
		}
	} // for( nIdx = nStartIdx; nIdx < nCount; nIdx++ )
	if( nStartIdx == 0 )
		return -1;
	for( nIdx = 0; nIdx<nStartIdx; nIdx++ )
	{
		const MENUITEMDATA & mi = _GetItemRef(nIdx);
		if( !mi.AccelCharIsSet() )
			continue;
		if( !mi.IsDisplayed() )
			continue;
		if( !mi.IsEnabled() )
			continue;
		TCHAR cAccel = mi.AccelCharGet();
		if( cAccelSearch ==
				cAccel // _totupper(cAccel)
				)
		{
			if( nStartIdx != nIdx )
				return nIdx;
		}
	} // for( nIdx = 0; nIdx<nStartIdx; nIdx++ )
	return -1;
}

BOOL CExtPopupMenuWnd::IsCmdKeyActivation(
	LPARAM lParam // = 0
	)
{
	if( (lParam & (1<<29)) != 0 ) // ALT pressed?
		return TRUE;
	
static int nTestKeys[] = {
	VK_MENU,VK_RMENU,VK_LMENU,
	VK_CONTROL,VK_RCONTROL,VK_LCONTROL,
	VK_SHIFT,VK_RSHIFT,VK_LSHIFT
};
	for( int i=0; i<sizeof(nTestKeys)/sizeof(int); i++ )
	{
		if( IsKeyPressed(nTestKeys[i]) )
		{
//			if(		nTestKeys[i] == VK_CONTROL
//				||	nTestKeys[i] == VK_RCONTROL
//				||	nTestKeys[i] == VK_LCONTROL
//				)
//			{
//				if( IsKeyPressed(VK_DOWN) )
//					return FALSE;
//			}
			return TRUE;
		}
	}
	return FALSE;
}

INT CExtPopupMenuWnd::ItemGetCount() const
{
	ASSERT_VALID( this );

	ASSERT_VALID( this );

//	ASSERT( GetTrackingMenu() != this );
INT nCountOfItems = m_items_all.GetSize();
	return nCountOfItems;
}

INT CExtPopupMenuWnd::ItemFindPosForCmdID(
	UINT nCmdID,
	INT nPosStart // = -1
	) const
{
	ASSERT_VALID( this );

INT nPos = (nPosStart < 0) ? 0 : nPosStart + 1;
INT nCount = ItemGetCount();
	for( ; nPos < nCount; nPos++ )
	{
		UINT nCmdID2 = ItemGetCmdID( nPos );
		if( nCmdID == nCmdID2 )
			return nPos;
	}
	return -1; // not found
}

UINT CExtPopupMenuWnd::ItemGetCmdID( // menu_item_type_t values can be returned
	INT nPos
	) const
{
	ASSERT_VALID( this );

	ASSERT( GetTrackingMenu() != this );
INT nCountOfItems = ItemGetCount();
	if( nPos < 0 || nPos >= nCountOfItems )
	{
		ASSERT( FALSE );
		return TYPE_SEPARATOR;
	}
const MENUITEMDATA & mi = _GetItemRef(nPos);
UINT nCmdID = mi.GetCmdID();
	return nCmdID;
}

bool CExtPopupMenuWnd::ItemSetPopupIcon(
	INT nPos,
	HICON hIcon // = NULL // no icon by default
	)
{
	ASSERT_VALID( this );

	ASSERT( GetTrackingMenu() != this );
INT nCountOfItems = ItemGetCount();
	if( nPos < 0 || nPos >= nCountOfItems )
	{
		ASSERT( FALSE );
		return false;
	}
MENUITEMDATA & mi = _GetItemRef(nPos);
	return mi.SetPopupIcon( hIcon );
}

bool CExtPopupMenuWnd::ItemSetPopupText(
	INT nPos,
	LPCTSTR sText // NULL if empty
	)
{
	ASSERT_VALID( this );

	ASSERT( GetTrackingMenu() != this );
INT nCountOfItems = ItemGetCount();
	if( nPos < 0 || nPos >= nCountOfItems )
	{
		ASSERT( FALSE );
		return false;
	}
MENUITEMDATA & mi = _GetItemRef(nPos);
	return mi.SetPopupText( sText );
}

bool CExtPopupMenuWnd::ItemSetPopupAccelText(
	INT nPos,
	LPCTSTR sText // NULL if empty
	)
{
	ASSERT_VALID( this );

	ASSERT( GetTrackingMenu() != this );
INT nCountOfItems = ItemGetCount();
	if( nPos < 0 || nPos >= nCountOfItems )
	{
		ASSERT( FALSE );
		return false;
	}
MENUITEMDATA & mi = _GetItemRef(nPos);
	return mi.SetPopupAccelText( sText );
}

HICON CExtPopupMenuWnd::ItemGetIcon( INT nPos ) const
{
	ASSERT_VALID( this );

	ASSERT( GetTrackingMenu() != this );
INT nCountOfItems = ItemGetCount();
	if( nPos < 0 || nPos >= nCountOfItems )
	{
		ASSERT( FALSE );
		return NULL;
	}
const MENUITEMDATA & mi = _GetItemRef(nPos);
	return ((MENUITEMDATA & )mi).GetIcon();
}

CString CExtPopupMenuWnd::ItemGetText( INT nPos ) const
{
	ASSERT_VALID( this );

	ASSERT( GetTrackingMenu() != this );
INT nCountOfItems = ItemGetCount();
	if( nPos < 0 || nPos >= nCountOfItems )
	{
		ASSERT( FALSE );
		return CString( _T("") );
	}
const MENUITEMDATA & mi = _GetItemRef(nPos);
	return CString( mi.GetText() );
}

CString CExtPopupMenuWnd::ItemGetAccelText( INT nPos ) const
{
	ASSERT_VALID( this );

	ASSERT( GetTrackingMenu() != this );
INT nCountOfItems = ItemGetCount();
	if( nPos < 0 || nPos >= nCountOfItems )
	{
		ASSERT( FALSE );
		return CString( _T("") );
	}
const MENUITEMDATA & mi = _GetItemRef(nPos);
	return CString( mi.GetAccelText() );
}

bool CExtPopupMenuWnd::ItemIsDisplayed(
	INT nPos
	) const
{
const MENUITEMDATA & mi = _GetItemRef( nPos );
	return mi.IsDisplayed();
}

void CExtPopupMenuWnd::ItemSetDisplayed(
	INT nPos,
	bool bForceDisplayed // = true
	)
{
MENUITEMDATA & mi = _GetItemRef( nPos );
	mi.SetForceDisplayed( bForceDisplayed );
	_SyncItems();
}

CExtPopupMenuWnd * CExtPopupMenuWnd::ItemGetPopup(
	INT nPos
	)
{
	ASSERT_VALID( this );

	ASSERT( GetTrackingMenu() != this );
const CExtPopupMenuWnd * pChild =
		((const CExtPopupMenuWnd *)this)->
			ItemGetPopup( nPos );
	if( pChild == NULL )
		return NULL;
	return
		const_cast
			<CExtPopupMenuWnd *>
				(pChild);
}

void CExtPopupMenuWnd::_DoExpand()
{
	ASSERT_VALID( this );

	_ItemFocusDelay();
	_CoolTipHide( false );
	if( ( GetSite().GetAnimated() != NULL )
		|| _CoolTipIsVisible()
		)
		return;

	ASSERT( m_bExpandAvailable );
	ASSERT( !m_bExpandWasPressed );
	ASSERT( ::IsWindow(GetSafeHwnd()) );
	ASSERT( ( GetSite().GetAnimated() == NULL ) );
	
//	_ItemFocusCancel( FALSE );
	
	m_bExpandWasPressed = true;
CSize m_sizeFullItems2 = m_sizeFullItems;
	_SyncItems();
	_RecalcLayoutImpl();

	if( m_sizeFullItems != m_sizeFullItems2 )
	{ // if size of all items was changed
		ASSERT(
			m_sizeFullItems.cx >= m_sizeFullItems2.cx
			&&
			m_sizeFullItems.cy >= m_sizeFullItems2.cy
			);

		CRect rcWndOld;
		GetWindowRect( &rcWndOld );
		
//		int nMenuShadowSize =
//			_GetMenuShadowSize();
//		int nMenuBorderSize =
//			g_PaintManager->GetMenuBorderSize();
//		int nXtraSz =
//			nMenuBorderSize*2 + nMenuShadowSize;
//		//	this conditional ShowWindow not work
//		//	fine coz wndclass has CS_SAVEBITS
//		if(	(m_sizeFullItems.cx - m_sizeFullItems2.cx)
//				< nXtraSz
//			||
//			(m_sizeFullItems.cy - m_sizeFullItems2.cy)
//				< nXtraSz
//			)
		{

//			_BitsRestore();
			VERIFY(
				SetWindowRgn(
					NULL,
					FALSE
					)
				);
			ShowWindow( SW_HIDE	);
			ASSERT( !IsWindowVisible() );
		}

		if( !rcWndOld.IsRectEmpty() )
		{
			CWnd * pWndTLP = GetTopLevelParent();
			if( pWndTLP != NULL )
			{
				ASSERT_VALID( pWndTLP );
				if( pWndTLP->IsWindowVisible() )
				{
					CRect rcTLP;
					pWndTLP->GetWindowRect( &rcTLP );
					if( !rcTLP.IsRectEmpty() )
					{
						CRect rcIntersection;
						if(	rcIntersection.IntersectRect(
								&rcTLP,
								&rcWndOld
								)
							)
							pWndTLP->UpdateWindow();
					} // if( !rcTLP.IsRectEmpty() )
				} // if( pWndTLP->IsWindowVisible() )
			} // if( pWndTLP != NULL )
		} // if( !rcWndOld.IsRectEmpty() )

		_FreeWinObjects();

		ASSERT( ::IsWindow(GetSafeHwnd()) );
		ASSERT( ( GetSite().GetAnimated() == NULL ) );

		m_bAnimFinished = false;
		m_AnimationType = __AT_CONTENT_DISPLAY;

		// adjust screen position
		CRect rcWnd = _CalcTrackRect();
		
		if( m_rgnWnd.GetSafeHandle() != NULL )
		{
			ASSERT( m_bExcludeAreaSpec );
			ASSERT( m_bCombineWithEA );
			ASSERT( m_eCombineAlign != __CMBA_NONE );
			CRgn rgnTmp;
			VERIFY( rgnTmp.CreateRectRgn(0,0,0,0) );
			rgnTmp.CopyRgn( &m_rgnWnd );
			ASSERT( rgnTmp.GetSafeHandle() != NULL );
			VERIFY(
				SetWindowRgn(
					(HRGN)rgnTmp.Detach(),
					FALSE
					)
				);
		} // if( m_rgnWnd.GetSafeHandle() != NULL )
		
		m_bAnimFinished = true;

		m_ePlaySoundOnAnimationFinished =
			CExtSoundPlayer::__ON_MENU_EXPAND_CLICKED;
		m_AnimationType =
			g_bMenuExpandAnimation ?
				__AT_CONTENT_EXPAND : __AT_CONTENT_DISPLAY
			;
		_StartAnimation();
		if( m_AnimationType == __AT_NONE )
		{
			m_AnimationType = __AT_CONTENT_DISPLAY;
			_StartAnimation();
			ASSERT( m_AnimationType == __AT_CONTENT_DISPLAY );
		}

		if( m_bScrollingAvailable )
			_RecalcLayoutImpl();
		SetWindowPos(
			NULL,
			rcWnd.left, rcWnd.top, rcWnd.Width(), rcWnd.Height(),
			SWP_NOACTIVATE
				|SWP_SHOWWINDOW
				//|SWP_NOREDRAW //|SWP_NOSENDCHANGING
				|SWP_NOZORDER //|SWP_NOOWNERZORDER
				//|SWP_NOCOPYBITS
			);

		ASSERT( IsWindowVisible() );

	} // if size of all items was changed
	else
		UpdateWindow();

	ASSERT( m_hWndCmdReciever != NULL );
	ASSERT( ::IsWindow(m_hWndCmdReciever) );
	::SendMessage(
		m_hWndCmdReciever,
		g_nMsgNotifyMenuExpanded,
		0,
		LPARAM( this )
		);
}

bool CExtPopupMenuWnd::IsAllItemsRarelyUsed() const
{
	ASSERT_VALID( this );

INT _iter = 0;
	for( ; _iter < m_items_all.GetSize(); ++_iter )
	{
		const MENUITEMDATA & mi = m_items_all[ _iter ];
		if( mi.IsDisplayed() )
			return false;
	} // for( ; _iter != m_items_all.end(); ++_iter )
	return true;
}

void CExtPopupMenuWnd::_SyncItems()
{
	ASSERT_VALID( this );

	ASSERT( m_hWndCmdReciever != NULL );
	ASSERT( ::IsWindow(m_hWndCmdReciever) );

	m_bExpandAvailable = false;
	m_sizeFullItems.cx = m_sizeFullItems.cy = 1;
int nItemIndex = 0;
INT _iterLast = m_items_all.GetSize();
INT _iterLastVisSep = _iterLast;
bool bAtLeastOneDisplayed = false;
INT _iter = 0;
	for( ; _iter < m_items_all.GetSize(); ++_iter )
	{
		MENUITEMDATA & mi = m_items_all[ _iter ];
		mi.SetIndex( nItemIndex++ );

		if( m_bExpandWasPressed )
		{
			mi.SetDisplayed( true );
		} // if( m_bExpandWasPressed )
		else
		{
			if( mi.IsPopup() )
			{ // if popup sub-menu
				ASSERT( mi.GetPopup() != NULL );
				mi.GetPopup()->_SyncItems();
				if( mi.IsAllItemsRarelyUsed() )
				{ // if all not displayed
					_iterLast = m_items_all.GetSize();
					mi.SetDisplayed( false );
				} // if all not displayed
				else
				{ // if at least one displayed
					_iterLast = _iter;
					_iterLastVisSep = m_items_all.GetSize();
					mi.SetDisplayed( true );
				} // if at least one displayed
			} // if popup sub-menu
			else
			{ // if separator or command item
				if( mi.IsSeparator() )
				{ // if separator
					if( _iterLast != m_items_all.GetSize()
						||
						(	 _iterLast == m_items_all.GetSize()
							&& (_iterLastVisSep == m_items_all.GetSize())
							&& bAtLeastOneDisplayed
							)
						)
					{
						_iterLastVisSep = _iter;
						mi.SetDisplayed( true );
					}
					else
					{
						_iterLast = m_items_all.GetSize();
						mi.SetDisplayed( false );
					}
				} // if separator
				else
				{ // if command item
					CExtCmdManager::cmd_t * p_cmd =
						mi.GetCmd();
					if( p_cmd->StateIsRarelyUsed() )
					{ // if command rarely used
						_iterLast = m_items_all.GetSize();
						mi.SetDisplayed( false );
					} // if command rarely used
					else
					{ // if basic command or frequently used
						_iterLast = _iter;
						_iterLastVisSep = m_items_all.GetSize();
						mi.SetDisplayed( true );
					} // if basic command or frequently used
				} // if command item
			} // if separator or command item
		} // else from if( m_bExpandWasPressed )

		if( mi.IsDisplayed() )
		{
			bAtLeastOneDisplayed = true;
			m_sizeFullItems.cy += mi.GetMeasuredHeight();
			if( m_sizeFullItems.cx < mi.GetMeasuredWidth() )
				m_sizeFullItems.cx = mi.GetMeasuredWidth();
		} // if( mi.IsDisplayed() )
		else
		{
			ASSERT( !m_bExpandWasPressed );
			m_bExpandAvailable = true;
		} // else from if( mi.IsDisplayed() )
	} // for( ; _iter < m_items_all.GetSize(); ++_iter )

	if( _iterLastVisSep != m_items_all.GetSize() )
	{ // remove last separator
		if( _iterLastVisSep >= _iterLast
			||
			_iterLast == m_items_all.GetSize()
			)
		{
			m_items_all[_iterLastVisSep].SetDisplayed( false );
			m_sizeFullItems.cy -=
				m_items_all[_iterLastVisSep].GetMeasuredHeight();
		}
	} // remove last separator

int nMixDx =
		//g_PaintManager->GetMenuBorderSize()*2
		//+ _GetMenuShadowSize()
		+ 80;
	if( m_sizeFullItems.cx < nMixDx )
		m_sizeFullItems.cx = nMixDx;
}

const CExtPopupMenuWnd * CExtPopupMenuWnd::ItemGetPopup(
	INT nPos
	) const
{
	ASSERT_VALID( this );

	ASSERT( GetTrackingMenu() != this );
INT nCountOfItems = ItemGetCount();
	if( nPos < 0 || nPos >= nCountOfItems )
	{
		ASSERT( FALSE );
		return NULL;
	}
const MENUITEMDATA & mi = _GetItemRef(nPos);
UINT nCmdID = mi.GetCmdID();
	if( nCmdID != TYPE_POPUP )
		return NULL;
	ASSERT( mi.IsPopup() );
	return mi.GetPopup();
}

BOOL CExtPopupMenuWnd::ItemRemove(
	INT nPos // = -1 // remove all
	)
{
	ASSERT_VALID( this );

	ASSERT( GetTrackingMenu() != this );

	if( nPos < 0 )
	{
		if( !_BuildItems( NULL, false ) )
		{
			ASSERT( FALSE );
			return FALSE;
		}
		_SyncItems();
		return TRUE;
	} // if( nPos < 0 )

INT nCountOfItems = ItemGetCount();
	if( nPos >= nCountOfItems )
	{
		ASSERT( FALSE );
		return FALSE;
	}

MENUITEMDATA & mi = _GetItemRef(nPos);
	if( mi.IsPopup() )
	{
		mi.GetPopup()->_OnCancelMode();
		VERIFY( mi.GetPopup()->_BuildItems( NULL, false ) );
		mi.DestroyPopup();
	}
	m_items_all.RemoveAt( nPos );
	ASSERT( nCountOfItems == m_items_all.GetSize() + 1 );

	_SyncItems();

	return TRUE;
}

BOOL CExtPopupMenuWnd::ItemInsertSpecPopup( // insert specific popup implementation
	CExtPopupMenuWnd * pSpecPopup,
	INT nPos, // = -1 // append
	LPCTSTR sText, // = NULL
	HICON hIcon // = NULL
	)
{
	ASSERT_VALID( this );

	ASSERT( pSpecPopup != NULL );

INT nCountCountOfItems = ItemGetCount();
	if( nPos < 0 )
		nPos = nCountCountOfItems;
	if( nPos > nCountCountOfItems )
	{
		ASSERT( FALSE );
		return FALSE;
	}

	ASSERT( m_hWndCmdReciever != NULL );
	ASSERT( ::IsWindow(m_hWndCmdReciever) );

MENUITEMDATA mi;
	mi.SetCmdReciever( m_hWndCmdReciever );

	pSpecPopup->m_bTopLevel = false;
	mi.SetPopup( nPos, sText, hIcon, pSpecPopup );
	ASSERT( mi.GetPopup()->m_pWndParentMenu == NULL ); // still not initialized
	ASSERT( !mi.GetPopup()->m_bTopLevel );
	mi.GetPopup()->m_pWndParentMenu = this;
	mi.SetDisplayed( true );

	_InsertItem( nPos, mi );

	if( m_bTopLevel )
		_SyncItems();
	else
	{
		ASSERT( m_pWndParentMenu != NULL );
		m_pWndParentMenu->_SyncItems();
	}

	return TRUE;
}

BOOL CExtPopupMenuWnd::ItemInsert(
	UINT nCmdID, // = TYPE_SEPARATOR,
	INT nPos, // = -1 // append
	LPCTSTR sText, // = NULL // for TYPE_POPUP only
	HICON hIcon, // = NULL // for TYPE_POPUP only
	HWND hWndSpecCmdReciever // = NULL // specific command reciever
	)
{
	ASSERT_VALID( this );

	ASSERT( GetTrackingMenu() != this );

INT nCountCountOfItems = ItemGetCount();
	if( nPos < 0 )
		nPos = nCountCountOfItems;
	if( nPos > nCountCountOfItems )
	{
		ASSERT( FALSE );
		return FALSE;
	}

	ASSERT( m_hWndCmdReciever != NULL );
	ASSERT( ::IsWindow(m_hWndCmdReciever) );

MENUITEMDATA mi;
	mi.SetCmdReciever( 
		(hWndSpecCmdReciever != NULL)
			? hWndSpecCmdReciever
			: m_hWndCmdReciever
		);

	switch( nCmdID )
	{
	case TYPE_POPUP:
		mi.SetPopup( nPos, sText, hIcon );
		break; // case TYPE_POPUP
	case TYPE_SEPARATOR:
		mi.SetSeparator( nPos );
		break; // case TYPE_SEPARATOR
	default:
	{
		ASSERT( m_hWndCmdReciever != NULL );
		ASSERT( ::IsWindow(m_hWndCmdReciever) );
		CExtCmdManager::cmd_t * p_cmd =
			g_CmdManager->CmdGetPtr(
				g_CmdManager->ProfileNameFromWnd(
					(hWndSpecCmdReciever != NULL)
						? hWndSpecCmdReciever
						: m_hWndCmdReciever
					),
				nCmdID
				);
		ASSERT( p_cmd != NULL );
		if( p_cmd == NULL )
			return FALSE;
		VERIFY(
			mi.UpdateCmdManagerCommand(
				p_cmd,
				nPos
				)
			);
	}
	break; // default
	} // switch( nCmdID )

	if( mi.IsPopup() )
	{
		ASSERT( mi.GetPopup()->m_pWndParentMenu == NULL ); // still not initialized
		mi.GetPopup()->m_pWndParentMenu = this;
		ASSERT( !mi.GetPopup()->m_bTopLevel );
	}
	
	_InsertItem( nPos, mi );

	if( m_bTopLevel )
		_SyncItems();
	else
	{
		ASSERT( m_pWndParentMenu != NULL );
		m_pWndParentMenu->_SyncItems();
	}

	return TRUE;
}

void CExtPopupMenuWnd::SetLeftAreaWidth(
	UINT nWidth // = 0
	)
{
	m_nLeftAreaWidth = nWidth;
}

UINT CExtPopupMenuWnd::GetLeftAreaWidth() const
{
	return m_nLeftAreaWidth;
}

BOOL CExtPopupMenuWnd::CreatePopupMenu( HWND hWndCmdRecv )
{
	ASSERT_VALID( this );
	ASSERT( ::IsWindow(hWndCmdRecv) );

	ASSERT( GetTrackingMenu() != this );
	if( m_bTopLevel
		|| m_pWndParentMenu != NULL
		|| ItemGetCount() != 0
		)
	{
		// already created
		ASSERT( FALSE );
		return FALSE;
	}
	m_sizeFullItems.cx = m_sizeFullItems.cy = 1;
	m_bTopLevel = true;
	m_pWndParentMenu = NULL;
	m_hWndCmdReciever = hWndCmdRecv;
	
	return TRUE;
}

void CExtPopupMenuWnd::SetCmdTargetToAllItems(
	HWND hWndSpecCmdReciever, // = NULL
	bool bOnlyThisLevel // = false
	)
{
	ASSERT_VALID( this );

	ASSERT( GetTrackingMenu() != this );

INT iter = 0;
	for( ; iter < m_items_all.GetSize(); iter++)
	{
		MENUITEMDATA & mi = m_items_all[ iter ];
		if( mi.IsSeparator() )
			continue;
		if( mi.IsPopup() )
		{
			if( !bOnlyThisLevel )
				mi.GetPopup()->SetCmdTargetToAllItems(
					hWndSpecCmdReciever,
					true
					);
		}
		else
		{
			mi.SetCmdReciever( hWndSpecCmdReciever );
		}
	}
}

//CExtPopupMenuWnd::const_items_container_t &
//	CExtPopupMenuWnd::_GetItemsContaner() const
//{
//	return m_items_all;
//}
//
//CExtPopupMenuWnd::items_container_t &
//	CExtPopupMenuWnd::_GetItemsContaner()
//{
//	return m_items_all;
//}

CExtPopupMenuWnd::MENUITEMDATA &
	CExtPopupMenuWnd::_GetItemRef(int nIndex)
{
	ASSERT_VALID( this );

	ASSERT( nIndex >= 0 && nIndex < m_items_all.GetSize() );
MENUITEMDATA & mi = m_items_all[nIndex];
	return mi;
}

const CExtPopupMenuWnd::MENUITEMDATA &
	CExtPopupMenuWnd::_GetItemRef(int nIndex) const
{
	ASSERT_VALID( this );

	return
		(const_cast< CExtPopupMenuWnd * > (this)) ->
			_GetItemRef(nIndex);
}

void CExtPopupMenuWnd::_InsertItem(
	int nInsertBefore,
	MENUITEMDATA & mi
	)
{
	ASSERT_VALID( this );

	m_items_all.InsertAt(
		(nInsertBefore < 0)
			? m_items_all.GetSize()
			: nInsertBefore
			,
		mi
		);
}

//
//void CExtPopupBaseWnd::_BitsSave( CDC &dc )
//{
//	if( m_bmpSaveBits.GetSafeHandle() != NULL )
//	{
//		//VERIFY( m_bmpSaveBits.DeleteObject() );
//		return;
//	}
//
//int nBitsPerPixel = CExtPaintManager::stat_GetBPP();
//	if( nBitsPerPixel < 8 )
//		return;
//
//CRect rcClient;
//	GetClientRect( &rcClient );
//int cx = rcClient.Width();
//int cy = rcClient.Height();
//	if( cx<=0 || cy<=0 )
//		return;
//
//CDC dcmm;
//	if( !dcmm.CreateCompatibleDC(&dc) )
//	{
//		ASSERT( FALSE );
//		return;
//	}
//
//	// Fill in the BITMAPINFOHEADER
//BITMAPINFOHEADER bih;
//	bih.biSize = sizeof(BITMAPINFOHEADER);
//	bih.biWidth = cx;
//	bih.biHeight = cy;
//	bih.biPlanes = 1;
//	bih.biBitCount = 32;
//	bih.biCompression = BI_RGB;
//	bih.biSizeImage = cx * cy;
//	bih.biXPelsPerMeter = 0;
//	bih.biYPelsPerMeter = 0;
//	bih.biClrUsed = 0;
//	bih.biClrImportant = 0;
//
//COLORREF * p_clrValues = NULL;
//HBITMAP hDIB =
//		::CreateDIBSection(
//			dcmm.GetSafeHdc(),
//			(LPBITMAPINFO)&bih,
//			DIB_RGB_COLORS,
//			(void **)&p_clrValues,
//			NULL,
//			NULL
//			);
//	if( hDIB == NULL || p_clrValues == NULL )
//	{
//		ASSERT( FALSE );
//		return;
//	}
//	m_bmpSaveBits.Attach( hDIB );
//CBitmap * pBmpOld =
//		dcmm.SelectObject( &m_bmpSaveBits );
//	VERIFY(
//		dcmm.BitBlt(
//			0, 0, cx, cy, &dc,
//			rcClient.left,
//			rcClient.top,
//			SRCCOPY
//			)
//		);
//	dcmm.SelectObject( pBmpOld );
//}
//
//void CExtPopupBaseWnd::_BitsRestore()
//{
//	if( m_bmpSaveBits.GetSafeHandle() == NULL )
//		return;
//int nBitsPerPixel = CExtPaintManager::stat_GetBPP();
//	if( nBitsPerPixel < 8 )
//		return;
//
//CRect rcClient;
//	GetClientRect( &rcClient );
//int cx = rcClient.Width();
//int cy = rcClient.Height();
//	if( cx<=0 || cy<=0 )
//		return;
//
//CClientDC dc( this );
//CDC dcmm;
//	if( !dcmm.CreateCompatibleDC(&dc) )
//	{
//		ASSERT( FALSE );
//		return;
//	}
//CBitmap * pBmpOld =
//		dcmm.SelectObject( &m_bmpSaveBits );
//	VERIFY(
//		dc.BitBlt(
//			rcClient.left, rcClient.top, cx, cy, 
//			&dcmm,
//			0,
//			0,
//			SRCCOPY
//			)
//		);
//	dcmm.SelectObject( pBmpOld );
//}
//

/////////////////////////////////////////////////////////////////////////////
// CExtPopupColorMenuWnd

IMPLEMENT_DYNCREATE(CExtPopupColorMenuWnd, CExtPopupMenuWnd)

BEGIN_MESSAGE_MAP(CExtPopupColorMenuWnd, CExtPopupMenuWnd)
	//{{AFX_MSG_MAP(CExtPopupColorMenuWnd)
	//}}AFX_MSG_MAP
    ON_WM_QUERYNEWPALETTE()
    ON_WM_PALETTECHANGED()
END_MESSAGE_MAP()

UINT CExtPopupColorMenuWnd::g_nMsgNotifyColorChanged =
	::RegisterWindowMessage(
		_T("CExtPopupColorMenuWnd::g_nMsgNotifyColorChanged")
		);
UINT CExtPopupColorMenuWnd::g_nMsgNotifyColorChangedFinally =
	::RegisterWindowMessage(
		_T("CExtPopupColorMenuWnd::g_nMsgNotifyColorChangedFinally")
		);

UINT CExtPopupColorMenuWnd::g_nMsgNotifyCustColor =
	::RegisterWindowMessage(
		_T("CExtPopupColorMenuWnd::g_nMsgNotifyCustColor")
		);

#define __NCLR_DX 8
#define __NCLR_DY 5
#define __NCLR_COUNT (__NCLR_DX*__NCLR_DY)
#define __NCLR_BOX_DX_SIZE 16
#define __NCLR_BOX_DY_SIZE 16
#define __NCLR_BOX_DX_SPACE 2
#define __NCLR_BOX_DY_SPACE 2

// table captured from color picker control source by
// Chris Maunder
CExtPopupColorMenuWnd::COLORREF_TABLE_ENTRY
	CExtPopupColorMenuWnd::g_colors[] =
{
    { RGB(0x00, 0x00, 0x00),    _T("Black")             },
    { RGB(0xA5, 0x2A, 0x00),    _T("Brown")             },
    { RGB(0x00, 0x40, 0x40),    _T("Dark Olive Green")  },
    { RGB(0x00, 0x55, 0x00),    _T("Dark Green")        },
    { RGB(0x00, 0x00, 0x5E),    _T("Dark Teal")         },
    { RGB(0x00, 0x00, 0x8B),    _T("Dark blue")         },
    { RGB(0x4B, 0x00, 0x82),    _T("Indigo")            },
    { RGB(0x28, 0x28, 0x28),    _T("Dark grey")         },

    { RGB(0x8B, 0x00, 0x00),    _T("Dark red")          },
    { RGB(0xFF, 0x68, 0x20),    _T("Orange")            },
    { RGB(0x8B, 0x8B, 0x00),    _T("Dark yellow")       },
    { RGB(0x00, 0x93, 0x00),    _T("Green")             },
    { RGB(0x38, 0x8E, 0x8E),    _T("Teal")              },
    { RGB(0x00, 0x00, 0xFF),    _T("Blue")              },
    { RGB(0x7B, 0x7B, 0xC0),    _T("Blue-grey")         },
    { RGB(0x66, 0x66, 0x66),    _T("Grey - 40")         },

    { RGB(0xFF, 0x00, 0x00),    _T("Red")               },
    { RGB(0xFF, 0xAD, 0x5B),    _T("Light orange")      },
    { RGB(0x32, 0xCD, 0x32),    _T("Lime")              }, 
    { RGB(0x3C, 0xB3, 0x71),    _T("Sea green")         },
    { RGB(0x7F, 0xFF, 0xD4),    _T("Aqua")              },
    { RGB(0x7D, 0x9E, 0xC0),    _T("Light blue")        },
    { RGB(0x80, 0x00, 0x80),    _T("Violet")            },
    { RGB(0x7F, 0x7F, 0x7F),    _T("Grey - 50")         },

    { RGB(0xFF, 0xC0, 0xCB),    _T("Pink")              },
    { RGB(0xFF, 0xD7, 0x00),    _T("Gold")              },
    { RGB(0xFF, 0xFF, 0x00),    _T("Yellow")            },    
    { RGB(0x00, 0xFF, 0x00),    _T("Bright green")      },
    { RGB(0x40, 0xE0, 0xD0),    _T("Turquoise")         },
    { RGB(0xC0, 0xFF, 0xFF),    _T("Skyblue")           },
    { RGB(0x48, 0x00, 0x48),    _T("Plum")              },
    { RGB(0xC0, 0xC0, 0xC0),    _T("Light grey")        },

    { RGB(0xFF, 0xE4, 0xE1),    _T("Rose")              },
    { RGB(0xD2, 0xB4, 0x8C),    _T("Tan")               },
    { RGB(0xFF, 0xFF, 0xE0),    _T("Light yellow")      },
    { RGB(0x98, 0xFB, 0x98),    _T("Pale green ")       },
    { RGB(0xAF, 0xEE, 0xEE),    _T("Pale turquoise")    },
    { RGB(0x68, 0x83, 0x8B),    _T("Pale blue")         },
    { RGB(0xE6, 0xE6, 0xFA),    _T("Lavender")          },
    { RGB(0xFF, 0xFF, 0xFF),    _T("White")             },
};

CExtPopupColorMenuWnd::CExtPopupColorMenuWnd()
{
	ASSERT( __NCLR_COUNT == sizeof(g_colors)/sizeof(COLORREF_TABLE_ENTRY) );

	m_nColorIdxCurr
		= m_nInitialColorIdx
		= -1;

	m_hWndNotifyColorChanged = NULL; // - use command targed

	m_clrInitial = (COLORREF)(-1); // unexisting
	m_clrDefault = RGB(0,0,0);
	m_bEnableBtnColorDefault = true;
	m_bEnableBtnColorCustom = true;

	m_rcDefColorText.SetRectEmpty();
	m_rcCustColorText.SetRectEmpty();

	m_lParamCookie = 0;

#if (defined _AFXDLL && !defined __STATPROFUIS_WITH_DLLMFC__)
CExtLocalResourceHelper _LRH;
#endif // #if (defined _AFXDLL && !defined __STATPROFUIS_WITH_DLLMFC__)
	
	if( !m_sBtnTextColorDefault.LoadString(IDS_COLOR_DEFAULT) )
	{
#if (defined _AFXDLL && !defined __STATPROFUIS_WITH_DLLMFC__)
		ASSERT( FALSE );
#endif // #if (defined _AFXDLL && !defined __STATPROFUIS_WITH_DLLMFC__)
		m_sBtnTextColorDefault = _T("Default Color");
	}
	if( !m_sBtnTextColorCustom.LoadString(IDS_COLOR_CUSTOM) )
	{
#if (defined _AFXDLL && !defined __STATPROFUIS_WITH_DLLMFC__)
		ASSERT( FALSE );
#endif // #if (defined _AFXDLL && !defined __STATPROFUIS_WITH_DLLMFC__)
		m_sBtnTextColorCustom = _T("Custom Color ...");
	}
}

BOOL CExtPopupColorMenuWnd::OnQueryNewPalette() 
{
	ASSERT_VALID( this );

	Invalidate();
	return CWnd::OnQueryNewPalette();
}

void CExtPopupColorMenuWnd::OnPaletteChanged(CWnd* pFocusWnd) 
{
	ASSERT_VALID( this );

	CWnd::OnPaletteChanged(pFocusWnd);
	if( pFocusWnd->GetSafeHwnd() != GetSafeHwnd() )
	{
		Invalidate();
	}
}

CSize CExtPopupColorMenuWnd::_CalcTrackSize()
{
	ASSERT_VALID( this );

int nMenuBorderSize =
		g_PaintManager->GetMenuBorderSize();
int nMenuShadowSize =
		_GetMenuShadowSize();
CSize _size(
		(__NCLR_BOX_DX_SIZE + __NCLR_BOX_DX_SPACE*2) * __NCLR_DX
			+ nMenuBorderSize*2 + nMenuShadowSize
			,
		(__NCLR_BOX_DY_SIZE + __NCLR_BOX_DY_SPACE*2) * __NCLR_DY
			+ nMenuBorderSize*2 + nMenuShadowSize
		);
	if( m_bEnableBtnColorDefault )
	{
		_size.cy +=
			__DEF_MENU_SEPARATOR_HEIGHT
			+ __DEF_MENU_GAP*2;
		CString sMeasureText( m_sBtnTextColorDefault );
		sMeasureText.Replace( _T("&"), _T("") );

		CWindowDC dc(NULL);
		CFont * pOldFont =
			dc.SelectObject( &(g_PaintManager->m_FontNormal) );
		ASSERT( pOldFont != NULL );
		CRect rect(0,0,0,0);
		CSize _sizeDefColorText;
		_sizeDefColorText.cy = DrawText(
			dc.GetSafeHdc(),
			(LPCTSTR)sMeasureText,
			sMeasureText.GetLength(),
			&rect,
			DT_CALCRECT|DT_SINGLELINE
				|DT_LEFT|DT_VCENTER
			);
		_sizeDefColorText.cx = rect.Width();
		dc.SelectObject( pOldFont );
		_sizeDefColorText.cx +=
			//__DEF_MENU_ICON_CX
			+ __DEF_MENU_GAP*2 // + __DEF_MENU_GAP*6
			//+ __DEF_MENU_POPUP_ARROW_AREA_DX
			;
		if( _sizeDefColorText.cy < __DEF_MENU_HEIGHT )
			_sizeDefColorText.cy = __DEF_MENU_HEIGHT;
		_size.cy += _sizeDefColorText.cy;
		if( _size.cx < _sizeDefColorText.cx )
			_size.cx = _sizeDefColorText.cx;
		CPoint pt(
			nMenuBorderSize + __DEF_MENU_GAP
				,
			nMenuBorderSize + __DEF_MENU_GAP
			);
		m_rcDefColorText.SetRect(
			pt,
			pt
			+
			CSize(
				max( _size.cx , _sizeDefColorText.cx )
					- __DEF_MENU_GAP*2
					- nMenuBorderSize*2
					- nMenuShadowSize
					,
				_sizeDefColorText.cy
				)
			);
	} // if( m_bEnableBtnColorDefault )
	if( m_bEnableBtnColorCustom )
	{
		_size.cy +=
			__DEF_MENU_SEPARATOR_HEIGHT
			+ __DEF_MENU_GAP*2;
		CString sMeasureText( m_sBtnTextColorCustom );
		sMeasureText.Replace( _T("&"), _T("") );

		CWindowDC dc(NULL);
		CFont * pOldFont =
			dc.SelectObject( &(g_PaintManager->m_FontNormal) );
		ASSERT( pOldFont != NULL );
		CRect rect(0,0,0,0);
		CSize _sizeCustColorText;
		_sizeCustColorText.cy = DrawText(
			dc.GetSafeHdc(),
			(LPCTSTR)sMeasureText,
			sMeasureText.GetLength(),
			&rect,
			DT_CALCRECT|DT_SINGLELINE
				|DT_LEFT|DT_VCENTER
			);
		_sizeCustColorText.cx = rect.Width();
		dc.SelectObject( pOldFont );
		_sizeCustColorText.cx +=
			//__DEF_MENU_ICON_CX
			+ __DEF_MENU_GAP*2 // + __DEF_MENU_GAP*6
			//+ __DEF_MENU_POPUP_ARROW_AREA_DX
			;
		if( _sizeCustColorText.cy < __DEF_MENU_HEIGHT )
			_sizeCustColorText.cy = __DEF_MENU_HEIGHT;
		_size.cy += _sizeCustColorText.cy;
		if( _size.cx < _sizeCustColorText.cx )
			_size.cx = _sizeCustColorText.cx;
		CPoint pt(
			nMenuBorderSize + __DEF_MENU_GAP
				,
			nMenuBorderSize + __DEF_MENU_GAP
			);
		m_rcCustColorText.SetRect(
			pt,
			pt
			+
			CSize(
				max( _size.cx , _sizeCustColorText.cx )
					- __DEF_MENU_GAP*2
					- nMenuBorderSize*2
					- nMenuShadowSize
					,
				_sizeCustColorText.cy
				)
			);
		if( m_bEnableBtnColorDefault )
			m_rcCustColorText.OffsetRect(
				0,
				m_rcCustColorText.Height()
				+ __DEF_MENU_GAP*2
				+ __DEF_MENU_SEPARATOR_HEIGHT
				);
		m_rcCustColorText.OffsetRect(
			0,
			nMenuBorderSize +
				(__NCLR_BOX_DY_SIZE + __NCLR_BOX_DY_SPACE*2) * __NCLR_DY
				+ __NCLR_BOX_DY_SPACE
			);
	} // if( m_bEnableBtnColorCustom )

	_size.cx += m_nLeftAreaWidth;
	return _size;
}

CPoint CExtPopupColorMenuWnd::_GetColorItemCoord(int nIdx)
{
	ASSERT_VALID( this );

	ASSERT( nIdx >= 0 && nIdx < __NCLR_COUNT );
int nX = nIdx % __NCLR_DX;
	ASSERT( nX < __NCLR_DX );
int nY = nIdx / __NCLR_DX;
	ASSERT( nY < __NCLR_DY );
	return CPoint(nX,nY);
}

CRect CExtPopupColorMenuWnd::_GetColorItemRect(int nIdx)
{
	ASSERT_VALID( this );

	ASSERT( nIdx >= 0 && nIdx < __NCLR_COUNT );
CPoint ptCoord =  _GetColorItemCoord(nIdx);
int nMenuBorderSize =
		g_PaintManager->GetMenuBorderSize();
CRect rcItem(
		CPoint(
			nMenuBorderSize +
				(__NCLR_BOX_DX_SIZE + __NCLR_BOX_DX_SPACE*2) * ptCoord.x
				+ __NCLR_BOX_DX_SPACE
				,
			nMenuBorderSize +
				(__NCLR_BOX_DY_SIZE + __NCLR_BOX_DY_SPACE*2) * ptCoord.y
				+ __NCLR_BOX_DY_SPACE
			),
		CSize(__NCLR_BOX_DX_SIZE,__NCLR_BOX_DY_SIZE)
		);
	if( m_bEnableBtnColorDefault )
	{
		rcItem.OffsetRect(
			0,
			m_rcDefColorText.Height()
			+ __DEF_MENU_SEPARATOR_HEIGHT
			+ __DEF_MENU_GAP*2
			);
	}
CRect rcClient;
	_GetClientRect( &rcClient );
	rcItem.OffsetRect( rcClient.TopLeft() );
	rcItem.OffsetRect( m_nLeftAreaWidth, 0 );
	return rcItem;
}

CRect CExtPopupColorMenuWnd::_CalcTrackRect()
{
	ASSERT_VALID( this );

	return CExtPopupMenuWnd::_CalcTrackRect();
}

bool CExtPopupColorMenuWnd::_CreateHelper(
	CWnd * pWndCmdReciever
	)
{
	ASSERT_VALID( this );

	if( !CExtPopupMenuWnd::_CreateHelper(
			pWndCmdReciever
			)
		)
		return false;
	int nIdx =
		_FindCellByColorRef(m_clrInitial);
	if( nIdx >= 0 )
	{
		m_nInitialColorIdx = nIdx;
		Invalidate();
	}
CRect rcClient;
	_GetClientRect( &rcClient );
	if( m_bEnableBtnColorDefault )
	{
		m_rcDefColorText.OffsetRect( rcClient.TopLeft() );
		m_rcDefColorText.OffsetRect( m_nLeftAreaWidth, 0 );
	}
	if( m_bEnableBtnColorCustom )
	{
		m_rcCustColorText.OffsetRect( rcClient.TopLeft() );
		m_rcCustColorText.OffsetRect( m_nLeftAreaWidth, 0 );
	}
	return true;
}

void CExtPopupColorMenuWnd::_DoPaint( CDC & dcPaint, bool bUseBackBuffer /*= true*/ )
{
	ASSERT_VALID( this );

	ASSERT_VALID( (&dcPaint) );
	ASSERT( dcPaint.GetSafeHdc() != NULL );

CRect rcRealClient;
	GetClientRect( &rcRealClient );
CRect rcClient;
	_GetClientRect( &rcClient );

    // Select and realize the palette
CPalette * pOldPalette = NULL;
    if( dcPaint.GetDeviceCaps(RASTERCAPS) & RC_PALETTE )
    {
        pOldPalette =
			dcPaint.SelectPalette( &g_PaintManager->m_PaletteWide, FALSE );
        dcPaint.RealizePalette();
    }

CExtMemoryDC mdc;
	if( bUseBackBuffer )
	{
		mdc.__InitMemoryDC(
			&dcPaint,
			&rcClient, // &rcRealClient
			CExtMemoryDC::MDCOPT_TO_MEMORY
				|CExtMemoryDC::MDCOPT_FILL_SURFACE
				|CExtMemoryDC::MDCOPT_FORCE_DIB 
			);
	}
CDC & dcDummyRef = mdc;
CDC & dc = bUseBackBuffer ? dcDummyRef : dcPaint;

CFont * pOldFont = (CFont *)
		dc.SelectObject(
			&g_PaintManager->m_FontNormal
			);

	dc.FillSolidRect(
		&rcClient,
		g_PaintManager->GetMenuFrameFillColor()
		);

	g_PaintManager->PaintMenuBorder(
		dc,
		&rcClient
		);

	ASSERT( !m_bExpandAvailable );
	ASSERT( !m_bScrollingAvailable );

int nMenuBorderSize =
		g_PaintManager->GetMenuBorderSize();
int nMenuShadowSize =
		_GetMenuShadowSize();

//	if( rcClient.left >= rcRealClient.left )
//	{
//		CRect rcExcludePart(rcRealClient);
//		rcExcludePart.right =
//			rcClient.left + nMenuBorderSize;
//		dc.ExcludeClipRect( rcExcludePart );
//	}
//	if( rcClient.right <= rcRealClient.right )
//	{
//		CRect rcExcludePart(rcRealClient);
//		rcExcludePart.left =
//			rcClient.right - nMenuBorderSize;
//		dc.ExcludeClipRect( rcExcludePart );
//	}

	if( rcClient.top >= rcRealClient.top )
	{
		CRect rcExcludePart(rcRealClient);
		rcExcludePart.bottom =
			rcClient.top + nMenuBorderSize;
		dc.ExcludeClipRect( rcExcludePart );
	}
	if( rcClient.bottom <= rcRealClient.bottom )
	{
		CRect rcExcludePart(rcRealClient);
		rcExcludePart.top =
			rcClient.bottom - nMenuBorderSize;
		dc.ExcludeClipRect( rcExcludePart );
	}

	// paint default color btn
	if( m_bEnableBtnColorDefault )
	{
		bool bSelected =
			(m_nColorIdxCurr == IDX_DEFAULT_COLOR_BTN) ?
			true : false;
		g_PaintManager->PaintPushButton(
			dc,
			true,
			m_rcDefColorText,
			(LPCTSTR)m_sBtnTextColorDefault,
			NULL,
			true,
			bSelected,
			false, // bSelected,
			false,
			true,
			bSelected,
			false,
			false,
			CExtPaintManager::__ALIGN_HORIZ_CENTER
				|CExtPaintManager::__ALIGN_VERT,
			NULL,
			false,
			0,
			!bSelected
			);
		CRect rcItem( m_rcDefColorText );
		rcItem.OffsetRect(
			0,
			rcItem.Height() + __DEF_MENU_GAP
			);
		rcItem.bottom =
			rcItem.top + __DEF_MENU_SEPARATOR_HEIGHT;
//		g_PaintManager->PaintMenuSeparator(
//			dc,
//			rcItem,
//			false
//			);
		rcItem.top += rcItem.Height()/2;
		rcItem.bottom = rcItem.top+1;
		g_PaintManager->PaintSeparator(
			dc,
			rcItem,
			false
			);
	}
	if( m_bEnableBtnColorCustom )
	{
		bool bSelected =
			(m_nColorIdxCurr == IDX_CUSTOM_COLOR_BTN) ?
			true : false;
		g_PaintManager->PaintPushButton(
			dc,
			true,
			m_rcCustColorText,
			(LPCTSTR)m_sBtnTextColorCustom,
			NULL,
			true,
			bSelected,
			false, // bSelected,
			false,
			true,
			bSelected,
			false,
			false,
			CExtPaintManager::__ALIGN_HORIZ_CENTER
				|CExtPaintManager::__ALIGN_VERT,
			NULL,
			false,
			0,
			!bSelected
			);
		CRect rcItem( m_rcCustColorText );
		rcItem.OffsetRect(
			0,
			- __DEF_MENU_GAP
			);
		rcItem.bottom = rcItem.top;
		rcItem.top -= __DEF_MENU_SEPARATOR_HEIGHT;
//		g_PaintManager->PaintMenuSeparator(
//			dc,
//			rcItem,
//			false
//			);
		rcItem.top += rcItem.Height()/2;
		rcItem.bottom = rcItem.top+1;
		g_PaintManager->PaintSeparator(
			dc,
			rcItem,
			false
			);
	}

	// paint color buttons
COLORREF clrColorBorder =
		g_PaintManager->GetColor(COLOR_3DDKSHADOW);
	for( int nIdx = 0; nIdx < __NCLR_COUNT; nIdx++ )
	{
		bool bSelected =
			(m_nColorIdxCurr == nIdx
			|| m_nInitialColorIdx == nIdx
			) ?
			true : false;
		CRect rcItem = _GetColorItemRect( nIdx );
		g_PaintManager->PaintPushButton(
			dc,
			true,
			rcItem,
			_T(""),
			NULL,
			true,
			bSelected,
			bSelected,
			false,
			true,
			bSelected,
			false,
			false,
			CExtPaintManager::__ALIGN_HORIZ_CENTER
				|CExtPaintManager::__ALIGN_VERT,
			NULL,
			false,
			0,
			!bSelected
			);
		rcItem.DeflateRect(
			__NCLR_BOX_DX_SPACE,
			__NCLR_BOX_DY_SPACE
			);
		dc.FillSolidRect(
			&rcItem,
			//dc.GetNearestColor(
				g_colors[nIdx].m_clr
				//) 
			);
		dc.Draw3dRect(
			&rcItem,
			clrColorBorder,clrColorBorder
			);
	}

	if( m_nLeftAreaWidth > 0 )
	{
		CRect rcLeftArea( rcClient );
		rcLeftArea.right = rcLeftArea.left + m_nLeftAreaWidth;
		rcLeftArea.OffsetRect( nMenuBorderSize, 0 );
		rcLeftArea.DeflateRect( 0, nMenuBorderSize );
		DRAWLEFTAREADATA _DrawLeftAreaData( &dc, &rcLeftArea, this );
		_DrawLeftAreaData.DoOwnerDrawPainting();
	}

CPoint point;
	VERIFY( ::GetCursorPos(&point) );
	ScreenToClient( &point );
	dc.SelectClipRgn( NULL );

	if( m_bCombineWithEA )
	{
		ASSERT( m_eCombineAlign != __CMBA_NONE );
		dc.SelectClipRgn(NULL);
		CRect rcExcludeClient( m_rcExcludeArea );
		ScreenToClient( &rcExcludeClient );
		g_PaintManager->PaintMenuCombinedArea(
			dc,
			rcExcludeClient,
			rcClient,
			m_eCombineAlign
			);
		if( m_pCbPaintCombinedContent != NULL )
			m_pCbPaintCombinedContent(
				m_pCbPaintCombinedCookie,
				dc,
				*this,
				m_rcExcludeArea,
				m_eCombineAlign
				);
	} // if( m_bCombineWithEA )

	dc.SelectObject( pOldFont );

	if( bUseBackBuffer )
	{
		ASSERT( mdc.GetSafeHdc() != NULL );
		mdc.__Flush();
	}

	if( CExtPopupMenuWnd::g_bMenuWithShadows
		&& m_bAnimFinished
		&& nMenuShadowSize > 0
		)
	{ // if we need to paint shadow for client area (and combined exclude area)
		dcPaint.SelectClipRgn(NULL);
		CRect
			rcExcludeClient( 0,0,0,0 ),
			rcExcludeScreen( 0,0,0,0 ),
			rcBaseScreen( 0,0,0,0 );
		if( m_bCombineWithEA )
		{
			if( CExtPopupMenuWnd::g_bMenuWithShadows
				&& m_bAnimFinished
				&& nMenuShadowSize > 0
				)
			{ // if we need to paint shadow for combined exclude area
				rcExcludeScreen = m_rcExcludeArea;
				rcExcludeClient = rcExcludeScreen;
				ScreenToClient( &rcExcludeClient );
				dcPaint.ExcludeClipRect( &rcClient );
				rcBaseScreen = rcClient;
				ClientToScreen( &rcBaseScreen );
				VERIFY(
					m_ShadowCMBA.Paint(
						dcPaint,
						rcExcludeClient,
						rcExcludeScreen,
						rcBaseScreen,
						nMenuShadowSize
						)
					);
				dcPaint.SelectClipRgn(NULL);
			} // if we need to paint shadow for combined exclude area

			CRect rcExcludePart( m_rcExcludeArea );
			ScreenToClient( &rcExcludePart );
			dcPaint.ExcludeClipRect( &rcExcludePart );
		} // if( m_bCombineWithEA )
		VERIFY(
			m_ShadowMain.Paint(
				dcPaint,
				rcClient,
				rcBaseScreen,
				rcExcludeScreen,
				nMenuShadowSize
				)
			);
	} // if we need to paint shadow for client area (and combined exclude area)

	if( pOldPalette != NULL )
		dcPaint.SelectPalette( pOldPalette, FALSE );

}

int CExtPopupColorMenuWnd::_ColorItemHitTest(
	const CPoint & point
	)
{
	ASSERT_VALID( this );

	for( int nIdx = 0; nIdx < __NCLR_COUNT; nIdx++ )
	{
		CRect rcItem = _GetColorItemRect( nIdx );
		if( rcItem.PtInRect(point) )
			return nIdx;
	}
	if( m_rcDefColorText.PtInRect(point) )
		return IDX_DEFAULT_COLOR_BTN;
	if( m_rcCustColorText.PtInRect(point) )
		return IDX_CUSTOM_COLOR_BTN;
	return -1;
}

bool CExtPopupColorMenuWnd::_OnMouseMove(UINT nFlags, CPoint point)
{
	ASSERT_VALID( this );

	if( GetSafeHwnd() == NULL )
		return false;

	if( GetSite().GetAnimated() != NULL )
		return true;

//	ASSERT( GetCapture() == this );

CRect rectWindow;
	GetWindowRect( &rectWindow );
	ScreenToClient( &rectWindow );
	if( !rectWindow.PtInRect(point) )
	{
//		_ItemFocusCancel( TRUE );
		if( m_pWndParentMenu != NULL
			&& m_pWndParentMenu->GetSafeHwnd() != NULL
			)
		{
			ASSERT_VALID( m_pWndParentMenu );
			ClientToScreen( &point );
			m_pWndParentMenu->ScreenToClient( &point );
			if( m_pWndParentMenu->_OnMouseMove(nFlags, point) )
			{
				_OnCancelMode();
				return true;
			}
		}
		return false;
	}

bool bHoverChanged = false;
int nColorIdxCurr = _ColorItemHitTest(point);
	if( m_nColorIdxCurr != nColorIdxCurr )
	{
		m_nColorIdxCurr = nColorIdxCurr;
		bHoverChanged = true;
		Invalidate();
		if( m_nColorIdxCurr != IDX_CUSTOM_COLOR_BTN )
			_NotifyColorChanged();
	}

	if( m_nColorIdxCurr >= 0 )
	{
		if(	g_bMenuShowCoolTips
			&& bHoverChanged
			)
		{
			CString sTipText =
				g_colors[m_nColorIdxCurr].m_sName;
			if( !sTipText.IsEmpty()
				&& GetSite().GetCapture() == this
				&& ( GetSite().GetAnimated() == NULL )
				)
			{
				CRect rcItem =
					_GetColorItemRect(m_nColorIdxCurr);
				ClientToScreen( &rcItem );
				m_wndToolTip.SetText( (LPCTSTR)sTipText );
				VERIFY(
					m_wndToolTip.Show(
						this,
						rcItem
						)
					);
			}
		} // if( nOldCurIndex != nCurIndex )
	}
	else
		_CoolTipHide();

	return true;
}

bool CExtPopupColorMenuWnd::_OnMouseClick(UINT nFlags, CPoint point)
{
	ASSERT_VALID( this );

	if( GetSafeHwnd() == NULL )
		return false;

	if( GetSite().GetAnimated() != NULL )
		return true;

	nFlags;
int m_nColorIdxCurr = _ColorItemHitTest(point);
	if( m_nColorIdxCurr >= 0
		|| m_nColorIdxCurr == IDX_DEFAULT_COLOR_BTN
		|| m_nColorIdxCurr == IDX_CUSTOM_COLOR_BTN
		)
	{
		_NotifyColorChanged( true );
		g_SoundPlayer->PlaySound(
			CExtSoundPlayer::__ON_MENU_CMD_CLICKED
			);
	}
	_EndSequence();
	return true;
}

bool CExtPopupColorMenuWnd::_OnKeyDown(UINT nChar, UINT nRepCnt, UINT nFlags)
{
	ASSERT_VALID( this );

	nRepCnt;
	nFlags;
	if( GetSafeHwnd() == NULL )
		return true; //false;

	if( GetSite().GetAnimated() != NULL )
		return true;

bool bEat = false;
//int nColorIdxCurr = m_nColorIdxCurr;
	switch( nChar )
	{
	case VK_RETURN:
	{

//		if( m_pWndParentMenu == NULL )
//			return true; // false;
//		int nParentCurIndex =
//			m_pWndParentMenu->_GetCurIndex();
//		ASSERT(
//			nParentCurIndex >= 0
//			&&
//			nParentCurIndex <=
//				m_pWndParentMenu->ItemGetCount()
//			);
//		m_pWndParentMenu->_ItemFocusCancel(
//			FALSE
//			);
//		HWND hWndThis = GetSafeHwnd();
//		CExtPopupMenuWnd::PassMsgLoop();
//		if( !::IsWindow(hWndThis) )
//			return false;
//		m_pWndParentMenu->_ItemFocusSet(
//			nParentCurIndex,
//			FALSE,
//			TRUE
//			);

		if( m_nColorIdxCurr >= 0
			|| m_nColorIdxCurr == IDX_DEFAULT_COLOR_BTN
			|| m_nColorIdxCurr == IDX_CUSTOM_COLOR_BTN
			)
		{
			_NotifyColorChanged( true );
			g_SoundPlayer->PlaySound(
				CExtSoundPlayer::__ON_MENU_CMD_CLICKED
				);
		}
		_EndSequence();
		return true;
	} // VK_RETURN
	
	case VK_ESCAPE:
		_EndSequence();
		return true;

	case VK_RIGHT:
		bEat = true;
		if( m_nColorIdxCurr < 0 )
			m_nColorIdxCurr = 0;
		else
		{
			CPoint ptCoord =
				_GetColorItemCoord(m_nColorIdxCurr);
			ptCoord.x++;
			if( ptCoord.x >= __NCLR_DX )
				ptCoord.x = 0;
			m_nColorIdxCurr = 
				ptCoord.x + ptCoord.y * __NCLR_DX;
		}
		break;
	case VK_LEFT:
		bEat = true;
		if( m_nColorIdxCurr < 0 )
			m_nColorIdxCurr = 0;
		else
		{
			CPoint ptCoord =
				_GetColorItemCoord(m_nColorIdxCurr);
			ptCoord.x--;
			if( ptCoord.x < 0 )
				ptCoord.x = __NCLR_DX - 1;
			m_nColorIdxCurr = 
				ptCoord.x + ptCoord.y * __NCLR_DX;
		}
		break;
	case VK_DOWN:
		bEat = true;
		if( m_nColorIdxCurr < 0 )
			m_nColorIdxCurr = 0;
		else
		{
			CPoint ptCoord =
				_GetColorItemCoord(m_nColorIdxCurr);
			ptCoord.y++;
			if( ptCoord.y >= __NCLR_DY )
				ptCoord.y = 0;
			m_nColorIdxCurr = 
				ptCoord.x + ptCoord.y * __NCLR_DX;
		}
		break;
	case VK_UP:
		bEat = true;
		if( m_nColorIdxCurr < 0 )
			m_nColorIdxCurr = 0;
		else
		{
			CPoint ptCoord =
				_GetColorItemCoord(m_nColorIdxCurr);
			ptCoord.y--;
			if( ptCoord.y < 0 )
				ptCoord.y = __NCLR_DY - 1;
			m_nColorIdxCurr = 
				ptCoord.x + ptCoord.y * __NCLR_DX;
		}
		break;

	} // switch( nChar )

	if( bEat )
	{
		_CoolTipHide();
		Invalidate();
		_NotifyColorChanged();
	}

	return bEat;
}

HWND CExtPopupColorMenuWnd::_GetWndNotifyColorChanged()
{
	ASSERT_VALID( this );
	if( m_hWndNotifyColorChanged != NULL )
	{
		ASSERT( ::IsWindow(m_hWndNotifyColorChanged) );
		return m_hWndNotifyColorChanged;
	}
	ASSERT( m_hWndCmdReciever != NULL );
	ASSERT( ::IsWindow(m_hWndCmdReciever) );
	return m_hWndCmdReciever;
}

void CExtPopupColorMenuWnd::_NotifyColorChanged(
	bool bFinal // = false
	)
{
	ASSERT_VALID( this );

HWND hWndNotify = _GetWndNotifyColorChanged();
	ASSERT( hWndNotify != NULL );
	ASSERT( ::IsWindow(hWndNotify) );

	if( m_nColorIdxCurr == IDX_CUSTOM_COLOR_BTN )
	{
		::PostMessage(
			hWndNotify,
			g_nMsgNotifyCustColor,
			0,
			m_lParamCookie
			);
		return;
	}

COLORREF clr = RGB(0,0,0);
	if( m_nColorIdxCurr == IDX_DEFAULT_COLOR_BTN )
		clr = m_clrDefault;
	else
	{
		if( m_nColorIdxCurr < 0 )
			return;
		clr = g_colors[m_nColorIdxCurr].m_clr;
	}
	::PostMessage(
		hWndNotify,
		bFinal
			? g_nMsgNotifyColorChangedFinally
			: g_nMsgNotifyColorChanged
			,
		(WPARAM)clr,
		m_lParamCookie
		);
}

int CExtPopupColorMenuWnd::_FindCellByColorRef(COLORREF clr)
{
	ASSERT_VALID( this );

	for( int nIdx = 0; nIdx < __NCLR_COUNT; nIdx++ )
	{
		if( g_colors[nIdx].m_clr == clr )
			return nIdx;
	}
	return -1;
}

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

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

License

This article has no explicit license attached to it but may contain usage terms in the article text or the download files themselves. If in doubt please contact the author via the discussion board below.

A list of licenses authors might use can be found here


Written By
Architect Foss Software Inc
Ukraine Ukraine
This member has not yet provided a Biography. Assume it's interesting and varied, and probably something to do with programming.

Comments and Discussions