Click here to Skip to main content
Click here to Skip to main content
Add your own
alternative version

A C++ implementation of Douglas-Peucker Line Approximation Algorithm

, 3 Mar 2003
DP Line approximation algorithm is a well-known method to approximate 2D lines. It is quite fast, O(nlog_2(n)) for a n-points line and can drastically compress a data curve. Here, a fully OOP implementation is given.
// ToolBarEx.cpp : implementation file
//

#include "stdafx.h"
#include "ToolBarEx.h"

#ifdef _DEBUG
#define new DEBUG_NEW
#undef THIS_FILE
static char THIS_FILE[] = __FILE__;
#endif

/////////////////////////////////////////////////////////////////////////////
// CToolBarEx

IMPLEMENT_DYNCREATE( CToolBarEx,CToolBar);

//Image sizes
const CSize CToolBarEx::m_szImageSmall( 16, 15 );
const CSize CToolBarEx::m_szImageLarge( 24, 24 );

const TextOptions CToolBarEx:: m_eInitialTextOptions =  toNoTextLabels;
const IconOptions CToolBarEx:: m_eInitialIconOptions =  ioSmallIcons;
								  


int CToolBarEx::m_nBarNumber = 0;
CCustomizeDialog*   CToolBarEx::m_pCustomizeDlg = NULL;
HHOOK               CToolBarEx::m_hCBTHook      = NULL;


#define STR_CUSTOMIZE  _T("&Customize...")


// for determining version of COMCTL32.DLL
#define VERSION_WIN4        MAKELONG(0, 4)
#define VERSION_IE3         MAKELONG(70, 4)
#define VERSION_IE4         MAKELONG(71, 4)
#define VERSION_IE401       MAKELONG(72, 4)
#define VERSION_IE5			MAKELONG(80, 5)
#define VERSION_IE5_2000    MAKELONG(81, 5)

struct AFX_DLLVERSIONINFO
{
	DWORD cbSize;
	DWORD dwMajorVersion;                   // Major version
	DWORD dwMinorVersion;                   // Minor version
	DWORD dwBuildNumber;                    // Build number
	DWORD dwPlatformID;                     // DLLVER_PLATFORM_*
};

typedef HRESULT (CALLBACK* AFX_DLLGETVERSIONPROC)(AFX_DLLVERSIONINFO *);

static int _ComCtlVersion = -1;

static DWORD AFXAPI _GetComCtlVersion()
{
	// return cached version if already determined...
	if (_ComCtlVersion != -1)
		return _ComCtlVersion;
	
	// otherwise determine comctl32.dll version via DllGetVersion
	HINSTANCE hInst = ::GetModuleHandleA("COMCTL32.DLL");
	ASSERT(hInst != NULL);
	AFX_DLLGETVERSIONPROC pfn;
	pfn = (AFX_DLLGETVERSIONPROC)GetProcAddress(hInst, "DllGetVersion");
	DWORD dwVersion = VERSION_WIN4;
	if (pfn != NULL)
	{
		AFX_DLLVERSIONINFO dvi;
		memset(&dvi, 0, sizeof(dvi));
		dvi.cbSize = sizeof(dvi);
		HRESULT hr = (*pfn)(&dvi);
		if (SUCCEEDED(hr))
		{
			ASSERT(dvi.dwMajorVersion <= 0xFFFF);
			ASSERT(dvi.dwMinorVersion <= 0xFFFF);
			dwVersion = MAKELONG(dvi.dwMinorVersion, dvi.dwMajorVersion);
		}
		
		TRACE(_T("Using CommCtl32.dll Ver:%d.%d.%d\n"),dvi.dwMajorVersion,dvi.dwMinorVersion,dvi.dwBuildNumber);

	}
	_ComCtlVersion = dwVersion;
	return dwVersion;
}


CToolBarEx::CToolBarEx()
{
	m_pControls		 = NULL;
	m_pDropButtons	 = NULL;		// list of drop-down buttons
//	m_bShowDropdownArrowWhenVertical = FALSE;
	m_bHideChildWndOnVertical=TRUE;

	m_clrBtnHilight=::GetSysColor(COLOR_BTNHILIGHT);
	m_clrBtnShadow=::GetSysColor(COLOR_BTNSHADOW);
	m_clrBtnFace  = ::GetSysColor(COLOR_BTNFACE);

	++m_nBarNumber; //Increase the Bar number

	CWinApp  *pApp = AfxGetApp();
	ASSERT_VALID(pApp);
	m_strValueName.Format( _T("ToolBarEx%d"), m_nBarNumber );
	m_strSubKey.Format( _T("Software\\%s\\%s\\Settings"),
		pApp->m_pszRegistryKey, pApp->m_pszProfileName );

    m_eTextOptions = toNone;    // no options selected yet
    m_eIconOptions = ioNone;    // no options selected yet

	m_nResButtons=0;

}

CToolBarEx::~CToolBarEx()
{
	while (m_pDropButtons)
	{
		CDropDownButtonInfo* pnext = m_pDropButtons->pNext;
		delete m_pDropButtons;
		m_pDropButtons = pnext;
	}

	if( m_pControls ) 
	{
		for( POSITION pos = m_pControls->GetHeadPosition() ; pos ; ) 
		{
			delete m_pControls->GetNext(pos);
		}

		delete m_pControls;
	}

}


BEGIN_MESSAGE_MAP(CToolBarEx, CToolBar)
	//{{AFX_MSG_MAP(CToolBarEx)
	ON_WM_CREATE()
	ON_WM_PAINT()
	ON_WM_SYSCOLORCHANGE()
	ON_WM_CONTEXTMENU()
	ON_WM_NCPAINT()
	//}}AFX_MSG_MAP
	ON_NOTIFY_REFLECT_EX(TBN_DROPDOWN,	 OnToolBarBtnDropDown)
	ON_NOTIFY_REFLECT(TBN_BEGINADJUST,	 OnToolBarBeginAdjust)
	ON_NOTIFY_REFLECT(TBN_CUSTHELP,		 OnToolBarCustomHelp)
	ON_NOTIFY_REFLECT(TBN_ENDADJUST,	 OnToolBarEndAdjust)
	ON_NOTIFY_REFLECT(TBN_GETBUTTONINFO, OnToolBarGetButtonInfo)
	ON_NOTIFY_REFLECT(TBN_QUERYDELETE,	 OnToolBarQueryDelete)
	ON_NOTIFY_REFLECT(TBN_QUERYINSERT,	 OnToolBarQueryInsert)
	ON_NOTIFY_REFLECT(TBN_RESET,		 OnToolBarReset)
	ON_NOTIFY_REFLECT(TBN_TOOLBARCHANGE, OnToolBarChange)
	ON_MESSAGE(TB_CUSTOMIZE, OnCustomize)
    ON_NOTIFY_REFLECT( TBN_INITCUSTOMIZE, OnInitCustomize )
 //   ON_NOTIFY_REFLECT( NM_CUSTOMDRAW , OnCustomDraw)

    // Saving and restoring toolbar
    ON_NOTIFY_REFLECT( TBN_SAVE, OnSave )
    ON_NOTIFY_REFLECT( TBN_RESTORE, OnRestore )
END_MESSAGE_MAP()


/////////////////////////////////////////////////////////////////////////////
// CToolBarEx message handlers

//////////////////////////////////////////////////////////////////////
// 1999 Kirk Stowell - Inserts a control into the toolbar at the given button id.
//
CWnd* CToolBarEx::InsertControl( CRuntimeClass* pClass, LPCTSTR lpszWindowName, CRect& rect, UINT nID, DWORD dwStyle )
{
	CWnd *pCtrl = NULL;
	
	if( pClass->IsDerivedFrom( RUNTIME_CLASS( CComboBox )))	// CComboBox control.
	{
		pCtrl = new CComboBox;

		ASSERT_VALID( pCtrl );

		if(((CComboBox*)pCtrl)->Create( WS_CHILD|WS_VISIBLE|dwStyle, rect, this, nID ) == FALSE )
		{
			delete pCtrl;
			return NULL;
		}
	}
	else if( pClass->IsDerivedFrom( RUNTIME_CLASS( CEdit )))		// CEdit control.
	{
		pCtrl = new CEdit;
							
		ASSERT_VALID( pCtrl );

		if(((CEdit*)pCtrl)->Create( WS_CHILD|WS_VISIBLE|dwStyle, rect, this, nID ) == FALSE )
		{
			delete pCtrl;
			return NULL;
		}
	}
	else if( pClass->IsDerivedFrom( RUNTIME_CLASS( CButton )))		// CButton control.
	{
		pCtrl = new CButton;

		ASSERT_VALID( pCtrl );

		if(((CButton*)pCtrl)->Create( lpszWindowName, WS_CHILD|WS_VISIBLE|dwStyle, rect, this, nID ) == FALSE )
		{
			delete pCtrl;
			return NULL;
		}
	}
	else if( pClass->IsDerivedFrom( RUNTIME_CLASS( CWnd )))			// CWnd object.
	{
		pCtrl = new CWnd;
		
		ASSERT_VALID( pCtrl );

#ifdef _UNICODE
		TCHAR szClassName[ 256 ];

		MultiByteToWideChar( CP_ACP,
							 MB_PRECOMPOSED,
							 pClass->m_lpszClassName,
							 -1,
							 szClassName,
							 255 );

		if(((CWnd*)pCtrl)->Create( szClassName, lpszWindowName, WS_CHILD|WS_VISIBLE|dwStyle, rect, this, nID ) == FALSE )
		{
			delete pCtrl;
			return NULL;
		}
#else
		if(((CWnd*)pCtrl)->Create( pClass->m_lpszClassName, lpszWindowName, WS_CHILD|WS_VISIBLE|dwStyle, rect, this, nID ) == FALSE )
		{
			delete pCtrl;
			return NULL;
		}
#endif
	}
	else	// An invalid object was passed in
	{
		ASSERT( FALSE );
		return NULL;
	}

	// if our object list has not been allocated, do it now...
	if( m_pControls == NULL )
	{
		m_pControls = new CObList();
		ASSERT( m_pControls );
	}

	// we have to remember this control, so we can delete it later
	m_pControls->AddTail( pCtrl );

	return InsertControl( pCtrl, rect, nID );
}

CWnd* CToolBarEx::InsertControl(CWnd* pCtrl, CRect & rect, UINT nID)
{
	ASSERT_VALID( pCtrl );
	ASSERT(IsWindow(pCtrl->m_hWnd));

	// make sure the id is valid, and set the button 
	// style for a seperator.
	int nIndex = CommandToIndex( nID ) ;
	if (nIndex>-1)
	{
		ASSERT( nIndex >= 0 );
		SetButtonInfo( nIndex, nID, TBBS_SEPARATOR, rect.Width());
		// insert the control into the toolbar.
		GetItemRect( nIndex, &rect );
		CRect rt;
		pCtrl->GetWindowRect(&rt);
		rect.top+=__max((rect.Height()-rt.Height())/2,0);	 //move to middle
		pCtrl->SetWindowPos(0, rect.left, rect.top, 0, 0,
			SWP_NOZORDER | SWP_NOACTIVATE | SWP_NOSIZE | SWP_NOCOPYBITS );
		pCtrl->SetFont( GetFont( ));

		BOOL bVert =  IsVertDocked(); //(m_dwStyle & CBRS_ORIENT_VERT) != 0;

		if (bVert && m_bHideChildWndOnVertical)
		{
		   	int nState=GetToolBarCtrl().GetState(nIndex);
		   	GetToolBarCtrl().SetState(nID,(nState | TBSTATE_HIDDEN));
			pCtrl->ShowWindow( SW_HIDE );
		}
		else
		{
		   	int nState=GetToolBarCtrl().GetState(nIndex);
		   	GetToolBarCtrl().SetState(nIndex,(nState & ~TBSTATE_HIDDEN));
			pCtrl->ShowWindow( SW_SHOW );
		}

	}
	else
	{
		pCtrl->ShowWindow( SW_HIDE);
	}

	ModifyStyle(0,WS_CLIPCHILDREN);
	return pCtrl;
}

BOOL CToolBarEx::AddDropDownButton(UINT nIDButton, UINT nIDMenu,BOOL bArrow)
{
	ASSERT_VALID(this);
	
	CDropDownButtonInfo* pb = FindDropDownButtonInfo(nIDButton);

	if (!pb) 
	{
		pb = new CDropDownButtonInfo;
		ASSERT(pb);
		pb->pNext = m_pDropButtons;
		m_pDropButtons = pb;
	}

	pb->idButton = nIDButton;
	pb->idMenu   = nIDMenu;
	
   return SetDropDownButton(nIDButton,bArrow);
}

CToolBarEx::CDropDownButtonInfo* CToolBarEx::FindDropDownButtonInfo(UINT nID)
{
	for (CDropDownButtonInfo* pb = m_pDropButtons; pb; pb = pb->pNext) 
	{
		if (pb->idButton == nID)
			return pb;
	}
	return NULL;
}

BOOL CToolBarEx::OnToolBarBtnDropDown(NMHDR* pNMHDR, LRESULT* pRes)
{
	UNUSED_ALWAYS( pRes );
	
	const NMTOOLBAR& nmtb = *(NMTOOLBAR*)pNMHDR;
														  
	// get location of button
	CRect rc;
	GetToolBarCtrl().GetRect(nmtb.iItem, rc);
	ClientToScreen(&rc);
	
	// call virtual function to display dropdown menu
	return OnDropDownButtonInfo(nmtb, nmtb.iItem, rc);
}

BOOL CToolBarEx::OnDropDownButtonInfo(const NMTOOLBAR& nmtb, UINT nID, CRect rc)
{
	UNUSED_ALWAYS( nID );

	CDropDownButtonInfo* pb = FindDropDownButtonInfo(nmtb.iItem);
	if (pb && pb->idMenu) 
	{
		
		// load and display popup menu
		CMenu menu;
		VERIFY(menu.LoadMenu(pb->idMenu));
		CMenu* pPopup = (CMenu*)menu.GetSubMenu(0);
		ASSERT(pPopup);
		pPopup->TrackPopupMenu(TPM_LEFTALIGN|TPM_LEFTBUTTON|TPM_VERTICAL,
			rc.left, rc.bottom, AfxGetMainWnd(), &rc);
		return TRUE;
	}

	return FALSE;
}


// This function saves the state (visible buttons, toolbar position, etc.)
// of the toolbar, using the registry key provided to the Create(...) function.
void CToolBarEx::SaveState()
{
	// if there is an associated registry subkey
	if (m_strSubKey.GetLength())
	{
		// save the toolbar state to the registry
		GetToolBarCtrl().SaveState( HKEY_CURRENT_USER, m_strSubKey, m_strValueName );
	}
}

// This function restores the state (visible buttons, toolbar position, etc.)
// of the toolbar, using the registry key provided to the Create(...) function.
void CToolBarEx::RestoreState()
{
	IconOptions eIconOptions=GetIconOptions();
	TextOptions eTextOptions=GetTextOptions();

	// if there is an associated registry subkey
	if (m_strSubKey.GetLength())
	{
		// restore the toolbar state from the registry
		GetToolBarCtrl().RestoreState( HKEY_CURRENT_USER, m_strSubKey, m_strValueName );
	}

	//Set Icon/Text options if changed
	if (eTextOptions!=GetTextOptions()) SetTextOptions(GetTextOptions(),TRUE);
	if (eIconOptions!=GetIconOptions()) SetIconOptions(GetIconOptions(),TRUE);

}

// This function is called when the user begins dragging a toolbar
// button or when the customization dialog is being populated with
// toolbar information.  Basically, *pResult should be populated with
// your answer to the question, "is the user allowed to delete this
// button?".
void CToolBarEx::OnToolBarQueryDelete(NMHDR *pNMHDR, LRESULT *pResult)
{
	UNUSED_ALWAYS( pNMHDR );

	NMTOOLBAR * tbStruct=(TBNOTIFY *)pNMHDR;


	ASSERT(tbStruct);
	// do not allow hidden button to be deleted as they just do not go
	// to the Add listbox.
	if ((tbStruct->tbButton.idCommand) && 
		GetToolBarCtrl().IsButtonHidden(tbStruct->tbButton.idCommand))
			*pResult = FALSE;
	else					 
			*pResult = TRUE;  

}

// This function is called when the user begins dragging a toolbar
// button or when the customization dialog is being populated with
// toolbar information.  Basically, *pResult should be populated with
// your answer to the question, "is the user allowed to insert a
// button to the left of this one?".
void CToolBarEx::OnToolBarQueryInsert(NMHDR *pNMHDR, LRESULT *pResult)
{
	UNUSED_ALWAYS( pNMHDR );
	*pResult = TRUE;


}

// This function is called whenever the user makes a change to the
// layout of the toolbar.  Calling the mainframe's RecalcLayout forces
// the toolbar to repaint itself.
void CToolBarEx::OnToolBarChange(NMHDR *pNMHDR, LRESULT *pResult)
{
	UNUSED_ALWAYS( pNMHDR );
	UNUSED_ALWAYS( pResult );


	SetTextOptions(m_eTextOptions,FALSE);
	PositionControls();

	// force the frame window to recalculate the size
	GetParentFrame()->RecalcLayout();
	OnIdleUpdateCmdUI(TRUE, 0L);

}


// This function is called when the user initially calls up the toolbar
// customization dialog box.
void CToolBarEx::OnToolBarBeginAdjust(NMHDR *pNMHDR, LRESULT *pResult)
{
	UNUSED_ALWAYS( pNMHDR );
	UNUSED_ALWAYS( pResult );


    *pResult = 0;

}

LRESULT CToolBarEx::OnCustomize(WPARAM,LPARAM)
{
	LONG lResult;

	ASSERT(m_pCustomizeDlg==NULL);
    m_pCustomizeDlg = new CCustomizeDialog( this, m_eTextOptions, m_eIconOptions );
    m_hCBTHook = ::SetWindowsHookEx( WH_CBT, CBTProc, 0, ::GetCurrentThreadId() );
    ASSERT( m_hCBTHook != 0 );
	 
    lResult = Default();

    VERIFY( ::UnhookWindowsHookEx( m_hCBTHook ) );
    m_hCBTHook = 0;

	 // if custom draw is not done then update Icon Draw at end
	 if (GetIconOptions()!=m_pCustomizeDlg->GetIconOptions())
		SetIconOptions(m_pCustomizeDlg->GetIconOptions(),TRUE);

    delete m_pCustomizeDlg;
    m_pCustomizeDlg = NULL;

	SaveState();
	ASSERT(m_pCustomizeDlg==NULL);

	return 	lResult;

}

// This function is called when the user clicks on the help button on the
// toolbar customization dialog box.
void CToolBarEx::OnToolBarCustomHelp(NMHDR *pNMHDR, LRESULT *pResult)
{
	UNUSED_ALWAYS( pNMHDR );
	UNUSED_ALWAYS( pResult );

	TRACE(_T("Help on Customize Toolbar called.\n"));
}

// This function is called when the user dismisses the toolbar customization
// dialog box.
void CToolBarEx::OnToolBarEndAdjust(NMHDR *pNMHDR, LRESULT *pResult)
{
	UNUSED_ALWAYS( pNMHDR );
	UNUSED_ALWAYS( pResult );

}

// This function is called to populate the toolbar customization dialog box
// with information regarding all of the possible toolbar buttons.
void CToolBarEx::OnToolBarGetButtonInfo(NMHDR *pNMHDR, LRESULT *pResult)
{
	UNUSED_ALWAYS( pResult );

	TBNOTIFY* tbStruct;		// data needed by customize dialog box

	// init the pointer
	tbStruct = (TBNOTIFY *)pNMHDR;

	// if the index is valid
	if ((0 <= tbStruct->iItem) && (tbStruct->iItem < m_ToolBarInfo.GetSize()))
	{
		// copy the stored button structure
		tbStruct->tbButton = m_ToolBarInfo[tbStruct->iItem].tbButton;

		// copy the text for the button label in the dialog
		_tcscpy(tbStruct->pszText, m_ToolBarInfo[tbStruct->iItem].btnText);

		// indicate valid data was sent
		*pResult = TRUE;
	}
	else  	// else there is no button for this index
	{
		*pResult = FALSE;
	}
}

// This function is called when the user clicks on the reset button on the
// toolbar customization dialog box.
void CToolBarEx::OnToolBarReset(NMHDR *pNMHDR, LRESULT *pResult)
{
	UNUSED_ALWAYS( pNMHDR );
	UNUSED_ALWAYS( pResult );


      int         nCount, i;
	  CToolBarCtrl &  tbCtrl =GetToolBarCtrl();
	
      // Remove all of the existing buttons 
      nCount = tbCtrl.GetButtonCount();

      for(i = nCount - 1; i >= 0; i--)
		 tbCtrl.DeleteButton(i);
      
      // Restore the buttons that were saved.
	  for (i=0;i<m_ToolBarInfo.GetSize();i++)
	  {
		  if (m_ToolBarInfo[i].bInitiallyVisible)
			 tbCtrl.AddButtons(1,&m_ToolBarInfo[i].tbButton);	
	  }

	if (m_pCustomizeDlg)
	{
	   ASSERT_VALID(m_pCustomizeDlg);
	   m_pCustomizeDlg->SetTextOptions(m_eInitialTextOptions);
	   m_pCustomizeDlg->SetIconOptions(m_eInitialIconOptions);
	}


	SetTextOptions(m_eInitialTextOptions);	//Default Values



	PositionControls();

	// force the frame window to recalculate the size
	GetParentFrame()->RecalcLayout();
	OnIdleUpdateCmdUI(TRUE, 0L);


	*pResult = TRUE;
}



void CToolBarEx::SetToolBarInfoForCustomization(const CToolBarEx::ToolBarInfoArray * pAdditional)
{
	 m_ToolBarInfo.RemoveAll();
	 const int nCount =	GetToolBarCtrl().GetButtonCount();
	 m_ToolBarInfo.SetSize(nCount); //SetSize


	 CToolBarCtrl & tbCtrl = GetToolBarCtrl();

	 for (int i=0;i<nCount;i++)
	 {
		CToolBarButtonInfo tbButtonInfo;

		tbCtrl.GetButton(i,&tbButtonInfo.tbButton);
		CString str;
		str.LoadString(tbButtonInfo.tbButton.idCommand);

		int nPos= str.ReverseFind(_T('\n'));
		tbButtonInfo.btnText=str.Right(str.GetLength()-nPos-1);
		tbButtonInfo.bInitiallyVisible=TRUE;
		
		m_ToolBarInfo.SetAt(i,tbButtonInfo);


	 }

	m_nResButtons =m_ToolBarInfo.GetSize();

	 // add the addiotnal buttons
	 if (pAdditional)
	 {
	   ASSERT_VALID(pAdditional);
	   m_ToolBarInfo.Append(*pAdditional);
	 }
	
	m_ToolBarInfo.FreeExtra();


	ModifyStyle(0, CCS_ADJUSTABLE);

	SetTextOptions(m_eInitialTextOptions);	//Default Values
	SetIconOptions(m_eInitialIconOptions);   //Default Values 


}

/////////////////////////////////////////////////////////////////////////////////////////
// Overrides 

int CToolBarEx::OnCreate(LPCREATESTRUCT lpCreateStruct) 
{
	if (CToolBar::OnCreate(lpCreateStruct) == -1)
		return -1;
	
	_GetComCtlVersion();
	ASSERT(_ComCtlVersion>=VERSION_IE5);

	//set version
//	int nVer=5;
//	DefWindowProc(CCM_SETVERSION,nVer,0);
//	ASSERT(nVer==DefWindowProc(CCM_GETVERSION,nVer,0));

	return 0;
}


void CToolBarEx::PositionControls()
{
	GetToolBarCtrl().AutoSize();
	m_bDelayedButtonLayout=TRUE;
}


// the all important function
CSize CToolBarEx::GetButtonSize(TBBUTTON* pData, int iButton, DWORD dwMode)
{
	ASSERT(_ComCtlVersion > 0);

	// Get the actual size of the button, not what's in m_sizeButton.
	// Make sure to do SendMessage instead of calling MFC's GetItemRect,
	// which has all sorts of bad side-effects!
	// 
	CRect rc;
	SendMessage(TB_GETITEMRECT, iButton, (LPARAM)&rc);
	CSize sz = rc.Size();

	DWORD dwStyle = pData[iButton].fsStyle;
	BOOL bVertDocked= (!(dwMode&LM_HORZ) && !(dwMode&LM_STRETCH) ) ;

	// do not allow sepearot to be greater than Button height ( Have to check this)
	if (dwStyle & TBSTYLE_SEP)
		sz.cy = __min(sz.cy ,HIWORD(GetToolBarCtrl().GetButtonSize()));



	// special cas  for custom controls
	if (m_bHideChildWndOnVertical)
	{
		if ((dwStyle & TBSTYLE_SEP) && 
				(pData[iButton].idCommand!=0))
		{

			if (bVertDocked)
			{
				sz.cx=sz.cy=0;
			}
			else
			{
		  		 // we will get 0,0 on hidden things
				if (GetToolBarCtrl().IsButtonHidden(pData[iButton].idCommand))
				{
				   CWnd * pWnd =GetDlgItem(pData[iButton].idCommand);

					ASSERT_VALID(pWnd);
					CRect rt;
					pWnd->GetWindowRect(rt);
					sz=rt.Size();
				}

			}
		}
	}  
		////////////////
	// Now must do special case for various versions of comctl32.dll,
	//
	if ((pData[iButton].fsState & TBSTATE_WRAP)) 
	{
		if (dwStyle & TBSTYLE_SEP) 
		{
			CWnd *pWnd =GetDlgItem(pData[iButton].idCommand);

			// Check seperator is child window
			if (!pWnd)
			{
				// this is the last separator in the row (eg vertically docked)
				// fudge the height, and ignore the width. TB_GETITEMRECT will return
				// size = (8 x 22) even for a separator in vertical toolbar
				//
				if (_ComCtlVersion <= VERSION_IE3)
					sz.cy -= 3;		// empircally good fudge factor
				else if (_ComCtlVersion != VERSION_IE4)
					sz.cy = sz.cx;
			
				sz.cx = 0;			// separator takes no width if it's the last one
			}
			else
			{
			  // Do not set value in case of the child window
			  //WE should never get here 
			  ASSERT_VALID(pWnd);
			  ASSERT(FALSE);
			}

		} 


	}
//	 // drop down arrow check
//	 if ((dwStyle & TBSTYLE_DROPDOWN) && 
//		  (bVertDocked) &&	
//		   !m_bShowDropdownArrowWhenVertical ) 
//	 {
//		// ignore width of dropdown
//		sz.cx = sz.cy;
//	 }

	return sz;
}



////////////////////////////////////////////////////////////

#define CX_OVERLAP  0

CSize CToolBarEx::CalcSize(TBBUTTON* pData, int nCount,DWORD dwMode)
{
	ASSERT(pData != NULL && nCount > 0);

	CPoint cur(0,0);
	CSize sizeResult(0,0);
	int cyTallestOnRow = 0;
	int nButtons=0;


	for (int i = 0; i < nCount; i++)
	{

		// also calculate for hidden custom controls
		if (  (pData[i].fsState & TBSTATE_HIDDEN)  &&
			!((pData[i].fsStyle & TBSTYLE_SEP) && (pData[i].idCommand!=0)))
			continue;

		// Load actual size of button into a local variable
		//
		CSize m_sizeButton = GetButtonSize(pData, i,dwMode);


		//  changed the logic below to be more correct.
		cyTallestOnRow = __max(cyTallestOnRow, m_sizeButton.cy);
		sizeResult.cx = __max(cur.x + m_sizeButton.cx, sizeResult.cx);
		sizeResult.cy = __max(cur.y + m_sizeButton.cy, sizeResult.cy);

		cur.x += m_sizeButton.cx - CX_OVERLAP;
		if (!(pData[i].fsState & TBSTATE_HIDDEN)) nButtons++;

		if (pData[i].fsState & TBSTATE_WRAP)
		{
			//only seperator is present
			if ((nButtons==1) && (pData[i].fsStyle & TBSTYLE_SEP))
			{
				cyTallestOnRow = HIWORD(GetToolBarCtrl().GetButtonSize());
			}

			cur.x = 0;
			cur.y += cyTallestOnRow;
			cyTallestOnRow = 0;
			if (pData[i].fsStyle & TBSTYLE_SEP)
				cur.y += m_sizeButton.cy;
			 nButtons=0;
		}

	}
	return sizeResult;
}

int CToolBarEx::WrapToolBar(TBBUTTON* pData, int nCount, int nWidth, DWORD dwMode)
{
	ASSERT(pData != NULL && nCount > 0);

	int nResult = 0;
	int x = 0;
	for (int i = 0; i < nCount; i++)
	{
		pData[i].fsState &= ~TBSTATE_WRAP;

		// also calculate for hidden custom controls
		if (  (pData[i].fsState & TBSTATE_HIDDEN)  &&
			!((pData[i].fsStyle & TBSTYLE_SEP) && (pData[i].idCommand!=0)))
			continue;

		int dx, dxNext;

		// Load actual size of button into a local variable
		CSize m_sizeButton = GetButtonSize(pData, i,dwMode);

		dx = m_sizeButton.cx;
		dxNext = dx - CX_OVERLAP;

		if (x + dx > nWidth)
		{
			BOOL bFound = FALSE;
			for (int j = i; j >= 0  &&  !(pData[j].fsState & TBSTATE_WRAP); j--)
			{
				// Find last separator that isn't hidden
				// a separator that has a command ID is not
				// a separator, but a custom control.
				if ((pData[j].fsStyle & TBSTYLE_SEP) &&
					(pData[j].idCommand == 0)
					&&	!(pData[j].fsState & TBSTATE_HIDDEN))
				{
					bFound = TRUE; i = j; x = 0;
					pData[j].fsState |= TBSTATE_WRAP;
					nResult++;
					break;
				}
			}
			if (!bFound)
			{
				for (int j = i - 1; j >= 0 && !(pData[j].fsState & TBSTATE_WRAP); j--)
				{
					// Never wrap anything that is hidden,
					// or any custom controls
					if ((pData[j].fsState & TBSTATE_HIDDEN) ||
						((pData[j].fsStyle & TBSTYLE_SEP) &&
						(pData[j].idCommand != 0)))
						continue;

					bFound = TRUE; i = j; x = 0;
					pData[j].fsState |= TBSTATE_WRAP;
					nResult++;
					break;
				}
				if (!bFound)
					x += dxNext;
			}
		}
		else
			x += dxNext;
	}
	return nResult + 1;
}

/////////////////////////////////////////////////////////////////////////////////////////////

void CToolBarEx::SizeToolBar(TBBUTTON* pData, int nCount, int nLength, BOOL bVert, DWORD dwMode)
{
	ASSERT(pData != NULL && nCount > 0);

	if (!bVert)
	{
		int nMin, n__max, nTarget, nCurrent, nMid;

		// Wrap ToolBar as specified
		n__max = nLength;
		nTarget = WrapToolBar(pData, nCount, n__max,dwMode);

		// Wrap ToolBar vertically
		nMin = 0;
		nCurrent = WrapToolBar(pData, nCount, nMin,dwMode);

		if (nCurrent != nTarget)
		{
			while (nMin < n__max)
			{
				nMid = (nMin + n__max) / 2;
				nCurrent = WrapToolBar(pData, nCount, nMid,dwMode);

				if (nCurrent == nTarget)
					n__max = nMid;
				else
				{
					if (nMin == nMid)
					{
						WrapToolBar(pData, nCount, n__max,dwMode);
						break;
					}
					nMin = nMid;
				}
			}
		}
		CSize size = CalcSize(pData, nCount,dwMode);
		WrapToolBar(pData, nCount, size.cx,dwMode);
	}
	else
	{
		CSize size__max, sizeMin, sizeMid;

		// Wrap ToolBar vertically
		WrapToolBar(pData, nCount, 0,dwMode);
		sizeMin = CalcSize(pData, nCount,dwMode);

		// Wrap ToolBar horizontally
		WrapToolBar(pData, nCount, 32767,dwMode);
		size__max = CalcSize(pData, nCount,dwMode);

		while (sizeMin.cx < size__max.cx)
		{
			sizeMid.cx = (sizeMin.cx + size__max.cx) / 2;
			WrapToolBar(pData, nCount, sizeMid.cx,dwMode);
			sizeMid = CalcSize(pData, nCount,dwMode);

			if (nLength < sizeMid.cy)
			{
				if (sizeMin == sizeMid)
				{
					WrapToolBar(pData, nCount, size__max.cx,dwMode);
					return;
				}
				sizeMin = sizeMid;
			}
			else if (nLength > sizeMid.cy)
			{
				if (size__max == sizeMid)
				{
					WrapToolBar(pData, nCount, sizeMin.cx,dwMode);
					return;
				}
				size__max = sizeMid;
			}
			else
				return;
		}
	}
}


CSize CToolBarEx::CalcLayout(DWORD dwMode, int nLength)
{
	ASSERT_VALID(this);
	ASSERT(::IsWindow(m_hWnd));
	if (dwMode & LM_HORZDOCK)
		ASSERT(dwMode & LM_HORZ);

	int nCount;
	TBBUTTON* pData = NULL;
	CSize sizeResult(0,0);

	//BLOCK: Load Buttons
	{
		nCount = DefWindowProc(TB_BUTTONCOUNT, 0, 0);
		if (nCount != 0)
		{
			int i;
			pData = new TBBUTTON[nCount];
			for (i = 0; i < nCount; i++)
				_GetButton(i, &pData[i]);
		}
	}

	if (nCount > 0)
	{
		if (!(m_dwStyle & CBRS_SIZE_FIXED))
		{
			BOOL bDynamic = m_dwStyle & CBRS_SIZE_DYNAMIC;

			if (bDynamic && (dwMode & LM_MRUWIDTH))
				SizeToolBar(pData, nCount, m_nMRUWidth,FALSE,dwMode);
			else if (bDynamic && (dwMode & LM_HORZDOCK))
				SizeToolBar(pData, nCount, 32767,FALSE,dwMode);
			else if (bDynamic && (dwMode & LM_VERTDOCK))
				SizeToolBar(pData, nCount, 0,FALSE,dwMode);
			else if (bDynamic && (nLength != -1))
			{
				CRect rect; rect.SetRectEmpty();
				CalcInsideRect(rect, (dwMode & LM_HORZ));
				BOOL bVert = (dwMode & LM_LENGTHY);
				int nLen = nLength + (bVert ? rect.Height() : rect.Width());

				SizeToolBar(pData, nCount, nLen, bVert,dwMode);
			}
			else if (bDynamic && (m_dwStyle & CBRS_FLOATING))
				SizeToolBar(pData, nCount, m_nMRUWidth,FALSE,dwMode);
			else
				SizeToolBar(pData, nCount, (dwMode & LM_HORZ) ? 32767 : 0,FALSE,dwMode);
		}

		sizeResult = CalcSize(pData, nCount,dwMode);

		if (dwMode & LM_COMMIT)
		{
			int nControlCount = 0;
			BOOL bIsDelayed = m_bDelayedButtonLayout;
			m_bDelayedButtonLayout = FALSE;
			BOOL bVert = (m_dwStyle & CBRS_ORIENT_VERT) != 0;


			for (int i = 0; i < nCount; i++)
				if ((pData[i].fsStyle & TBSTYLE_SEP) && (pData[i].idCommand != 0))
					nControlCount++;


			if (nControlCount > 0)
			{

				for(int i = 0; i < nCount; i++)
				{
					if ((pData[i].fsStyle & TBSTYLE_SEP) && (pData[i].idCommand != 0))
					{
						
						CRect rt;
						CWnd* pWnd = GetDlgItem(pData[i].idCommand);
						if (pWnd != NULL)
						{
							ASSERT_VALID(pWnd);
  						    pWnd->GetWindowRect(rt);
							pData[i].iBitmap=rt.Width(); //width 

							if (bVert && m_bHideChildWndOnVertical)
	   							pData[i].fsState |= TBSTATE_HIDDEN;
							else	   			
								pData[i].fsState &= ~TBSTATE_HIDDEN;
						}

					}
				}
			}
		

			if ((m_dwStyle & CBRS_FLOATING) && (m_dwStyle & CBRS_SIZE_DYNAMIC))
				m_nMRUWidth = sizeResult.cx;
			for (i = 0; i < nCount; i++)
					_SetButton(i, &pData[i]);

			{  
					//Now place the windows
					CWnd * pWnd = GetWindow(GW_CHILD);
					while(pWnd)
					{
					  ASSERT_VALID(pWnd);

					  int id =pWnd->GetDlgCtrlID();
						  ///////////////////////////
						// make sure the id is valid, and set the button 
						// style for a seperator.
						int nIndex = CommandToIndex( id ) ;
						if (nIndex>-1)
						{
							ASSERT( nIndex >= 0 );
							// insert the control into the toolbar.
							CRect rect;
							GetItemRect( nIndex, &rect );

							CRect rt;
							pWnd->GetWindowRect(&rt);
							rect.top+=__max((rect.Height()-rt.Height())/2,0);

							pWnd->SetWindowPos(0, rect.left, rect.top, 0, 0,
								SWP_NOZORDER | SWP_NOACTIVATE | SWP_NOSIZE | SWP_NOCOPYBITS );
							//pWnd->SetFont( GetFont( ));


							if (bVert && m_bHideChildWndOnVertical)
							{
								ASSERT(GetToolBarCtrl().IsButtonHidden(id));
								pWnd->ShowWindow( SW_HIDE );
							}
							else
							{
								ASSERT(!GetToolBarCtrl().IsButtonHidden(id));
								pWnd->ShowWindow( SW_SHOW );
							}

						}
						else
						{
							pWnd->ShowWindow( SW_HIDE);
						}
					  //////////////////////////
					  pWnd=pWnd->GetNextWindow();
					}
			}

			m_bDelayedButtonLayout = bIsDelayed;
		}

		delete[] pData;
	}

	//BLOCK: Adjust Margins
	{
		CRect rect; rect.SetRectEmpty();
		CalcInsideRect(rect, (dwMode & LM_HORZ));
		sizeResult.cy -= rect.Height();
		sizeResult.cx -= rect.Width();

		CSize size = CControlBar::CalcFixedLayout((dwMode & LM_STRETCH), (dwMode & LM_HORZ));
		sizeResult.cx = __max(sizeResult.cx, size.cx);
		sizeResult.cy = __max(sizeResult.cy, size.cy);
	}
	return sizeResult;
}

CSize CToolBarEx::CalcFixedLayout(BOOL bStretch, BOOL bHorz)
{
	DWORD dwMode = bStretch ? LM_STRETCH : 0;
	dwMode |= bHorz ? LM_HORZ : 0;

	return CalcLayout(dwMode);
}

CSize CToolBarEx::CalcDynamicLayout(int nLength, DWORD dwMode)
{
	if ((nLength == -1) && !(dwMode & LM_MRUWIDTH) && !(dwMode & LM_COMMIT) &&
		((dwMode & LM_HORZDOCK) || (dwMode & LM_VERTDOCK)))
	{
		return CalcFixedLayout(dwMode & LM_STRETCH, dwMode & LM_HORZDOCK);
	}
	return CalcLayout(dwMode, nLength);
}

/////////////////////////////////////////////////////////////////////////////
// CToolBarEx attribute access

void CToolBarEx::_GetButton(int nIndex, TBBUTTON* pButton) const
{
	CToolBarEx* pBar = (CToolBarEx*)this;
	VERIFY(pBar->DefWindowProc(TB_GETBUTTON, nIndex, (LPARAM)pButton));
	// TBSTATE_ENABLED == TBBS_DISABLED so invert it
	pButton->fsState ^= TBSTATE_ENABLED;
}

void CToolBarEx::_SetButton(int nIndex, TBBUTTON* pButton)
{
	// get original button state
	TBBUTTON button;
	VERIFY(DefWindowProc(TB_GETBUTTON, nIndex, (LPARAM)&button));

	// prepare for old/new button comparsion
	button.bReserved[0] = 0;
	button.bReserved[1] = 0;
	// TBSTATE_ENABLED == TBBS_DISABLED so invert it
	pButton->fsState ^= TBSTATE_ENABLED;
	pButton->bReserved[0] = 0;
	pButton->bReserved[1] = 0;

	// nothing to do if they are the same
	if (memcmp(pButton, &button, sizeof(TBBUTTON)) != 0)
	{
		// don't redraw everything while setting the button
		DWORD dwStyle = GetStyle();
		ModifyStyle(WS_VISIBLE, 0);
		VERIFY(DefWindowProc(TB_DELETEBUTTON, nIndex, 0));
		
		// Force a recalc of the toolbar's layout to work around a comctl bug
		int iTextRows = (int)::SendMessage(m_hWnd, TB_GETTEXTROWS, 0, 0);
		::SendMessage(m_hWnd, WM_SETREDRAW, FALSE, 0);
		::SendMessage(m_hWnd, TB_SETMAXTEXTROWS, iTextRows+1, 0);
		::SendMessage(m_hWnd, TB_SETMAXTEXTROWS, iTextRows, 0);
		::SendMessage(m_hWnd, WM_SETREDRAW, TRUE, 0);
		

		VERIFY(DefWindowProc(TB_INSERTBUTTON, nIndex, (LPARAM)pButton));
		ModifyStyle(0, dwStyle & WS_VISIBLE);

		// invalidate appropriate parts
		if (((pButton->fsStyle ^ button.fsStyle) & TBSTYLE_SEP) ||
			((pButton->fsStyle & TBSTYLE_SEP) && pButton->iBitmap != button.iBitmap))
		{
			// changing a separator
			Invalidate();
		}
		else
		{
			// invalidate just the button
			CRect rect;
			if (DefWindowProc(TB_GETITEMRECT, nIndex, (LPARAM)&rect))
				InvalidateRect(rect);
		}
	}
}








BOOL CToolBarEx::SetDropDownButton(UINT nID, BOOL bArrow)
{
		
	int iButton = CommandToIndex(nID);
	
	DWORD dwStyle = GetButtonStyle(iButton);
	dwStyle |= TBSTYLE_DROPDOWN|( (!bArrow) ?BTNS_WHOLEDROPDOWN :0);
	SetButtonStyle(iButton, dwStyle);								

	GetToolBarCtrl().SetExtendedStyle(GetToolBarCtrl().GetExtendedStyle() |TBSTYLE_EX_DRAWDDARROWS);

	return TRUE;
}

BOOL CToolBarEx::IsVertDocked()
{
	UINT nID =GetParent()->GetDlgCtrlID();
	return ( (nID ==AFX_IDW_DOCKBAR_LEFT) || (nID== AFX_IDW_DOCKBAR_RIGHT));
}

void CToolBarEx::OnPaint() 
{
	CToolBar::OnPaint();

	//I have to use this, as there is not customdraw mesasges for seperators
	// draw the controls seperator again to hide it
	for (int i=0;i<GetToolBarCtrl().GetButtonCount();i++)
	{
		TBBUTTON tb;
		GetToolBarCtrl().GetButton(i,&tb);

		//only for seperators controls
		if  ( ((tb.fsStyle & TBSTYLE_SEP) == TBSTYLE_SEP) &&
			   (tb.idCommand!=0) )
		{
			CRect rc;
			GetItemRect(i,rc);
			CClientDC dc(this);

			CWnd *pWnd = GetDlgItem(tb.idCommand);
			ASSERT_VALID(pWnd);
			dc.FillSolidRect(rc, m_clrBtnFace);

			if (pWnd)
			{
				pWnd->RedrawWindow();
			}
		}
	}

	 
}

void CToolBarEx::SetTextOptions(TextOptions eTextOptions, BOOL bUpdate)
{
    ASSERT( ::IsWindow( m_hWnd ) );
    ASSERT( eTextOptions != toNone );

    m_eTextOptions = eTextOptions;


	    // Modify toolbar style according to new text options
    ModifyStyle(
        ( eTextOptions == toTextOnRight ) ? 0 : TBSTYLE_LIST,
        ( eTextOptions == toTextOnRight ) ? TBSTYLE_LIST : 0 );

    CToolBarCtrl& tbCtrl = GetToolBarCtrl();

    DWORD dwStyleEx = tbCtrl.GetExtendedStyle();

	tbCtrl.SetExtendedStyle(
        ( eTextOptions == toTextOnRight ) ?
            ( dwStyleEx |  TBSTYLE_EX_MIXEDBUTTONS ) :
            ( dwStyleEx & ~TBSTYLE_EX_MIXEDBUTTONS ) );


	
	for(int i=0;i<m_ToolBarInfo.GetSize();i++)
 		{ 
 		//	if ((m_ToolBarInfo[i].tbButton.fsStyle & TBSTYLE_SEP) !=  TBSTYLE_SEP)
 			{
 				int nIndex= CommandToIndex(m_ToolBarInfo[i].tbButton.idCommand);
 				
 				if (nIndex>-1) 	// buton is there on bar
				{

					 TBBUTTON tbinfo;

					_GetButton(nIndex,&tbinfo);

					if ( !( tbinfo.fsStyle & TBSTYLE_SEP ) )  //check again
					{
 							// attempt to lookup string index in map
							int nString = -1;
							if ((eTextOptions==toTextLabels) || ((eTextOptions==toTextOnRight)))
							{
								void* p=NULL;
								CString strTemp(m_ToolBarInfo[i].btnText);
								if (m_pStringMap != NULL && m_pStringMap->Lookup(strTemp, p))
									nString = (int)p;

								// add new string if not already in map
								if (nString == -1)
								{
									// initialize map if necessary
									if (m_pStringMap == NULL)
									{
										m_pStringMap = new CMapStringToPtr;
										ASSERT(m_pStringMap);
									}

									// add new string to toolbar list
									nString = (int)DefWindowProc(TB_ADDSTRING, 0, (LPARAM)(LPCTSTR)strTemp);
									if (nString != -1)
									{
										// cache string away in string map
										m_pStringMap->SetAt(strTemp, (void*)nString);
										ASSERT(m_pStringMap->Lookup(strTemp, p));
									}
								}

							}

						

							switch ( eTextOptions )
							{
								case toTextLabels:
									{
										tbinfo.iString =nString;
										tbinfo.fsStyle &= ~BTNS_SHOWTEXT;
										tbinfo.fsStyle |= TBSTYLE_AUTOSIZE;
									}
									break;

								case toTextOnRight:
									{
										if ((nString!=-1) && 
												(HasButtonText(m_ToolBarInfo[i].tbButton.idCommand)))
										{
											tbinfo.iString =nString;
											tbinfo.fsStyle |= ( TBSTYLE_AUTOSIZE |BTNS_SHOWTEXT );
										}
										else
										{
											tbinfo.fsStyle &= ~BTNS_SHOWTEXT;
											tbinfo.fsStyle |= TBSTYLE_AUTOSIZE;
										}
									}
									break;

								case toNoTextLabels:
									{
 										tbinfo.iString= -1;   //Set string to zero
										tbinfo.fsStyle &= ~BTNS_SHOWTEXT;
										tbinfo.fsStyle |= TBSTYLE_AUTOSIZE;
									}
									break;
								default:
									ASSERT(FALSE); // anew type added
							}

							//Delete & add the button
							{
								tbinfo.fsState ^= TBSTATE_ENABLED;
								m_ToolBarInfo[i].tbButton=tbinfo;
								tbinfo.fsState ^= TBSTATE_ENABLED;
								_SetButton(nIndex,&tbinfo);
							}
 					}
				}
			}
	}

	int iTextRows = 0;
	// now total setting
	switch ( eTextOptions )
	{
		case toTextLabels:
			{
  				iTextRows=1;
			}
			break;

		case toTextOnRight:
			{
  				iTextRows=1;
			}
			break;

		case toNoTextLabels:
			{
  				iTextRows=0;
			}
			break;
		default:
			ASSERT(FALSE); // anew type added
	}

	::SendMessage(m_hWnd, TB_SETMAXTEXTROWS, iTextRows, 0);
	


    // If requested, reflect changes immediately
    if ( bUpdate )
    {
		PositionControls();
		GetParentFrame()->RecalcLayout();
		OnIdleUpdateCmdUI(TRUE, 0L);
    }

}

 

void CToolBarEx::SetIconOptions(IconOptions eIconOptions, BOOL bUpdate)
{
    ASSERT( ::IsWindow( m_hWnd ) );
    ASSERT( eIconOptions != ioNone );

    m_eIconOptions = eIconOptions;


	switch(eIconOptions)
	{
	 case ioSmallIcons:
		 m_sizeImage= m_szImageSmall ;
		 SetIconOptionBitmap(ioSmallIcons);
		 GetToolBarCtrl().SetBitmapSize(m_szImageSmall);
		break;

	 case ioLargeIcons:
		 m_sizeImage= m_szImageLarge ;
		 SetIconOptionBitmap(ioLargeIcons);
		 GetToolBarCtrl().SetBitmapSize(m_szImageLarge);
		 break;
	}

			// Force a recalc of the toolbar's layout to work around a comctl bug
		int iTextRows = (int)::SendMessage(m_hWnd, TB_GETTEXTROWS, 0, 0);
		::SendMessage(m_hWnd, WM_SETREDRAW, FALSE, 0);
		::SendMessage(m_hWnd, TB_SETMAXTEXTROWS, iTextRows+1, 0);
		::SendMessage(m_hWnd, TB_SETMAXTEXTROWS, iTextRows, 0);
		::SendMessage(m_hWnd, WM_SETREDRAW, TRUE, 0);


    // If requested, reflect changes immediately
    if ( bUpdate )
    {
		PositionControls();
		GetParentFrame()->RecalcLayout();
		OnIdleUpdateCmdUI(TRUE, 0L);
    }

}

//static ftn for Hook

LRESULT CALLBACK CToolBarEx::CBTProc( int nCode, WPARAM wParam, LPARAM lParam )
{
    ASSERT( m_pCustomizeDlg != NULL );

	try
	{
		if ( ( nCode == HCBT_CREATEWND ) && (m_pCustomizeDlg) && ( m_pCustomizeDlg->m_hWnd == 0 ) )
		{
			// This is where we have a good chance to subclass standard
			// "Customize toolbar" dialog in order to add to it some of
			// our new features (ie. text and icon options selectors)
			HWND hWnd = ( HWND )wParam;
			VERIFY( m_pCustomizeDlg->SubclassWindow( hWnd ) );
		}
	}
	catch(...)	// if exception is not caught then we can get in infinite loop as assert window is opened.
	{
		TRACE0(_T("Exception thrown while Hooking-Extra Custom features unavaialble.\n"));

		//Call next
		LRESULT lResult=::CallNextHookEx( m_hCBTHook, nCode, wParam, lParam );
		VERIFY( ::UnhookWindowsHookEx( m_hCBTHook ) );
		m_hCBTHook = 0;
		if (m_pCustomizeDlg) delete m_pCustomizeDlg;
		m_pCustomizeDlg = NULL;
		return lResult;
	}

    return ::CallNextHookEx( m_hCBTHook, nCode, wParam, lParam );
}


// has to override this
BOOL CToolBarEx::HasButtonText(int nID)
{
	nID;
    return TRUE;
}

/*
	DIBs use RGBQUAD format:
		0xbb 0xgg 0xrr 0x00

	Reasonably efficient code to convert a COLORREF into an
	RGBQUAD is byte-order-dependent, so we need different
	code depending on the byte order we're targeting.
*/
#define RGB_TO_RGBQUAD(r,g,b)   (RGB(b,g,r))
#define CLR_TO_RGBQUAD(clr)     (RGB(GetBValue(clr), GetGValue(clr), GetRValue(clr)))

static COLORREF MapToSysColor (COLORREF color, BOOL bUseRGBQUAD)
{
	struct COLORMAP
	{
		// use DWORD instead of RGBQUAD so we can compare two RGBQUADs easily
		DWORD rgbqFrom;
		int iSysColorTo;
	};
	static const COLORMAP sysColorMap[] =
	{
		// mapping from color in DIB to system color
		{ RGB_TO_RGBQUAD(0x00, 0x00, 0x00),  COLOR_BTNTEXT },       // black
		{ RGB_TO_RGBQUAD(0x80, 0x80, 0x80),  COLOR_BTNSHADOW },     // dark grey
		{ RGB_TO_RGBQUAD(0xC0, 0xC0, 0xC0),  COLOR_BTNFACE },       // bright grey
		{ RGB_TO_RGBQUAD(0xFF, 0xFF, 0xFF),  COLOR_BTNHIGHLIGHT }   // white
	};
	const int nMaps = 4;

	// look for matching RGBQUAD color in original
	for (int i = 0; i < nMaps; i++)
	{
		if (color == sysColorMap[i].rgbqFrom)
		{
			return bUseRGBQUAD ? 
				CLR_TO_RGBQUAD(::GetSysColor(sysColorMap[i].iSysColorTo)) :
				::GetSysColor(sysColorMap[i].iSysColorTo);
		}
	}

	return color;
}

static HBITMAP LoadSysColorBitmapSize(HINSTANCE hInst, HRSRC hRsrc,CSize sz)
{
	HGLOBAL hglb;

	if ((hglb = LoadResource(hInst, hRsrc)) == NULL)
		return NULL;

	LPBITMAPINFOHEADER lpBitmap = (LPBITMAPINFOHEADER)LockResource(hglb);
	if (lpBitmap == NULL)
		return NULL;

	UINT nSize=lpBitmap->biSize;
	const int nColorTableSize = 16;

	if (lpBitmap->biBitCount  <=8)
	{
		// make copy of BITMAPINFOHEADER so we can modify the color table
		nSize = lpBitmap->biSize + nColorTableSize * sizeof(RGBQUAD);
	}


	LPBITMAPINFOHEADER lpBitmapInfo = (LPBITMAPINFOHEADER)::malloc(nSize);
	if (lpBitmapInfo == NULL)	return NULL;

	memcpy(lpBitmapInfo, lpBitmap, nSize);
	HBITMAP hbm	=NULL;
	if (lpBitmapInfo->biBitCount  <=8)
	{
		// color table is in RGBQUAD DIB format
		DWORD* pColorTable =
			(DWORD*)(((LPBYTE)lpBitmapInfo) + (UINT)lpBitmapInfo->biSize);

		for (int iColor = 0; iColor < nColorTableSize; iColor++)
		{
			pColorTable[iColor] = MapToSysColor(pColorTable[iColor],TRUE) ;
		}	

		int nWidth = (int)lpBitmapInfo->biWidth;
		int nHeight = (int)lpBitmapInfo->biHeight;
		HDC hDCScreen = ::GetDC(NULL);
		hbm = ::CreateCompatibleBitmap(hDCScreen, sz.cx, sz.cy);

		if (hbm != NULL)
		{
			HDC hDCGlyphs = ::CreateCompatibleDC(hDCScreen);
			HBITMAP hbmOld = (HBITMAP)::SelectObject(hDCGlyphs, hbm);

			LPBYTE lpBits;
			lpBits = (LPBYTE)(lpBitmap + 1);
			lpBits += (1 << (lpBitmapInfo->biBitCount)) * sizeof(RGBQUAD);

			StretchDIBits(hDCGlyphs, 0, 0, sz.cx, sz.cy, 0, 0, nWidth, nHeight,
				lpBits, (LPBITMAPINFO)lpBitmapInfo, DIB_RGB_COLORS, SRCCOPY);
			SelectObject(hDCGlyphs, hbmOld);
			::DeleteDC(hDCGlyphs);
		}
		::ReleaseDC(NULL, hDCScreen);


	}
	else
	{

		int nWidth = (int)lpBitmapInfo->biWidth;
		int nHeight = (int)lpBitmapInfo->biHeight;
		HDC hDCScreen = ::GetDC(NULL);
		hbm = ::CreateCompatibleBitmap(hDCScreen, sz.cx, sz.cy);

		if (hbm != NULL)
		{
			HDC hDCGlyphs = ::CreateCompatibleDC(hDCScreen);
			HBITMAP hbmOld = (HBITMAP)::SelectObject(hDCGlyphs, hbm);

			LPBYTE lpBits;
			lpBits = (LPBYTE)(lpBitmap + 1);

			StretchDIBits(hDCGlyphs, 0, 0, sz.cx, sz.cy, 0, 0, nWidth, nHeight,
				lpBits, (LPBITMAPINFO)lpBitmapInfo, DIB_RGB_COLORS, SRCCOPY);

			// Change a specific colors to system:
			for (int x = 0; x < sz.cx; x ++)
			{
				for (int y = 0; y < sz.cy; y ++)
				{
					COLORREF clrOrig = ::GetPixel (hDCGlyphs, x, y);
					COLORREF clrNew = MapToSysColor (clrOrig,FALSE);

					if (clrOrig != clrNew)
					{
						::SetPixel (hDCGlyphs, x, y, clrNew);
					}
				}
			}

			SelectObject(hDCGlyphs, hbmOld);
			::DeleteDC(hDCGlyphs);
		}
		::ReleaseDC(NULL, hDCScreen);

	}


	// free copy of bitmap info struct and resource itself
	::free(lpBitmapInfo);
	::FreeResource(hglb);

	return hbm;
}


BOOL CToolBarEx::SetIconOptionBitmap(IconOptions eIconOptions)
{

	if ((m_hInstImageWell != NULL) && (m_hRsrcImageWell != NULL))
	{

		HBITMAP hBitmap=NULL;
		HINSTANCE  hInstImageWell= m_hInstImageWell	;
		HRSRC  hRsrcImageWell	=  m_hRsrcImageWell	;

		int nCount = 0;

		for(UINT i=0;i<m_nResButtons;i++)
		{
		 
			if ((m_ToolBarInfo[i].tbButton.idCommand !=0))
				nCount++;
		}

		if (eIconOptions==ioSmallIcons)
		{
			CSize  sizeSmallImage(nCount *m_szImageSmall.cx,m_szImageSmall.cy);
			hBitmap= LoadSysColorBitmapSize(m_hInstImageWell, m_hRsrcImageWell,sizeSmallImage);
		}
		else
		{
			ASSERT(eIconOptions==ioLargeIcons);
			CSize  sizeLargeImage(nCount *m_szImageLarge.cx,m_szImageLarge.cy);
			hBitmap= LoadSysColorBitmapSize(m_hInstImageWell, m_hRsrcImageWell,sizeLargeImage);
		}

		ASSERT(hBitmap);
		SetBitmap(hBitmap);

		m_hInstImageWell = hInstImageWell; // SetBitmap resets these
		m_hRsrcImageWell = hRsrcImageWell; // SetBitmap resets these
		return TRUE;
	}


	return FALSE;
}

void CToolBarEx::OnSysColorChange() 
{
	m_clrBtnShadow=::GetSysColor(COLOR_BTNSHADOW);
	m_clrBtnHilight=::GetSysColor(COLOR_BTNHILIGHT);
	m_clrBtnFace  = ::GetSysColor(COLOR_BTNFACE);
	SetIconOptions(m_eIconOptions);	//load bitmap again
}

void CToolBarEx::OnSave( NMHDR* pNMHDR, LRESULT* pResult )
{
    NMTBSAVE* lpnmtb = ( NMTBSAVE* )pNMHDR;
    if ( lpnmtb->iItem == -1 )
    {
        lpnmtb->cbData  += sizeof( DWORD ) * 2;
        lpnmtb->pData    = ( LPDWORD )::GlobalAlloc( GMEM_FIXED, lpnmtb->cbData );  //freed by Toolbar ( Not sure)
        lpnmtb->pCurrent = lpnmtb->pData;

        *lpnmtb->pCurrent++ = (DWORD)m_eIconOptions;
        *lpnmtb->pCurrent++ = (DWORD)m_eTextOptions;
    }

    *pResult = 0;
}

void CToolBarEx::OnRestore( NMHDR* pNMHDR, LRESULT* pResult )
{
    NMTBRESTORE* lpnmtb = ( NMTBRESTORE* )pNMHDR;

    if ( lpnmtb->iItem == -1 )
    {
        lpnmtb->cButtons = ( lpnmtb->cbData - sizeof( DWORD ) * 2 ) / lpnmtb->cbBytesPerRecord;
        lpnmtb->pCurrent = lpnmtb->pData;

        m_eIconOptions=(IconOptions)*lpnmtb->pCurrent++ ;
        m_eTextOptions=(TextOptions)*lpnmtb->pCurrent++ ;
    }

    *pResult = 0;
}


BOOL CToolBarEx::ShowContextMenu(CPoint point)
{

	if( GetToolBarCtrl().GetButtonCount() && m_ToolBarInfo.GetSize())
	{
		CPoint pt( point );
		ClientToScreen( &pt );
		
		// load and display popup menu
		CMenu popupMenu;
		VERIFY(popupMenu.CreatePopupMenu());

		CFrameWnd * pFrame=(CFrameWnd *)AfxGetMainWnd();

		if (pFrame && pFrame->IsKindOf(RUNTIME_CLASS(CFrameWnd)) )
		{
			ASSERT_VALID(pFrame);
			POSITION pos = pFrame->m_listControlBars.GetHeadPosition();

			while (pos != NULL)
			{
				const CControlBar* pBar = (CControlBar*)pFrame->m_listControlBars.GetNext(pos);
				ASSERT(pBar != NULL);
				
				if (pBar && 
					pBar->IsKindOf(RUNTIME_CLASS(CToolBar))) // Put any other type

				{
					ASSERT_VALID(pBar);
					CString strName;
					pBar->GetWindowText(strName);
					popupMenu.AppendMenu( (pBar->GetStyle()&WS_VISIBLE?MF_CHECKED:MF_UNCHECKED)|MF_STRING,
											pBar->GetDlgCtrlID(),
											strName);
				}
			}
			
			//Add a Seperator
			popupMenu.AppendMenu(MF_SEPARATOR) ;
		}

		
		//Finally a Customize
		popupMenu.AppendMenu(MF_STRING ,ID_CUSTOMIZE_BAR, STR_CUSTOMIZE);

		int nResult = popupMenu.TrackPopupMenu(TPM_LEFTALIGN|TPM_LEFTBUTTON|TPM_VERTICAL|TPM_RETURNCMD,pt.x, pt.y, this );
	
		switch(nResult)
		{
			case 0:		//Nothing clicked  on menu
				break;
			case ID_CUSTOMIZE_BAR  :
				// open the customization dialog.
				Customize();
			break;
			default:
				{
					ASSERT_VALID(pFrame);
					if (pFrame && pFrame->IsKindOf(RUNTIME_CLASS(CFrameWnd)) )
					{	
						pFrame->OnBarCheck(nResult);
					}
				}
		}
		return TRUE;
	}


	return FALSE;

}

void CToolBarEx::OnContextMenu(CWnd* pWnd, CPoint point) 
{
	ASSERT_VALID(pWnd);
	CPoint pt(point);

	if (WindowFromPoint(pt)!=this) return;

	ScreenToClient(&pt);
	if (!ShowContextMenu(pt))
		CToolBar::OnContextMenu(pWnd,point);
}

void CToolBarEx::Customize()
{
	GetToolBarCtrl().Customize();
}

void CToolBarEx::OnInitCustomize( NMHDR* /*pNMHDR*/, LRESULT* pResult )
{
    *pResult = TBNRF_HIDEHELP;  // help button  is hidden      
}

void CToolBarEx::OnCustomDraw( NMHDR* pNMHDR, LRESULT* pResult )
{
	LPNMTBCUSTOMDRAW lpNMCustomDraw = (LPNMTBCUSTOMDRAW) pNMHDR;

	ASSERT_POINTER(lpNMCustomDraw,NMTBCUSTOMDRAW);
	switch(lpNMCustomDraw->nmcd.dwDrawStage)
	{
	case CDDS_PREPAINT:
		*pResult = CDRF_NOTIFYITEMDRAW    ;
		break;
	case CDDS_ITEMPREPAINT:
		// draw the button
		{
			if (lpNMCustomDraw->nmcd.uItemState & CDIS_HOT)
			{
				//draw button
				CDC dc;
				CRect rt(lpNMCustomDraw->nmcd.rc);
				TBBUTTONINFO bbi;
				int xOffset=5,yOffset=3;

				dc.Attach(lpNMCustomDraw->nmcd.hdc);
				//Init button info
				memset(&bbi,0,sizeof(bbi));
				bbi.cbSize =sizeof(bbi);
				bbi.dwMask = TBIF_IMAGE;

				GetToolBarCtrl().GetButtonInfo(lpNMCustomDraw->nmcd.dwItemSpec,&bbi);
				
				


				//draw shadow
				CDC  dcGlyphs;
				dcGlyphs.CreateCompatibleDC(NULL);
				HBITMAP hbmOld = (HBITMAP)dcGlyphs.SelectObject(m_hbmImageWell);

				dc.BitBlt(rt.left+xOffset+1,rt.top+yOffset+1,m_sizeImage.cx,m_sizeImage.cy,&dcGlyphs,m_sizeImage.cx*bbi.iImage,0,SRCCOPY);
				dcGlyphs.SelectObject(hbmOld);
				dcGlyphs.DeleteDC();
			
				
				// darken the drawn thing
				long r,g,b;
				float  perc=0.07f;
				for (int x= rt.left+1;x< rt.right;x++)
					for (int y= rt.top+1;y< rt.bottom;y++)
					{
						COLORREF cr = dc.GetPixel(CPoint(x,y));
						if (cr == m_clrBtnFace)
						{
							r = GetRValue(cr);
							g = GetGValue(cr);
							b = GetBValue(cr);

							r -=(BYTE)(r*perc);
							g -=(BYTE)(g*perc);
							b -=(BYTE)(b*perc);
							dc.SetPixel(CPoint(x,y),RGB(r,g,b));
						}
						else
							dc.SetPixel(CPoint(x,y),m_clrBtnShadow);  // this creates shadow

					}



				dc.Draw3dRect(&rt,m_clrBtnShadow,m_clrBtnShadow);



				dc.Detach();

				*pResult = CDRF_SKIPDEFAULT;
			}
			else  // for normal cases
			{
				*pResult = CDRF_DODEFAULT ;
			}
		}
		break;
	case CDRF_NOTIFYPOSTPAINT :
		*pResult = CDRF_DODEFAULT ;
		ASSERT(FALSE);
		break;
	default:
		*pResult = CDRF_DODEFAULT ;
	}
}




void CToolBarEx::OnNcPaint() 
{

	if( GetToolBarCtrl().GetStyle()& TBSTYLE_FLAT ) 
	{
		// get window DC that is clipped to the non-client area
		CWindowDC dc(this);
		CRect rectClient;
		GetClientRect(rectClient);
		CRect rectWindow;
		GetWindowRect(rectWindow);
		ScreenToClient(rectWindow);
		rectClient.OffsetRect(-rectWindow.left, -rectWindow.top);
		dc.ExcludeClipRect(rectClient);

		// draw borders in non-client area
		rectWindow.OffsetRect(-rectWindow.left, -rectWindow.top);

		Draw3DBorders(&dc, rectWindow);

		dc.IntersectClipRect(rectWindow);

		// erase parts not drawn
		SendMessage(WM_ERASEBKGND, (WPARAM)dc.m_hDC);

		DrawGripper(&dc,rectWindow);
	} 
	else
	{
		CToolBar::OnNcPaint();
	}
}

void CToolBarEx :: Draw3DBorders(CDC * pDC, CRect & rect) 
{
	ASSERT_VALID(this);
	ASSERT_VALID(pDC);

	if( GetToolBarCtrl().GetStyle()& TBSTYLE_FLAT ) 
	{
		DWORD dwStyle = m_dwStyle;
		if (!(dwStyle & CBRS_BORDER_ANY))
			return;

		COLORREF clr = (m_dwStyle & CBRS_BORDER_3D) ? m_clrBtnHilight : m_clrBtnShadow;
		if(m_dwStyle & CBRS_BORDER_LEFT)
			pDC->FillSolidRect(0, 0, 1, rect.Height() - 1, clr);
		if(m_dwStyle & CBRS_BORDER_TOP)
			pDC->FillSolidRect(0, 0, rect.Width()-1 , 1, clr);
		
		
		// this for ver 6.0
		if (dwStyle & CBRS_BORDER_ANY)
		{
			CRect rctBk;
			rctBk.left = 0;
			rctBk.right = rect.right;
			rctBk.top = rect.top;
			rctBk.bottom = rect.bottom;

			pDC->FillSolidRect((LPRECT)rctBk, pDC->GetBkColor());
		}

		if(m_dwStyle & CBRS_BORDER_RIGHT)
			pDC->FillSolidRect(rect.right, 1, -1, rect.Height() - 1, m_clrBtnShadow);
		if(m_dwStyle & CBRS_BORDER_BOTTOM)
			pDC->FillSolidRect(0, rect.bottom, rect.Width()-1, -1, m_clrBtnShadow);



		// if undockable toolbar at top of frame, apply special formatting to mesh
		// properly with frame menu
		if(!m_pDockContext) 
		{
			pDC->FillSolidRect(0,0,rect.Width(),1,m_clrBtnShadow);
			pDC->FillSolidRect(0,1,rect.Width(),1,m_clrBtnHilight);
		}

		if (dwStyle & CBRS_BORDER_LEFT)
			++rect.left;
		if (dwStyle & CBRS_BORDER_TOP)
			++rect.top;
		if (dwStyle & CBRS_BORDER_RIGHT)
			--rect.right;
		if (dwStyle & CBRS_BORDER_BOTTOM)
			--rect.bottom;
	} 
	else
	{
		DrawBorders(pDC, rect);
	}


}
	 
BOOL CToolBarEx::LoadBitmap(LPCTSTR lpszResourceName)
{
	ASSERT_VALID(this);
	ASSERT(lpszResourceName != NULL);

	// determine location of the bitmap in resource fork
	HINSTANCE hInstImageWell = AfxFindResourceHandle(lpszResourceName, RT_BITMAP);
	HRSRC hRsrcImageWell = ::FindResource(hInstImageWell, lpszResourceName, RT_BITMAP);
	if (hRsrcImageWell == NULL)
		return FALSE;

	// delete last one
	if (hRsrcImageWell) ::DeleteObject(hRsrcImageWell);



	// remember the resource handles so the bitmap can be recolored if necessary
	m_hInstImageWell = hInstImageWell;
	m_hRsrcImageWell = hRsrcImageWell;

	return TRUE;
}

/////////////////////////////////////////////////////////////////////////////
// CDockBarEx

CDockBarEx::CDockBarEx()
{
	// TODO: add construction code here.
}

CDockBarEx::~CDockBarEx()
{
	// TODO: add destruction code here.
}

IMPLEMENT_DYNAMIC(CDockBarEx, CDockBar)

BEGIN_MESSAGE_MAP(CDockBarEx, CDockBar)
	//{{AFX_MSG_MAP(CDockBarEx)				  
		// NOTE - the ClassWizard will add and remove mapping macros here.
		//    DO NOT EDIT what you see in these blocks of generated code!
	//}}AFX_MSG_MAP
END_MESSAGE_MAP()

/////////////////////////////////////////////////////////////////////////////
// CDockBarEx message handlers

CSize CDockBarEx::CalcFixedLayout(BOOL bStretch, BOOL bHorz)
{
	ASSERT_VALID(this);

	CSize sizeFixed = CControlBar::CalcFixedLayout(bStretch, bHorz);

	// get __max size
	CSize size__max;
	if (!m_rectLayout.IsRectEmpty())
	{
		CRect rect = m_rectLayout;
		CalcInsideRect(rect, bHorz);
		size__max = rect.Size();
	}
	else
	{
		CRect rectFrame;
		CFrameWnd* pFrame = GetParentFrame();
		pFrame->GetClientRect(&rectFrame);
		size__max = rectFrame.Size();
	}

	// prepare for layout
	AFX_SIZEPARENTPARAMS layout;
	layout.hDWP = m_bLayoutQuery ?
		NULL : ::BeginDeferWindowPos(m_arrBars.GetSize());
	int cxBorder = 2, cyBorder = 2;
	CPoint pt(-cxBorder, -cyBorder);
	int nWidth = 0;

	BOOL bWrapped = FALSE;

	// layout all the control bars
	for (int nPos = 0; nPos < m_arrBars.GetSize(); nPos++)
	{
		CControlBar* pBar = GetDockedControlBar(nPos);
		void* pVoid = m_arrBars[nPos];

		if (pBar != NULL)
		{
			if(pBar->IsKindOf(RUNTIME_CLASS(CToolBarEx)))
			{
			  if (pBar->GetStyle() & TBSTYLE_FLAT)
				cxBorder = cyBorder = 0;
			  else
				cxBorder = cyBorder = 2;
			}
			else
				cxBorder = cyBorder = 2;

			if (pBar->IsVisible())
			{
				// get ideal rect for bar
				DWORD dwMode = 0;
				if ((pBar->m_dwStyle & CBRS_SIZE_DYNAMIC) &&
					(pBar->m_dwStyle & CBRS_FLOATING))
					dwMode |= LM_HORZ | LM_MRUWIDTH;
				else if (pBar->m_dwStyle & CBRS_ORIENT_HORZ)
					dwMode |= LM_HORZ | LM_HORZDOCK;
				else
					dwMode |=  LM_VERTDOCK;

				CSize sizeBar = pBar->CalcDynamicLayout(-1, dwMode);

				CRect rect(pt, sizeBar);

				// get current rect for bar
				CRect rectBar;
				pBar->GetWindowRect(&rectBar);
				ScreenToClient(&rectBar);

				if (bHorz)
				{
					// Offset Calculated Rect out to Actual
					if (rectBar.left > rect.left && !m_bFloating)
						rect.OffsetRect(rectBar.left - rect.left, 0);

					// If ControlBar goes off the right, then right justify
					if (rect.right > size__max.cx && !m_bFloating)
					{
						int x = rect.Width() - cxBorder;
						x = __max(size__max.cx - x, pt.x);
						rect.OffsetRect(x - rect.left, 0);
					}

					// If ControlBar has been wrapped, then left justify
					if (bWrapped)
					{
						bWrapped = FALSE;
						rect.OffsetRect(-(rect.left + cxBorder), 0);
					}
					// If ControlBar is completely invisible, then wrap it
					else if ((rect.left >= (size__max.cx - cxBorder)) &&
						(nPos > 0) && (m_arrBars[nPos - 1] != NULL))
					{
						m_arrBars.InsertAt(nPos, (CObject*)NULL);
						pBar = NULL; pVoid = NULL;
						bWrapped = TRUE;
					}
					if (!bWrapped)
					{
						if (rect != rectBar)
						{
							if (!m_bLayoutQuery &&
								!(pBar->m_dwStyle & CBRS_FLOATING))
							{
								pBar->m_pDockContext->m_rectMRUDockPos = rect;
							}
							AfxRepositionWindow(&layout, pBar->m_hWnd, &rect);
						}
						pt.x = rect.left + sizeBar.cx - cxBorder;
						nWidth = __max(nWidth, sizeBar.cy);
					}
				}
				else
				{
					// Offset Calculated Rect out to Actual
					if (rectBar.top > rect.top && !m_bFloating)
						rect.OffsetRect(0, rectBar.top - rect.top);

					// If ControlBar goes off the bottom, then bottom justify
					if (rect.bottom > size__max.cy && !m_bFloating)
					{
						int y = rect.Height() - cyBorder;
						y = __max(size__max.cy - y, pt.y);
						rect.OffsetRect(0, y - rect.top);
					}

					// If ControlBar has been wrapped, then top justify
					if (bWrapped)
					{
						bWrapped = FALSE;
						rect.OffsetRect(0, -(rect.top + cyBorder));
					}
					// If ControlBar is completely invisible, then wrap it
					else if ((rect.top >= (size__max.cy - cyBorder)) &&
						(nPos > 0) && (m_arrBars[nPos - 1] != NULL))
					{
						m_arrBars.InsertAt(nPos, (CObject*)NULL);
						pBar = NULL; pVoid = NULL;
						bWrapped = TRUE;
					}
					if (!bWrapped)
					{
						if (rect != rectBar)
						{
							if (!m_bLayoutQuery &&
								!(pBar->m_dwStyle & CBRS_FLOATING))
							{
								pBar->m_pDockContext->m_rectMRUDockPos = rect;
							}
							AfxRepositionWindow(&layout, pBar->m_hWnd, &rect);
						}
						pt.y = rect.top + sizeBar.cy - cyBorder;
						nWidth = __max(nWidth, sizeBar.cx);
					}
				}
			}
			if (!bWrapped)
			{
				// handle any delay/show hide for the bar
				pBar->RecalcDelayShow(&layout);
			}
		}
		if (pBar == NULL && pVoid == NULL && nWidth != 0)
		{
			// end of row because pBar == NULL
			if (bHorz)
			{
				pt.y += nWidth - cyBorder;
				sizeFixed.cx = __max(sizeFixed.cx, pt.x);
				sizeFixed.cy = __max(sizeFixed.cy, pt.y);
				pt.x = -cxBorder;
			}
			else
			{
				pt.x += nWidth - cxBorder;
				sizeFixed.cx = __max(sizeFixed.cx, pt.x);
				sizeFixed.cy = __max(sizeFixed.cy, pt.y);
				pt.y = -cyBorder;
			}
			nWidth = 0;
		}
	}
	if (!m_bLayoutQuery)
	{
		// move and resize all the windows at once!
		if (layout.hDWP == NULL || !::EndDeferWindowPos(layout.hDWP))
			TRACE0("Warning: DeferWindowPos failed - low system resources.\n");
	}

	// adjust size for borders on the dock bar itself
	CRect rect;
	rect.SetRectEmpty();
	CalcInsideRect(rect, bHorz);

	if ((!bStretch || !bHorz) && sizeFixed.cx != 0)
		sizeFixed.cx += -rect.right + rect.left;
	if ((!bStretch || bHorz) && sizeFixed.cy != 0)
		sizeFixed.cy += -rect.bottom + rect.top;

	return sizeFixed;
}



// dwDockBarMap
const DWORD dwDockBarMap[4][2] =
{
	{ AFX_IDW_DOCKBAR_TOP,      CBRS_TOP    },
	{ AFX_IDW_DOCKBAR_BOTTOM,   CBRS_BOTTOM },
	{ AFX_IDW_DOCKBAR_LEFT,     CBRS_LEFT   },
	{ AFX_IDW_DOCKBAR_RIGHT,    CBRS_RIGHT  },
};


void FrameEnableDocking(CFrameWnd * pFrame, DWORD dwDockStyle) 
{
	ASSERT_VALID(pFrame);

	// must be CBRS_ALIGN_XXX or CBRS_FLOAT_MULTI only
	ASSERT((dwDockStyle & ~(CBRS_ALIGN_ANY|CBRS_FLOAT_MULTI)) == 0);

	pFrame->EnableDocking(dwDockStyle);

	for (int i = 0; i < 4; i++) {
		if (dwDockBarMap[i][1] & dwDockStyle & CBRS_ALIGN_ANY) {
			CDockBar* pDock = (CDockBar*)pFrame->GetControlBar(dwDockBarMap[i][0]);
			
			// make sure the dock bar is of correct type
			if( pDock == 0 || ! pDock->IsKindOf(RUNTIME_CLASS(CDockBarEx)) ) {
				BOOL bNeedDelete = ! pDock->m_bAutoDelete;
				pDock->m_pDockSite->RemoveControlBar(pDock);
				pDock->m_pDockSite = 0;	// avoid problems in destroying the dockbar
				pDock->DestroyWindow();
				if( bNeedDelete )
					delete pDock;
				pDock = 0;
			}

			if( pDock == 0 ) {
				pDock = new CDockBarEx;
				ASSERT_VALID(pDock);
				if ((!pDock) || (!pDock->Create(pFrame,
					WS_CLIPSIBLINGS|WS_CLIPCHILDREN|WS_CHILD|WS_VISIBLE |
						dwDockBarMap[i][1], dwDockBarMap[i][0]))) {
					AfxThrowResourceException();
				}
			}
		}
	}
}


BOOL CToolBarEx::MarkDefaultState()
{

	 CToolBarCtrl & tbCtrl = GetToolBarCtrl();

		 //Set intial Visible info
	for (int i=0;i<m_ToolBarInfo.GetSize();i++)
	{
		if  ( (m_ToolBarInfo[i].tbButton.fsStyle & TBSTYLE_SEP) == 0) 	//   seperator	?

		{	 // Not a seperator
			 if  (tbCtrl.CommandToIndex(m_ToolBarInfo[i].tbButton.idCommand)==-1)	// button exists on toolbar
			{
				m_ToolBarInfo[i].bInitiallyVisible=FALSE;
			}
			else
			{
				m_ToolBarInfo[i].bInitiallyVisible=TRUE;
			}
		}
		else
		{
			if (m_ToolBarInfo[i].tbButton.idCommand>0)
			{
				if (tbCtrl.CommandToIndex(m_ToolBarInfo[i].tbButton.idCommand)==-1)
				{
					m_ToolBarInfo[i].bInitiallyVisible=FALSE;
				}
				else
				{
					m_ToolBarInfo[i].bInitiallyVisible=TRUE;
				}
			}
			else
			{
					m_ToolBarInfo[i].bInitiallyVisible=TRUE;	// simple seperatores are visible
			}
		}
	}
	return TRUE;
}


By viewing downloads associated with this article you agree to the Terms of Service and the article's licence.

If a file you wish to view isn't highlighted, and is a text file (not binary), please let us know and we'll add colourisation support for it.

License

This article has no explicit license attached to it but may contain usage terms in the article text or the download files themselves. If in doubt please contact the author via the discussion board below.

A list of licenses authors might use can be found here

Share

About the Author

Jonathan de Halleux
Engineer
United States United States
Jonathan de Halleux is Civil Engineer in Applied Mathematics. He finished his PhD in 2004 in the rainy country of Belgium. After 2 years in the Common Language Runtime (i.e. .net), he is now working at Microsoft Research on Pex (http://research.microsoft.com/pex).

| Advertise | Privacy | Mobile
Web04 | 2.8.140826.1 | Last Updated 4 Mar 2003
Article Copyright 2002 by Jonathan de Halleux
Everything else Copyright © CodeProject, 1999-2014
Terms of Service
Layout: fixed | fluid