Figure 2 Flyby
mouse.h
////////////////////////////////////////////////////////////////
// 1998 Microsoft Systems Journal.
// If this code works, it was written by Paul DiLascia.
// If not, I don't know who wrote it.
// Compiles with Visual C++ 5.0 on Windows 95
//
//////////////////
// class to represent global mouse object.
//
class CMouse {
public:
CWnd* Capture() { return CWnd::GetCapture(); }
CWnd* Capture(CWnd *w) { return w->SetCapture(); }
void Release() { ReleaseCapture(); }
CPoint GetPos() { CPoint p; ::GetCursorPos(&p); return p; }
operator CPoint() { return GetPos(); }
};
extern CMouse Mouse;
mouse.cpp
////////////////////////////////////////////////////////////////
// 1998 Microsoft Systems Journal.
// If this code works, it was written by Paul DiLascia.
// If not, I don't know who wrote it.
// Compiles with Visual C++ 5.0 on Windows 95
//
#include <stdafx.h>
#include "mouse.h"
// Instantiate one-and-only mouse object
CMouse Mouse;
view.h
////////////////////////////////////////////////////////////////
// 1998 Microsoft Systems Journal.
// If this code works, it was written by Paul DiLascia.
// If not, I don't know who wrote it.
// Compiles with Visual C++ 5.0 on Windows 95
//
class CMyView : public CView {
private:
CRect m_rcClient; // client area rectangle
CRgn m_hotRegion; // elliptic region
BOOL m_bHighlighted; // whether region is highlighted
BOOL m_bTrackLeave; // whether tracking mouse
public:
virtual ~CMyView();
CMyDoc* GetDocument() { return (CMyDoc*)m_pDocument; }
virtual void OnDraw(CDC* pDC);
BOOL TrackMouseLeave(BOOL bTrackLeave);
protected:
DECLARE_DYNCREATE(CMyView)
CMyView();
afx_msg void OnMouseMove(UINT nFlags, CPoint pt);
afx_msg void OnSize(UINT nType, int cx, int cy);
afx_msg void OnTimer(UINT nIDEvent);
DECLARE_MESSAGE_MAP()
};
view.cpp
////////////////////////////////////////////////////////////////
// FLYBY 1998 Microsoft Systems Journal.
// If this program works, it was written by Paul DiLascia.
// If not, I don't know who wrote it.
//
#include "StdAfx.h"
#include "Flyby.h"
#include "Doc.h"
#include "View.h"
#include "Mouse.h"
#ifdef _DEBUG
#define new DEBUG_NEW
#undef THIS_FILE
static char THIS_FILE[] = __FILE__;
#endif
IMPLEMENT_DYNCREATE(CMyView, CView)
BEGIN_MESSAGE_MAP(CMyView, CView)
ON_WM_MOUSEMOVE()
ON_WM_SIZE()
ON_WM_TIMER()
END_MESSAGE_MAP()
CMyView::CMyView()
{
m_bTrackLeave = FALSE; // not tracking mouse
m_bHighlighted = -1; // invalid state
}
CMyView::~CMyView()
{
}
//////////////////
// Draw ellipse within client area.
// If mouse is outside the ellipse, draw blue; else red
//
void CMyView::OnDraw(CDC* pDC)
{
CPoint pt = Mouse; // mouse pos in screen coords
ScreenToClient(&pt); // convert to client
// create brush w/appropriate color
CBrush brush(m_hotRegion.PtInRegion(pt) ?
RGB(255,0,0) : // red
RGB(0,0,255)); // blue
// select brush and draw ellipse
CGdiObject *pOldBrush = pDC->SelectObject(&brush);
pDC->Ellipse(&m_rcClient);
pDC->SelectObject(pOldBrush);
}
//////////////////
// Window size changed: update client rectangle and elliptic region.
//
void CMyView::OnSize(UINT nType, int cx, int cy)
{
m_rcClient.SetRect(0,0,cx,cy);
m_hotRegion.DeleteObject();
m_hotRegion.CreateEllipticRgnIndirect(&m_rcClient);
}
//////////////////
// Handle mouse move message: highlight or unhighlight ellipse,
// and if highlighted, track mouse for leaving window.
//
void CMyView::OnMouseMove(UINT nFlags, CPoint pt)
{
// Determine correct highlight for
// ellipse, and repaint if necessary.
//
BOOL bHighlighted = m_hotRegion.PtInRegion(pt);
if (bHighlighted != m_bHighlighted) {
// Mouse has either left or entered the ellipse: repaint
m_bHighlighted = bHighlighted;
Invalidate(FALSE);
UpdateWindow();
// Track the mouse leaving window based on whether highlighted or not
//
TrackMouseLeave(m_bHighlighted);
}
}
//////////////////
// Track when mouse leaves window -- by setting a timer (yuk).
// In Windows NT, you should use TrackMouseEvent instead.
//
BOOL CMyView::TrackMouseLeave(BOOL bTrackLeave)
{
if (bTrackLeave != m_bTrackLeave) {
if (bTrackLeave)
VERIFY(SetTimer(1, 50, NULL));
else
KillTimer(1);
m_bTrackLeave = bTrackLeave;
}
return m_bTrackLeave;
}
/////////////////
// Handle timer click: check for mouse leaving window
//
void CMyView::OnTimer(UINT nIDEvent)
{
ASSERT(nIDEvent==1);
// Get mouse pos in client coords
CPoint pt = Mouse;
ScreenToClient(&pt);
if (!m_rcClient.PtInRect(pt)) {
//
// Mouse is outside window: send bogus WM_MOUSEMOVE message.
// Be careful doing this: if your OnMouseMove function does other
// stuff that expects the mouse to be in the client area, it might
// fail.
//
// Probably better to send WM_MOUSELEAVE here.
//
SendMessage(WM_MOUSEMOVE, 0, MAKELONG(pt.x, pt.y));
TrackMouseLeave(FALSE); // stop tracking
}
}
Figure 5 HTBTest
hottb.h
////////////////////////////////////////////////////////////////
// 1998 Microsoft Systems Journal.
// If this code works, it was written by Paul DiLascia.
// If not, I don't know who wrote it.
// Compiles with Visual C++ 5.0 on Windows 95
//
//////////////////
// This class sets up a toolbar with hot/cold button bitmaps.
// To use it instead of CToolBar::LoadToolBar, create an instance in
// you CMainFrame::OnCreate, then call SetupHotToolBar like so
//
// CHotToolBarSetup htbs;
// htbs.SetupHotToolBar(m_wndToolBar, ID_NORMAL, ID_HOT, ID_DISAB, cx, clrBk);
//
// m_wndToolBar is your CToolBar
// ID_NORMAL is the resource id of bitmap to use for normal buttons
// ID_HOT is the resource id of bitmap to use for "hot" buttons
// ID_DISAB is the resource id of bitmap to use for disabled buttons
// cx is the width of one button
// clrBk is the background color of the bitmaps, which will be
// mapped to transparent
//
class CHotToolBarSetup {
private:
CSize m_szButtonMargin; // button size this much bigger than image size
public:
CHotToolBarSetup();
void SetupHotToolBar(CToolBar& tb, UINT nIdCold, UINT nidHot, UINT nIdDisab,
int cx, COLORREF clrBkgnd);
};
hottb.cpp
////////////////////////////////////////////////////////////////
// 1998 Microsoft Systems Journal.
// If this code works, it was written by Paul DiLascia.
// If not, I don't know who wrote it.
// Compiles with Visual C++ 5.0 on Windows 95
//
#include "stdafx.h"
#include "hottb.h"
CHotToolBarSetup::CHotToolBarSetup()
{
// MFC normally makes the button 7 pixels larger all around than the
// actual button image. Change this if you like before calling Setup.
//
m_szButtonMargin = CSize(7,7);
}
// Set up toolbar with normal and "hot" button bitmaps
//
void CHotToolBarSetup::SetupHotToolBar(CToolBar& tb, // toolbar
UINT nIdNormal, // resource ID for normal buttons bitmap
UINT nIdHot, // resource ID for hot button bitmap
UINT nIdDisab, // resource ID for disabled button bitmap
int cx, // width of one button image
COLORREF clrBkgnd) // background (transparent) color
{
// Size of one button image--will calculate cy below
CSize szImage(cx,0);
// A toolbar must be flat to use "hot" bitmap (image list)
tb.ModifyStyle(0, TBSTYLE_FLAT);
// Create image list from normal bitmap
ASSERT(nIdNormal);
CImageList il;
VERIFY(il.Create(nIdNormal, cx, 0, clrBkgnd));
// Get height of button image from image list itself.
IMAGEINFO info;
il.GetImageInfo(0, &info);
szImage.cy = ((CRect&)info.rcImage).Height();
// Set toolbar button sizes for MFC
tb.SetSizes(szImage + m_szButtonMargin, szImage);
// set normal button images.
// It's important to detach the HIMAGELIST, else CImageList will destroy.
tb.SendMessage(TB_SETIMAGELIST, 0, (LPARAM)il.Detach());
// Load hot bitmap and set in toolbar
if (nIdHot) {
VERIFY(il.Create(nIdHot, cx, 0, clrBkgnd));
tb.SendMessage(TB_SETHOTIMAGELIST, 0, (LPARAM)il.Detach());
}
// Load disabled bitmap and set in toolbar
if (nIdDisab) {
VERIFY(il.Create(nIdDisab, cx, 0, clrBkgnd));
tb.SendMessage(TB_SETDISABLEDIMAGELIST, 0, (LPARAM)il.Detach());
}
}
mainfrm.cpp
////////////////////////////////////////////////////////////////
// 1998 Microsoft Systems Journal.
// If this program works, it was written by Paul DiLascia.
// If not, I don't know who wrote it.
//
#include "StdAfx.h"
#include "HTBTest.h"
#include "MainFrm.h"
#include "hottb.h"
#ifdef _DEBUG
#define new DEBUG_NEW
#undef THIS_FILE
static char THIS_FILE[] = __FILE__;
#endif
IMPLEMENT_DYNAMIC(CMainFrame, CFrameWnd)
BEGIN_MESSAGE_MAP(CMainFrame, CFrameWnd)
//{{AFX_MSG_MAP(CMainFrame)
ON_WM_CREATE()
ON_COMMAND(ID_GO_BACK, OnNotImplemented)
ON_COMMAND(ID_GO_FORWARD, OnNotImplemented)
ON_COMMAND(ID_VIEW_STOP, OnNotImplemented)
ON_COMMAND(ID_VIEW_REFRESH, OnNotImplemented)
ON_COMMAND(ID_GO_START_PAGE, OnNotImplemented)
ON_COMMAND(ID_GO_SEARCH_THE_WEB, OnNotImplemented)
ON_COMMAND(ID_FAVORITES_DROPDOWN, OnNotImplemented)
ON_COMMAND(ID_FILE_PRINT, OnNotImplemented)
ON_COMMAND(ID_FONT_DROPDOWN, OnNotImplemented)
//}}AFX_MSG_MAP
END_MESSAGE_MAP()
static UINT BASED_CODE indicators[] = {
ID_SEPARATOR, // status line indicator
ID_INDICATOR_CAPS,
ID_INDICATOR_NUM,
ID_INDICATOR_SCRL,
};
CMainFrame::CMainFrame()
{
}
CMainFrame::~CMainFrame()
{
}
#ifndef TB_SETEXTENDEDSTYLE
// from newer versions of commctrl.h
#define TB_SETEXTENDEDSTYLE (WM_USER + 84) // For TBSTYLE_EX_*
#define TBSTYLE_EX_DRAWDDARROWS 0x00000001
#endif
const NBUTTONS = 9;
// This table is used to load the buttons
// One table is worth a thousand lines of code (well, a lot, anyway)
// Use tables!!!
//
static struct {
UINT id; // command ID
UINT style; // button style
UINT iImage; // index of image in normal/hot bitmaps
} Buttons[NBUTTONS] = {
// command ID button style image index
{ ID_GO_BACK, TBSTYLE_BUTTON, 0 },
{ ID_GO_FORWARD, TBSTYLE_BUTTON, 1 },
{ ID_VIEW_STOP, TBSTYLE_BUTTON, 2 },
{ ID_VIEW_REFRESH, TBSTYLE_BUTTON, 3 },
{ ID_GO_START_PAGE, TBSTYLE_BUTTON, 4 },
{ ID_GO_SEARCH_THE_WEB, TBSTYLE_BUTTON, 5 },
{ ID_FAVORITES_DROPDOWN, TBSTYLE_BUTTON | TBSTYLE_DROPDOWN, 6 },
{ ID_FILE_PRINT, TBSTYLE_BUTTON, 7 },
{ ID_FONT_DROPDOWN, TBSTYLE_BUTTON | TBSTYLE_DROPDOWN, 8 }
};
int CMainFrame::OnCreate(LPCREATESTRUCT lpCreateStruct)
{
if (CFrameWnd::OnCreate(lpCreateStruct) == -1)
return -1;
// Create toolbar--but don't load it
if (!m_wndToolBar.Create(this)) {
TRACE0("Failed to create toolbar\n");
return -1; // fail to create
}
// Use handy class to set up cold/hot toolbar button bitmaps
CHotToolBarSetup htb;
htb.SetupHotToolBar(m_wndToolBar,
IDB_COLDTOOLBAR, // ID of bitmap for "normal" buttons
IDB_HOTTOOLBAR, // ID of bitmap for "hot" buttons
0, // ID of bitmap for disabled buttons
22, // width of one button in bitmap
RGB(255, 0, 255)); // background color
// for dropdown arrows--note: they are not implemented
m_wndToolBar.SendMessage(TB_SETEXTENDEDSTYLE, 0, TBSTYLE_EX_DRAWDDARROWS);
// Add toolbar buttons since I'm not using LoadToolBar
m_wndToolBar.SetButtons(NULL, NBUTTONS);
for (int i=0; i<NBUTTONS; i++) {
m_wndToolBar.SetButtonInfo(i,
Buttons[i].id, // command id
Buttons[i].style, // buttons style
Buttons[i].iImage); // index of image in bitmap
}
// Rest is normal main frame stuff...
//
if (!m_wndStatusBar.Create(this) ||
!m_wndStatusBar.SetIndicators(indicators,
sizeof(indicators)/sizeof(UINT))) {
TRACE("Failed to create status bar\n");
return -1; // fail to create
}
m_wndToolBar.SetBarStyle(m_wndToolBar.GetBarStyle() |
CBRS_TOOLTIPS | CBRS_FLYBY | CBRS_SIZE_DYNAMIC);
return 0;
}
void CMainFrame::OnNotImplemented()
{
MessageBeep(0);
}