/********************************************************************
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_H