// PopupText.cpp #include "stdafx.h" #include "PopupText.h" #ifdef _DEBUG #define new DEBUG_NEW #undef THIS_FILE static char THIS_FILE[] = __FILE__; #endif IMPLEMENT_DYNAMIC(CPopupText,CWnd) BEGIN_MESSAGE_MAP(CPopupText,CWnd) ON_WM_PAINT() ON_MESSAGE(WM_SETTEXT, OnSetText) ON_WM_TIMER() END_MESSAGE_MAP() const UINT PopupTimer=114; CPopupText::CPopupText() : Margins(3,3) { NONCLIENTMETRICS ncm; ncm.cbSize=sizeof(NONCLIENTMETRICS); SystemParametersInfo(SPI_GETNONCLIENTMETRICS,0,&ncm,0); Font.CreateFontIndirect(&ncm.lfStatusFont); // create font - use system tooltip font } CPopupText::~CPopupText() {try{Hide();} catch(...){}} // Create window. pt is upper-left or upper-right corner depending on nStyle. BOOL CPopupText::Create(CPoint pt, CWnd* pParentWnd, UINT nStyle, UINT nID) { Style = nStyle; return CreateEx(0,0,0, WS_POPUP|WS_VISIBLE, CRect(pt,pt), pParentWnd, nID); } LRESULT CPopupText::OnSetText(WPARAM /*wp*/, LPARAM lp) { CClientDC dc(this); CFont* pOldFont = dc.SelectObject(&Font); CRect rc; GetWindowRect(&rc); int x = (Style==Right) ? rc.right : rc.left; int y = rc.top; dc.DrawText(CString((LPCTSTR)lp), &rc, DT_CALCRECT); rc.InflateRect(Margins); if(m_nStyle & JUSTIFYRIGHT) x -= rc.Width(); CRect DesktopRect; // Don't draw over the TaskBar or outside the clipping area: if(::SystemParametersInfo(SPI_GETWORKAREA, 0, &DesktopRect, 0)) { // <-- Could use GetClientRect instead, to keep it in the Window int dx=rc.right -DesktopRect.right; int dy=rc.bottom-DesktopRect.bottom; if(dx>0) x-=dx; if(dy>0) y-=dy; } SetWindowPos(0,x,y,rc.Width(),rc.Height(), SWP_NOZORDER|SWP_NOACTIVATE); dc.SelectObject(pOldFont); return Default(); } void CPopupText::OnPaint() { CPaintDC dc(this); CRect rc; GetClientRect(&rc); CString s; GetWindowText(s); dc.FillSolidRect(rc, GetSysColor(COLOR_INFOBK)); dc.SetBkMode(TRANSPARENT); CFont* pOldFont = dc.SelectObject(&Font); dc.SetTextColor(GetSysColor(COLOR_INFOTEXT)); // tooltip text color bool multi_line = (s.FindOneOf("\r\n") != -1); dc.DrawText(s, &rc, DT_CENTER | (!multi_line ? DT_SINGLELINE : 0) | (!multi_line ? DT_VCENTER : 0)); dc.SelectObject(pOldFont); } // Register class if needed: BOOL CPopupText::PreCreateWindow(CREATESTRUCT& cs) { static CString sClassName; if(sClassName.IsEmpty()) sClassName = AfxRegisterWndClass(0); cs.lpszClass = sClassName; cs.style = WS_POPUP|WS_BORDER; cs.dwExStyle |= WS_EX_TOOLWINDOW; return CWnd::PreCreateWindow(cs); } // Show window with delay (Zero means show now): void CPopupText::Show(UINT msec) { if(msec==0) OnTimer(PopupTimer); // no delay: show it now else SetTimer(PopupTimer,msec,0); // delay: set time } // kill timer and hide window void CPopupText::Hide() { KillTimer(PopupTimer); ShowWindow(SW_HIDE); } // Timer popped: display and kill timer void CPopupText::OnTimer(UINT /*nIDEvent*/) { ShowWindow(SW_SHOWNA); Invalidate(); UpdateWindow(); KillTimer(PopupTimer); }