PupText.h
////////////////////////////////////////////////////////////////
// Microsoft Systems Journal -- December 1999
// If this code works, it was written by Paul DiLascia.
// If not, I don't know who wrote it.
// Compiles with Visual C++ 6.0, runs on Windows 98 and probably Windows NT too.
//
#pragma once
//////////////////
// Get NONCLIENTMETRICS info: ctor calls SystemParametersInfo.
//
class CNonClientMetrics : public NONCLIENTMETRICS {
public:
CNonClientMetrics() {
cbSize = sizeof(NONCLIENTMETRICS);
SystemParametersInfo(SPI_GETNONCLIENTMETRICS,0,this,0);
}
};
//////////////////
// Popup text window, like tooltip but no timer stuff.
// Can be right or left-justified relative to creation point.
//
class CPopupText : public CWnd {
public:
CSize m_szMargins; // extra space around text: change if you like
enum {JUSTIFYLEFT=0, JUSTIFYRIGHT};
CPopupText();
virtual ~CPopupText();
BOOL Create(CPoint pt, CWnd* pParentWnd, UINT nStyle=0, UINT nID=0);
protected:
CFont m_font; // font to use (same as tooltips)
UINT m_nStyle; // style (see enum below)
virtual void PostNcDestroy();
virtual BOOL PreCreateWindow(CREATESTRUCT& cs);
afx_msg void OnPaint();
afx_msg LRESULT OnSetText(WPARAM wp, LPARAM lp);
DECLARE_MESSAGE_MAP()
};
PupText.cpp
////////////////////////////////////////////////////////////////
// Microsoft Systems Journal -- December 1999
// If this code works, it was written by Paul DiLascia.
// If not, I don't know who wrote it.
// Compiles with Visual C++ 6.0, runs on Windows 98 and probably Windows NT too.
//
#include "stdafx.h"
#include "puptext.h"
#ifdef _DEBUG
#define new DEBUG_NEW
#undef THIS_FILE
static char THIS_FILE[] = __FILE__;
#endif
BEGIN_MESSAGE_MAP(CPopupText,CWnd)
ON_WM_PAINT()
ON_MESSAGE(WM_SETTEXT, OnSetText)
END_MESSAGE_MAP()
CPopupText::CPopupText()
{
m_szMargins = CSize(4,4);
// create font -- use system tooltip font
CNonClientMetrics ncm;
m_font.CreateFontIndirect(&ncm.lfStatusFont);
}
CPopupText::~CPopupText()
{
}
//////////////////
// Create window. pt is upper left or upper-right corner depending on nStyle.
//
CPopupText::Create(CPoint pt, CWnd* pParentWnd, UINT nStyle, UINT nID)
{
m_nStyle = nStyle;
return CreateEx(0,
NULL,
NULL,
WS_POPUP|WS_VISIBLE,
CRect(pt,CSize(0,0)),
pParentWnd,
nID);
}
//////////////////
// Someone changed the text: resize to fit new text
//
LRESULT CPopupText::OnSetText(WPARAM wp, LPARAM lp)
{
CClientDC dc = this;
CFont* pOldFont = dc.SelectObject(&m_font);
CRect rc;
GetWindowRect(&rc);
int x = (m_nStyle & JUSTIFYRIGHT) ? rc.right : rc.left;
int y = rc.top;
dc.DrawText(CString((LPCTSTR)lp), &rc, DT_CALCRECT);
rc.InflateRect(m_szMargins);
if (m_nStyle & JUSTIFYRIGHT)
x -= rc.Width();
SetWindowPos(NULL,x,y,rc.Width(),rc.Height(), SWP_NOZORDER);
return Default();
}
//////////////////
// Paint the text. Use system colors
//
void CPopupText::OnPaint()
{
CPaintDC dc(this);
CRect rc;
GetClientRect(&rc);
CString s;
GetWindowText(s);
CBrush b(GetSysColor(COLOR_INFOBK)); // use tooltip bg color
dc.FillRect(&rc, &b);
// draw text
dc.SetBkMode(TRANSPARENT);
CFont* pOldFont = dc.SelectObject(&m_font);
dc.SetTextColor(GetSysColor(COLOR_INFOTEXT)); // tooltip text color
dc.DrawText(s, &rc, DT_SINGLELINE|DT_CENTER|DT_VCENTER);
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_BORDER;
return CWnd::PreCreateWindow(cs);
}
//////////////////
// CPopupText is intended to be used on the stack,
// not heap, so don't auto-delete.
//
void CPopupText::PostNcDestroy()
{
// don't delete this
}
Figure 3 CDeferScrollHook
DeferScroll.h
////////////////////////////////////////////////////////////////
// Microsoft Systems Journal -- December 1999
// If this code works, it was written by Paul DiLascia.
// If not, I don't know who wrote it.
// Compiles with Visual C++ 6.0, runs on Windows 98 and probably Windows NT too.
//
#pragma once
#include "SubClass.h"
#include "PupText.h"
//////////////////
// This class implements deferred scrolling for views and list
// controls, and probably any other kind of scrolling window.
//
class CDeferScrollHook : public CSubclassWnd {
public:
CDeferScrollHook();
virtual ~CDeferScrollHook();
BOOL Install(CWnd* pWnd, UINT nStyle = CPopupText::JUSTIFYRIGHT);
// You must override to provide the "tip" text.
// If you really don't, just return FALSE.
virtual BOOL OnGetScrollText(CString& s, UINT nPos)=0;
protected:
UINT m_nStyle; // style for popup text
BOOL m_bIgnoreThumb; // ignore SB_THUMBTRACK
virtual LRESULT WindowProc(UINT msg, WPARAM wp, LPARAM lp);
afx_msg void OnVScroll(UINT nSBCode, UINT nPos, CScrollBar* pScrollBar);
DECLARE_DYNAMIC(CDeferScrollHook)
};
DeferScroll.cpp
////////////////////////////////////////////////////////////////
// Microsoft Systems Journal -- December 1999
// If this code works, it was written by Paul DiLascia.
// If not, I don't know who wrote it.
// Compiles with Visual C++ 6.0, runs on Windows 98 and probably Windows NT too.
//
#include "stdafx.h"
#include "DeferScroll.h"
#include "PupText.h"
#ifdef _DEBUG
#define new DEBUG_NEW
#undef THIS_FILE
static char THIS_FILE[] = __FILE__;
#endif
IMPLEMENT_DYNAMIC(CDeferScrollHook, CSubclassWnd);
CDeferScrollHook::CDeferScrollHook()
{
m_bIgnoreThumb=TRUE;
}
CDeferScrollHook::~CDeferScrollHook()
{
}
BOOL CDeferScrollHook::Install(CWnd* pWnd, UINT nStyle)
{
m_nStyle = nStyle; // style for popup scroll tip
return HookWindow(pWnd);
}
//////////////////
// Main hook proc intercepts scrolling notifications
//
LRESULT CDeferScrollHook::WindowProc(UINT msg, WPARAM wp, LPARAM lp)
{
if (msg==WM_VSCROLL) {
UINT nSBCode = LOWORD(wp);
UINT nPos = HIWORD(wp);
static CPopupText wndTip; // one and only
CWnd* pWnd = CWnd::FromHandle(m_hWnd);
switch (nSBCode) {
case SB_THUMBTRACK:
if (m_bIgnoreThumb) {
// ignoring: don't pass to window, but display scroll tip
CString s;
if (OnGetScrollText(s,nPos)) { // if app supplies popup text:
if (!wndTip) {
// create scroll tip window
CPoint pt;
GetCursorPos(&pt);
pt.x -= 10;
wndTip.Create(pt, pWnd, m_nStyle);
}
wndTip.SetWindowText(s);
wndTip.Invalidate();
wndTip.UpdateWindow();
}
return 0; // handled; otherwise (not ignoring) pass along
}
break;
case SB_THUMBPOSITION:
{
// convert SB_THUMBPOSITION to SB_THUMBTRACK, and don't ignore it
BOOL bSaveIgnoreThumb = m_bIgnoreThumb;
m_bIgnoreThumb = FALSE;
pWnd->SendMessage(msg, MAKEWPARAM(SB_THUMBTRACK, nPos), lp);
m_bIgnoreThumb = bSaveIgnoreThumb;
return 0; // handled
}
case SB_ENDSCROLL:
// end of scrollling: remove scroll tip
if (wndTip)
wndTip.DestroyWindow();
break;
}
}
// I don't handle it: pass along
return CSubclassWnd::WindowProc(msg, wp, lp);
}