Click here to Skip to main content
15,896,487 members
Articles / Desktop Programming / MFC

The Ultimate Toolbox - Updates and User Contributions

Rate me:
Please Sign up or sign in to vote.
4.79/5 (26 votes)
12 Feb 2013CPOL8 min read 256.5K   23.7K   170  
Updates and User Contributions for the Ultimate Toolbox Libraries
// OXCoolToolBar.cpp : implementation file
//
// Version: 9.3


#include "stdafx.h"
#include <stdlib.h>

#include "OXCoolToolBar.h"

#include "UTBStrOp.h"

#ifdef OX_CUSTOMIZE_COMMANDS
#include "OXDragDropCommands.h"
#endif	//	OX_CUSTOMIZE_COMMANDS

#if _MFC_VER>0x0421
#include <afxdtctl.h>
#endif

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

const int ID_OXGRIPPER_WIDTH = 0;

/////////////////////////////////////////////////////////////////////////////
/////////////////////////////////////////////////////////////////////////////
// COXCoolToolBar idle update through COXCoolToolBarCmdUI class. 

void COXCoolToolBarCmdUI::Enable(BOOL bOn)
{
	m_bEnableChanged = TRUE;
	COXCoolToolBar* pCoolToolBar = (COXCoolToolBar*)m_pOther;
	CToolBarCtrl* pToolBarCtrl = &pCoolToolBar->GetToolBarCtrl();
	ASSERT(pToolBarCtrl != NULL);
	
	ASSERT(m_nIndex < m_nIndexMax);
	
	// Get toolbar button state
	TBBUTTON TB;
	pToolBarCtrl->GetButton(m_nIndex, &TB);
	BYTE nNewState = (BYTE) (TB.fsState & ~TBSTATE_ENABLED);
	if (bOn)
		nNewState |= TBSTATE_ENABLED;
	if (nNewState != TB.fsState)
	{
#ifdef TBIF_BYINDEX
		TBBUTTONINFO	bi;
		ZeroMemory(&bi, sizeof(bi));
		bi.cbSize=sizeof(bi);
		bi.dwMask = TBIF_BYINDEX | TBIF_STATE;
		bi.fsState = nNewState;

		pToolBarCtrl->SetButtonInfo(m_nIndex, &bi);
#else
		pToolBarCtrl->SetState(m_nID, nNewState);
#endif
	}
}


void COXCoolToolBarCmdUI::SetCheck(int nCheck)
{
	ASSERT(nCheck >= 0 && nCheck <= 2); // 0=>off, 1=>on, 2=>indeterminate
	COXCoolToolBar* pCoolToolBar = (COXCoolToolBar*)m_pOther;
	CToolBarCtrl* pToolBarCtrl = &pCoolToolBar->GetToolBarCtrl();
	ASSERT(pToolBarCtrl != NULL);
	
	ASSERT(m_nIndex < m_nIndexMax);
	
	// Get toolbar button state
	TBBUTTON TB;
	pToolBarCtrl->GetButton(m_nIndex, &TB);	
	BYTE nNewState = (BYTE) (TB.fsState & ~ (TBSTATE_CHECKED | TBSTATE_INDETERMINATE));
	
	if (nCheck == 1)
		nNewState |= TBSTATE_CHECKED;
	else
		if (nCheck == 2)
		nNewState |= TBSTATE_INDETERMINATE;
	
	if (nNewState != TB.fsState)
	{
#ifdef TBIF_BYINDEX
		TBBUTTONINFO	bi;
		ZeroMemory(&bi, sizeof(bi));
		bi.cbSize=sizeof(bi);
		bi.dwMask = TBIF_BYINDEX | TBIF_STATE;
		bi.fsState = nNewState;

		pToolBarCtrl->SetButtonInfo(m_nIndex, &bi);
#else
		pToolBarCtrl->SetState(m_nID, nNewState);
#endif
	}
	
	// should we set the button style too ?
	//	pToolBarCtrl->_SetButtonStyle(m_nIndex, nNewStyle | TBBS_CHECKBOX); 
}

/////////////////////////////////////////////////////////////////////////////
/////////////////////////////////////////////////////////////////////////////
// COXCoolToolBar
/////////////////////////////////////////////////////////////////////////////
/////////////////////////////////////////////////////////////////////////////

#include "OXSkins.h"

DWORD COXCoolToolBar::m_dwComCtlVersion=0;
CMap<int,int,OXCUSTOMBUTTONDESCRIPTOR,OXCUSTOMBUTTONDESCRIPTOR&> 
	COXCoolToolBar::m_mapAllCustomButtons;
CArray<int,int> COXCoolToolBar::m_arrAllCustomButtonIDs;
BOOL COXCoolToolBar::m_bCustomButtonsStateSaved=FALSE;
BOOL COXCoolToolBar::m_bCustomButtonsStateLoaded=FALSE;

IMPLEMENT_DYNAMIC(COXCoolToolBar,CToolBar)

COXCoolToolBar::COXCoolToolBar() :
#if _MFC_VER>=0x0420
	m_bCool(FALSE),
	// by default - flat mode
	m_bSeparator(TRUE), 
	m_nIndent(0),
	// means not set
	m_sizeMinMaxWidth(-1,-1),
	m_crDefaultTextColor(CLR_DEFAULT),
	m_crHotTextColor(CLR_DEFAULT),
	m_crSelectedTextColor(CLR_DEFAULT),
	m_crCheckedTextColor(CLR_DEFAULT),
	m_crDefaultBkColor(CLR_DEFAULT),
	m_crHotBkColor(CLR_DEFAULT),
	m_crSelectedBkColor(CLR_DEFAULT),
	m_crCheckedBkColor(CLR_DEFAULT),
	m_crDefaultBorderColor(CLR_DEFAULT),
	m_crHotBorderColor(CLR_DEFAULT),
	m_crSelectedBorderColor(CLR_DEFAULT),
	m_crCheckedBorderColor(CLR_DEFAULT),
	m_bDropDownArrow(FALSE),
#endif
	m_ttID(TTID_NOTSET),
	m_pBitmapIds(NULL),
	m_nBitmapButtons(0),
	m_hIcon(NULL),
    m_bPrevFloating(3),				// neither TRUE not FALSE;
	m_dwPrevDockSide((DWORD)-1),	// none of side
	m_nCustomizedButtonIndex(-1),
	m_bAdvancedCutomizable(FALSE),
	m_bInAdvancedCustomizationMode(FALSE),
	m_bDragDropOwner(FALSE),
	m_bDragDropOperation(FALSE),
	m_hWndCustomizeOrganizer(NULL),
	m_nDraggedButtonIndex(-1),
	m_bNoInternalRedraw(FALSE),
	m_bNoBkgndRedraw(FALSE),
	m_nIdleFlags(0),
	m_pToolbarSkin(NULL),
	m_iDropDownIndex(-1),
	m_iLastDropDownIndex(-1),
	m_bFloatingEnabled(TRUE),
	m_bSnapWhileDragging(FALSE),
	m_bDragging(FALSE),
	m_ptLButtonDown(0, 0)
{
	m_bWindowsNTRunning=IsWindowsNTRunning();
	if(m_dwComCtlVersion==0)
	{
		DWORD dwMajor, dwMinor;
		if(SUCCEEDED(GetComCtlVersion(&dwMajor, &dwMinor)))
		{
			m_dwComCtlVersion=MAKELONG((WORD)dwMinor, (WORD)dwMajor);
		}
		else
		{
			// assume that neither IE 3.0 nor IE 4.0 installed
			m_dwComCtlVersion=0x00040000;
		}
	}

	m_nDropDownArrowWidth=GetDropDownArrowWidth();

	m_iconRect.SetRectEmpty();
}

COXCoolToolBar::~COXCoolToolBar()
{
	LPTSTR lpszResourceName;

	// delete all bitmaps that we associated with CoolToolBar
	HBITMAP hBitmap;
	POSITION pos=m_allBitmaps.GetStartPosition();
	while(pos!=NULL)
	{
		m_allBitmaps.GetNextAssoc(pos,lpszResourceName,hBitmap);
		::DeleteObject(hBitmap);
	}
	m_allBitmaps.RemoveAll();

	// delete all image lists that we associated with CoolToolBar
	HANDLE hImageList;
	pos=m_allImageLists.GetStartPosition();
	while(pos!=NULL)
	{
		m_allImageLists.GetNextAssoc(pos,lpszResourceName,hImageList);
		ImageList_Destroy((HIMAGELIST)hImageList);
	}
	m_allImageLists.RemoveAll();

	// delete the classic skin
	if (m_pToolbarSkin != NULL)
		delete m_pToolbarSkin;
}

BEGIN_MESSAGE_MAP(COXCoolToolBar, CToolBar)
	//{{AFX_MSG_MAP(COXCoolToolBar)
	ON_WM_NCCREATE()
	ON_WM_NCPAINT()
	ON_WM_PAINT()
	ON_WM_ERASEBKGND()
	ON_WM_NCCALCSIZE()
	ON_WM_WINDOWPOSCHANGING()
	ON_WM_WINDOWPOSCHANGED()
	ON_WM_SETTINGCHANGE()
	ON_WM_LBUTTONDOWN()
	ON_WM_LBUTTONUP()
	ON_WM_MBUTTONDOWN()
	ON_WM_RBUTTONDOWN()
	ON_WM_RBUTTONUP()
	ON_WM_MOUSEMOVE()
	ON_WM_LBUTTONDBLCLK()
	//}}AFX_MSG_MAP
	ON_MESSAGE(TB_INSERTBUTTON, OnInsertButton)
	ON_MESSAGE(TB_DELETEBUTTON, OnDeleteButton)
#if _MFC_VER>=0x0420
	ON_MESSAGE(TB_MOVEBUTTON, OnMoveButton)
#endif

	ON_MESSAGE(WM_IDLEUPDATECMDUI, OnIdleUpdateCmdUI)

	// reflect messages to make customization work
	ON_NOTIFY_REFLECT_EX(TBN_BEGINDRAG, OnTBNBeginDrag)
	ON_NOTIFY_REFLECT_EX(TBN_ENDDRAG, OnTBNEndDrag)
	ON_NOTIFY_REFLECT_EX(TBN_QUERYINSERT, OnTBNQueryInsert)
	ON_NOTIFY_REFLECT_EX(TBN_QUERYDELETE, OnTBNQueryDelete)
	ON_NOTIFY_REFLECT_EX(TBN_TOOLBARCHANGE, OnTBNToolBarChange)
	ON_NOTIFY_REFLECT_EX(TBN_GETBUTTONINFO, OnTBNGetButtonInfo)

	// handle drag'n'drop messages
	ON_MESSAGE(SHBDTM_DRAGENTER, OnDragEnter)
	ON_MESSAGE(SHBDTM_DRAGLEAVE, OnDragLeave)
	ON_MESSAGE(SHBDTM_DRAGOVER, OnDragOver)
	ON_MESSAGE(SHBDTM_DROP, OnDrop)

	// handle advanced customization commands
	ON_COMMAND(ID_OXCUSTTB_DELETE,OnCustTBDelete)
	ON_COMMAND(ID_OXCUSTTB_APPEARANCE,OnCustTBAppearance)
	ON_COMMAND(ID_OXCUSTTB_IMAGEONLY,OnCustTBImageOnly)
	ON_COMMAND(ID_OXCUSTTB_IMAGETEXT,OnCustTBImageText)
	ON_COMMAND(ID_OXCUSTTB_SEPARATOR_BEFORE,OnCustTBSeparatorBefore)
	ON_COMMAND(ID_OXCUSTTB_SEPARATOR_AFTER,OnCustTBSeparatorAfter)

#if _MFC_VER>=0x0420
	// reflect message to provide custom draw functionality
	ON_NOTIFY_REFLECT(NM_CUSTOMDRAW,OnCustomDraw)
#endif

	ON_NOTIFY_REFLECT_EX(TBN_DROPDOWN, OnDropDownButton)
END_MESSAGE_MAP()

/////////////////////////////////////////////////////////////////////////////
// COXCoolToolBar message handlers

BOOL COXCoolToolBar::Create(CWnd* pParentWnd, DWORD dwStyle, UINT nID)
{
//#if _WIN32_IE>=0x0400
	if(m_dwComCtlVersion>=_IE40_COMCTL_VERSION)
	{
		ASSERT_VALID(pParentWnd);   // must have a parent
		ASSERT (!((dwStyle & CBRS_SIZE_FIXED) && (dwStyle & CBRS_SIZE_DYNAMIC)));

		dwStyle|=WS_CLIPCHILDREN;

#if _MFC_VER<=0x0421
		// save the style
		m_dwStyle = dwStyle;
		if (nID == AFX_IDW_TOOLBAR)
			m_dwStyle |= CBRS_HIDE_INPLACE;

		dwStyle &= ~CBRS_ALL;
		dwStyle |= CCS_NOPARENTALIGN|CCS_NODIVIDER|CCS_NORESIZE;

		// by default set flat style
		dwStyle|=TBSTYLE_FLAT;

		// Initialize bar common controls
		static BOOL bInitCoolToolBar = FALSE;
		if (!bInitCoolToolBar) 
		{
			INITCOMMONCONTROLSEX sex;
			sex.dwSize = sizeof(INITCOMMONCONTROLSEX);
			sex.dwICC = ICC_BAR_CLASSES;
			InitCommonControlsEx(&sex);
			bInitCoolToolBar = TRUE;
		}

		// Create the CoolToolBar using style and parent.
		CRect rc;
		rc.SetRectEmpty();
		if(CWnd::CreateEx(WS_EX_TOOLWINDOW, TOOLBARCLASSNAME, NULL,
			dwStyle, rc.left, rc.top, rc.Width(), rc.Height(), 
			pParentWnd->m_hWnd, (HMENU)nID))
#else
		if(CToolBar::Create(pParentWnd, dwStyle, nID))
#endif
		{
#if _MFC_VER>0x0421
			// by default set flat style
			ModifyStyle(0,TBSTYLE_FLAT|TBSTYLE_TRANSPARENT);
			SetBorders(0,0,0,0);
			SetDropDownArrow(TRUE);
#else
			SendMessage(TB_BUTTONSTRUCTSIZE,sizeof(TBBUTTON));
#endif
			if(pParentWnd->IsKindOf(RUNTIME_CLASS(CMDIChildWnd)))
				VERIFY(ModifyStyle(TBSTYLE_TRANSPARENT,0));
		}
		else
			return FALSE;
	}
//#else
	else
	{
		if(!CToolBar::Create(pParentWnd,dwStyle,nID))
			return FALSE;

#if _MFC_VER>=0x0420
		// by default set flat style
		SetFlat();
#endif //_MFC_VER>=0x0420
	}
//#endif //_WIN32_IE>=0x0400

	// register OLE Drag'n'Drop
	COleDropTarget* pOleDropTarget=GetDropTarget();
	ASSERT(pOleDropTarget!=NULL);
	if(!pOleDropTarget->Register(this))
	{
		TRACE(_T("COXCoolToolBar::Create: failed to register the control with COleDropTarget. You've probably forgotten to initialize OLE libraries using AfxOleInit function\n"));
	}

	// Add empty string
	VERIFY(GetToolBarCtrl().AddStrings(_T("\0"))==0);

	return TRUE;
}

BOOL COXCoolToolBar::OnNcCreate(LPCREATESTRUCT lpCreateStruct) 
{
#if _MFC_VER>=0x0420
	if(IsCool())
	{
		// bypass CToolBar/CControlBar
		return (BOOL)Default();
	}
	else
	{
		return CToolBar::OnNcCreate(lpCreateStruct);
	}
#else
	return CToolBar::OnNcCreate(lpCreateStruct);
#endif
}

void COXCoolToolBar::OnNcPaint()
{
	CWindowDC dc(this);

	// Exclude the client rectangle, but not the gripper
	CRect rectWindow, rectClient;
	GetWindowRect(rectWindow);
	GetClientRect(rectClient);
	ClientToScreen(rectClient);
	rectClient.OffsetRect(-rectWindow.left, -rectWindow.top);
	dc.ExcludeClipRect(rectClient);

	CRect rect(0, 0, 0, 0);
	GetWindowRect(rect);
	rect.OffsetRect(-rect.left, -rect.top);

	GetToolbarSkin()->DrawNonClientArea(&dc, rect, this);

#if _MFC_VER>=0x0420
	if(IsCool())
	{
		// bypass CToolBar/CControlBar
		Default();	
	}
	else
	{
		if(IsFlat() && IsGripper())
			DrawGripper(dc,rect);
	}
#endif

	if(m_hIcon!=NULL)
		DrawIcon(dc,rect);

	DrawInBookedSpace(dc,rect);
}

void COXCoolToolBar::OnPaint()
{
	if(m_dwComCtlVersion>=_IE40_COMCTL_VERSION)
	{
		CToolBar::OnPaint();
	}
	else
	{
		// CToolBar has some problems with painting when CToolBar is dockable
		// (due to a bug in comctl32.dll version 4.70 which is supplied with IE 3.0)
		CRect rectUpdate(0,0,0,0);
		GetUpdateRect(&rectUpdate,TRUE);

#if _MFC_VER>=0x0420
		if(IsCool())
		{
			// bypass CToolBar/CControlBar
			Default();	
		}
		else
		{
			if(IsFloating())
			{
				CToolBar::OnPaint();
			}
			else
			{
				Default();	
				if(!IsFlat())
				{
					InvalidateRect(&rectUpdate);
					CToolBar::OnPaint();
				}
			}
		}
#else
		if(IsFloating())
		{
			CToolBar::OnPaint();
		}
		else
		{
			Default();	
			InvalidateRect(&rectUpdate);
			CToolBar::OnPaint();
		}
#endif
	}
}

BOOL COXCoolToolBar::OnEraseBkgnd(CDC* pDC)
{
	if (GetToolbarSkin()->CallOnEraseBkgnd() == TRUE)
		return CToolBar::OnEraseBkgnd(pDC);
	else
		return FALSE;
}

void COXCoolToolBar::OnNcCalcSize(BOOL bCalcValidRects, NCCALCSIZE_PARAMS* lpncsp)
{
#if _MFC_VER>=0x0420
	if(IsCool())
	{
		// bypass CToolBar/CControlBar
		Default();	

		// Change the non-client area of CoolToolBar
		// to make it look pretty in CoolBar
		int nAddIntension=IsFlat() ? 2 : 0;
		if(m_dwStyle&CBRS_ORIENT_HORZ) 
		{
			lpncsp->rgrc[0].top+=nAddIntension;
			lpncsp->rgrc[0].bottom+=nAddIntension;
		} 
		else 
		{
			lpncsp->rgrc[0].left+=nAddIntension;
			lpncsp->rgrc[0].right+=nAddIntension;
		}
	}
	else
	{
		CToolBar::OnNcCalcSize(bCalcValidRects, lpncsp);

		if(IsFlat())
		{
			// adjust non-client area
#if _MFC_VER<=0x0421
			lpncsp->rgrc[0].top+=2;
			lpncsp->rgrc[0].bottom+=2;
#endif
			// adjust non-client area for gripper at left or top
			if(m_dwStyle&CBRS_ORIENT_HORZ) 
			{
				if(IsGripper() && !(m_dwStyle & CBRS_FLOATING))
				{
					lpncsp->rgrc[0].left+=ID_OXGRIPPER_WIDTH;
				}
			} 
			else 
			{
				if(IsGripper() && !(m_dwStyle & CBRS_FLOATING))
				{
					lpncsp->rgrc[0].top+=ID_OXGRIPPER_WIDTH;
				}
			}
		}
	}
#else
	CToolBar::OnNcCalcSize(bCalcValidRects, lpncsp);
#endif

	if(m_hIcon!=NULL)
	{
		// adjust non-client area for icon at left or top
		if(m_dwStyle&CBRS_ORIENT_HORZ) 
		{
			int nIconWidth=::GetSystemMetrics(SM_CXSMICON);
			lpncsp->rgrc[0].left+=nIconWidth+2;
		} 
		else 
		{
			int nIconHeight=::GetSystemMetrics(SM_CYSMICON);
			lpncsp->rgrc[0].top+=nIconHeight+2;
		}
	}

	CRect rectBookedSpace(0,0,0,0);
	BookSpace(rectBookedSpace,(m_dwStyle&CBRS_ORIENT_HORZ) ? LM_HORZ : 0);
	lpncsp->rgrc[0].left+=rectBookedSpace.left;
	lpncsp->rgrc[0].right-=rectBookedSpace.right;
	lpncsp->rgrc[0].top+=rectBookedSpace.top;
	lpncsp->rgrc[0].bottom-=rectBookedSpace.bottom;
}


void COXCoolToolBar::OnWindowPosChanging(WINDOWPOS FAR* lpwndpos) 
{
#if _MFC_VER>=0x0420
	if(IsCool())
	{
		// bypass CToolBar/CControlBar
		Default();	
	}
	else
	{
		CToolBar::OnWindowPosChanging(lpwndpos);
	}
	
#if _MFC_VER<=0x0421
	// TODO: Add your message handler code here
	if (IsFlat() && !(lpwndpos->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.
		//
		pParent->InvalidateRect(&rc);		 // paint old rectangle

		// 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
		//
		if(m_bWindowsNTRunning)
		{
			// we need this code on NT systems 
			// because we've got problem with redrawing
			CRect rect;
			GetWindowRect(&rect);
			// redraw 
			SetWindowPos(NULL,0,0,rect.Width(),rect.Height(),
				SWP_NOMOVE|SWP_NOZORDER|SWP_DRAWFRAME|
				SWP_FRAMECHANGED|SWP_NOREDRAW);
		}
		else
		{
			PostMessage(WM_NCPAINT);
		}
	}
#endif	//	_MFC_VER<=0x0421
#else
	CToolBar::OnWindowPosChanging(lpwndpos);
#endif	//	_MFC_VER>=0x0420
}


void COXCoolToolBar::OnWindowPosChanged(WINDOWPOS FAR* lpwndpos) 
{
	// TODO: Add your message handler code here
	
	if(m_pDockContext!=NULL)
	{
		m_pDockContext->m_bDragging=FALSE;
	}

	CToolBar::OnWindowPosChanged(lpwndpos);

    BOOL bFloating=IsFloating();

	if(bFloating!=m_bPrevFloating)
	{
		m_bPrevFloating=bFloating;
		OnFloatingDocking(bFloating);
	}
	else
	{
		DWORD dwDockSide=GetBarStyle()&CBRS_ALIGN_ANY;
		if(m_dwPrevDockSide!=dwDockSide)
		{
			m_dwPrevDockSide=dwDockSide;
			OnChangeDockSide(m_dwPrevDockSide);
		}
	}

	DelayUpdateCustomButtons();
	SendMessage(WM_NCPAINT, 0, 0);
}


LRESULT COXCoolToolBar::OnIdleUpdateCmdUI(WPARAM wParam, LPARAM lParam)
{
	if(IsWindowVisible())
	{
		// redraw the toolbar if necessary
		if(m_nIdleFlags & oxidleRedrawToolbar)
		{
			RedrawToolBar(TRUE,TRUE);
		}
		
		if(m_nIdleFlags & oxidleUpdateCustomButtons)
		{
			UpdateCustomButtons();
		}

		m_nIdleFlags=0;
	}

	return CToolBar::OnIdleUpdateCmdUI(wParam,lParam);
}


void COXCoolToolBar::OnUpdateCmdUI(CFrameWnd* pTarget, BOOL bDisableIfNoHndler)
{
	COXCoolToolBarCmdUI state;
	state.m_pOther = this;
	
	state.m_nIndexMax = GetToolBarCtrl().GetButtonCount();
	for (state.m_nIndex = 0; state.m_nIndex < state.m_nIndexMax; state.m_nIndex++)
	{
		// get buttons state
		TBBUTTON TB;
		GetToolBarCtrl().GetButton(state.m_nIndex, &TB);
		state.m_nID = TB.idCommand;

		// ignore separators
		if (!(TB.fsStyle & TBSTYLE_SEP) || IsCustomButton(state.m_nIndex))
		{
			// 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 any dialog controls added to the toolbar
	UpdateDialogControls(pTarget, bDisableIfNoHndler);
}


void COXCoolToolBar::OnSettingChange(UINT uFlags, LPCTSTR lpszSection)
{
	UNREFERENCED_PARAMETER(uFlags);
	UNREFERENCED_PARAMETER(lpszSection);

	m_nDropDownArrowWidth=GetDropDownArrowWidth();
	RedrawToolBar();

	CToolBar::OnSettingChange(uFlags, lpszSection);
}


// v9.3 - update 03 - 64-bit - return value was declared as LONG - changed to LRESULT
LRESULT COXCoolToolBar::OnDragEnter(WPARAM wParam, LPARAM lParam)
{
	// toolbar must be in advanced customizable state
	if(!IsCustomizable(TRUE))
		return (LONG)FALSE;

	// set flag that specifies that drag'n'drop operation is active
	m_bDragDropOperation=TRUE;

	// lParam is the pointer to SHBDROPTARGETACTION structure
	LPSHBDROPTARGETACTION pSHBDTAction=(LPSHBDROPTARGETACTION)lParam;
	ASSERT(pSHBDTAction!=NULL);

	ASSERT(pSHBDTAction->pWnd);
	ASSERT(pSHBDTAction->pWnd->GetSafeHwnd()==GetSafeHwnd());

	return OnDragOver(wParam,lParam);
}


// v9.3 - update 03 - 64-bit - return value was declared as LONG - changed to LRESULT
LRESULT COXCoolToolBar::OnDragOver(WPARAM wParam, LPARAM lParam)
{
	UNREFERENCED_PARAMETER(wParam);

	// toolbar must be in advanced customizable state
	if(!IsCustomizable(TRUE))
		return (LONG)FALSE;

	// lParam is the pointer to SHBDROPTARGETACTION structure
	LPSHBDROPTARGETACTION pSHBDTAction=(LPSHBDROPTARGETACTION)lParam;
	ASSERT(pSHBDTAction!=NULL);

	ASSERT(pSHBDTAction->pWnd);
	ASSERT(pSHBDTAction->pWnd->GetSafeHwnd()==GetSafeHwnd());

	pSHBDTAction->result=(LRESULT)DROPEFFECT_NONE;
#ifdef OX_CUSTOMIZE_COMMANDS
	// Can we use this object?
	if(pSHBDTAction->pDataObject->
		IsDataAvailable(COXDragDropCommands::m_cfCommandButton))
	{
		BOOL bQualified=!(m_bDragDropOwner && 
			(pSHBDTAction->dwKeyState & MK_CONTROL)==MK_CONTROL);
		if(bQualified)
		{
			if(!(m_bDragDropOwner && 
				(pSHBDTAction->dwKeyState & MK_CONTROL)!=MK_CONTROL))
			{
				// Get the drag item info
				//
				HGLOBAL hgData=pSHBDTAction->pDataObject->
					GetGlobalData(COXDragDropCommands::m_cfCommandButton);
				ASSERT(hgData!=NULL);
				// lock it
				BYTE* lpItemData=(BYTE*)::GlobalLock(hgData);

				// get button command ID
				int nCommandID=*(int*)lpItemData;
				lpItemData+=sizeof(int);
				
				// unlock it
				::GlobalUnlock(hgData);
				// free it
				::GlobalFree(hgData);

				if(nCommandID<0 || (nCommandID>0 && CommandToIndex(nCommandID)!=-1))
					bQualified=FALSE;
			}

			if(bQualified)
			{
				// analize the current cursor position
				//
				CPoint point=pSHBDTAction->point;

				int nButtonIndex=HitTest(&point);
				BOOL bIsOut=(nButtonIndex<0);
				nButtonIndex=(bIsOut ? -nButtonIndex : nButtonIndex);
				if(nButtonIndex>GetToolBarCtrl().GetButtonCount() && 
					GetToolBarCtrl().GetButtonCount()>0)
				{
					nButtonIndex=-1;
					bQualified=FALSE;
				}
				else
				{
					// check if we are really over custom button, 
					// which is interpreted as separator and never being 
					// reterned as legitimate value from HitTest() function
					CRect rectItem;
					GetItemRect(nButtonIndex,rectItem);
					if(!rectItem.PtInRect(point))
					{
						// check if previous button is custom one
						if(nButtonIndex>0 && IsCustomButton(nButtonIndex-1))
						{
							nButtonIndex--;
						}
					}

					CWnd* pParentWnd=GetParent();
					ASSERT(pParentWnd!=NULL);
					NMTOOLBAR nmtb;
					nmtb.hdr.hwndFrom=GetSafeHwnd();
					nmtb.hdr.idFrom=GetDlgCtrlID();
					nmtb.hdr.code=TBN_QUERYINSERT;
					nmtb.iItem=nButtonIndex;
					if(!pParentWnd->
						SendMessage(WM_NOTIFY,nmtb.hdr.idFrom,(LPARAM)&nmtb))
					{
						bQualified=FALSE;
					}
					else
					{
						TBINSERTMARK tbim;
						if(nButtonIndex==GetToolBarCtrl().GetButtonCount() && 
							nButtonIndex>0)
						{
							tbim.iButton=nButtonIndex-1;
							tbim.dwFlags=TBIMHT_AFTER;
						}
						else
						{
							tbim.iButton=nButtonIndex;
							tbim.dwFlags=0;
							CRect rectItem;
							GetItemRect(tbim.iButton,rectItem);
							if(point.x>=rectItem.left+rectItem.Width()/2 || point.x<0)
							{
								tbim.dwFlags=TBIMHT_AFTER;
							}
						}
						SetInsertMark(&tbim);

						// Check if the control key was pressed          
						if((pSHBDTAction->dwKeyState & MK_CONTROL)==MK_CONTROL)
							pSHBDTAction->result=(LRESULT)DROPEFFECT_COPY;
						else
							pSHBDTAction->result=(LRESULT)DROPEFFECT_MOVE; 
					}
				}
			}
		}
			
		if(!bQualified)
			SetInsertMark(-1);
	}
#endif	//	OX_CUSTOMIZE_COMMANDS

	return (LONG)TRUE;
}


// v9.3 - update 03 - 64-bit - return value was declared as LONG - changed to LRESULT
LRESULT COXCoolToolBar::OnDragLeave(WPARAM wParam, LPARAM lParam)
{
	UNREFERENCED_PARAMETER(wParam);

	if(!IsCustomizable(TRUE))
		return (LONG)FALSE;

	// lParam is the pointer to SHBDROPTARGETACTION structure
	LPSHBDROPTARGETACTION pSHBDTAction=(LPSHBDROPTARGETACTION)lParam;
	ASSERT(pSHBDTAction!=NULL);

	ASSERT(pSHBDTAction->pWnd);
	ASSERT(pSHBDTAction->pWnd->GetSafeHwnd()==GetSafeHwnd());

	SetInsertMark(-1);

	if(!m_bDragDropOwner)
	{
		// reset flag that specifies that drag'n'drop operation is active
		m_bDragDropOperation=FALSE;
	}

	return (LONG)TRUE;
}


// v9.3 - update 03 - 64-bit - return value was declared as LONG - changed to LRESULT
LRESULT COXCoolToolBar::OnDrop(WPARAM wParam, LPARAM lParam)
{
	UNREFERENCED_PARAMETER(wParam);

	if(!IsCustomizable(TRUE))
		return (LONG)FALSE;

	// lParam is the pointer to SHBDROPTARGETACTION structure
	LPSHBDROPTARGETACTION pSHBDTAction=(LPSHBDROPTARGETACTION)lParam;
	ASSERT(pSHBDTAction!=NULL);

	ASSERT(pSHBDTAction->pWnd);
	ASSERT(pSHBDTAction->pWnd->GetSafeHwnd()==GetSafeHwnd());

	pSHBDTAction->result=(LRESULT)FALSE;

#ifdef OX_CUSTOMIZE_COMMANDS
	// if dragged item is to be copied or moved
	if((pSHBDTAction->dropEffect&DROPEFFECT_COPY)!=0 || 
		(pSHBDTAction->dropEffect&DROPEFFECT_MOVE)!=0)
	{
		// data must be in the specific format
		ASSERT(pSHBDTAction->pDataObject->
			IsDataAvailable(COXDragDropCommands::m_cfCommandButton));

		TBINSERTMARK tbim;
		GetInsertMark(&tbim);
		int nButtonIndex=tbim.iButton;
		if(nButtonIndex!=-1 || GetToolBarCtrl().GetButtonCount()==0)
		{
			BOOL bButtonRemainsTheSame=FALSE;
			if(m_bDragDropOwner && (pSHBDTAction->dropEffect&DROPEFFECT_COPY)==0)
			{
				ASSERT(GetToolBarCtrl().GetButtonCount()>0);

				int nDraggedButtonIndex=GetDraggedButton();
				ASSERT(nDraggedButtonIndex!=-1);
				if(nDraggedButtonIndex<GetToolBarCtrl().GetButtonCount()-1 &&
					((tbim.dwFlags==0 && nButtonIndex==nDraggedButtonIndex) ||
					(tbim.dwFlags==TBIMHT_AFTER && 
					(nButtonIndex+1)==nDraggedButtonIndex)))
				{
					if((GetButtonStyle(nDraggedButtonIndex+1)&TBSTYLE_SEP)==0 ||
						IsCustomButton(nDraggedButtonIndex+1))
					{
						TBBUTTON button={ 0 };
						button.fsStyle=TBSTYLE_SEP;
						button.iString=-1;
						button.iBitmap=-1;
						VERIFY(GetToolBarCtrl().
							InsertButton(nDraggedButtonIndex+1,&button));
					}
					bButtonRemainsTheSame=TRUE;
				}
				else if(nDraggedButtonIndex>0 && ((tbim.dwFlags==TBIMHT_AFTER && 
					nButtonIndex==nDraggedButtonIndex) ||
					(tbim.dwFlags==0 && (nButtonIndex-1)==nDraggedButtonIndex)))
				{
					if((GetButtonStyle(nDraggedButtonIndex-1)&TBSTYLE_SEP)==0 ||
						IsCustomButton(nDraggedButtonIndex-1))
					{
						TBBUTTON button={ 0 };
						button.fsStyle=TBSTYLE_SEP;
						button.iString=-1;
						button.iBitmap=-1;
						VERIFY(GetToolBarCtrl().
							InsertButton(nDraggedButtonIndex,&button));
					}
					bButtonRemainsTheSame=TRUE;
				}
				else if((nButtonIndex==nDraggedButtonIndex+2 && tbim.dwFlags==0) ||
					(nButtonIndex==nDraggedButtonIndex+1 && 
					tbim.dwFlags==TBIMHT_AFTER))
				{
					if((GetButtonStyle(nDraggedButtonIndex+1)&TBSTYLE_SEP)!=0 &&
						!IsCustomButton(nDraggedButtonIndex+1))
					{
						VERIFY(GetToolBarCtrl().DeleteButton(nDraggedButtonIndex+1));
						nButtonIndex--;
						bButtonRemainsTheSame=TRUE;
					}
				}
				else if((nButtonIndex==nDraggedButtonIndex-2 && 
					tbim.dwFlags==TBIMHT_AFTER) ||
					(nButtonIndex==nDraggedButtonIndex-1 && tbim.dwFlags==0))
				{
					if((GetButtonStyle(nDraggedButtonIndex-1)&TBSTYLE_SEP)!=0 &&
						!IsCustomButton(nDraggedButtonIndex-1))
					{
						VERIFY(GetToolBarCtrl().DeleteButton(nDraggedButtonIndex-1));
						bButtonRemainsTheSame=TRUE;
					}
				}
			}

			// remove insert mark
			SetInsertMark(-1);

			if(bButtonRemainsTheSame)
			{
				m_bDragDropOperation=FALSE;
				pSHBDTAction->result=(LRESULT)TRUE;
				return (LONG)TRUE;
			}

			nButtonIndex=(tbim.dwFlags==0 ? nButtonIndex : nButtonIndex+1);
			int nButtonCount=GetToolBarCtrl().GetButtonCount();
			if(nButtonIndex==-1)
			{
				ASSERT(nButtonCount==0 && !m_bDragDropOwner);
				nButtonIndex=0;
			}
			else if(nButtonIndex>nButtonCount)
			{
				nButtonIndex=nButtonCount;
			}

			if(m_bDragDropOwner)
			{
#if _MFC_VER<0x0420
				if(!IsCustomButton(GetDraggedButton()))
#endif
				{
					int nOldButtonPos=GetDraggedButton();
					int nNewButtonPos=(nButtonIndex>GetDraggedButton() ? 
						nButtonIndex-1 : nButtonIndex);
					if(nOldButtonPos!=nNewButtonPos)
					{
						// just move button
						VERIFY(MoveButton(nOldButtonPos,nNewButtonPos));
						SetCustomizedButton(nNewButtonPos);
					}

					m_bDragDropOperation=FALSE;
					pSHBDTAction->result=(LRESULT)TRUE;
					return (LONG)TRUE;
				}
			}

			// Get the drag item info
			//
			HGLOBAL hgData=pSHBDTAction->pDataObject->
				GetGlobalData(COXDragDropCommands::m_cfCommandButton);
			ASSERT(hgData!=NULL);
			// lock it
			BYTE* lpItemData=(BYTE*)::GlobalLock(hgData);

			// get button command ID
			int nCommandID=*(int*)lpItemData;
			lpItemData+=sizeof(int);
			
			// get button text
			CString sText((LPTSTR)lpItemData);
			lpItemData+=sText.GetLength()*sizeof(TCHAR)+sizeof(TCHAR);
			int nPosition=sText.Find(_T('\t'));
			if(nPosition!=-1)
				sText=sText.Left(nPosition);
		

			// get button image index
			int nImageIndex=*(int*)lpItemData;
			lpItemData+=sizeof(int);

			// get button style
			BYTE fsStyle=*(BYTE*)lpItemData;
			lpItemData+=sizeof(BYTE);

			if(nCommandID>0 || (nCommandID==0 && nButtonCount>0))
			{
				// determine if dragged button is a custom one
				BOOL bCustomButton=(GetCustomButtonIndex(nCommandID)!=-1);

				if(!bCustomButton)
				{
					// insert new button
					//
					TBBUTTON button={ 0 };
					button.iBitmap=nImageIndex;
					button.idCommand=nCommandID;
					if((fsStyle&TBSTYLE_SEP)==TBSTYLE_SEP)
						fsStyle&=~TBSTYLE_AUTOSIZE;
					else
						fsStyle|=TBSTYLE_AUTOSIZE;
					button.fsStyle=fsStyle;
					button.iString=-1;

					// don't redraw the toolbar contents, we will do it later
					m_bNoInternalRedraw=TRUE;
					VERIFY(GetToolBarCtrl().InsertButton(nButtonIndex,&button));
					m_bNoInternalRedraw=FALSE;
					if(!sText.IsEmpty())
					{
						VERIFY(SetButtonText(nButtonIndex,sText));
					}
					RedrawToolBar(TRUE,TRUE);
					//////////////////////////////
				}
				else
				{
					int nCustomButtonIndex=GetCustomButtonIndex(nCommandID);
					ASSERT(nCustomButtonIndex!=-1);
					// insert new custom button
					VERIFY(InsertCustomButton(nButtonIndex,nCustomButtonIndex));
					if(IsInAdvancedCustomizationMode())
					{
						// set it into customization mode
						OXCUSTOMBUTTONDESCRIPTOR descriptor;
						VERIFY(GetCustomButton(nButtonIndex,descriptor));
						descriptor.m_pCBTemplate->CBSetCustomizationMode(TRUE);
					}
				}
			}

			// unlock it
			::GlobalUnlock(hgData);
			// free it
			::GlobalFree(hgData);

			// drag'n'drop operation completed successfully
			pSHBDTAction->result=(LRESULT)TRUE;
		}
		else
		{
			pSHBDTAction->result=(LRESULT)FALSE;
		}
	}
#endif	//	OX_CUSTOMIZE_COMMANDS

	m_bDragDropOperation=FALSE;

	// we handled the message
	return (LONG)TRUE;
}


LRESULT COXCoolToolBar::OnInsertButton(WPARAM wParam, LPARAM lParam)
{
	UNREFERENCED_PARAMETER(lParam);

	LRESULT lResult=Default();

	if((BOOL)lResult)
	{
		CRect rect;
		GetClientRect(rect);
		ValidateRect(rect);
	
		if((int)wParam<=m_nCustomizedButtonIndex)
		{
			SetCustomizedButton(m_nCustomizedButtonIndex+1);
		}
		if((int)wParam<=m_nDraggedButtonIndex)
		{
			SetDraggedButton(m_nDraggedButtonIndex+1);
		}

		// update custom buttons positions
		for(int nButtonIndex=GetToolBarCtrl().GetButtonCount()-2; 
			nButtonIndex>=(int)wParam; nButtonIndex--)
		{
			OXCUSTOMBUTTONDESCRIPTOR descriptor;
			if(m_mapCustomButtons.Lookup(nButtonIndex,descriptor))
			{
				m_mapCustomButtons.SetAt(nButtonIndex+1,descriptor);
				m_mapCustomButtons.RemoveKey(nButtonIndex);
			}
		}
	}
	RedrawToolBar(TRUE,TRUE);
	
	return lResult;
}


LRESULT COXCoolToolBar::OnDeleteButton(WPARAM wParam, LPARAM lParam)
{
	UNREFERENCED_PARAMETER(lParam);

	LRESULT lResult=Default();
	
	if((BOOL)lResult)
	{
		CRect rect;
		GetClientRect(rect);
		ValidateRect(rect);
	
		int nButtonIndex=(int)wParam;

		// delete custom button if any found
		OXCUSTOMBUTTONDESCRIPTOR descriptor;
		if(GetCustomButton(nButtonIndex,descriptor))
		{
			descriptor.m_pCBTemplate->CBDelete();
			m_mapCustomButtons.RemoveKey(nButtonIndex);
		}
		// update custom buttons positions
		for(int nIndex=nButtonIndex+1; 
			nIndex<=GetToolBarCtrl().GetButtonCount(); nIndex++)
		{
			OXCUSTOMBUTTONDESCRIPTOR descriptor;
			if(m_mapCustomButtons.Lookup(nIndex,descriptor))
			{
				m_mapCustomButtons.SetAt(nIndex-1,descriptor);
				m_mapCustomButtons.RemoveKey(nIndex);
			}
		}

		if(nButtonIndex<m_nCustomizedButtonIndex)
			SetCustomizedButton(m_nCustomizedButtonIndex-1);
		else if(nButtonIndex==m_nCustomizedButtonIndex)
			SetCustomizedButton(-1);

		if(nButtonIndex<m_nDraggedButtonIndex)
			SetDraggedButton(m_nDraggedButtonIndex-1);
		else if(nButtonIndex==m_nDraggedButtonIndex)
			SetDraggedButton(-1);

		int nButtonCount=GetToolBarCtrl().GetButtonCount();
		if(nButtonIndex==nButtonCount && nButtonCount>0 &&
			GetButtonStyle(nButtonCount-1)&TBBS_SEPARATOR &&
			!IsCustomButton(nButtonCount-1))
		{
			m_bNoInternalRedraw=TRUE;
			VERIFY(GetToolBarCtrl().DeleteButton(nButtonCount-1));
			m_bNoInternalRedraw=FALSE;
		}
		nButtonCount=GetToolBarCtrl().GetButtonCount();
		if(nButtonIndex==0 && nButtonCount>0 &&	
			GetButtonStyle(0)&TBBS_SEPARATOR &&	!IsCustomButton(0))
		{
			m_bNoInternalRedraw=TRUE;
			VERIFY(GetToolBarCtrl().DeleteButton(0));
			m_bNoInternalRedraw=FALSE;
		}
	}

	RedrawToolBar(TRUE,TRUE);
	
	return lResult;
}


#if _MFC_VER>=0x0420
LRESULT COXCoolToolBar::OnMoveButton(WPARAM wParam, LPARAM lParam)
{
	UNREFERENCED_PARAMETER(lParam);

	LRESULT lResult=Default();
	
	if((BOOL)lResult && (int)wParam!=(int)lParam)
	{
		OXCUSTOMBUTTONDESCRIPTOR descriptorMoved;
		BOOL bCustomButton=GetCustomButton((int)wParam,descriptorMoved);
		BOOL bDeleteMovedDescriptor=FALSE;

		int nMinButtonIndex=__min((int)wParam,(int)lParam);
		int nMaxButtonIndex=__max((int)wParam,(int)lParam);

		// update custom buttons positions
		if((int)wParam<(int)lParam)
		{
			bDeleteMovedDescriptor=
				bCustomButton && !IsCustomButton(nMinButtonIndex+1);

			for(int nIndex=nMinButtonIndex+1; 
				nIndex<=nMaxButtonIndex; nIndex++)
			{
				OXCUSTOMBUTTONDESCRIPTOR descriptor;
				if(m_mapCustomButtons.Lookup(nIndex,descriptor))
				{
					m_mapCustomButtons.SetAt(nIndex-1,descriptor);
					m_mapCustomButtons.RemoveKey(nIndex);
				}
			}

			if(bCustomButton)
			{
				m_mapCustomButtons.SetAt(nMaxButtonIndex,descriptorMoved);
				if(bDeleteMovedDescriptor)
				{
					m_mapCustomButtons.RemoveKey(nMinButtonIndex);
				}
			}
		}
		else
		{
			bDeleteMovedDescriptor=
				bCustomButton && !IsCustomButton(nMaxButtonIndex-1);

			for(int nIndex=nMaxButtonIndex-1; 
				nIndex>=nMinButtonIndex; nIndex--)
			{
				OXCUSTOMBUTTONDESCRIPTOR descriptor;
				if(m_mapCustomButtons.Lookup(nIndex,descriptor))
				{
					m_mapCustomButtons.SetAt(nIndex+1,descriptor);
					m_mapCustomButtons.RemoveKey(nIndex);
				}
			}

			if(bCustomButton)
			{
				m_mapCustomButtons.SetAt(nMinButtonIndex,descriptorMoved);
				if(bDeleteMovedDescriptor)
				{
					m_mapCustomButtons.RemoveKey(nMaxButtonIndex);
				}
			}
		}

		UpdateCustomButtons(nMinButtonIndex,nMaxButtonIndex);
	}

	return lResult;
}
#endif


void COXCoolToolBar::OnLButtonDown(UINT nFlags, CPoint point)
{
	if(IsInAdvancedCustomizationMode() && IsCustomizable(TRUE))
	{
		int nButtonIndex=HitTest(&point);
		if(nButtonIndex>=0 && nButtonIndex<GetToolBarCtrl().GetButtonCount())
		{
			SetCustomizedButton(nButtonIndex);
		}
		else
		{
			if(IsCustomButton(-nButtonIndex-1))
			{
				SetCustomizedButton(-nButtonIndex-1);
			}
			else
			{
				SetCustomizedButton(-1);
			}
		}

		CWnd::OnLButtonDown(nFlags,point);

		if(nButtonIndex>=0 && nButtonIndex<GetToolBarCtrl().GetButtonCount())
		{
			int nState=GetToolBarCtrl().GetState(GetItemID(nButtonIndex));
			if((nState&TBSTATE_PRESSED)!=0)
			{
				GetToolBarCtrl().SetState(GetItemID(nButtonIndex),
					nState&~TBSTATE_PRESSED);
			}
		}

		return;
	}

	if (IsFloatingEnabled() || (!IsFloatingEnabled() && HitTest(&point) >= 0))
	{
		if (AfxGetMainWnd()->SendMessage(WM_QUERYSNAPPING))
		{
			// only start dragging if clicked in "void" space
			if (m_pDockBar != NULL && OnToolHitTest(point, NULL) == -1)
			{
				// Start dragging
				SaveMouseOffset(point);
				m_bDragging = TRUE;
				SetCapture();
				::SetCursor(AfxGetApp()->LoadStandardCursor(IDC_SIZEALL));
			}
			else
			{
				CWnd::OnLButtonDown(nFlags, point);
			}
		}
		else
			CToolBar::OnLButtonDown(nFlags, point);
	}
}


void COXCoolToolBar::OnLButtonUp(UINT nFlags, CPoint point)
{
	if (m_bDragging)
	{
		ReleaseCapture();
		m_bDragging = FALSE;
		return;
	}

	if(IsInAdvancedCustomizationMode() && IsCustomizable(TRUE))
	{
		return;
	}

	CToolBar::OnLButtonUp(nFlags,point);

	// update the state of the clicked button right away
	if(::IsWindow(GetSafeHwnd()))
	{
		SendMessage(WM_IDLEUPDATECMDUI);
	}
}


void COXCoolToolBar::OnMButtonDown(UINT nFlags, CPoint point)
{
	if(IsInAdvancedCustomizationMode() && IsCustomizable(TRUE))
	{
		int nButtonIndex=HitTest(&point);
		if(nButtonIndex>=0 && nButtonIndex<GetToolBarCtrl().GetButtonCount())
		{
			SetCustomizedButton(nButtonIndex);
		}
		else
		{
			if(IsCustomButton(-nButtonIndex-1))
			{
				SetCustomizedButton(-nButtonIndex-1);
			}
			else
			{
				SetCustomizedButton(-1);
			}
		}

		return;
	}

	CToolBar::OnMButtonDown(nFlags,point);
}


void COXCoolToolBar::OnRButtonDown(UINT nFlags, CPoint point)
{
	if(IsInAdvancedCustomizationMode() && IsCustomizable(TRUE))
	{
		int nButtonIndex=HitTest(&point);
		if(nButtonIndex>=0 && nButtonIndex<GetToolBarCtrl().GetButtonCount())
		{
			SetCustomizedButton(nButtonIndex);
		}
		else
		{
			if(IsCustomButton(-nButtonIndex-1))
			{
				SetCustomizedButton(-nButtonIndex-1);
			}
			else
			{
				SetCustomizedButton(-1);
			}
		}

		return;
	}

	CToolBar::OnRButtonDown(nFlags,point);
}


void COXCoolToolBar::OnRButtonUp(UINT nFlags, CPoint point)
{
	if(IsInAdvancedCustomizationMode() && IsCustomizable(TRUE))
	{
		int nCustomizedButtonIndex=GetCustomizedButton();
		if(nCustomizedButtonIndex!=-1)
		{
			ClientToScreen(&point);
			VERIFY(DisplayCustomizeButtonContextMenu(nCustomizedButtonIndex,point));
			return;
		}
	}

	CToolBar::OnRButtonUp(nFlags,point);
}


void COXCoolToolBar::OnMouseMove(UINT nFlags, CPoint point)
{
	if(IsInAdvancedCustomizationMode() && IsCustomizable(TRUE))
	{
		return;
	}

	if (m_bDragging)
	{
		// Make sure the mouse button is still down
		if (::GetKeyState(VK_LBUTTON) >= 0)
		{
			// No longer down
			ReleaseCapture();
			m_bDragging = FALSE;
			return;
		}

		CPoint ptScreen = point;
		ClientToScreen(&point);
		CRect rectWindow;
		GetWindowRect(rectWindow);
		CRect rectDock(point.x, point.y, point.x + rectWindow.Width(), point.y + rectWindow.Height());
		
		// Get the appropriate dock bar. If one is not found then float.
		CFrameWnd* pFrameWnd = DYNAMIC_DOWNCAST(CFrameWnd, ::AfxGetMainWnd());
		if (pFrameWnd == NULL)
		{
			ReleaseCapture();
			m_bDragging = FALSE;
			return;
		}

		// Handle pending WM_PAINT messages
		MSG msg;
		while (::PeekMessage(&msg, NULL, WM_PAINT, WM_PAINT, PM_NOREMOVE))
		{
			if (!GetMessage(&msg, NULL, WM_PAINT, WM_PAINT))
			{
				ReleaseCapture();
				m_bDragging = FALSE;
				return;
			}
			DispatchMessage(&msg);
		}

		if (m_pDockContext == NULL)
			pFrameWnd->FloatControlBar(this, point);
		else
		{
			COXSizeDockBar* pDockBar = COXSizeDockBar::GetAppropriateDockBar(point, this);
			if (pDockBar == NULL || nFlags & MK_CONTROL)
				pFrameWnd->FloatControlBar(this, point - m_ptOffset);			
			else
				pDockBar->DockControlBar(this, rectDock);
		}
	}
	else
		CToolBar::OnMouseMove(nFlags,point);
}


void COXCoolToolBar::OnLButtonDblClk(UINT nFlags, CPoint point)
{
	if(IsInAdvancedCustomizationMode() && IsCustomizable(TRUE))
	{
		return;
	}

	if (!IsFloatingEnabled())
	{
		if (HitTest(&point) >= 0)
			CToolBar::OnLButtonDblClk(nFlags,point);
	}
	else
		CToolBar::OnLButtonDblClk(nFlags,point);
}


int COXCoolToolBar::SetCustomizedButton(int nIndex) 
{ 
	int nOldCustomizedButtonIndex=m_nCustomizedButtonIndex;
	m_nCustomizedButtonIndex=nIndex;
	if(nOldCustomizedButtonIndex!=nIndex)
	{
		RedrawButton(nOldCustomizedButtonIndex);
	}
	if(nIndex!=-1)
	{
		int nState=GetToolBarCtrl().GetState(GetItemID(nIndex));
		if((nState&TBSTATE_PRESSED)!=0)
		{
			GetToolBarCtrl().SetState(GetItemID(nIndex),nState&~TBSTATE_PRESSED);
		}
		else
		{
			RedrawButton(nIndex);
		}
	}
	SendCustomizeNotification(ID_OXCUSTTB_SET_CUSTOMIZE_BUTTON);
	return nOldCustomizedButtonIndex;
}


BOOL COXCoolToolBar::DisplayCustomizeButtonContextMenu(int nButtonIndex, CPoint point)
{
	ASSERT(::IsWindow(GetSafeHwnd()));
	ASSERT(nButtonIndex>=0 && nButtonIndex<GetToolBarCtrl().GetButtonCount());

	CString sText=GetButtonText(nButtonIndex);
	TBBUTTON button;
	VERIFY(GetToolBarCtrl().GetButton(nButtonIndex,&button));
	ASSERT((button.fsStyle&TBSTYLE_SEP)==0 || IsCustomButton(nButtonIndex));
	ASSERT(!(sText.IsEmpty() && button.iBitmap==-1));

	CMenu menu;
	if(!menu.CreatePopupMenu())
		return FALSE;
	// populate menu
	CString sItem;
	sItem.LoadString(IDS_OX_CUSTTB_DELETE);
	VERIFY(menu.AppendMenu(MF_STRING,ID_OXCUSTTB_DELETE,sItem));
	VERIFY(menu.AppendMenu(MF_SEPARATOR));
	sItem.LoadString(IDS_OX_CUSTTB_APPEARANCE);
	VERIFY(menu.AppendMenu(MF_STRING,ID_OXCUSTTB_APPEARANCE,sItem));
	if((button.fsStyle&TBSTYLE_SEP)==0 && !IsCustomButton(nButtonIndex))
	{
		sItem.LoadString(IDS_OX_CUSTTB_IMAGEONLY);
		VERIFY(menu.AppendMenu(MF_STRING|(sText.IsEmpty() ? MF_CHECKED : MF_UNCHECKED),
			ID_OXCUSTTB_IMAGEONLY,sItem));
		sItem.LoadString(IDS_OX_CUSTTB_IMAGETEXT);
		VERIFY(menu.AppendMenu(MF_STRING|(!sText.IsEmpty() && button.iBitmap!=-1 ? 
			MF_CHECKED : MF_UNCHECKED),ID_OXCUSTTB_IMAGETEXT,sItem));
	}
	VERIFY(menu.AppendMenu(MF_SEPARATOR));
	sItem.LoadString(IDS_OX_CUSTTB_SEPARATOR_BEFORE);
	VERIFY(menu.AppendMenu(MF_STRING|
		((nButtonIndex>0 && ((GetButtonStyle(nButtonIndex-1)&TBBS_SEPARATOR)==0 ||
		IsCustomButton(nButtonIndex-1))) ? 0 : MF_GRAYED),
		ID_OXCUSTTB_SEPARATOR_BEFORE,sItem));
	sItem.LoadString(IDS_OX_CUSTTB_SEPARATOR_AFTER);
	VERIFY(menu.AppendMenu(MF_STRING|
		((nButtonIndex<GetToolBarCtrl().GetButtonCount()-1 && 
		((GetButtonStyle(nButtonIndex+1)&TBBS_SEPARATOR)==0 ||
		IsCustomButton(nButtonIndex+1))) ? 0 : MF_GRAYED),
		ID_OXCUSTTB_SEPARATOR_AFTER,sItem));

	menu.TrackPopupMenu(TPM_LEFTALIGN|TPM_LEFTBUTTON|TPM_RIGHTBUTTON,
		point.x,point.y,this);

	return TRUE;
}


void COXCoolToolBar::OnCustTBDelete()
{
	ASSERT(IsInAdvancedCustomizationMode());
	int nCustomizedButtonIndex=GetCustomizedButton();
	ASSERT(nCustomizedButtonIndex!=-1);

	if(SendCustomizeNotification(ID_OXCUSTTB_DELETE))
		return;

	VERIFY(GetToolBarCtrl().DeleteButton(nCustomizedButtonIndex));
}

void COXCoolToolBar::OnCustTBAppearance()
{
	ASSERT(IsInAdvancedCustomizationMode());
	int nCustomizedButtonIndex=GetCustomizedButton();
	ASSERT(nCustomizedButtonIndex!=-1);
	UNUSED(nCustomizedButtonIndex);

	SendCustomizeNotification(ID_OXCUSTTB_APPEARANCE);	
}

void COXCoolToolBar::OnCustTBImageOnly()
{
	ASSERT(IsInAdvancedCustomizationMode());
	int nCustomizedButtonIndex=GetCustomizedButton();
	ASSERT(nCustomizedButtonIndex!=-1);

	if(SendCustomizeNotification(ID_OXCUSTTB_IMAGEONLY))
		return;

	UINT nCommandID=GetItemID(nCustomizedButtonIndex);
#ifdef _DEBUG
	TBBUTTON button;
	VERIFY(GetToolBarCtrl().GetButton(nCustomizedButtonIndex,&button));
	ASSERT(button.iBitmap!=-1);
#endif

	CString sText=GetButtonText(nCustomizedButtonIndex);
	if(!sText.IsEmpty())
	{
		m_mapButtonText.SetAt(nCommandID,sText);
		SetButtonText(nCustomizedButtonIndex,_T(""));
		RedrawToolBar(TRUE,TRUE);
	}
}

void COXCoolToolBar::OnCustTBImageText()
{
	ASSERT(IsInAdvancedCustomizationMode());
	int nCustomizedButtonIndex=GetCustomizedButton();
	ASSERT(nCustomizedButtonIndex!=-1);

	if(SendCustomizeNotification(ID_OXCUSTTB_IMAGETEXT))
		return;

	UINT nCommandID=GetItemID(nCustomizedButtonIndex);
#ifdef _DEBUG
	TBBUTTON button;
	VERIFY(GetToolBarCtrl().GetButton(nCustomizedButtonIndex,&button));
	ASSERT(button.iBitmap!=-1);
#endif

	CString sText=GetButtonText(nCustomizedButtonIndex);
	if(sText.IsEmpty())
	{
		if(!m_mapButtonText.Lookup(nCommandID,sText))
		{
			HINSTANCE hInstance=
				AfxFindResourceHandle(MAKEINTRESOURCE(nCommandID),RT_STRING);
			ASSERT(hInstance!=NULL);
			sText.LoadString(nCommandID);
			int nPosition=sText.Find(_T('\n'));
			if(nPosition!=-1)
				sText=sText.Mid(nPosition+1);
		}
		if(!sText.IsEmpty())
		{
			SetButtonText(nCustomizedButtonIndex,sText);
			RedrawToolBar(TRUE,TRUE);
		}
	}
}

void COXCoolToolBar::OnCustTBSeparatorBefore()
{
	ASSERT(IsInAdvancedCustomizationMode());
	int nCustomizedButtonIndex=GetCustomizedButton();
	ASSERT(nCustomizedButtonIndex!=-1);

	if(SendCustomizeNotification(ID_OXCUSTTB_SEPARATOR_BEFORE))
		return;

	TBBUTTON button={ 0 };
	button.fsStyle=TBSTYLE_SEP;
	button.iString=-1;
	button.iBitmap=-1;
	VERIFY(GetToolBarCtrl().
		InsertButton(nCustomizedButtonIndex,&button));
}

void COXCoolToolBar::OnCustTBSeparatorAfter()
{
	ASSERT(IsInAdvancedCustomizationMode());
	int nCustomizedButtonIndex=GetCustomizedButton();
	ASSERT(nCustomizedButtonIndex!=-1);

	if(SendCustomizeNotification(ID_OXCUSTTB_SEPARATOR_AFTER))
		return;

	TBBUTTON button={ 0 };
	button.fsStyle=TBSTYLE_SEP;
	button.iString=-1;
	button.iBitmap=-1;
	VERIFY(GetToolBarCtrl().
		InsertButton(nCustomizedButtonIndex+1,&button));
}


LRESULT COXCoolToolBar::SendCustomizeNotification(UINT nCustomizeCmdID,
												  LPARAM lParam/*=NULL*/)
{
	HWND hWnd=m_hWndCustomizeOrganizer;
	if(hWnd==NULL)
	{
		hWnd=::GetParent(GetSafeHwnd());
	}
	if(hWnd==NULL)
		return (LRESULT)0;

	NMCTBCUSTOMIZE nmctbCustomize;
	nmctbCustomize.nmhdr.code=OXCTBN_CUSTOMIZECMD;
	nmctbCustomize.nmhdr.hwndFrom=GetSafeHwnd();
	nmctbCustomize.nmhdr.idFrom=GetDlgCtrlID();
	nmctbCustomize.nCustomizeEventID=nCustomizeCmdID;
	nmctbCustomize.lParam=lParam;

	return ::SendMessage(hWnd,WM_NOTIFY,(WPARAM)nmctbCustomize.nmhdr.idFrom,
		(LPARAM)&nmctbCustomize);
}


CString COXCoolToolBar::GetRecentButtonText(UINT nCommandID)
{
	CString sText(_T(""));
	m_mapButtonText.Lookup(nCommandID,sText);
	return sText;
}

#if _MFC_VER>=0x0420
////////////////////
void COXCoolToolBar::EraseNonClient()
{
	// 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);
	rectWindow.OffsetRect(-rectWindow.left, -rectWindow.top);

	// draw borders in non-client area
	if(!IsCool())
	{
		// only if CoolToolBar is not used in CoolBar
		DrawBorders(&dc, rectWindow);

		// fixing for spurious edges
		if((m_dwStyle&CBRS_BORDER_3D)==0)
		{
			rectWindow.InflateRect(1,1);
		}
	}

	// erase parts not drawn
	dc.IntersectClipRect(rectWindow);
	dc.ExcludeClipRect(rectClient);
	SendMessage(WM_ERASEBKGND, (WPARAM) dc.m_hDC);
}

void COXCoolToolBar::DrawGripper(CDC& dc, CRect& rect)
{ 
	GetToolbarSkin()->DrawGripper(&dc, rect, this);
}

void COXCoolToolBar::DrawSeparator(CDC& dc, CRect& rc)
{
	GetToolbarSkin()->DrawSeparator(&dc, rc, this);
}

void COXCoolToolBar::DrawIcon(CDC& dc, CRect& rect)
{
	if(m_hIcon==NULL)
		return;

	m_iconRect=rect;

	if(m_dwStyle&CBRS_ORIENT_HORZ) 
	{
		if(m_iconRect.left==0 && !IsFloating())
		{
			m_iconRect.left += 10;
			m_iconRect.top=(rect.Height()-::GetSystemMetrics(SM_CYSMICON))/2;
		}
		else
		{
			m_iconRect.left += 3;
			m_iconRect.top = 3;
		}

		m_iconRect.right=m_iconRect.left+::GetSystemMetrics(SM_CXSMICON);
		m_iconRect.bottom=m_iconRect.top+::GetSystemMetrics(SM_CYSMICON);
		rect.left=m_iconRect.right+1;
	} 
	else 
	{
		if(m_iconRect.top==0 && !IsFloating())
			m_iconRect.top += 10;
		else
			m_iconRect.top += 3;

		m_iconRect.bottom=m_iconRect.top+::GetSystemMetrics(SM_CYSMICON);
		m_iconRect.left=(rect.Width()-::GetSystemMetrics(SM_CXSMICON))/2;
		m_iconRect.right=m_iconRect.left+::GetSystemMetrics(SM_CXSMICON);

		rect.top=m_iconRect.bottom+1;
	}

	::DrawIconEx(dc,m_iconRect.left,m_iconRect.top,m_hIcon,
		m_iconRect.Width(),m_iconRect.Height(),0,NULL,DI_NORMAL);
}

void COXCoolToolBar::DrawCustomizedButton(CDC& dc, CRect& rect)
{
	GetToolbarSkin()->DrawCustomizedButton(&dc, rect, this);
}

void COXCoolToolBar::SetDropDownArrow(BOOL bDropDownArrow) 
{ 
	if(m_dwComCtlVersion>=_IE40_COMCTL_VERSION)
	{
		DWORD dwStyleEx=GetStyleEx();
		dwStyleEx=bDropDownArrow ? dwStyleEx|TBSTYLE_EX_DRAWDDARROWS : 
			dwStyleEx&~TBSTYLE_EX_DRAWDDARROWS;
		SetStyleEx(dwStyleEx); 
	}

	m_bDropDownArrow=bDropDownArrow;
}

BOOL COXCoolToolBar::IsDropDownArrow() const
{ 
	if(m_dwComCtlVersion>=_IE40_COMCTL_VERSION)
	{
		return GetStyleEx()&TBSTYLE_EX_DRAWDDARROWS ? TRUE : FALSE; 
	}

	return m_bDropDownArrow;
}

////////////////////
#endif

void COXCoolToolBar::SetCustomizable(BOOL bCustomizable/*=TRUE*/,
									 BOOL bAdvanced/*=TRUE*/)
{
	// set CoolToolBar customizable only if array of bitmap IDs was previously set 
	// by function SetBitmapIds()

	if(m_pBitmapIds==NULL)
	{
		bCustomizable=FALSE;
	}
	
	if(bCustomizable && !bAdvanced)
		ModifyStyle(0,CCS_ADJUSTABLE);
	else
		ModifyStyle(CCS_ADJUSTABLE,0);

	m_bAdvancedCutomizable=bCustomizable&bAdvanced;
}


void COXCoolToolBar::SetBitmapIds(UINT* pIds, int nButtons)
{
	m_pBitmapIds=pIds;
	m_nBitmapButtons=nButtons;

	// if we call this function then we probably want our CoolToolBar 
	// to be customizable
	SetCustomizable();
}


int COXCoolToolBar::FindBitmapIndex(UINT nID) const
{
	// helper function to find the number of element in array of bitmap IDs
	// by its ID
	ASSERT(m_pBitmapIds != NULL);
	for (int i = 0; i < m_nBitmapButtons ; i++)
	{
		if (m_pBitmapIds[i] == (int)nID)
			return i;
	}
	return -1;
}


void COXCoolToolBar::SetAdvancedCustomizationMode(BOOL bInAdvancedCustomizationMode,
												  HWND hWndCustomizeOrganizer/*=NULL*/) 
{ 
	if(bInAdvancedCustomizationMode && !IsCustomizable(TRUE))
	{
		SetCustomizable(TRUE,TRUE);
	}
	if(!bInAdvancedCustomizationMode)
	{
		SetCustomizedButton(-1);
	}
	m_hWndCustomizeOrganizer=hWndCustomizeOrganizer;
	m_bInAdvancedCustomizationMode=bInAdvancedCustomizationMode;

	// reset the customization mode for custom button windows
	POSITION pos=m_mapCustomButtons.GetStartPosition();
	while(pos!=NULL)
	{
		int nIndex=-1;
		OXCUSTOMBUTTONDESCRIPTOR descriptor;
		m_mapCustomButtons.GetNextAssoc(pos,nIndex,descriptor);
		ASSERT(nIndex>=0 && nIndex<GetToolBarCtrl().GetButtonCount());
		descriptor.m_pCBTemplate->CBSetCustomizationMode(bInAdvancedCustomizationMode);
	}
}


// Return information for bitmap indexes in the toolbar
BOOL COXCoolToolBar::OnTBNGetButtonInfo(NMHDR* pNMHDR, LRESULT* pResult)
{
	TBNOTIFY* pTBN=(TBNOTIFY*)pNMHDR;
	
	int nIndex=pTBN->iItem;
	if(nIndex<m_nBitmapButtons)
	{
		*pResult=TRUE;

		// find button's ID by its image index
		UINT nButtonId=m_pBitmapIds[nIndex];
		pTBN->tbButton.iBitmap=nIndex;
		pTBN->tbButton.idCommand=nButtonId;
		pTBN->tbButton.fsState=TBSTATE_ENABLED;
		pTBN->tbButton.fsStyle=TBSTYLE_BUTTON;
		pTBN->tbButton.iString=-1;		
		// use as tooltip as text associated with button shown in Customize dialog
		if(pTBN->pszText!=NULL)
		{		
			CString strText;
			if(strText.LoadString(nButtonId))
			{
				// tool tip is after "\n" in the string
				LPCTSTR pTipText=_tcschr(strText,_T('\n'));   
				if(pTipText!=NULL)
				{	
					const int len = (int)_tcslen(pTipText+1);

					UTBStr::tcsncpy(pTBN->pszText,len+1,pTipText+1,len);
					return TRUE;
				}
			}
			TRACE(_T("COXCoolToolBar:No Tooltip prompt for ID=%d\n"),nButtonId);
			UTBStr::tcsncpy(pTBN->pszText,4,_T("???"),3);
		}
	}
	else 
	{
		*pResult=FALSE;
	}

	return TRUE;
}


BOOL COXCoolToolBar::OnTBNBeginDrag(NMHDR* pNMHDR, LRESULT* pResult)
{
	NMTOOLBAR* pNMToolBar=(NMTOOLBAR*)pNMHDR;

	BOOL bCustomButton=IsCustomButtonWnd(pNMToolBar->iItem);
	int nIndex=(!bCustomButton ? CommandToIndex(pNMToolBar->iItem) : 
		GetCustomButtonPosition(pNMToolBar->iItem));
	ASSERT((nIndex>=0 && nIndex<GetToolBarCtrl().GetButtonCount()));

#ifdef OX_CUSTOMIZE_COMMANDS
	if(IsInAdvancedCustomizationMode() || (IsCustomizable(TRUE) && 
		((GetStyle()&TBSTYLE_ALTDRAG && ::GetKeyState(VK_MENU)<0) ||
		(!(GetStyle()&TBSTYLE_ALTDRAG) && ::GetKeyState(VK_SHIFT)<0))))
	{
		if(!bCustomButton)
		{
			int nState=GetToolBarCtrl().GetState(GetItemID(nIndex));
			if((nState&TBSTATE_PRESSED)!=0)
			{
				GetToolBarCtrl().SetState(GetItemID(nIndex),nState&~TBSTATE_PRESSED);
			}
		}

		CWnd* pParentWnd=GetParent();
		ASSERT(pParentWnd!=NULL);
		pNMToolBar->hdr.code=TBN_QUERYDELETE;
		if(pParentWnd->
			SendMessage(WM_NOTIFY,pNMToolBar->hdr.idFrom,(LPARAM)pNMToolBar))
		{
			BOOL bWasInAdvancedCustomizationMode=IsInAdvancedCustomizationMode();
			if(GetCustomizedButton()!=nIndex)
			{
				SetCustomizedButton(nIndex);
			}
			SetDraggedButton(nIndex);

			// mark the control as the one that launched drag'n'drop operation
			m_bDragDropOwner=TRUE;

			TBBUTTON button;
			VERIFY(GetToolBarCtrl().GetButton(nIndex,&button));
			COleDataSource* pDataSource=
				COXDragDropCommands::PrepareDragDropData(GetButtonText(nIndex),
				button.iBitmap,button.idCommand,button.fsStyle);
			ASSERT(pDataSource!=NULL);

			// analyze current mouse position
			CPoint ptMouse;
			::GetCursorPos(&ptMouse);
			CRect rectWindow;
			GetWindowRect(rectWindow);
			if(!rectWindow.PtInRect(ptMouse))
			{
				m_bDragDropOperation=TRUE;
			}
			
			DROPEFFECT dropEffect=
				COXDragDropCommands::DoDragDrop(pDataSource,GetDropSource());
			if((DROPEFFECT_MOVE==dropEffect && m_bDragDropOperation) || 
				(DROPEFFECT_NONE==dropEffect &&	::GetKeyState(VK_LBUTTON)>=0 && 
				m_bDragDropOperation))
			{
				int nDraggedButtonIndex=GetDraggedButton();
				OnRemoveDraggedButton(nDraggedButtonIndex);
			}
			SetDraggedButton(-1);
			m_bDragDropOperation=FALSE;

			//delete drag source (we are responsible to do that)
			delete pDataSource;

			// unmark as the control which launched drag'n'drop operation
			m_bDragDropOwner=FALSE;


			if(!bWasInAdvancedCustomizationMode)
			{
				SetCustomizedButton(-1);
			}
		}
	}
#else
	UNREFERENCED_PARAMETER(nIndex);
#endif	//	OX_CUSTOMIZE_COMMANDS

	*pResult=0;
	return FALSE;
}


BOOL COXCoolToolBar::OnTBNEndDrag(NMHDR* pNMHDR, LRESULT* pResult)
{
	NMTOOLBAR* pNMToolBar=(NMTOOLBAR*)pNMHDR;
	UNREFERENCED_PARAMETER(pNMToolBar);
	*pResult=0;
	return FALSE;
}


BOOL COXCoolToolBar::OnTBNQueryInsert(NMHDR* pNMHDR, LRESULT* pResult)
{
	NMTOOLBAR* pNMToolBar=(NMTOOLBAR*)pNMHDR;
	UNREFERENCED_PARAMETER(pNMToolBar);
	*pResult=TRUE;		// always allow buttons to be inserted
	return TRUE;
}


BOOL COXCoolToolBar::OnTBNQueryDelete(NMHDR* /*pNMHDR*/, LRESULT* pResult)
{
	*pResult=TRUE;		// always allow buttons to be deleted
	return TRUE;
}


BOOL COXCoolToolBar::OnTBNToolBarChange(NMHDR* /*pNMHDR*/, LRESULT* /*pResult*/)
{
	SetButtonTextFromID(m_ttID);
	return FALSE;
}

#if _MFC_VER>=0x0420
//////////////////////
// custom draw of a toolbar is available since MFC 4.2
// in you derived class you can provide your own custom draw routines
void COXCoolToolBar::OnCustomDraw(NMHDR* pNotify, LRESULT* pResult)
{
	GetToolbarSkin()->OnCustomDraw(pNotify, pResult, this);
}
//////////////////////
#endif

void COXCoolToolBar::OnRemoveDraggedButton(int nButtonIndex)
{
	// delete button if it was moved
	VERIFY(GetToolBarCtrl().DeleteButton(nButtonIndex));
}

// helper function to keep array of all used bitmaps
HBITMAP COXCoolToolBar::AddBitmap(LPTSTR lpszResourceName)
{
	HBITMAP hBitmap=NULL;
	if(!m_allBitmaps.Lookup(lpszResourceName,hBitmap))
	{
		if((hBitmap=::LoadBitmap(AfxGetResourceHandle(),
			lpszResourceName))==NULL)
		{
			TRACE(_T("COXCoolToolBar::AddBitmap: unable to load bitmap\n"));
			return NULL;
		}
		m_allBitmaps.SetAt(lpszResourceName,hBitmap);
	}

	return hBitmap;
}

// helper function to keep array of all used image lists
HIMAGELIST COXCoolToolBar::AddImageList(LPTSTR lpszResourceName, int cx, int cGrow, 
										COLORREF crMask, UINT uType, UINT uFlags)
{
	HANDLE hImageList=NULL;
	if(!m_allImageLists.Lookup(lpszResourceName,hImageList))
	{
		if((hImageList=(HANDLE)::ImageList_LoadImage(AfxGetResourceHandle(),
			lpszResourceName,cx,cGrow,crMask,uType,uFlags))==NULL)
		{
			TRACE(_T("COXCoolToolBar::AddImageList: unable to load image list\n"));
			return NULL;
		}
		m_allImageLists.SetAt(lpszResourceName,hImageList);
	}

	return (HIMAGELIST)hImageList;
}

// helper function to keep array of all used image lists
HIMAGELIST COXCoolToolBar::AddImageList(LPTSTR lpszResourceName, int cx, 
										COLORREF crMask, UINT uFlags, 
										int cInitial, int cGrow)
{
	HANDLE hImageList=NULL;
	if(!m_allImageLists.Lookup(lpszResourceName,hImageList))
	{
		CBitmap bitmap;
		if(!bitmap.LoadBitmap(lpszResourceName))
		{
			TRACE(_T("COXCoolToolBar::AddImageList: unable to load image\n"));
			return NULL;
		}
		BITMAP bitmapInfo;
		VERIFY(bitmap.GetBitmap(&bitmapInfo)!=0);
		if((hImageList=(HANDLE)::ImageList_Create(cx,bitmapInfo.bmHeight,
			uFlags,cInitial,cGrow))==NULL)
		{
			TRACE(_T("COXCoolToolBar::AddImageList: unable to create image list\n"));
			return NULL;
		}
		if(ImageList_AddMasked((HIMAGELIST)hImageList,bitmap,crMask)==-1)
		{
			TRACE(_T("COXCoolToolBar::AddImageList: unable to populate image list\n"));
			ImageList_Destroy((HIMAGELIST)hImageList);
			return NULL;
		}
		m_allImageLists.SetAt(lpszResourceName,hImageList);
	}

	return (HIMAGELIST)hImageList;
}


// helper function to automatically set text to buttons
//	TTID_PLAIN - lookup string resource for var equals button's ID
//			if found, set text in button to string text 
//			(not includded tool tip text)
//	TTID_TOOLTIP - lookup string resource for var equals button's ID
//			if found, set text in button to tooltip text 
//	TTID_MENU - lookup menu resource for var equals button's ID
//			if found, set text in button to text of corresponding Item in menu
//	TTID_NONE - remove all text associated with buttons
//	TTID_NOTSET - default value (there is no any text associated with toolbar)
void COXCoolToolBar::SetButtonTextFromID(UINT nFirstButtonID, 
										 UINT nLastButtonID, TextTypeFromID ttID)
{
	m_ttID=ttID;

	if(ttID==TTID_NOTSET)
	{
		return;
	}

	ASSERT(nFirstButtonID<=nLastButtonID);
	CToolBarCtrl* pToolBarCtrl = &GetToolBarCtrl();
	ASSERT(pToolBarCtrl != NULL);

	BOOL bMenuLoaded=FALSE;
	CMenu* pMenu=NULL;
	if(ttID==TTID_MENU)
	{
		// try to get a menu associated with framework
		if(AfxGetApp()->m_pMainWnd!=NULL)
		{
			if(AfxGetApp()->m_pMainWnd->GetMenu()!=NULL)
			{
				pMenu=AfxGetApp()->m_pMainWnd->GetMenu();
				bMenuLoaded=TRUE;
			}
			else
			{
				TRACE(_T("COXCoolToolBar::SetButtonTextFromID: cannot get framework menu!/n"));
			}
		}
		else
		{
			TRACE(_T("COXCoolToolBar::SetButtonTextFromID: m_pMainWnd of app is not defined yet menu!/n"));
		}
	}
	
	UINT nID;
	CString strText;
	for(int i=0; i<pToolBarCtrl->GetButtonCount(); i++)
	{
		nID=GetItemID(i);
		if(nID>=nFirstButtonID && nID<=nLastButtonID)
		{
			switch(ttID)
			{
			// text in string resourse (not included tooltip)
			case TTID_PLAIN:
				{
					if (strText.LoadString(nID))
					{
						int nPlacement=strText.Find(_T('\n'));   // tool tip is after "\n" in the string
						if (nPlacement!=-1)
						{	
							strText=strText.Left(nPlacement);
						}
					}
					break;
				}
			// text in string resourse (only tooltip)
			case TTID_TOOLTIP:
				{
					if (strText.LoadString(nID))
					{
						int nPlacement=strText.Find(_T('\n'));   // tool tip is after "\n" in the string
						if (nPlacement!=-1)
						{	
							strText=strText.Mid(nPlacement+1);
						}
						else
						{
							strText=_T("");
						}
					}
					break;
				}
			// text in menu item resourse
			case TTID_MENU:
				{
					if(bMenuLoaded)
					{
						ASSERT(pMenu!=NULL);
						pMenu->GetMenuString(nID,strText,MF_BYCOMMAND);
						if(!strText.IsEmpty())
						{
							int nPlacement=strText.Find(_T('\t'));   // accelerator keys are placed after "\t" 
							if (nPlacement!=-1)
							{	
								strText=strText.Left(nPlacement);
							}
						}
					}
					break;
				}
			// remove any text
			case TTID_NONE:
				{
					strText=_T("");
					break;
				}
			default:
				{
					m_ttID=TTID_NONE;
					strText=_T("");
					break;
				}
			}
			SetButtonText(i,strText);
		}
	}
}

// Save to registry state of buttons in CoolToolBar
BOOL COXCoolToolBar::SaveBarState(LPCTSTR lpszSubKey, LPCTSTR lpszValueName, 
								  BOOL bProperties)
{
#ifndef _MAC
	CWinApp* pApp=AfxGetApp();
	CString sProfileName;
	sProfileName.Format(_T("%s_%s"),lpszSubKey,lpszValueName);

	// make sure you called SetButtonsIds()  
	// makes no sense to load/store buttons state info for uncustomizable CoolToolBar
	if(IsCustomizable(TRUE) || IsCustomizable(FALSE))
	{
		ASSERT(m_pBitmapIds!=NULL);

		// make sure you called CWinApp::SetRegistryKey() functions before
		if(pApp->m_pszRegistryKey==NULL || pApp->m_pszProfileName==NULL)
		{
			TRACE(_T("COXCoolToolBar::SaveBarState: haven't called	SetRegistryKey()\n"));
			return FALSE;
		}
		// we use default registry key assigned to your application by MFC
		HKEY hSecKey=pApp->GetSectionKey(_T(""));
		if (hSecKey==NULL)
		{
			TRACE(_T("COXCoolToolBar::SaveBarState: unable to get section key\n"));
			return FALSE;
		}

		// save buttons settings
		//
		CString sValueName;
		sValueName.Format(_T("%s_ButtonsSettings"),lpszValueName);
		
		CMemFile memFile;
		CArchive ar(&memFile,CArchive::store);
		int nButtonCount=GetToolBarCtrl().GetButtonCount();
		ar<<(DWORD)nButtonCount;
		for(int nIndex=0; nIndex<nButtonCount; nIndex++)
		{
			TBBUTTON button;
			VERIFY(GetToolBarCtrl().GetButton(nIndex,&button));

			ar<<(DWORD)button.idCommand;
			ar<<(DWORD)button.iBitmap;
			ar<<button.fsStyle;

			CString sText=GetButtonText(nIndex);
			ar<<(sText.IsEmpty() ? FALSE : TRUE);
			if(sText.IsEmpty())
				sText=GetRecentButtonText(button.idCommand);
			ar<<sText;
		}
		ar.Close();
		int nBufferLength=(int)memFile.GetLength();
		ASSERT(nBufferLength>0);
		BYTE* pBuffer=memFile.Detach();

		pApp->WriteProfileBinary(lpszSubKey,sValueName,pBuffer,nBufferLength);
		::free((void*)pBuffer);

		sValueName+=_T("_Size");
		pApp->WriteProfileInt(lpszSubKey,sValueName,nBufferLength);


		// save custom buttons positions
		//
		sValueName.Format(_T("%s_CustomButtonsPositions"),lpszValueName);
		CMemFile memFileCustom;
		CArchive arCustom(&memFileCustom,CArchive::store);
		int nCustomButtonCount=PtrToInt(m_mapCustomButtons.GetCount());
		arCustom<<(DWORD)nCustomButtonCount;
		for(int nCustomButtonIndex=0; 
			nCustomButtonIndex<GetToolBarCtrl().GetButtonCount(); 
			nCustomButtonIndex++)
		{
			OXCUSTOMBUTTONDESCRIPTOR descriptor;
			if(GetCustomButton(nCustomButtonIndex,descriptor))
			{
				arCustom<<(DWORD)nCustomButtonIndex;
				arCustom<<
					(DWORD)descriptor.m_pCBTemplate->CBGetWindow()->GetDlgCtrlID();
			}
		}

		arCustom.Close();
		nBufferLength=(int)memFileCustom.GetLength();
		ASSERT(nBufferLength>0);
		pBuffer=memFileCustom.Detach();

		pApp->WriteProfileBinary(lpszSubKey,sValueName,pBuffer,nBufferLength);
		::free((void*)pBuffer);

		sValueName+=_T("_Size");
		pApp->WriteProfileInt(lpszSubKey,sValueName,nBufferLength);


		// save buttons state
		GetToolBarCtrl().SaveState(hSecKey,lpszSubKey,lpszValueName);
		::RegCloseKey(hSecKey);
	}

	// save custom buttons settings
	//
	if(!m_bCustomButtonsStateSaved)
	{
		CString sValueName=_T("Toolbars_CustomButtonsSettings");
		
		CMemFile memFile;
		CArchive ar(&memFile,CArchive::store);
		int nButtonCount=PtrToInt(m_mapAllCustomButtons.GetCount());
		ar<<(DWORD)nButtonCount;
		POSITION pos=m_mapAllCustomButtons.GetStartPosition();
		while(pos!=NULL)
		{
			int nCtrlID=-1;
			OXCUSTOMBUTTONDESCRIPTOR descriptor;
			m_mapAllCustomButtons.GetNextAssoc(pos,nCtrlID,descriptor);
			ASSERT(nCtrlID>0);
			ar<<(DWORD)nCtrlID;
			descriptor.SaveState(ar);
			descriptor.m_pCBTemplate->CBSaveState(ar);
		}
		ar.Close();
		int nBufferLength=(int)memFile.GetLength();
		ASSERT(nBufferLength>0);
		BYTE* pBuffer=memFile.Detach();

		pApp->WriteProfileBinary(lpszSubKey,sValueName,pBuffer,nBufferLength);
		::free((void*)pBuffer);

		sValueName+=_T("_Size");
		pApp->WriteProfileInt(lpszSubKey,sValueName,nBufferLength);

		m_bCustomButtonsStateSaved=TRUE;
	}


	// save CoolToolBar properties
	if(bProperties)
	{
#if _MFC_VER>=0x0420
		pApp->WriteProfileInt(sProfileName,szCool,IsCool());
		pApp->WriteProfileInt(sProfileName,szGripper,IsGripper());
		pApp->WriteProfileInt(sProfileName,szSeparator,IsSeparator());
		pApp->WriteProfileInt(sProfileName,szFlat,IsFlat());
		pApp->WriteProfileInt(sProfileName,szList,IsList());
		pApp->WriteProfileInt(sProfileName,szDropDownArrow,IsDropDownArrow());
		pApp->WriteProfileInt(sProfileName,szIndent,GetIndent());
		pApp->WriteProfileInt(sProfileName,szDefaultTextColor,GetDefaultTextColor());
		pApp->WriteProfileInt(sProfileName,szHotTextColor,GetHotTextColor());
		pApp->WriteProfileInt(sProfileName,szSelectedTextColor,GetSelectedTextColor());
		pApp->WriteProfileInt(sProfileName,szCheckedTextColor,GetCheckedTextColor());
		pApp->WriteProfileInt(sProfileName,szDefaultBkColor,GetDefaultBkColor());
		pApp->WriteProfileInt(sProfileName,szHotBkColor,GetHotBkColor());
		pApp->WriteProfileInt(sProfileName,szSelectedBkColor,GetSelectedBkColor());
		pApp->WriteProfileInt(sProfileName,szCheckedBkColor,GetCheckedBkColor());
		pApp->WriteProfileInt(sProfileName,szDefaultBorderColor,GetDefaultBorderColor());
		pApp->WriteProfileInt(sProfileName,szHotBorderColor,GetHotBorderColor());
		pApp->WriteProfileInt(sProfileName,szSelectedBorderColor,GetSelectedBorderColor());
		pApp->WriteProfileInt(sProfileName,szCheckedBorderColor,GetCheckedBorderColor());
		pApp->WriteProfileInt(sProfileName,szTextType,GetTextType());
		pApp->WriteProfileInt(sProfileName,szTextRows,GetTextRows());
		pApp->WriteProfileInt(sProfileName,szMinButtonsWidth,GetButtonsMinMaxWidth().cx);
		pApp->WriteProfileInt(sProfileName,szMaxButtonsWidth,GetButtonsMinMaxWidth().cy);
#endif
		pApp->WriteProfileInt(sProfileName,szCustomizable,IsCustomizable());
	}

	return TRUE;
#else
	return FALSE;
#endif
}

// Load from registry state of buttons in CoolToolBar
BOOL COXCoolToolBar::LoadBarState(LPCTSTR lpszSubKey, LPCTSTR lpszValueName, 
								  BOOL bProperties)
{
#ifndef _MAC
	CWinApp* pApp=AfxGetApp();
	CString sProfileName;
	sProfileName.Format(_T("%s_%s"),lpszSubKey,lpszValueName);
	int nResult;

	if(bProperties)
	{
		nResult=pApp->GetProfileInt(sProfileName,szCustomizable,-1);
		if(nResult!=-1)
		{
			SetCustomizable(nResult);
		}
	}

	BOOL bUpdate=FALSE;

	// load and apply CoolToolBar properties
	if(bProperties)
	{
#if _MFC_VER>=0x0420
		nResult=pApp->GetProfileInt(sProfileName,szCool,-1);
		if(nResult!=-1)
		{
			SetCool(nResult);
		}
	
		nResult=pApp->GetProfileInt(sProfileName,szGripper,-1);
		if(nResult!=-1)
		{
			SetGripper(nResult);
		}
	
		nResult=pApp->GetProfileInt(sProfileName,szSeparator,-1);
		if(nResult!=-1)
		{
			SetSeparator(nResult);
		}
	
		nResult=pApp->GetProfileInt(sProfileName,szFlat,-1);
		if(nResult!=-1)
		{
			SetFlat(nResult);
		}
	
		nResult=pApp->GetProfileInt(sProfileName,szList,-1);
		if(nResult!=-1)
		{
			SetList(nResult);
			bUpdate=TRUE;
		}
	
		nResult=pApp->GetProfileInt(sProfileName,szDropDownArrow,-1);
		if(nResult!=-1)
		{
			SetDropDownArrow(nResult);
		}
	
		nResult=pApp->GetProfileInt(sProfileName,szIndent,-1);
		if(nResult!=-1)
		{
			SetIndent(nResult);
		}
	
		nResult=pApp->GetProfileInt(sProfileName,szDefaultTextColor,-1);
		if(nResult!=-1)
		{
			SetDefaultTextColor(nResult);
		}
	
		nResult=pApp->GetProfileInt(sProfileName,szHotTextColor,-1);
		if(nResult!=-1)
		{
			SetHotTextColor(nResult);
		}
	
		nResult=pApp->GetProfileInt(sProfileName,szSelectedTextColor,-1);
		if(nResult!=-1)
		{
			SetSelectedTextColor(nResult);
		}
	
		nResult=pApp->GetProfileInt(sProfileName,szCheckedTextColor,-1);
		if(nResult!=-1)
		{
			SetCheckedTextColor(nResult);
		}
	
		nResult=pApp->GetProfileInt(sProfileName,szDefaultBkColor,-1);
		if(nResult!=-1)
		{
			SetDefaultBkColor(nResult);
		}
	
		nResult=pApp->GetProfileInt(sProfileName,szHotBkColor,-1);
		if(nResult!=-1)
		{
			SetHotBkColor(nResult);
		}
	
		nResult=pApp->GetProfileInt(sProfileName,szSelectedBkColor,-1);
		if(nResult!=-1)
		{
			SetSelectedBkColor(nResult);
		}
	
		nResult=pApp->GetProfileInt(sProfileName,szCheckedBkColor,-1);
		if(nResult!=-1)
		{
			SetCheckedBkColor(nResult);
		}
	
		nResult=pApp->GetProfileInt(sProfileName,szDefaultBorderColor,-1);
		if(nResult!=-1)
		{
			SetDefaultBorderColor(nResult);
		}
	
		nResult=pApp->GetProfileInt(sProfileName,szHotBorderColor,-1);
		if(nResult!=-1)
		{
			SetHotBorderColor(nResult);
		}
	
		nResult=pApp->GetProfileInt(sProfileName,szSelectedBorderColor,-1);
		if(nResult!=-1)
		{
			SetSelectedBorderColor(nResult);
		}
	
		nResult=pApp->GetProfileInt(sProfileName,szCheckedBorderColor,-1);
		if(nResult!=-1)
		{
			SetCheckedBorderColor(nResult);
		}
	
		nResult=pApp->GetProfileInt(sProfileName,szTextType,-1);
		if(nResult!=-1 && nResult!=GetTextType())
		{
			if(nResult==TTID_NOTSET)
			{
				SetButtonTextFromID(TTID_NONE);
			}
			bUpdate=TRUE;
			SetButtonTextFromID((TextTypeFromID)nResult);
		}
	
		nResult=pApp->GetProfileInt(sProfileName,szTextRows,-1);
		if(nResult!=-1 && nResult!=GetTextRows())
		{
			SetMaxTextRows(nResult);
			bUpdate=TRUE;
		}
	
		nResult=pApp->GetProfileInt(sProfileName,szMinButtonsWidth,-1);
		if(nResult!=-1 && nResult!=m_sizeMinMaxWidth.cx)
		{
			m_sizeMinMaxWidth.cx=nResult;
			SetButtonsMinMaxWidth(m_sizeMinMaxWidth.cx,m_sizeMinMaxWidth.cy);
		}
		nResult=pApp->GetProfileInt(sProfileName,szMaxButtonsWidth,-1);
		if(nResult!=-1 && nResult!=m_sizeMinMaxWidth.cy)
		{
			m_sizeMinMaxWidth.cy=nResult;
			SetButtonsMinMaxWidth(m_sizeMinMaxWidth.cx,m_sizeMinMaxWidth.cy);
			bUpdate=TRUE;
		}

#endif
	}


	// load custom button settings
	//
	if(!m_bCustomButtonsStateLoaded)
	{
		CString sValueName=_T("Toolbars_CustomButtonsSettings_Size");
		int nSavedBufferLength=pApp->GetProfileInt(lpszSubKey,sValueName,-1);
		if(nSavedBufferLength!=-1)
		{
			ASSERT(nSavedBufferLength>0);
			UINT nBufferLength=0;
			BYTE* pBuffer=NULL;
			sValueName=_T("Toolbars_CustomButtonsSettings");
			if(pApp->GetProfileBinary(lpszSubKey,sValueName,&pBuffer,&nBufferLength))
			{
				ASSERT(nBufferLength>0);
				ASSERT(pBuffer!=NULL);
				CMemFile memFile(pBuffer,nBufferLength);
				CArchive ar(&memFile,CArchive::load);
				DWORD dwButtonCount=0;
				ar>>dwButtonCount;
				for(int nIndex=0; nIndex<(int)dwButtonCount; nIndex++)
				{
					DWORD dwCtrlID;
					ar>>dwCtrlID;
					OXCUSTOMBUTTONDESCRIPTOR descriptor;
					VERIFY(m_mapAllCustomButtons.Lookup((int)dwCtrlID,descriptor));
					descriptor.LoadState(ar);
					descriptor.m_pCBTemplate->CBLoadState(ar);
					m_mapAllCustomButtons.SetAt((int)dwCtrlID,descriptor);
				}
				ar.Close();
				memFile.Detach();

				delete[] pBuffer;
			}
		}

		m_bCustomButtonsStateLoaded=TRUE;
	}


	// make sure you called SetButtonsIds()  
	// makes no sense to load/store buttons state info for uncustomizable CoolToolBar
	//
	// load and apply button settings
	if(IsCustomizable(FALSE) || IsCustomizable(TRUE))
	{
		ASSERT(m_pBitmapIds!=NULL);
		// make sure you called CWinApp::SetRegistryKey() functions before
		if(pApp->m_pszRegistryKey==NULL || pApp->m_pszProfileName==NULL)
		{
			TRACE(_T("COXCoolToolBar::LoadBarState: haven't called	SetRegistryKey()\n"));
			return FALSE;
		}
		// we use default registry key assigned to your application by MFC
		HKEY hSecKey=pApp->GetSectionKey(_T(""));
		if (hSecKey==NULL)
		{
			TRACE(_T("COXCoolToolBar::LoadBarState: unable to get section key\n"));
			return FALSE;
		}

		// before restoring state of buttons we should remove all custom buttons
		// and store them temporary in mapDeletedCustomButtons map
		CMap<int,int,OXCUSTOMBUTTONDESCRIPTOR,OXCUSTOMBUTTONDESCRIPTOR&> 
			mapDeletedCustomButtons;
		// check if any custom buttons info has been saved
		CString sValueName;
		sValueName.Format(_T("%s_CustomButtonsPositions_Size"),lpszValueName);
		int nSavedBufferLength=pApp->GetProfileInt(lpszSubKey,sValueName,-1);
		if(nSavedBufferLength>0)
		{
			for(int nIndex=GetToolBarCtrl().GetButtonCount()-1; nIndex>=0; nIndex--)
			{
				OXCUSTOMBUTTONDESCRIPTOR descriptor;
				if(GetCustomButton(nIndex,descriptor))
				{
					ASSERT(::IsWindow(
						descriptor.m_pCBTemplate->CBGetWindow()->GetSafeHwnd()));
					int nButtonCtrlID=
						descriptor.m_pCBTemplate->CBGetWindow()->GetDlgCtrlID();
					if(descriptor.m_pCBTemplate->CBIsDynamicallyCreated())
					{
						// this button will be deleted later
						descriptor.m_pCBTemplate=NULL;
					}
					mapDeletedCustomButtons.SetAt(nButtonCtrlID,descriptor);
					GetToolBarCtrl().DeleteButton(nIndex);
				}
			}
		}


		m_bNoInternalRedraw=TRUE;

		// restore the toolbar contents
		GetToolBarCtrl().RestoreState(hSecKey,lpszSubKey,lpszValueName);
		::RegCloseKey(hSecKey);


		// apply saved button settings
		//
		sValueName.Format(_T("%s_ButtonsSettings_Size"),lpszValueName);
		nSavedBufferLength=pApp->GetProfileInt(lpszSubKey,sValueName,-1);
		if(nSavedBufferLength!=-1)
		{
			ASSERT(nSavedBufferLength>0);
			UINT nBufferLength=0;
			BYTE* pBuffer=NULL;
			sValueName.Format(_T("%s_ButtonsSettings"),lpszValueName);
			if(pApp->GetProfileBinary(lpszSubKey,sValueName,&pBuffer,&nBufferLength))
			{
				ASSERT(nBufferLength>0);
				ASSERT(pBuffer!=NULL);
				CMemFile memFile(pBuffer,nBufferLength);
				CArchive ar(&memFile,CArchive::load);
				DWORD dwButtonCount=0;
				ar>>dwButtonCount;
				for(int nIndex=0; nIndex<(int)dwButtonCount; nIndex++)
				{
					DWORD dwCommandID;
					ar>>dwCommandID;
					DWORD dwImageIndex;
					ar>>dwImageIndex;
					BYTE fsStyle;
					ar>>fsStyle;

					BOOL bSetText;
					ar>>bSetText;
					CString sText;
					ar>>sText;

					if(fsStyle&TBSTYLE_SEP)
						continue;

					int nButtonIndex=CommandToIndex((UINT)dwCommandID);
					if(nButtonIndex!=-1)
					{
						SetButtonInfo(nButtonIndex,(UINT)dwCommandID,
							fsStyle,(int)dwImageIndex);
						if(bSetText)
						{
							SetButtonText(nButtonIndex,sText);
						}
						else
						{
							if(!sText.IsEmpty())
								m_mapButtonText.SetAt((UINT)dwCommandID,sText);
						}
					}
				}
				ar.Close();
				memFile.Detach();

				delete[] pBuffer;
			}
		}
	
		// apply saved custom button positions
		//
		sValueName.Format(_T("%s_CustomButtonsPositions_Size"),lpszValueName);
		nSavedBufferLength=pApp->GetProfileInt(lpszSubKey,sValueName,-1);
		if(nSavedBufferLength!=-1)
		{
			ASSERT(nSavedBufferLength>0);
			UINT nBufferLength=0;
			BYTE* pBuffer=NULL;
			sValueName.Format(_T("%s_CustomButtonsPositions"),lpszValueName);
			if(pApp->GetProfileBinary(lpszSubKey,sValueName,&pBuffer,&nBufferLength))
			{
				ASSERT(nBufferLength>0);
				ASSERT(pBuffer!=NULL);
				CMemFile memFile(pBuffer,nBufferLength);
				CArchive ar(&memFile,CArchive::load);
				DWORD dwButtonCount=0;
				ar>>dwButtonCount;
				for(int nIndex=0; nIndex<(int)dwButtonCount; nIndex++)
				{
					DWORD dwIndex;
					ar>>dwIndex;
					DWORD dwCtrlID;
					ar>>dwCtrlID;

					ASSERT((int)dwIndex>=0 && 
						(int)dwIndex<=GetToolBarCtrl().GetButtonCount());
					OXCUSTOMBUTTONDESCRIPTOR descriptor;
					if(mapDeletedCustomButtons.Lookup((int)dwCtrlID,descriptor) && 
						descriptor.m_pCBTemplate!=NULL && ::IsWindow(
						descriptor.m_pCBTemplate->CBGetWindow()->GetSafeHwnd()))
					{
						OXCUSTOMBUTTONDESCRIPTOR descriptorOrig;
						VERIFY(m_mapAllCustomButtons.
							Lookup((int)dwCtrlID,descriptorOrig));
						// add placeholder
						TBBUTTON button={ 0 };
						button.iBitmap=-1;
						button.idCommand=0;
						button.fsStyle=TBSTYLE_SEP;
						button.iString=-1;
						VERIFY(GetToolBarCtrl().InsertButton((int)dwIndex,&button));
						// add new custom button
						m_mapCustomButtons.SetAt((int)dwIndex,descriptorOrig);
					}
					else
					{
						int nCustomButtonIndex=GetCustomButtonIndex((int)dwCtrlID);
						ASSERT(nCustomButtonIndex!=-1);
						VERIFY(InsertCustomButton((int)dwIndex,nCustomButtonIndex));
					}
				}
				ar.Close();
				memFile.Detach();

				delete[] pBuffer;
			}
		}
	
		SetButtonTextFromID(m_ttID);
	}

	m_bNoInternalRedraw=FALSE;

	// change the size of CoolToolBar
	if(bUpdate)
	{
		if(GetTextRows()==0)
		{
			IniSizes(m_sizeImage);
		}
		else
		{
			UpdateSizes();
		}

		RedrawToolBar();
	}
	else
	{
		UpdateCustomButtons();
	}


	return TRUE;

#else
	return FALSE;
#endif
}

void COXCoolToolBar::DockControlBarLeftOf(CToolBar *leftOf)
{
	ASSERT_VALID(this);
	// make sure CControlBar::EnableDocking has been called
	ASSERT(m_pDockContext!=NULL);

	if(leftOf!=NULL)
	{
		ASSERT_VALID(leftOf);
	}

	CFrameWnd* pFrameWnd=GetDockingFrame();
	ASSERT_VALID(pFrameWnd);

	// get MFC to adjust the dimensions of all docked ToolBars
	// so that GetWindowRect will be accurate
	pFrameWnd->RecalcLayout();

	UINT nDockBarID=0;
	CRect rect(0,0,0,0);
	if(leftOf!=NULL)
	{
		leftOf->GetWindowRect(&rect);
		rect.OffsetRect(1,0);

		DWORD dwStyle=leftOf->GetBarStyle();
		nDockBarID=(dwStyle & CBRS_ALIGN_TOP) ? AFX_IDW_DOCKBAR_TOP :
			(dwStyle & CBRS_ALIGN_BOTTOM) ? AFX_IDW_DOCKBAR_BOTTOM :
			(dwStyle & CBRS_ALIGN_LEFT) ? AFX_IDW_DOCKBAR_LEFT :
			(dwStyle & CBRS_ALIGN_RIGHT) ? AFX_IDW_DOCKBAR_RIGHT : 0;
	}


	// When we take the default parameters on rect, DockControlBar will dock
	// each Toolbar on a seperate line. Calculating a rectangle, we in effect
	// are simulating a Toolbar being dragged to that location and docked.
	pFrameWnd->DockControlBar(this, nDockBarID, &rect);
}

#if _MFC_VER<=0x0421

#define OXCY_BORDER		1

void COXCoolToolBar::SetHeight(int cyHeight)
{
	ASSERT_VALID(this);

	int nHeight = cyHeight;
	if (m_dwStyle & CBRS_BORDER_TOP)
		cyHeight -= OXCY_BORDER;
	if (m_dwStyle & CBRS_BORDER_BOTTOM)
		cyHeight -= OXCY_BORDER;
	m_cyBottomBorder = (cyHeight - m_sizeButton.cy) / 2;
	// if there is an extra pixel, m_cyTopBorder will get it
	m_cyTopBorder = cyHeight - m_sizeButton.cy - m_cyBottomBorder;
	if (m_cyTopBorder < 0)
	{
		TRACE(_T("Warning: COXCoolToolBar::SetHeight(%d) is smaller than button.\n"),
			nHeight);
		m_cyBottomBorder += m_cyTopBorder;
		m_cyTopBorder = 0;  // will clip at bottom
	}

	// recalculate the non-client region
	SetWindowPos(NULL, 0, 0, 0, 0,
		SWP_DRAWFRAME|SWP_NOMOVE|SWP_NOSIZE|SWP_NOACTIVATE|SWP_NOZORDER);
	Invalidate();   // just to be nice if called when toolbar is visible
}
#endif

BOOL COXCoolToolBar::IsWindowsNTRunning()
{
	BOOL bResult=FALSE;

	OSVERSIONINFO verInfo;
	verInfo.dwOSVersionInfoSize=sizeof(OSVERSIONINFO);
	if (::GetVersionEx(&verInfo))
	{
		if (verInfo.dwPlatformId==VER_PLATFORM_WIN32_NT && 
			verInfo.dwMajorVersion>=4)
		{
			bResult=TRUE;
		}
	}

	return bResult;
}

int COXCoolToolBar::GetDropDownArrowWidth() const
{
#if _MFC_VER>=0x0420
	HDC hDC = ::GetDC(NULL);
	ASSERT(hDC != NULL);

	HFONT hFont;
	HFONT oldFont=NULL;
	int nDropDownArrowWidth=0;
	if((hFont=CreateFont(GetSystemMetrics(SM_CYMENUCHECK), 0, 0, 0, 
		FW_NORMAL, 0, 0, 0, SYMBOL_CHARSET, 0, 0, 0, 0, _T("Marlett")))!=NULL)
	{
		oldFont = (HFONT)SelectObject(hDC, hFont);
	}
	
	VERIFY(GetCharWidth(hDC, '6', '6', &nDropDownArrowWidth));

	if(oldFont!=NULL)
	{
		SelectObject(hDC, oldFont);
	}
	if(hFont!=NULL)
	{
		DeleteObject(hFont);
	}
	::ReleaseDC(NULL, hDC);
	
	return nDropDownArrowWidth;
#else
	return 0;
#endif
}

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

void COXCoolToolBar::_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 anything while setting the button
		BOOL bWasVisible=(GetStyle()&WS_VISIBLE);
		if(bWasVisible)
			ModifyStyle(WS_VISIBLE, 0);
		VERIFY(DefWindowProc(TB_DELETEBUTTON, nIndex, 0));
		VERIFY(DefWindowProc(TB_INSERTBUTTON, nIndex, (LPARAM)pButton));
		if(bWasVisible)
		{
			ModifyStyle(0,WS_VISIBLE);
		}

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

#ifdef _MAC
	#define CX_OVERLAP  1
#else
	#define CX_OVERLAP  0
#endif

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

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

		if (pData[i].fsState & TBSTATE_HIDDEN)
			continue;

		int dx, dxNext;

		// take into account custom button style
		if(pData[i].fsStyle & TBSTYLE_SEP)
		{
			dx = pData[i].iBitmap;
			dxNext = dx;
		}
		else
		{
			dx = m_sizeButton.cx;
			if(pData[i].fsStyle & TBSTYLE_AUTOSIZE)
			{
				CRect rect;
				GetToolBarCtrl().GetItemRect(i,&rect);
				dx=rect.Width();
			}
			// check for dropdown style, but only if the buttons are being drawn
			if((pData[i].fsStyle & TBSTYLE_DROPDOWN) && IsDropDownArrow() &&
				(pData[i].fsStyle & TBSTYLE_AUTOSIZE)==0)
			{
				if(!IsFlat() || m_dwComCtlVersion>=_IE40_COMCTL_VERSION)
				{
					// add size of drop down
					if(m_dwComCtlVersion<_IE40_COMCTL_VERSION)
					{
						m_nDropDownArrowWidth=GetDropDownArrowWidth();
					}
					dx += m_nDropDownArrowWidth;
				}
			}
			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 COXCoolToolBar::SizeToolBar(TBBUTTON* pData, int nCount, 
								 int nLength, BOOL bVert/*=FALSE*/)
{
	ASSERT(pData != NULL && nCount > 0);

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

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

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

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

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

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

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

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

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

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

	CPoint cur(0,0);
	CSize sizeResult(0,0);

	for (int i = 0; i < nCount; i++)
	{
		int cySep = pData[i].iBitmap;
		if(!IsFlat() || m_dwComCtlVersion<_IE40_COMCTL_VERSION)
		{
			cySep = cySep * 2 / 3;
		}

		if(pData[i].fsState & TBSTATE_HIDDEN)
			continue;

		int cx = m_sizeButton.cx;
		if(pData[i].fsStyle & TBSTYLE_AUTOSIZE)
		{
			CRect rect;
			GetToolBarCtrl().GetItemRect(i,&rect);
			cx=rect.Width();
		}

		if(pData[i].fsStyle & TBSTYLE_SEP)
		{
			// a separator represents either a height or width
			if (pData[i].fsState & TBSTATE_WRAP)
			{
				sizeResult.cy = __max(cur.y + m_sizeButton.cy + cySep, 
					sizeResult.cy);
			}
			else
			{
				sizeResult.cx = __max(cur.x + pData[i].iBitmap, sizeResult.cx);
				sizeResult.cy = __max(cur.y + m_sizeButton.cy, sizeResult.cy);
			}
		}
		else
		{
			// check for dropdown style, but only if the buttons are being drawn
			if((pData[i].fsStyle & TBSTYLE_DROPDOWN) && IsDropDownArrow() &&
				(pData[i].fsStyle & TBSTYLE_AUTOSIZE)==0)
			{
				if(!IsFlat() || m_dwComCtlVersion>=_IE40_COMCTL_VERSION)
				{
					// add size of drop down
					if(m_dwComCtlVersion<_IE40_COMCTL_VERSION)
					{
						m_nDropDownArrowWidth=GetDropDownArrowWidth();
					}
					cx += m_nDropDownArrowWidth;
				}
			}
			sizeResult.cx = __max(cur.x + cx, sizeResult.cx);
			sizeResult.cy = __max(cur.y + m_sizeButton.cy, sizeResult.cy);
		}

		if(pData[i].fsStyle & TBSTYLE_SEP)
		{
			cur.x += pData[i].iBitmap;
		}
		else
		{
			cur.x += cx - CX_OVERLAP;
		}

		if(pData[i].fsState & TBSTATE_WRAP)
		{
			cur.x = 0;
			cur.y += m_sizeButton.cy;
			if(pData[i].fsStyle & TBSTYLE_SEP)
				cur.y += cySep;
		}
	}

	// add indention
	sizeResult.cx+=m_nIndent;
	return sizeResult;
}

struct _AFX_CONTROLPOS
{
	int nIndex, nID;
	CRect rectOldPos;
};

CSize COXCoolToolBar::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;
	CMap<int,int,TBBUTTON*,TBBUTTON*> mapIndexToIgnore;
	CSize sizeResult(0,0);

	// Load Buttons
	{
		nCount = PtrToInt(DefWindowProc(TB_BUTTONCOUNT, 0, 0));
		if (nCount != 0)
		{
			int nFlags=(((dwMode & LM_HORZDOCK)==0 && (dwMode & LM_VERTDOCK)==0) ? 
				OXCBD_SHOWFLOAT : ((dwMode & LM_HORZDOCK)!=0 ? 
				OXCBD_SHOWHORZ : OXCBD_SHOWVERT));
			int i;
			pData=new TBBUTTON[nCount];
			for(i=0; i<nCount; i++)
			{
				_GetButton(i,&pData[i]);

				// take into account custom button style
				OXCUSTOMBUTTONDESCRIPTOR descriptor;
				if(GetCustomButton(i,descriptor))
				{
					if(((descriptor.m_nFlags & OXCBD_SHOWFLOAT)==0 && 
						nFlags==OXCBD_SHOWFLOAT) ||
						((descriptor.m_nFlags & OXCBD_SHOWHORZ)==0 && 
						nFlags==OXCBD_SHOWHORZ) ||
						((descriptor.m_nFlags & OXCBD_SHOWVERT)==0 && 
						nFlags==OXCBD_SHOWVERT))
					{
						TBBUTTON* pButton=new TBBUTTON;
						*pButton=pData[i];
						pData[i].fsStyle&=~TBSTYLE_SEP;
						pData[i].fsStyle|=TBSTYLE_BUTTON;
						pData[i].iBitmap=descriptor.m_nImageIndex;
						mapIndexToIgnore.SetAt(i,pButton);
					}
				}
			}
		}
	}

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

			ASSERT(pData!=NULL);

			if (bDynamic && (dwMode & LM_MRUWIDTH))
				SizeToolBar(pData, nCount, m_nMRUWidth);
			else if (bDynamic && (dwMode & LM_HORZDOCK))
				SizeToolBar(pData, nCount, 32767);
			else if (bDynamic && (dwMode & LM_VERTDOCK))
				SizeToolBar(pData, nCount, 0);
			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);
			}
			else if (bDynamic && (m_dwStyle & CBRS_FLOATING))
				SizeToolBar(pData, nCount, m_nMRUWidth);
			else
				SizeToolBar(pData, nCount, (dwMode & LM_HORZ) ? 32767 : 0);
		}

		sizeResult = CalcSize(pData, nCount);

		if (dwMode & LM_COMMIT)
		{
			_AFX_CONTROLPOS* pControl = NULL;
			int nControlCount = 0;
			BOOL bIsDelayed = m_bDelayedButtonLayout;
			m_bDelayedButtonLayout = FALSE;

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

			if (nControlCount > 0)
			{
				pControl = new _AFX_CONTROLPOS[nControlCount];
				nControlCount = 0;

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

						CRect rect;
						GetItemRect(i, &rect);
						ClientToScreen(&rect);
						pControl[nControlCount].rectOldPos = rect;

						nControlCount++;
					}
				}
			}

			if ((m_dwStyle & CBRS_FLOATING) && (m_dwStyle & CBRS_SIZE_DYNAMIC))
			{
				m_nMRUWidth = sizeResult.cx;
			}
			for (i = 0; i < nCount; i++)
			{
				TBBUTTON* pButton=NULL;
				if(mapIndexToIgnore.Lookup(i,pButton))
				{
					ASSERT(pButton!=NULL);
					if(pData[i].fsState & TBSTATE_WRAP)
					{
						pButton->fsState|=TBSTATE_WRAP;
					}
					else
					{
						pButton->fsState&=~TBSTATE_WRAP;
					}
					_SetButton(i, pButton);
				}
				else
				{
					_SetButton(i, &pData[i]);
				}
			}

			if (nControlCount > 0)
			{
				for (int i = 0; i < nControlCount; i++)
				{
					CWnd* pWnd = GetDlgItem(pControl[i].nID);
					if (pWnd != NULL)
					{
						CRect rect;
						pWnd->GetWindowRect(&rect);
						CPoint pt = rect.TopLeft() - pControl[i].rectOldPos.TopLeft();
						GetItemRect(pControl[i].nIndex, &rect);
						pt = rect.TopLeft() + pt;
						pWnd->SetWindowPos(NULL, pt.x, pt.y, 0, 0, 
							SWP_NOACTIVATE | SWP_NOSIZE | SWP_NOZORDER);
					}
				}
				delete[] pControl;
			}
			m_bDelayedButtonLayout = bIsDelayed;
		}
		delete[] pData;
	}
	else
	{
		CSize sizeButtons=GetButtonsSize();
		if(dwMode & LM_HORZ)
		{
			if(IsFloating())
			{
				sizeResult.cx=sizeButtons.cx;
			}
			else
			{
				sizeResult.cx=sizeButtons.cx/2;
			}
			sizeResult.cy=sizeButtons.cy;
		}
		else
		{
			sizeResult.cx=sizeButtons.cx;
			if(IsFloating())
			{
				sizeResult.cy=sizeButtons.cy;
			}
			else
			{
				sizeResult.cy=sizeButtons.cy/2;
			}
		}
	}

	POSITION pos=mapIndexToIgnore.GetStartPosition();
	while(pos!=NULL)
	{
		int nIndex=0;
		TBBUTTON* pButton=NULL;
		mapIndexToIgnore.GetNextAssoc(pos,nIndex,pButton);
		ASSERT(pButton!=NULL);
		delete pButton;
	}
	mapIndexToIgnore.RemoveAll();

	//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 COXCoolToolBar::CalcFixedLayout(BOOL bStretch, BOOL bHorz)
{
	DWORD dwMode = bStretch ? LM_STRETCH : 0;
	dwMode |= bHorz ? LM_HORZ : 0;

	return CalcLayout(dwMode);
}

CSize COXCoolToolBar::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);
}

void COXCoolToolBar::CalcInsideRect(CRect& rect, BOOL bHorz)
{
	CToolBar::CalcInsideRect(rect,bHorz);

	if(m_hIcon)
	{
		// Icon size
		CSize szIcon(::GetSystemMetrics(SM_CXSMICON),
			::GetSystemMetrics(SM_CYSMICON));
		if(bHorz)
			rect.left+=szIcon.cx+2;
		else
			rect.top+=szIcon.cy+2;
	}

	CRect rectBookedSpace(0,0,0,0);
	BookSpace(rectBookedSpace,(bHorz ? LM_HORZ : 0));
	rect.left+=rectBookedSpace.left;
	rect.top+=rectBookedSpace.top;
	rect.right-=rectBookedSpace.right;
	rect.bottom-=rectBookedSpace.bottom;

	if(IsFlat() && IsGripper() && !(m_dwStyle & CBRS_FLOATING))
	{
		if(bHorz)
		{
			rect.left+=ID_OXGRIPPER_WIDTH;
		}
		else
		{
			rect.top+=ID_OXGRIPPER_WIDTH;
		}
	}
}


void COXCoolToolBar::RedrawToolBar(BOOL bRecalcLayout/*=TRUE*/, 
								   BOOL bOnlyFrame/*=FALSE*/)
{
	ASSERT(::IsWindow(GetSafeHwnd()));

	if(m_bNoInternalRedraw)
	{
		return;
	}

	// update custom buttons state
	UpdateCustomButtons();

	if(!IsWindowVisible())
	{
		return;
	}

	if(bRecalcLayout)
	{
		CFrameWnd* pFrameWnd=GetDockingFrame();
		if(pFrameWnd!=NULL)
		{
			m_bNoBkgndRedraw=TRUE;
			pFrameWnd->RecalcLayout();
			m_bNoBkgndRedraw=FALSE;
			for(int nIndex=0; nIndex<GetToolBarCtrl().GetButtonCount(); nIndex++)
			{
				RedrawButton(nIndex);
				CRect rect;
				GetItemRect(nIndex,rect);
				ValidateRect(rect);
			}
		}
	}
	else
	{
		if(!bOnlyFrame)
		{
			RedrawWindow(NULL,NULL,
				RDW_INVALIDATE|RDW_UPDATENOW|RDW_ERASE|RDW_FRAME|RDW_ALLCHILDREN);
		}
	}

	if(bOnlyFrame)
	{
		SetWindowPos(NULL,0,0,0,0,
			SWP_NOZORDER|SWP_NOMOVE|SWP_NOSIZE|SWP_DRAWFRAME);
	}
}


void COXCoolToolBar::RedrawButton(int nIndex)
{
	ASSERT(::IsWindow(GetSafeHwnd()));

	if(nIndex<0 || nIndex>GetToolBarCtrl().GetButtonCount())
	{
		return;
	}

	CRect rect;
	GetItemRect(nIndex,rect);
	RedrawWindow(rect);
	if(IsCustomButton(nIndex))
	{
		GetCustomButtonWnd(nIndex)->RedrawWindow(rect);
	}
}


CString COXCoolToolBar::GetButtonTooltip(int nButtonIndex) const
{ 
	ASSERT(::IsWindow(m_hWnd));

	CString sTooltip(_T(""));
	UINT nID=GetItemID(nButtonIndex); 
	if(nID!=0) // will be zero on a separator
	{
		TCHAR szFullText[256];
		// don't handle the message if no string resource found
		if(AfxLoadString(nID,szFullText))
		{
			AfxExtractSubString(sTooltip,szFullText,1,'\n');
		}
	}

	return sTooltip;
}


BOOL COXCoolToolBar::MoveButton(UINT nOldPos, UINT nNewPos)
{ 
#if _MFC_VER>=0x0420
	ASSERT(::IsWindow(m_hWnd)); 
	if((BOOL)::SendMessage(m_hWnd,TB_MOVEBUTTON,nOldPos,nNewPos))
	{
		if(IsCustomButton(nNewPos))
		{
			RedrawToolBar(FALSE,TRUE);
		}
		return TRUE;
	}
	else
	{
		return FALSE;
	}
#else
	if(nOldPos==nNewPos)
		return TRUE;
	TBBUTTON button;
	if(!GetToolBarCtrl().GetButton(nOldPos,&button))
		return FALSE;
	if(!GetToolBarCtrl().DeleteButton(nOldPos))
		return FALSE;
	if(nNewPos>nOldPos)
		nNewPos--;
	return (GetToolBarCtrl().InsertButton(nNewPos,&button))
#endif
}


int COXCoolToolBar::AddCustomButton(COXCustomTBButtonTemplate* pCBTemplate, int nID, 
									int nWidth, int nHeight/*=-1*/, 
									int nFlags/*=OXCBD_SHOWANY*/, 
									int nImageIndex/*=-1*/)
{
	OXCUSTOMBUTTONDESCRIPTOR 
		descriptor(pCBTemplate,nID,nWidth,nHeight,nFlags,nImageIndex);
	return AddCustomButton(descriptor);
}


int COXCoolToolBar::AddCustomButton(OXCUSTOMBUTTONDESCRIPTOR& descriptor)
{
	ASSERT(descriptor.m_pCBTemplate!=NULL);
	ASSERT(!::IsWindow(descriptor.m_pCBTemplate->CBGetWindow()->GetSafeHwnd()));
	
	OXCUSTOMBUTTONDESCRIPTOR descriptorTest;
	if(!m_mapAllCustomButtons.Lookup(descriptor.m_nID,descriptorTest))
	{
		// add new custom button
		m_mapAllCustomButtons.SetAt(descriptor.m_nID,descriptor);
		return PtrToInt(m_arrAllCustomButtonIDs.Add(descriptor.m_nID));
	}
	else
	{
		// custom button has already been inserted
		int nCustomButtonIndex=GetCustomButtonIndex(descriptor.m_nID);
		ASSERT(nCustomButtonIndex!=-1);
		if(!SetCustomButton(nCustomButtonIndex,descriptor))
		{
			TRACE(_T("COXCoolToolBar::AddCustomButton: failed to update the descriptor of existing custom button\n"));
			return -1;
		}
		else
		{
			return nCustomButtonIndex;
		}
	}
}


BOOL COXCoolToolBar::SetCustomButton(int nCustomButtonIndex, 
									 OXCUSTOMBUTTONDESCRIPTOR& descriptor)
{
	if(nCustomButtonIndex<0 || nCustomButtonIndex>=m_arrAllCustomButtonIDs.GetSize())
	{
		TRACE(_T("COXCoolToolBar::SetCustomButton: specified custom button index is out of range\n"));
		return FALSE;
	}

	int nID=m_arrAllCustomButtonIDs[nCustomButtonIndex];
	ASSERT(nID==descriptor.m_nID);
	OXCUSTOMBUTTONDESCRIPTOR descriptorOrig;
	VERIFY(m_mapAllCustomButtons.Lookup(nID,descriptorOrig));
	// copy properties to original button descriptor
	VERIFY(descriptorOrig.CopyProperties(descriptor));
	m_mapAllCustomButtons.SetAt(nID,descriptorOrig);

	// apply the same properties for all copies of specified button
	// Iterate all the control bars and use only the toolbars
	CFrameWnd* pFrameWnd=DYNAMIC_DOWNCAST(CFrameWnd,AfxGetMainWnd());
	if(pFrameWnd!=NULL)
	{
		POSITION pos=pFrameWnd->m_listControlBars.GetHeadPosition();
		while(pos!=NULL)
		{
			COXCoolToolBar* pCoolToolbar=DYNAMIC_DOWNCAST(COXCoolToolBar, 
				(CControlBar*)pFrameWnd->m_listControlBars.GetNext(pos));
			//If it is a COXCoolToolBar
			if(pCoolToolbar!=NULL)
			{
				POSITION pos=pCoolToolbar->m_mapCustomButtons.GetStartPosition();
				while(pos!=NULL)
				{
					int nIndex=-1;
					OXCUSTOMBUTTONDESCRIPTOR descriptorExisting;
					pCoolToolbar->
						m_mapCustomButtons.GetNextAssoc(pos,nIndex,descriptorExisting);
					ASSERT(nIndex!=-1);
					if(descriptorExisting.m_nID==descriptor.m_nID)
					{
						VERIFY(descriptorExisting.CopyProperties(descriptor));
						pCoolToolbar->
							m_mapCustomButtons.SetAt(nIndex,descriptorExisting);
						pCoolToolbar->RedrawToolBar(TRUE,TRUE);
						break;
					}
				}
			}
		}
	}

	return TRUE;
}	


BOOL COXCoolToolBar::CreateCustomButton(int nCustomButtonIndex, 
										OXCUSTOMBUTTONDESCRIPTOR& descriptor,
										DWORD dwStyle/*=WS_CHILD|WS_VISIBLE*/, 
										DWORD dwStyleEx/*=0*/, 
										LPCTSTR lpszClassName/*=AfxRegisterWndClass(CS_DBLCLKS)*/,
										LPCTSTR lpszWindowName/*=_T("")*/)
{
	if(nCustomButtonIndex<0 || nCustomButtonIndex>=m_arrAllCustomButtonIDs.GetSize())
	{
		TRACE(_T("COXCoolToolBar::CreateCustomButton: specified custom button index is out of range\n"));
		return FALSE;
	}

	int nID=m_arrAllCustomButtonIDs[nCustomButtonIndex];
	OXCUSTOMBUTTONDESCRIPTOR descriptorOrig;
	VERIFY(m_mapAllCustomButtons.Lookup(nID,descriptorOrig));

	// check if any instance of this button has already been created
	if(!::IsWindow(descriptorOrig.m_pCBTemplate->CBGetWindow()->GetSafeHwnd()))
	{
		if(!descriptorOrig.m_pCBTemplate->CBCreate(descriptorOrig.m_nID,this,dwStyle,
			dwStyleEx,lpszClassName,lpszWindowName))
		{
			TRACE(_T("COXCoolToolBar::CreateCustomButton: failed to create custom button\n"));
			return FALSE;
		}
		m_mapAllCustomButtons.SetAt(descriptorOrig.m_nID,descriptorOrig);

		descriptor=descriptorOrig;
	}
	else
	{
		descriptor=descriptorOrig;
		// create a copy of the existing button
		descriptor.m_pCBTemplate=
			(COXCustomTBButtonWnd<CWnd>*)descriptorOrig.m_pCBTemplate->
			CBCreateCopy(this);
		if(descriptor.m_pCBTemplate==NULL)
		{
			TRACE(_T("COXCoolToolBar::CreateCustomButton: failed to create custom button\n"));
			return FALSE;
		}
	}

	return TRUE;
}


BOOL COXCoolToolBar::InsertCustomButton(int nIndex, int nCustomButtonIndex,
										DWORD dwStyle/*=WS_CHILD|WS_VISIBLE*/, 
										DWORD dwStyleEx/*=0*/, 
										LPCTSTR lpszClassName/*=AfxRegisterWndClass(CS_DBLCLKS)*/,
										LPCTSTR lpszWindowName/*=_T("")*/)
{
	if(nIndex<0 || nIndex>GetToolBarCtrl().GetButtonCount())
	{
		TRACE(_T("COXCoolToolBar::InsertCustomButton: specified index is out of range\n"));
		return FALSE;
	}

	if(nCustomButtonIndex<0 || nCustomButtonIndex>=m_arrAllCustomButtonIDs.GetSize())
	{
		TRACE(_T("COXCoolToolBar::InsertCustomButton: specified custom button index is out of range\n"));
		return FALSE;
	}

	// add placeholder
	TBBUTTON button={ 0 };
	button.iBitmap=-1;
	button.idCommand=0;
	button.fsStyle=TBSTYLE_SEP;
	button.iString=-1;
	// don't redraw the toolbar contents, we will do it later
	m_bNoInternalRedraw=TRUE;
	if(!GetToolBarCtrl().InsertButton(nIndex,&button))
	{
		m_bNoInternalRedraw=FALSE;
		TRACE(_T("COXCoolToolBar::InsertCustomButton: failed to insert new button\n"));
		return FALSE;
	}
	m_bNoInternalRedraw=FALSE;

	// create new custom button
	OXCUSTOMBUTTONDESCRIPTOR descriptorCreated;
	if(!CreateCustomButton(nCustomButtonIndex,descriptorCreated,dwStyle,
		dwStyleEx,lpszClassName,lpszWindowName))
	{
		TRACE(_T("COXCoolToolBar::InsertCustomButton: failed to create custom button\n"));
		// don't redraw the toolbar contents, we just rollback to the original state
		m_bNoInternalRedraw=TRUE;
		GetToolBarCtrl().DeleteButton(nIndex);
		m_bNoInternalRedraw=FALSE;
		return FALSE;
	}

	// add new custom button
	m_mapCustomButtons.SetAt(nIndex,descriptorCreated);

	RedrawToolBar(TRUE,TRUE);

	return TRUE;
}


int COXCoolToolBar::GetCustomButtonPosition(int nCtrlID) const
{
	POSITION pos=m_mapCustomButtons.GetStartPosition();
	while(pos!=NULL)
	{
		int nIndex=-1;
		OXCUSTOMBUTTONDESCRIPTOR descriptor;
		m_mapCustomButtons.GetNextAssoc(pos,nIndex,descriptor);
		ASSERT(nIndex!=-1);
		ASSERT(::IsWindow(descriptor.m_pCBTemplate->CBGetWindow()->GetSafeHwnd()));
		if(descriptor.m_pCBTemplate->CBGetWindow()->GetDlgCtrlID()==nCtrlID)
		{
			return nIndex;
		}
	}

	return -1;
}


BOOL COXCoolToolBar::IsCustomButtonWnd(int nCtrlID) const
{
	POSITION pos=m_mapCustomButtons.GetStartPosition();
	while(pos!=NULL)
	{
		int nIndex=-1;
		OXCUSTOMBUTTONDESCRIPTOR descriptor;
		m_mapCustomButtons.GetNextAssoc(pos,nIndex,descriptor);
		ASSERT(nIndex!=-1);
		ASSERT(::IsWindow(descriptor.m_pCBTemplate->CBGetWindow()->GetSafeHwnd()));
		if(descriptor.m_pCBTemplate->CBGetWindow()->GetDlgCtrlID()==nCtrlID)
		{
			return TRUE;
		}
	}

	return FALSE;
}


BOOL COXCoolToolBar::InsertComboBox(int nIndex, int nCustomButtonIndex, 
									DWORD dwStyle/*=WS_CHILD|WS_VISIBLE|CBS_DROPDOWN|WS_VSCROLL*/, 
									DWORD dwStyleEx/*=0*/)
{
#ifdef _DEBUG
	int nID=m_arrAllCustomButtonIDs[nCustomButtonIndex];
	OXCUSTOMBUTTONDESCRIPTOR descriptorOrig;
	VERIFY(m_mapAllCustomButtons.Lookup(nID,descriptorOrig));
	ASSERT_KINDOF(CComboBox,descriptorOrig.m_pCBTemplate->CBGetWindow());
#endif	//	_DEBUG
	return InsertCustomButton(
		nIndex,nCustomButtonIndex,dwStyle,dwStyleEx,_T("ComboBox"));
}


BOOL COXCoolToolBar::InsertEditBox(int nIndex, int nCustomButtonIndex, 
								   LPCTSTR lpszWindowName/*=_T("")*/,
								   DWORD dwStyle/*=WS_CHILD|WS_VISIBLE|ES_AUTOHSCROLL*/, 
								   DWORD dwStyleEx/*=WS_EX_CLIENTEDGE*/)
{
#ifdef _DEBUG
	int nID=m_arrAllCustomButtonIDs[nCustomButtonIndex];
	OXCUSTOMBUTTONDESCRIPTOR descriptorOrig;
	VERIFY(m_mapAllCustomButtons.Lookup(nID,descriptorOrig));
	ASSERT_KINDOF(CEdit,descriptorOrig.m_pCBTemplate->CBGetWindow());
#endif	//	_DEBUG
	return InsertCustomButton(
		nIndex,nCustomButtonIndex,dwStyle,dwStyleEx,_T("Edit"),lpszWindowName);
}


BOOL COXCoolToolBar::InsertRichEditBox(int nIndex, int nCustomButtonIndex,
									   DWORD dwStyle/*=WS_CHILD|WS_VISIBLE|ES_AUTOHSCROLL*/, 
									   DWORD dwStyleEx/*=WS_EX_CLIENTEDGE*/)
{
#ifdef _DEBUG
	int nID=m_arrAllCustomButtonIDs[nCustomButtonIndex];
	OXCUSTOMBUTTONDESCRIPTOR descriptorOrig;
	VERIFY(m_mapAllCustomButtons.Lookup(nID,descriptorOrig));
	ASSERT_KINDOF(CRichEditCtrl,descriptorOrig.m_pCBTemplate->CBGetWindow());
#endif	//	_DEBUG
	return InsertCustomButton(
		nIndex,nCustomButtonIndex,dwStyle,dwStyleEx,_T("RICHEDIT"));
}


BOOL COXCoolToolBar::InsertStaticCtrl(int nIndex, int nCustomButtonIndex, 
									  LPCTSTR lpszWindowName, 
									  DWORD dwStyle/*=WS_CHILD|WS_VISIBLE|SS_LEFT|SS_SIMPLE*/, 
									  DWORD dwStyleEx/*=0*/)
{
#ifdef _DEBUG
	int nID=m_arrAllCustomButtonIDs[nCustomButtonIndex];
	OXCUSTOMBUTTONDESCRIPTOR descriptorOrig;
	VERIFY(m_mapAllCustomButtons.Lookup(nID,descriptorOrig));
	ASSERT_KINDOF(CStatic,descriptorOrig.m_pCBTemplate->CBGetWindow());
#endif	//	_DEBUG
	return InsertCustomButton(
		nIndex,nCustomButtonIndex,dwStyle,dwStyleEx,_T("Static"),lpszWindowName);
}


BOOL COXCoolToolBar::InsertHotKeyCtrl(int nIndex, int nCustomButtonIndex, 
									  DWORD dwStyle/*=WS_CHILD|WS_VISIBLE*/, 
									  DWORD dwStyleEx/*=0*/)
{
#ifdef _DEBUG
	int nID=m_arrAllCustomButtonIDs[nCustomButtonIndex];
	OXCUSTOMBUTTONDESCRIPTOR descriptorOrig;
	VERIFY(m_mapAllCustomButtons.Lookup(nID,descriptorOrig));
	ASSERT_KINDOF(CHotKeyCtrl,descriptorOrig.m_pCBTemplate->CBGetWindow());
#endif	//	_DEBUG
	return InsertCustomButton(
		nIndex,nCustomButtonIndex,dwStyle,dwStyleEx,_T("msctls_hotkey32"));
}


BOOL COXCoolToolBar::InsertButtonCtrl(int nIndex, int nCustomButtonIndex, 
									  LPCTSTR lpszWindowName, 
									  DWORD dwStyle/*=WS_CHILD|WS_VISIBLE|BS_PUSHBUTTON*/, 
									  DWORD dwStyleEx/*=0*/)
{
#ifdef _DEBUG
	int nID=m_arrAllCustomButtonIDs[nCustomButtonIndex];
	OXCUSTOMBUTTONDESCRIPTOR descriptorOrig;
	VERIFY(m_mapAllCustomButtons.Lookup(nID,descriptorOrig));
	ASSERT_KINDOF(CButton,descriptorOrig.m_pCBTemplate->CBGetWindow());
#endif	//	_DEBUG
	return InsertCustomButton(
		nIndex,nCustomButtonIndex,dwStyle,dwStyleEx,_T("Button"),lpszWindowName);
}


BOOL COXCoolToolBar::InsertCheckBox(int nIndex, int nCustomButtonIndex, 
									LPCTSTR lpszWindowName, 
									DWORD dwStyle/*=WS_CHILD|WS_VISIBLE|BS_CHECKBOX*/, 
									DWORD dwStyleEx/*=0*/)
{
#ifdef _DEBUG
	int nID=m_arrAllCustomButtonIDs[nCustomButtonIndex];
	OXCUSTOMBUTTONDESCRIPTOR descriptorOrig;
	VERIFY(m_mapAllCustomButtons.Lookup(nID,descriptorOrig));
	ASSERT_KINDOF(CButton,descriptorOrig.m_pCBTemplate->CBGetWindow());
#endif	//	_DEBUG
	return InsertCustomButton(
		nIndex,nCustomButtonIndex,dwStyle,dwStyleEx,_T("Button"),lpszWindowName);
}


BOOL COXCoolToolBar::InsertProgressBar(int nIndex, int nCustomButtonIndex, 
									   DWORD dwStyle/*=WS_CHILD|WS_VISIBLE*/, 
									   DWORD dwStyleEx/*=0*/)
{
#ifdef _DEBUG
	int nID=m_arrAllCustomButtonIDs[nCustomButtonIndex];
	OXCUSTOMBUTTONDESCRIPTOR descriptorOrig;
	VERIFY(m_mapAllCustomButtons.Lookup(nID,descriptorOrig));
	ASSERT_KINDOF(CProgressCtrl,descriptorOrig.m_pCBTemplate->CBGetWindow());
#endif	//	_DEBUG
	return InsertCustomButton(
		nIndex,nCustomButtonIndex,dwStyle,dwStyleEx,_T("msctls_progress32"));
}


BOOL COXCoolToolBar::InsertSlider(int nIndex, int nCustomButtonIndex, 
								  DWORD dwStyle/*=WS_CHILD|WS_VISIBLE|TBS_HORZ*/, 
								  DWORD dwStyleEx/*=0*/)
{
#ifdef _DEBUG
	int nID=m_arrAllCustomButtonIDs[nCustomButtonIndex];
	OXCUSTOMBUTTONDESCRIPTOR descriptorOrig;
	VERIFY(m_mapAllCustomButtons.Lookup(nID,descriptorOrig));
	ASSERT_KINDOF(CSliderCtrl,descriptorOrig.m_pCBTemplate->CBGetWindow());
#endif	//	_DEBUG
	return InsertCustomButton(
		nIndex,nCustomButtonIndex,dwStyle,dwStyleEx,_T("msctls_trackbar32"));
}


#if _MFC_VER>0x0421
/////////////////////////////////////////////////////////////////////////////////
BOOL COXCoolToolBar::InsertDateTimePicker(int nIndex, int nCustomButtonIndex, 
										  COleDateTime date, 
										  DWORD dwStyle/*=WS_CHILD|WS_VISIBLE*/, 
										  DWORD dwStyleEx/*=0*/)
{
	// register date-time and mont calendar window classes
	INITCOMMONCONTROLSEX icex;
	icex.dwSize=sizeof(INITCOMMONCONTROLSEX);
	icex.dwICC=ICC_DATE_CLASSES;
	::InitCommonControlsEx(&icex);

	if(!InsertCustomButton(
		nIndex,nCustomButtonIndex,dwStyle,dwStyleEx,_T("SysDateTimePick32")))
	{
		return FALSE;
	}
	else
	{
		CWnd* pWnd=GetCustomButtonWnd(nIndex);
		ASSERT(pWnd!=NULL);
		CDateTimeCtrl* pDateTimeCtrl=(CDateTimeCtrl*)(pWnd);
		pDateTimeCtrl->SetTime(date);

		return TRUE;
	}
}


BOOL COXCoolToolBar::InsertIPAddressCtrl(int nIndex, int nCustomButtonIndex, 
										 DWORD dwStyle/*=WS_CHILD|WS_VISIBLE*/, 
										 DWORD dwStyleEx/*=0*/)
{
#ifdef _DEBUG
	int nID=m_arrAllCustomButtonIDs[nCustomButtonIndex];
	OXCUSTOMBUTTONDESCRIPTOR descriptorOrig;
	VERIFY(m_mapAllCustomButtons.Lookup(nID,descriptorOrig));
	ASSERT_KINDOF(CIPAddressCtrl,descriptorOrig.m_pCBTemplate->CBGetWindow());
#endif	//	_DEBUG
	
	// register date-time and mont calendar window classes
	INITCOMMONCONTROLSEX icex;
	icex.dwSize=sizeof(INITCOMMONCONTROLSEX);
	icex.dwICC=ICC_INTERNET_CLASSES;
	::InitCommonControlsEx(&icex);

	return InsertCustomButton(
		nIndex,nCustomButtonIndex,dwStyle,dwStyleEx,_T("SysIPAddress32"));
}


BOOL COXCoolToolBar::InsertComboBoxEx(int nIndex, int nCustomButtonIndex, 
									  DWORD dwStyle/*=WS_CHILD|WS_VISIBLE|CBS_DROPDOWN*/, 
									  DWORD dwStyleEx/*=0*/)
{
#ifdef _DEBUG
	int nID=m_arrAllCustomButtonIDs[nCustomButtonIndex];
	OXCUSTOMBUTTONDESCRIPTOR descriptorOrig;
	VERIFY(m_mapAllCustomButtons.Lookup(nID,descriptorOrig));
	ASSERT_KINDOF(CComboBoxEx,descriptorOrig.m_pCBTemplate->CBGetWindow());
#endif	//	_DEBUG
	return InsertCustomButton(
		nIndex,nCustomButtonIndex,dwStyle,dwStyleEx,WC_COMBOBOXEX);
}
/////////////////////////////////////////////////////////////////////////////////
#endif	//	_MFC_VER>0x0421


BOOL COXCoolToolBar::ShowCustomButton(int nIndex)
{
	OXCUSTOMBUTTONDESCRIPTOR descriptor;
	if(!GetCustomButton(nIndex,descriptor))
	{
		TRACE(_T("COXCoolToolBar::ShowCustomButton: there is no custom button at specified index\n"));
		return FALSE;
	}

	BOOL bIsVisible=IsWindowVisible();

	BOOL bShowCustomButton=((descriptor.m_nFlags&(OXCBD_SHOWANY))==(OXCBD_SHOWANY));
	if(!bShowCustomButton)
	{
		if(IsFloating())
		{
			bShowCustomButton=(descriptor.m_nFlags&OXCBD_SHOWFLOAT);
		}
		else
		{
			if(m_dwStyle&CBRS_ORIENT_HORZ)
			{
				bShowCustomButton=(descriptor.m_nFlags&OXCBD_SHOWHORZ);
			}
			else
			{
				bShowCustomButton=(descriptor.m_nFlags&OXCBD_SHOWVERT);
			}
		}
	}

	if(bShowCustomButton)
	{
		UINT nIDTest;
		UINT nStyleTest;
		int nWidthTest;
		GetButtonInfo(nIndex,nIDTest,nStyleTest,nWidthTest);
		if((nStyleTest&TBBS_SEPARATOR)!=TBBS_SEPARATOR || 
			nWidthTest!=descriptor.m_nWidth)
		{
			SetButtonInfo(
				nIndex,descriptor.m_pCBTemplate->CBGetWindow()->GetDlgCtrlID(),
				TBBS_SEPARATOR,descriptor.m_nWidth);
		}

		CRect rect;
		GetItemRect(nIndex,&rect);
		rect.DeflateRect(2,0);
		if(descriptor.m_nHeight>0)
		{
			if(descriptor.m_nHeight<rect.Height())
			{
				rect.top+=(rect.Height()-descriptor.m_nHeight)/2;
			}
			rect.bottom=rect.top+descriptor.m_nHeight;
		}
		CWnd* pWnd = descriptor.m_pCBTemplate->CBGetWindow();
		if (DYNAMIC_DOWNCAST(CComboBox, pWnd))
		{
			// Center the combo box
			RECT rectButton;
			GetItemRect(0, &rectButton);
			rect.OffsetRect(0, (rectButton.bottom - 22) / 2 + 1);
		}
		pWnd->MoveWindow(rect,bIsVisible);
		pWnd->ShowWindow(SW_SHOWNA);
	}	
	else
	{
		UINT nIDTest;
		UINT nStyleTest;
		int nWidthTest;
		GetButtonInfo(nIndex,nIDTest,nStyleTest,nWidthTest);
		if((nStyleTest&TBBS_SEPARATOR)==TBBS_SEPARATOR || 
			(int)nIDTest!=descriptor.m_pCBTemplate->CBGetWindow()->GetDlgCtrlID())
		{
#if _MFC_VER > 0x0421
			SetButtonInfo(
				nIndex,descriptor.m_pCBTemplate->CBGetWindow()->GetDlgCtrlID(),
				TBBS_BUTTON,descriptor.m_nImageIndex);
			TBBUTTONINFO buttonInfo={ sizeof(TBBUTTONINFO) };
			buttonInfo.dwMask=TBIF_STYLE;
			if(GetToolBarCtrl().
				GetButtonInfo(descriptor.m_pCBTemplate->CBGetWindow()->GetDlgCtrlID(),
				&buttonInfo))
			{
				buttonInfo.fsStyle|=TBSTYLE_AUTOSIZE;
			}
			else
			{
				buttonInfo.fsStyle=TBSTYLE_AUTOSIZE;
			}
			VERIFY(GetToolBarCtrl().
				SetButtonInfo(descriptor.m_pCBTemplate->CBGetWindow()->GetDlgCtrlID(),
				&buttonInfo));
#else
			SetButtonInfo(
				nIndex,descriptor.m_pCBTemplate->CBGetWindow()->GetDlgCtrlID(),
				TBBS_BUTTON,descriptor.m_nImageIndex);
			TBBUTTONINFO buttonInfo={ sizeof(TBBUTTONINFO) };
			buttonInfo.dwMask=TBIF_STYLE;
			if(GetToolBarCtrl().SendMessage(TB_GETBUTTONINFO,
				(WPARAM) descriptor.m_pCBTemplate->CBGetWindow()->GetDlgCtrlID(),
				(LPARAM)(LPTBBUTTONINFO) &buttonInfo))
			{
				buttonInfo.fsStyle|=TBSTYLE_AUTOSIZE;
			}
			else
			{
				buttonInfo.fsStyle=TBSTYLE_AUTOSIZE;
			}
			VERIFY(GetToolBarCtrl().SendMessage(TB_GETBUTTONINFO,
				(WPARAM) descriptor.m_pCBTemplate->CBGetWindow()->GetDlgCtrlID(),
				(LPARAM)(LPTBBUTTONINFO) &buttonInfo));

#endif
		}
		descriptor.m_pCBTemplate->CBGetWindow()->ShowWindow(SW_HIDE);
	}

	if(bIsVisible!=IsWindowVisible())
	{
		if(bIsVisible)
		{
			ModifyStyle(0,WS_VISIBLE,SWP_NOREDRAW);
		}
		else
		{
			ModifyStyle(WS_VISIBLE,0,SWP_NOREDRAW);
		}
	}

	return TRUE;
}


int COXCoolToolBar::GetCustomButtonIndex(int nCtrlID)
{
	for(int nIndex=0; nIndex<m_arrAllCustomButtonIDs.GetSize(); nIndex++)
	{
		if(m_arrAllCustomButtonIDs[nIndex]==nCtrlID)
		{
			return nIndex;
		}
	}

	return -1;
}


int COXCoolToolBar::GetCustomButtonIndex(CWnd* pWnd)
{
	ASSERT(::IsWindow(pWnd->GetSafeHwnd()));
	return GetCustomButtonIndex(pWnd->GetDlgCtrlID());
}


void COXCoolToolBar::UpdateCustomButtons(int nFirstButtonIndex/*=0*/, 
										 int nLastButtonIndex/*=-1*/)
{
	if(nLastButtonIndex==-1)
	{
		nLastButtonIndex=GetToolBarCtrl().GetButtonCount()-1;
	}

	for(int nIndex=nFirstButtonIndex; nIndex<=nLastButtonIndex; nIndex++)
	{
		OXCUSTOMBUTTONDESCRIPTOR descriptor;
		if(m_mapCustomButtons.Lookup(nIndex,descriptor))
		{
			ShowCustomButton(nIndex);
		}
	}
}


HRESULT COXCoolToolBar::GetComCtlVersion(LPDWORD pdwMajor, LPDWORD pdwMinor) const
{
	if(IsBadWritePtr(pdwMajor, sizeof(DWORD)) || 
		IsBadWritePtr(pdwMinor, sizeof(DWORD)))
	{
		return E_INVALIDARG;
	}

	// get handle of the common control DLL
	BOOL bAlreadyLoaded=TRUE;
	HINSTANCE hComCtl=::GetModuleHandle(_T("comctl32.dll"));
	if(hComCtl==NULL)
	{
		// load the DLL
		hComCtl=::LoadLibrary(_T("comctl32.dll"));
		bAlreadyLoaded=FALSE;
	}

	if(hComCtl)
	{
		HRESULT           hr=S_OK;
		DLLGETVERSIONPROC pDllGetVersion;
   
		/*
		You must get this function explicitly because earlier versions of the DLL 
		don't implement this function. That makes the lack of implementation of the 
		function a version marker in itself.
		*/
		pDllGetVersion=(DLLGETVERSIONPROC)GetProcAddress(hComCtl, "DllGetVersion");
   
		if(pDllGetVersion)
		{
			DLLVERSIONINFO dvi;
      
			ZeroMemory(&dvi, sizeof(dvi));
			dvi.cbSize=sizeof(dvi);
   
			hr = (*pDllGetVersion)(&dvi);
      
			if(SUCCEEDED(hr))
			{
				*pdwMajor = dvi.dwMajorVersion;
				*pdwMinor = dvi.dwMinorVersion;
			}
			else
			{
				hr = E_FAIL;
			}   
		}
		else
		{
			// If GetProcAddress failed, then the DLL is a version previous 
			// to the one shipped with IE 3.x.
			*pdwMajor = 4;
			*pdwMinor = 0;
		}
   
		if(!bAlreadyLoaded)
			::FreeLibrary(hComCtl);

		return hr;
	}

	return E_FAIL;
}

#if _MFC_VER >= 0x0700
void COXCoolToolBar::DrawBorders(CDC* pDC, CRect& rect)
{
	ASSERT_VALID(this);
	ASSERT_VALID(pDC);

	DWORD dwStyle = m_dwStyle;
	if (!(dwStyle & CBRS_BORDER_ANY))
		return;

	// prepare for dark lines
	ASSERT(rect.top == 0 && rect.left == 0);
	CRect rect1, rect2;
	rect1 = rect;
	rect2 = rect;
	COLORREF clr = afxData.clrBtnShadow;


	// draw dark line one pixel back/up
	if (dwStyle & CBRS_BORDER_3D)
	{
		rect1.right -= CX_BORDER;
		rect1.bottom -= CY_BORDER;
	}
	if (dwStyle & CBRS_BORDER_TOP)
		rect2.top += afxData.cyBorder2;
	if (dwStyle & CBRS_BORDER_BOTTOM)
		rect2.bottom -= afxData.cyBorder2;

	// draw left and top
	if (dwStyle & CBRS_BORDER_LEFT)
		pDC->FillSolidRect(0, rect2.top, CX_BORDER, rect2.Height(), clr);
	if (dwStyle & CBRS_BORDER_TOP)
		pDC->FillSolidRect(0, 0, rect.right, CY_BORDER, clr);

	// draw right and bottom
	if (dwStyle & CBRS_BORDER_RIGHT)
		pDC->FillSolidRect(rect1.right, rect2.top, -CX_BORDER, rect2.Height(), clr);
	if (dwStyle & CBRS_BORDER_BOTTOM)
		pDC->FillSolidRect(0, rect1.bottom, rect.right, -CY_BORDER, clr);


	if (dwStyle & CBRS_BORDER_3D)
	{
		// prepare for hilite lines
		clr = afxData.clrBtnHilite;

		// draw left and top
		if (dwStyle & CBRS_BORDER_LEFT)
			pDC->FillSolidRect(1, rect2.top, CX_BORDER, rect2.Height(), clr);
		if (dwStyle & CBRS_BORDER_TOP)
			pDC->FillSolidRect(0, 1, rect.right, CY_BORDER, clr);

		// draw right and bottom
		if (dwStyle & CBRS_BORDER_RIGHT)
			pDC->FillSolidRect(rect.right, rect2.top, -CX_BORDER, rect2.Height(), clr);
		if (dwStyle & CBRS_BORDER_BOTTOM)
			pDC->FillSolidRect(0, rect.bottom, rect.right, -CY_BORDER, clr);
	}

	if (dwStyle & CBRS_BORDER_LEFT)
		rect.left += afxData.cxBorder2;
	if (dwStyle & CBRS_BORDER_TOP)
		rect.top += afxData.cyBorder2;
	if (dwStyle & CBRS_BORDER_RIGHT)
		rect.right -= afxData.cxBorder2;
	if (dwStyle & CBRS_BORDER_BOTTOM)
		rect.bottom -= afxData.cyBorder2;

}
#endif // _MFC_VER >= 0x0700

////////////////////////////////
#endif //_MFC_VER>=0x0420

COXToolbarSkin* COXCoolToolBar::GetToolbarSkin()
{
	// Check if the app is derived from COXSkinnedApp
	COXSkinnedApp* pSkinnedApp = DYNAMIC_DOWNCAST(COXSkinnedApp, AfxGetApp());
	if (pSkinnedApp != NULL && pSkinnedApp->GetCurrentSkin() != NULL)
		return pSkinnedApp->GetCurrentSkin()->GetToolbarSkin();
	else
	{
		// Create a classic skin for this class if not created already
		if (m_pToolbarSkin == NULL)
			m_pToolbarSkin = new COXToolbarSkinClassic();

		return m_pToolbarSkin;
	}
}

BOOL COXCoolToolBar::OnDropDownButton(NMHDR* pNMHDR, LRESULT* result)
{
	// Save the index of the last drop down button
	LPNMTOOLBAR pNMToolBar = (LPNMTOOLBAR) pNMHDR;
	m_iDropDownIndex = pNMToolBar->iItem;
	m_iLastDropDownIndex = pNMToolBar->iItem;
	result = 0;
	return FALSE;
}

BOOL COXCoolToolBar::IsFloatingEnabled()
{
	return m_bFloatingEnabled;
}

void COXCoolToolBar::EnableFloating(BOOL bEnable)
{
	m_bFloatingEnabled = bEnable;
}

void COXCoolToolBar::EnableDocking(DWORD dwDockStyle, BOOL bSnapWhileDragging)
{
	// must be CBRS_ALIGN_XXX or CBRS_FLOAT_MULTI only
	ASSERT((dwDockStyle & ~(CBRS_ALIGN_ANY|CBRS_FLOAT_MULTI)) == 0);
	// CBRS_SIZE_DYNAMIC toolbar cannot have the CBRS_FLOAT_MULTI style
	ASSERT(((dwDockStyle & CBRS_FLOAT_MULTI) == 0) || ((m_dwStyle & CBRS_SIZE_DYNAMIC) == 0));

	m_dwDockStyle = dwDockStyle;
	if (m_pDockContext == NULL)
		m_pDockContext = new CDockContext(this);

	// permanently wire the bar's owner to its current parent
	if (m_hWndOwner == NULL)
		m_hWndOwner = ::GetParent(m_hWnd);

	m_bSnapWhileDragging = bSnapWhileDragging;
}

void COXCoolToolBar::SaveMouseOffset(CPoint point)
{
	// Calculate and save the offset
	CRect rectWindow;
	GetWindowRect(rectWindow);
	ScreenToClient(&rectWindow);

	m_ptOffset = point - rectWindow.TopLeft();
}

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, along with any associated source code and files, is licensed under The Code Project Open License (CPOL)


Written By
Web Developer
Canada Canada
In January 2005, David Cunningham and Chris Maunder created TheUltimateToolbox.com, a new group dedicated to the continued development, support and growth of Dundas Software’s award winning line of MFC, C++ and ActiveX control products.

Ultimate Grid for MFC, Ultimate Toolbox for MFC, and Ultimate TCP/IP have been stalwarts of C++/MFC development for a decade. Thousands of developers have used these products to speed their time to market, improve the quality of their finished products, and enhance the reliability and flexibility of their software.
This is a Organisation

476 members

Comments and Discussions