// ToolBar1.cpp : implementation file
//

// This is a part of the Microsoft Foundation Classes C++ library.
// Copyright (C) 1992-1995 Microsoft Corporation
// All rights reserved.
//
// This source code is only intended as a supplement to the
// Microsoft Foundation Classes Reference and related
// electronic documentation provided with the library.
// See these sources for detailed information regarding the
// Microsoft Foundation Classes product.

#include "stdafx.h"
#include "afxpriv.h"
#include "ctrldemo.h"
#include "Toolbar1.h"

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

/////////////////////////////////////////////////////////////////////////////
// CStandardBar

CStandardBar::CStandardBar() : m_pTBButtons(NULL)
{

}

CStandardBar::~CStandardBar()
{
	if (m_pTBButtons)
		delete []m_pTBButtons;

}


BEGIN_MESSAGE_MAP(CStandardBar, CToolBarCtrl)
	//{{AFX_MSG_MAP(CStandardBar)
	ON_NOTIFY_RANGE( TTN_NEEDTEXTA, ID_NEW, ID_CONTEXTHELP, OnNeedTextA)
	ON_NOTIFY_RANGE( TTN_NEEDTEXTW, ID_NEW, ID_CONTEXTHELP, OnNeedTextW)
	//}}AFX_MSG_MAP
END_MESSAGE_MAP()


BOOL CStandardBar::Create(DWORD dwStyle, const RECT& rect, CWnd* pParentWnd, UINT nID ) 
{
	BOOL bRet = CToolBarCtrl::Create(dwStyle, rect, pParentWnd, nID);
	
	m_nButtonCount = ID_CONTEXTHELP - ID_NEW + 1;

	VERIFY(AddBitmap(m_nButtonCount,IDR_STANDARDBAR) != -1);

	m_pTBButtons = new TBBUTTON[m_nButtonCount];

	for (int nIndex = 0; nIndex < m_nButtonCount; nIndex++)
	{
		CString string;
		string.LoadString(nIndex + ID_NEW);

		// Add second '\0'
		int nStringLength = string.GetLength() + 1;
		TCHAR * pString = string.GetBufferSetLength(nStringLength);
		pString[nStringLength] = 0;

		VERIFY((m_pTBButtons[nIndex].iString = AddStrings(pString)) != -1);
	
		string.ReleaseBuffer();


		m_pTBButtons[nIndex].fsState = TBSTATE_ENABLED;
		m_pTBButtons[nIndex].fsStyle = TBSTYLE_BUTTON;
		m_pTBButtons[nIndex].dwData = 0;
		m_pTBButtons[nIndex].iBitmap = nIndex;
		m_pTBButtons[nIndex].idCommand = nIndex + ID_NEW;

	}

	TBBUTTON sepButton;
	sepButton.idCommand = 0;
	sepButton.fsStyle = TBSTYLE_SEP;
	sepButton.fsState = TBSTATE_ENABLED;
	sepButton.iString = 0;
	sepButton.iBitmap = 0;
	sepButton.dwData = 0;

	for (nIndex = 0; nIndex < m_nButtonCount; nIndex++)
	{
		VERIFY(AddButtons(1,&m_pTBButtons[nIndex]));
		if (!((nIndex +1) % 3))
		{
			VERIFY(AddButtons(1,&sepButton));
		}
	}


	return bRet;
}


/////////////////////////////////////////////////////////////////////////////
// CStandardBar message handlers

// MFC routes the notifications sent to the parent of the control to
// the control before the parent can process the notification.
// The control object can handle the notification or ignore it.
// If the notification is handled then return TRUE. Otherwise MFC
// will route it to the parent of the control.

BOOL CStandardBar::OnChildNotify(UINT message, WPARAM wParam, LPARAM lParam, LRESULT* pLResult) 
{
	if (message == WM_NOTIFY)
	{
		NMHDR *pNMHDR = (NMHDR *) lParam;
		switch (pNMHDR->code)
		{
		case TBN_BEGINADJUST :
			return BeginAdjust(wParam,  lParam,  pLResult);
			
		case TBN_BEGINDRAG:
			return BeginDrag(wParam,  lParam,  pLResult);
	
		case TBN_CUSTHELP:
			return CustomizeHelp(wParam,  lParam,  pLResult);
		
		case TBN_ENDADJUST:
			return EndAdjust(wParam,  lParam,  pLResult);
		
		case TBN_ENDDRAG:
			return EndDrag(wParam,  lParam,  pLResult);
		
		case TBN_GETBUTTONINFO:
			return GetButtonInfo(wParam,  lParam,  pLResult);
		
		case TBN_QUERYDELETE:
			return QueryDelete(wParam,  lParam,  pLResult);
		
		case TBN_QUERYINSERT:
			return QueryInsert(wParam,  lParam,  pLResult);
		
		case TBN_RESET:
			return Reset(wParam, lParam,  pLResult);
		
		case TBN_TOOLBARCHANGE:
			return ToolBarChange(wParam, lParam, pLResult);
		}
	}

	return CToolBarCtrl::OnChildNotify(message, wParam, lParam, pLResult);
}

BOOL CStandardBar::BeginAdjust(WPARAM wParam, LPARAM lParam, LRESULT* pLResult)
{
	TRACE(_T("TBN_BEGINADJUST\n"));

	// the customize dialog box is about to be displayed

	// save toolbar state before customization using the dialog
	// Use this information to restore the state if reset button is pressed
	SaveState(HKEY_CURRENT_USER,_T("Software\\Microsoft\\VC40\\Samples\\CtrlDemo"),_T("Standard Tool Bar"));

	return TRUE;
}

BOOL CStandardBar::BeginDrag(WPARAM wParam, LPARAM  lParam, LRESULT* pLResult)
{
	TRACE(_T("TBN_BEGINDRAG\n"));

	// we are not implementing custon drag and drop 
	* pLResult = FALSE;
	return FALSE;
}

BOOL CStandardBar::CustomizeHelp(WPARAM wParam, LPARAM  lParam, LRESULT* pLResult)
{
	TRACE(_T("TBN_CUSTHELP\n"));

	// Sample displays a message box but a valid help topic
	// can be displayed for the customize dialog for this toolbar
	AfxMessageBox(_T("Help not implemented!"));

	return TRUE;
}

BOOL CStandardBar::EndAdjust(WPARAM wParam, LPARAM  lParam, LRESULT* pLResult)
{
	TRACE(_T("TBN_ENDADJUST\n"));

	// the customize dialog box has been closed

	return TRUE;
}

BOOL CStandardBar::EndDrag(WPARAM wParam, LPARAM  lParam, LRESULT* pLResult)
{
	TRACE(_T("TBN_ENDDRAG\n"));

	// Code to handle custom drag and drop. This message indicates that 
 	// the item is being dropped
	* pLResult = FALSE;
	return TRUE;
}

BOOL CStandardBar::GetButtonInfo(WPARAM wParam, LPARAM  lParam, LRESULT* pLResult)
{
	// This notification message has to be handled correctly if 
	// all operations in the custom dialogbox has to function correctly
	// We have to supply information for the button specified by pTBN->tbButton
	//
	// This notification is sent in the following cases
	// 
	// After TBN_BEGINADJUST the control sends these notifications until
	// * pLResult is TRUE. We have to supply valid values when this value is
	// set to TRUE. Here the control is collecting information for all
	// the buttons that have to be displayed in the dialog box
	// 
	// The control sends this notification to get information about
	// a button if the user is trying to add it to the toolbar or 
	// rearranging the buttons on the toolbar from within the dialog

	TRACE(_T("TBN_GETBUTTONINFO\n"));

	TBNOTIFY *pTBN = (TBNOTIFY *) lParam;

	if (pTBN->iItem >= m_nButtonCount)
	{
		* pLResult = FALSE;
	}
	else
	{
		CString buffer;
		buffer.LoadString(pTBN->iItem + ID_NEW);

		// set the string for the button
		// truncate the string if its length is greater than the buffer
		// supplied by the toolbar
		_tcsncpy(pTBN->pszText, buffer, pTBN->cchText - 1);
		pTBN->pszText[pTBN->cchText - 1] = '\0';

		// set the button info
		pTBN->tbButton = m_pTBButtons[pTBN->iItem];

		// valid values are structure
		*pLResult = TRUE;
	}

	return TRUE;
}

BOOL CStandardBar::QueryDelete(WPARAM wParam, LPARAM  lParam, LRESULT* pLResult)
{
	TRACE(_T("TBN_QUERYDELETE\n"));

	// in this sample any button can be deleted
	// if a particular button cannot be deleted set *pResult to FALSE for that item
	*pLResult = TRUE;
	return TRUE;
}

BOOL CStandardBar::QueryInsert(WPARAM wParam, LPARAM  lParam, LRESULT* pLResult)
{
	TRACE(_T("TBN_QUERYINSERT\n"));

	// in this sample buttons can be inserted at any location on the 
	// toolbar
	*pLResult = TRUE;
	return TRUE;
}

BOOL CStandardBar::Reset(WPARAM wParam, LPARAM lParam, LRESULT* pLResult)
{
	TRACE(_T("TBN_RESET\n"));

	// User has pressed the reset button
	// restore the state of the toolbar to the state it was before customization
	RestoreState(HKEY_CURRENT_USER,_T("Software\\Microsoft\\VC40\\Samples\\CtrlDemo"),_T("Standard Tool Bar"));

	*pLResult = TRUE;
	return TRUE;
}

BOOL CStandardBar::ToolBarChange(WPARAM wParam, LPARAM lParam,LRESULT* pLResult)
{
	TRACE(_T("TBN_TOOLBARCHANGE\n"));

	// the toolbar has changed
	return TRUE;
}


// Helper function for tooltips

CString CStandardBar::NeedText( UINT nID, NMHDR * pNotifyStruct, LRESULT * lResult )
{
	LPTOOLTIPTEXT lpTTT = (LPTOOLTIPTEXT)pNotifyStruct ;
    ASSERT(nID == lpTTT->hdr.idFrom); 

	CString toolTipText;
	toolTipText.LoadString(nID);

	// szText length is 80
	int nLength = (toolTipText.GetLength() > 79) ? 79 : toolTipText.GetLength();

	toolTipText = toolTipText.Left(nLength);

	return toolTipText;
}


void CStandardBar::OnNeedTextW( UINT nID, NMHDR * pNotifyStruct, LRESULT * lResult )
{
	CString toolTipText = NeedText(nID, pNotifyStruct, lResult);

	LPTOOLTIPTEXTW lpTTT = (LPTOOLTIPTEXTW)pNotifyStruct;

#ifndef _UNICODE
	mbstowcs(lpTTT->szText,(LPCSTR)toolTipText, toolTipText.GetLength() + 1); 
#else
	_tcsncpy(lpTTT->szText, toolTipText, toolTipText.GetLength() + 1);
#endif
}

void CStandardBar::OnNeedTextA( UINT nID, NMHDR * pNotifyStruct, LRESULT * lResult )
{
	CString toolTipText = NeedText(nID, pNotifyStruct, lResult);

	LPTOOLTIPTEXT lpTTT = (LPTOOLTIPTEXT)pNotifyStruct;

	_tcscpy(lpTTT->szText,(LPCTSTR)toolTipText);
}


///////////////////////////////////////////////////////////////////////
// This has been overridden so we can handle the tooltip TTN_NEEDTEXT//
// notification message                                              //
///////////////////////////////////////////////////////////////////////

BOOL CStandardBar::OnNotify(WPARAM wParam, LPARAM lParam, LRESULT* pResult)
{
	ASSERT(pResult != NULL);
	NMHDR* pNMHDR = (NMHDR*)lParam;
	HWND hWndCtrl = pNMHDR->hwndFrom;

	// get the child ID from the window itself
	// UINT nID = _AfxGetDlgCtrlID(hWndCtrl); 

	//////////////////////////////////////////////////////////////////
	// If TTN_NEEDTEXT we cannot get the ID from the tooltip window //
	//////////////////////////////////////////////////////////////////

	int nCode = pNMHDR->code;

	//
	// if it is the following notification message 
	// nID has to obtained from wParam
	//
	
	if (nCode == TTN_NEEDTEXTA || nCode == TTN_NEEDTEXTW)
	{	
		UINT nID;   // = _AfxGetDlgCtrlID(hWndCtrl);
		nID = (UINT)wParam;


		ASSERT((UINT)pNMHDR->idFrom == (UINT)wParam);
		UNUSED(wParam);  // not used in release build
		ASSERT(hWndCtrl != NULL);
		ASSERT(::IsWindow(hWndCtrl));

		if (AfxGetThreadState()->m_hLockoutNotifyWindow == m_hWnd)
			return TRUE;        // locked out - ignore control notification

	// reflect notification to child window control
		if (ReflectLastMsg(hWndCtrl, pResult))
			return TRUE;        // eaten by child

		AFX_NOTIFY notify;
		notify.pResult = pResult;
		notify.pNMHDR = pNMHDR;
		return OnCmdMsg(nID, MAKELONG(nCode, WM_NOTIFY), &notify, NULL);
	}

	return CToolBarCtrl::OnNotify(wParam, lParam, pResult);
}

