// ==========================================================================
// Class Implementation : COXToolTipCtrl
// ==========================================================================
// Source file : OXToolTipCtrl.cpp
// Copyright � Dundas Software Ltd. 1999, All Rights Reserved
// //////////////////////////////////////////////////////////////////////////
#include "stdafx.h"
#include "OXToolTipCtrl.h"
#ifdef _DEBUG
#define new DEBUG_NEW
#undef THIS_FILE
static char THIS_FILE[] = __FILE__;
#endif
// TODO: Add message handlers (eg TTM_SETTIPBKCOLOR) and point them
// to the correct functions.
LPCTSTR COXToolTipCtrl::m_szArrowSpace = _T(" ");
/////////////////////////////////////////////////////////////////////////////
// COXToolTipCtrl construction
COXToolTipCtrl::COXToolTipCtrl() :
m_pParentWnd(NULL),
m_rectMargin(2,2,3,3),
m_nMaxWidth(0),
m_ptOffset(0,20),
m_pCurrentToolTip(NULL),
m_nCheckInterval(500), // Time between checks of the tooltip - allows
// user to move the mouse to the tooltip before
// it disappears
m_nDisplayDelay(500), // delay in milliseconds till the tooltip is
// displayed
m_nDisplayTime(5000), // Length of time the tooltip is displayed
m_nElapsedTime(0),
m_bActivated(TRUE),
m_bTipCancelled(FALSE),
m_bHasExtendedText(FALSE),
m_hOldFocusWnd(NULL),
m_crBackColor(CLR_DEFAULT),
m_crTextColor(CLR_DEFAULT),
m_bUsingSystemFont(TRUE),
m_dwTextStyle(DT_EXPANDTABS|DT_EXTERNALLEADING|DT_NOPREFIX|DT_WORDBREAK)
{
m_arrTools.RemoveAll();
}
COXToolTipCtrl::~COXToolTipCtrl()
{
m_Font.DeleteObject();
COXToolTipInfo *pInfo = NULL;
int nSize = m_arrTools.GetSize();
for (int nIndex = 0; nIndex < nSize; nIndex++)
{
pInfo = (COXToolTipInfo* )m_arrTools.GetAt(nIndex);
delete pInfo;
}
m_arrTools.RemoveAll();
if (IsWindow(m_hWnd))
DestroyWindow();
}
/////////////////////////////////////////////////////////////////////////////
// COXToolTipCtrl message handlers
BEGIN_MESSAGE_MAP(COXToolTipCtrl, CWnd)
//{{AFX_MSG_MAP(COXToolTipCtrl)
ON_WM_PAINT()
ON_WM_TIMER()
ON_WM_LBUTTONDOWN()
ON_WM_LBUTTONUP()
ON_WM_SETFOCUS()
ON_WM_DESTROY()
ON_WM_SETTINGCHANGE()
ON_WM_MOUSEACTIVATE()
//}}AFX_MSG_MAP
ON_MESSAGE(WM_SETFONT, OnSetFont)
ON_MESSAGE(WM_GETFONT, OnGetFont)
END_MESSAGE_MAP()
// --- In� :
// --- Out :
// --- Returns :
// --- Effect : Draws the tooltip - called in response to a WM_PAINT message
void COXToolTipCtrl::OnPaint()
{
if (!m_pCurrentToolTip)
return;
CString str = GetTooltipText(m_pCurrentToolTip);
if (str.IsEmpty())
return;
CPaintDC dc(this); // device context for painting
CRect rect;
GetClientRect(rect);
CBrush Brush, *pOldBrush;
if (m_pCurrentToolTip->clrBackColor == CLR_DEFAULT)
Brush.CreateSolidBrush(GetSysColor(COLOR_INFOBK));
else
Brush.CreateSolidBrush(m_pCurrentToolTip->clrBackColor);
pOldBrush = dc.SelectObject(&Brush);
if (m_pCurrentToolTip->clrTextColor == CLR_DEFAULT)
dc.SetTextColor(GetSysColor(COLOR_INFOTEXT));
else
dc.SetTextColor(m_pCurrentToolTip->clrTextColor);
CFont *pOldFont = dc.SelectObject(&m_Font);
// Draw Border
dc.FillRect(&rect, &Brush);
dc.SelectStockObject(NULL_BRUSH);
dc.SelectStockObject(BLACK_PEN);
dc.Rectangle(rect);
// Draw Text
dc.SetBkMode(TRANSPARENT);
rect.DeflateRect(m_rectMargin);
dc.DrawText(str, rect, m_dwTextStyle);
if (m_bHasExtendedText)
{
TEXTMETRIC tm;
dc.GetTextMetrics(&tm);
int nYMargin = max(tm.tmExternalLeading + tm.tmInternalLeading, tm.tmDescent);
int nXMargin = tm.tmAveCharWidth / 2;
CSize size = dc.GetTextExtent(m_szArrowSpace);
if ((size.cy & 1))
size.cy--;
CPoint pt[4];
if (m_bExtended)
{
pt[0] = CPoint(rect.left + size.cx - nXMargin, rect.top + nYMargin);
pt[1] = CPoint(rect.left, rect.top + size.cy/2);
pt[2] = CPoint(rect.left + size.cx - nXMargin, rect.top + size.cy - nYMargin);
pt[3] = pt[0];
}
else
{
pt[0] = CPoint(rect.right - size.cx + nXMargin, rect.top + nYMargin);
pt[1] = CPoint(rect.right, rect.top + size.cy/2);
pt[2] = CPoint(rect.right - size.cx + nXMargin, rect.top + size.cy - nYMargin);
pt[3] = pt[0];
}
dc.SelectStockObject(BLACK_BRUSH);
dc.Polygon(pt, 4);
}
// Cleanup
dc.SelectObject(pOldBrush);
dc.SelectObject(pOldFont);
}
// --- In� : nIDEvent - The timer event
// --- Out :
// --- Returns :
// --- Effect : Timer events are used to either Activate the tooltip after
// the mouse has been stationary for the specified time, Remove
// the tip after a specified display time, or peridodically check
// that the mouse is still within the bounds of the tool
void COXToolTipCtrl::OnTimer(UINT nIDEvent)
{
CPoint pt;
COXToolTipInfo *pToolTip = NULL;
if (!m_pCurrentToolTip || m_bTipCancelled)
{
KillTimer(nIDEvent);
Pop();
return;
}
switch (nIDEvent)
{
// The mouse has been still for sufficient time. If it's still in the
// initial tool, then show the tooltip for that tool.
case eIDDisplayToolEvent:
KillTimer(eIDDisplayToolEvent);
if (IsCursorInTool(m_pCurrentToolTip))
{
CPoint pt;
GetCursorPos(&pt);
pt += m_ptOffset;
DisplayToolTip(pt);
m_nElapsedTime = 0;
SetTimer(eIDCheckToolEvent, m_nCheckInterval, NULL);
}
break;
// The tooltip is visible, check it's (a) not been around too long, and
// (b) still in the bounding rect (or tooltip window). If all is well then
// reset the egg timer and check again later.
case eIDCheckToolEvent:
m_nElapsedTime += m_nCheckInterval;
GetCursorPos(&pt);
m_pParentWnd->ScreenToClient(&pt);
pToolTip = FindToolFromPoint(pt);
// Check that the cursor isn't over a new tool
if (pToolTip && pToolTip != m_pCurrentToolTip)
{
KillTimer(eIDCheckToolEvent);
Pop();
return;
}
if (!IsCursorInTool(m_pCurrentToolTip) || (m_nElapsedTime >= m_nDisplayTime))
{
if (IsCursorInToolTip())
{
//TRACE0("Cursor in tooltip - will check later\n");
//SetTimer(eIDCheckToolEvent, m_nCheckInterval, NULL);
}
else
{
//TRACE0("Not in tool or tooltip anymore, or expired. Destroying\n");
KillTimer(eIDCheckToolEvent);
Pop();
//m_pCurrentToolTip = NULL;
}
}
else
{
//TRACE0("Everything's OK - will check later\n");
//SetTimer(eIDCheckToolEvent, m_nCheckInterval, NULL);
}
break;
default:
ASSERT(FALSE);
}
}
// --- In� : nFlags - unused
// point - unused
// --- Out :
// --- Returns :
// --- Effect : Causes a switch between standard and extended info viewing
void COXToolTipCtrl::OnLButtonDown(UINT /*nFlags*/, CPoint /*point*/)
{
// Sometimes a click comes through the pipeline aft