////////////////////////////////////////////////////////////////
// OneDlg 1997 Microsoft Systems Journal.
// If this program works, it was written by Paul DiLascia.
// If not, I don't know who wrote it.
//
#include <afxwin.h> // MFC core and standard components
#include <afxext.h> // MFC extensions
#include <afxpriv.h> // for WM_KICKIDLE
#include "resource.h"
#ifdef _DEBUG
#define new DEBUG_NEW
#undef THIS_FILE
static char THIS_FILE[] = __FILE__;
#endif
const LRESULT OpenSesame = 0x1234abcd;
const MY_WM_PING = WM_USER;
//////////////////
// Dialog class that alters the TAB sequence and handles the RETURN key.
//
class CMyDialog : public CDialog {
public:
CMyDialog();
~CMyDialog();
DECLARE_MESSAGE_MAP()
afx_msg LRESULT OnPing(WPARAM, LPARAM);
};
////////////////////////////////////////////////////////////////
// Application class
//
class CApp : public CWinApp {
public:
CApp() { }
virtual BOOL InitInstance();
} theApp;
/////////////////
// Initialize: just run the dialog and quit.
//
BOOL CApp::InitInstance()
{
TRACE("previous instance=%p\n", m_hPrevInstance); // always NULL
CWnd *pWnd = CWnd::FindWindow(NULL, "Only One Instance Dialog");
if (pWnd && pWnd->SendMessage(MY_WM_PING)==OpenSesame) {
// My dialog already exists: activate it
pWnd->SetForegroundWindow();
} else {
// Dialog doesn't exist
CMyDialog dlg;
dlg.DoModal();
}
return FALSE;
}
////////////////////////////////////////////////////////////////
// CMyDialog
//
BEGIN_MESSAGE_MAP(CMyDialog, CDialog)
ON_MESSAGE(MY_WM_PING, OnPing)
END_MESSAGE_MAP()
//////////////////
// Construct dialog: set everything to zero or NULL.
//
CMyDialog::CMyDialog() : CDialog(IDD_DIALOG1)
{
}
CMyDialog::~CMyDialog()
{
}
LRESULT CMyDialog::OnPing(WPARAM, LPARAM)
{
return OpenSesame;
}
Figure 5
FlatBar
FlatBar.h
////////////////////////////////////////////////////////////////
// CFlatToolBar 1997 Microsoft Systems Journal.
// If this code works, it was written by Paul DiLascia.
// If not, I don't know who wrote it.
// This code compiles with Visual C++ 5.0 on Windows 95
//
#ifndef TBSTYLE_FLAT
#define TBSTYLE_FLAT 0x0800 // (in case you don't have the new commctrl.h)
#endif
//////////////////
// "Flat" style tool bar. Use instead of CToolBar in your CMainFrame
// or other window to create a tool bar with the flat look.
//
// CFlatToolBar fixes the display bug described in the article. It also has
// overridden load functions that modify the style to TBSTYLE_FLAT. If you
// don't create your toolbar by loading it from a resource, you should call
// ModifyStyle(0, TBSTYLE_FLAT) yourself.
//
class CFlatToolBar : public CToolBar {
public:
BOOL LoadToolBar(LPCTSTR lpszResourceName);
BOOL LoadToolBar(UINT nIDResource)
{ return LoadToolBar(MAKEINTRESOURCE(nIDResource)); }
protected:
DECLARE_DYNAMIC(CFlatToolBar)
virtual void OnUpdateCmdUI(CFrameWnd* pTarget, BOOL bDisableIfNoHndler);
DECLARE_MESSAGE_MAP()
afx_msg void OnWindowPosChanging(LPWINDOWPOS lpWndPos);
};
FlatBar.cpp
////////////////////////////////////////////////////////////////
// CFlatToolBar 1997 Microsoft Systems Journal.
// If this code works, it was written by Paul DiLascia.
// If not, I don't know who wrote it.
//
#include "StdAfx.h"
#include "FlatBar.h"
#ifdef _DEBUG
#define new DEBUG_NEW
#undef THIS_FILE
static char THIS_FILE[] = __FILE__;
#endif
////////////////////////////////////////////////////////////////
// CFlatToolBar--does flat tool bar in MFC.
//
IMPLEMENT_DYNAMIC(CFlatToolBar, CToolBar)
BEGIN_MESSAGE_MAP(CFlatToolBar, CToolBar)
ON_WM_WINDOWPOSCHANGING()
ON_WM_WINDOWPOSCHANGED()
END_MESSAGE_MAP()
////////////////
// Load override modifies the style after loading toolbar.
//
BOOL CFlatToolBar::LoadToolBar(LPCTSTR lpszResourceName)
{
if (!CToolBar::LoadToolBar(lpszResourceName))
return FALSE;
ModifyStyle(0, TBSTYLE_FLAT); // make it flat
return TRUE;
}
//#define ILLUSTRATE_DISPLAY_BUG // remove comment to see the bug
//////////////////
// MFC doesn't handle moving a TBSTYLE_FLAT toolbar correctly.
// The simplest way to fix it is to repaint the old rectangle and
// toolbar itself whenever the toolbar moves.
//
void CFlatToolBar::OnWindowPosChanging(LPWINDOWPOS lpwp)
{
CToolBar::OnWindowPosChanging(lpwp);
#ifndef ILLUSTRATE_DISPLAY_BUG
if (!(lpwp->flags & SWP_NOMOVE)) { // if moved:
CRect rc; // Fill rectangle with..
GetWindowRect(&rc); // ..my (toolbar) rectangle.
CWnd* pParent = GetParent(); // get parent (dock bar/frame) win..
pParent->ScreenToClient(&rc); // .. and convert to parent coords
// Ask parent window to paint the area beneath my old location.
// Typically, this is just solid grey. The area won't get painted until
// I send WM_NCPAINT after the move, in OnWindowPosChanged below.
//
pParent->InvalidateRect(&rc); // paint old rectangle
}
#endif
}
//////////////////
// Now toolbar has moved: repaint old area
//
void CFlatToolBar::OnWindowPosChanged(LPWINDOWPOS lpwp)
{
CToolBar::OnWindowPosChanged(lpwp);
#ifndef ILLUSTRATE_DISPLAY_BUG
if (!(lpwp->flags & SWP_NOMOVE)) { // if moved:
// Now paint my non-client area at the new location.
// This is the extra bit of border space surrounding the buttons.
// Without this, you will still have a partial display bug (try it!)
//
SendMessage(WM_NCPAINT);
}
#endif
}
////////////////////////////////////////////////////////////////
// The following stuff is to make the command update UI mechanism
// work properly for flat tool bars. The main idea is to convert
// a "checked" button state into a "pressed" button state. Changed
// lines marked with "PD"
////////////////
// The following class was copied from BARTOOL.CPP in the MFC source.
// All I changed was SetCheck--PD.
//
class CFlatOrCoolBarCmdUI : public CCmdUI // class private to this file !
{
public: // re-implementations only
virtual void Enable(BOOL bOn);
virtual void SetCheck(int nCheck);
virtual void SetText(LPCTSTR lpszText);
};
void CFlatOrCoolBarCmdUI::Enable(BOOL bOn)
{
m_bEnableChanged = TRUE;
CToolBar* pToolBar = (CToolBar*)m_pOther;
ASSERT(pToolBar != NULL);
ASSERT_KINDOF(CToolBar, pToolBar);
ASSERT(m_nIndex < m_nIndexMax);
UINT nNewStyle = pToolBar->GetButtonStyle(m_nIndex) & ~TBBS_DISABLED;
if (!bOn)
{
nNewStyle |= TBBS_DISABLED;
// WINBUG: If a button is currently pressed and then is disabled
// COMCTL32.DLL does not unpress the button, even after the mouse
// button goes up! We work around this bug by forcing TBBS_PRESSED
// off when a button is disabled.
nNewStyle &= ~TBBS_PRESSED;
}
ASSERT(!(nNewStyle & TBBS_SEPARATOR));
pToolBar->SetButtonStyle(m_nIndex, nNewStyle);
}
// Take your pick:
//#define MYTBBS_CHECKED TBBS_CHECKED // use "checked" state
#define MYTBBS_CHECKED TBBS_PRESSED // use pressed state
//////////////////
// This is the only function that has changed: instead of TBBS_CHECKED,
// I use TBBS_PRESSED--PD
//
void CFlatOrCoolBarCmdUI::SetCheck(int nCheck)
{
ASSERT(nCheck >= 0 && nCheck <= 2); // 0=>off, 1=>on, 2=>indeterminate
CToolBar* pToolBar = (CToolBar*)m_pOther;
ASSERT(pToolBar != NULL);
ASSERT_KINDOF(CToolBar, pToolBar);
ASSERT(m_nIndex < m_nIndexMax);
UINT nOldStyle = pToolBar->GetButtonStyle(m_nIndex); // PD
UINT nNewStyle = nOldStyle &
~(MYTBBS_CHECKED | TBBS_INDETERMINATE); // PD
if (nCheck == 1)
nNewStyle |= MYTBBS_CHECKED; // PD
else if (nCheck == 2)
nNewStyle |= TBBS_INDETERMINATE;
// Following is to fix display bug for TBBS_CHECKED:
// If new state is unchecked, repaint--but only if style actually changing.
// (Otherwise will end up with flicker)
//
if (nNewStyle != nOldStyle) {
ASSERT(!(nNewStyle & TBBS_SEPARATOR));
pToolBar->SetButtonStyle(m_nIndex, nNewStyle);
pToolBar->Invalidate();
}
}
void CFlatOrCoolBarCmdUI::SetText(LPCTSTR)
{
// ignore for now, but you should really set the text
}
//////////////////
// This function is mostly copied from CToolBar/BARTOOL.CPP. The only thing
// that's different is I instantiated a CFlatOrCoolBarCmdUI instead of
// CToolCmdUI.
//
void CFlatToolBar::OnUpdateCmdUI(CFrameWnd* pTarget, BOOL bDisableIfNoHndler)
{
CFlatOrCoolBarCmdUI state; // <<<< This is the only line that's different--PD
state.m_pOther = this;
state.m_nIndexMax = (UINT)DefWindowProc(TB_BUTTONCOUNT, 0, 0);
for (state.m_nIndex = 0; state.m_nIndex < state.m_nIndexMax; state.m_nIndex++)
{
// get button state
TBBUTTON button;
VERIFY(DefWindowProc(TB_GETBUTTON, state.m_nIndex, (LPARAM)&button));
// TBSTATE_ENABLED == TBBS_DISABLED so invert it
button.fsState ^= TBSTATE_ENABLED;
state.m_nID = button.idCommand;
// ignore separators
if (!(button.fsStyle & TBSTYLE_SEP))
{
// allow the toolbar itself to have update handlers
if (CWnd::OnCmdMsg(state.m_nID, CN_UPDATE_COMMAND_UI, &state, NULL))
continue;
// allow the owner to process the update
state.DoUpdate(pTarget, bDisableIfNoHndler);
}
}
// update the dialog controls added to the toolbar
UpdateDialogControls(pTarget, bDisableIfNoHndler);
}
FBApp.cpp
////////////////////////////////////////////////////////////////
// FBApp 1997 Microsoft Systems Journal.
// If this program works, it was written by Paul DiLascia.
// If not, I don't know who wrote it.
//
// FBApp illustrates how to create a flat style tool bar in an MFC app.
// Compiles with Visual C++ 5.0 or later, under Windows 95.
// See FlatBar.cpp for the good stuff.
#include "StdAfx.h"
#include "Resource.h"
#include "FlatBar.h"
//////////////////
// Standard do-nothing application class
//
class CMyApp : public CWinApp {
public:
DECLARE_DYNAMIC(CMyApp)
virtual BOOL InitInstance();
protected:
DECLARE_MESSAGE_MAP()
afx_msg void OnAppAbout();
};
////////////////
// Standard MFC main frame window uses CFlatToolBar instead of CToolBar
//
class CMainFrame : public CFrameWnd {
public:
virtual ~CMainFrame();
//protected:
DECLARE_DYNCREATE(CMainFrame)
CStatusBar m_wndStatusBar;
CFlatToolBar m_wndToolBar; // <<<< flat tool bar
CMainFrame();
afx_msg int OnCreate(LPCREATESTRUCT lpCreateStruct);
DECLARE_MESSAGE_MAP()
};
/////////////////
// Standard do-nothing doc
//
class CMyDoc : public CDocument {
public:
virtual void Serialize(CArchive& ar);
DECLARE_DYNCREATE(CMyDoc)
};
/////////////////
// Standard do-nothing view
//
class CMyView : public CView {
BOOL m_bRed; // whether to paint red
public:
DECLARE_DYNCREATE(CMyView)
CMyView();
virtual void OnDraw(CDC* pDC); // overridden to draw this view
DECLARE_MESSAGE_MAP()
afx_msg void OnViewRed(); // handle View Red command..
afx_msg void OnUpdateViewRed(CCmdUI* pCmdUI); // and UI update
};
#ifdef _DEBUG
#define new DEBUG_NEW
#undef THIS_FILE
static char THIS_FILE[] = __FILE__;
#endif
////////////////////////////////////////////////////////////////
// CMyApp
//
BEGIN_MESSAGE_MAP(CMyApp, CWinApp)
ON_COMMAND(ID_APP_ABOUT, OnAppAbout)
ON_COMMAND(ID_FILE_NEW, CWinApp::OnFileNew)
ON_COMMAND(ID_FILE_OPEN, CWinApp::OnFileOpen)
END_MESSAGE_MAP()
IMPLEMENT_DYNAMIC(CMyApp, CWinApp)
CMyApp theApp;
BOOL CMyApp::InitInstance()
{
CSingleDocTemplate* pDocTemplate;
pDocTemplate = new CSingleDocTemplate(
IDR_MAINFRAME,
RUNTIME_CLASS(CMyDoc),
RUNTIME_CLASS(CMainFrame), // main SDI frame window
RUNTIME_CLASS(CMyView));
AddDocTemplate(pDocTemplate);
// Parse command line for standard shell commands, DDE, file open
CCommandLineInfo cmdInfo;
ParseCommandLine(cmdInfo);
// Dispatch commands specified on the command line
return ProcessShellCommand(cmdInfo);
}
void CMyApp::OnAppAbout()
{
CDialog(IDD_ABOUTBOX).DoModal();
}
////////////////////////////////////////////////////////////////
// CMainFrame
//
IMPLEMENT_DYNCREATE(CMainFrame, CFrameWnd)
BEGIN_MESSAGE_MAP(CMainFrame, CFrameWnd)
ON_WM_CREATE()
END_MESSAGE_MAP()
static UINT indicators[] = {
ID_SEPARATOR, // status line indicator
ID_INDICATOR_CAPS,
ID_INDICATOR_NUM,
ID_INDICATOR_SCRL,
};
CMainFrame::CMainFrame()
{
}
CMainFrame::~CMainFrame()
{
}
int CMainFrame::OnCreate(LPCREATESTRUCT lpCreateStruct)
{
if (CFrameWnd::OnCreate(lpCreateStruct) == -1)
return -1;
if (!m_wndToolBar.Create(this) ||
!m_wndToolBar.LoadToolBar(IDR_MAINFRAME)) {
TRACE0("Failed to create toolbar\n");
return -1; // fail to create
}
// m_wndToolBar.ModifyStyle(0, TBSTYLE_FLAT);
if (!m_wndStatusBar.Create(this) ||
!m_wndStatusBar.SetIndicators(indicators,
sizeof(indicators)/sizeof(UINT))) {
TRACE0("Failed to create status bar\n");
return -1; // fail to create
}
// TODO: Remove this if you don't want tool tips or a resizeable toolbar
m_wndToolBar.SetBarStyle(m_wndToolBar.GetBarStyle() |
CBRS_TOOLTIPS | CBRS_FLYBY | CBRS_SIZE_DYNAMIC);
// TODO: Delete these three lines if you don't want the toolbar to
// be dockable
m_wndToolBar.EnableDocking(CBRS_ALIGN_ANY);
EnableDocking(CBRS_ALIGN_ANY);
DockControlBar(&m_wndToolBar);
return 0;
}
////////////////////////////////////////////////////////////////
// CMyView
//
BEGIN_MESSAGE_MAP(CMyView, CView)
ON_COMMAND(ID_VIEW_RED, OnViewRed)
ON_UPDATE_COMMAND_UI(ID_VIEW_RED, OnUpdateViewRed)
END_MESSAGE_MAP()
IMPLEMENT_DYNCREATE(CMyView, CView)
CMyView::CMyView()
{
m_bRed = FALSE;
}
void CMyView::OnDraw(CDC* pDC)
{
if (m_bRed) {
CRect rc;
GetClientRect(&rc);
CBrush b(RGB(255,0,0)); // red brush
CBrush* pOldBrush = pDC->SelectObject(&b);
pDC->PatBlt(0,0,rc.Width(),rc.Height(),PATCOPY);
pDC->SelectObject(pOldBrush);
}
}
void CMyView::OnViewRed()
{
m_bRed = !m_bRed;
Invalidate();
}
void CMyView::OnUpdateViewRed(CCmdUI* pCmdUI)
{
pCmdUI->SetCheck(m_bRed);
}
////////////////////////////////////////////////////////////////
// CMyDoc
//
IMPLEMENT_DYNCREATE(CMyDoc, CDocument)
void CMyDoc::Serialize(CArchive& ar)
{
if (ar.IsStoring()) {
} else {
}
}
Figure 6
CoolBar
CoolBar.h
////////////////////////////////////////////////////////////////
// CCoolBar 1997 Microsoft Systems Journal.
// If this program 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
//////////////////
// CCoolBar encapsulates IE 4.0 common coolbar for MFC.
//
class CCoolBar : public CControlBar {
protected:
DECLARE_DYNAMIC(CCoolBar)
public:
CCoolBar();
virtual ~CCoolBar();
BOOL Create(CWnd* pParentWnd, DWORD dwStyle,
DWORD dwAfxBarStyle = CBRS_ALIGN_TOP,
UINT nID = AFX_IDW_TOOLBAR);
// Message wrappers
BOOL GetBarInfo(LPREBARINFO lp)
{ ASSERT(::IsWindow(m_hWnd));
return (BOOL)SendMessage(RB_GETBARINFO, 0, (LPARAM)lp); }
BOOL SetBarInfo(LPREBARINFO lp)
{ ASSERT(::IsWindow(m_hWnd));
return (BOOL)SendMessage(RB_SETBARINFO, 0, (LPARAM)lp); }
BOOL GetBandInfo(int iBand, LPREBARBANDINFO lp)
{ ASSERT(::IsWindow(m_hWnd));
return (BOOL)SendMessage(RB_GETBANDINFO, iBand, (LPARAM)lp); }
BOOL SetBandInfo(int iBand, LPREBARBANDINFO lp)
{ ASSERT(::IsWindow(m_hWnd));
return (BOOL)SendMessage(RB_SETBANDINFO, iBand, (LPARAM)lp); }
BOOL InsertBand(int iWhere, LPREBARBANDINFO lp)
{ ASSERT(::IsWindow(m_hWnd));
return (BOOL)SendMessage(RB_INSERTBAND, (WPARAM)iWhere, (LPARAM)lp); }
BOOL DeleteBand(int nWhich)
{ ASSERT(::IsWindow(m_hWnd));
return (BOOL)SendMessage(RB_INSERTBAND, (WPARAM)nWhich); }
int GetBandCount()
{ ASSERT(::IsWindow(m_hWnd));
return (int)SendMessage(RB_GETBANDCOUNT); }
int GetRowCount()
{ ASSERT(::IsWindow(m_hWnd));
return (int)SendMessage(RB_GETROWCOUNT); }
int GetRowHeight(int nWhich)
{ ASSERT(::IsWindow(m_hWnd));
return (int)SendMessage(RB_GETROWHEIGHT, (WPARAM)nWhich); }
protected:
// new virtual functions you must/can override
virtual BOOL OnCreateBands() = 0; // return -1 if failed
virtual void OnHeightChange(const CRect& rcNew);
// CControlBar Overrides
virtual CSize CalcFixedLayout(BOOL bStretch, BOOL bHorz);
virtual CSize CalcDynamicLayout(int nLength, DWORD nMode);
virtual void OnUpdateCmdUI(CFrameWnd* pTarget, BOOL bDisableIfNoHndler);
// message handlers
DECLARE_MESSAGE_MAP()
afx_msg int OnCreate(LPCREATESTRUCT lpcs);
afx_msg void OnPaint();
afx_msg void OnHeigtChange(NMHDR* pNMHDR, LRESULT* pRes);
afx_msg BOOL OnEraseBkgnd(CDC* pDC);
};
//////////////////
// Specialized CToolBar fixes display problems in MFC.
//
class CCoolToolBar : public CToolBar {
public:
CCoolToolBar();
virtual ~CCoolToolBar();
protected:
DECLARE_DYNAMIC(CCoolToolBar)
virtual void OnUpdateCmdUI(CFrameWnd* pTarget, BOOL bDisableIfNoHndler);
DECLARE_MESSAGE_MAP()
afx_msg BOOL OnNcCreate(LPCREATESTRUCT lpcs);
afx_msg void OnNcPaint();
afx_msg void OnPaint();
afx_msg void OnNcCalcSize(BOOL, NCCALCSIZE_PARAMS*);
};
//////////////////
// Programmer-friendly REBARINFO initializes itself
//
class CRebarInfo : public REBARINFO {
public:
CRebarInfo() {
memset(this, 0, sizeof(REBARINFO));
cbSize = sizeof(REBARINFO);
}
};
//////////////////
// Programmer-friendly REBARBANDINFO initializes itself
//
class CRebarBandInfo : public REBARBANDINFO {
public:
CRebarBandInfo() {
memset(this, 0, sizeof(REBARBANDINFO));
cbSize = sizeof(REBARBANDINFO);
}
};
CbApp.cpp
//included in the source code file
CoolBar.cpp
////////////////////////////////////////////////////////////////
// CCoolBar 1997 Microsoft Systems Journal.
// If this program works, it was written by Paul DiLascia.
// If not, I don't know who wrote it.
// CCoolBar implements coolbars for MFC.
//
#include "StdAfx.h"
#include "CoolBar.h"
#ifdef _DEBUG
#define new DEBUG_NEW
#undef THIS_FILE
static char THIS_FILE[] = __FILE__;
#endif
IMPLEMENT_DYNAMIC(CCoolBar, CControlBar)
BEGIN_MESSAGE_MAP(CCoolBar, CControlBar)
//{{AFX_MSG_MAP(CCoolBar)
ON_WM_CREATE()
ON_WM_PAINT()
ON_WM_ERASEBKGND()
ON_NOTIFY_REFLECT(RBN_HEIGHTCHANGE, OnHeigtChange)
//}}AFX_MSG_MAP
END_MESSAGE_MAP()
CCoolBar::CCoolBar()
{
}
CCoolBar::~CCoolBar()
{
}
//////////////////
// Create coolbar
//
BOOL CCoolBar::Create(CWnd* pParentWnd, DWORD dwStyle,
DWORD dwAfxBarStyle, UINT nID)
{
ASSERT_VALID(pParentWnd); // must have a parent
// dynamic coolbar not supported
dwStyle &= ~CBRS_SIZE_DYNAMIC;
// save the style (this code copied from MFC--probably unecessary)
m_dwStyle = dwAfxBarStyle;
if (nID == AFX_IDW_TOOLBAR)
m_dwStyle |= CBRS_HIDE_INPLACE;
// MFC requires these:
dwStyle |= CCS_NODIVIDER|CCS_NOPARENTALIGN;
// Initialize cool common controls
static BOOL bInit = FALSE;
if (!bInit) {
INITCOMMONCONTROLSEX sex;
sex.dwSize = sizeof(INITCOMMONCONTROLSEX);
sex.dwICC = ICC_COOL_CLASSES;
InitCommonControlsEx(&sex);
bInit = TRUE;
}
// Create the cool bar using style and parent.
CRect rc;
rc.SetRectEmpty();
return CWnd::CreateEx(WS_EX_TOOLWINDOW, REBARCLASSNAME, NULL,
dwStyle, rc, pParentWnd, nID);
}
//////////////////
// Handle WM_CREATE. Call virtual fn so derived class can create bands.
//
int CCoolBar::OnCreate(LPCREATESTRUCT lpcs)
{
return CControlBar::OnCreate(lpcs) == -1 ? -1
: OnCreateBands(); // call pure virtual fn to create bands
}
//////////////////
// Standard UI handler updates any controls in the coolbar.
//
void CCoolBar::OnUpdateCmdUI(CFrameWnd* pTarget, BOOL bDisableIfNoHndler)
{
UpdateDialogControls(pTarget, bDisableIfNoHndler);
}
/////////////////
// These two functions are called by MFC to calculate the layout of
// the main frame. Since CCoolBar is not designed to be dynamic, the
// size is always fixed, and the same as the window size.
//
CSize CCoolBar::CalcDynamicLayout(int nLength, DWORD dwMode)
{
return CalcFixedLayout(dwMode & LM_STRETCH, dwMode & LM_HORZ);
}
CSize CCoolBar::CalcFixedLayout(BOOL bStretch, BOOL bHorz)
{
CRect rc;
GetWindowRect(&rc);
CSize sz(bHorz && bStretch ? 0x7FFF : rc.Width(),
!bHorz && bStretch ? 0x7FFF : rc.Height());
return sz;
}
//////////////////
// Low-level height-changed handler just passes to virtual fn w/nicer args.
//
void CCoolBar::OnHeigtChange(NMHDR* pNMHDR, LRESULT* pRes)
{
CRect rc;
GetWindowRect(&rc);
OnHeightChange(rc);
*pRes = 0; // why not?
}
//////////////////
// Height changed:
// Notify the parent frame by posting a WM_SIZE message. This will cause the
// frame to do RecalcLayout. The message must be posted, not sent, because
// the coolbar could send RBN_HEIGHTCHANGE while the user is sizing, which
// would be in the middle of a CFrame::RecalcLayout, and RecalcLayout doesn't
// let you re-enter it. Posting guarantees that CFrameWnd can finish any recalc
// it may be in the middle of before handling my posted WM_SIZE. Very
// confusing.
//
void CCoolBar::OnHeightChange(const CRect& rcNew)
{
CWnd* pParent = GetParent();
CRect rc;
pParent->GetWindowRect(&rc);
pParent->PostMessage(WM_SIZE, 0, MAKELONG(rc.Width(),rc.Height()));
}
void CCoolBar::OnPaint()
{
Default(); // bypass CControlBar
}
BOOL CCoolBar::OnEraseBkgnd(CDC* pDC)
{
return (BOOL)Default(); // bypass CControlBar
}
////////////////////////////////////////////////////////////////
// Special tool bar to use in cool bars.
// Mainly, it overides yukky stuff in CToolBar.
//
IMPLEMENT_DYNAMIC(CCoolToolBar, CToolBar)
BEGIN_MESSAGE_MAP(CCoolToolBar, CToolBar)
ON_WM_NCCREATE()
ON_WM_NCPAINT()
ON_WM_PAINT()
ON_WM_NCCALCSIZE()
END_MESSAGE_MAP()
CCoolToolBar::CCoolToolBar()
{
}
CCoolToolBar::~CCoolToolBar()
{
}
//////////////////
// Make the parent frame my owner. This is important for status bar
// prompts to work. Note that when you create the CCoolToolBar in
// CYourCoolBar::OnCreateBands, you must also set CBRS_FLYBY in the
// the CCoolToolBar style!
//
BOOL CCoolToolBar::OnNcCreate(LPCREATESTRUCT lpcs)
{
CFrameWnd* pFrame = GetParentFrame();
ASSERT_VALID(pFrame);
SetOwner(pFrame);
return CToolBar::OnNcCreate(lpcs);
}
void CCoolToolBar::OnNcPaint()
{
Default(); // bypass CToolBar/CControlBar
}
void CCoolToolBar::OnPaint()
{
Default(); // bypass CToolBar/CControlBar
}
void CCoolToolBar::OnNcCalcSize(BOOL, NCCALCSIZE_PARAMS*)
{
Default(); // bypass CToolBar/CControlBar
}
////////////////////////////////////////////////////////////////
// The following stuff is to make the command update UI mechanism
// work properly for flat tool bars. The main idea is to convert
// a "checked" button state into a "pressed" button state. Changed
// lines marked with "PD"
////////////////
// The following class was copied from BARTOOL.CPP in the MFC source.
// All I changed was SetCheck--PD.
//
class CFlatOrCoolBarCmdUI : public CCmdUI // class private to this file !
{
public: // re-implementations only
virtual void Enable(BOOL bOn);
virtual void SetCheck(int nCheck);
virtual void SetText(LPCTSTR lpszText);
};
void CFlatOrCoolBarCmdUI::Enable(BOOL bOn)
{
m_bEnableChanged = TRUE;
CToolBar* pToolBar = (CToolBar*)m_pOther;
ASSERT(pToolBar != NULL);
ASSERT_KINDOF(CToolBar, pToolBar);
ASSERT(m_nIndex < m_nIndexMax);
UINT nNewStyle = pToolBar->GetButtonStyle(m_nIndex) & ~TBBS_DISABLED;
if (!bOn)
{
nNewStyle |= TBBS_DISABLED;
// WINBUG: If a button is currently pressed and then is disabled
// COMCTL32.DLL does not unpress the button, even after the mouse
// button goes up! We work around this bug by forcing TBBS_PRESSED
// off when a button is disabled.
nNewStyle &= ~TBBS_PRESSED;
}
ASSERT(!(nNewStyle & TBBS_SEPARATOR));
pToolBar->SetButtonStyle(m_nIndex, nNewStyle);
}
//////////////////
// This is the only function that has changed: instead of TBBS_CHECKED,
// I use TBBS_PRESSED--PD
//
void CFlatOrCoolBarCmdUI::SetCheck(int nCheck)
{
ASSERT(nCheck >= 0 && nCheck <= 2); // 0=>off, 1=>on, 2=>indeterminate
CToolBar* pToolBar = (CToolBar*)m_pOther;
ASSERT(pToolBar != NULL);
ASSERT_KINDOF(CToolBar, pToolBar);
ASSERT(m_nIndex < m_nIndexMax);
UINT nOldStyle = pToolBar->GetButtonStyle(m_nIndex); // PD
UINT nNewStyle = nOldStyle &
~(TBBS_CHECKED | TBBS_PRESSED | TBBS_INDETERMINATE); // PD
if (nCheck == 1)
nNewStyle |= TBBS_PRESSED; // PD
else if (nCheck == 2)
nNewStyle |= TBBS_INDETERMINATE;
else if (nCheck == 3)
nNewStyle |= TBBS_CHECKED; // PD
// Following is to fix display bug for TBBS_CHECKED:
// If new state is unchecked, repaint--but only if style actually changing.
// (Otherwise will end up with flicker)
//
if (nNewStyle != nOldStyle) {
ASSERT(!(nNewStyle & TBBS_SEPARATOR));
pToolBar->SetButtonStyle(m_nIndex, nNewStyle);
pToolBar->Invalidate();
}
}
void CFlatOrCoolBarCmdUI::SetText(LPCTSTR)
{
// ignore for now, but you should really set the text
}
//////////////////
// This function is mostly copied from CToolBar/BARTOOL.CPP. The only thing
// that's different is I instantiated a CFlatOrCoolBarCmdUI instead of
// CToolCmdUI.
//
void CCoolToolBar::OnUpdateCmdUI(CFrameWnd* pTarget, BOOL bDisableIfNoHndler)
{
CFlatOrCoolBarCmdUI state; // this is the only line that's different--PD
state.m_pOther = this;
state.m_nIndexMax = (UINT)DefWindowProc(TB_BUTTONCOUNT, 0, 0);
for (state.m_nIndex = 0; state.m_nIndex < state.m_nIndexMax; state.m_nIndex++)
{
// get button state
TBBUTTON button;
VERIFY(DefWindowProc(TB_GETBUTTON, state.m_nIndex, (LPARAM)&button));
// TBSTATE_ENABLED == TBBS_DISABLED so invert it
button.fsState ^= TBSTATE_ENABLED;
state.m_nID = button.idCommand;
// ignore separators
if (!(button.fsStyle & TBSTYLE_SEP))
{
// allow the toolbar itself to have update handlers
if (CWnd::OnCmdMsg(state.m_nID, CN_UPDATE_COMMAND_UI, &state, NULL))
continue;
// allow the owner to process the update
state.DoUpdate(pTarget, bDisableIfNoHndler);
}
}
// update the dialog controls added to the toolbar
UpdateDialogControls(pTarget, bDisableIfNoHndler);
}