www.pudn.com > CTableDemo.rar > PPTooltip.cpp


/******************************************************************** 
	created:	2003/04/12 
	created:	12:04:2003   10:50 
	file base:	PPTooltip 
	file ext:	cpp 
	author:		Eugene Pustovoyt 
	 
	purpose:	 
*********************************************************************/ 
#include "stdafx.h" 
#include "PPToolTip.h" 
 
#ifdef _DEBUG 
#define new DEBUG_NEW 
#undef THIS_FILE 
static char THIS_FILE[] = __FILE__; 
#endif 
 
///////////////////////////////////////////////////////////////////////////// 
// CPPToolTip 
 
CPPToolTip::CPPToolTip() 
{ 
	m_pParentWnd = NULL; 
 
	m_rgnShadow.CreateRectRgn(0, 0, 0, 0); 
	m_rgnToolTip.CreateRectRgn(0, 0, 0, 0); 
	// m_rgnCombo.CreateRectRgn(0, 0, 0, 0); 
 
	m_ptOriginal.x = -1; 
	m_ptOriginal.y = -1; 
 
	m_nIndexCurrentWnd = PPTOOLTIP_TOOL_NOEXIST; 
	m_nIndexDisplayWnd = PPTOOLTIP_TOOL_NOEXIST; 
 
	SetDelayTime(TTDT_INITIAL, 500); 
	SetDelayTime(TTDT_AUTOPOP, 5000); 
	SetNotify(FALSE); 
	SetDirection(); 
	SetBehaviour(); 
	SetDefaultStyles(); 
	SetDefaultColors(); 
	SetDefaultSizes(); 
	SetEffectBk(PPTOOLTIP_EFFECT_SOLID); 
	RemoveAllTools(); 
 
	// Register the window class if it has not already been registered. 
	WNDCLASS wndcls; 
	HINSTANCE hInst = AfxGetInstanceHandle(); 
	if(!(::GetClassInfo(hInst, PPTOOLTIP_CLASSNAME, &wndcls))) 
	{ 
		// otherwise we need to register a new class 
		wndcls.style			= CS_SAVEBITS; 
		wndcls.lpfnWndProc		= ::DefWindowProc; 
		wndcls.cbClsExtra		= wndcls.cbWndExtra = 0; 
		wndcls.hInstance		= hInst; 
		wndcls.hIcon			= NULL; 
		wndcls.hCursor			= LoadCursor(hInst, IDC_ARROW ); 
		wndcls.hbrBackground	= NULL; 
		wndcls.lpszMenuName		= NULL; 
		wndcls.lpszClassName	= PPTOOLTIP_CLASSNAME; 
 
		if (!AfxRegisterClass(&wndcls)) 
			AfxThrowResourceException(); 
	} 
} 
 
CPPToolTip::~CPPToolTip() 
{ 
	RemoveAllTools(); 
	RemoveAllNamesOfResource(); 
 
	m_nLengthLines.RemoveAll(); 
	m_nHeightLines.RemoveAll(); 
 
	// m_rgnCombo.Detach(); 
	// m_rgnCombo.DeleteObject(); 
	m_rgnToolTip.DeleteObject(); 
	m_rgnShadow.DeleteObject(); 
 
	if (IsWindow(m_hWnd)) 
        DestroyWindow(); 
} 
 
 
BEGIN_MESSAGE_MAP(CPPToolTip, CWnd) 
	//{{AFX_MSG_MAP(CPPToolTip) 
	ON_WM_PAINT() 
	ON_WM_TIMER() 
	ON_WM_DESTROY() 
	ON_WM_KILLFOCUS() 
	ON_WM_ERASEBKGND() 
	//}}AFX_MSG_MAP 
END_MESSAGE_MAP() 
 
 
///////////////////////////////////////////////////////////////////////////// 
// CPPToolTip message handlers 
 
BOOL CPPToolTip::Create(CWnd* pParentWnd, BOOL bBalloonSize /* = TRUE */)  
{ 
	TRACE(_T("CPPToolTip::Create\n")); 
 
	ASSERT_VALID(pParentWnd); 
 
	DWORD dwStyle = WS_POPUP;  
	DWORD dwExStyle = WS_EX_TOOLWINDOW | WS_EX_TOPMOST; 
	m_pParentWnd = pParentWnd; 
 
	if (!CreateEx(dwExStyle, PPTOOLTIP_CLASSNAME, NULL, dwStyle, 0, 0, 0, 0, pParentWnd->GetSafeHwnd(), NULL, NULL)) 
	{ 
		return FALSE; 
	} 
 
	SetDefaultFont(); 
	SetDefaultSizes(bBalloonSize); 
	 
	return TRUE; 
} 
 
void CPPToolTip::OnDestroy()  
{ 
	KillTimers(); 
	 
	CWnd::OnDestroy(); 
} 
 
void CPPToolTip::OnKillFocus(CWnd* pNewWnd)  
{ 
	CWnd::OnKillFocus(pNewWnd); 
	 
	Pop(); 
} 
 
BOOL CPPToolTip::OnEraseBkgnd(CDC* pDC)  
{ 
	return FALSE; 
} 
 
void CPPToolTip::Pop() 
{ 
	if (m_nIndexDisplayWnd == PPTOOLTIP_TOOL_HELPER) 
		m_nIndexDisplayWnd = PPTOOLTIP_TOOL_NOEXIST; 
	KillTimers(); 
	ShowWindow(SW_HIDE); 
} 
 
BOOL CPPToolTip::PreTranslateMessage(MSG* pMsg)  
{ 
	RelayEvent(pMsg); 
	 
	return CWnd::PreTranslateMessage(pMsg); 
} 
 
LRESULT CPPToolTip::SendNotify(CPoint * pt, PPTOOLTIP_INFO & ti)  
{  
	TRACE(_T("CPPToolTip::SendNotify()\n"));  
 	// Make sure this is a valid window   
	if (!IsWindow(GetSafeHwnd()))  
		return 0L;  
   
	// See if the user wants to be notified   
	if (!GetNotify())  
		return 0L;  
  	 
	NM_PPTOOLTIP_DISPLAY lpnm;  
	PPTOOLTIP_INFO tiCopy = ti;  
	FromHandle(ti.hWnd)->ClientToScreen(&tiCopy.rectBounds);  
	m_pParentWnd->ScreenToClient(&tiCopy.rectBounds);  
	lpnm.pt = pt;   
	lpnm.ti = &tiCopy;  
	lpnm.hdr.hwndFrom = m_hWnd;  
	lpnm.hdr.idFrom   = GetDlgCtrlID();  
	lpnm.hdr.code     = UDM_TOOLTIP_DISPLAY;  
	  
	::SendMessage(m_hNotifyWnd, WM_NOTIFY, lpnm.hdr.idFrom, (LPARAM)&lpnm);   
	CRect rcBound = ti.rectBounds;   
	ti = tiCopy;  
	ti.rectBounds = rcBound;   
	return 0L;  
} 
 
void CPPToolTip::OnPaint()  
{ 
	if (!IsEnabledIndexTool(m_nIndexCurrentWnd)) 
		return; 
 
	m_nIndexDisplayWnd = m_nIndexCurrentWnd; 
	m_nIndexCurrentWnd = PPTOOLTIP_TOOL_NOEXIST; 
 
	CPaintDC dc(this); // device context for painting 
 
	CRect rect; 
	GetClientRect(&rect); 
	rect.DeflateRect(0, 0, 1, 1); 
 
	// Create a memory device-context. This is done to help reduce 
	// screen flicker, since we will paint the entire control to the 
	// off screen device context first.CDC memDC; 
	CDC memDC; 
	CBitmap bitmap; 
	memDC.CreateCompatibleDC(&dc); 
	bitmap.CreateCompatibleBitmap(&dc, rect.Width(), rect.Height()); 
	CBitmap* pOldBitmap = memDC.SelectObject(&bitmap);  
	 
	memDC.BitBlt(0, 0, rect.Width(), rect.Height(), &dc, 0,0, SRCCOPY); 
 
	OnDraw(&memDC, rect); 
 
	//Copy the memory device context back into the original DC via BitBlt(). 
	dc.BitBlt(0, 0, rect.Width(), rect.Height(), &memDC, 0,0, SRCCOPY); 
	 
	//Cleanup resources. 
	memDC.SelectObject(pOldBitmap); 
	memDC.DeleteDC(); 
	bitmap.DeleteObject();  
} 
 
void CPPToolTip::OnDraw(CDC * pDC, CRect rect) 
{ 
	CBrush brBackground(m_crColor [PPTOOLTIP_COLOR_BK_BEGIN]); 
	CBrush brBorder(m_crColor [PPTOOLTIP_COLOR_BORDER]); 
	 
	pDC->SetBkMode(TRANSPARENT);  
 
	//Sets clip region of the tooltip and draws the shadow if you need 
	if (m_pToolInfo.nStyles & PPTOOLTIP_SHADOW) 
	{ 
		//Draws the shadow for the tooltip 
		OnDrawShadow(pDC); 
		rect.DeflateRect(0, 0, m_nSizes[PPTTSZ_SHADOW_CX], m_nSizes[PPTTSZ_SHADOW_CY]); 
	} 
	pDC->SelectClipRgn(&m_rgnToolTip); 
 
	OnDrawBackground(pDC, &rect); 
 
	//Draws the main region's border of the tooltip 
	pDC->FrameRgn(&m_rgnToolTip, &brBorder, m_nSizes[PPTTSZ_BORDER_CX], m_nSizes[PPTTSZ_BORDER_CY]); 
 
	//Gets the rectangle to draw the tooltip text 
	rect.DeflateRect(m_nSizes[PPTTSZ_MARGIN_CX], m_nSizes[PPTTSZ_MARGIN_CY]); 
	if ((m_nLastDirection == PPTOOLTIP_RIGHT_BOTTOM) || (m_nLastDirection == PPTOOLTIP_LEFT_BOTTOM)) 
		rect.top += m_nSizes[PPTTSZ_HEIGHT_ANCHOR]; 
	else 
		rect.bottom -= m_nSizes[PPTTSZ_HEIGHT_ANCHOR]; 
 
	// Draw the icon 
	if (m_pToolInfo.hIcon != NULL) 
	{ 
		CPoint ptIcon; 
		ptIcon.x = m_nSizes[PPTTSZ_MARGIN_CX]; 
		ptIcon.y = rect.top; 
		if (m_pToolInfo.nStyles & PPTOOLTIP_ICON_VCENTER_ALIGN) 
			ptIcon.y = rect.top + (rect.Height() - m_szToolIcon.cy) / 2; 
		else if (m_pToolInfo.nStyles & PPTOOLTIP_ICON_BOTTOM_ALIGN) 
			ptIcon.y = rect.bottom - m_szToolIcon.cy; 
		//First variant 
//		pDC->DrawIcon(m_nSizes[PPTTSZ_MARGIN_CX], rect.top + (rect.Height() - m_szToolIcon.cy) / 2, m_pToolInfo.hIcon); 
 
		//Second variant 
		pDC->DrawState(ptIcon, m_szToolIcon, m_pToolInfo.hIcon, DSS_NORMAL, (CBrush*)NULL); 
 
		//Third variant 
//		DrawIconEx(pDC->m_hDC, ptIcon.x, ptIcon.y, m_pToolInfo.hIcon, m_szToolIcon.cx,  
//			m_szToolIcon.cy, 0, NULL, DI_NORMAL); 
 
		rect.left += m_szToolIcon.cx + m_nSizes[PPTTSZ_MARGIN_CX];  
	} 
 
	//Aligns tooltip's text 
	if (m_pToolInfo.nStyles & PPTOOLTIP_BOTTOM_ALIGN) 
		rect.top = rect.bottom - m_szTextTooltip.cy; 
	else if (m_pToolInfo.nStyles & PPTOOLTIP_VCENTER_ALIGN) 
		rect.top += (rect.Height() - m_szTextTooltip.cy) / 2; 
 
	//Prints the tooltip's text 
	PrintTitleString(pDC, rect, m_pToolInfo.sTooltip, FALSE); 
 
	brBackground.DeleteObject(); 
	brBorder.DeleteObject(); 
} 
 
void CPPToolTip::OnDrawShadow(CDC * pDC) 
{ 
	CBrush brShadow(m_crColor [PPTOOLTIP_COLOR_SHADOW]); 
	//Draws the shadow for the tooltip 
	int nRop2Mode = pDC->SetROP2(R2_MASKPEN); 
	pDC->FillRgn(&m_rgnShadow, &brShadow); 
	pDC->SetROP2(nRop2Mode); 
	brShadow.DeleteObject(); 
} 
 
void CPPToolTip::OnDrawBackground(CDC * pDC, CRect * pRect) 
{ 
	switch (m_pToolInfo.nEffect) 
	{ 
	default: 
		pDC->FillSolidRect(pRect, m_crColor[PPTOOLTIP_COLOR_BK_BEGIN]); 
		break; 
	case PPTOOLTIP_EFFECT_HGRADIENT: 
		FillGradient(pDC, pRect, m_crColor[PPTOOLTIP_COLOR_BK_BEGIN], m_crColor [PPTOOLTIP_COLOR_BK_END], TRUE); 
		break; 
	case PPTOOLTIP_EFFECT_VGRADIENT: 
		FillGradient(pDC, pRect, m_crColor[PPTOOLTIP_COLOR_BK_BEGIN], m_crColor [PPTOOLTIP_COLOR_BK_END], FALSE); 
		break; 
	case PPTOOLTIP_EFFECT_HCGRADIENT: 
		FillGradient(pDC, CRect(pRect->left, pRect->top, pRect->left + pRect->Width() / 2, pRect->bottom),  
			m_crColor[PPTOOLTIP_COLOR_BK_BEGIN], m_crColor [PPTOOLTIP_COLOR_BK_END], TRUE); 
		FillGradient(pDC, CRect(pRect->left + pRect->Width() / 2, pRect->top, pRect->right, pRect->bottom),  
			m_crColor[PPTOOLTIP_COLOR_BK_END], m_crColor [PPTOOLTIP_COLOR_BK_BEGIN], TRUE); 
		break; 
	case PPTOOLTIP_EFFECT_VCGRADIENT: 
		FillGradient(pDC, CRect (pRect->left, pRect->top, pRect->right, pRect->top + pRect->Height() / 2),  
			m_crColor[PPTOOLTIP_COLOR_BK_BEGIN], m_crColor [PPTOOLTIP_COLOR_BK_END], FALSE); 
		FillGradient(pDC, CRect (pRect->left, pRect->top + pRect->Height() / 2, pRect->right, pRect->bottom),  
			m_crColor[PPTOOLTIP_COLOR_BK_END], m_crColor [PPTOOLTIP_COLOR_BK_BEGIN], FALSE); 
		break; 
	case PPTOOLTIP_EFFECT_3HGRADIENT: 
		FillGradient(pDC, CRect(pRect->left, pRect->top, pRect->left + pRect->Width()/2, pRect->bottom),  
			m_crColor[PPTOOLTIP_COLOR_BK_BEGIN], m_crColor [PPTOOLTIP_COLOR_BK_MID], TRUE); 
		FillGradient(pDC, CRect(pRect->left + pRect->Width() / 2, pRect->top, pRect->right, pRect->bottom),  
			m_crColor[PPTOOLTIP_COLOR_BK_MID], m_crColor [PPTOOLTIP_COLOR_BK_END], TRUE); 
		break; 
	case PPTOOLTIP_EFFECT_3VGRADIENT: 
		FillGradient(pDC, CRect (pRect->left, pRect->top, pRect->right, pRect->top + pRect->Height() / 2),  
			m_crColor[PPTOOLTIP_COLOR_BK_BEGIN], m_crColor [PPTOOLTIP_COLOR_BK_MID], FALSE); 
		FillGradient(pDC, CRect (pRect->left, pRect->top + pRect->Height() / 2, pRect->right, pRect->bottom),  
			m_crColor[PPTOOLTIP_COLOR_BK_MID], m_crColor [PPTOOLTIP_COLOR_BK_END], FALSE); 
		break; 
#ifdef PPTOOLTIP_USE_SHADE 
	case PPTOOLTIP_EFFECT_NOISE: 
	case PPTOOLTIP_EFFECT_DIAGSHADE: 
	case PPTOOLTIP_EFFECT_HSHADE: 
	case PPTOOLTIP_EFFECT_VSHADE: 
	case PPTOOLTIP_EFFECT_HBUMP: 
	case PPTOOLTIP_EFFECT_VBUMP: 
	case PPTOOLTIP_EFFECT_SOFTBUMP: 
	case PPTOOLTIP_EFFECT_HARDBUMP: 
	case PPTOOLTIP_EFFECT_METAL: 
		m_dNormal.Draw(pDC->GetSafeHdc(),0,0); 
		break; 
#endif 
	} 
} 
 
void CPPToolTip::RelayEvent(MSG* pMsg) 
{ 
	ASSERT(m_pParentWnd); 
	CWnd * pWnd = NULL; 
	CPoint pt; 
	CRect rect; 
	CString str; 
	int nIndexTool = PPTOOLTIP_TOOL_NOEXIST; 
 
//	PPTOOLTIP_INFO  Info; 
		 
	switch(pMsg->message) 
	{ 
	case WM_LBUTTONDOWN: 
	case WM_LBUTTONDBLCLK: 
	case WM_RBUTTONDOWN: 
	case WM_RBUTTONDBLCLK: 
	case WM_MBUTTONDOWN: 
	case WM_MBUTTONDBLCLK: 
	case WM_NCLBUTTONDOWN: 
	case WM_NCLBUTTONDBLCLK: 
	case WM_NCRBUTTONDOWN: 
	case WM_NCRBUTTONDBLCLK: 
	case WM_NCMBUTTONDOWN: 
	case WM_NCMBUTTONDBLCLK: 
	case WM_KEYDOWN: 
	case WM_SYSKEYDOWN: 
		// The user has interupted the current tool - dismiss it 
		Pop(); 
		break; 
	case WM_MOUSEMOVE: 
//		TRACE (_T("OnMouseMove()\n")); 
		if ((m_ptOriginal == pMsg->pt) ||  
			(m_nIndexCurrentWnd == PPTOOLTIP_TOOL_HELPER) || 
			(m_nIndexDisplayWnd == PPTOOLTIP_TOOL_HELPER)) 
			return; //Mouse pointer was not move 
 
		//Check Active window 
		if (!(m_nStyles & PPTOOLTIP_SHOW_INACTIVE)) 
		{ 
			pWnd = GetActiveWindow(); 
			if (!pWnd) 
				return; 
		} 
 
		m_ptOriginal = pMsg->pt; //Stores the mouse's coordinates 
		 
		//Gets the real window under the mouse 
		pt = pMsg->pt; 
		m_pParentWnd->ScreenToClient(&pt); 
		 
		nIndexTool = FindTool(pt); 
 
		if (!IsExistTool(nIndexTool)) 
		{ 
			//If the window under the mouse isn't exist 
			if (IsCursorInToolTip() && (m_pToolInfo.nBehaviour & PPTOOLTIP_CLOSE_LEAVEWND)) 
				return; 
			Pop(); 
			m_nIndexCurrentWnd = PPTOOLTIP_TOOL_NOEXIST; 
			m_nIndexDisplayWnd = PPTOOLTIP_TOOL_NOEXIST; 
			return; 
		} 
		else 
		{ 
			//The window under the mouse is exist 
			if (nIndexTool == m_nIndexDisplayWnd) 
			{ 
				if (IsVisible()) 
				{ 
					//Now the tooltip is visible 
					if ((m_pToolInfo.nBehaviour & PPTOOLTIP_CLOSE_LEAVEWND)) 
						return; 
				} 
				if (m_pToolInfo.nBehaviour & PPTOOLTIP_MULTIPLE_SHOW) 
				{ 
					SetNewToolTip(nIndexTool); 
				} 
				else Pop(); 
			} 
			else 
			{ 
				SetNewToolTip(nIndexTool, !IsVisible()); 
			} 
		} 
		break; 
	} 
} 
 
void CPPToolTip::SetNewToolTip(int nIndexTool, BOOL bWithDelay /* = TRUE */) 
{ 
	TRACE (_T("CPPToolTip::SetNewToolTip(Index = 0x%X)\n"), nIndexTool); 
	 
	m_nIndexDisplayWnd = PPTOOLTIP_TOOL_NOEXIST; //reset the displayed window 
	Pop(); 
 
	//Gets the info about current tool 
	if (!GetTool(nIndexTool, m_pToolInfo)) 
		return; 
 
	//Remembers the pointer to the current window 
	m_nIndexCurrentWnd = nIndexTool; 
 
	//Start the show timer 
	if (bWithDelay) 
		SetTimer(PPTOOLTIP_SHOW, m_nTimeInitial, NULL); 
	else 
		OnTimer(PPTOOLTIP_SHOW); 
} 
 
void CPPToolTip::OnTimer(UINT nIDEvent)  
{ 
	CPoint pt = m_ptOriginal, point; 
	CString str; 
	int nIndexTool = PPTOOLTIP_TOOL_HELPER; 
 
	switch (nIDEvent) 
	{ 
	case PPTOOLTIP_SHOW: 
		TRACE(_T("OnTimerShow\n")); 
		Pop(); 
		if (m_nIndexCurrentWnd != PPTOOLTIP_TOOL_HELPER) 
		{ 
			GetCursorPos(&pt); 
			point = pt; 
			m_pParentWnd->ScreenToClient(&point); 
			nIndexTool = FindTool(point); 
		} 
		if ((nIndexTool == m_nIndexCurrentWnd) && (pt == m_ptOriginal) && IsEnabledIndexTool(nIndexTool)) 
		{ 
			PrepareDisplayToolTip(&pt); 
			if (m_nTimeAutoPop && !(m_pToolInfo.nBehaviour & PPTOOLTIP_DISABLE_AUTOPOP)) //Don't hide window if autopop is 0 
				SetTimer(PPTOOLTIP_HIDE, m_nTimeAutoPop, NULL); 
		} 
		break; 
	case PPTOOLTIP_HIDE: 
		TRACE(_T("OnTimerHide\n")); 
		if (!IsCursorInToolTip() ||  
			!IsVisible() ||  
			!(m_pToolInfo.nBehaviour & PPTOOLTIP_NOCLOSE_OVER)) 
			Pop(); 
		break; 
	} 
	 
	CWnd::OnTimer(nIDEvent); 
} 
 
BOOL CPPToolTip::IsEnabledIndexTool(int nIndex) 
{ 
	return (BOOL)(IsExistTool(nIndex) || (nIndex == PPTOOLTIP_TOOL_HELPER)); 
} 
 
BOOL CPPToolTip::IsCursorInToolTip() const 
{ 
    ASSERT(m_pParentWnd); 
	 
    // Is tooltip visible? 
    if (!IsVisible() || !IsWindow(m_hWnd)) 
		return FALSE; 
	 
    CPoint pt; 
    GetCursorPos(&pt); 
	 
	CPPToolTip * pWnd = (CPPToolTip*)WindowFromPoint(pt); 
	 
	return (pWnd == this); 
} 
 
void CPPToolTip::KillTimers(UINT nIDTimer /* = NULL */) 
{ 
//	TRACE (_T("CPPToolTip::KillTimers\n")); 
	if (nIDTimer == NULL) 
	{ 
		KillTimer(PPTOOLTIP_SHOW); 
		KillTimer(PPTOOLTIP_HIDE); 
	} 
	else if (nIDTimer == PPTOOLTIP_SHOW) 
		KillTimer(PPTOOLTIP_SHOW); 
	else if (nIDTimer == PPTOOLTIP_HIDE) 
		KillTimer(PPTOOLTIP_HIDE); 
} 
 
void CPPToolTip::PrepareDisplayToolTip(CPoint * pt) 
{ 
	TRACE (_T("CPPToolTip::DisplayToolTip()\n")); 
	 
	//Fills default members 
	if (!(m_pToolInfo.nMask & PPTOOLTIP_MASK_STYLES)) 
		m_pToolInfo.nStyles = m_nStyles; 
	if (!(m_pToolInfo.nMask & PPTOOLTIP_MASK_EFFECT)) 
	{ 
		m_pToolInfo.nEffect = m_nEffect; 
		m_pToolInfo.nGranularity = m_nGranularity; 
	} 
	if (!(m_pToolInfo.nMask & PPTOOLTIP_MASK_COLORS)) 
	{ 
		m_pToolInfo.crBegin = m_crColor[PPTOOLTIP_COLOR_BK_BEGIN]; 
		m_pToolInfo.crMid = m_crColor[PPTOOLTIP_COLOR_BK_MID]; 
		m_pToolInfo.crEnd = m_crColor[PPTOOLTIP_COLOR_BK_END]; 
	} 
	if (!(m_pToolInfo.nMask & PPTOOLTIP_MASK_DIRECTION)) 
		m_pToolInfo.nDirection = m_nDirection; 
	if (!(m_pToolInfo.nMask & PPTOOLTIP_MASK_BEHAVIOUR)) 
		m_pToolInfo.nBehaviour = m_nBehaviour; 
	 
	//Send notify 
	SendNotify(pt, m_pToolInfo); 
 
	//If string and icon are not exist then exit 
	if ((m_pToolInfo.hIcon == NULL) && m_pToolInfo.sTooltip.IsEmpty()) 
		return; 
	 
	//calculate the width and height of the box dynamically 
    CSize sz = GetTooltipSize(m_pToolInfo.sTooltip); 
	m_szTextTooltip = sz; //Stores the real size of the tooltip's text 
	 
	//Gets size of the current icon 
	m_szToolIcon = GetSizeIcon(m_pToolInfo.hIcon); 
	if (m_szToolIcon.cx || m_szToolIcon.cy) 
	{ 
		sz.cx += m_szToolIcon.cx; 
		if (m_szTextTooltip.cx != 0) 
			sz.cx += m_nSizes[PPTTSZ_MARGIN_CX]; //If text is exist then adds separator 
		sz.cy = max(m_szToolIcon.cy, sz.cy); 
	} 
 
	//Gets size of the tooltip with margins 
	sz.cx += m_nSizes[PPTTSZ_MARGIN_CX] * 2; 
	sz.cy += m_nSizes[PPTTSZ_MARGIN_CY] * 2 + m_nSizes[PPTTSZ_HEIGHT_ANCHOR]; 
	if (m_pToolInfo.nStyles & PPTOOLTIP_SHADOW) 
	{ 
		sz.cx += m_nSizes[PPTTSZ_SHADOW_CX]; 
		sz.cy += m_nSizes[PPTTSZ_SHADOW_CY]; 
	} 
	 
	CRect rect (0, 0, sz.cx, sz.cy); 
	 
#ifdef PPTOOLTIP_USE_SHADE 
	//If needed to create the bitmap of the background effect 
	switch (m_pToolInfo.nEffect) 
	{ 
	case PPTOOLTIP_EFFECT_NOISE: 
	case PPTOOLTIP_EFFECT_DIAGSHADE: 
	case PPTOOLTIP_EFFECT_HSHADE: 
	case PPTOOLTIP_EFFECT_VSHADE: 
	case PPTOOLTIP_EFFECT_HBUMP: 
	case PPTOOLTIP_EFFECT_VBUMP: 
	case PPTOOLTIP_EFFECT_SOFTBUMP: 
	case PPTOOLTIP_EFFECT_HARDBUMP: 
	case PPTOOLTIP_EFFECT_METAL: 
		SetShade(rect, m_pToolInfo.nEffect, m_nGranularity, 5, m_pToolInfo.crBegin); 
	} 
#endif 
 
	DisplayToolTip(pt, &rect); 
} 
 
void CPPToolTip::DisplayToolTip(CPoint * pt, CRect * rect) 
{ 
	//Calculate the placement on the screen 
	CalculateInfoBoxRect(pt, rect); 
 
	SetWindowPos(NULL,  
                 rect->left, rect->top, 
                 rect->Width() + 2, rect->Height() + 2, 
                 SWP_SHOWWINDOW|SWP_NOCOPYBITS|SWP_NOACTIVATE|SWP_NOZORDER); 
 
	CRgn rgnCombo; 
	rgnCombo.CreateRectRgn(0, 0, 0, 0); 
	if (m_pToolInfo.nStyles & PPTOOLTIP_SHADOW) 
	{ 
		rect->right -= m_nSizes[PPTTSZ_SHADOW_CX]; 
		rect->bottom -= m_nSizes[PPTTSZ_SHADOW_CY]; 
	} 
	m_rgnToolTip.DeleteObject(); 
	GetWindowRegion(&m_rgnToolTip, CSize (rect->Width(), rect->Height()), *pt); 
	rgnCombo.CopyRgn(&m_rgnToolTip); 
	if (m_pToolInfo.nStyles & PPTOOLTIP_SHADOW) 
	{ 
		m_rgnShadow.DeleteObject(); 
		m_rgnShadow.CreateRectRgn(0, 0, 0, 0); 
		m_rgnShadow.CopyRgn(&m_rgnToolTip); 
		m_rgnShadow.OffsetRgn(m_nSizes[PPTTSZ_SHADOW_CX], m_nSizes[PPTTSZ_SHADOW_CY]); 
		rgnCombo.CombineRgn(&rgnCombo, &m_rgnShadow, RGN_OR); 
	} 
	SetWindowRgn((HRGN)rgnCombo.Detach(), FALSE); 
} 
 
CRect CPPToolTip::GetWindowRegion(CRgn * rgn, CSize sz, CPoint pt) 
{ 
	CRect rect; 
	rect.SetRect(0, 0, sz.cx, sz.cy); 
	CRgn rgnRect; 
	CRgn rgnAnchor; 
	CPoint ptAnchor [3]; 
	ptAnchor [0] = pt; 
	ScreenToClient(&ptAnchor [0]); 
	 
	switch (m_nLastDirection) 
	{ 
	case PPTOOLTIP_LEFT_TOP: 
	case PPTOOLTIP_RIGHT_TOP: 
		rect.bottom -= m_nSizes[PPTTSZ_HEIGHT_ANCHOR]; 
		ptAnchor [1].y = ptAnchor [2].y = rect.bottom; 
		break; 
	case PPTOOLTIP_LEFT_BOTTOM: 
	case PPTOOLTIP_RIGHT_BOTTOM: 
		rect.top += m_nSizes[PPTTSZ_HEIGHT_ANCHOR]; 
		ptAnchor [1].y = ptAnchor [2].y = rect.top; 
		break; 
	} 
	 
	//Gets the region for rectangle with the text 
	if (m_pToolInfo.nStyles & PPTOOLTIP_ROUNDED) 
		rgnRect.CreateRoundRectRgn(rect.left, rect.top, rect.right + 1, rect.bottom + 1,  
		m_nSizes[PPTTSZ_ROUNDED_CX], m_nSizes[PPTTSZ_ROUNDED_CY]); 
	else rgnRect.CreateRectRgn(rect.left, rect.top, rect.right + 1, rect.bottom + 1); 
	 
	//Gets the region for anchor 
	if (m_pToolInfo.nStyles & PPTOOLTIP_ANCHOR) 
	{ 
		switch (m_nLastDirection) 
		{ 
		case PPTOOLTIP_LEFT_TOP: 
		case PPTOOLTIP_LEFT_BOTTOM: 
			ptAnchor [1].x = rect.right - m_nSizes[PPTTSZ_MARGIN_ANCHOR]; 
			ptAnchor [2].x = ptAnchor [1].x - m_nSizes[PPTTSZ_WIDTH_ANCHOR]; 
			break; 
		case PPTOOLTIP_RIGHT_TOP: 
		case PPTOOLTIP_RIGHT_BOTTOM: 
			ptAnchor [1].x = rect.left + m_nSizes[PPTTSZ_MARGIN_ANCHOR]; 
			ptAnchor [2].x = ptAnchor [1].x + m_nSizes[PPTTSZ_WIDTH_ANCHOR]; 
			break; 
		} 
		rgnAnchor.CreatePolygonRgn(ptAnchor, 3, ALTERNATE); 
	} 
	else 
		rgnAnchor.CreateRectRgn(0, 0, 0, 0); 
	 
	rgn->CreateRectRgn(0, 0, 0, 0); 
	rgn->CombineRgn(&rgnRect, &rgnAnchor, RGN_OR); 
	 
	rgnAnchor.DeleteObject(); 
	rgnRect.DeleteObject(); 
	 
	return rect; 
} 
 
/////////////////////////////////////////////////// 
//	Gets the size of the current tooltip text 
// 
//	Parameters: 
//		none 
// 
//	Return value: 
//		Size of current tooltip text 
/////////////////////////////////////////////////// 
CSize CPPToolTip::GetTooltipSize(CString str) 
{ 
	//Gets max windows rectangle 
	CRect rect; 
	GetWindowRect(&rect); 
 
	//Creates compatibility context device in memory 
//	CDC * pDC = GetDC(); 
	CWindowDC dc(NULL); 
 
	CDC memDC; 
	CBitmap bitmap; 
	memDC.CreateCompatibleDC(&dc); 
//	memDC.CreateCompatibleDC(pDC); 
	bitmap.CreateCompatibleBitmap(&dc, rect.Width(), rect.Height()); 
//	bitmap.CreateCompatibleBitmap(pDC, rect.Width(), rect.Height()); 
	CBitmap* pOldBitmap = memDC.SelectObject(&bitmap); 
 
	//Prints the string on device context for gets minimal size of the rectangle  
	//of the tooltip 
	CSize sz = PrintTitleString(&memDC, rect, str); 
 
	memDC.SelectObject(pOldBitmap); 
	memDC.DeleteDC(); 
	bitmap.DeleteObject(); 
 
//	ReleaseDC(pDC); 
 
	//Returns minimal rectangle of the tooltip 
	return sz; 
} 
 
CSize CPPToolTip::GetSizeIcon(HICON hIcon) const 
{ 
	ICONINFO ii; 
	CSize sz (0, 0); 
 
	if (hIcon != NULL) 
	{ 
		// Gets icon dimension 
		::ZeroMemory(&ii, sizeof(ICONINFO)); 
		if (::GetIconInfo(hIcon, &ii)) 
		{ 
			sz.cx = (DWORD)(ii.xHotspot * 2); 
			sz.cy = (DWORD)(ii.yHotspot * 2); 
			//release icon mask bitmaps 
			if(ii.hbmMask) 
				::DeleteObject(ii.hbmMask); 
			if(ii.hbmColor) 
				::DeleteObject(ii.hbmColor); 
		} 
	} 
	return sz; 
} 
 
/////////////////////////////////////////////////// 
//	Calculates the real rect for the tooltip with margins 
// 
//	Parameters: 
//		pt		[in] - the mouse coordinates (screen coordinates) 
//		sz		[in] - the size of the tooltip text 
// 
//	Return value: 
//		The rectangle when the tooltip will draw (screen coordinates) 
/////////////////////////////////////////////////// 
void CPPToolTip::CalculateInfoBoxRect(CPoint * pt, CRect * rect) 
{ 
	// Use the screen's right edge as the right hand border, not the right edge of the client. 
	CWindowDC wdc(NULL); 
	CRect rWindow(0, 0, 0, 0); 
	rWindow.right = GetDeviceCaps(wdc, HORZRES);// - 8; 
	rWindow.bottom = GetDeviceCaps(wdc, VERTRES);// - 8; 
/* 
	m_szToolIcon = GetSizeIcon(m_pToolInfo.hIcon); 
	if (m_szToolIcon.cx || m_szToolIcon.cy) 
	{ 
		sz.cx += m_szToolIcon.cx + m_nSizes[PPTTSZ_MARGIN_CX]; 
		sz.cy = max(m_szToolIcon.cy, sz.cy); 
	} 
 
	//Gets size of the tooltip with margins 
	sz.cx += m_nSizes[PPTTSZ_MARGIN_CX] * 2; 
	sz.cy += m_nSizes[PPTTSZ_MARGIN_CY] * 2 + m_nSizes[PPTTSZ_HEIGHT_ANCHOR]; 
	if (m_pToolInfo.nStyles & PPTOOLTIP_SHADOW) 
	{ 
		rWindow.right -= m_nSizes[PPTTSZ_SHADOW_CX]; 
		rWindow.bottom -= m_nSizes[PPTTSZ_SHADOW_CY]; 
		sz.cx += m_nSizes[PPTTSZ_SHADOW_CX]; 
		sz.cy += m_nSizes[PPTTSZ_SHADOW_CY]; 
	} 
*/	 
//	CRect rect; 
//	rect.SetRect(0, 0, sz.cx, sz.cy); 
//	CRect rectCopy = *rect; 
	 
	//Offset the rect from the mouse pointer 
	CPoint ptEnd; 
	m_nLastDirection = m_pToolInfo.nDirection; 
	 
	if (!TestHorizDirection(pt->x, rect->Width(), rWindow.right, m_nLastDirection, rect)) 
	{ 
		m_nLastDirection = GetNextHorizDirection(m_nLastDirection); 
		TestHorizDirection(pt->x, rect->Width(), rWindow.right, m_nLastDirection, rect); 
	} 
	if (!TestVertDirection(pt->y, rect->Height(), rWindow.bottom, m_nLastDirection, rect)) 
	{ 
		m_nLastDirection = GetNextVertDirection(m_nLastDirection); 
		TestVertDirection(pt->y, rect->Height(), rWindow.bottom, m_nLastDirection, rect); 
	} 
 
	//Returns the rect of the tooltip 
	if ((m_pToolInfo.nStyles & PPTOOLTIP_SHADOW) &&  
		((m_nLastDirection == PPTOOLTIP_LEFT_TOP) || (m_nLastDirection == PPTOOLTIP_LEFT_BOTTOM))) 
		rect->OffsetRect(m_nSizes[PPTTSZ_SHADOW_CX], m_nSizes[PPTTSZ_SHADOW_CY]); 
} 
 
/////////////////////////////////////////////////// 
//	Gets the next horizontal direction 
// 
//	Parameters: 
//		nDirection		[in] - the current direction 
// 
//	Return value: 
//		The next horizontal direction 
/////////////////////////////////////////////////// 
int CPPToolTip::GetNextHorizDirection(int nDirection) const 
{ 
	switch (nDirection) 
	{ 
	case PPTOOLTIP_LEFT_TOP: 
		nDirection = PPTOOLTIP_RIGHT_TOP; 
		break; 
	case PPTOOLTIP_RIGHT_TOP: 
		nDirection = PPTOOLTIP_LEFT_TOP; 
		break; 
	case PPTOOLTIP_LEFT_BOTTOM: 
		nDirection = PPTOOLTIP_RIGHT_BOTTOM; 
		break; 
	case PPTOOLTIP_RIGHT_BOTTOM: 
		nDirection = PPTOOLTIP_LEFT_BOTTOM; 
		break; 
	} 
	return nDirection; 
} 
 
/////////////////////////////////////////////////// 
//	Gets the next vertical direction 
// 
//	Parameters: 
//		nDirection		[in] - the current direction 
// 
//	Return value: 
//		The next vertical direction 
/////////////////////////////////////////////////// 
int CPPToolTip::GetNextVertDirection(int nDirection) const 
{ 
	switch (nDirection) 
	{ 
	case PPTOOLTIP_LEFT_TOP: 
		nDirection = PPTOOLTIP_LEFT_BOTTOM; 
		break; 
	case PPTOOLTIP_LEFT_BOTTOM: 
		nDirection = PPTOOLTIP_LEFT_TOP; 
		break; 
	case PPTOOLTIP_RIGHT_TOP: 
		nDirection = PPTOOLTIP_RIGHT_BOTTOM; 
		break; 
	case PPTOOLTIP_RIGHT_BOTTOM: 
		nDirection = PPTOOLTIP_RIGHT_TOP; 
		break; 
	} 
	return nDirection; 
} 
 
BOOL CPPToolTip::TestHorizDirection(int x, int cx, int w_cx, int nDirection, LPRECT rect) const 
{ 
	int left,right; 
	 
	switch (nDirection) 
	{ 
	case PPTOOLTIP_LEFT_TOP: 
	case PPTOOLTIP_LEFT_BOTTOM: 
		right = ((x + (int)m_nSizes[PPTTSZ_MARGIN_ANCHOR]) > w_cx) ? w_cx : (x + m_nSizes[PPTTSZ_MARGIN_ANCHOR]); 
		left = right - cx; 
		break; 
	case PPTOOLTIP_RIGHT_TOP: 
	case PPTOOLTIP_RIGHT_BOTTOM: 
		left = (x < (int)m_nSizes[PPTTSZ_MARGIN_ANCHOR]) ? 0 : (x - m_nSizes[PPTTSZ_MARGIN_ANCHOR]); 
		right = left + cx; 
		break; 
	} 
 
	BOOL bTestOk = ((left >= 0) && (right <= w_cx)) ? TRUE : FALSE; 
	if (bTestOk) 
	{ 
		rect->left = left; 
		rect->right = right; 
	} 
 
	return bTestOk; 
} 
 
BOOL CPPToolTip::TestVertDirection(int y, int cy, int w_cy, int nDirection, LPRECT rect) const 
{ 
	int top, bottom; 
 
	switch (nDirection) 
	{ 
	case PPTOOLTIP_LEFT_TOP: 
	case PPTOOLTIP_RIGHT_TOP: 
		bottom = y; 
		top = bottom - cy; 
		break; 
	case PPTOOLTIP_LEFT_BOTTOM: 
	case PPTOOLTIP_RIGHT_BOTTOM: 
		top = y; 
		bottom = top + cy; 
		break; 
	} 
 
	BOOL bTestOk = ((top >= 0) && (bottom <= w_cy)) ? TRUE : FALSE; 
	if (bTestOk) 
	{ 
		rect->top = top; 
		rect->bottom = bottom; 
	} 
 
	return bTestOk; 
} 
 
///////////////////////////////////////////////////////////////// 
// Gets the system tooltip's logfont 
///////////////////////////////////////////////////////////////// 
LPLOGFONT CPPToolTip::GetSystemToolTipFont() const 
{ 
    static LOGFONT LogFont; 
 
    NONCLIENTMETRICS ncm; 
    ncm.cbSize = sizeof(NONCLIENTMETRICS); 
    if (!SystemParametersInfo(SPI_GETNONCLIENTMETRICS, sizeof(NONCLIENTMETRICS), &ncm, 0)) 
        return FALSE; 
 
    memcpy(&LogFont, &(ncm.lfStatusFont), sizeof(LOGFONT)); 
 
    return &LogFont;  
} 
 
///////////////////////////////////////////////////////////////// 
// Prints the formating string of the tooltip 
//   
// Parameters: 
//		pDC			 - [in] The device context to print the string 
//      str			 - [in] The formating string for drawing 
//      rect         - [in] The rectangle to draws the tooltip 
//		bEnableAlign - [in] If TRUE align's operators are enables. 
// 
// Return values: 
//      None. 
//--------------------------------------------------------------- 
// Format of string: 
//   text  - The bold string 
//   text  - The italic string  
//   text  - The underline string 
//   text  - The strike out string 
// 
//   text  - The background color (RGB (12,34,56)) 
//   text  - The text color (RGB (12,34,56)) 
// 
//   text  - The index background color(0 - F) 
//   text  - The index text color(0 - F) 
// 
//	 or  - sets align to left edge 
//   - sets align to the center  
//   - sets align to the right edge 
// 
//	 - the horizontal line with length 100% 
//   - the horizontal line with length 32 pixels. 
// 
//	 text  - The hyperlink  
// 
//   text  - hot zone (number of zone) 
// 
//	 - new line (numbers of the lines) 
//   - tabulation (number of tabulations) 
// 
//  				 - draws the image by his name 
//  								 - draws the image from image list 
//   - draws bitmap 
//  				 - draws the icon 
//////////////////////////////////////////////////////////////// 
CSize CPPToolTip::PrintTitleString(CDC * pDC, CRect rect, CString str, BOOL bCalculate /* = TRUE */) 
{ 
	enum{	CMD_NONE = 0, 
			CMD_BOLD, 
			CMD_ITALIC, 
			CMD_STRIKE, 
			CMD_UNDERLINE, 
			CMD_COLOR_TEXT, 
			CMD_COLOR_TEXT_INDEX, 
			CMD_COLOR_BK, 
			CMD_COLOR_BK_INDEX, 
			CMD_NEW_LINE, 
			CMD_TABULATION, 
			CMD_HORZ_LINE, 
			CMD_HORZ_LINE_PERCENT, 
			CMD_DRAW_IMAGE, 
			CMD_DRAW_IMAGE_LIST, 
			CMD_DRAW_BITMAP, 
			CMD_DRAW_BITMAP_MASK, 
			CMD_DRAW_ICON 
	}; 
 
	enum{	ALIGN_LEFT = 0, 
			ALIGN_CENTER, 
			ALIGN_RIGHT 
		}; 
 
	//Clears the length of the lines 
	if (bCalculate) 
	{ 
		m_nLengthLines.RemoveAll(); 
		m_nHeightLines.RemoveAll(); 
	} 
	 
	int nLine = 0; 
	int nCmd = CMD_NONE; 
	int nAlign = ALIGN_LEFT; 
	BOOL bCloseTag = FALSE; 
 
	CSize sz(0, 0); 
	CSize szLine (0, 0); 
	CSize szIcon (0, 0); //The size of icon 
 
	if (str.IsEmpty()) 
		return sz; 
 
	CPoint	pt = rect.TopLeft(); 
	CPoint  ptCur = pt; 
	 
	// Copies default logfont's structure 
	LOGFONT lf; 
    memcpy(&lf, &m_LogFont, sizeof(LOGFONT)); 
 
	CFont font; 
	font.CreateFontIndirect(&lf); 
 
	CFont * pOldFont = pDC->SelectObject(&font); 
 
	TEXTMETRIC tm; 
	pDC->GetTextMetrics(&tm); 
	int nHeight = tm.tmHeight; //The height of the font 
	int nWidth = tm.tmAveCharWidth; //The width of the font 
 
	CString strTag = _T("");  // Tag's name  
	CString strText = _T(""); // The current text to output 
	CString sParam = _T(""); // The text parameter 
 
	UINT nParam = 0, nParam1 = 0; 
	int nLineHeight = bCalculate ? nHeight : m_nHeightLines.GetAt(0); //The height of the current line 
	 
	CUIntArray percent; 
	percent.Add(0); 
 
	int nTemp = 0; //the temporary variable 
	BOOL bFirstOutput = TRUE; 
	 
	for (int i = 0; i <= str.GetLength(); i++) 
	{ 
		if (i < str.GetLength()) 
		{ 
			nCmd = CMD_NONE; 
			strText = SearchBeginOfTag(str, i); 
			if (strText.IsEmpty()) 
			{ 
				//Tag was found 
				strTag = GetNameOfTag(str, i); 
				bCloseTag = (strTag.GetAt(0) == _T('/')) ? TRUE : FALSE; 
				if (bCloseTag) 
					strTag = strTag.Right(strTag.GetLength() - 1); 
				 
				if (!strTag.CompareNoCase(_T("b"))) 
				{ 
					nCmd = CMD_BOLD; 
				} 
				else if (!strTag.CompareNoCase(_T("i"))) 
				{ 
					nCmd = CMD_ITALIC; 
				} 
				else if (!strTag.CompareNoCase(_T("u"))) 
				{ 
					nCmd = CMD_UNDERLINE; 
				} 
				else if (!strTag.CompareNoCase(_T("s"))) 
				{ 
					nCmd = CMD_STRIKE; 
				} 
				else if (!strTag.CompareNoCase(_T("br"))) 
				{ 
					nCmd = CMD_NEW_LINE; 
					nParam = GetUIntValue(str, i, 1); 
				} 
				else if (!strTag.CompareNoCase(_T("t"))) 
				{ 
					nCmd = CMD_TABULATION; 
					nParam = GetUIntValue(str, i, 1); 
				} 
				else if (strTag.GetAt(0) == _T('\n')) 
				{ 
					nCmd = CMD_NEW_LINE; 
					nParam = 1; 
				} 
				else if (strTag.GetAt(0) == _T('\t')) 
				{ 
					nCmd = CMD_TABULATION; 
					nParam = 1; 
				} 
				else if (!strTag.CompareNoCase(_T("ct"))) 
				{ 
					nCmd = CMD_COLOR_TEXT; 
					nParam = GetUIntValue(str, i, (UINT)m_crColor[PPTOOLTIP_COLOR_FG]); 
				} 
				else if (!strTag.CompareNoCase(_T("cti"))) 
				{ 
					nCmd = CMD_COLOR_TEXT; 
					nParam = GetUIntValue(str, i, PPTOOLTIP_COLOR_FG); 
				} 
				else if (!strTag.CompareNoCase(_T("cb"))) 
				{ 
					nCmd = CMD_COLOR_BK; 
					nParam = GetUIntValue(str, i, (UINT)m_crColor[PPTOOLTIP_COLOR_BK_BEGIN]); 
				} 
				else if (!strTag.CompareNoCase(_T("cbi"))) 
				{ 
					nCmd = CMD_COLOR_BK_INDEX; 
					nParam = GetUIntValue(str, i, PPTOOLTIP_COLOR_BK_BEGIN); 
				} 
				else if (!strTag.CompareNoCase(_T("al")) || !strTag.CompareNoCase(_T("al_l"))) 
				{ 
					nAlign = ALIGN_LEFT; 
				} 
				else if (!strTag.CompareNoCase(_T("al_c"))) 
				{ 
					if (!bCalculate) 
						nAlign = ALIGN_CENTER; 
				} 
				else if (!strTag.CompareNoCase(_T("al_r"))) 
				{ 
					if (!bCalculate) 
						nAlign = ALIGN_RIGHT; 
				} 
				else if (!strTag.CompareNoCase(_T("hr"))) 
				{ 
					sParam = GetStringValue(str, i); 
					if (!sParam.IsEmpty()) 
						nParam = _tcstoul(sParam, 0, 0); 
					else 
						nParam = 100; 
					nCmd = (sParam.Right(1) == _T("%"))? CMD_HORZ_LINE_PERCENT : CMD_HORZ_LINE; 
				} 
				else if (!strTag.CompareNoCase(_T("img"))) 
				{ 
					nCmd = CMD_DRAW_IMAGE; 
					sParam = GetStringValue(str, i); 
					szIcon = CSize(0, 0); 
					//Gets two param 
					for (nTemp = 0; nTemp < 2; nTemp++) 
					{ 
						strTag = GetPropertiesOfTag(str, i); 
						if (!strTag.CompareNoCase(_T("cx"))) 
							szIcon.cx = GetUIntValue(str, i, 0); 
						else if (!strTag.CompareNoCase(_T("cy"))) 
							szIcon.cy = GetUIntValue(str, i, 0); 
					} 
				} 
				else if (!strTag.CompareNoCase(_T("ilst"))) 
				{ 
					nCmd = CMD_DRAW_IMAGE_LIST; 
					nParam = GetUIntValue(str, i, 0); 
				} 
				else if (!strTag.CompareNoCase(_T("icon"))) 
				{ 
					nCmd = CMD_DRAW_ICON; 
					nParam = GetUIntValue(str, i, 0); 
					szIcon = CSize(0, 0); 
					//Gets two param 
					for (nTemp = 0; nTemp < 2; nTemp++) 
					{ 
						strTag = GetPropertiesOfTag(str, i); 
						if (!strTag.CompareNoCase(_T("cx"))) 
							szIcon.cx = GetUIntValue(str, i, 0); 
						else if (!strTag.CompareNoCase(_T("cy"))) 
							szIcon.cy = GetUIntValue(str, i, 0); 
					} 
				} 
				else if (!strTag.CompareNoCase(_T("bmp"))) 
				{ 
					nCmd = CMD_DRAW_BITMAP; 
					nParam = GetUIntValue(str, i, 0); 
					sParam.Empty(); 
					//Gets three param 
					for (nTemp = 0; nTemp < 3; nTemp++) 
					{ 
						strTag = GetPropertiesOfTag(str, i); 
						if (!strTag.CompareNoCase(_T("mask"))) 
						{ 
							sParam = strTag; 
							nParam1 = GetUIntValue(str, i, 0xFF00FF); 
						} 
						else if (!strTag.CompareNoCase(_T("cx"))) 
							szIcon.cx = GetUIntValue(str, i, 0); 
						else if (!strTag.CompareNoCase(_T("cy"))) 
							szIcon.cy = GetUIntValue(str, i, 0); 
					} 
				} 
				else nCmd = CMD_NONE; 
				SearchEndOfTag(str, i); 
			} 
			else 
			{ 
				//If text to output is exist 
				if (bFirstOutput) 
				{ 
					switch (nAlign) 
					{ 
					case ALIGN_CENTER: 
						ptCur.x = pt.x + (rect.Width() - m_nLengthLines.GetAt(nLine)) / 2; 
						break; 
					case ALIGN_RIGHT: 
						ptCur.x = pt.x + rect.Width() - m_nLengthLines.GetAt(nLine); 
						break; 
					} 
				} 
				szLine = pDC->GetTextExtent(strText); 
				if (bCalculate) 
					nLineHeight = max(nLineHeight, szLine.cy); 
				else 
					pDC->TextOut(ptCur.x, ptCur.y + m_nHeightLines.GetAt(nLine) - nHeight, strText); 
				ptCur.x += szLine.cx; 
				strText = _T(""); 
				bFirstOutput = FALSE; 
				i--; 
			} 
		} 
		else 
		{ 
			nCmd = CMD_NEW_LINE; 
			nParam = 1;  
		} 
				 
		//Prepares to first draw in line 
		switch (nCmd) 
		{ 
		case CMD_DRAW_IMAGE: 
		case CMD_DRAW_IMAGE_LIST: 
		case CMD_DRAW_BITMAP: 
		case CMD_DRAW_ICON: 
			if (bFirstOutput) 
			{ 
				switch (nAlign) 
				{ 
				case ALIGN_CENTER: 
					ptCur.x = pt.x + (rect.Width() - m_nLengthLines.GetAt(nLine)) / 2; 
					break; 
				case ALIGN_RIGHT: 
					ptCur.x = pt.x + rect.Width() - m_nLengthLines.GetAt(nLine); 
					break; 
				} 
				bFirstOutput = FALSE; 
			} 
			break; 
		} 
		 
		//Executes command 
		switch (nCmd) 
		{ 
		case CMD_BOLD: 
			//Bold text 
			pDC->SelectObject(pOldFont); 
			font.DeleteObject(); 
			lf.lfWeight = m_LogFont.lfWeight; 
			if (!bCloseTag) 
			{ 
				lf.lfWeight *= 2; 
				if (lf.lfWeight > FW_BLACK) 
					lf.lfWeight = FW_BLACK; 
			} 
			font.CreateFontIndirect(&lf); 
			pDC->SelectObject(&font); 
			break; 
		case CMD_ITALIC: 
			//Italic text 
			pDC->SelectObject(pOldFont); 
			font.DeleteObject(); 
			lf.lfItalic = bCloseTag ? FALSE : TRUE; 
			font.CreateFontIndirect(&lf); 
			pDC->SelectObject(&font); 
			break; 
		case CMD_STRIKE: 
			//Strikeout text 
			pDC->SelectObject(pOldFont); 
			font.DeleteObject(); 
			lf.lfStrikeOut = bCloseTag ? FALSE : TRUE; 
			font.CreateFontIndirect(&lf); 
			pDC->SelectObject(&font); 
			break; 
		case CMD_UNDERLINE: 
			//Underline text 
			pDC->SelectObject(pOldFont); 
			font.DeleteObject(); 
			lf.lfUnderline = bCloseTag ? FALSE : TRUE; 
			font.CreateFontIndirect(&lf); 
			pDC->SelectObject(&font); 
			break; 
		case CMD_COLOR_TEXT: 
			//Color of the text 
			pDC->SetTextColor((COLORREF)nParam); 
			break; 
		case CMD_COLOR_TEXT_INDEX: 
			//Indexed color of the text 
			if (nParam < PPTOOLTIP_MAX_COLORS) 
				pDC->SetTextColor(m_crColor[nParam]); 
			break; 
		case CMD_COLOR_BK: 
			//Color of the background 
			pDC->SetBkColor((COLORREF)nParam); 
			pDC->SetBkMode(bCloseTag ? TRANSPARENT : OPAQUE); 
			break; 
		case CMD_COLOR_BK_INDEX: 
			//Indexed color of the background 
			if (nParam < PPTOOLTIP_MAX_COLORS) 
			{ 
				pDC->SetBkColor(m_crColor[nParam]); 
				pDC->SetBkMode(bCloseTag ? TRANSPARENT : OPAQUE); 
			} 
			break; 
		case CMD_HORZ_LINE_PERCENT: 
			//Horizontal line with percent length 
			if (bCalculate) 
			{ 
				percent.SetAt(nLine, percent.GetAt(nLine) + nParam); 
				nParam = 0; 
			} 
			else nParam = ::MulDiv(rect.Width(), nParam, 100); 
		case CMD_HORZ_LINE: 
			//Horizontal line with absolute length 
			//If text to output is exist 
			if (!bCalculate) 
				DrawHorzLine(pDC, ptCur.x, ptCur.x + nParam, ptCur.y + m_nHeightLines.GetAt(nLine) / 2); 
			ptCur.x += nParam; 
			break; 
		case CMD_DRAW_IMAGE: 
			if (!sParam.IsEmpty()) 
			{ 
				if (bCalculate) 
				{ 
					szLine = DrawResource(sParam, pDC, ptCur, 0, szIcon, bCalculate); 
					nLineHeight = max (nLineHeight, szLine.cy); 
				} 
				else 
					szLine = DrawResource(sParam, pDC, ptCur, m_nHeightLines.GetAt(nLine), szIcon, bCalculate); 
 
				ptCur.x += szLine.cx; 
			} 
			break; 
		case CMD_DRAW_IMAGE_LIST: 
			if (m_imgTooltip.m_hImageList != NULL) 
			{ 
				if (bCalculate) 
				{ 
					szLine = DrawIconFromImageList(pDC, ptCur, m_szImage, m_imgTooltip, nParam, bCalculate); 
					nLineHeight = max (nLineHeight, szLine.cy); 
				} 
				else 
				{ 
					szLine = DrawIconFromImageList(pDC, ptCur, m_szImage, m_imgTooltip, nParam, bCalculate); 
				} 
				// If in one line a few bitmap with different height, then store max height 
				ptCur.x += szLine.cx; //m_szImage.cx; 
			} 
			break; 
		case CMD_DRAW_BITMAP: 
			if (nParam != 0) 
			{ 
				if (bCalculate) 
				{ 
					szLine = DrawBitmap(pDC, ptCur, 0, nParam, !sParam.IsEmpty(), nParam1, szIcon, bCalculate); 
					nLineHeight = max (nLineHeight, szLine.cy); 
				} 
				else 
				{ 
					szLine = DrawBitmap(pDC, ptCur, m_nHeightLines.GetAt(nLine), nParam, !sParam.IsEmpty(), nParam1, szIcon, bCalculate); 
				} 
				// If in one line a few bitmap with different height, then store max height 
				ptCur.x += szLine.cx; 
			} 
		case CMD_DRAW_ICON: 
			if (nParam != 0) 
			{ 
				if (bCalculate) 
				{ 
					szLine = DrawIcon(pDC, ptCur, 0, nParam, szIcon, bCalculate); 
					nLineHeight = max (nLineHeight, szLine.cy); 
				} 
				else 
				{ 
					szLine = DrawIcon(pDC, ptCur, m_nHeightLines.GetAt(nLine), nParam, szIcon, bCalculate); 
				} 
				// If in one line a few bitmap with different height, then store max height 
				ptCur.x += szLine.cx; 
			} 
			break; 
		case CMD_NEW_LINE: 
			//New line 
			if (!nParam) 
				nParam = 1; 
			if (bCalculate) 
			{ 
				sz.cx = max(sz.cx, ptCur.x - pt.x); 
				m_nLengthLines.Add(ptCur.x - pt.x); //Adds the real length of the lines 
				m_nHeightLines.Add(nLineHeight); //Adds the real height of the lines 
			} 
			ptCur.y += m_nHeightLines.GetAt(nLine) * nParam; 
			nLine ++; 
			percent.Add(0); 
			bFirstOutput = TRUE; 
			ptCur.x = pt.x; 
			nLineHeight = nHeight; 
	//		szLine.cy = nHeight; 
			break; 
		case CMD_TABULATION: 
			//Tabulation 
			if (!nParam) 
				nParam = 1; 
			nParam1 = (ptCur.x - pt.x) % (nWidth * 4); 
			if (nParam1) 
			{ 
				//aligns with tab 
				ptCur.x += (nWidth * 4) - nParam1; 
				nParam --; 
			} 
			ptCur.x += (nParam * nWidth * 4); 
			break; 
		} 
	} 
	 
	//Gets real height of the tooltip 
	sz.cy = ptCur.y - pt.y; 
 
	pDC->SelectObject(pOldFont); 
	font.DeleteObject(); 
 
	//Adds the percent's length to the line's length 
	for (i = 0; i < percent.GetSize(); i++) 
	{ 
		if (percent.GetAt(i)) 
			m_nLengthLines.SetAt(i, m_nLengthLines.GetAt(i) + ::MulDiv(percent.GetAt(i), sz.cx, 100)); 
	} 
 
	return sz; 
} 
 
CString CPPToolTip::SearchBeginOfTag(CString & str, int & nIndex) 
{ 
	CString sText = _T(""); 
	BOOL bTagFound = FALSE; 
	 
	for (nIndex; nIndex < str.GetLength(); nIndex ++) 
	{ 
		switch (str.GetAt(nIndex)) 
		{ 
		case _T('\r'): 
			break; 
		case _T('<'): 
			nIndex ++; 
			if ((nIndex < str.GetLength()) && (str.GetAt(nIndex) != _T('<'))) 
			{ 
				if (!sText.IsEmpty()) 
					nIndex --; 
				return sText; 
			} 
			sText += _T('<'); 
			break; 
		case _T('\t'): 
		case _T('\n'): 
			if (!sText.IsEmpty()) 
				nIndex--; 
			return sText; 
		default: 
			sText += str.GetAt(nIndex); 
			break; 
		} 
	} 
	return sText; 
} 
 
void CPPToolTip::SearchEndOfTag(CString & str, int & nIndex) 
{ 
	for (nIndex; nIndex < str.GetLength(); nIndex ++) 
	{ 
		switch (str.GetAt(nIndex)) 
		{ 
		case _T('>'): 
		case _T('\n'): 
		case _T('\t'): 
			return; 
		} 
	} 
} 
 
CString CPPToolTip::GetNameOfTag(CString & str, int & nIndex) 
{ 
	CString sText = _T(""); 
	 
	for (nIndex; nIndex < str.GetLength(); nIndex ++) 
	{ 
		switch (str.GetAt(nIndex)) 
		{ 
		case _T('\r'): //Pass character 
			break; 
		case _T('\t'): //It is a tab tag 
		case _T('\n'): //It is a new line tag 
			if (sText.IsEmpty()) 
			{ 
				sText += str.GetAt(nIndex); 
//				nIndex ++; 
				return sText; 
			} 
			break; 
		case _T(' '): 
			if (!sText.IsEmpty()) 
			{ 
				nIndex ++; 
				return sText; 
			} 
			break; 
		case _T('>'): 
		case _T('='): 
			return sText; 
		default: 
			sText += str.GetAt(nIndex); 
			break; 
		} 
	} 
	return sText; 
} 
 
CString CPPToolTip::GetPropertiesOfTag(CString & str, int & nIndex) 
{ 
	CString sText = _T(""); 
	 
	for (nIndex; nIndex < str.GetLength(); nIndex ++) 
	{ 
		switch (str.GetAt(nIndex)) 
		{ 
		case _T('\r'): //Pass characters 
		case _T('\t'): 
		case _T('\n'): 
			break; 
		case _T(' '): 
			if (!sText.IsEmpty()) 
			{ 
				nIndex ++; 
				return sText; 
			} 
			break; 
		case _T('>'): 
		case _T('='): 
			return sText; 
		default: 
			sText += str.GetAt(nIndex); 
			break; 
		} 
	} 
	return sText; 
} 
 
CString CPPToolTip::GetStringValue(CString & str, int & nIndex) 
{ 
	CString sText = _T(""); 
	BOOL bValueFound = FALSE; 
	 
	for (nIndex; nIndex < str.GetLength(); nIndex ++) 
	{ 
		switch (str.GetAt(nIndex)) 
		{ 
		case _T('\r'): //Pass character 
		case _T('\t'): //It is a tab tag 
		case _T('\n'): //It is a new line tag 
			break; 
		case _T(' '): 
			if (!sText.IsEmpty()) 
			{ 
				nIndex ++; 
				return sText; 
			} 
			break; 
		case _T('>'): 
			return sText; 
		case _T('='): 
			bValueFound = TRUE; 
			break; 
		default: 
			if (!bValueFound) 
				return sText; 
			sText += str.GetAt(nIndex); 
			break; 
		} 
	} 
	return sText; 
 
} 
 
UINT CPPToolTip::GetUIntValue(CString & str, int & nIndex, UINT nDefValue) 
{ 
	CString sText = GetStringValue(str, nIndex); 
	if (!sText.IsEmpty()) 
		nDefValue = _tcstoul(sText, 0, 0); 
 
	return nDefValue; 
} 
 
CSize CPPToolTip::DrawResource(CString sName, CDC * pDC, CPoint pt, int nMaxHeight, CSize szResource, BOOL bCalculate) 
{ 
	CSize sz(0, 0); 
	 
	int nIndex = FindIdOfResource(sName); 
	if (nIndex < 0) 
		return sz; 
 
	PPTOOLTIP_NAME_RES nr = m_arrNameRes.GetAt(nIndex); 
 
	if (nr.nID == 0) 
		return sz; 
 
	switch (nr.nTypeRes) 
	{ 
	case TYPE_RES_ICON: 
		sz = DrawIcon(pDC, pt, nMaxHeight, nr.nID, szResource, bCalculate); 
		break; 
	case TYPE_RES_BITMAP: 
		sz = DrawBitmap(pDC, pt, nMaxHeight, nr.nID, FALSE, nr.crMask, szResource, bCalculate); 
		break; 
	case TYPE_RES_MASK_BITMAP: 
		sz = DrawBitmap(pDC, pt, nMaxHeight, nr.nID, TRUE, nr.crMask, szResource, bCalculate); 
		break; 
	} 
 
	return sz; 
} 
 
CSize CPPToolTip::DrawBitmap(CDC * pDC, CPoint pt, int nMaxHeight, UINT nID, BOOL bUseMask, COLORREF crMask, CSize szBitmap, BOOL bCalculate) 
{ 
	CSize sz(0, 0); 
	HBITMAP	hBitmap = GetBitmapFromResources(nID); 
	 
	int		nRetValue; 
	BITMAP	csBitmapSize; 
	 
	if (hBitmap == NULL) 
		return sz; 
	 
	// Get bitmap size 
	nRetValue = ::GetObject(hBitmap, sizeof(csBitmapSize), &csBitmapSize); 
	if (nRetValue == 0) 
		return sz; 
	 
	sz.cx = (DWORD)csBitmapSize.bmWidth; 
	sz.cy = (DWORD)csBitmapSize.bmHeight; 
 
	if (!szBitmap.cy) 
		szBitmap.cy = sz.cy; 
 
	if (!szBitmap.cx) 
		szBitmap.cx = sz.cx; 
 
	if (bCalculate) 
		return szBitmap; 
	 
	HDC hSrcDC = ::CreateCompatibleDC(pDC->m_hDC); 
	HDC hResDC = ::CreateCompatibleDC(pDC->m_hDC); 
	 
	HBITMAP hSrcBitmap = ::CreateCompatibleBitmap(pDC->m_hDC, szBitmap.cx, szBitmap.cy); 
	HBITMAP hOldSrcBitmap = (HBITMAP)::SelectObject(hSrcDC, hSrcBitmap); 
	HBITMAP hOldResBitmap = (HBITMAP)::SelectObject(hResDC, hBitmap); 
 
	//Scales a bitmap if need 
	if ((sz.cx != szBitmap.cx) || (sz.cy != szBitmap.cy)) 
		::StretchBlt(hSrcDC, 0, 0, szBitmap.cx, szBitmap.cy, hResDC, 0, 0, sz.cx, sz.cy, SRCCOPY); 
	else 
		::BitBlt(hSrcDC, 0, 0, szBitmap.cx, szBitmap.cy, hResDC, 0, 0, SRCCOPY); 
 
	::SelectObject(hResDC, hOldResBitmap); 
	::DeleteDC(hResDC); 
	::DeleteObject(hOldResBitmap); 
	::DeleteObject(hBitmap); 
 
	pt.y += (nMaxHeight - szBitmap.cy); 
 
	if (bUseMask) 
	{ 
		//Draws a bitmap with mask 
		::SelectObject(hSrcDC, hOldSrcBitmap); 
		CImageList img; 
		img.Create(szBitmap.cx, szBitmap.cy, ILC_COLOR32 | ILC_MASK, 1, 1); 
		img.Add(CBitmap::FromHandle(hSrcBitmap), crMask); 
		DrawIconFromImageList(pDC, pt, szBitmap, img, 0, FALSE); 
	} 
	else 
	{ 
		//Draws a bitmap without mask 
		pDC->BitBlt(pt.x, pt.y, szBitmap.cx, szBitmap.cy, CDC::FromHandle(hSrcDC), 0, 0, SRCCOPY); 
		::SelectObject(hSrcDC, hOldSrcBitmap); 
	} 
 
	::DeleteDC(hSrcDC); 
	::DeleteObject(hOldSrcBitmap); 
	::DeleteObject(hSrcBitmap); 
 
	return szBitmap; 
} 
 
CSize CPPToolTip::DrawIcon(CDC * pDC, CPoint pt, int nMaxHeight, UINT nID, CSize szIcon, BOOL bCalculate) 
{ 
	CSize sz (0, 0); 
	HICON hIcon = GetIconFromResources(nID, szIcon); 
	if (hIcon != NULL) 
	{ 
		sz = GetSizeIcon(hIcon); 
		if (!bCalculate) 
		{ 
			pt.y += (nMaxHeight - sz.cy); 
			pDC->DrawState(pt, sz, hIcon, DSS_NORMAL, (CBrush*)NULL); 
		} 
	} 
	 
	if (hIcon) 
		::DestroyIcon(hIcon); 
	 
	return sz; 
} 
 
CSize CPPToolTip::DrawIconFromImageList(CDC * pDC, CPoint pt, CSize sz, CImageList & img, int nIndex /* = 0 */, BOOL bCalculate /* = TRUE */) 
{ 
	if (img.GetSafeHandle() == NULL) 
		return CSize (0, 0); 
 
	int nCount = img.GetImageCount(); 
	if (nIndex >= nCount) 
		return CSize (0, 0); 
 
	if (bCalculate) 
		return sz; 
	 
	HICON hIcon = img.ExtractIcon(nIndex); 
	pDC->DrawState(pt, sz, hIcon, DSS_NORMAL, (CBrush*)NULL); 
 
	if (hIcon) 
		DestroyIcon(hIcon); 
 
	return sz; 
} 
 
void CPPToolTip::DrawHorzLine(CDC * pDC, int xStart, int xEnd, int y) const 
{ 
	CPen pen(PS_SOLID, 1, pDC->GetTextColor()); 
	CPen * penOld = pDC->SelectObject(&pen); 
	pDC->MoveTo(xStart, y); 
	pDC->LineTo(xEnd, y); 
	pDC->SelectObject(penOld); 
	pen.DeleteObject(); 
} 
 
void CPPToolTip::FillGradient (	CDC * pDC, CRect rect,  
								COLORREF colorStart, COLORREF colorFinish,  
								BOOL bHorz/* = TRUE*/) 
{ 
    // this will make 2^6 = 64 fountain steps 
    int nShift = 6; 
    int nSteps = 1 << nShift; 
 
    for (int i = 0; i < nSteps; i++) 
    { 
        // do a little alpha blending 
        BYTE bR = (BYTE) ((GetRValue(colorStart) * (nSteps - i) + 
                   GetRValue(colorFinish) * i) >> nShift); 
        BYTE bG = (BYTE) ((GetGValue(colorStart) * (nSteps - i) + 
                   GetGValue(colorFinish) * i) >> nShift); 
        BYTE bB = (BYTE) ((GetBValue(colorStart) * (nSteps - i) + 
                   GetBValue(colorFinish) * i) >> nShift); 
 
		CBrush br (RGB(bR, bG, bB)); 
 
        // then paint with the resulting color 
        CRect r2 = rect; 
        if (!bHorz) 
        { 
            r2.top = rect.top +  
                ((i * rect.Height()) >> nShift); 
            r2.bottom = rect.top +  
                (((i + 1) * rect.Height()) >> nShift); 
            if (r2.Height() > 0) 
                pDC->FillRect(r2, &br); 
        } 
        else 
        { 
            r2.left = rect.left +  
                ((i * rect.Width()) >> nShift); 
            r2.right = rect.left +  
                (((i + 1) * rect.Width()) >> nShift); 
            if (r2.Width() > 0) 
                pDC->FillRect(r2, &br); 
        } 
    } 
} 
 
#ifdef PPTOOLTIP_USE_SHADE 
void CPPToolTip::SetShade(CRect rect, UINT shadeID /* = 0 */, BYTE granularity /* = 8 */,  
						  BYTE coloring /* = 0 */, COLORREF color /* = 0 */) 
{ 
	long	sXSize,sYSize,bytes,j,i,k,h; 
	BYTE	*iDst ,*posDst; 
	 
	sYSize= rect.Height(); //rect.bottom-rect.top; 
	sXSize= rect.Width(); //rect.right-rect.left ; 
 
	m_dh.Create(max(1,sXSize /*-2*m_FocusRectMargin-1*/ ),1,8);	//create the horizontal focus bitmap 
	m_dv.Create(1,max(1,sYSize /*-2*m_FocusRectMargin*/),8);	//create the vertical focus bitmap 
 
	m_dNormal.Create(sXSize,sYSize,8);					//create the default bitmap 
 
	COLORREF hicr = m_pToolInfo.crBegin; //GetSysColor(COLOR_BTNHIGHLIGHT);		//get the button base colors 
	COLORREF midcr = m_pToolInfo.crMid;  //GetSysColor(COLOR_BTNFACE); 
	COLORREF locr = m_pToolInfo.crEnd;   //GetSysColor(COLOR_BTNSHADOW); 
	long r,g,b;											//build the shaded palette 
	for(i=0;i<129;i++){ 
		r=((128-i)*GetRValue(locr)+i*GetRValue(midcr))/128; 
		g=((128-i)*GetGValue(locr)+i*GetGValue(midcr))/128; 
		b=((128-i)*GetBValue(locr)+i*GetBValue(midcr))/128; 
		m_dNormal.SetPaletteIndex((BYTE)i,(BYTE)r,(BYTE)g,(BYTE)b); 
		m_dh.SetPaletteIndex((BYTE)i,(BYTE)r,(BYTE)g,(BYTE)b); 
		m_dv.SetPaletteIndex((BYTE)i,(BYTE)r,(BYTE)g,(BYTE)b); 
	} 
	for(i=1;i<129;i++){ 
		r=((128-i)*GetRValue(midcr)+i*GetRValue(hicr))/128; 
		g=((128-i)*GetGValue(midcr)+i*GetGValue(hicr))/128; 
		b=((128-i)*GetBValue(midcr)+i*GetBValue(hicr))/128; 
		m_dNormal.SetPaletteIndex((BYTE)(i+127),(BYTE)r,(BYTE)g,(BYTE)b); 
		m_dh.SetPaletteIndex((BYTE)(i+127),(BYTE)r,(BYTE)g,(BYTE)b); 
		m_dv.SetPaletteIndex((BYTE)(i+127),(BYTE)r,(BYTE)g,(BYTE)b); 
	} 
 
	m_dNormal.BlendPalette(color,coloring);	//color the palette 
 
	iDst=m_dh.GetBits();		//build the horiz. dotted focus bitmap 
	j=(long)m_dh.GetWidth(); 
	for(i=0;i0)&&((y+i)0)) 
					m_dNormal.SetPixelIndex(sXSize-x+i,y-i,(BYTE)d); 
			} 
		} 
		//blend strokes with SHS_DIAGONAL 
		posDst =iDst; 
		a=(idxmax-idxmin-k)/2; 
		for(i = 0; i < sYSize; i++) { 
			for(j = 0; j < sXSize; j++) { 
				d=posDst[j]+((a*i)/sYSize+(a*(sXSize-j))/sXSize); 
				posDst[j]=(BYTE)d; 
				posDst[j]+=rand()/grainx2; 
			} 
			posDst+=bytes; 
		} 
 
		break; 
//---------------------------------------------------- 
	case PPTOOLTIP_EFFECT_HARDBUMP:	//  
		//set horizontal bump 
		for(i = 0; i < sYSize; i++) { 
			k=(255*i/sYSize)-127; 
			k=(k*(k*k)/128)/128; 
			k=(k*(128-granularity*2))/128+128; 
			for(j = 0; j < sXSize; j++) { 
				posDst[j]=(BYTE)k; 
				posDst[j]+=rand()/grainx2-granularity; 
			} 
			posDst+=bytes; 
		} 
		//set vertical bump 
		d=min(16,sXSize/6);	//max edge=16 
		a=sYSize*sYSize/4; 
		posDst =iDst; 
		for(i = 0; i < sYSize; i++) { 
			y=i-sYSize/2; 
			for(j = 0; j < sXSize; j++) { 
				x=j-sXSize/2; 
				xs=sXSize/2-d+(y*y*d)/a; 
				if (x>xs) posDst[j]=idxmin+(BYTE)(((sXSize-j)*128)/d); 
				if ((x+xs)<0) posDst[j]=idxmax-(BYTE)((j*128)/d); 
				posDst[j]+=rand()/grainx2-granularity; 
			} 
			posDst+=bytes; 
		} 
		break; 
//---------------------------------------------------- 
	case PPTOOLTIP_EFFECT_SOFTBUMP: // 
		for(i = 0; i < sYSize; i++) { 
			h=(255*i/sYSize)-127; 
			for(j = 0; j < sXSize; j++) { 
				k=(255*(sXSize-j)/sXSize)-127; 
				k=(h*(h*h)/128)/128+(k*(k*k)/128)/128; 
				k=k*(128-granularity)/128+128; 
				if (kidxmax) k=idxmax; 
				posDst[j]=(BYTE)k; 
				posDst[j]+=rand()/grainx2-granularity; 
			} 
			posDst+=bytes; 
		} 
		break; 
//---------------------------------------------------- 
	case PPTOOLTIP_EFFECT_VBUMP: //  
		for(j = 0; j < sXSize; j++) { 
			k=(255*(sXSize-j)/sXSize)-127; 
			k=(k*(k*k)/128)/128; 
			k=(k*(128-granularity))/128+128; 
			for(i = 0; i < sYSize; i++) { 
				posDst[j+i*bytes]=(BYTE)k; 
				posDst[j+i*bytes]+=rand()/grainx2-granularity; 
			} 
		} 
		break; 
//---------------------------------------------------- 
	case PPTOOLTIP_EFFECT_HBUMP: // 
		for(i = 0; i < sYSize; i++) { 
			k=(255*i/sYSize)-127; 
			k=(k*(k*k)/128)/128; 
			k=(k*(128-granularity))/128+128; 
			for(j = 0; j < sXSize; j++) { 
				posDst[j]=(BYTE)k; 
				posDst[j]+=rand()/grainx2-granularity; 
			} 
			posDst+=bytes; 
		} 
		break; 
//---------------------------------------------------- 
	case PPTOOLTIP_EFFECT_DIAGSHADE:	// 
		a=(idxmax-idxmin)/2; 
		for(i = 0; i < sYSize; i++) { 
			for(j = 0; j < sXSize; j++) { 
				posDst[j]=(BYTE)(idxmin+a*i/sYSize+a*(sXSize-j)/sXSize); 
				posDst[j]+=rand()/grainx2-granularity; 
			} 
			posDst+=bytes; 
		} 
		break; 
//---------------------------------------------------- 
	case PPTOOLTIP_EFFECT_HSHADE:	// 
		a=idxmax-idxmin; 
		for(i = 0; i < sYSize; i++) { 
			k=a*i/sYSize+idxmin; 
			for(j = 0; j < sXSize; j++) { 
				posDst[j]=(BYTE)k; 
				posDst[j]+=rand()/grainx2-granularity; 
			} 
			posDst+=bytes; 
		} 
		break; 
//---------------------------------------------------- 
	case PPTOOLTIP_EFFECT_VSHADE:	//: 
		a=idxmax-idxmin; 
		for(j = 0; j < sXSize; j++) { 
			k=a*(sXSize-j)/sXSize+idxmin; 
			for(i = 0; i < sYSize; i++) { 
				posDst[j+i*bytes]=(BYTE)k; 
				posDst[j+i*bytes]+=rand()/grainx2-granularity; 
			} 
		} 
		break; 
//---------------------------------------------------- 
	case PPTOOLTIP_EFFECT_NOISE: 
		for(i = 0; i < sYSize; i++) { 
			for(j = 0; j < sXSize; j++) { 
				posDst[j]=128+rand()/grainx2-granularity; 
			} 
			posDst+=bytes; 
		} 
	} 
//---------------------------------------------------- 
} 
#endif 
 
HICON CPPToolTip::GetIconFromResources(UINT nID, CSize szIcon /* = CSize(0, 0) */) const 
{ 
	// Find correct resource handle 
	HINSTANCE hInstResource = AfxFindResourceHandle(MAKEINTRESOURCE(nID), RT_GROUP_ICON); 
	// Set icon when the mouse is IN the button 
	HICON hIcon = (HICON)::LoadImage(hInstResource, MAKEINTRESOURCE(nID), IMAGE_ICON, szIcon.cx, szIcon.cy, 0); 
 
	return hIcon; 
} 
 
HBITMAP CPPToolTip::GetBitmapFromResources(UINT nID) const 
{ 
	// Find correct resource handle 
	HINSTANCE hInstResource = AfxFindResourceHandle(MAKEINTRESOURCE(nID), RT_BITMAP); 
	// Load bitmap 
	HBITMAP hBitmap = (HBITMAP)::LoadImage(hInstResource, MAKEINTRESOURCE(nID), IMAGE_BITMAP, 0, 0, 0); 
 
	return hBitmap; 
} 
/////////////////////////////////////////////////////////////////////////////// 
/////////////////////////////////////////////////////////////////////////////// 
/////////////////////////////////////////////////////////////////////////////// 
 
///////////////////////////////////////////////////////////////////////////// 
//  CPPToolTip::SetStyles  (public member function) 
//    Sets the new styles of the control 
// 
//  Parameters : 
//		nStyle		[in] - new style 
// 
//  Returns : 
//		Old styles 
// 
///////////////////////////////////////////////////////////////////////////// 
void CPPToolTip::SetStyles(DWORD nStyles, int nIndexTool /* = PPTOOLTIP_TOOL_NOEXIST */) 
{ 
	TRACE(_T("CPPToolTip::SetStyles()\n")); 
 
	ModifyStyles(nStyles, -1, nIndexTool); 
}  // End of SetStyles 
 
///////////////////////////////////////////////////////////////////////////// 
//  CPPToolTip::ModifyStyles  (public member function) 
//    Modify the styles of the control 
// 
//  Parameters : 
//		nAddStyle	 [in] - The styles to add 
//		nRemoveStyle [in] - The styles to remove 
// 
//  Returns : 
//		Old styles 
// 
///////////////////////////////////////////////////////////////////////////// 
void CPPToolTip::ModifyStyles(DWORD nAddStyles, DWORD nRemoveStyles, int nIndexTool /* = PPTOOLTIP_TOOL_NOEXIST */) 
{ 
	if (!IsExistTool(nIndexTool)) 
	{ 
		m_nStyles &= ~nRemoveStyles; 
		m_nStyles |= nAddStyles; 
	} 
	else 
	{ 
		PPTOOLTIP_INFO ti; 
		GetTool(nIndexTool, ti); 
		if (!(ti.nMask & PPTOOLTIP_MASK_STYLES)) 
			ti.nStyles = m_nStyles; 
		ti.nStyles &= ~nRemoveStyles; 
		ti.nStyles |= nAddStyles; 
		ti.nMask |= PPTOOLTIP_MASK_STYLES; 
		SetAtTool(nIndexTool, ti); 
	} 
}  // End of ModifyStyles 
 
///////////////////////////////////////////////////////////////////////////// 
//  CPPToolTip::GetStyles (public member function) 
//    Gets the current styles of the control 
// 
//  Parameters : 
// 
//  Returns : 
//		Current styles 
// 
///////////////////////////////////////////////////////////////////////////// 
DWORD CPPToolTip::GetStyles(int nIndexTool /* = PPTOOLTIP_TOOL_NOEXIST */) 
{ 
	TRACE(_T("CPPToolTip::GetStyles()\n")); 
 
	if (IsExistTool(nIndexTool)) 
	{ 
		PPTOOLTIP_INFO ti; 
		GetTool(nIndexTool, ti); 
		if (ti.nMask & PPTOOLTIP_MASK_STYLES) 
			return ti.nStyles; 
	} 
	return m_nStyles; 
}  // End of GetStyles 
 
///////////////////////////////////////////////////////////////////////////// 
//  CPPToolTip::SetDefaultStyles  (public member function) 
//    Sets the new styles of the control 
// 
//  Parameters : 
// 
//  Returns : 
//		None 
// 
///////////////////////////////////////////////////////////////////////////// 
void CPPToolTip::SetDefaultStyles(int nIndexTool /* = PPTOOLTIP_TOOL_NOEXIST */) 
{ 
	TRACE(_T("CPPToolTip::SetDefaultStyles()\n")); 
 
	SetStyles(PPTOOLTIP_BALLOON | PPTOOLTIP_ICON_VCENTER_ALIGN, nIndexTool); 
}  // End of SetDefaultStyles 
 
 
///////////////////////////////////////////////////////////////////////////// 
//  CPPToolTip::SetColor (public member function) 
//    Set the color 
// 
//  Parameters : 
//		nIndex  [in] - index of the color 
//		crColor [in] - new color 
// 
//  Returns : 
//		None 
// 
///////////////////////////////////////////////////////////////////////////// 
void CPPToolTip::SetColor(int nIndex, COLORREF crColor) 
{ 
	TRACE (_T("CPPToolTip::SetColor(nIndex = %d)\n"), nIndex); 
	 
	if (nIndex >= PPTOOLTIP_MAX_COLORS) 
		return; 
 
	m_crColor [nIndex] = crColor; 
}  // End of SetColor 
 
///////////////////////////////////////////////////////////////////////////// 
//  CPPToolTip::GetColor (public member function) 
//    Set the color 
// 
//  Parameters : 
//		nIndex  [in] - index of the color 
// 
//  Returns : 
//		Current color 
// 
///////////////////////////////////////////////////////////////////////////// 
COLORREF CPPToolTip::GetColor(int nIndex) 
{ 
	TRACE (_T("CPPToolTip::GetColor(nIndex = %d)\n"), nIndex); 
 
	if (nIndex >= PPTOOLTIP_MAX_COLORS) 
		nIndex = PPTOOLTIP_COLOR_FG; 
 
	return m_crColor [nIndex]; 
}  // End of GetColor 
 
///////////////////////////////////////////////////////////////////////////// 
//  CPPToolTip::SetDefaultColors (public member function) 
//    Set the color as default 
// 
//  Parameters : 
//		None 
// 
//  Returns : 
//		None 
// 
///////////////////////////////////////////////////////////////////////////// 
void CPPToolTip::SetDefaultColors() 
{ 
	TRACE (_T("CPPToolTip::SetDefaultColors\n")); 
	 
	SetColor(PPTOOLTIP_COLOR_0, RGB (0, 0, 0)); 
	SetColor(PPTOOLTIP_COLOR_1, RGB (0, 0, 128)); 
	SetColor(PPTOOLTIP_COLOR_2, RGB (0, 128, 0)); 
	SetColor(PPTOOLTIP_COLOR_3, RGB (0, 128, 128)); 
	SetColor(PPTOOLTIP_COLOR_4, RGB (128, 0, 0)); 
	SetColor(PPTOOLTIP_COLOR_5, RGB (128, 0, 128)); 
	SetColor(PPTOOLTIP_COLOR_6, RGB (128, 128, 0)); 
	SetColor(PPTOOLTIP_COLOR_7, RGB (128, 128, 128)); 
	SetColor(PPTOOLTIP_COLOR_8, RGB (0, 0, 255)); 
	SetColor(PPTOOLTIP_COLOR_9, RGB (0, 255, 0)); 
	SetColor(PPTOOLTIP_COLOR_10, RGB (0, 255, 255)); 
	SetColor(PPTOOLTIP_COLOR_11, RGB (255, 0, 0)); 
	SetColor(PPTOOLTIP_COLOR_12, RGB (255, 0, 255)); 
	SetColor(PPTOOLTIP_COLOR_13, RGB (255, 255, 0)); 
	SetColor(PPTOOLTIP_COLOR_14, RGB (192, 192, 192)); 
	SetColor(PPTOOLTIP_COLOR_15, RGB (255, 255, 255)); 
	SetColor(PPTOOLTIP_COLOR_FG, ::GetSysColor(COLOR_INFOTEXT)); 
	SetColor(PPTOOLTIP_COLOR_BK_BEGIN, ::GetSysColor(COLOR_INFOBK)); 
	SetColor(PPTOOLTIP_COLOR_BK_MID, ::GetSysColor(COLOR_INFOBK)); 
	SetColor(PPTOOLTIP_COLOR_BK_END, ::GetSysColor(COLOR_INFOBK)); 
	SetColor(PPTOOLTIP_COLOR_LINK, RGB(0, 0, 238)); 
	SetColor(PPTOOLTIP_COLOR_VISITED, RGB(85, 26, 139)); 
	SetColor(PPTOOLTIP_COLOR_HOVER, RGB(255, 0, 0)); 
	SetColor(PPTOOLTIP_COLOR_SHADOW, ::GetSysColor(COLOR_3DSHADOW)); 
	SetColor(PPTOOLTIP_COLOR_BORDER, ::GetSysColor(COLOR_INFOTEXT)); 
}  // End of SetDefaultColors 
 
///////////////////////////////////////////////////////////////////////////// 
//  CPPToolTip::SetGradientColors (public member function) 
//    Set the gradient colors 
// 
//  Parameters : 
//		crStart [in] - start color 
//		crEnd [in] - end color 
// 
//  Returns : 
//		None 
// 
///////////////////////////////////////////////////////////////////////////// 
void CPPToolTip::SetGradientColors(COLORREF crBegin, COLORREF crMid, COLORREF crEnd, int nIndexTool /* = PPTOOLTIP_TOOL_NOEXIST */) 
{ 
	TRACE (_T("CPPToolTip::SetGradientColors\n")); 
	if (!IsExistTool(nIndexTool)) 
	{ 
		SetColor(PPTOOLTIP_COLOR_BK_BEGIN, crBegin); 
		SetColor(PPTOOLTIP_COLOR_BK_MID, crMid); 
		SetColor(PPTOOLTIP_COLOR_BK_END, crEnd); 
	} 
	else 
	{ 
		PPTOOLTIP_INFO ti; 
		GetTool(nIndexTool, ti); 
		ti.crBegin = crBegin; 
		ti.crMid = crMid; 
		ti.crEnd = crEnd; 
		ti.nMask |= PPTOOLTIP_MASK_COLORS; 
		SetAtTool(nIndexTool, ti); 
	} 
} // End of SetGradientColors 
 
///////////////////////////////////////////////////////////////////////////// 
//  CPPToolTip::GetGradientColors (public member function) 
//    Set the gradient colors 
// 
//  Parameters : 
//		None 
// 
//  Returns : 
//		crStart [out] - start color 
//		crEnd [out] - end color 
// 
///////////////////////////////////////////////////////////////////////////// 
void CPPToolTip::GetGradientColors(COLORREF & crBegin, COLORREF & crMid, COLORREF & crEnd, int nIndexTool /* = -1 */) 
{ 
	TRACE (_T("CPPToolTip::GetGradientColors\n")); 
	if (IsExistTool(nIndexTool)) 
	{ 
		PPTOOLTIP_INFO ti; 
		GetTool(nIndexTool, ti); 
		if (ti.nMask & PPTOOLTIP_MASK_COLORS) 
		{ 
			crBegin = ti.crBegin; 
			crMid = ti.crMid; 
			crEnd = ti.crEnd; 
			return; 
		} 
	} 
	crBegin = GetColor(PPTOOLTIP_COLOR_BK_BEGIN); 
	crMid = GetColor(PPTOOLTIP_COLOR_BK_MID); 
	crEnd = GetColor(PPTOOLTIP_COLOR_BK_END); 
} // End of GetGradientColors 
 
void CPPToolTip::SetMaskTool(int nIndexTool, UINT nMask /* = 0 */) 
{ 
	ModifyMaskTool(nIndexTool, nMask, -1); 
} 
 
void CPPToolTip::ModifyMaskTool(int nIndexTool, UINT nAddMask, UINT nRemoveMask) 
{ 
	if (!IsExistTool(nIndexTool)) 
		return; 
	PPTOOLTIP_INFO ti; 
	GetTool(nIndexTool, ti); 
	ti.nMask &= ~nRemoveMask; 
	ti.nMask |= nAddMask; 
	SetAtTool(nIndexTool, ti); 
} 
 
UINT CPPToolTip::GetMaskTool(int nIndexTool) 
{ 
	if (!IsExistTool(nIndexTool)) 
		return 0; 
	PPTOOLTIP_INFO ti; 
	GetTool(nIndexTool, ti); 
	return ti.nMask; 
} 
 
///////////////////////////////////////////////////////////////////////////// 
//  CPPToolTip::SetEffectBk (public member function) 
//    sets the background's effect 
// 
//  Parameters : 
//		nEffect	[in]  - the background's effect  
// 
//  Returns : 
//		None  
// 
///////////////////////////////////////////////////////////////////////////// 
void CPPToolTip::SetEffectBk(UINT nEffect, BYTE nGranularity /* = 2 */, int nIndexTool /* = PPTOOLTIP_TOOL_NOEXIST */) 
{ 
	TRACE (_T("CPPToolTip::SetEffectBk\n")); 
	 
	if (!IsExistTool(nIndexTool)) 
	{ 
		m_nEffect = nEffect; 
		m_nGranularity = nGranularity; 
	} 
	else 
	{ 
		PPTOOLTIP_INFO ti; 
		GetTool(nIndexTool, ti); 
		ti.nEffect = nEffect; 
		ti.nGranularity = nGranularity; 
		ti.nMask |= PPTOOLTIP_MASK_EFFECT; 
		SetAtTool(nIndexTool, ti); 
	} 
} // End SetEffectBk 
 
///////////////////////////////////////////////////////////////////////////// 
//  CPPToolTip::GetEffectBk (public member function) 
//    gets the background's effect 
// 
//  Parameters : 
//		None  
// 
//  Returns : 
//		the background's effect  
// 
///////////////////////////////////////////////////////////////////////////// 
UINT CPPToolTip::GetEffectBk(int nIndexTool /* = PPTOOLTIP_TOOL_NOEXIST */) 
{ 
	BYTE nGranularity = 0; 
	 
	return GetEffectBk(nGranularity, nIndexTool); 
} // End SetEffectBk 
 
///////////////////////////////////////////////////////////////////////////// 
//  CPPToolTip::GetEffectBk (public member function) 
//    gets the background's effect 
// 
//  Parameters : 
//		nGranularity	[out] - effect's granularity 
// 
//  Returns : 
//		the background's effect  
// 
///////////////////////////////////////////////////////////////////////////// 
UINT CPPToolTip::GetEffectBk(BYTE & nGranularity, int nIndexTool /* = PPTOOLTIP_TOOL_NOEXIST */) 
{ 
	TRACE (_T("CPPToolTip::GetEffectBk\n")); 
	 
	if (IsExistTool(nIndexTool)) 
	{ 
		PPTOOLTIP_INFO ti; 
		GetTool(nIndexTool, ti); 
		if (ti.nMask & PPTOOLTIP_MASK_EFFECT) 
		{ 
			nGranularity = ti.nGranularity; 
			return ti.nEffect; 
		} 
	} 
	nGranularity = m_nGranularity; 
	return m_nEffect; 
} // End SetEffectBk 
 
///////////////////////////////////////////////////////////////////// 
// CPPToolTip::SetNotify 
// This function sets or removes the notification messages from the control before display. 
// 
// Parameters: 
//	bParentNotify [in] - If TRUE the control will be send the notification  
//				   to parent window 
//				   Else the notification will not send 
/////////////////////////////////////////////////////////////////////// 
void CPPToolTip::SetNotify(BOOL bParentNotify /* = TRUE */) 
{ 
	HWND hWnd = NULL; 
 
	if (bParentNotify) 
		hWnd = m_pParentWnd->GetSafeHwnd(); 
 
	SetNotify(hWnd); 
} //End SetNotify 
 
///////////////////////////////////////////////////////////////////// 
// CPPToolTip::SetNotify 
// This function sets or removes the notification messages from the control before display. 
// 
// Parameters: 
//	hWnd [in] -    If non-NULL the control will be send the notification  
//				   to specified window 
//				   Else the notification will not send 
/////////////////////////////////////////////////////////////////////// 
void CPPToolTip::SetNotify(HWND hWnd) 
{ 
	TRACE(_T("CPPToolTip::SetNotify\n")); 
 
	m_hNotifyWnd = hWnd; 
} //End SetNotify 
 
///////////////////////////////////////////////////////////////////// 
// CPPToolTip::GetNotify 
// This function determines will be send the notification messages from  
// the control or not before display. 
// 
// Return value: 
//	TRUE if the control will be notified the specified window 
/////////////////////////////////////////////////////////////////////// 
BOOL CPPToolTip::GetNotify() 
{ 
	TRACE(_T("CPPToolTip::GetNotify\n")); 
 
	return (m_hNotifyWnd != NULL); 
}  //End GetNotify 
 
///////////////////////////////////////////////////////////////////// 
// CPPToolTip::SetDelayTime 
// Call this function to set the delay time for a tool tip control.  
// The delay time is the length of time the cursor must remain on a tool  
// before the tool tip window appears. The default delay time is 500 milliseconds. 
// 
// Parameters: 
//   dwDuration	[in]  - Flag that specifies which duration value will be retrieved.  
//						This parameter can be one of the following values: 
//			 
//			TTDT_AUTOPOP  - Retrieve the length of time the tool tip  
//							window remains visible if the pointer is  
//							stationary within a tool's bounding rectangle.  
//			TTDT_INITIAL  - Retrieve the length of time the pointer  
//							must remain stationary within a tool's bounding  
//							rectangle before the tool tip window appears.  
//			TTDT_RESHOW   - Retrieve the length of time it takes for  
//							subsequent tool tip windows to appear as the  
//							pointer moves from one tool to another. 
//	 nTime [in] - The specified delay time, in milliseconds. 
// 
///////////////////////////////////////////////////////////////////// 
void CPPToolTip::SetDelayTime(DWORD dwDuration, UINT nTime) 
{ 
	switch (dwDuration) 
	{ 
	case TTDT_AUTOPOP: 
		m_nTimeAutoPop = nTime; 
		break; 
	case TTDT_INITIAL : 
		m_nTimeInitial = nTime; 
		break; 
//	case TTDT_RESHOW: 
//		m_nTimeReShow = nTime; 
//		break; 
	} 
} // End SetDelayTime 
 
///////////////////////////////////////////////////////////////////// 
// CPPToolTip::GetDelayTime 
// Retrieves the initial, pop-up, and reshow durations currently set  
// for a CPPToolTip control 
// 
// Parameters: 
//   dwDuration	[in] - Flag that specifies which duration value will  
//					   be retrieved. This parameter can be one of the  
//					   following values: 
//			 
//			TTDT_AUTOPOP  - Retrieve the length of time the tool tip  
//							window remains visible if the pointer is  
//							stationary within a tool's bounding rectangle.  
//			TTDT_INITIAL  - Retrieve the length of time the pointer  
//							must remain stationary within a tool's bounding  
//							rectangle before the tool tip window appears.  
//			TTDT_RESHOW   - Retrieve the length of time it takes for  
//							subsequent tool tip windows to appear as the  
//							pointer moves from one tool to another.  
// 
// Return value: 
//	The specified delay time, in milliseconds 
/////////////////////////////////////////////////////////////////////// 
UINT CPPToolTip::GetDelayTime(DWORD dwDuration) const 
{ 
	UINT nTime = 0; 
	switch (dwDuration) 
	{ 
	case TTDT_AUTOPOP: 
		nTime = m_nTimeAutoPop; 
		break; 
	case TTDT_INITIAL: 
		nTime = m_nTimeInitial; 
		break; 
//	case TTDT_RESHOW: 
//		nTime = m_nTimeReShow; 
//		break; 
	} 
 
	return nTime; 
} // End GetDelayTime 
 
///////////////////////////////////////////////////////////////////////////// 
//  CPPToolTip::SetSize (public member function) 
//    Sets the specified size 
// 
//  Parameters : 
//		nSizeIndex  [in] - index of the size 
//		nValue [in] - size's value 
// 
//  Returns : 
//		None 
// 
///////////////////////////////////////////////////////////////////////////// 
void CPPToolTip::SetSize(int nSizeIndex, UINT nValue) 
{ 
	TRACE(_T("CPPToolTip::SetSize(nSizeIndex = %d, nValue = %d)\n"), nSizeIndex, nValue); 
	if (nSizeIndex >= PPTTSZ_MAX_SIZES) 
		return; 
 
	m_nSizes [nSizeIndex] = nValue; 
} 
 
///////////////////////////////////////////////////////////////////////////// 
//  CPPToolTip::GetSize (public member function) 
//    Gets the specified size 
// 
//  Parameters : 
//		nSizeIndex  [in] - index of the size 
// 
//  Returns : 
//		size's value 
// 
///////////////////////////////////////////////////////////////////////////// 
UINT CPPToolTip::GetSize(int nSizeIndex) 
{ 
	TRACE(_T("CPPToolTip::GetSize(nSizeIndex = %d)\n"), nSizeIndex); 
	if (nSizeIndex >= PPTTSZ_MAX_SIZES) 
		return 0; 
 
	return m_nSizes [nSizeIndex]; 
} 
 
///////////////////////////////////////////////////////////////////////////// 
//  CPPToolTip::SetDefaultSizes (public member function) 
//    Sets all sizes to default values 
// 
//  Returns : 
//		None 
// 
///////////////////////////////////////////////////////////////////////////// 
void CPPToolTip::SetDefaultSizes(BOOL bBalloonSize /* = TRUE */) 
{ 
	TRACE(_T("CPPToolTip::SetDefaultSizes()\n")); 
 
	if (bBalloonSize) 
	{ 
		SetSize(PPTTSZ_ROUNDED_CX, 16); 
		SetSize(PPTTSZ_ROUNDED_CY, 16); 
		SetSize(PPTTSZ_MARGIN_CX, 12); 
		SetSize(PPTTSZ_MARGIN_CY, 12); 
		SetSize(PPTTSZ_SHADOW_CX, 4); 
		SetSize(PPTTSZ_SHADOW_CY, 4); 
		SetSize(PPTTSZ_WIDTH_ANCHOR, 12); 
		SetSize(PPTTSZ_HEIGHT_ANCHOR, 16); 
		SetSize(PPTTSZ_MARGIN_ANCHOR, 16); 
		SetSize(PPTTSZ_BORDER_CX, 1); 
		SetSize(PPTTSZ_BORDER_CY, 1); 
	} 
	else 
	{ 
		SetSize(PPTTSZ_ROUNDED_CX, 0); 
		SetSize(PPTTSZ_ROUNDED_CY, 0); 
		SetSize(PPTTSZ_MARGIN_CX, 3); 
		SetSize(PPTTSZ_MARGIN_CY, 1); 
		SetSize(PPTTSZ_SHADOW_CX, 0); 
		SetSize(PPTTSZ_SHADOW_CY, 0); 
		SetSize(PPTTSZ_WIDTH_ANCHOR, 0); 
		SetSize(PPTTSZ_HEIGHT_ANCHOR, 0); 
		SetSize(PPTTSZ_MARGIN_ANCHOR, 0); 
		SetSize(PPTTSZ_BORDER_CX, 1); 
		SetSize(PPTTSZ_BORDER_CY, 1); 
	} 
} 
 
///////////////////////////////////////////////////////////////////////////// 
//  CPPToolTip::SetDirection (public member function) 
//    Sets the tooltip's direction 
// 
//  Parameters : 
//		nDirection  [in] - direction of the tooltip 
// 
//  Returns : 
//		None 
// 
///////////////////////////////////////////////////////////////////////////// 
void CPPToolTip::SetDirection(UINT nDirection /* = PPTOOLTIP_RIGHT_BOTTOM */, int nIndexTool /* = PPTOOLTIP_TOOL_NOEXIST */) 
{ 
	TRACE(_T("CPPToolTip::SetDirection(nDirection = %d)\n"), nDirection); 
 
	if (nDirection >= PPTOOLTIP_MAX_DIRECTIONS) 
		return; 
 
	if (!IsExistTool(nIndexTool)) 
	{ 
		m_nDirection = nDirection; 
	} 
	else 
	{ 
		PPTOOLTIP_INFO ti; 
		GetTool(nIndexTool, ti); 
		ti.nDirection = nDirection; 
		ti.nMask |= PPTOOLTIP_MASK_DIRECTION; 
		SetAtTool(nIndexTool, ti); 
	} 
} 
 
///////////////////////////////////////////////////////////////////////////// 
//  CPPToolTip::GetDirection (public member function) 
//    Gets the tooltip's direction 
// 
//  Returns : 
//		tooltip's direction 
// 
///////////////////////////////////////////////////////////////////////////// 
UINT CPPToolTip::GetDirection(int nIndexTool /* = PPTOOLTIP_TOOL_NOEXIST */) 
{ 
	TRACE(_T("CPPToolTip::GetDirection()\n")); 
 
	if (IsExistTool(nIndexTool)) 
	{ 
		PPTOOLTIP_INFO ti; 
		GetTool(nIndexTool, ti); 
		if (ti.nMask & PPTOOLTIP_MASK_DIRECTION) 
			return ti.nDirection; 
	} 
	return m_nDirection; 
} 
 
///////////////////////////////////////////////////////////////////////////// 
//  CPPToolTip::SetBehaviour (public member function) 
//    Sets the tooltip's direction 
// 
//  Parameters : 
//		nBehaviour  [in] - direction of the tooltip 
// 
//  Returns : 
//		None 
// 
///////////////////////////////////////////////////////////////////////////// 
 
void CPPToolTip::SetBehaviour(UINT nBehaviour /* = 0 */, int nIndexTool /* = PPTOOLTIP_TOOL_NOEXIST */) 
{ 
	TRACE(_T("CPPToolTip::SetBehaviour(nBehaviour = 0x%X)\n"), nBehaviour); 
 
	if (IsExistTool(nIndexTool)) 
	{ 
		PPTOOLTIP_INFO ti; 
		GetTool(nIndexTool, ti); 
		ti.nBehaviour = nBehaviour; 
		ti.nMask |= PPTOOLTIP_MASK_BEHAVIOUR; 
		SetAtTool(nIndexTool, ti); 
	} 
	else m_nBehaviour = nBehaviour; 
} 
 
///////////////////////////////////////////////////////////////////////////// 
//  CPPToolTip::GetBehaviour (public member function) 
//    Gets the tooltip's direction 
// 
//  Returns : 
//		tooltip's direction 
// 
///////////////////////////////////////////////////////////////////////////// 
UINT CPPToolTip::GetBehaviour(int nIndexTool /* = PPTOOLTIP_TOOL_NOEXIST */) 
{ 
	TRACE(_T("CPPToolTip::GetBehaviour()\n")); 
 
	if (IsExistTool(nIndexTool)) 
	{ 
		PPTOOLTIP_INFO ti; 
		GetTool(nIndexTool, ti); 
		if (ti.nMask & PPTOOLTIP_MASK_BEHAVIOUR) 
			return ti.nBehaviour; 
	} 
	return m_nBehaviour; 
} 
 
/* 
///////////////////////////////////////////////////////////////////////////// 
//  CPPToolTip::SetMultipleShow (public member function) 
//    Sets the multiple show for the tooltip 
// 
//  Parameters : 
//		bMultiple	[in] -  
//		pWnd		[in] - the pointer to the window 
// 
//  Returns : 
//		None 
// 
///////////////////////////////////////////////////////////////////////////// 
void CPPToolTip::SetMultipleShow(BOOL bMultiple  = TRUE , CWnd * pWnd  = NULL ) 
{ 
	if (bMultiple) 
		ModifyStyles(PPTOOLTIP_MULTIPLE_SHOW, 0, pWnd); 
	else 
		ModifyStyles(0, PPTOOLTIP_MULTIPLE_SHOW, pWnd); 
} // End of SetMultipleShow 
 
///////////////////////////////////////////////////////////////////////////// 
//  CPPToolTip::IsMultipleShow (public member function) 
//     
// 
//  Parameters : 
//		pWnd		[in] - the pointer to the window 
// 
//  Returns : 
//		TRUE if for window sets the multiple show 
// 
///////////////////////////////////////////////////////////////////////////// 
BOOL CPPToolTip::IsMultipleShow(CWnd * pWnd  = NULL ) 
{ 
	return (BOOL)(PPTOOLTIP_MULTIPLE_SHOW & GetStyles(pWnd)); 
} // End of IsMultipleShow 
*/ 
 
///////////////////////////////////////////////////////////////////////////// 
//  CPPToolTip::SetFont  (public member function) 
//    Sets the new font to the control 
// 
//  Parameters : 
//		font		[in] - new font 
// 
//  Returns : 
//		Nonzero if successful; otherwise 0. 
// 
///////////////////////////////////////////////////////////////////////////// 
BOOL CPPToolTip::SetFont(CFont & font) 
{ 
	TRACE(_T("CPPToolTip::SetFont()\n")); 
 
	LOGFONT lf; 
	font.GetLogFont (&lf); 
 
	return SetFont(&lf); 
}  // End of SetFont 
 
///////////////////////////////////////////////////////////////////////////// 
//  CPPToolTip::SetFont  (public member function) 
//    Sets the new font to the control 
// 
//  Parameters : 
//		lf			[in] - structure LOGFONT for the new font 
// 
//  Returns : 
//		Nonzero if successful; otherwise 0. 
// 
///////////////////////////////////////////////////////////////////////////// 
BOOL CPPToolTip::SetFont(LPLOGFONT lf) 
{ 
	TRACE(_T("CPPToolTip::SetFont()\n")); 
 
//	m_font.DeleteObject(); 
 
	// Store font as the global default 
    memcpy(&m_LogFont, lf, sizeof(LOGFONT)); 
 
	return TRUE; //m_font.CreateFontIndirect(lf); 
}  // End of SetFont 
 
///////////////////////////////////////////////////////////////////////////// 
//  CPPToolTip::SetFont  (public member function) 
//    Sets the new font to the control 
// 
//  Parameters : 
//		font		[in] - new font 
// 
//  Returns : 
//		Nonzero if successful; otherwise 0. 
// 
///////////////////////////////////////////////////////////////////////////// 
BOOL CPPToolTip::SetFont(LPCTSTR lpszFaceName, int nSizePoints /* = 8 */, 
									BOOL bUnderline /* = FALSE */, BOOL bBold /* = FALSE */, 
									BOOL bStrikeOut /* = FALSE */, BOOL bItalic /* = FALSE */) 
{ 
	TRACE(_T("CPPToolTip::SetFont()\n")); 
 
	CDC* pDC = GetDC(); 
	LOGFONT lf; 
	memset (&lf, 0, sizeof(LOGFONT)); 
 
	_tcscpy (lf.lfFaceName, lpszFaceName); 
	lf.lfHeight = -MulDiv (nSizePoints, GetDeviceCaps (pDC->m_hDC, LOGPIXELSY), 72); 
	lf.lfUnderline = bUnderline; 
	lf.lfWeight = bBold ? FW_BOLD : FW_NORMAL; 
	lf.lfStrikeOut = bStrikeOut; 
	lf.lfItalic = bItalic; 
 
	if (pDC) 
		ReleaseDC(pDC); 
 
	return SetFont(&lf); 
}  // End of SetFont 
 
///////////////////////////////////////////////////////////////////////////// 
//  CPPToolTip::SetDefaultFonts  (public member function) 
//    Sets default fonts of the control 
// 
//  Returns : 
//		None 
// 
///////////////////////////////////////////////////////////////////////////// 
void CPPToolTip::SetDefaultFont() 
{ 
	TRACE(_T("CPPToolTip::SetDefaultFont()\n")); 
 
	LPLOGFONT lpSysFont = GetSystemToolTipFont(); 
 
	SetFont(lpSysFont); 
} // End of SetDefaultFonts 
 
///////////////////////////////////////////////////////////////////////////// 
//  CPPToolTip::GetFont  (public member function) 
//    Sets the new font to the control 
// 
//  Parameters : 
//		font		[out] - the current font 
// 
///////////////////////////////////////////////////////////////////////////// 
void CPPToolTip::GetFont(CFont & font) 
{ 
	font.CreateFontIndirect(&m_LogFont); 
} 
 
///////////////////////////////////////////////////////////////////////////// 
//  CPPToolTip::GetFont  (public member function) 
//    Sets the new font to the control 
// 
//  Parameters : 
//		lf		[out] - the current font's structure 
// 
///////////////////////////////////////////////////////////////////////////// 
void CPPToolTip::GetFont(LPLOGFONT lf) 
{ 
	memcpy(lf, &m_LogFont, sizeof(LOGFONT)); 
} 
 
/////////////////////////////////////////////////////////////////// 
// 
// 
// Parameters: 
//		pt		[in] - the mouse's coordinates in client coordinates 
// 
// Return values: 
//      CWnd*	[out] - the pointer to the window under the mouse. Returns 
//                      NULL if under the mouse no control. 
/////////////////////////////////////////////////////////////////// 
HWND CPPToolTip::GetWndFromPoint(CPoint & pt, BOOL bGetDisabled /* = TRUE */) const 
{ 
	ASSERT(m_pParentWnd); 
	 
    CPoint point = pt; 
	// Find the window under the cursor 
    m_pParentWnd->ClientToScreen(&point); 
    HWND hWnd = ::WindowFromPoint(point); 
	 
	// WindowFromPoint misses disabled windows and such - go for a more 
    // comprehensive search in this case. 
	UINT nFlags = CWP_ALL; 
	if (!bGetDisabled) 
		nFlags |= CWP_SKIPDISABLED; 
    if (hWnd == m_pParentWnd->GetSafeHwnd()) 
        hWnd = m_pParentWnd->ChildWindowFromPoint(pt, nFlags)->GetSafeHwnd(); 
 
    return hWnd; 
} 
 
///////////////////////////////////////////////////////////////////////////// 
//  CPPToolTip::AddTool (public member function) 
//    adds or updates the tool 
// 
//  Parameters : 
//		pWnd	[in] - the pointer to the window 
//		nIdText  [in] - the tooltip's text id  
//		nIdIcon  [in] - the icon's identificator  
// 
//  Returns : 
//		None 
// 
///////////////////////////////////////////////////////////////////////////// 
void CPPToolTip::AddTool(CWnd * pWnd, UINT nIdText, HICON hIcon /* = NULL */, 
						 LPCRECT lpRectTool /* = NULL */, UINT nIDTool /* = 0 */) 
{ 
	CString str; 
    str.LoadString(nIdText); 
	AddTool(pWnd, str, hIcon, lpRectTool, nIDTool); 
} // End AddTool 
 
///////////////////////////////////////////////////////////////////////////// 
//  CPPToolTip::AddTool (public member function) 
//    adds or updates the tool 
// 
//  Parameters : 
//		pWnd	[in] - the pointer to the window 
//		nIdText  [in] - the tooltip's text id  
//		nIdIcon  [in] - the icon's identificator  
// 
//  Returns : 
//		None 
// 
///////////////////////////////////////////////////////////////////////////// 
void CPPToolTip::AddTool(CWnd * pWnd, UINT nIdText, UINT nIdIcon, CSize szIcon /* = CSize(0, 0) */, 
						 LPCRECT lpRectTool /* = NULL */, UINT nIDTool /* = 0 */) 
{ 
	CString str; 
    str.LoadString(nIdText); 
	AddTool(pWnd, str, nIdIcon, szIcon, lpRectTool, nIDTool); 
} // End AddTool 
 
///////////////////////////////////////////////////////////////////////////// 
//  CPPToolTip::AddTool (public member function) 
//    adds or updates the tool 
// 
//  Parameters : 
//		pWnd	[in] - the pointer to the window 
//		sTooltipText [in] - the tooltip's text  
//		nIdIcon  [in] - the icon's identificator  
// 
//  Returns : 
//		None 
// 
///////////////////////////////////////////////////////////////////////////// 
void CPPToolTip::AddTool(CWnd * pWnd, CString sTooltipText, UINT nIdIcon, CSize szIcon /* = CSize(0, 0) */, 
						 LPCRECT lpRectTool /* = NULL */, UINT nIDTool /* = 0 */) 
{ 
	HICON hIcon	= GetIconFromResources (nIdIcon, szIcon); 
 
	AddTool(pWnd, sTooltipText, hIcon, lpRectTool, nIDTool); 
} // End AddTool 
 
///////////////////////////////////////////////////////////////////////////// 
//  CPPToolTip::AddTool (public member function) 
//    adds or updates the tool 
// 
//  Parameters : 
//		pWnd	[in] - the pointer to the window 
//		sTooltipText [in] - the tooltip's text  
//		hIcon   [in] - the icon's handle  
// 
//  Returns : 
//		None 
// 
///////////////////////////////////////////////////////////////////////////// 
void CPPToolTip::AddTool(CWnd * pWnd, CString sTooltipText, HICON hIcon /* = NULL */, 
						 LPCRECT lpRectTool /* = NULL */, UINT nIDTool /* = 0 */) 
{ 
	// Store the tool information 
	PPTOOLTIP_INFO ti; 
	ti.hWnd = pWnd->GetSafeHwnd(); 
	ti.nIDTool = nIDTool; 
	ti.hIcon = hIcon; 
	ti.sTooltip = sTooltipText; 
	ti.nMask = 0; //All values as default 
	 
    if (lpRectTool) 
		ti.rectBounds = lpRectTool; 
	else 
		ti.rectBounds.SetRectEmpty(); 
 
	AddTool(ti); 
} // End AddTool 
 
///////////////////////////////////////////////////////////////////////////// 
//  CPPToolTip::AddTool (public member function) 
//    adds or updates the tool 
// 
//  Parameters : 
//		ti		[in] - the tooltip's structure  
// 
//  Returns : 
//		None 
// 
///////////////////////////////////////////////////////////////////////////// 
void CPPToolTip::AddTool(PPTOOLTIP_INFO ti)  
{  
	ASSERT (ti.hWnd);   
	TRACE (_T("CPPToolTip::AddTool = 0x%X\n"), ti.hWnd);  
	// Get bounding region for tooltip info  
/* 
    if (ti.rectBounds.IsRectEmpty())  
    {   
		CRect rect;  
		CWnd::FromHandle(ti.hWnd)->GetClientRect(&rect);  
		//m_pParentWnd->ScreenToClient(rect);  
		ti.rectBounds = rect;  
    }  
*/ 
	int nIndexTool = FindTool(CWnd::FromHandle(ti.hWnd), ti.rectBounds);  
	if (!IsExistTool(nIndexTool))  
		m_arrTools.Add(ti);  
	else  
		m_arrTools.SetAt(nIndexTool, ti);  
} // End AddTool 
 
///////////////////////////////////////////////////////////////////////////// 
//  CPPToolTip::FindTool (public member function) 
//    searches the tool under cursor point 
// 
//  Parameters : 
//		pt	[in] - cursor point in client coordinates 
// 
//  Returns : 
//		< 0  = Not available tool 
//      >= 0 = Index of the found tool 
// 
///////////////////////////////////////////////////////////////////////////// 
int CPPToolTip::FindTool(CPoint & pt)  
{  
	HWND hWnd = GetWndFromPoint(pt, m_nStyles & PPTOOLTIP_SHOW_DISABLED);  
	 
	PPTOOLTIP_INFO pToolInfo;   
	int nSize = m_arrTools.GetSize();  
	CPoint ptClient;   
	// Find the window under the cursor  
    m_pParentWnd->ClientToScreen(&pt);  
    for (int i = 0; i < nSize; i++)  
    {  
        pToolInfo = m_arrTools.GetAt(i);  
        if (hWnd == pToolInfo.hWnd)   
		{  
			ptClient = pt;  
			::ScreenToClient(hWnd, &ptClient);  
  			if (pToolInfo.rectBounds.PtInRect(ptClient) || pToolInfo.rectBounds.IsRectEmpty())  
			{ 
				return i;   
			} 
		} 
	}   
	return PPTOOLTIP_TOOL_NOEXIST; 
} 
 
///////////////////////////////////////////////////////////////////////////// 
//  CPPToolTip::FindTool (public member function) 
//    searches the tool with window's pointer and rectangle 
// 
//  Parameters : 
//		pWnd	[in] - the pointer to the window 
//		lpRect	[in] - rectangle of the hot area. Or NULL for any rectangle 
// 
//  Returns : 
//		< 0  = Not available tool 
//      >= 0 = Index of the found tool 
// 
///////////////////////////////////////////////////////////////////////////// 
int CPPToolTip::FindTool(CWnd * pWnd, LPCRECT lpRect /* = NULL */) 
{ 
	HWND hWnd = pWnd->GetSafeHwnd(); 
	PPTOOLTIP_INFO pToolInfo; 
	int nSize = m_arrTools.GetSize(); 
    for (int i = 0; i < nSize; i++) 
    { 
        pToolInfo = m_arrTools.GetAt(i); 
		 
        if (hWnd == pToolInfo.hWnd)  
			if ((NULL == lpRect) || (lpRect == pToolInfo.rectBounds)) 
			return i; 
    } 
	return PPTOOLTIP_TOOL_NOEXIST; 
} 
 
///////////////////////////////////////////////////////////////////////////// 
//  CPPToolTip::FindTool (public member function) 
//    searches the tool with id 
// 
//  Parameters : 
//		nIDTool	[in] - id of the window 
// 
//  Returns : 
//		< 0  = Not available tool 
//      >= 0 = Index of the found tool 
// 
///////////////////////////////////////////////////////////////////////////// 
int CPPToolTip::FindTool(UINT nIDTool) 
{ 
	PPTOOLTIP_INFO pToolInfo; 
	int nSize = m_arrTools.GetSize(); 
    for (int i = 0; i < nSize; i++) 
    { 
        pToolInfo = m_arrTools.GetAt(i); 
		 
        if (nIDTool == pToolInfo.nIDTool) 
			return i; 
    } 
	return PPTOOLTIP_TOOL_NOEXIST; 
} 
 
///////////////////////////////////////////////////////////////////////////// 
//  CPPToolTip::GetTool (public member function) 
//    gets the tooltip's info 
// 
//  Parameters : 
//		nIndexTool	[in]  - the index of the tool 
//		ti		[out] - the tooltip's structure  
// 
//  Returns : 
//		FALSE - tool not found 
// 
///////////////////////////////////////////////////////////////////////////// 
BOOL CPPToolTip::GetTool(int nIndexTool, PPTOOLTIP_INFO & ti) 
{ 
	if (!IsExistTool(nIndexTool)) 
		return FALSE; 
	ti = m_arrTools.GetAt(nIndexTool); 
	return TRUE; 
} // End GetTool 
 
///////////////////////////////////////////////////////////////////////////// 
//  CPPToolTip::RemoveTool (public member function) 
//    removes the tool 
// 
//  Parameters : 
//		pWnd	[in]  - the pointer to the window 
// 
//  Returns : 
//		None  
// 
///////////////////////////////////////////////////////////////////////////// 
BOOL CPPToolTip::RemoveTool(int nIndexTool) 
{ 
	TRACE (_T("CPPToolTip::RemoveTool\n")); 
 
	if (!IsExistTool(nIndexTool)) 
		return FALSE; 
	 
	m_arrTools.RemoveAt(nIndexTool); 
 
	return TRUE; 
} // End RemoveTool 
 
///////////////////////////////////////////////////////////////////////////// 
//  CPPToolTip::RemoveAllTools (public member function) 
//    removes the tool 
// 
//  Parameters : 
//		None 
// 
//  Returns : 
//		None  
// 
///////////////////////////////////////////////////////////////////////////// 
void CPPToolTip::RemoveAllTools() 
{ 
	TRACE (_T("CPPToolTip::RemoveAllTools\n")); 
	 
	m_arrTools.RemoveAll(); 
} // End RemoveAllTools 
 
///////////////////////////////////////////////////////////////////////////// 
//  CPPToolTip::IsExistTool (public member function) 
//    removes the tool 
// 
//  Parameters : 
//		nIndexTool	[in]  - the index of the tool 
// 
//  Returns : 
//		TRUE - the tool is exist 
// 
///////////////////////////////////////////////////////////////////////////// 
BOOL CPPToolTip::IsExistTool(int nIndexTool) 
{ 
	return (BOOL)((nIndexTool < m_arrTools.GetSize()) && (nIndexTool >= 0)); 
} 
 
///////////////////////////////////////////////////////////////////////////// 
//  CPPToolTip::SetAtTool (public member function) 
//    adds or updates the tool 
// 
//  Parameters : 
//		nIndexTool	[in] - the index of the tool 
//		ti		[in] - the tooltip's structure  
// 
//  Returns : 
//		None 
// 
///////////////////////////////////////////////////////////////////////////// 
void CPPToolTip::SetAtTool(int nIndexTool, PPTOOLTIP_INFO & ti) 
{ 
	if (!IsExistTool(nIndexTool)) 
		return; 
	m_arrTools.SetAt(nIndexTool, ti); 
} 
 
///////////////////////////////////////////////////////////////////////////// 
//  CPPToolTip::ShowHelpTooltip (public member function) 
//    shows the tooltip as help window 
// 
//  Parameters : 
//		pt	[in] - the point of the tooltip's anchor in client coordinates 
//		nIdText  [in] - the tooltip's text id  
//		nIdIcon  [in] - the icon's identificator  
// 
//  Returns : 
//		None 
// 
///////////////////////////////////////////////////////////////////////////// 
void CPPToolTip::ShowHelpTooltip(CPoint & pt, UINT nIdText, HICON hIcon /* = NULL */) 
{ 
	CString str; 
    str.LoadString(nIdText); 
	ShowHelpTooltip(pt, str, hIcon); 
} 
 
///////////////////////////////////////////////////////////////////////////// 
//  CPPToolTip::ShowHelpTooltip (public member function) 
//    shows the tooltip as help window 
// 
//  Parameters : 
//		pt	[in] - the point of the tooltip's anchor in client coordinates 
//		nIdText  [in] - the tooltip's text id  
//		nIdIcon  [in] - the icon's identificator  
// 
//  Returns : 
//		None 
// 
///////////////////////////////////////////////////////////////////////////// 
void CPPToolTip::ShowHelpTooltip(CPoint & pt, UINT nIdText, UINT nIdIcon) 
{ 
	CString str; 
    str.LoadString(nIdText); 
	ShowHelpTooltip(pt, str, nIdIcon); 
} 
 
///////////////////////////////////////////////////////////////////////////// 
//  CPPToolTip::ShowHelpTooltip (public member function) 
//    shows the tooltip as help window 
// 
//  Parameters : 
//		pt	[in] - the point of the tooltip's anchor in client coordinates 
//		sTooltipText [in] - the tooltip's text  
//		nIdIcon  [in] - the icon's identificator  
// 
//  Returns : 
//		None 
// 
///////////////////////////////////////////////////////////////////////////// 
void CPPToolTip::ShowHelpTooltip(CPoint & pt, CString sTooltipText, UINT nIdIcon) 
{ 
	HICON hIcon	= GetIconFromResources(nIdIcon); 
	ShowHelpTooltip(pt, sTooltipText, hIcon); 
} 
 
///////////////////////////////////////////////////////////////////////////// 
//  CPPToolTip::ShowHelpTooltip (public member function) 
//    shows the tooltip as help window 
// 
//  Parameters : 
//		pt	[in] - the point of the tooltip's anchor in client coordinates 
//		sTooltipText [in] - the tooltip's text  
//		hIcon   [in] - the icon's handle  
// 
//  Returns : 
//		None 
// 
///////////////////////////////////////////////////////////////////////////// 
void CPPToolTip::ShowHelpTooltip(CPoint & pt, CString sTooltipText, HICON hIcon /* = NULL */) 
{ 
	PPTOOLTIP_INFO ti; 
	ti.hWnd = m_pParentWnd->GetSafeHwnd(); 
	ti.hIcon = hIcon; 
	ti.sTooltip = sTooltipText; 
	ti.nMask = 0; //All values as default 
	ShowHelpTooltip(pt, ti); 
} 
 
///////////////////////////////////////////////////////////////////////////// 
//  CPPToolTip::ShowHelpTooltip (public member function) 
//    shows the tooltip as help window 
// 
//  Parameters : 
//		pt		[in] - the point of the tooltip's anchor in client coordinates 
//		ti		[in] - the tooltip's structure  
// 
//  Returns : 
//		None 
// 
///////////////////////////////////////////////////////////////////////////// 
void CPPToolTip::ShowHelpTooltip(CPoint & pt, PPTOOLTIP_INFO & ti) 
{ 
	TRACE(_T("ShowHelpTooltip()\n")); 
	m_nIndexDisplayWnd = PPTOOLTIP_TOOL_NOEXIST; 
	m_nIndexCurrentWnd = PPTOOLTIP_TOOL_HELPER; 
	m_pToolInfo = ti; 
 
	m_ptOriginal = pt; 
	m_pParentWnd->ClientToScreen(&m_ptOriginal); 
	 
	//Start the show timer 
	OnTimer(PPTOOLTIP_SHOW); 
} 
 
///////////////////////////////////////////////////////////////////////////// 
//  CPPToolTip::SetImageList (public member function) 
//    sets the image list to tooltip 
// 
//  Parameters : 
//		nIdBitmap	[in] - Resource IDs of the bitmap to be associated with the image list 
//		cx			[in] - Dimensions of each image, in pixels. 
//		cy			[in] - Dimensions of each image, in pixels. 
//		nCount		[in] - Number of images that the image list initially contains. 
//		crMask		[in] - Color used to generate a mask. Each pixel of this color in the  
//						   specified bitmap is changed to black, and the corresponding  
//						   bit in the mask is set to one. 
//  Returns : 
//		None 
// 
///////////////////////////////////////////////////////////////////////////// 
void CPPToolTip::SetImageList(UINT nIdBitmap, int cx, int cy, int nCount, COLORREF crMask /* = RGB(255, 0, 255) */) 
{ 
	// Load bitmap 
	HBITMAP hBitmap = GetBitmapFromResources(nIdBitmap); 
	SetImageList(hBitmap, cx, cy, nCount, crMask); 
} 
 
///////////////////////////////////////////////////////////////////////////// 
//  CPPToolTip::SetImageList (public member function) 
//    sets the image list to tooltip 
// 
//  Parameters : 
//		hBitmap		[in] - Handle of the bitmap to be associated with the image list 
//		cx			[in] - Dimensions of each image, in pixels. 
//		cy			[in] - Dimensions of each image, in pixels. 
//		nCount		[in] - Number of images that the image list initially contains. 
//		crMask		[in] - Color used to generate a mask. Each pixel of this color in the  
//						   specified bitmap is changed to black, and the corresponding  
//						   bit in the mask is set to one. 
//  Returns : 
//		None 
// 
///////////////////////////////////////////////////////////////////////////// 
void CPPToolTip::SetImageList(HBITMAP hBitmap, int cx, int cy, int nCount, COLORREF crMask /* = RGB(255, 0, 255) */) 
{ 
	if (m_imgTooltip.m_hImageList != NULL) 
		m_imgTooltip.DeleteImageList(); 
 
	m_imgTooltip.Create(cx, cy, ILC_COLOR32 | ILC_MASK, nCount, 1); 
	m_imgTooltip.Add(CBitmap::FromHandle(hBitmap), crMask); 
 
	m_szImage = CSize(cx, cy); 
} 
 
///////////////////////////////////////////////////////////////////////////// 
//  CPPToolTip::GetImageList (public member function) 
//    gets the image list from tooltip 
// 
//  Parameters : 
//		sz		   [out] - Dimensions of each image, in pixels. 
//  Returns : 
//		A pointer to a CImageList object 
// 
///////////////////////////////////////////////////////////////////////////// 
CImageList * CPPToolTip::GetImageList(CSize & sz) 
{ 
	sz = m_szImage; 
	return &m_imgTooltip; 
} 
 
///////////////////////////////////////////////////////////////////////////// 
//  CPPToolTip::AddNameOfResource (public member function) 
//    Associates the resource name with him ID 
// 
//  Parameters : 
//		sName		[in] - A resource name in format string of the tooltip 
//		nID			[in] - A resource ID associated with name. 
//		nTypeRes	[in] - A resource type: 
//							TYPE_RES_ICON - a resource is a icon 
//							TYPE_RES_BITMAP - a resource is a bitmap 
//							TYPE_RES_MASK_BITMAP - a resource is a transparent bitmap 
//		crMask		[in] - Color used to generate a mask. Each pixel of this color in the  
//						   specified bitmap is changed to black, and the corresponding  
//						   bit in the mask is set to one. 
//  Returns : 
//		None 
///////////////////////////////////////////////////////////////////////////// 
void CPPToolTip::AddNameOfResource(CString sName, UINT nID, BYTE nTypeRes /* = TYPE_RES_TRAN_BITMAP */, COLORREF crMask /* = RGB(255, 0, 255) */) 
{ 
	if (sName.IsEmpty() || (nID == 0) || (nTypeRes >= MAX_TYPES_RES)) 
		return; 
	 
	PPTOOLTIP_NAME_RES nr; 
	nr.sName = sName; 
	nr.nID = nID; 
	nr.nTypeRes = nTypeRes; 
	nr.crMask = crMask; 
 
	m_arrNameRes.Add(nr); 
} 
 
///////////////////////////////////////////////////////////////////////////// 
//  CPPToolTip::FindIdOfResource (public member function) 
//    Search the ID resource by his name 
// 
//  Parameters : 
//		sName		[in] - A resource name in format string of the tooltip 
//  Returns : 
//		The array's index with ID resource associated with name or -1 if ID not found 
///////////////////////////////////////////////////////////////////////////// 
int CPPToolTip::FindIdOfResource(CString sName) 
{ 
	PPTOOLTIP_NAME_RES nr; 
	for (int i = 0; i < m_arrNameRes.GetSize(); i++) 
	{ 
		nr = m_arrNameRes.GetAt(i); 
		if (!sName.CompareNoCase(nr.sName)) 
			return i; 
	} 
	return -1; 
} 
 
///////////////////////////////////////////////////////////////////////////// 
//  CPPToolTip::FindIdOfResource (public member function) 
//    Search the resource name by his ID 
// 
//  Parameters : 
//		nID		[in] - A ID resource 
//  Returns : 
//		The array's index with resource name associated with ID or -1 if name not found 
///////////////////////////////////////////////////////////////////////////// 
int CPPToolTip::FindNameOfResource(UINT nID) 
{ 
	PPTOOLTIP_NAME_RES nr; 
	for (int i = 0; i < m_arrNameRes.GetSize(); i++) 
	{ 
		nr = m_arrNameRes.GetAt(i); 
		if (nr.nID == nID) 
			return i; 
	} 
	return -1; 
} 
 
///////////////////////////////////////////////////////////////////////////// 
//  CPPToolTip::FindIdOfResource (public member function) 
//    Removes resource name by index of the array 
// 
//  Parameters : 
//		nIndex		[in] - A The index of the resource name in the array 
//  Returns : 
//		None 
///////////////////////////////////////////////////////////////////////////// 
void CPPToolTip::RemoveNameOfResource(int nIndex) 
{ 
	if (nIndex < m_arrNameRes.GetSize()) 
		m_arrNameRes.RemoveAt(nIndex); 
} 
 
///////////////////////////////////////////////////////////////////////////// 
//  CPPToolTip::FindIdOfResource (public member function) 
//    Removes all resource names from the array 
///////////////////////////////////////////////////////////////////////////// 
void CPPToolTip::RemoveAllNamesOfResource() 
{ 
	m_arrNameRes.RemoveAll(); 
}