// XTPToolTipContext.cpp: implementation of the CXTPToolTipContext class. // // This file is a part of the XTREME TOOLKIT PRO 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 // ///////////////////////////////////////////////////////////////////////////// #include "stdafx.h" #if _MSC_VER < 1200 #define _XTP_EXCLUDE_HTML #else #include #include #endif // !_MSC_VER < 1200 #include "XTPToolTipContext.h" #include "XTPVC80Helpers.h" #include "XTPDrawHelpers.h" #include "XTPColorManager.h" #include "XTPImageManager.h" #include "XTPResourceImage.h" #include "XTPSystemHelpers.h" #include "XTPRichRender.h" #include "XTPResourceManager.h" #include "XTPMarkupRender.h" #ifdef _INC_COMDEF // Warning "ComDef.h" was included #endif #ifdef _DEBUG #undef THIS_FILE static char THIS_FILE[] = __FILE__; #define new DEBUG_NEW #endif #pragma warning (disable : 4097) // typedef-name 'CXTPToolTipContextTipOfficeCtrl' used as synonym for class-name 'CRichEditToolTip' #define WM_SYSKEYFIRST WM_SYSKEYDOWN #define WM_SYSKEYLAST WM_SYSDEADCHAR #define VERSION_IE5 MAKELONG(80, 5) #define TTS_NOANIMATE 0x10 #define TTS_NOFADE 0x20 #define TTS_BALLOON 0x40 #define CS_DROPSHADOW 0x00020000 #ifndef TTM_SETTITLE #define TTM_SETTITLEA (WM_USER + 32) // wParam = TTI_*, lParam = char* szTitle #define TTM_SETTITLEW (WM_USER + 33) // wParam = TTI_*, lParam = wchar* szTitle #ifdef UNICODE #define TTM_SETTITLE TTM_SETTITLEW #else #define TTM_SETTITLE TTM_SETTITLEA #endif #endif #ifndef WF_TRACKINGTOOLTIPS #define WF_TRACKINGTOOLTIPS 0x0400 #endif #define SAFE_DELETEWINDOW(ptr) \ if (ptr) { ptr->DestroyWindow(); delete ptr; ptr = NULL; } CXTPToolTipContext* CXTPToolTipContext::m_pModuleContext = 0; IMPLEMENT_DYNAMIC(CXTPToolTipContextToolTip, CWnd) void XTPStripEllipsis(LPTSTR lpszText) { if (lpszText == NULL || lpszText == LPSTR_TEXTCALLBACK) return; int len = (int)_tcslen(lpszText); if (len > 3) { for (int i = len - 3; i < len; i++) { if (lpszText[i] != _T('.')) return; } lpszText[len - 3] = 0; } }; ////////////////////////////////////////////////////////////////////////// // CXTPToolTipContextToolTip CXTPToolTipContextToolTip::CXTPToolTipContextToolTip(CXTPToolTipContext* pContext) : m_pContext(pContext) { m_bActive = FALSE; m_toolVisible.Reset(); m_toolDisabled.Reset(); m_toolDelay.Reset(); m_pIcon = NULL; m_bWindowRegion = FALSE; m_nDelayTimer = 0; m_nAutoPopTimer = 0; m_dwLastTip = 0; m_nDelayInitial = 500; m_nDelayReshow = 200; m_nDelayAutoPop = 0; } void CXTPToolTipContext::SetFont(CFont* pFont) { LOGFONT lf; pFont->GetLogFont(&lf); SetFontIndirect(&lf); } void CXTPToolTipContext::SetFontIndirect(LOGFONT* lpLogFont) { if (!lpLogFont) return; lpLogFont->lfWeight = FW_NORMAL; m_fnt.DeleteObject(); m_fnt.CreateFontIndirect(lpLogFont); lpLogFont->lfWeight = FW_BOLD; m_fntTitle.DeleteObject(); m_fntTitle.CreateFontIndirect(lpLogFont); if (m_pToolTip) m_pToolTip->DestroyWindow(); } CXTPToolTipContextToolTip::~CXTPToolTipContextToolTip() { for (int i = 0; i < (int)m_arrTools.GetSize(); i++) { delete m_arrTools[i]; } m_arrTools.RemoveAll(); HookMouseMove(FALSE); } BEGIN_MESSAGE_MAP(CXTPToolTipContextToolTip, CWnd) //{{AFX_MSG_MAP(CXTPToolTipContextToolTip) ON_MESSAGE(TTM_ADDTOOL, OnAddTool) ON_MESSAGE(TTM_ACTIVATE, OnActivate) ON_MESSAGE(TTM_DELTOOL, OnDelTool) ON_MESSAGE(TTM_RELAYEVENT, OnRelayEvent) ON_MESSAGE(TTM_SETTITLE, OnSetTitle) ON_MESSAGE(TTM_UPDATETIPTEXT, OnUpdateTipText) ON_MESSAGE(TTM_SETDELAYTIME, OnSetDelayTime) ON_MESSAGE(XTP_TTM_SETIMAGE, OnSetImage) ON_WM_PAINT() ON_WM_ERASEBKGND() ON_WM_NCHITTEST_EX() ON_WM_MOUSEACTIVATE() ON_WM_MOUSEMOVE() ON_WM_TIMER() ON_WM_DESTROY() ON_MESSAGE(TTM_WINDOWFROMPOINT, OnWindowFromPoint) //}}AFX_MSG_MAP END_MESSAGE_MAP() ///////////////////////////////////////////////////////////////////////////// // CXTPToolTipContextToolTip message handlers BOOL CXTPToolTipContextToolTip::Create(CWnd* pParentWnd, DWORD dwStyle) { UINT nClassStyle = (dwStyle & XTP_TTS_NOSHADOW ? 0 : CS_DROPSHADOW) | CS_SAVEBITS | CS_OWNDC; if ((nClassStyle & CS_DROPSHADOW) && !XTPSystemVersion()->IsWinXPOrGreater()) // Windows XP only { nClassStyle &= ~CS_DROPSHADOW; } BOOL bResult = CWnd::CreateEx(WS_EX_TOOLWINDOW, AfxRegisterWndClass(nClassStyle, AfxGetApp()->LoadStandardCursor(IDC_ARROW)), NULL, WS_POPUP | dwStyle, // force WS_POPUP CW_USEDEFAULT, CW_USEDEFAULT, CW_USEDEFAULT, CW_USEDEFAULT, pParentWnd->GetSafeHwnd(), NULL, NULL); if (bResult) SetOwner(pParentWnd); return bResult; } void CXTPToolTipContextToolTip::OnDestroy() { m_toolVisible.Reset(); m_toolDisabled.Reset(); m_toolDelay.Reset(); for (int i = 0; i < (int)m_arrTools.GetSize(); i++) { delete m_arrTools[i]; } m_arrTools.RemoveAll(); m_strTitle.Empty(); m_pIcon = NULL; Activate(FALSE); HookMouseMove(FALSE); CWnd::OnDestroy(); } LRESULT CXTPToolTipContextToolTip::OnSetImage(WPARAM, LPARAM lParam) { m_pIcon = (CXTPImageManagerIcon*)lParam; return 0; } LRESULT CXTPToolTipContextToolTip::OnSetTitle(WPARAM, LPARAM lParam) { m_strTitle = (LPCTSTR)lParam; return 0; } LRESULT CXTPToolTipContextToolTip::OnSetDelayTime(WPARAM dwDuration, LPARAM lParam) { UINT iTime = LOWORD(lParam); switch (dwDuration) { case TTDT_RESHOW: m_nDelayReshow = iTime; break; case TTDT_INITIAL: m_nDelayInitial = iTime; break; case TTDT_AUTOPOP: m_nDelayAutoPop = iTime; break; } return 0; } LRESULT CXTPToolTipContextToolTip::OnUpdateTipText(WPARAM, LPARAM lParam) { LPTOOLINFO lpToolInfo = LPTOOLINFO(lParam); for (int i = 0; i < (int)m_arrTools.GetSize(); i++) { TOOLITEM* pItem = m_arrTools[i]; if ((pItem->uId == lpToolInfo->uId) && (pItem->hwnd == lpToolInfo->hwnd)) { pItem->bAutoCaption = (lpToolInfo->lpszText == LPSTR_TEXTCALLBACK); pItem->strCaption = pItem->bAutoCaption ? _T("") : lpToolInfo->lpszText; break; } } return 0; } LRESULT CXTPToolTipContextToolTip::OnAddTool(WPARAM, LPARAM lParam) { return AddTool((LPTOOLINFO)lParam); } LRESULT CXTPToolTipContextToolTip::OnActivate(WPARAM wParam, LPARAM) { Activate((BOOL)wParam); return 0; } LRESULT CXTPToolTipContextToolTip::OnDelTool(WPARAM, LPARAM lParam) { DelTool((LPTOOLINFO)lParam); return 0; } LRESULT CXTPToolTipContextToolTip::OnRelayEvent(WPARAM, LPARAM lParam) { RelayEvent((LPMSG)lParam); return 0; } LRESULT CXTPToolTipContextToolTip::OnWindowFromPoint(WPARAM, LPARAM lParam) { LPPOINT lpPoint = (LPPOINT)lParam; HWND hWnd = lpPoint ? ::WindowFromPoint(*lpPoint) : 0; if ((hWnd != NULL) && (GetWindowLong(hWnd, GWL_STYLE) & WS_CHILD) && (::SendMessage(hWnd, XTP_TTM_WINDOWFROMPOINT, 0, 0) == 1)) { return (LRESULT)::GetParent(hWnd); } return (LRESULT)hWnd; } BOOL CXTPToolTipContextToolTip::AddTool(LPTOOLINFO lpToolInfo) { ASSERT(lpToolInfo); if (!lpToolInfo) return FALSE; TOOLITEM* pti = new TOOLITEM; pti->hwnd = lpToolInfo->hwnd; pti->uFlags = lpToolInfo->uFlags; pti->uId = lpToolInfo->uId; pti->rect = lpToolInfo->rect; pti->bAutoCaption = (lpToolInfo->lpszText == LPSTR_TEXTCALLBACK); pti->strCaption = pti->bAutoCaption ? _T("") : lpToolInfo->lpszText; pti->hinst = lpToolInfo->hinst; pti->rectExclude.SetRectEmpty(); if (lpToolInfo->cbSize == sizeof(XTP_TOOLTIP_TOOLINFO_EX)) { pti->rectExclude = ((XTP_TOOLTIP_TOOLINFO_EX*)lpToolInfo)->pToolInfo->rcExclude; } m_arrTools.Add(pti); return TRUE; } void CXTPToolTipContextToolTip::Activate(BOOL bActivate) { m_bActive = bActivate; if (!bActivate && GetSafeHwnd() && m_nDelayTimer) { KillTimer(m_nDelayTimer); m_nDelayTimer = 0; m_toolDelay.Reset(); } if (!bActivate && GetSafeHwnd() && IsWindowVisible()) { SetVisibleTool(NULL); } } void CXTPToolTipContextToolTip::DelTool(LPTOOLINFO lpToolInfo) { ASSERT(lpToolInfo); if (!lpToolInfo) return; for (int i = 0; i < (int)m_arrTools.GetSize(); i++) { TOOLITEM* pItem = m_arrTools[i]; if ((pItem->uId == lpToolInfo->uId) && (pItem->hwnd == lpToolInfo->hwnd)) { if (m_toolVisible.IsEqual(pItem)) SetVisibleTool(0); if (m_toolDisabled.IsEqual(pItem)) m_toolDisabled.Reset(); if (m_toolDelay.IsEqual(pItem)) m_toolDelay.Reset(); m_arrTools.RemoveAt(i); delete pItem; break; } } } CXTPToolTipContextToolTip::TOOLITEM* CXTPToolTipContextToolTip::FindTool() { if (!(GetKeyState(VK_LBUTTON) >= 0 && GetKeyState(VK_RBUTTON) >= 0 && GetKeyState(VK_MBUTTON) >= 0)) { return NULL; } CPoint pt; GetCursorPos(&pt); for (int i = 0; i < m_arrTools.GetSize(); i++) { TOOLITEM* pItem = m_arrTools[i]; if (!::IsWindow(pItem->hwnd)) continue; CWnd* pWnd = CWnd::FromHandle(pItem->hwnd); CRect rcTool = pItem->rect; if (pItem->uFlags & TTF_IDISHWND) { pWnd->GetWindowRect(rcTool); } else { pWnd->ClientToScreen(rcTool); } if (rcTool.PtInRect(pt) && ((pItem->uFlags & TTF_IDISHWND) || ((HWND)OnWindowFromPoint(0, (LRESULT)(LPPOINT)&pt) == pItem->hwnd))) return pItem; } return NULL; } #ifndef IS_INTRESOURCE #define IS_INTRESOURCE(x) (((size_t)(x) >> 16) == 0) #endif CString CXTPToolTipContextToolTip::GetToolText(TOOLITEM* lpToolInfo) { if (lpToolInfo->bAutoCaption) { UINT_PTR id = lpToolInfo->uId; TOOLTIPTEXT tt = {0}; tt.hdr.hwndFrom = m_hWnd; tt.hdr.idFrom = lpToolInfo->uId; tt.hdr.code = TTN_NEEDTEXT; tt.uFlags = lpToolInfo->uFlags; tt.hinst = NULL; tt.szText[0] = _T('\0'); tt.lpszText = tt.szText; ::SendMessage(lpToolInfo->hwnd, WM_NOTIFY, id, (LPARAM)&tt); if (IS_INTRESOURCE(tt.lpszText)) { XTPResourceManager()->LoadLocaleString(tt.hinst, (UINT)(UINT_PTR)tt.lpszText, lpToolInfo->strCaption); } else { lpToolInfo->strCaption = tt.lpszText; } if ((m_pContext->GetControlStyle() & TTS_NOPREFIX) == 0) { CXTPDrawHelpers::StripMnemonics(lpToolInfo->strCaption); } lpToolInfo->bAutoCaption = FALSE; } return lpToolInfo->strCaption; } int CXTPToolTipContextToolTip::GetMaxTipWidth() const { const int nWidth = m_pContext->GetMaxTipWidth(); if (nWidth == -1) { return ::GetSystemMetrics(SM_CXSCREEN); } return nWidth; } CSize CXTPToolTipContextToolTip::GetToolSize(TOOLITEM* lpToolInfo) { CClientDC dc(this); CFont* pOldFont = dc.SelectObject(&m_pContext->m_fnt); CString str = GetToolText(lpToolInfo); if (str.IsEmpty()) { dc.SelectObject(pOldFont); return CSize(0); } int nMaxTipWidth = GetMaxTipWidth(); CRect rcMargin = m_pContext->GetMargin(); CSize szMargin(3 + rcMargin.left + rcMargin.right + 3, 3 + rcMargin.top + rcMargin.bottom + 3); DWORD dwFlags = DT_NOPREFIX | DT_EXPANDTABS; BOOL bDrawImage = m_pIcon != NULL; BOOL bDrawTitle = !m_strTitle.IsEmpty(); BOOL bDrawImageTop = TRUE; CSize szImage(0, 0); CSize szTitle(0, 0); if (bDrawTitle) { CXTPFontDC fntTitle(&dc, &m_pContext->m_fntTitle); CRect rcTitle(0, 0, 0, 0); dc.DrawText(m_strTitle, rcTitle, dwFlags | DT_CALCRECT | DT_SINGLELINE); szTitle = CSize(rcTitle.Width() + 4, rcTitle.Height() + 10 + 10); } if (bDrawImage) { CSize szIcon(m_pIcon->GetWidth(), m_pIcon->GetHeight()); bDrawImageTop = (szIcon.cy <= 16); if (bDrawImageTop) { if (!bDrawTitle) { szImage.cx = szIcon.cx + 3; } else { szTitle.cx += szIcon.cx + 1; } } else { szImage.cx = szIcon.cx + 5; } szImage.cy = szIcon.cy; } CRect rcText(0, 0, nMaxTipWidth - szMargin.cx, 0); if (bDrawTitle) rcText.right = max(szTitle.cx, nMaxTipWidth - szMargin.cx) - (10 + 15); dc.DrawText(str, rcText, dwFlags | DT_CALCRECT | DT_WORDBREAK); dc.SelectObject(pOldFont); CSize szText = rcText.Size(); CSize sz(0, 0); sz.cy = max(szImage.cy, szText.cy); sz.cx = szImage.cx + szText.cx; if (bDrawTitle) { sz.cx = max(sz.cx + 10 + 15, szTitle.cx); sz.cy += szTitle.cy; } sz += szMargin; return sz; } HHOOK CXTPToolTipContextToolTip::m_hHookMouse = 0; CXTPToolTipContextToolTip* CXTPToolTipContextToolTip::m_pWndMonitor = 0; LRESULT CALLBACK CXTPToolTipContextToolTip::MouseProc(int nCode, WPARAM wParam, LPARAM lParam) { if (nCode != HC_ACTION || !m_pWndMonitor || m_pWndMonitor->m_toolVisible.IsEmpty()) return CallNextHookEx(m_hHookMouse, nCode, wParam, lParam); POINT pt = ((PMOUSEHOOKSTRUCT)lParam)->pt; HWND hWnd = (HWND)m_pWndMonitor->OnWindowFromPoint(0, (LPARAM)&pt); if (hWnd != m_pWndMonitor->m_toolVisible.hwnd) { MSG msg; msg.pt = pt; msg.message = WM_MOUSEMOVE; m_pWndMonitor->RelayEvent(&msg); } return CallNextHookEx(m_hHookMouse, nCode, wParam, lParam); } void CXTPToolTipContextToolTip::HookMouseMove(BOOL bSetupHook) { if (bSetupHook && m_hHookMouse == 0 && (m_pWndMonitor == NULL)) { m_hHookMouse = SetWindowsHookEx(WH_MOUSE, MouseProc, 0, GetCurrentThreadId ()); m_pWndMonitor = this; } else if (!bSetupHook && m_hHookMouse && (m_pWndMonitor == this)) { UnhookWindowsHookEx(m_hHookMouse); m_hHookMouse = 0; m_pWndMonitor = NULL; } } void CXTPToolTipContextToolTip::EnsureVisible(CRect& rcToolTip) { CRect rcWork = XTPMultiMonitor()->GetWorkArea(); int nGap = 4; if (rcWork.right - nGap < rcToolTip.right) { rcToolTip.OffsetRect(- rcToolTip.right + rcWork.right - nGap, 0); } if (rcWork.left > rcToolTip.left) { rcToolTip.OffsetRect(rcWork.left - rcToolTip.left, 0); } if (rcWork.bottom - nGap < rcToolTip.bottom) { CPoint pt; GetCursorPos(&pt); rcToolTip.OffsetRect(0, pt.y - rcToolTip.bottom - 3); } } int CXTPToolTipContext::GetCursorHeight() { HCURSOR hCursor = GetCursor(); ICONINFO iconInfo; if (!GetIconInfo(hCursor, &iconInfo)) return 21; BITMAP bm; if (!GetObject(iconInfo.hbmMask, sizeof(BITMAP), &bm)) return 21; WORD curBits[16 * 8]; memset(&curBits, -1, sizeof(curBits)); if (!GetBitmapBits(iconInfo.hbmMask, sizeof(curBits), curBits)) return 21; int nBitSize = sizeof(WORD) * 8; int nCount = MulDiv(bm.bmWidth, bm.bmHeight, nBitSize); int nXor = 0; if (!iconInfo.hbmColor) { nXor = nCount - 1; nCount = nCount / 2; } if (nCount >= sizeof(curBits)/sizeof(WORD)) nCount = sizeof(curBits)/sizeof(WORD) - 1; if (nXor >= sizeof(curBits)/sizeof(WORD)) nXor = 0; int i = nCount - 1; for (; i >= 0; i--) { if (curBits[i] != 0xFFFF || (nXor && (curBits[nXor--] != 0))) break; } if (iconInfo.hbmColor) DeleteObject(iconInfo.hbmColor); if (iconInfo.hbmMask) DeleteObject(iconInfo.hbmMask); return MulDiv(i + 1, nBitSize, (int)bm.bmWidth) - (int)iconInfo.yHotspot; } void CXTPToolTipContextToolTip::SetRoundRectRegion(CWnd* pWnd) { CXTPWindowRect rc(pWnd); rc.OffsetRect(-rc.TopLeft()); int cx = rc.Width(), cy = rc.Height(); RECT rgn[] = { {1, 0, cx - 1, 1}, {0, 1, cx, cy - 1}, {1, cy - 1, cx - 1, cy} }; int nSizeData = sizeof(RGNDATAHEADER) + sizeof(rgn); RGNDATA* pRgnData = (RGNDATA*)malloc(nSizeData); if (!pRgnData) return; MEMCPY_S(&pRgnData->Buffer, (void*)&rgn, sizeof(rgn)); pRgnData->rdh.dwSize = sizeof(RGNDATAHEADER); pRgnData->rdh.iType = RDH_RECTANGLES; pRgnData->rdh.nCount = sizeof(rgn) / sizeof(RECT); pRgnData->rdh.nRgnSize = 0; pRgnData->rdh.rcBound = CRect(0, 0, cx, cy); CRgn rgnResult; VERIFY(rgnResult.CreateFromData(NULL, nSizeData, pRgnData)); free(pRgnData); pWnd->SetWindowRgn((HRGN)rgnResult.Detach(), FALSE); m_bWindowRegion = TRUE; } void CXTPToolTipContextToolTip::SetVisibleTool(TOOLITEM* pVisibleTool) { if (!m_toolVisible.IsEqual(pVisibleTool)) { CSize sz(0); if (pVisibleTool) { sz = GetToolSize(pVisibleTool); if (sz == CSize(0)) pVisibleTool = 0; } if (m_hWnd) { SetWindowPos(0, 0, 0, 0, 0, SWP_NOMOVE | SWP_NOSIZE | SWP_NOZORDER | SWP_HIDEWINDOW | SWP_NOACTIVATE | SWP_NOOWNERZORDER); if (m_bWindowRegion) { SetWindowRgn(NULL, FALSE); m_bWindowRegion = FALSE; } } if (pVisibleTool) { CRect rcToolTip(0, 0, 0, 0); if (!pVisibleTool->rectExclude.IsRectEmpty()) { CWnd* pWnd = CWnd::FromHandle(pVisibleTool->hwnd); //CRect rcExclude = pVisibleTool->rectExclude; //rcToolTip = pVisibleTool->rect; rcToolTip.SetRect(pVisibleTool->rect.left, pVisibleTool->rectExclude.bottom, pVisibleTool->rect.left + sz.cx, pVisibleTool->rectExclude.bottom + sz.cy); pWnd->ClientToScreen(rcToolTip); } else { CPoint pt; GetCursorPos(&pt); int nCursorHeight = CXTPToolTipContext::GetCursorHeight(); rcToolTip.SetRect(pt.x, pt.y + nCursorHeight, pt.x + sz.cx, pt.y + nCursorHeight + sz.cy); if (GetWindowLong(pVisibleTool->hwnd, GWL_EXSTYLE) & WS_EX_LAYOUTRTL) { rcToolTip.OffsetRect(-sz.cx, 0); } } EnsureVisible(rcToolTip); SetWindowPos(&CWnd::wndTop, rcToolTip.left, rcToolTip.top, rcToolTip.Width(), rcToolTip.Height(), SWP_NOACTIVATE | SWP_NOOWNERZORDER); UINT_PTR id = pVisibleTool->uId; NMHDR hdr = {0}; hdr.hwndFrom = m_hWnd; hdr.idFrom = pVisibleTool->uId; hdr.code = TTN_SHOW; ::SendMessage(pVisibleTool->hwnd, WM_NOTIFY, id, (LPARAM)&hdr); if (GetStyle() & XTP_TTS_OFFICE2007FRAME) { SetRoundRectRegion(this); } SetWindowPos(0, 0, 0, 0, 0, SWP_SHOWWINDOW | SWP_NOACTIVATE | SWP_NOOWNERZORDER | SWP_NOMOVE | SWP_NOSIZE | SWP_NOZORDER); Invalidate(FALSE); HookMouseMove(TRUE); m_toolDisabled.Reset(); if (m_nDelayAutoPop > 0) { if (m_nAutoPopTimer > 0) { KillTimer(m_nAutoPopTimer); m_nAutoPopTimer = 0; } m_nAutoPopTimer = SetTimer(3, m_nDelayAutoPop, NULL); } } else { HookMouseMove(FALSE); m_toolDelay.Reset(); if (m_nAutoPopTimer > 0) { if (m_hWnd) KillTimer(m_nAutoPopTimer); m_nAutoPopTimer = 0; } } m_toolVisible.Assign(pVisibleTool); m_dwLastTip = GetTickCount(); OnVisibleChanged(pVisibleTool != NULL); } } void CXTPToolTipContextToolTip::RelayEvent(LPMSG lpMsg) { if (!m_bActive) return; if (!((lpMsg->message >= WM_MOUSEFIRST && lpMsg->message <= WM_MOUSELAST) || (lpMsg->message >= WM_NCMOUSEMOVE && lpMsg->message <= WM_NCMBUTTONDBLCLK))) return; TOOLITEM* pVisibleTool = FindTool(); if (lpMsg->message == WM_LBUTTONDOWN) { if (pVisibleTool) { m_toolDisabled = *pVisibleTool; pVisibleTool = 0; } } if (pVisibleTool && (m_toolDisabled.IsEqual(pVisibleTool))) { pVisibleTool = 0; } if (m_nDelayTimer && !m_toolDelay.IsEqual(pVisibleTool)) { KillTimer(m_nDelayTimer); m_nDelayTimer = 0; m_toolDelay.Reset(); } if (pVisibleTool) { if (!m_toolVisible.IsEqual(pVisibleTool)) { if (GetTickCount() - m_dwLastTip < m_nDelayReshow) { SetVisibleTool(pVisibleTool); } else if (!m_toolDelay.IsEqual(pVisibleTool)) { m_toolDelay = *pVisibleTool; m_nDelayTimer = SetTimer(1, m_nDelayInitial, NULL); } } } else { SetVisibleTool(0); } } void CXTPToolTipContextToolTip::DrawEntry(CDC* pDC, TOOLITEM* lpToolInfo, CRect rc) { CString str = lpToolInfo->strCaption; rc.DeflateRect(m_pContext->GetMargin()); rc.DeflateRect(3, 3, 3, 3); DWORD dwFlags = DT_NOPREFIX | DT_EXPANDTABS; BOOL bLayoutRTL = lpToolInfo->hwnd && GetWindowLong(lpToolInfo->hwnd, GWL_EXSTYLE) & WS_EX_LAYOUTRTL; if (bLayoutRTL) { dwFlags |= DT_RTLREADING | DT_RIGHT; } CRect rcTitle(rc.left + 2, rc.top + 2, rc.right - 2, rc.bottom); BOOL bDrawImage = m_pIcon != NULL; BOOL bDrawTitle = !m_strTitle.IsEmpty(); BOOL bDrawImageTop = TRUE; CSize szImage(0, 0); if (bDrawImage) { szImage = CSize(m_pIcon->GetWidth(), m_pIcon->GetHeight()); bDrawImageTop = (szImage.cy <= 16); if (bDrawImageTop) { CPoint ptIcon = bLayoutRTL ? CPoint(rc.right - szImage.cx, rc.top) : rc.TopLeft(); m_pIcon->Draw(pDC, ptIcon); if (bLayoutRTL) { if (bDrawTitle) rcTitle.right -= szImage.cx + 1; else rc.right -= szImage.cx + 3; } else { if (bDrawTitle) rcTitle.left += szImage.cx + 1; else rc.left += szImage.cx + 3; } } } if (bDrawTitle) { CXTPFontDC fnt(pDC, &m_pContext->m_fntTitle); pDC->DrawText(m_strTitle, rcTitle, dwFlags | DT_SINGLELINE); rc.top += pDC->GetTextExtent(m_strTitle).cy; if (bLayoutRTL) { rc.DeflateRect(15, 12, 10, 0); } else { rc.DeflateRect(10, 12, 15, 0); } } if (bDrawImage && !bDrawImageTop) { CPoint ptIcon = bLayoutRTL ? CPoint(rc.right - szImage.cx, rc.top) : rc.TopLeft(); m_pIcon->Draw(pDC, ptIcon); if (bLayoutRTL) rc.right -= szImage.cx + 5; else rc.left += szImage.cx + 5; } pDC->DrawText(str, rc, dwFlags | DT_WORDBREAK); } void CXTPToolTipContextToolTip::DrawBackground(CDC* pDC, TOOLITEM* /*lpToolInfo*/, CRect rc) { m_pContext->DrawBackground(pDC, rc); } void CXTPToolTipContextToolTip::OnPaint() { CPaintDC dc(this); // device context for painting CXTPClientRect rc(this); DrawBackground(&dc, &m_toolVisible, rc); COLORREF clrTextColor = m_pContext->GetTipTextColor(); dc.SetBkMode(TRANSPARENT); dc.SetTextColor(clrTextColor); CXTPFontDC font(&dc, &m_pContext->m_fnt); DrawEntry(&dc, &m_toolVisible, rc); } void CXTPToolTipContext::DrawBackground(CDC* pDC, CRect rc) { if (m_dwStyle & XTP_TTS_OFFICE2007FRAME) { CXTPResourceImages* pImages = XTPResourceImages(); COLORREF clrLight = pImages->GetImageColor(_T("Window"), _T("TooltipLight")); COLORREF clrDark = pImages->GetImageColor(_T("Window"), _T("TooltipDark")); if (clrLight == COLORREF_NULL) clrLight = RGB(255, 255, 255); if (clrDark == COLORREF_NULL) clrDark = RGB(201, 217, 239); XTPDrawHelpers()->GradientFill(pDC, rc, clrLight, clrDark, FALSE); CXTPResourceImage* pImage = pImages->LoadFile(_T("TOOLTIPFRAME")); if (pImage) { pImage->DrawImage(pDC, rc, pImage->GetSource(0, 1), CRect(3, 3, 3, 3), 0xFF00FF); } else { COLORREF clrBorder = pImages->GetImageColor(_T("Window"), _T("TooltipBorder")); if (clrBorder == COLORREF_NULL) clrBorder = RGB(118, 118, 118); pDC->Draw3dRect(rc, clrBorder, clrBorder); } } else { pDC->FillSolidRect(rc, GetTipBkColor()); if (m_dwStyle & XTP_TTS_OFFICEFRAME) pDC->Draw3dRect(rc, GetSysColor(COLOR_3DFACE), 0); else pDC->Draw3dRect(rc, 0, 0); } pDC->SetTextColor(GetTipTextColor()); } BOOL CXTPToolTipContextToolTip::OnEraseBkgnd(CDC* /*pDC*/) { return TRUE; } LRESULT CXTPToolTipContextToolTip::OnNcHitTest(CPoint /*point*/) { return (LRESULT)HTTRANSPARENT; } int CXTPToolTipContextToolTip::OnMouseActivate(CWnd* /*pDesktopWnd*/, UINT /*nHitTest*/, UINT /*message*/) { return MA_NOACTIVATE; } void CXTPToolTipContextToolTip::OnMouseMove(UINT /*nFlags*/, CPoint /*point*/) { SetVisibleTool(NULL); } void CXTPToolTipContextToolTip::OnTimer(UINT_PTR nIDEvent) { if (nIDEvent == m_nDelayTimer) { if (!m_toolDelay.IsEmpty()) { TOOLITEM* pVisibleTool = FindTool(); if (m_toolDelay.IsEqual(pVisibleTool)) { SetVisibleTool(pVisibleTool); } } KillTimer(m_nDelayTimer); m_nDelayTimer = 0; m_toolDelay.Reset(); } if (nIDEvent == m_nAutoPopTimer) { KillTimer(m_nAutoPopTimer); m_nAutoPopTimer = 0; Activate(FALSE); } CWnd::OnTimer(nIDEvent); } ////////////////////////////////////////////////////////////////////////// // CXTPToolTipContext::CStandardToolTip class CXTPToolTipContext::CStandardToolTip : public CToolTipCtrl { DECLARE_MESSAGE_MAP() LRESULT OnWindowFromPoint(WPARAM, LPARAM); }; typedef CXTPToolTipContext::CStandardToolTip CXTPToolTipContextStandardTip; BEGIN_MESSAGE_MAP(CXTPToolTipContextStandardTip, CToolTipCtrl) ON_MESSAGE(TTM_WINDOWFROMPOINT, OnWindowFromPoint) END_MESSAGE_MAP() LRESULT CXTPToolTipContext::CStandardToolTip::OnWindowFromPoint(WPARAM, LPARAM) { HWND hWnd = (HWND)Default(); if ((hWnd != NULL) && (GetWindowLong(hWnd, GWL_STYLE) & WS_CHILD) && (::SendMessage(hWnd, XTP_TTM_WINDOWFROMPOINT, 0, 0) == 1)) { return (LRESULT)::GetParent(hWnd); } return (LRESULT)hWnd; } ////////////////////////////////////////////////////////////////////////// // CXTPToolTipContext::CLunaToolTip class CXTPToolTipContext::CLunaToolTip : public CXTPToolTipContextToolTip { public: CLunaToolTip(CXTPToolTipContext* pContext) : CXTPToolTipContextToolTip(pContext) { } void DrawBackground(CDC* pDC, TOOLITEM* /*lpToolInfo*/, CRect rc) { switch (XTPColorManager()->GetCurrentSystemTheme()) { case xtpSystemThemeBlue: case xtpSystemThemeRoyale: case xtpSystemThemeAero: XTPDrawHelpers()->GradientFill(pDC, rc, RGB(255, 212, 151), RGB(255, 242, 200), FALSE); pDC->Draw3dRect(rc, RGB(0, 0, 128), RGB(0, 0, 128)); break; case xtpSystemThemeOlive: XTPDrawHelpers()->GradientFill(pDC, rc, RGB(255, 212, 151), RGB(255, 242, 200), FALSE); pDC->Draw3dRect(rc, RGB(63, 93, 56), RGB(63, 93, 56)); break; case xtpSystemThemeSilver: XTPDrawHelpers()->GradientFill(pDC, rc, RGB(255, 212, 151), RGB(255, 242, 200), FALSE); pDC->Draw3dRect(rc, RGB(75, 75, 111), RGB(75, 75, 111)); break; default: XTPDrawHelpers()->GradientFill(pDC, rc, m_pContext->GetTipBkColor(), RGB(255, 255, 255), FALSE); pDC->Draw3dRect(rc, 0, 0); } } }; ////////////////////////////////////////////////////////////////////////// // CXTPToolTipContext::CRichEditToolTip class CXTPToolTipContext::CRichEditToolTip : public CXTPToolTipContextToolTip { public: CRichEditToolTip(CXTPToolTipContext* pContext) : CXTPToolTipContextToolTip(pContext) { } protected: virtual void DrawEntry(CDC* pDC, TOOLITEM* lpToolInfo, CRect rc); virtual CSize GetToolSize(TOOLITEM* lpToolInfo); protected: CXTPRichRender m_render; }; CSize CXTPToolTipContext::CRichEditToolTip::GetToolSize(TOOLITEM* lpToolInfo) { if (!m_render.GetTextService()) return CSize(0); CString sText = GetToolText(lpToolInfo); if (sText.IsEmpty()) return CSize(0); CClientDC dc(this); CXTPFontDC font(&dc, &m_pContext->m_fnt); CHARFORMATW cf; ZeroMemory(&cf, sizeof(CHARFORMATW)); cf.cbSize = sizeof(CHARFORMATW); cf.dwMask = CFM_BOLD | CFM_COLOR | CFM_ITALIC | CFM_PROTECTED | CFM_STRIKEOUT | CFM_UNDERLINE; cf.crTextColor = m_pContext->GetTipTextColor(); LOGFONT lf; if (m_pContext->GetFont()->GetLogFont(&lf)) { cf.yHeight = -MulDiv(lf.lfHeight, 1440, ::GetDeviceCaps(dc, LOGPIXELSY)); WCSNCPY_S(cf.szFaceName, LF_FACESIZE, XTP_CT2CW(lf.lfFaceName), LF_FACESIZE); cf.dwMask |= CFM_FACE | CFM_SIZE; } m_render.SetText(NULL); m_render.SetDefaultCharFormat(&cf); m_render.SetText(sText); CRect rcMargin = m_pContext->GetMargin(); CSize szMargin(3 + rcMargin.left + rcMargin.right + 3, 3 + rcMargin.top + rcMargin.bottom + 3); CSize size = m_render.GetTextExtent(&dc, GetMaxTipWidth() - szMargin.cx); size += szMargin; return size; } void CXTPToolTipContext::CRichEditToolTip::DrawEntry(CDC* pDC, TOOLITEM* /*lpToolInfo*/, CRect rc) { rc.DeflateRect(m_pContext->GetMargin()); rc.DeflateRect(3, 3, 3, 3); m_render.DrawText(pDC, rc); } class CXTPToolTipContext::CMarkupToolTip : public CXTPToolTipContextToolTip { public: CMarkupToolTip(CXTPToolTipContext* pContext) : CXTPToolTipContextToolTip(pContext) { m_pUIElement = NULL; m_pMarkupContext = XTPMarkupCreateContext(); } ~CMarkupToolTip() { XTPMarkupReleaseElement(m_pUIElement); XTPMarkupReleaseContext(m_pMarkupContext); } protected: virtual void DrawEntry(CDC* pDC, TOOLITEM* lpToolInfo, CRect rc); virtual CSize GetToolSize(TOOLITEM* lpToolInfo); protected: CXTPMarkupUIElement* m_pUIElement; CXTPMarkupContext* m_pMarkupContext; }; CSize CXTPToolTipContext::CMarkupToolTip::GetToolSize(TOOLITEM* lpToolInfo) { XTPMarkupReleaseElement(m_pUIElement); CString sText = GetToolText(lpToolInfo); if (sText.IsEmpty()) return CSize(0); XTPMarkupSetDefaultFont(m_pMarkupContext, (HFONT)m_pContext->GetFont()->GetSafeHandle(), m_pContext->GetTipTextColor()); m_pUIElement = XTPMarkupParseText(m_pMarkupContext, sText); if (!m_pUIElement) { return CXTPToolTipContextToolTip::GetToolSize(lpToolInfo); } CRect rcMargin = m_pContext->GetMargin(); CSize szMargin(3 + rcMargin.left + rcMargin.right + 3, 3 + rcMargin.top + rcMargin.bottom + 3); CSize size = XTPMarkupMeasureElement(m_pUIElement, GetMaxTipWidth() - szMargin.cx); size += szMargin; return size; } void CXTPToolTipContext::CMarkupToolTip::DrawEntry(CDC* pDC, TOOLITEM* lpToolInfo, CRect rc) { if (m_pUIElement) { CRect rcMargin = m_pContext->GetMargin(); CRect rcText(rc); rcText.DeflateRect(3 + rcMargin.left, 3 + rcMargin.top, rcMargin.right + 3, rcMargin.bottom + 3); XTPMarkupRenderElement(m_pUIElement, pDC->GetSafeHdc(), rcText); } else { CXTPToolTipContextToolTip::DrawEntry(pDC, lpToolInfo, rc); } } #ifndef _XTP_EXCLUDE_HTML ////////////////////////////////////////////////////////////////////////// // CXTPToolTipContext::CHTMLToolTip class CXTPToolTipContext::CHTMLToolTip : public CXTPToolTipContextToolTip { public: CHTMLToolTip(CXTPToolTipContext* pContext); ~CHTMLToolTip(); protected: virtual void DrawEntry(CDC* pDC, TOOLITEM* lpToolInfo, CRect rc); virtual CSize GetToolSize(TOOLITEM* lpToolInfo); virtual void OnVisibleChanged(BOOL bVisble); protected: DECLARE_INTERFACE_MAP() BEGIN_INTERFACE_PART(OleClientSite, IOleClientSite) STDMETHOD(SaveObject)( void) { return E_NOTIMPL;} STDMETHOD (GetMoniker)( /* [in] */ DWORD /*dwAssign*/, /* [in] */ DWORD /*dwWhichMoniker*/, /* [out] */ IMoniker ** /*ppmk*/) { return E_NOTIMPL;} STDMETHOD(GetContainer)( /* [out] */ IOleContainer ** /*ppContainer*/) { return E_NOTIMPL;} STDMETHOD(ShowObject)( void) { return E_NOTIMPL;} STDMETHOD(OnShowWindow)( /* [in] */ BOOL /*fShow*/) { return E_NOTIMPL;} STDMETHOD(RequestNewObjectLayout)( void) { return E_NOTIMPL;} END_INTERFACE_PART(OleClientSite) BEGIN_INTERFACE_PART(DocHostUIHandler, IDocHostUIHandler) STDMETHOD(ShowContextMenu)(/* [in] */ DWORD dwID, /* [in] */ POINT __RPC_FAR *ppt, /* [in] */ IUnknown __RPC_FAR *pcmdtReserved, /* [in] */ IDispatch __RPC_FAR *pdispReserved); STDMETHOD(GetHostInfo)( /* [out][in] */ DOCHOSTUIINFO __RPC_FAR *pInfo); STDMETHOD(ShowUI)( /* [in] */ DWORD dwID, /* [in] */ IOleInPlaceActiveObject __RPC_FAR *pActiveObject, /* [in] */ IOleCommandTarget __RPC_FAR *pCommandTarget, /* [in] */ IOleInPlaceFrame __RPC_FAR *pFrame, /* [in] */ IOleInPlaceUIWindow __RPC_FAR *pDoc); STDMETHOD(HideUI)(void); STDMETHOD(UpdateUI)(void); STDMETHOD(EnableModeless)(/* [in] */ BOOL fEnable); STDMETHOD(OnDocWindowActivate)(/* [in] */ BOOL fEnable); STDMETHOD(OnFrameWindowActivate)(/* [in] */ BOOL fEnable); STDMETHOD(ResizeBorder)( /* [in] */ LPCRECT prcBorder, /* [in] */ IOleInPlaceUIWindow __RPC_FAR *pUIWindow, /* [in] */ BOOL fRameWindow); STDMETHOD(TranslateAccelerator)( /* [in] */ LPMSG lpMsg, /* [in] */ const GUID __RPC_FAR *pguidCmdGroup, /* [in] */ DWORD nCmdID); STDMETHOD(GetOptionKeyPath)( /* [out] */ LPOLESTR __RPC_FAR *pchKey, /* [in] */ DWORD dw); STDMETHOD(GetDropTarget)( /* [in] */ IDropTarget __RPC_FAR *pDropTarget, /* [out] */ IDropTarget __RPC_FAR *__RPC_FAR *ppDropTarget); STDMETHOD(GetExternal)( /* [out] */ IDispatch __RPC_FAR *__RPC_FAR *ppDispatch); STDMETHOD(TranslateUrl)( /* [in] */ DWORD dwTranslate, /* [in] */ OLECHAR __RPC_FAR *pchURLIn, /* [out] */ OLECHAR __RPC_FAR *__RPC_FAR *ppchURLOut); STDMETHOD(FilterDataObject)( /* [in] */ IDataObject __RPC_FAR *pDO, /* [out] */ IDataObject __RPC_FAR *__RPC_FAR *ppDORet); END_INTERFACE_PART(DocHostUIHandler) protected: CBitmap m_bmpScreen; CWnd m_wndBrowser; IWebBrowser2* m_pBrowserApp; }; ////////////////////////////////////////////////////////////////////////// // CWebBrowserSite BEGIN_INTERFACE_MAP(CXTPToolTipContext::CHTMLToolTip, CWnd) INTERFACE_PART(CXTPToolTipContext::CHTMLToolTip, IID_IOleClientSite, OleClientSite) INTERFACE_PART(CXTPToolTipContext::CHTMLToolTip, IID_IDocHostUIHandler, DocHostUIHandler) END_INTERFACE_MAP() #define IMPLEMENT_INTERFACE_PART(theClass, localClass)\ STDMETHODIMP_(ULONG) theClass::X##localClass::AddRef()\ {\ METHOD_PROLOGUE(theClass, localClass)\ return pThis->ExternalAddRef();\ }\ STDMETHODIMP_(ULONG) theClass::X##localClass::Release()\ {\ METHOD_PROLOGUE(theClass, localClass)\ return pThis->ExternalRelease();\ }\ STDMETHODIMP theClass::X##localClass::QueryInterface(REFIID riid, void **ppvObj)\ {\ METHOD_PROLOGUE(theClass, localClass)\ HRESULT hr = (HRESULT)pThis->ExternalQueryInterface(&riid, ppvObj);\ return hr;\ } IMPLEMENT_INTERFACE_PART(CXTPToolTipContext::CHTMLToolTip, OleClientSite) IMPLEMENT_INTERFACE_PART(CXTPToolTipContext::CHTMLToolTip, DocHostUIHandler) STDMETHODIMP CXTPToolTipContext::CHTMLToolTip::XDocHostUIHandler::GetHostInfo( DOCHOSTUIINFO* pInfo ) { pInfo->dwFlags = 0x40000 | DOCHOSTUIFLAG_NO3DBORDER; pInfo->dwFlags |= DOCHOSTUIFLAG_DIALOG; pInfo->dwFlags |= DOCHOSTUIFLAG_SCROLL_NO; pInfo->dwDoubleClick = DOCHOSTUIDBLCLK_DEFAULT; return S_OK; } STDMETHODIMP CXTPToolTipContext::CHTMLToolTip::XDocHostUIHandler::ShowUI( DWORD /*dwID*/, IOleInPlaceActiveObject * /*pActiveObject*/, IOleCommandTarget * /*pCommandTarget*/, IOleInPlaceFrame * /*pFrame*/, IOleInPlaceUIWindow * /*pDoc*/) { return S_OK; } STDMETHODIMP CXTPToolTipContext::CHTMLToolTip::XDocHostUIHandler::HideUI(void) { return S_OK; } STDMETHODIMP CXTPToolTipContext::CHTMLToolTip::XDocHostUIHandler::UpdateUI(void) { return S_OK; } STDMETHODIMP CXTPToolTipContext::CHTMLToolTip::XDocHostUIHandler::EnableModeless(BOOL /*fEnable*/) { return E_NOTIMPL; } STDMETHODIMP CXTPToolTipContext::CHTMLToolTip::XDocHostUIHandler::OnDocWindowActivate(BOOL /*fActivate*/) { return E_NOTIMPL; } STDMETHODIMP CXTPToolTipContext::CHTMLToolTip::XDocHostUIHandler::OnFrameWindowActivate(BOOL /*fActivate*/) { return E_NOTIMPL; } STDMETHODIMP CXTPToolTipContext::CHTMLToolTip::XDocHostUIHandler::ResizeBorder( LPCRECT /*prcBorder*/, IOleInPlaceUIWindow* /*pUIWindow*/, BOOL /*fRameWindow*/) { return E_NOTIMPL; } STDMETHODIMP CXTPToolTipContext::CHTMLToolTip::XDocHostUIHandler::ShowContextMenu( DWORD /*dwID*/, POINT* /*pptPosition*/, IUnknown* /*pCommandTarget*/, IDispatch* /*pDispatchObjectHit*/) { return S_OK; } STDMETHODIMP CXTPToolTipContext::CHTMLToolTip::XDocHostUIHandler::TranslateAccelerator(LPMSG /*lpMsg*/, /* [in] */ const GUID __RPC_FAR* /*pguidCmdGroup*/, /* [in] */ DWORD /*nCmdID*/) { return S_FALSE; } STDMETHODIMP CXTPToolTipContext::CHTMLToolTip::XDocHostUIHandler::GetOptionKeyPath(BSTR* /*pbstrKey*/, DWORD) { return E_NOTIMPL; } STDMETHODIMP CXTPToolTipContext::CHTMLToolTip::XDocHostUIHandler::GetDropTarget( /* [in] */ IDropTarget __RPC_FAR* /*pDropTarget*/, /* [out] */ IDropTarget __RPC_FAR *__RPC_FAR* /*ppDropTarget*/) { return E_NOTIMPL; } STDMETHODIMP CXTPToolTipContext::CHTMLToolTip::XDocHostUIHandler::GetExternal( /* [out] */ IDispatch __RPC_FAR *__RPC_FAR* /*ppDispatch*/) { return E_NOTIMPL; } STDMETHODIMP CXTPToolTipContext::CHTMLToolTip::XDocHostUIHandler::TranslateUrl( /* [in] */ DWORD /*dwTranslate*/, /* [in] */ OLECHAR __RPC_FAR* /*pchURLIn*/, /* [out] */ OLECHAR __RPC_FAR *__RPC_FAR* /*ppchURLOut*/) { return E_NOTIMPL; } STDMETHODIMP CXTPToolTipContext::CHTMLToolTip::XDocHostUIHandler::FilterDataObject( /* [in] */ IDataObject __RPC_FAR* /*pDO*/, /* [out] */ IDataObject __RPC_FAR *__RPC_FAR* /*ppDORet*/) { return E_NOTIMPL; } CXTPToolTipContext::CHTMLToolTip::CHTMLToolTip(CXTPToolTipContext* pContext) : CXTPToolTipContextToolTip(pContext) { AfxEnableControlContainer(); m_pBrowserApp = 0; } CXTPToolTipContext::CHTMLToolTip::~CHTMLToolTip() { SAFE_RELEASE(m_pBrowserApp); } CSize CXTPToolTipContext::CHTMLToolTip::GetToolSize(TOOLITEM* lpToolInfo) { m_bmpScreen.DeleteObject(); if (m_wndBrowser.GetSafeHwnd() == 0) { // create the control window // AFX_IDW_PANE_FIRST is a safe but arbitrary ID if (!m_wndBrowser.CreateControl(CLSID_WebBrowser, 0, WS_VISIBLE | WS_CHILD, CRect(0, 0, 200, 200), this, AFX_IDW_PANE_FIRST)) { return 0; } LPUNKNOWN lpUnk = m_wndBrowser.GetControlUnknown(); HRESULT hr = lpUnk->QueryInterface(IID_IWebBrowser2, (void**) &m_pBrowserApp); if (!SUCCEEDED(hr) || !m_pBrowserApp) { m_pBrowserApp = NULL; m_wndBrowser.DestroyWindow(); return 0; } IOleObject* spOleObj = NULL; m_pBrowserApp->QueryInterface(IID_IOleObject, (void**)&spOleObj); if (spOleObj) { spOleObj->SetClientSite((IOleClientSite*)GetInterface(&IID_IOleClientSite)); spOleObj->Release(); } CString strFaceName = _T("Arial"); int nFontSize = 11; LOGFONT lf; if (m_pContext->GetFont()->GetLogFont(&lf)) { strFaceName = lf.lfFaceName; nFontSize = lf.lfHeight < 0 ? -lf.lfHeight : lf.lfHeight; } CString strBackColor; COLORREF clrBack = m_pContext->GetTipBkColor(); strBackColor.Format(_T("#%0.2x%0.2x%0.2x"), GetRValue(clrBack), GetGValue(clrBack), GetBValue(clrBack)); CString strBody; strBody.Format( _T("about:") _T(""), (LPCTSTR)strFaceName, nFontSize, (LPCTSTR)strFaceName, nFontSize, (LPCTSTR)strBackColor); COleVariant varEmpty; BSTR bstrBody = strBody.AllocSysString(); m_pBrowserApp->Navigate(bstrBody, (VARIANT*)&varEmpty, (VARIANT*)&varEmpty, (VARIANT*)&varEmpty, (VARIANT*)&varEmpty); SysFreeString(bstrBody); READYSTATE rs; do { AfxGetApp()->PumpMessage(); m_pBrowserApp->get_ReadyState (&rs); } while (rs != READYSTATE_COMPLETE); } CString strText = GetToolText(lpToolInfo); if (strText.IsEmpty()) return CSize(0); IDispatch* lpDocument = NULL; m_pBrowserApp->get_Document(&lpDocument); if (lpDocument == 0) return 0; // Verify that what we get is a pointer to a IHTMLDocument2 // interface. To be sure, let's query for // the IHTMLDocument2 interface (through smart pointers) IHTMLDocument2* lpHTML = NULL; lpDocument->QueryInterface(IID_IHTMLDocument2, (void**)&lpHTML); if (lpHTML == 0) { lpDocument->Release(); return 0; } // The previous step is sufficient to keep Explorer aside // without an explicit check against the loader module // Extract the source code of the document IHTMLElement* lpBody = NULL; // Get the BODY object HRESULT hr = lpHTML->get_body(&lpBody); if (FAILED(hr) || (lpBody == 0)) { lpHTML->Release(); lpDocument->Release(); return 0; } BSTR bstrText = strText.AllocSysString(); lpBody->put_innerHTML(bstrText); SysFreeString(bstrText); m_wndBrowser.MoveWindow(0, 0, 650, 200); IHTMLTextContainer* lpHTMLContainer = NULL; lpBody->QueryInterface(IID_IHTMLTextContainer, (void**)&lpHTMLContainer); if (lpHTMLContainer == 0) { lpBody->Release(); lpHTML->Release(); lpDocument->Release(); return 0; } long nScrollHeight, nScrollWidth; lpHTMLContainer->get_scrollHeight(&nScrollHeight); int nBestWidth = m_pContext->GetMaxTipWidth(); int nBestHeight = nScrollHeight; int cxFirst = 0; int cxLast = nBestWidth * 2; do { // Taking a guess int cx = (cxFirst + cxLast) / 2; m_wndBrowser.MoveWindow(0, 0, cx, nScrollHeight); lpHTMLContainer->get_scrollHeight(&nScrollHeight); lpHTMLContainer->get_scrollWidth(&nScrollWidth); if (nScrollWidth > cx && nScrollHeight <= nBestHeight) { nBestWidth = nScrollWidth; break; } if (nScrollHeight > nBestHeight) { // If the control required a larger height, then // it's too narrow. cxFirst = cx + 1; } else { // If the control didn't required a larger height, // then it's too wide. cxLast = cx - 1; nBestWidth = cx; } } while (cxFirst <= cxLast); m_wndBrowser.MoveWindow(0, 0, nBestWidth, nBestHeight); CSize sz(nBestWidth, nBestHeight); CRect rcMargin = m_pContext->GetMargin(); #if 0 if (sz.cx > 0 && sz.cy > 0) { CWindowDC dcPaint(this); CDC dc; dc.CreateCompatibleDC(&dcPaint); m_bmpScreen.CreateCompatibleBitmap(&dcPaint, sz.cx, sz.cy); CBitmap* pOldBitmap = dc.SelectObject(&m_bmpScreen); dc.FillSolidRect(0, 0, sz.cx, sz.cy, m_pContext->GetTipBkColor()); m_wndBrowser.SendMessage(WM_PRINT, (WPARAM)dc.GetSafeHdc(), PRF_CLIENT | PRF_CHILDREN); dc.SelectObject(pOldBitmap); } m_wndBrowser.MoveWindow(0, 0, 0, 0); #else m_wndBrowser.MoveWindow(3 + rcMargin.left, 3 + rcMargin.top, nBestWidth, nBestHeight); #endif CSize szMargin(3 + rcMargin.left + rcMargin.right + 3, 3 + rcMargin.top + rcMargin.bottom + 3); sz += szMargin; lpHTMLContainer->Release(); lpBody->Release(); lpHTML->Release(); lpDocument->Release(); return sz; } void CXTPToolTipContext::CHTMLToolTip::DrawEntry(CDC* pDC, TOOLITEM* /*lpToolInfo*/, CRect rc) { rc.DeflateRect(m_pContext->GetMargin()); rc.DeflateRect(3, 3, 3, 3); if (m_bmpScreen.GetSafeHandle()) { pDC->DrawState(rc.TopLeft(), CSize(0, 0), &m_bmpScreen, DSS_NORMAL, 0); } } void CXTPToolTipContext::CHTMLToolTip::OnVisibleChanged(BOOL bVisble) { if (!bVisble) { m_bmpScreen.DeleteObject(); } } #endif // _XTP_EXCLUDE_HTML ////////////////////////////////////////////////////////////////////// // Construction/Destruction ////////////////////////////////////////////////////////////////////// CXTPToolTipContext::CXTPToolTipContext() { m_pToolTip = 0; m_bShowTitleAndDescription = FALSE; m_bShowImage = FALSE; m_nImageSize = ICON_BIG; m_nImageBase = 0; m_toolStyle = xtpToolTipStandard; m_nMaxTipWidth = ::GetSystemMetrics(SM_CXSCREEN) / 2; ZeroMemory(&m_lastInfo, sizeof(m_lastInfo)); m_dwComCtlVersion = XTPSystemVersion()->GetComCtlVersion(); m_clrTipTextColor = m_clrTipBkColor = COLORREF_NULL; m_nIconTitle = TTI_INFO; m_dwStyle = TTS_NOPREFIX; m_rcMargin.SetRect(0, 0, 0, 0); m_nDelayAutoPop = m_nDelayInitial = m_nDelayReshow = -1; NONCLIENTMETRICS ncm; ::ZeroMemory(&ncm, sizeof(NONCLIENTMETRICS)); ncm.cbSize = sizeof(NONCLIENTMETRICS); VERIFY(::SystemParametersInfo(SPI_GETNONCLIENTMETRICS, sizeof(NONCLIENTMETRICS), &ncm, 0)); ncm.lfStatusFont.lfWeight = FW_NORMAL; ncm.lfStatusFont.lfCharSet = XTPResourceManager()->GetFontCharset(); m_fnt.CreateFontIndirect(&ncm.lfStatusFont); ncm.lfStatusFont.lfWeight = FW_BOLD; m_fntTitle.CreateFontIndirect(&ncm.lfStatusFont); m_bStripEllipsisFromToolTip = TRUE; } CXTPToolTipContext::~CXTPToolTipContext() { SAFE_DELETEWINDOW(m_pToolTip); if (m_pModuleContext == this) { m_pModuleContext = 0; } } BOOL CXTPToolTipContext::IsBalloonStyleSupported() const { return m_dwComCtlVersion >= VERSION_IE5; } void CXTPToolTipContext::ShowTitleAndDescription(BOOL bShowTitleAndDescription, int nIconTitle) { m_bShowTitleAndDescription = bShowTitleAndDescription; m_nIconTitle = nIconTitle; } void CXTPToolTipContext::ShowImage(BOOL bShowImage, int nImageBase, int nImageSize) { m_bShowImage = bShowImage; m_nImageBase = nImageBase; m_nImageSize = nImageSize; SAFE_DELETEWINDOW(m_pToolTip); } void CXTPToolTipContext::FillInToolInfo(TOOLINFO* pTI, HWND hWnd, CRect rect, INT_PTR nHit, const CString& strToolTip) { #if _MSC_VER < 1200 // MFC 5.0 if (pTI != NULL && pTI->cbSize >= sizeof(TOOLINFO)) #else if (pTI != NULL && pTI->cbSize >= sizeof(XTP_TOOLTIP_TOOLINFO)) #endif { pTI->hwnd = hWnd; pTI->rect = rect; pTI->uId = nHit; pTI->lpszText = (LPTSTR) ::calloc(strToolTip.GetLength() + 1, sizeof(TCHAR)); if (pTI->lpszText != NULL) STRCPY_S(pTI->lpszText, strToolTip.GetLength() + 1, (LPCTSTR)strToolTip); } } void CXTPToolTipContext::FillInToolInfo(TOOLINFO* pTI, HWND hWnd, CRect rect, INT_PTR nHit, const CString& strToolTip, const CString& strTitle, const CString& strDescription, CXTPImageManager* pImageManager) { FillInToolInfo(pTI, hWnd, rect, nHit, strToolTip); if (pTI != NULL && pTI->cbSize == sizeof(XTP_TOOLTIP_TOOLINFO_EX)) { XTP_TOOLTIP_CONTEXT* ptc = ((XTP_TOOLTIP_TOOLINFO_EX*)pTI)->pToolInfo; if (!ptc) return; if (!strDescription.IsEmpty() && !strTitle.IsEmpty()) { ptc->lpszDescription = (LPTSTR)::calloc(strDescription.GetLength() + 1, sizeof(TCHAR)); if (ptc->lpszDescription != NULL) STRCPY_S(ptc->lpszDescription, strDescription.GetLength() + 1, (LPCTSTR)strDescription); ptc->lpszTitle = (LPTSTR)::calloc(strTitle.GetLength() + 1, sizeof(TCHAR)); if (ptc->lpszTitle != NULL) STRCPY_S(ptc->lpszTitle, strTitle.GetLength() + 1, (LPCTSTR)strTitle); } ptc->pImageManager = pImageManager; } } void CXTPToolTipContext::SetMargin(LPCRECT lprc) { if (lprc) { m_rcMargin = *lprc; if (m_pToolTip) m_pToolTip->DestroyWindow(); } } void CXTPToolTipContext::SetStyle(XTPToolTipStyle toolStyle) { if (m_toolStyle != toolStyle && (toolStyle != xtpToolTipBalloon || IsBalloonStyleSupported())) { m_toolStyle = toolStyle; SAFE_DELETEWINDOW(m_pToolTip); ModifyToolTipStyle(XTP_TTS_OFFICEFRAME | XTP_TTS_NOSHADOW, m_toolStyle == xtpToolTipOffice ? XTP_TTS_OFFICEFRAME | XTP_TTS_NOSHADOW : 0); ModifyToolTipStyle(XTP_TTS_OFFICE2007FRAME, m_toolStyle == xtpToolTipResource ? XTP_TTS_OFFICE2007FRAME : 0); } } XTPToolTipStyle CXTPToolTipContext::GetStyle() const { return m_toolStyle; } void CXTPToolTipContext::SetMaxTipWidth(int iWidth) { m_nMaxTipWidth = iWidth; if (m_pToolTip) m_pToolTip->DestroyWindow(); } int CXTPToolTipContext::GetMaxTipWidth() const { return m_nMaxTipWidth; } COLORREF CXTPToolTipContext::GetTipBkColor() const { return m_clrTipBkColor != COLORREF_NULL ? m_clrTipBkColor :GetXtremeColor(COLOR_INFOBK); } void CXTPToolTipContext::SetTipBkColor(COLORREF clr) { m_clrTipBkColor = clr; if (m_pToolTip) m_pToolTip->DestroyWindow(); } void CXTPToolTipContext::ModifyToolTipStyle(DWORD dwRemove, DWORD dwAdd) { DWORD dwStyle = (m_dwStyle & ~dwRemove) | dwAdd; if (m_dwStyle != dwStyle) { m_dwStyle = dwStyle; SAFE_DELETEWINDOW(m_pToolTip); } } COLORREF CXTPToolTipContext::GetTipTextColor() const { return m_clrTipTextColor != COLORREF_NULL ? m_clrTipTextColor : m_dwStyle & XTP_TTS_OFFICE2007FRAME ? RGB(76, 76, 76) : GetXtremeColor(COLOR_INFOTEXT); } void CXTPToolTipContext::SetTipTextColor(COLORREF clr) { m_clrTipTextColor = clr; if (m_pToolTip) m_pToolTip->DestroyWindow(); } void CXTPToolTipContext::SetDelayTime(DWORD dwDuration, int iTime) { switch (dwDuration) { case TTDT_RESHOW: m_nDelayReshow = iTime; break; case TTDT_INITIAL: m_nDelayInitial = iTime; break; case TTDT_AUTOPOP: m_nDelayAutoPop = iTime; break; default: ASSERT(FALSE); } if (m_pToolTip) m_pToolTip->DestroyWindow(); } void CXTPToolTipContext::RelayToolTipMessage(CWnd* pToolTip, MSG* pMsg) { // transate the message based on TTM_WINDOWFROMPOINT MSG msg = *pMsg; msg.hwnd = (HWND)pToolTip->SendMessage(TTM_WINDOWFROMPOINT, 0, (LPARAM)&msg.pt); CPoint pt = pMsg->pt; if (msg.message >= WM_MOUSEFIRST && msg.message <= WM_MOUSELAST) ::ScreenToClient(msg.hwnd, &pt); msg.lParam = MAKELONG(pt.x, pt.y); // relay mouse event before deleting old tool pToolTip->SendMessage(TTM_RELAYEVENT, 0, (LPARAM)&msg); } void CXTPToolTipContext::FilterToolTipMessage(CWnd* pWndHost, UINT message, WPARAM wParam, LPARAM lParam) { MSG msg; msg.wParam = wParam; msg.lParam = lParam; msg.message = message; msg.hwnd = pWndHost->m_hWnd; GetCursorPos(&msg.pt); FilterToolTipMessage(pWndHost, &msg); } void CXTPToolTipContext::FilterToolTipMessage(CWnd* pWndHost, MSG* pMsg) { FilterToolTipMessageHelper(pWndHost, pMsg, TRUE); } void PASCAL CXTPToolTipContext::FilterToolTipMessageStatic(MSG* pMsg, CWnd* pWnd) { if (m_pModuleContext) { m_pModuleContext->FilterToolTipMessageHelper(pWnd, pMsg, FALSE); } else { pWnd->FilterToolTipMessage(pMsg); } } void CXTPToolTipContext::SetModuleToolTipContext() { AFX_MODULE_STATE* pModuleState = _AFX_CMDTARGET_GETSTATE(); pModuleState->m_pfnFilterToolTipMessage = &CXTPToolTipContext::FilterToolTipMessageStatic; m_pModuleContext = this; } CWnd* CXTPToolTipContext::CreateToolTip(CWnd* /*pOwner*/) { switch (m_toolStyle) { case xtpToolTipOffice: return new CXTPToolTipContextToolTip(this); case xtpToolTipRTF: return new CRichEditToolTip(this); case xtpToolTipLuna: return new CLunaToolTip(this); case xtpToolTipResource: return new CXTPToolTipContextToolTip(this); #ifndef _XTP_EXCLUDE_HTML case xtpToolTipHTML: return new CHTMLToolTip(this); #endif case xtpToolTipMarkup: return new CMarkupToolTip(this); } return new CStandardToolTip(); } void CXTPToolTipContext::SetToolTipCtrl(CXTPToolTipContextToolTip* pToolTipCtrl) { SAFE_DELETEWINDOW(m_pToolTip); m_pToolTip = pToolTipCtrl; } void CXTPToolTipContext::CancelToolTips() { if (m_pToolTip->GetSafeHwnd() != NULL) m_pToolTip->SendMessage(TTM_ACTIVATE, FALSE); } INT_PTR CXTPToolTipContext::OnToolHitTest(CWnd* pWnd, CPoint point, TOOLINFO* pToolInfo) { return pWnd->OnToolHitTest(point, pToolInfo); } void CXTPToolTipContext::FilterToolTipMessageHelper(CWnd* pWndHost, MSG* pMsg, BOOL bIgnoreFlags) { // this CWnd has tooltips enabled UINT message = pMsg->message; if ((message == WM_MOUSEMOVE || message == WM_NCMOUSEMOVE || message == WM_MOUSELEAVE || message == WM_LBUTTONUP || message == WM_RBUTTONUP || message == WM_MBUTTONUP) && (GetKeyState(VK_LBUTTON) >= 0 && GetKeyState(VK_RBUTTON) >= 0 && GetKeyState(VK_MBUTTON) >= 0)) { if (!bIgnoreFlags) { // make sure that tooltips are not already being handled CWnd* pWnd = CWnd::FromHandle(pMsg->hwnd); while (pWnd != NULL && !(pWnd->m_nFlags & (WF_TOOLTIPS | WF_TRACKINGTOOLTIPS))) { pWnd = pWnd->GetParent(); } if (pWnd != pWndHost) { return; } } BOOL bTopParentActive = CXTPDrawHelpers::IsTopParentActive(pWndHost->GetSafeHwnd()); if (m_pToolTip->GetSafeHwnd() && m_pToolTip->IsWindowVisible() && !bTopParentActive) { m_pToolTip->SendMessage(TTM_ACTIVATE, FALSE); return; } CWnd* pOwner = pWndHost->GetParentOwner(); if (m_pToolTip != NULL && m_pToolTip->GetOwner() != pOwner) { m_pToolTip->DestroyWindow(); } if (m_pToolTip == NULL || m_pToolTip->GetSafeHwnd() == NULL) { if (m_pToolTip == NULL) { m_pToolTip = CreateToolTip(pOwner); } if (!m_pToolTip) return; if (!m_pToolTip->GetSafeHwnd()) { if (DYNAMIC_DOWNCAST(CXTPToolTipContextToolTip, m_pToolTip)) { ((CXTPToolTipContextToolTip*)m_pToolTip)->Create(pOwner, m_dwStyle | TTS_ALWAYSTIP | TTS_NOPREFIX); } else if (DYNAMIC_DOWNCAST(CToolTipCtrl, m_pToolTip)) { ((CToolTipCtrl*)m_pToolTip)->Create(pOwner, m_dwStyle | TTS_ALWAYSTIP | TTS_NOPREFIX | (m_toolStyle == xtpToolTipBalloon ? TTS_BALLOON : 0)); } else { ASSERT(FALSE); return; } } if (!m_pToolTip->GetSafeHwnd()) return; m_pToolTip->SetFont(&m_fnt); m_pToolTip->SendMessage(TTM_SETMAXTIPWIDTH, 0, m_nMaxTipWidth); m_pToolTip->SendMessage(TTM_SETMARGIN, 0, (LPARAM)(LPRECT)&m_rcMargin); if (m_clrTipBkColor != COLORREF_NULL) m_pToolTip->SendMessage(TTM_SETTIPBKCOLOR, m_clrTipBkColor); if (m_clrTipTextColor != COLORREF_NULL) m_pToolTip->SendMessage(TTM_SETTIPTEXTCOLOR, m_clrTipTextColor); if (m_nDelayReshow != -1) m_pToolTip->SendMessage(TTM_SETDELAYTIME, TTDT_RESHOW, MAKELPARAM(m_nDelayReshow, 0)); if (m_nDelayInitial != -1) m_pToolTip->SendMessage(TTM_SETDELAYTIME, TTDT_INITIAL, MAKELPARAM(m_nDelayInitial, 0)); if (m_nDelayAutoPop != -1) m_pToolTip->SendMessage(TTM_SETDELAYTIME, TTDT_AUTOPOP, MAKELPARAM(m_nDelayAutoPop, 0)); m_pToolTip->SendMessage(TTM_ACTIVATE, FALSE); } CWnd* pToolTip = m_pToolTip; ASSERT_VALID(pToolTip); ASSERT(::IsWindow(pToolTip->m_hWnd)); XTP_TOOLTIP_CONTEXT tc; ZeroMemory(&tc, sizeof(tc)); // determine which tool was hit CPoint point = pMsg->pt; ::ScreenToClient(pWndHost->m_hWnd, &point); XTP_TOOLTIP_TOOLINFO_EX tiHit; memset(&tiHit, 0, sizeof(XTP_TOOLTIP_TOOLINFO_EX)); tiHit.cbSize = m_bShowTitleAndDescription || m_bShowImage ? sizeof(XTP_TOOLTIP_TOOLINFO_EX) : sizeof(XTP_TOOLTIP_TOOLINFO); tiHit.pToolInfo = &tc; INT_PTR nHit = OnToolHitTest(pWndHost, point, (TOOLINFO*)&tiHit); if (m_bShowTitleAndDescription && tc.lpszDescription && tc.lpszTitle && (_tcscmp(tc.lpszDescription, tc.lpszTitle) == 0)) { free(tc.lpszDescription); tc.lpszDescription = 0; } if ((m_dwStyle & TTS_NOPREFIX) == 0) { CXTPDrawHelpers::StripMnemonics(tiHit.lpszText); CXTPDrawHelpers::StripMnemonics(tiHit.pToolInfo->lpszTitle); } if (m_bStripEllipsisFromToolTip) { XTPStripEllipsis(tiHit.lpszText); XTPStripEllipsis(tiHit.pToolInfo->lpszTitle); } // build new toolinfo and if different than current, register it BOOL bTipInfoChanged = m_lastInfo.uId != tiHit.uId || m_lastInfo.hwnd != tiHit.hwnd; if (bTipInfoChanged || CRect(m_lastInfo.rect) != CRect(tiHit.rect)) { if (m_lastInfo.cbSize >= sizeof(XTP_TOOLTIP_TOOLINFO) && !bTipInfoChanged) pToolTip->SendMessage(TTM_DELTOOL, 0, (LPARAM)&m_lastInfo); if (nHit != -1) { // add new tool and activate the tip XTP_TOOLTIP_TOOLINFO_EX ti = tiHit; ti.uFlags &= ~(TTF_NOTBUTTON | TTF_ALWAYSTIP); VERIFY(pToolTip->SendMessage(TTM_ADDTOOL, 0, (LPARAM)&ti)); if ((m_toolStyle != xtpToolTipRTF && m_toolStyle != xtpToolTipHTML && m_toolStyle != xtpToolTipMarkup) && ((m_dwComCtlVersion >= VERSION_IE5) || (m_toolStyle != xtpToolTipStandard))) { if (m_bShowTitleAndDescription && tc.lpszDescription && tc.lpszTitle) { pToolTip->SendMessage(TTM_SETTITLE, m_nIconTitle, (LPARAM)(LPCTSTR)tc.lpszTitle); ti.lpszText = tc.lpszDescription; pToolTip->SendMessage(TTM_UPDATETIPTEXT, 0, (LPARAM)&ti); } else { pToolTip->SendMessage(TTM_SETTITLE, 0, 0); } } if (m_bShowImage) { CXTPImageManagerIcon* pIcon = NULL; pIcon = tc.pImageManager ? tc.pImageManager->GetImage(UINT(m_nImageBase + nHit), m_nImageSize) : 0; if (pIcon) { pToolTip->SendMessage(XTP_TTM_SETIMAGE, 0, (LPARAM)pIcon); } else { pToolTip->SendMessage(XTP_TTM_SETIMAGE, 0, NULL); } } if ((tiHit.uFlags & TTF_ALWAYSTIP) || bTopParentActive) { // allow the tooltip to popup when it should pToolTip->SendMessage(TTM_ACTIVATE, TRUE); // bring the tooltip window above other popup windows ::SetWindowPos(pToolTip->m_hWnd, HWND_TOP, 0, 0, 0, 0, SWP_NOACTIVATE | SWP_NOSIZE | SWP_NOMOVE | SWP_NOOWNERZORDER); } } else { pToolTip->SendMessage(TTM_ACTIVATE, FALSE); } // relay mouse event before deleting old tool RelayToolTipMessage(pToolTip, pMsg); //// now safe to delete the old tool if (m_lastInfo.cbSize >= sizeof(XTP_TOOLTIP_TOOLINFO) && bTipInfoChanged) pToolTip->SendMessage(TTM_DELTOOL, 0, (LPARAM)&m_lastInfo); m_lastInfo = tiHit; } else { // relay mouse events through the tooltip if (nHit != -1) RelayToolTipMessage(pToolTip, pMsg); } if ((tiHit.lpszText != LPSTR_TEXTCALLBACK) && (tiHit.hinst == 0)) free(tiHit.lpszText); if (tc.lpszDescription != 0) free(tc.lpszDescription); if (tc.lpszTitle != 0) free(tc.lpszTitle); } else { if (!bIgnoreFlags) { // make sure that tooltips are not already being handled CWnd* pWnd = CWnd::FromHandle(pMsg->hwnd); while (pWnd != NULL && pWnd != pWndHost && !(pWnd->m_nFlags & (WF_TOOLTIPS | WF_TRACKINGTOOLTIPS))) { pWnd = pWnd->GetParent(); } if (pWnd != pWndHost) return; } BOOL bKeys = (message >= WM_KEYFIRST && message <= WM_KEYLAST) || (message >= WM_SYSKEYFIRST && message <= WM_SYSKEYLAST); if ((bKeys || (message == WM_LBUTTONDOWN || message == WM_LBUTTONDBLCLK) || (message == WM_RBUTTONDOWN || message == WM_RBUTTONDBLCLK) || (message == WM_MBUTTONDOWN || message == WM_MBUTTONDBLCLK) || (message == WM_NCLBUTTONDOWN || message == WM_NCLBUTTONDBLCLK) || (message == WM_NCRBUTTONDOWN || message == WM_NCRBUTTONDBLCLK) || (message == WM_NCMBUTTONDOWN || message == WM_NCMBUTTONDBLCLK))) { CancelToolTips(); } } }