464 lines
9.1 KiB
C++
464 lines
9.1 KiB
C++
// OXItemTipWnd.cpp : implementation file
|
|
//
|
|
// Version: 9.3
|
|
|
|
|
|
#include "stdafx.h"
|
|
#include <winuser.h>
|
|
#include <windowsx.h>
|
|
#include "OXItemTipWnd.h"
|
|
#include "UTB64Bit.h"
|
|
|
|
#ifdef _DEBUG
|
|
#define new DEBUG_NEW
|
|
#undef THIS_FILE
|
|
static char THIS_FILE[] = __FILE__;
|
|
#endif
|
|
|
|
|
|
/////////////////////////////////////////////////////////////////////////////
|
|
// COXItemTipWnd
|
|
|
|
COXItemTipWnd::COXItemTipWnd()
|
|
{
|
|
m_nTimerID=0;
|
|
}
|
|
|
|
|
|
COXItemTipWnd::~COXItemTipWnd()
|
|
{
|
|
}
|
|
|
|
|
|
BEGIN_MESSAGE_MAP(COXItemTipWnd, CWnd)
|
|
//{{AFX_MSG_MAP(COXItemTipWnd)
|
|
ON_WM_DESTROY()
|
|
//}}AFX_MSG_MAP
|
|
END_MESSAGE_MAP()
|
|
|
|
|
|
|
|
void COXItemTipWnd::PostNcDestroy()
|
|
{
|
|
DestroyWindow();
|
|
CWnd::PostNcDestroy();
|
|
}
|
|
|
|
|
|
BOOL COXItemTipWnd::Create(CWnd* pParentWnd, HBRUSH hbrBackground)
|
|
{
|
|
ASSERT_VALID(pParentWnd);
|
|
ASSERT(::IsWindow(pParentWnd->GetSafeHwnd()));
|
|
|
|
m_pParentWnd=pParentWnd;
|
|
|
|
// creation of window
|
|
//
|
|
if(hbrBackground==NULL)
|
|
{
|
|
hbrBackground=(HBRUSH)(COLOR_INFOBK+1);
|
|
}
|
|
|
|
WNDCLASS wndClass;
|
|
wndClass.style=CS_SAVEBITS|CS_DBLCLKS;
|
|
wndClass.lpfnWndProc=AfxWndProc;
|
|
wndClass.cbClsExtra=0;
|
|
wndClass.cbWndExtra=0;
|
|
wndClass.hInstance=AfxGetInstanceHandle();
|
|
wndClass.hIcon=::LoadCursor(NULL,IDC_ARROW);
|
|
wndClass.hCursor=0;
|
|
wndClass.hbrBackground=hbrBackground;
|
|
wndClass.lpszMenuName=NULL;
|
|
wndClass.lpszClassName=_T("ItemTipWnd");
|
|
|
|
if(!AfxRegisterClass(&wndClass))
|
|
{
|
|
return FALSE;
|
|
}
|
|
|
|
CRect rect(0,0,0,0);
|
|
if(!CWnd::CreateEx(WS_EX_TOOLWINDOW,wndClass.lpszClassName,_T(""),
|
|
WS_BORDER|WS_POPUP,rect,NULL,0,NULL))
|
|
{
|
|
return FALSE;
|
|
}
|
|
|
|
return TRUE;
|
|
}
|
|
|
|
|
|
void COXItemTipWnd::Display(CRect& rect, CString sText, int nOffset, int nAlignment,
|
|
CFont* pFont, COLORREF clrText, COLORREF clrBackground)
|
|
{
|
|
ASSERT_VALID(m_pParentWnd);
|
|
ASSERT(::IsWindow(m_pParentWnd->GetSafeHwnd()));
|
|
ASSERT(::IsWindow(m_hWnd));
|
|
|
|
CWnd* pWnd=GetActiveWindow();
|
|
if(pWnd==NULL || (!IsDescendant(pWnd,m_pParentWnd) &&
|
|
(m_pParentWnd->GetExStyle()&WS_EX_TOPMOST)!=WS_EX_TOPMOST))
|
|
{
|
|
return;
|
|
}
|
|
|
|
CClientDC dc(this); // device context for drawing
|
|
|
|
CFont* pOldFont=NULL;
|
|
if(pFont)
|
|
{
|
|
pOldFont=dc.SelectObject(pFont);
|
|
}
|
|
COLORREF clrOld=ID_OX_COLOR_NONE;
|
|
if(clrText!=ID_OX_COLOR_NONE)
|
|
{
|
|
clrOld=dc.SetTextColor(clrText);
|
|
}
|
|
int nOldBkMode=dc.SetBkMode(TRANSPARENT);
|
|
|
|
CRect rectDraw=rect;
|
|
dc.DrawText(sText,&rectDraw,DT_CALCRECT|DT_LEFT|DT_SINGLELINE|DT_NOPREFIX);
|
|
rectDraw.right+=2*nOffset;
|
|
if(rectDraw.Width()>rect.Width())
|
|
{
|
|
rect.right=rect.left+rectDraw.Width();
|
|
}
|
|
if(rectDraw.Height()>rect.Height())
|
|
{
|
|
rect.bottom=rect.top+rectDraw.Height();
|
|
}
|
|
|
|
// it's show time!
|
|
m_pParentWnd->ClientToScreen(&rect);
|
|
|
|
// adjust rectangle to fit the screen
|
|
//
|
|
CWnd* pParentWnd=m_pParentWnd;
|
|
BOOL bTopMostParent=FALSE;
|
|
while(pParentWnd!=NULL)
|
|
{
|
|
if(pParentWnd->GetExStyle() & WS_EX_TOPMOST)
|
|
{
|
|
bTopMostParent=TRUE;
|
|
break;
|
|
}
|
|
pParentWnd=pParentWnd->GetParent();
|
|
}
|
|
|
|
DWORD dwMessagePos=::GetMessagePos();
|
|
CPoint point(GET_X_LPARAM(dwMessagePos),GET_Y_LPARAM(dwMessagePos));
|
|
CRect rectDisplay=GetMonitorRectFromPoint(point,!bTopMostParent);
|
|
|
|
if(rect.right>rectDisplay.right)
|
|
{
|
|
rect.OffsetRect(rectDisplay.right-rect.right,0);
|
|
}
|
|
if(rect.left<rectDisplay.left)
|
|
{
|
|
rect.OffsetRect(rectDisplay.left-rect.left,0);
|
|
}
|
|
//
|
|
/////////////////////////////////////////////////////////////
|
|
|
|
if(bTopMostParent)
|
|
{
|
|
SetWindowPos(&wndTopMost,rect.left,rect.top,rect.Width(),
|
|
rect.Height(),SWP_NOACTIVATE);
|
|
}
|
|
else
|
|
{
|
|
SetWindowPos(NULL,rect.left,rect.top,rect.Width(),
|
|
rect.Height(),SWP_NOZORDER|SWP_NOACTIVATE);
|
|
}
|
|
ShowWindow(SW_SHOWNA);
|
|
|
|
if(clrBackground!=ID_OX_COLOR_NONE)
|
|
{
|
|
CBrush brush;
|
|
brush.CreateSolidBrush(clrBackground);
|
|
CRect rectClient;
|
|
GetClientRect(rectClient);
|
|
dc.FillRect(&rectClient,&brush);
|
|
}
|
|
else
|
|
{
|
|
SendMessage(WM_ERASEBKGND,(WPARAM)(HDC)dc);
|
|
}
|
|
|
|
rectDraw=rect;
|
|
rectDraw.DeflateRect(nOffset,0);
|
|
ScreenToClient(&rectDraw);
|
|
dc.DrawText(sText,&rectDraw,nAlignment|DT_SINGLELINE|DT_VCENTER|DT_NOPREFIX);
|
|
|
|
if(pOldFont)
|
|
{
|
|
dc.SelectObject(pOldFont);
|
|
}
|
|
if(clrOld!=ID_OX_COLOR_NONE)
|
|
{
|
|
dc.SetTextColor(clrOld);
|
|
}
|
|
dc.SetBkMode(nOldBkMode);
|
|
|
|
m_nTimerID=SetTimer(ID_OXITEMTIP_TIMER,ID_OXITEMTIP_TIMER_DELAY,NULL);
|
|
if(m_nTimerID==0)
|
|
{
|
|
TRACE(_T("COXItemTipWnd::Display: failed to set timer to check item tip state\n"));
|
|
}
|
|
}
|
|
|
|
|
|
void COXItemTipWnd::Hide(MSG* pMsg, CWnd* pWnd)
|
|
{
|
|
ASSERT_VALID(m_pParentWnd);
|
|
ASSERT(::IsWindow(m_pParentWnd->GetSafeHwnd()));
|
|
ASSERT(::IsWindow(m_hWnd));
|
|
|
|
if(m_nTimerID!=0)
|
|
{
|
|
KillTimer(m_nTimerID);
|
|
}
|
|
|
|
ShowWindow(SW_HIDE);
|
|
if(pMsg!=NULL)
|
|
{
|
|
if(pWnd==NULL)
|
|
{
|
|
pWnd=m_pParentWnd;
|
|
}
|
|
|
|
if(::IsWindow(pWnd->GetSafeHwnd()))
|
|
{
|
|
pWnd->PostMessage(pMsg->message,pMsg->wParam,pMsg->lParam);
|
|
}
|
|
}
|
|
}
|
|
|
|
|
|
BOOL COXItemTipWnd::PreTranslateMessage(MSG* pMsg)
|
|
{
|
|
ASSERT_VALID(m_pParentWnd);
|
|
ASSERT(::IsWindow(m_pParentWnd->GetSafeHwnd()));
|
|
ASSERT(::IsWindow(m_hWnd));
|
|
|
|
CWnd *pWnd=NULL;
|
|
int nHitTest;
|
|
|
|
pWnd=m_pParentWnd;
|
|
while(pWnd!=NULL && (pWnd->GetStyle()&WS_CHILD)!=0)
|
|
{
|
|
pWnd=pWnd->GetParent();
|
|
}
|
|
ASSERT(pWnd!=NULL);
|
|
|
|
if(pMsg->message==WM_MOUSEMOVE ||
|
|
(pMsg->message==WM_TIMER && pMsg->wParam==(WPARAM)m_nTimerID))
|
|
{
|
|
CPoint point;
|
|
::GetCursorPos(&point);
|
|
CRect rect;
|
|
GetWindowRect(rect);
|
|
pWnd=WindowFromPoint(point);
|
|
ASSERT(pWnd!=NULL);
|
|
if(pWnd->GetSafeHwnd()==GetSafeHwnd())
|
|
{
|
|
return CWnd::PreTranslateMessage(pMsg);
|
|
}
|
|
else
|
|
{
|
|
if(pMsg->message!=WM_MOUSEMOVE)
|
|
{
|
|
Hide();
|
|
return TRUE;
|
|
}
|
|
}
|
|
}
|
|
|
|
switch(pMsg->message)
|
|
{
|
|
case WM_LBUTTONDOWN:
|
|
case WM_RBUTTONDOWN:
|
|
case WM_MBUTTONDOWN:
|
|
case WM_LBUTTONUP:
|
|
case WM_RBUTTONUP:
|
|
case WM_MBUTTONUP:
|
|
case WM_MOUSEMOVE:
|
|
case WM_LBUTTONDBLCLK:
|
|
case WM_RBUTTONDBLCLK:
|
|
case WM_MBUTTONDBLCLK:
|
|
{
|
|
POINTS points=MAKEPOINTS(pMsg->lParam);
|
|
CPoint point(points.x,points.y);
|
|
ClientToScreen(&point);
|
|
pWnd=WindowFromPoint(point);
|
|
ASSERT(pWnd);
|
|
if(pWnd==this)
|
|
{
|
|
pWnd=m_pParentWnd;
|
|
}
|
|
|
|
nHitTest=(int)pWnd->SendMessage(WM_NCHITTEST,0,
|
|
MAKELONG(point.x,point.y));
|
|
if(nHitTest==HTCLIENT)
|
|
{
|
|
pWnd->ScreenToClient(&point);
|
|
}
|
|
else
|
|
{
|
|
switch(pMsg->message)
|
|
{
|
|
case WM_LBUTTONDOWN:
|
|
{
|
|
pMsg->message=WM_NCLBUTTONDOWN;
|
|
break;
|
|
}
|
|
case WM_RBUTTONDOWN:
|
|
{
|
|
pMsg->message=WM_NCRBUTTONDOWN;
|
|
break;
|
|
}
|
|
case WM_MBUTTONDOWN:
|
|
{
|
|
pMsg->message=WM_NCMBUTTONDOWN;
|
|
break;
|
|
}
|
|
case WM_LBUTTONUP:
|
|
{
|
|
pMsg->message=WM_NCLBUTTONUP;
|
|
break;
|
|
}
|
|
case WM_RBUTTONUP:
|
|
{
|
|
pMsg->message=WM_NCRBUTTONUP;
|
|
break;
|
|
}
|
|
case WM_MBUTTONUP:
|
|
{
|
|
pMsg->message=WM_NCMBUTTONUP;
|
|
break;
|
|
}
|
|
case WM_LBUTTONDBLCLK:
|
|
{
|
|
pMsg->message=WM_NCLBUTTONDBLCLK;
|
|
break;
|
|
}
|
|
case WM_RBUTTONDBLCLK:
|
|
{
|
|
pMsg->message=WM_NCRBUTTONDBLCLK;
|
|
break;
|
|
}
|
|
case WM_MBUTTONDBLCLK:
|
|
{
|
|
pMsg->message=WM_NCMBUTTONDBLCLK;
|
|
break;
|
|
}
|
|
case WM_MOUSEMOVE:
|
|
{
|
|
pMsg->message=WM_NCMOUSEMOVE;
|
|
break;
|
|
}
|
|
}
|
|
pMsg->wParam=nHitTest;
|
|
}
|
|
pMsg->lParam=MAKELONG(point.x,point.y);
|
|
|
|
ASSERT(pWnd!=this);
|
|
}
|
|
case WM_KEYDOWN:
|
|
case WM_SYSKEYDOWN:
|
|
{
|
|
ASSERT(pWnd!=NULL);
|
|
|
|
Hide(pMsg,pWnd);
|
|
return TRUE;
|
|
}
|
|
}
|
|
|
|
BOOL bResult=CWnd::PreTranslateMessage(pMsg);
|
|
return bResult;
|
|
}
|
|
|
|
|
|
void COXItemTipWnd::OnDestroy()
|
|
{
|
|
if(m_nTimerID!=0)
|
|
{
|
|
KillTimer(m_nTimerID);
|
|
}
|
|
}
|
|
|
|
|
|
BOOL COXItemTipWnd::IsDescendant(CWnd* pWndParent, CWnd* pWndChild)
|
|
// helper for detecting whether child descendent of parent
|
|
// (works with owned popups as well)
|
|
{
|
|
ASSERT(pWndParent!=NULL);
|
|
ASSERT(::IsWindow(pWndParent->GetSafeHwnd()));
|
|
ASSERT(pWndChild!=NULL);
|
|
ASSERT(::IsWindow(pWndChild->GetSafeHwnd()));
|
|
|
|
HWND hWndParent=pWndParent->GetSafeHwnd();
|
|
HWND hWndChild=pWndChild->GetSafeHwnd();
|
|
do
|
|
{
|
|
if (hWndParent == hWndChild)
|
|
return TRUE;
|
|
|
|
// check for permanent-owned window first
|
|
CWnd* pWnd=CWnd::FromHandlePermanent(hWndChild);
|
|
if(pWnd!=NULL)
|
|
hWndChild=pWnd->GetOwner()->GetSafeHwnd();
|
|
else
|
|
hWndChild=(::GetWindowLongPtr(hWndChild,GWL_STYLE)&WS_CHILD) ?
|
|
::GetParent(hWndChild) : ::GetWindow(hWndChild,GW_OWNER);
|
|
|
|
} while (hWndChild != NULL);
|
|
|
|
return FALSE;
|
|
}
|
|
|
|
|
|
CRect COXItemTipWnd::GetMonitorRectFromPoint(const CPoint& ptHitTest,
|
|
BOOL bOnlyWorkArea)
|
|
{
|
|
CRect rectDisplay;
|
|
|
|
#if(defined(GetMonitorInfo) && defined(MonitorFromPoint))
|
|
// if we use Win 98/NT5 we have to take into account multiple monitors
|
|
OSVERSIONINFO osvi={ sizeof(OSVERSIONINFO) };
|
|
VERIFY(::GetVersionEx(&osvi)!=0);
|
|
if(osvi.dwMajorVersion>4 ||
|
|
(osvi.dwMajorVersion==4 && osvi.dwMinorVersion>0))
|
|
{
|
|
HMONITOR hMonitor=::MonitorFromPoint(ptHitTest,MONITOR_DEFAULTTONEAREST);
|
|
ASSERT(hMonitor!=NULL);
|
|
MONITORINFO monitorInfo={ sizeof(MONITORINFO) };
|
|
VERIFY(::GetMonitorInfo(hMonitor,&monitorInfo));
|
|
if(!bOnlyWorkArea)
|
|
{
|
|
rectDisplay=monitorInfo.rcMonitor;
|
|
}
|
|
else
|
|
{
|
|
rectDisplay=monitorInfo.rcWork;
|
|
}
|
|
}
|
|
else
|
|
{
|
|
#endif
|
|
if(!bOnlyWorkArea)
|
|
{
|
|
GetDesktopWindow()->GetWindowRect(rectDisplay);
|
|
}
|
|
else
|
|
{
|
|
::SystemParametersInfo(SPI_GETWORKAREA,NULL,&rectDisplay,NULL);
|
|
}
|
|
#if(defined(GetMonitorInfo) && defined(MonitorFromPoint))
|
|
}
|
|
#else
|
|
UNREFERENCED_PARAMETER(ptHitTest);
|
|
#endif
|
|
|
|
return rectDisplay;
|
|
}
|