www.pudn.com > 20040716141459_combotree.rar > TreeCombo.cpp


/* Standard Disclaimer:  
Copyright (C) 2000  Dennis Howard 
This file is free software; you can redistribute it and/or 
modify it without any conditions. There is no warranty, 
implied or expressed, as to validity or fitness for a particular purpose. 
*/ 
 
// TreeCombo.cpp : implementation file 
// 
 
#include "stdafx.h" 
#include "TreeCombo.h" 
 
#ifdef _DEBUG 
#define new DEBUG_NEW 
#undef THIS_FILE 
static char THIS_FILE[] = __FILE__; 
#endif 
 
 
//non top level child control ids 
#define IDC_COMBOTREE_BUTTON 4317          
#define IDC_COMBOTREE_EDIT   4318  
         
 
///////////////////////////////////////////////////////////////////////////// 
// CTreeCombo 
 
CTreeCombo::CTreeCombo() 
{ 
	m_Tree.SetCombo (this); 
	m_ComboWidth = 200; 
	m_ComboHeight = 200; 
	m_bDroppedState = FALSE; 
} 
 
CTreeCombo::~CTreeCombo() 
{ 
} 
 
 
BEGIN_MESSAGE_MAP(CTreeCombo, CWnd) 
	//{{AFX_MSG_MAP(CTreeCombo) 
	ON_WM_CREATE() 
	ON_WM_SETFOCUS() 
	//}}AFX_MSG_MAP 
	ON_BN_CLICKED (IDC_COMBOTREE_BUTTON, OnDropdownButton ) 
END_MESSAGE_MAP() 
 
///////////////////////////////////////////////////////////////////////////// 
// CTreeCombo message handlers 
 
LRESULT CTreeCombo::SendParentComboMessage (UINT Action) 
{ 
	CWnd* pParent = GetParent (); 
	if (pParent && pParent->GetSafeHwnd ()) 
	{ 
		return pParent->SendMessage (WM_COMMAND, MAKEWPARAM( GetDlgCtrlID(), Action),(LPARAM) GetSafeHwnd ()); 
	} 
 
	return 0L; 
} 
 
void CTreeCombo::SetWindowText (LPCTSTR Text) 
{ 
	m_Edit.SetWindowText (Text); 
	Invalidate (); 
} 
 
 
CString CTreeCombo::GetWindowText () 
{ 
	CString Text; 
	m_Edit.GetWindowText(Text); 
	return Text; 
} 
 
int CTreeCombo::GetLBText (HTREEITEM hItem, CString& rText) 
{ 
  rText = _T(""); 
  int retval = CB_ERR; 
  rText = m_Tree.GetItemText (hItem); 
  if (rText.GetLength () > 0) 
  { 
	retval = 0; 
  } 
  return retval; 
} 
 
TCHAR CTreeCombo::GetPathDelimiter () 
{ 
	return m_Tree.GetPathDelimiter (); 
} 
 
void CTreeCombo::SetPathDelimiter (TCHAR Delimiter) 
{ 
	m_Tree.SetPathDelimiter (Delimiter); 
} 
 
void CTreeCombo::OnDropdownButton () 
{ 
	 
    if (GetDroppedState ()) 
	{ 
		//If the drop down button was clicked on while the tree was open, 
		//the tree's OnKillFocus () will close it. Only need to clear the  
		//flag here. 
	    SetDroppedState (FALSE); 
	} 
	else 
	{ 
		DisplayTree (); 
		SendParentComboMessage (CBN_DROPDOWN); 
	} 
} 
 
 
void CTreeCombo::CalculateDroppedRect(LPRECT lpDroppedRect) 
{ 
	_ASSERTE (lpDroppedRect); 
 
	if (!lpDroppedRect) 
	{ 
		return; 
	} 
 
	CRect rectCombo; 
	GetWindowRect(&rectCombo); 
 
	//adjust to either the top or bottom 
	int DropTop = rectCombo.bottom; 
	int ScreenHeight = GetSystemMetrics (SM_CYSCREEN); 
	if ((DropTop + m_ComboHeight) > ScreenHeight) 
	{ 
		DropTop = rectCombo.top - m_ComboHeight; 
	} 
 
	//adjust to either the right or left 
	int DropLeft = rectCombo.left; 
	int ScreenWidth = GetSystemMetrics (SM_CXSCREEN); 
	if ((DropLeft + m_ComboWidth) > ScreenWidth) 
	{ 
		DropLeft = rectCombo.right - m_ComboWidth; 
	} 
 
	lpDroppedRect->left  = DropLeft; 
	lpDroppedRect->top   = DropTop; 
	lpDroppedRect->bottom = DropTop + m_ComboHeight; 
	lpDroppedRect->right  = DropLeft + m_ComboWidth; 
 
} 
 
void CTreeCombo::DisplayTree() 
{ 
	CRect rect(0,0,200,200); 
 
	CalculateDroppedRect (&rect); 
 
	m_Tree.InitDisplay (); 
 
	m_Tree.SetWindowPos (&wndNoTopMost, rect.left, rect.top, 
		                 rect.Width (), rect.Height (), SWP_SHOWWINDOW ); 
 
	m_BeginPath = m_Tree.GetCurrentTreePath (); 
 
	SetDroppedState (TRUE); 
} 
 
 
void CTreeCombo::OnCancel () 
{ 
	//restore inital path 
	m_Tree.SelectString (m_BeginPath); 
	SendParentComboMessage (CBN_SELENDCANCEL); 
} 
 
BOOL CTreeCombo::CreateTree () 
{	 
	CWnd* pParent = GetParent (); 
	if (!pParent && pParent->GetSafeHwnd ()) 
	{ 
		return FALSE; 
	} 
 
	CRect treeRect (0,0, m_ComboWidth, m_ComboHeight); 
 
	//can't have a control Id with WS_POPUP style 
    if (! m_Tree.CreateEx ( 0, 
		                   WC_TREEVIEW, NULL, 
						   	WS_POPUP | WS_BORDER | TVS_SINGLEEXPAND | TVS_HASLINES | TVS_LINESATROOT | TVS_HASBUTTONS, 
							treeRect, pParent, 0, NULL)) 
	{ 
		return FALSE; 
	} 
 
 
	return TRUE; 
} 
 
 
BOOL CTreeCombo::CreateButton () 
{	 
	CRect btnRect; 
	GetClientRect (&btnRect); 
 
//Get the bitmap size and add border space	 
	CBitmap bitmapDown; 
	CDC* pDC = GetDC(); 
	CDC tempDC; 
	BITMAP bm; 
 
	bitmapDown.LoadBitmap (_T("CBU")); 
    tempDC.CreateCompatibleDC (pDC); 
	CBitmap* pOldBitmap = tempDC.SelectObject (&bitmapDown); 
	bitmapDown.GetObject (sizeof(BITMAP), (LPSTR)&bm); 
	tempDC.SelectObject (pOldBitmap); 
 
	int xBorder = GetSystemMetrics (SM_CXEDGE); 
	int yBorder = GetSystemMetrics (SM_CYEDGE); 
 
	btnRect.left = btnRect.right - bm.bmWidth - xBorder*2; 
    btnRect.bottom = btnRect.top + bm.bmHeight + yBorder*2; 
	 
	 
     m_DropDownButton.CreateEx(WS_EX_CLIENTEDGE, // Make a 3D-border 
      _T("BUTTON"), NULL, 
      BS_PUSHBUTTON | WS_VISIBLE | WS_CHILD | BS_OWNERDRAW , 
      btnRect, this, IDC_COMBOTREE_BUTTON); 
 
	m_DropDownButton.LoadBitmaps (_T("CBU"), _T("CBD")); 
 
	return TRUE; 
} 
 
 
//Requires that dropdown button be created first, to size it properly 
BOOL CTreeCombo::CreateEdit () 
{	 
	if (!m_DropDownButton.GetSafeHwnd ()) 
	{ 
		return FALSE; 
	} 
 
	CRect clientRect; 
	GetClientRect (&clientRect); 
 
	CRect btnRect; 
	m_DropDownButton.GetWindowRect (&btnRect); 
	ScreenToClient (&btnRect); 
 
	CRect editRect; 
	editRect.left = clientRect.left; 
	editRect.top = clientRect.top; 
	editRect.bottom = clientRect.bottom; 
	editRect.right = btnRect.left; 
 
 
	BOOL bCreate = m_Edit.Create (WS_CHILD | WS_TABSTOP | ES_LEFT | WS_VISIBLE | ES_WANTRETURN, editRect, this, IDC_COMBOTREE_EDIT); 
 
	if (bCreate) 
	{ 
		CWnd* pParent = GetParent (); 
		CFont* pFont = pParent->GetFont (); 
		m_Edit.SetFont (pFont); 
	} 
 
	return bCreate; 
} 
 
//Removes the original ComboBox control instead of subclassing it 
BOOL CTreeCombo::SubclassDlgItem (UINT nID, CWnd* pParent) 
{ 
	CComboBox* pCombo = static_cast(pParent->GetDlgItem (nID)); 
	if (!pCombo) 
	{ 
		return FALSE; 
	} 
 
	CRect DroppedRect; 
	pCombo->GetDroppedControlRect (&DroppedRect); 
	m_ComboWidth = DroppedRect.Width (); 
	m_ComboHeight = DroppedRect.Height (); 
 
 
 	CRect rect; 
	pCombo->GetWindowRect (&rect); 
	pParent->ScreenToClient (&rect); 
 
   CString className = AfxRegisterWndClass(   CS_VREDRAW | CS_HREDRAW | CS_DBLCLKS, 
						::LoadCursor(NULL, IDC_ARROW), 
						(HBRUSH) ::GetStockObject(WHITE_BRUSH)); 
 
 
   BOOL bCreate =  CreateEx(WS_EX_CLIENTEDGE, // 3D  client edge  
		 className, NULL, 
		 WS_CHILD | WS_VISIBLE | WS_TABSTOP, 
		 rect, pParent, nID); 
 
	_ASSERTE (bCreate); 
 
	if (!bCreate) 
	{ 
		return FALSE; 
	} 
 
	//Set Z Order to follow after original combo 
	SetWindowPos (pCombo, 0, 0, 0, 0, SWP_NOSIZE | SWP_NOMOVE | SWP_SHOWWINDOW); 
 
	UpdateWindow (); 
 
	pCombo->DestroyWindow (); //remove original window 
 
	return TRUE;  
} 
 
int CTreeCombo::OnCreate(LPCREATESTRUCT lpCreateStruct)  
{ 
	if (CWnd::OnCreate(lpCreateStruct) == -1) 
		return -1; 
 
	if (!CreateTree()) 
	{ 
		return -1; 
	} 
 
	if (!CreateButton()) 
	{ 
		return -1; 
	} 
 
	if (!CreateEdit()) 
	{ 
		return -1; 
	} 
 
	return 0; 
} 
 
 
CString CTreeCombo::GetTreePath (HTREEITEM hItem) 
{ 
	return m_Tree.GetTreePath (hItem); 
} 
 
CString CTreeCombo::GetCurrentTreePath () 
{ 
	return m_Tree.GetCurrentTreePath (); 
} 
 
 
HTREEITEM CTreeCombo::AddString ( LPCTSTR lpszString) 
{ 
	return m_Tree.AddString (lpszString); 
} 
 
HTREEITEM CTreeCombo::FindString ( LPCTSTR lpszString, HTREEITEM hParent /*=NULL*/) 
{ 
	return m_Tree.FindString (lpszString, hParent); 
} 
 
 
int CTreeCombo::DeleteString( HTREEITEM hItem ) 
{ 
	HTREEITEM hSelected = m_Tree.GetSelectedItem (); 
	if (m_Tree.DeleteItem (hItem)) 
	{ 
		if (hItem == hSelected) 
		{ 
			//get the new item 
			hItem = m_Tree.GetSelectedItem (); 
			if (hItem) 
			{ 
				CString NodeText = m_Tree.GetItemText (hItem); 
				SetWindowText (NodeText); 
				SendParentComboMessage (CBN_SELCHANGE); 
			} 
			else 
			{ 
				SetWindowText (_T("")); 
			} 
		} 
 
		return 0; 
	} 
	else 
	{ 
		return CB_ERR; 
	} 
} 
 
 
HTREEITEM CTreeCombo::SelectString( LPCTSTR lpszString, HTREEITEM hParent /*=NULL*/) 
{ 
	HTREEITEM hMatch = m_Tree.SelectString (lpszString, hParent); 
	CString NodeText = m_Tree.GetItemText (hMatch); 
	SetWindowText (NodeText); 
 
	SendParentComboMessage (CBN_SELCHANGE); 
 
	return hMatch; 
} 
 
HTREEITEM CTreeCombo::GetCurSel () 
{ 
	return m_Tree.GetSelectedItem (); 
} 
 
int CTreeCombo::SetItemData (HTREEITEM hItem, DWORD dwItemData) 
{ 
	if (!m_Tree.SetItemData (hItem, dwItemData)) 
	{ 
		return CB_ERR; 
	} 
	else  
	{ 
		return 0; 
	} 
} 
 
DWORD CTreeCombo::GetItemData (HTREEITEM hItem) 
{ 
	return m_Tree.GetItemData (hItem); 
} 
 
void CTreeCombo::ShowDropDown( BOOL bShowIt) 
{ 
	if (!GetDroppedState ()) 
	{ 
		DisplayTree (); 
	} 
} 
 
void CTreeCombo::ResetContent () 
{ 
	m_Tree.DeleteAllItems( ); 
} 
 
 
int CTreeCombo::SetDroppedWidth( UINT nWidth ) 
{ 
	int retval = 0; 
	if (nWidth >= 0) 
	{ 
		m_ComboWidth = nWidth; 
		if (GetDroppedState ()) 
		{ 
			DisplayTree (); 
		} 
	} 
	else 
	{ 
		retval = CB_ERR; 
	} 
	return retval; 
} 
 
int CTreeCombo::GetDroppedWidth( ) 
{ 
	return m_ComboWidth; 
} 
 
int CTreeCombo::SetDroppedHeight (UINT nHeight) 
{ 
	int retval = 0; 
	if (nHeight >= 0) 
	{ 
		m_ComboHeight = nHeight; 
		if (GetDroppedState ()) 
		{ 
			DisplayTree (); 
		} 
	} 
	else 
	{ 
		retval = CB_ERR; 
	} 
	return retval; 
} 
 
int CTreeCombo::GetDroppedHeight () 
{ 
	return m_ComboHeight; 
} 
 
BOOL CTreeCombo::GetDroppedState( ) 
{ 
	return m_bDroppedState; 
} 
 
void CTreeCombo::GetDroppedControlRect (LPRECT pRect) 
{ 
	_ASSERTE (pRect); 
	if (pRect) 
	{ 
		CalculateDroppedRect (pRect); 
	} 
} 
 
void CTreeCombo::OnSetFocus(CWnd* pOldWnd)  
{ 
	CWnd::OnSetFocus(pOldWnd); 
	if (::GetFocus() != m_DropDownButton.GetSafeHwnd()) 
	{ 
		m_Edit.SetFocus (); 
	} 
} 
 
BOOL CTreeCombo::IsMouseOnButton()  
{ 
	BOOL bMouseOn = FALSE; 
	CPoint point; 
	if (GetCursorPos (&point)) 
	{ 
		CRect rect; 
		m_DropDownButton.GetWindowRect (&rect); 
		if (rect.PtInRect (point)) 
		{ 
			bMouseOn = TRUE; 
		} 
	} 
	return bMouseOn; 
} 
 
BOOL CTreeCombo::IsMouseOnEdit()  
{ 
	BOOL bMouseOn = FALSE; 
	CPoint point; 
	if (GetCursorPos (&point)) 
	{ 
		CRect rect; 
		m_Edit.GetWindowRect (&rect); 
		if (rect.PtInRect (point)) 
		{ 
			bMouseOn = TRUE; 
		} 
	} 
	return bMouseOn; 
}