Click here to Skip to main content
15,881,248 members
Articles / Desktop Programming / MFC

An Adaptable Property List Control

Rate me:
Please Sign up or sign in to vote.
4.68/5 (11 votes)
25 Apr 2003 209.4K   1.7K   83  
An object properties list control than can change based on the objects state.
// InPlaceComboBoxImp.cpp : implementation file
//
/////////////////////////////////////////////////////////////////////////////
//
// Copyright � 1999, Stefan Belopotocan, http://welcome.to/StefanBelopotocan
//
/////////////////////////////////////////////////////////////////////////////

#include "stdafx.h"
#include "InPlaceComboBoxImp.h"

#include "UserMessageID.h"

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

#define DEFAULT_IPLISTBOX_HEIGHT		16 * 8

/////////////////////////////////////////////////////////////////////////////
// CInPlaceCBEditImp

BOOL CInPlaceCBEditImp::PreTranslateMessage(MSG* pMsg) 
{
	if(pMsg->message == WM_KEYDOWN)
	{
		CWnd* pOwner = GetOwner();
		WPARAM nChar = pMsg->wParam;

		switch(nChar)
		{
			case VK_ESCAPE:
			case VK_RETURN:
			case VK_TAB:
				::PeekMessage(pMsg, NULL, NULL, NULL, PM_REMOVE);
				pOwner->GetParent()->SetFocus();
				return TRUE;
			case VK_UP:
			case VK_DOWN:
				pOwner->SendMessage(WM_USER_ON_NEW_SELECTION, nChar);
				return TRUE;
			default:
				;
		}
	}
	
	return CEdit::PreTranslateMessage(pMsg);
}

BEGIN_MESSAGE_MAP(CInPlaceCBEditImp, CEdit)
	//{{AFX_MSG_MAP(CInPlaceCBEditImp)
	ON_WM_ERASEBKGND()
	//}}AFX_MSG_MAP
END_MESSAGE_MAP()

/////////////////////////////////////////////////////////////////////////////
// CInPlaceCBEditImp message handlers

BOOL CInPlaceCBEditImp::OnEraseBkgnd(CDC* /*pDC*/)
{
	return TRUE;
}

/////////////////////////////////////////////////////////////////////////////
// CInPlaceCBListBoxImp

CInPlaceCBListBoxImp::CInPlaceCBListBoxImp()
{
}

CInPlaceCBListBoxImp::~CInPlaceCBListBoxImp()
{
}

BEGIN_MESSAGE_MAP(CInPlaceCBListBoxImp, CListBox)
	//{{AFX_MSG_MAP(CInPlaceCBListBoxImp)
	ON_WM_LBUTTONUP()
	//}}AFX_MSG_MAP
END_MESSAGE_MAP()

/////////////////////////////////////////////////////////////////////////////
// CInPlaceCBListBoxImp message handlers

void CInPlaceCBListBoxImp::ProcessSelected(bool bProcess)
{
	ReleaseCapture();

	CWnd* pOwner = GetOwner();

	if(bProcess)
	{
		int nSelectedItem = GetCurSel();
		pOwner->SendMessage(WM_USER_ON_SELECTION_OK, nSelectedItem, GetItemData(nSelectedItem));
	}
	else
		pOwner->SendMessage(WM_USER_ON_SELECTION_CANCEL);
}

void CInPlaceCBListBoxImp::OnLButtonUp(UINT nFlags, CPoint point) 
{
	CListBox::OnLButtonUp(nFlags, point);

	CRect rect;
	GetClientRect(rect);

	if(rect.PtInRect(point))
		ProcessSelected();
	//else
	//	ReleaseCapture();
}

BOOL CInPlaceCBListBoxImp::PreTranslateMessage(MSG* pMsg) 
{
	if(pMsg->message == WM_KEYDOWN)
	{
		switch(pMsg->wParam)
		{
			case VK_RETURN:
				ProcessSelected();
				return TRUE;
			case VK_ESCAPE:
			case VK_TAB:
				ProcessSelected(false);
				return TRUE;
			default:
				;
		}
	}

	return CListBox::PreTranslateMessage(pMsg);
}

#if 0
/////////////////////////////////////////////////////////////////////////////
// CInPlaceCBListCtrlImp

CInPlaceCBListCtrlImp::CInPlaceCBListCtrlImp()
{
}

CInPlaceCBListCtrlImp::~CInPlaceCBListCtrlImp()
{
}

int CInPlaceCBListCtrlImp::GetCount() const
{
	return GetItemCount();
}

void CInPlaceCBListCtrlImp::GetText(int nIndex, CString& strText) const
{
	strText = GetItemText(nIndex, 0);
}

int CInPlaceCBListCtrlImp::SetCurSel(int nSelect)
{	 
	return SetItemState(nSelect, LVIS_SELECTED | LVIS_FOCUSED, LVIS_SELECTED | LVIS_FOCUSED) ? 0 : LB_ERR;
}

int CInPlaceCBListCtrlImp::AddString(LPCTSTR pStrText)
{
	return InsertItem(GetItemCount(), pStrText);
}

void CInPlaceCBListCtrlImp::ResetContent()
{
	DeleteAllItems();
}

BEGIN_MESSAGE_MAP(CInPlaceCBListCtrlImp, CListCtrl)
	//{{AFX_MSG_MAP(CInPlaceCBListCtrlImp)
	ON_WM_KILLFOCUS()
	ON_WM_LBUTTONUP()
	//}}AFX_MSG_MAP
END_MESSAGE_MAP()

/////////////////////////////////////////////////////////////////////////////
// CInPlaceCBListCtrlImp message handlers

void CInPlaceCBListCtrlImp::OnKillFocus(CWnd* pNewWnd) 
{
	CListCtrl::OnKillFocus(pNewWnd);

	GetOwner()->SendMessage(WM_USER_ON_SELECTION_CANCEL);
}

void CInPlaceCBListCtrlImp::ProcessSelected()
{
	int nSelectedItem = GetNextItem(-1, LVNI_ALL | LVNI_SELECTED);

	GetOwner()->SendMessage(WM_USER_ON_SELECTION_OK, nSelectedItem, GetItemData(nSelectedItem));
}

void CInPlaceCBListCtrlImp::OnLButtonUp(UINT nFlags, CPoint point) 
{
	CListCtrl::OnLButtonUp(nFlags, point);

	ProcessSelected();
}

BOOL CInPlaceCBListCtrlImp::PreTranslateMessage(MSG* pMsg) 
{
	if(pMsg->message == WM_KEYDOWN)
	{
		if(pMsg->wParam == VK_RETURN)
		{
			ProcessSelected();
			return TRUE;
		}
	}

	return CListCtrl::PreTranslateMessage(pMsg);
}
#endif


/////////////////////////////////////////////////////////////////////////////
// CInPlaceComboBoxImp

int CInPlaceComboBoxImp::m_nButtonDx = ::GetSystemMetrics(SM_CXHSCROLL);

IMPLEMENT_DYNAMIC(CInPlaceComboBoxImp, CWnd)

CInPlaceComboBoxImp::CInPlaceComboBoxImp()
{
	m_nCurrentSelection = -1;
}

CInPlaceComboBoxImp* CInPlaceComboBoxImp::CreateInPlaceComboBox(CWnd* pWndParent, CRect& rect)
{	
	CInPlaceComboBoxImp* pInPlaceComboBox = (CInPlaceComboBoxImp*)new CInPlaceComboBoxImp;
	
	pInPlaceComboBox->Create(NULL, "", WS_VISIBLE|WS_CHILD, rect, pWndParent, 1);

	return pInPlaceComboBox;
}

BEGIN_MESSAGE_MAP(CInPlaceComboBoxImp, CWnd)
	//{{AFX_MSG_MAP(CInPlaceComboBoxImp)
	ON_WM_CREATE()
	ON_WM_SIZE()
	ON_WM_ERASEBKGND()
	ON_WM_PAINT()
	ON_WM_SETFOCUS()
	ON_WM_LBUTTONDOWN()
	ON_MESSAGE(WM_USER_ON_SELECTION_OK, OnSelectionOk)
	ON_MESSAGE(WM_USER_ON_SELECTION_CANCEL, OnSelectionCancel)
	ON_MESSAGE(WM_USER_ON_NEW_SELECTION, OnNewSelection)
	//}}AFX_MSG_MAP
END_MESSAGE_MAP()

/////////////////////////////////////////////////////////////////////////////
// CInPlaceComboBoxImp message handlers

int CInPlaceComboBoxImp::OnCreate(LPCREATESTRUCT lpCreateStruct) 
{
	if(CWnd::OnCreate(lpCreateStruct) == -1)
		return -1;
	
	CRect rect;
	GetClientRect(rect);
	rect.DeflateRect(0, 1);
	rect.right -= m_nButtonDx;

	CWnd* pParent = GetParent();
	ASSERT(pParent != NULL);

	CFont* pFont = pParent->GetFont();

	// Vstupn� riadok
	m_wndEdit.Create(WS_CHILD|WS_VISIBLE|ES_AUTOHSCROLL, rect, this, 2);
	m_wndEdit.SetOwner(this);
	m_wndEdit.SetFont(pFont);

	// Zoznam polo�iek
	rect.right += m_nButtonDx - 1;
	rect.top = rect.bottom + 2;
	rect.bottom += 100;

	ClientToScreen(rect);
	pParent = pParent->GetParent();
	pParent->ScreenToClient(rect);
		
	m_wndList.Create(WS_BORDER|WS_CHILD|WS_VSCROLL, rect, pParent, 3);
	m_wndList.SetOwner(this);
	m_wndList.SetFont(pFont);

	return 0;
}

void CInPlaceComboBoxImp::OnSize(UINT nType, int cx, int cy) 
{
	CWnd::OnSize(nType, cx, cy);
		
	m_wndEdit.SetWindowPos(NULL, 0, 0, cx - m_nButtonDx, cy, SWP_NOZORDER|SWP_NOMOVE);
}

void CInPlaceComboBoxImp::MoveControl(CRect& rect)
{
	CRect prevRect;
	GetClientRect(prevRect);

	CWnd* pParent = GetParent();

	// Prekresli predo�l� poz�ciu
	ClientToScreen(prevRect);
	pParent->ScreenToClient(prevRect);
	pParent->InvalidateRect(prevRect);

	// Nov� poz�cia
	MoveWindow(rect, FALSE);

	pParent->ClientToScreen(rect);
	pParent = pParent->GetParent();	
	pParent->ScreenToClient(rect);

	m_wndList.SetWindowPos(NULL, rect.left, rect.bottom + 1, 0, 0, SWP_NOZORDER|SWP_NOSIZE);
}

void CInPlaceComboBoxImp::ResetListBoxHeight()
{
	CRect rect;

	GetClientRect(rect);
	rect.right -= 1;

	int nItems = m_wndList.GetCount();
	int nListBoxHeight = nItems > 0 ? nItems * m_nButtonDx : DEFAULT_IPLISTBOX_HEIGHT;

	if(nListBoxHeight > DEFAULT_IPLISTBOX_HEIGHT)
		nListBoxHeight = DEFAULT_IPLISTBOX_HEIGHT;

	m_wndList.SetWindowPos(NULL, 0, 0, rect.Width(), nListBoxHeight, SWP_NOZORDER|SWP_NOMOVE);
}

void CInPlaceComboBoxImp::OnPaint() 
{
	CPaintDC dc(this);
	
	// Nakresli tla��tko
	CRect rect;

	GetClientRect(rect);
	rect.left = rect.right - m_nButtonDx;

#if 1
	dc.DrawFrameControl(rect, DFC_SCROLL, m_wndList.IsWindowVisible() ? 
		DFCS_SCROLLDOWN|DFCS_PUSHED : DFCS_SCROLLDOWN);
#else
	dc.DrawFrameControl(rect, DFC_SCROLL, m_wndList.IsWindowVisible() ? 
		DFCS_SCROLLDOWN|DFCS_PUSHED|DFCS_FLAT : DFCS_SCROLLDOWN|DFCS_FLAT);
#endif
}

BOOL CInPlaceComboBoxImp::OnEraseBkgnd(CDC* /*pDC*/)
{
	return TRUE;	
}

void CInPlaceComboBoxImp::OnLButtonDown(UINT nFlags, CPoint point)
{
	CWnd::OnLButtonDown(nFlags, point);

	CRect rect;
	GetClientRect(rect);

	CRect rectButton(rect);
	rectButton.left = rectButton.right - m_nButtonDx;

	if(rectButton.PtInRect(point))
	{
		int nDoAction = m_wndList.IsWindowVisible() ? SW_HIDE : SW_SHOW;

		m_wndList.ShowWindow(nDoAction);
		InvalidateRect(rectButton, FALSE);

		if(nDoAction == SW_SHOW)
		{
			m_wndList.SetFocus();
			m_wndList.SetCapture();
		}
	}
}

void CInPlaceComboBoxImp::OnSetFocus(CWnd* pOldWnd) 
{
	CWnd::OnSetFocus(pOldWnd);
	
	m_wndEdit.SetFocus();
}

void CInPlaceComboBoxImp::HideListBox()
{
	m_wndList.ShowWindow(SW_HIDE);

	CRect rectButton;

	GetClientRect(rectButton);
	rectButton.left = rectButton.right - m_nButtonDx;

	InvalidateRect(rectButton, FALSE);

	m_wndEdit.SetFocus();
}

LRESULT CInPlaceComboBoxImp::OnSelectionOk(WPARAM wParam, LPARAM /*lParam*/)
{
	HideListBox();

	SetCurSelToEdit(m_nCurrentSelection = int(wParam));

	GetOwner()->SendMessage(WM_USER_SET_DATA);

	return TRUE;
}

LRESULT CInPlaceComboBoxImp::OnSelectionCancel(WPARAM /*wParam*/, LPARAM /*lParam*/)
{
	HideListBox();

	return TRUE;
}

LRESULT CInPlaceComboBoxImp::OnNewSelection(WPARAM wParam, LPARAM /*lParam*/)
{
	int nItems = m_wndList.GetCount();

	if(nItems > 0)
	{
		if(wParam == VK_UP)
		{
			if(m_nCurrentSelection > 0)
				SetCurSel(m_nCurrentSelection - 1);
		}
		else
		{
			if(m_nCurrentSelection < nItems - 1)
				SetCurSel(m_nCurrentSelection + 1);
		}
	}

	return TRUE;
}

void CInPlaceComboBoxImp::SetCurSelToEdit(int nSelect)
{
	CString strText;

	if(nSelect != -1)
		m_wndList.GetText(nSelect, strText);
		
	m_wndEdit.SetWindowText(strText);
	m_wndEdit.SetSel(0, -1); 
}

int CInPlaceComboBoxImp::SetCurSel(int nSelect, bool bSendSetData)
{
	if(nSelect >= m_wndList.GetCount())
		return CB_ERR;


	int nRet = m_wndList.SetCurSel(nSelect);

	if(nRet != -1)
	{
		SetCurSelToEdit(nSelect);
		m_nCurrentSelection = nSelect;

		if(bSendSetData)
			GetOwner()->SendMessage(WM_USER_SET_DATA);
	}

	return nRet;
}

CString CInPlaceComboBoxImp::GetTextData() const
{
	CString strText;

	if(m_nCurrentSelection != -1)
		m_wndList.GetText(m_nCurrentSelection, strText);

	return strText;
}

int CInPlaceComboBoxImp::AddString(LPCTSTR pStrText, DWORD nData)
{
	int nIndex = m_wndList.AddString(pStrText);

	return m_wndList.SetItemData(nIndex, nData);
}

void CInPlaceComboBoxImp::ResetContent()
{
	m_wndList.ResetContent();

	m_nCurrentSelection = -1;
}

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

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

License

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

A list of licenses authors might use can be found here


Written By
Software Developer (Senior)
Slovakia Slovakia
This member has not yet provided a Biography. Assume it's interesting and varied, and probably something to do with programming.

Comments and Discussions