You cannot select more than 25 topics
Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
639 lines
18 KiB
C++
639 lines
18 KiB
C++
// XTPTipWindow.cpp : implementation of the CXTPTipWindow class.
|
|
//
|
|
// This file is a part of the XTREME CONTROLS MFC class library.
|
|
// (c)1998-2012 Codejock Software, All Rights Reserved.
|
|
//
|
|
// THIS SOURCE FILE IS THE PROPERTY OF CODEJOCK SOFTWARE AND IS NOT TO BE
|
|
// RE-DISTRIBUTED BY ANY MEANS WHATSOEVER WITHOUT THE EXPRESSED WRITTEN
|
|
// CONSENT OF CODEJOCK SOFTWARE.
|
|
//
|
|
// THIS SOURCE CODE CAN ONLY BE USED UNDER THE TERMS AND CONDITIONS OUTLINED
|
|
// IN THE XTREME TOOLKIT PRO LICENSE AGREEMENT. CODEJOCK SOFTWARE GRANTS TO
|
|
// YOU (ONE SOFTWARE DEVELOPER) THE LIMITED RIGHT TO USE THIS SOFTWARE ON A
|
|
// SINGLE COMPUTER.
|
|
//
|
|
// CONTACT INFORMATION:
|
|
// support@codejock.com
|
|
// http://www.codejock.com
|
|
//
|
|
/////////////////////////////////////////////////////////////////////////////
|
|
|
|
// Thanks to Michael Berlenz for helping to extend the CXTPTipWindow class.
|
|
|
|
#include "stdafx.h"
|
|
#include "Common/XTPDrawHelpers.h"
|
|
#include "Common/XTPColorManager.h"
|
|
#include "Common/XTPSystemHelpers.h"
|
|
|
|
#include "../Util/XTPGlobal.h"
|
|
#include "XTPTipWindow.h"
|
|
|
|
#ifdef _DEBUG
|
|
#define new DEBUG_NEW
|
|
#undef THIS_FILE
|
|
static char THIS_FILE[] = __FILE__;
|
|
#endif
|
|
|
|
#define CS_DROPSHADOW 0x00020000
|
|
|
|
|
|
/////////////////////////////////////////////////////////////////////////////
|
|
// CXTPTipWindow
|
|
/////////////////////////////////////////////////////////////////////////////
|
|
|
|
CXTPTipWindow::CXTPTipWindow()
|
|
{
|
|
m_sizeMargin = CSize(0, 0);
|
|
m_nLineSpace = 0;
|
|
m_dwTipStyle = 0;
|
|
m_nElapseTimerEventID = 1;
|
|
m_pParentWnd = NULL;
|
|
m_strTitle = _T("");
|
|
m_strDescrip = _T("");
|
|
m_crBackColor = ::GetSysColor(COLOR_INFOBK);
|
|
m_crTextColor = ::GetSysColor(COLOR_INFOTEXT);
|
|
m_sizeTitle = CSize(0, 0);
|
|
// m_bMouseWasClickedSoDoNotShowTip = FALSE;
|
|
m_ptMousePos = CPoint(0, 0);
|
|
m_bCenterHorz = FALSE;
|
|
m_nDelayTimerEventID = 2;
|
|
m_bDelayTimerRunning = FALSE;
|
|
m_pointTipOffsetPos = CPoint(0, 20); //20 = mouse cursor height
|
|
m_pnTabStopPositions = NULL;
|
|
m_nTabPositions = 0;
|
|
m_bSystemShadow = FALSE;
|
|
|
|
m_rectTipArea.SetRectEmpty();
|
|
}
|
|
|
|
CXTPTipWindow::~CXTPTipWindow()
|
|
{
|
|
}
|
|
|
|
BOOL CXTPTipWindow::Create(CWnd* pParentWnd)
|
|
{
|
|
// register the wnd class.
|
|
XTPDrawHelpers()->RegisterWndClass(0, _T("XTPTipWindow"), CS_SAVEBITS | CS_HREDRAW | CS_VREDRAW);
|
|
|
|
// call the base class for creation.
|
|
if (!CWnd::CreateEx(0, _T("XTPTipWindow"), _T(""), WS_POPUP, 0, 0, 0, 0, pParentWnd->m_hWnd, 0, NULL))
|
|
{
|
|
TRACE0("Failed to create popup window.\n");
|
|
return FALSE;
|
|
}
|
|
|
|
m_pParentWnd = pParentWnd;
|
|
return TRUE;
|
|
}
|
|
|
|
BEGIN_MESSAGE_MAP(CXTPTipWindow, CWnd)
|
|
//{{AFX_MSG_MAP(CXTPTipWindow)
|
|
ON_WM_MOUSEMOVE()
|
|
ON_WM_KILLFOCUS()
|
|
ON_WM_PAINT()
|
|
ON_WM_TIMER()
|
|
ON_WM_ERASEBKGND()
|
|
ON_WM_LBUTTONDOWN()
|
|
ON_WM_RBUTTONDOWN()
|
|
ON_WM_MBUTTONDOWN()
|
|
//}}AFX_MSG_MAP
|
|
END_MESSAGE_MAP()
|
|
|
|
void CXTPTipWindow::CreateShadow()
|
|
{
|
|
if (((m_dwTipStyle & (TWS_XTP_ALPHASHADOW | TWS_XTP_DROPSHADOW)) == (TWS_XTP_ALPHASHADOW | TWS_XTP_DROPSHADOW)) &&
|
|
XTPSystemVersion()->IsWinXPOrGreater()) // Windows XP only
|
|
{
|
|
SetClassLong(m_hWnd, GCL_STYLE, GetClassLong(m_hWnd, GCL_STYLE) | CS_DROPSHADOW);
|
|
m_bSystemShadow = TRUE;
|
|
}
|
|
else
|
|
{
|
|
SetClassLong(m_hWnd, GCL_STYLE, GetClassLong(m_hWnd, GCL_STYLE) & ~CS_DROPSHADOW);
|
|
m_bSystemShadow = FALSE;
|
|
}
|
|
}
|
|
|
|
BOOL CXTPTipWindow::ShowTipWindow(const CPoint& point, DWORD dwTipStyle/*= TWS_XTP_DROPSHADOW*/, UINT nDelay/*= 0*/, UINT nElapse/*= 5000*/, BOOL bCenterHorz /*= FALSE*/)
|
|
{
|
|
//Check for valid tip text
|
|
if (m_strTitle.IsEmpty() && m_strDescrip.IsEmpty())
|
|
return FALSE;
|
|
|
|
// Save values for InitializeSize() function
|
|
m_ptMousePos = point;
|
|
m_bCenterHorz = bCenterHorz;
|
|
|
|
// Return if process is running
|
|
if (m_bDelayTimerRunning || IsWindowVisible())
|
|
return FALSE;
|
|
|
|
// Analyze tip text
|
|
m_arStrings.RemoveAll();
|
|
if (m_strDescrip.Find(_T("\n")) != -1)
|
|
{
|
|
CString strDesc(m_strDescrip);
|
|
|
|
while (strDesc.Find(_T("\n")) != -1)
|
|
{
|
|
int nDelim = strDesc.Find(_T("\n"));
|
|
CString strAdd = strDesc.Left(nDelim);
|
|
m_arStrings.Add(strAdd);
|
|
strDesc = strDesc.Mid(nDelim + 1);
|
|
}
|
|
m_arStrings.Add(strDesc);
|
|
}
|
|
|
|
// Save the tip style
|
|
m_dwTipStyle = dwTipStyle;
|
|
CreateShadow();
|
|
|
|
if (!nDelay)
|
|
{
|
|
// Show the tip window
|
|
InitializeSize(m_ptMousePos, m_bCenterHorz);
|
|
SetWindowPos(&wndTop, m_rcScreenWindow.left, m_rcScreenWindow.top, m_rcShadow.right - m_rcWindow.left,
|
|
m_rcShadow.bottom - m_rcWindow.top, SWP_SHOWWINDOW | SWP_NOACTIVATE); //see also InitializeSize()
|
|
|
|
SetCapture();
|
|
}
|
|
|
|
// If a time-out value was specified, start the timer.
|
|
if (nElapse || nDelay)
|
|
{
|
|
if (nDelay)
|
|
{
|
|
SetTimer(m_nDelayTimerEventID, nDelay, NULL); //if timer runns out, window will be shown
|
|
m_bDelayTimerRunning = TRUE;
|
|
}
|
|
|
|
if (nElapse)
|
|
SetTimer(m_nElapseTimerEventID, nDelay + nElapse, NULL); //if timer runns out, window will be hide
|
|
}
|
|
|
|
return TRUE; // success!
|
|
}
|
|
|
|
|
|
//////////////////////////////////////////////////////////////////////////
|
|
// ShowTipWindow
|
|
// ----------------------------------------------------------------------------
|
|
// rectCtrl = if the mouse is inside this rectangle the tip will be shown
|
|
// => client coordinates of the window that owns this tip window
|
|
// pointMousePos => client coordinates of the window that owns this tip window
|
|
//
|
|
BOOL CXTPTipWindow::ShowTipWindow(const CRect& rectCtrl, const CPoint& pointMousePos, DWORD dwTipStyle/*= TWS_XTP_DROPSHADOW*/, UINT nDelay/*= 0*/, UINT nElapse/*= 5000*/, BOOL bCenterHorz /*= FALSE*/, BOOL bShowTipAtCursorPos/*= FALSE*/)
|
|
{
|
|
//Check for valid tip text
|
|
// if (m_strTitle.IsEmpty() && m_strDescrip.IsEmpty()) //Do not process this check here!
|
|
// return FALSE;
|
|
|
|
//Check for zero rectangle
|
|
if (rectCtrl.IsRectNull())
|
|
return ShowTipWindow(pointMousePos, dwTipStyle, nDelay, nElapse, bCenterHorz);
|
|
|
|
//Check mouse was clicked -> do not show tip window
|
|
// if (m_bMouseWasClickedSoDoNotShowTip && rectCtrl == m_rectLast)
|
|
// return FALSE;
|
|
|
|
//In case the tip window is visible hide it
|
|
HideTipWindow();
|
|
|
|
//Calculate offset for bShowTipAtCursorPos = TRUE
|
|
CPoint pointMove = pointMousePos - rectCtrl.TopLeft();
|
|
pointMove.Offset(m_pointTipOffsetPos);
|
|
|
|
//Copy rectCtrl and move rectangle to zero origin
|
|
m_rectTipArea = rectCtrl;
|
|
|
|
//Offset rectangle
|
|
CPoint ptTipWindowPos = rectCtrl.TopLeft();
|
|
if (bShowTipAtCursorPos) //else show window at top left corner of rectCtrl
|
|
{
|
|
ptTipWindowPos += pointMove;
|
|
}
|
|
|
|
// m_bMouseWasClickedSoDoNotShowTip = FALSE;
|
|
//m_rectLast = rectCtrl;
|
|
|
|
m_pParentWnd->ClientToScreen(&ptTipWindowPos);
|
|
m_pParentWnd->ClientToScreen(&m_rectTipArea);
|
|
return ShowTipWindow(ptTipWindowPos, dwTipStyle, nDelay, nElapse, bCenterHorz);
|
|
}
|
|
|
|
void CXTPTipWindow::HideTipWindow()
|
|
{
|
|
// Kill the timers
|
|
KillTimer(m_nElapseTimerEventID);
|
|
KillTimer(m_nDelayTimerEventID);
|
|
m_bDelayTimerRunning = FALSE;
|
|
|
|
// Release capture
|
|
if (GetCapture() == this)
|
|
ReleaseCapture();
|
|
|
|
// Hide the tip window
|
|
if (IsWindowVisible())
|
|
ShowWindow(SW_HIDE);
|
|
|
|
//Initialize variables
|
|
m_rectTipArea.SetRectEmpty();
|
|
}
|
|
|
|
void CXTPTipWindow::InitializeSize(const CPoint& point, BOOL bCenterHorz /*FALSE*/)
|
|
{
|
|
// Create a temporary window dc, we are not actually
|
|
// going to paint anything, we just want to get the sizes
|
|
// of the title and description text.
|
|
CWindowDC dc(NULL);
|
|
|
|
// Get the size of the title string.
|
|
CFont* pOldFont = dc.SelectObject(&XTPAuxData().fontBold);
|
|
m_sizeTitle = dc.GetTabbedTextExtent(m_strTitle, m_nTabPositions, m_pnTabStopPositions);
|
|
|
|
// Get the size of the description string.
|
|
dc.SelectObject(&XTPAuxData().font);
|
|
|
|
CSize sizeDescrip(0, 0); // description text size.
|
|
if (m_arStrings.GetSize() == 0)
|
|
{
|
|
sizeDescrip = dc.GetTabbedTextExtent(m_strDescrip, m_nTabPositions, m_pnTabStopPositions);
|
|
}
|
|
else
|
|
{
|
|
TEXTMETRIC tm; // get the text metrics for the device context that is using the
|
|
dc.GetTextMetrics(&tm); // control's font, this will give us the text height in pixels.
|
|
|
|
CSize sizeTemp;
|
|
int nStrings;
|
|
for (nStrings = 0; nStrings < m_arStrings.GetSize(); ++nStrings)
|
|
{
|
|
// Strings could be empty because only a line break could be in the line.
|
|
// A empty string will return zero text extend. But we still have to count this line!
|
|
if (m_arStrings[nStrings].IsEmpty())
|
|
sizeDescrip.cy += tm.tmHeight;
|
|
else
|
|
{
|
|
sizeTemp = dc.GetTabbedTextExtent(m_arStrings[nStrings], m_nTabPositions, m_pnTabStopPositions);
|
|
sizeDescrip.cy += sizeTemp.cy;
|
|
sizeDescrip.cx = __max(sizeDescrip.cx, sizeTemp.cx);
|
|
}
|
|
}
|
|
}
|
|
|
|
// Restore GDI object.
|
|
dc.SelectObject(pOldFont);
|
|
|
|
// Define the width of the tip window.
|
|
int nWidth = __max(m_sizeTitle.cx, sizeDescrip.cx);
|
|
nWidth = (m_sizeMargin.cx * 2 + nWidth);
|
|
|
|
// Define the height of the tip window.
|
|
int nHeight = (m_sizeMargin.cy * 2 + ((m_strTitle.GetLength() > 0) ? m_sizeTitle.cy + m_nLineSpace : 0) + sizeDescrip.cy);
|
|
|
|
// Set the sizes for the tip window and its shadow.
|
|
m_rcScreenWindow.left = point.x;
|
|
m_rcScreenWindow.top = point.y;
|
|
m_rcScreenWindow.right = point.x + nWidth + 2; //+2 for better view
|
|
m_rcScreenWindow.bottom = point.y + nHeight;
|
|
|
|
if (bCenterHorz)
|
|
m_rcScreenWindow.OffsetRect(-m_rcScreenWindow.Width()/2, 0);
|
|
|
|
// ensure that the tip window is visible.
|
|
CRect rcWork = XTPMultiMonitor()->GetWorkArea(point);
|
|
CSize size = m_rcScreenWindow.Size();
|
|
|
|
// move right
|
|
if (m_rcScreenWindow.left < rcWork.left)
|
|
{
|
|
m_rcScreenWindow.left = rcWork.left;
|
|
m_rcScreenWindow.right = m_rcScreenWindow.left + size.cx;
|
|
}
|
|
|
|
// move left
|
|
else if (m_rcScreenWindow.right > rcWork.right)
|
|
{
|
|
m_rcScreenWindow.right = rcWork.right;
|
|
m_rcScreenWindow.left = m_rcScreenWindow.right - size.cx;
|
|
}
|
|
|
|
// move up
|
|
if (m_rcScreenWindow.bottom > rcWork.bottom)
|
|
{
|
|
m_rcScreenWindow.bottom = rcWork.bottom;
|
|
m_rcScreenWindow.top = m_rcScreenWindow.bottom - size.cy;
|
|
}
|
|
|
|
// Initialize the size of the shadow rect.
|
|
m_rcWindow = m_rcScreenWindow;
|
|
m_rcWindow.top = 0;
|
|
m_rcWindow.left = 0;
|
|
m_rcWindow.right = m_rcScreenWindow.Width();
|
|
m_rcWindow.bottom = m_rcScreenWindow.Height();
|
|
|
|
m_rcShadow = m_rcWindow;
|
|
if ((m_dwTipStyle & TWS_XTP_DROPSHADOW) && !m_bSystemShadow)
|
|
m_rcShadow.OffsetRect(5, 5);
|
|
}
|
|
|
|
void CXTPTipWindow::OnKillFocus(CWnd* pNewWnd)
|
|
{
|
|
CWnd::OnKillFocus(pNewWnd);
|
|
|
|
HideTipWindow();
|
|
|
|
// Repaint the area where the shadow was displayed.
|
|
if ((m_dwTipStyle & TWS_XTP_DROPSHADOW) && !m_bSystemShadow)
|
|
{
|
|
m_pParentWnd->RedrawWindow(0, 0,
|
|
RDW_INVALIDATE | RDW_UPDATENOW | RDW_ERASE | RDW_ALLCHILDREN);
|
|
}
|
|
}
|
|
|
|
int CXTPTipWindow::CheckValue(int iValue)
|
|
{
|
|
return ((iValue > 255) ? 255 : ((iValue < 0) ? 0 : iValue));
|
|
}
|
|
|
|
COLORREF CXTPTipWindow::AlphaPixel(COLORREF crPixel, int i)
|
|
{
|
|
return RGB(
|
|
CheckValue(GetRValue(crPixel)-i),
|
|
CheckValue(GetGValue(crPixel)-i),
|
|
CheckValue(GetBValue(crPixel)-i));
|
|
}
|
|
|
|
void CXTPTipWindow::DrawShadowRect(CDC* pDC, const CRect& rcShadow)
|
|
{
|
|
if ((m_dwTipStyle & TWS_XTP_ALPHASHADOW) == 0)
|
|
{
|
|
// Bit pattern for a monochrome brush with every
|
|
// other pixel turned off
|
|
WORD bits[] =
|
|
{
|
|
0x0055, 0x00AA, 0x0055, 0x00AA,
|
|
0x0055, 0x00AA, 0x0055, 0x00AA
|
|
};
|
|
|
|
// Need a monochrome pattern bitmap
|
|
CBitmap bitmap;
|
|
bitmap.CreateBitmap(8, 8, 1, 1, &bits);
|
|
|
|
// Create the pattern brush
|
|
CBrush brush;
|
|
brush.CreatePatternBrush(&bitmap);
|
|
CBrush *pOldBrush = pDC->SelectObject(&brush);
|
|
|
|
// Turn every other pixel to black
|
|
COLORREF clrBk = pDC->SetBkColor(RGB(0x00, 0x00, 0x00));
|
|
COLORREF clrText = pDC->SetTextColor(RGB(0xFF, 0xFF, 0xFF));
|
|
|
|
// 0x00A000C9 is the ROP code to AND the brush with the destination
|
|
pDC->PatBlt(rcShadow.left, rcShadow.top, rcShadow.Width(), rcShadow.Height(),
|
|
(DWORD)0x00A000C9); //DPa - raster code
|
|
|
|
// Restore the device context
|
|
pDC->SelectObject(pOldBrush);
|
|
pDC->SetTextColor(clrText);
|
|
pDC->SetBkColor(clrBk);
|
|
|
|
brush.DeleteObject();
|
|
bitmap.DeleteObject();
|
|
}
|
|
else
|
|
{
|
|
CRect rc1 = rcShadow;
|
|
CRect rc2 = rcShadow;
|
|
CRect rc3 = rcShadow;
|
|
CRect rc4 = rcShadow;
|
|
CRect rc5 = rcShadow;
|
|
CRect rc6 = rcShadow;
|
|
|
|
rc2.DeflateRect(1, 1);
|
|
rc3.DeflateRect(2, 2);
|
|
rc4.DeflateRect(3, 3);
|
|
rc5.DeflateRect(4, 4);
|
|
rc6.DeflateRect(5, 5);
|
|
|
|
int cx = rcShadow.Width() + 5;
|
|
int cy = rcShadow.Height() + 5;
|
|
|
|
int x;
|
|
for (x = 5; x < cx; ++x)
|
|
{
|
|
int y;
|
|
for (y = 5; y < cy; ++y)
|
|
{
|
|
CPoint pt(x, y);
|
|
int iAlpha = 0;
|
|
|
|
// area covered by menu...continue.
|
|
if (rc6.PtInRect(pt))
|
|
{
|
|
continue;
|
|
}
|
|
else if (rc5.PtInRect(pt))
|
|
{
|
|
iAlpha = 75;
|
|
}
|
|
else if (rc4.PtInRect(pt))
|
|
{
|
|
iAlpha = 60;
|
|
}
|
|
else if (rc3.PtInRect(pt))
|
|
{
|
|
iAlpha = 45;
|
|
}
|
|
else if (rc2.PtInRect(pt))
|
|
{
|
|
iAlpha = 30;
|
|
}
|
|
else if (rc1.PtInRect(pt))
|
|
{
|
|
iAlpha = 15;
|
|
}
|
|
if (iAlpha != 0)
|
|
{
|
|
COLORREF crAlpha = AlphaPixel(pDC->GetPixel(x, y), iAlpha);
|
|
pDC->SetPixel(x, y, crAlpha);
|
|
}
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
void CXTPTipWindow::OnPaint()
|
|
{
|
|
CPaintDC dc(this); // device context for painting
|
|
|
|
// Set the background mode to transparent.
|
|
dc.SetBkMode(TRANSPARENT);
|
|
|
|
// Draw a shadow on the the parent window, we will need the
|
|
// parent's device context to do this.
|
|
if ((m_dwTipStyle & TWS_XTP_DROPSHADOW) && !m_bSystemShadow)
|
|
DrawShadowRect(&dc, m_rcShadow);
|
|
|
|
// use the system tooltip colors for text and background.
|
|
dc.SetTextColor(m_crTextColor);
|
|
dc.FillSolidRect(m_rcWindow, m_crBackColor);
|
|
|
|
// Draw a border around the window.
|
|
dc.Draw3dRect(m_rcWindow, GetXtremeColor(COLOR_3DDKSHADOW),
|
|
GetXtremeColor(COLOR_3DDKSHADOW));
|
|
|
|
// Draw an inner light grey border.
|
|
if (m_dwTipStyle & TWS_XTP_THICKBORDER)
|
|
{
|
|
CRect rect(m_rcWindow);
|
|
rect.DeflateRect(1, 1);
|
|
dc.Draw3dRect(rect, GetXtremeColor(COLOR_3DSHADOW),
|
|
GetXtremeColor(COLOR_3DSHADOW));
|
|
}
|
|
|
|
// Draw the title text.
|
|
CFont* pOldFont = dc.SelectObject(&XTPAuxData().fontBold);
|
|
dc.TabbedTextOut(m_sizeMargin.cx + 1, m_sizeMargin.cy, m_strTitle, m_nTabPositions,
|
|
m_pnTabStopPositions, m_sizeMargin.cx + 1);
|
|
|
|
// Draw the description text.
|
|
dc.SelectObject(&XTPAuxData().font);
|
|
|
|
if (m_arStrings.GetSize() == 0)
|
|
dc.TabbedTextOut(m_sizeMargin.cx + 1, m_sizeMargin.cy + ((m_strTitle.GetLength() > 0) ? m_sizeTitle.cy + m_nLineSpace : 0),
|
|
m_strDescrip, m_nTabPositions, m_pnTabStopPositions, m_sizeMargin.cx + 1);
|
|
else
|
|
{
|
|
// Get the string height for stepping through
|
|
CSize sizeDesc = dc.GetTabbedTextExtent(m_arStrings[0], m_nTabPositions, m_pnTabStopPositions);
|
|
|
|
// The second parameter is long because we add the height of the strings already done, and also
|
|
// we don't add anything to get below the title if the length of the title is 0.
|
|
int nStrings;
|
|
for (nStrings = 0; nStrings < m_arStrings.GetSize(); ++nStrings)
|
|
dc.TabbedTextOut(m_sizeMargin.cx + 1,
|
|
m_sizeMargin.cy + (nStrings * sizeDesc.cy) + ((m_strTitle.GetLength() > 0) ? m_sizeTitle.cy + m_nLineSpace : 0),
|
|
m_arStrings[nStrings], m_nTabPositions, m_pnTabStopPositions, m_sizeMargin.cx + 1);
|
|
|
|
}
|
|
|
|
// Restore the device context.
|
|
dc.SelectObject(pOldFont);
|
|
}
|
|
|
|
void CXTPTipWindow::OnTimer(UINT_PTR nIDEvent)
|
|
{
|
|
if (m_nElapseTimerEventID == nIDEvent)
|
|
{
|
|
// Hide the tip window.
|
|
HideTipWindow();
|
|
}
|
|
|
|
if (m_nDelayTimerEventID == nIDEvent)
|
|
{
|
|
KillTimer(m_nDelayTimerEventID);
|
|
if (!m_rectTipArea.IsRectNull())
|
|
{
|
|
//If someone moves the mouse over a tip area in the client window
|
|
//it may happen that the tip delay timer will be started. During this
|
|
//delay time the user may move the mouse out of the application window.
|
|
//After the timer runs out the tip window will be shown but because
|
|
//of the fast mouse move the cursor will not be located inside the tip area.
|
|
//Because the cursor my located outside the application we will not get
|
|
//the mouse move messages at CXTPTipWindow::OnMouseMove().
|
|
//So better check if the mouse is still located inside the tip area.
|
|
//If not do not show the tip window.
|
|
|
|
CPoint pointMouse;
|
|
GetCursorPos(&pointMouse);
|
|
if (!m_rectTipArea.PtInRect(pointMouse))
|
|
return;
|
|
}
|
|
|
|
// Show the tip window
|
|
InitializeSize(m_ptMousePos, m_bCenterHorz); //Calculates m_rcScreenWindow values
|
|
SetWindowPos(&wndTop, m_rcScreenWindow.left, m_rcScreenWindow.top, m_rcScreenWindow.Width(), m_rcScreenWindow.Height(), SWP_SHOWWINDOW | SWP_NOACTIVATE); //+5 because of the shadow
|
|
SetCapture();
|
|
m_bDelayTimerRunning = FALSE;
|
|
}
|
|
|
|
CWnd::OnTimer(nIDEvent);
|
|
}
|
|
|
|
BOOL CXTPTipWindow::OnEraseBkgnd(CDC* /*pDC*/)
|
|
{
|
|
return TRUE;
|
|
}
|
|
|
|
//////////////////////////////////////////////////////////////////////////
|
|
//
|
|
// Hide the tip window and forward the message to the window at mouse point.
|
|
//
|
|
void CXTPTipWindow::ForwardMessage(UINT uiMsg, UINT nFlags, CPoint point)
|
|
{
|
|
// m_bMouseWasClickedSoDoNotShowTip = TRUE;
|
|
|
|
HideTipWindow();
|
|
|
|
CPoint pt(point);
|
|
ClientToScreen(&pt);
|
|
CWnd* pClick = WindowFromPoint(pt);
|
|
|
|
if (!pClick->IsChild(this) && pClick != this)
|
|
{
|
|
LRESULT iHitTest = pClick->SendMessage(WM_NCHITTEST, 0, MAKELPARAM(pt.x, pt.y));
|
|
if (AfxGetMainWnd() != NULL)
|
|
pClick->SendMessage(WM_MOUSEACTIVATE, (LPARAM)AfxGetMainWnd()->m_hWnd, MAKELPARAM(iHitTest , uiMsg));
|
|
pClick->ScreenToClient(&pt);
|
|
pClick->SendMessage(uiMsg, nFlags, MAKELPARAM(pt.x, pt.y));
|
|
}
|
|
|
|
CWnd::OnLButtonDown(nFlags, point);
|
|
}
|
|
|
|
void CXTPTipWindow::OnLButtonDown(UINT nFlags, CPoint point)
|
|
{
|
|
ForwardMessage(WM_LBUTTONDOWN, nFlags, point);
|
|
}
|
|
|
|
void CXTPTipWindow::OnRButtonDown(UINT nFlags, CPoint point)
|
|
{
|
|
ForwardMessage(WM_RBUTTONDOWN, nFlags, point);
|
|
}
|
|
|
|
void CXTPTipWindow::OnMButtonDown(UINT nFlags, CPoint point)
|
|
{
|
|
ForwardMessage(WM_MBUTTONDOWN, nFlags, point);
|
|
}
|
|
|
|
void CXTPTipWindow::OnMouseMove(UINT /*nFlags*/, CPoint point)
|
|
{
|
|
ClientToScreen( &point );
|
|
if (!m_rectTipArea.IsRectNull() && !m_rectTipArea.PtInRect(point))
|
|
HideTipWindow();
|
|
}
|
|
|
|
void CXTPTipWindow::SetTipText(LPCTSTR lpszTitle, LPCTSTR lpszDescrip, BOOL bRedraw)
|
|
{
|
|
m_strTitle = lpszTitle; //Single line
|
|
|
|
// Avoid uggly outputed rectangle character in the tip window
|
|
m_strDescrip = lpszDescrip; //Could be multi-line
|
|
m_strDescrip.Remove(_T('\r'));
|
|
|
|
if (bRedraw)
|
|
{
|
|
InvalidateRect(NULL);
|
|
}
|
|
}
|
|
|
|
void CXTPTipWindow::SetTextTabStopPositions(LPINT pnTabStopPositions, int nTabPositions)
|
|
{
|
|
//pointer to integer array containing the tab stop positions (could be a static array)
|
|
m_pnTabStopPositions = pnTabStopPositions;
|
|
|
|
//number of array elements
|
|
m_nTabPositions = nTabPositions;
|
|
}
|