Click here to Skip to main content
15,886,199 members
Articles / Desktop Programming / MFC

An MFC-CListCtrl derived class that allows other ‘controls’ to be inserted into a particular cell

Rate me:
Please Sign up or sign in to vote.
4.92/5 (54 votes)
5 Jan 2014CPOL12 min read 167.5K   13.9K   160  
A class derived from CListCtrl that allows edit controls, combo boxes, check boxes, date pickers, and color pickers to be inserted into or removed from particular cells extremely easily. The inserted 'controls' are not CWnd-derived.
#include "stdafx.h"
#include "..\resource.h"
#include "CellCheckBox.h"
#include "..\utilities.h"

#define IMAGE_SIZE			20
#define BOX_SEP				3

CImageList CCellCheckBox::m_CheckBoxImageList;
DWORD CCellCheckBox::m_dwCheckBoxStyle = 0;

//////////////////////////////////////////////////////////////////////
// Construction/Destruction
//////////////////////////////////////////////////////////////////////

CCellCheckBox::CCellCheckBox() : CCellButton()
{
	m_dwStyle = CLCS_ALIGN_CENTER;
	::ZeroMemory(&m_rcArea, sizeof(RECT)); 
}

CCellCheckBox::~CCellCheckBox()
{
}

void CCellCheckBox::InitImageList()
{
	if (!m_CheckBoxImageList.m_hImageList)
	{
		m_CheckBoxImageList.Create(IDB_CHECKBOX, IMAGE_SIZE, IMAGE_SIZE, RGB(0xFF, 0x00, 0xFF));
	}
}

void CCellCheckBox::Initialize(HWND hParentWnd, BOOL *pParentEnabled, LPCTSTR strText)
{
	CCellCtrl::Initialize(hParentWnd, pParentEnabled, strText);

	if (m_strText[0] != _T('0') && m_strText[0] != _T('1'))
		m_strText = _T("0") + m_strText; // Assume user meant it unchecked if forgot to specify.

	InitImageList();
}

CString CCellCheckBox::GetDisplayedText()
{
	LPCTSTR strText = m_strText;
	return ++strText;
}

BOOL CCellCheckBox::IsChecked()
{
	return (m_strText[0] == _T('1')); 
}

void CCellCheckBox::SetIsChecked(BOOL bChecked)
{
	m_strText.SetAt(0, (bChecked)? _T('1') : _T('0'));
}

void CCellCheckBox::DrawCtrl(CDC *pDC, const LPRECT prcCell, UINT uiItemState /*= 0*/)
{
	POINT							ptCheckBox;
	CBrush							Brush;
	CSize							szSize;
	RECT							rcText;
	int								iSavedDC;

	iSavedDC = pDC->SaveDC();
	::ZeroMemory(&m_rcClickRect, sizeof(RECT)); // or use SetRectEmpty

	CopyRect(&m_rcArea, prcCell);
			
	if (IsDisabled())
	{
		Brush.CreateSolidBrush(GetSysColor(COLOR_BTNFACE));
		pDC->SetTextColor(GetSysColor(COLOR_GRAYTEXT)); // or COLOR_INACTIVECAPTION. Seems same
	}
	else if (uiItemState & (ODS_FOCUS | ODS_SELECTED))
	{
		Brush.CreateSolidBrush(GetSysColor(COLOR_HIGHLIGHT));
		pDC->SetTextColor(GetSysColor(COLOR_HIGHLIGHTTEXT));
	}
	else
	{
		Brush.CreateSolidBrush(GetSysColor(COLOR_WINDOW));
		pDC->SetTextColor(GetSysColor(COLOR_WINDOWTEXT));
	}
	pDC->FillRect(prcCell, &Brush);

	SelectFont(pDC);

	szSize = pDC->GetTextExtent(GetDisplayedText());
	CopyRect(&rcText, prcCell);

	HTHEME hTheme = OpenThemeData(m_hParentWnd, _T("Button"));

	if (!hTheme)
	{
		szSize.cx += IMAGE_SIZE;	// Have to add the image list width.

		if (szSize.cx > prcCell->right - prcCell->left)
		{
			ptCheckBox.x = prcCell->left;
			rcText.left += IMAGE_SIZE;		
		}
		else
		{
			if (m_dwStyle & CLCS_ALIGN_CENTER)
			{
				ptCheckBox.x = prcCell->left + (prcCell->right - prcCell->left - szSize.cx)/2;
				rcText.left = ptCheckBox.x + IMAGE_SIZE;
				rcText.right = ptCheckBox.x + szSize.cx + 1; // For some reason, have to add 1 for when you have bold, otherwise, displays ellipsis instead 
			}
			else if (m_dwStyle & CLCS_ALIGN_RIGHT)
			{
				if (szSize.cy)
				{
					rcText.right = prcCell->right;
					rcText.left = rcText.right - (szSize.cx + 1);
					ptCheckBox.x = rcText.left - IMAGE_SIZE;
				}
				else
				{
					rcText.right = rcText.left = 0;
					ptCheckBox.x = prcCell->right - IMAGE_SIZE;
				}
			}
			else
			{
				ptCheckBox.x = prcCell->left;
				rcText.left = ptCheckBox.x + IMAGE_SIZE;
				rcText.right = ptCheckBox.x + szSize.cx + 1;
			}
		}
		ptCheckBox.y = prcCell->top;

		if (prcCell->right - prcCell->left >= IMAGE_SIZE)
		{
			int ImageIdx = (IsChecked())? 1:0;
			if (IsDisabled())
				ImageIdx += 2;

			m_CheckBoxImageList.Draw(pDC, ImageIdx, ptCheckBox, ILD_NORMAL);
			
			pDC->DrawText(GetDisplayedText(), &rcText, DT_CENTER | DT_BOTTOM | DT_END_ELLIPSIS);

			m_rcClickRect.left = ptCheckBox.x;
			m_rcClickRect.top = ptCheckBox.y;
			m_rcClickRect.right = ptCheckBox.x + IMAGE_SIZE; 
			m_rcClickRect.bottom = ptCheckBox.y + IMAGE_SIZE;
		}
		else
		{
			rcText.left -= IMAGE_SIZE;
			pDC->DrawText(GetDisplayedText(), &rcText, DT_CENTER | DT_BOTTOM | DT_END_ELLIPSIS);
		}
	}
	else
	{
		int				StateId;
		HRESULT			hRes = 0;
		SIZE			sz;

		if (IsChecked())
			StateId = GetThemeButtonStateId(m_bActive, CBS_CHECKEDNORMAL, CBS_CHECKEDHOT, CBS_CHECKEDPRESSED, CBS_CHECKEDDISABLED);
		else
			StateId = GetThemeButtonStateId(m_bActive, CBS_UNCHECKEDNORMAL, CBS_UNCHECKEDHOT, CBS_UNCHECKEDPRESSED, CBS_UNCHECKEDDISABLED);

		hRes = GetThemePartSize(hTheme, pDC->m_hDC, BP_CHECKBOX, StateId, prcCell, TS_DRAW, &sz);

		szSize.cx += sz.cx + BOX_SEP;	// Have to add the image list width.

		if (szSize.cx > prcCell->right - prcCell->left)
		{
			m_rcClickRect.left = prcCell->left;
			m_rcClickRect.right = prcCell->left + sz.cx;
			rcText.left += sz.cx + BOX_SEP;		
		}
		else
		{
			if (m_dwStyle & CLCS_ALIGN_CENTER)
			{
				m_rcClickRect.left = prcCell->left + (prcCell->right - prcCell->left - szSize.cx)/2;
				m_rcClickRect.right = prcCell->left + (prcCell->right - prcCell->left - szSize.cx)/2 + sz.cx;
			
				rcText.left = m_rcClickRect.left + sz.cx + BOX_SEP;
				rcText.right = m_rcClickRect.left + szSize.cx;
			}
			else if (m_dwStyle & CLCS_ALIGN_RIGHT)
			{
				if (szSize.cy)
				{
					rcText.right = prcCell->right;
					rcText.left = rcText.right - szSize.cx;
					m_rcClickRect.right = rcText.left - BOX_SEP;
				}
				else
				{
					rcText.right = rcText.left = 0;
					m_rcClickRect.right = prcCell->right;
				}
				m_rcClickRect.left = m_rcClickRect.right - sz.cx;
			}
			else
			{
				m_rcClickRect.left = prcCell->left;
				m_rcClickRect.right = prcCell->left + sz.cx;
				rcText.left = m_rcClickRect.left + sz.cx + BOX_SEP;
				rcText.right = m_rcClickRect.left + szSize.cx;
			}
		}
		m_rcClickRect.top = prcCell->top + (prcCell->bottom - prcCell->top - sz.cy)/2;
		m_rcClickRect.bottom = prcCell->top + (prcCell->bottom - prcCell->top - sz.cy)/2 + sz.cy;
		rcText.top = prcCell->top + (prcCell->bottom - prcCell->top - szSize.cy)/2;
		rcText.bottom = prcCell->top + (prcCell->bottom - prcCell->top - sz.cy)/2 + szSize.cy;

		hRes = DrawThemeBackground(hTheme, pDC->m_hDC, BP_CHECKBOX, StateId, &m_rcClickRect, NULL);
		
		pDC->DrawText(GetDisplayedText(), &rcText, DT_CENTER | DT_BOTTOM | DT_END_ELLIPSIS);

		CloseThemeData(hTheme);
	}
	Brush.DeleteObject();
	pDC->RestoreDC(iSavedDC);
}

BOOL CCellCheckBox::OnPressButton(UINT nFlags, CPoint point)
{
	SetIsChecked(!IsChecked());
	return TRUE;
}

void CCellCheckBox::OnEnter()
{
	if (m_bActive)
	{
		SetIsChecked(!IsChecked());
		GetWindowFromHandle()->InvalidateRect(&m_rcClickRect, FALSE);
	}
}

int CCellCheckBox::GetMinWidth()
{
	CDC *pDC;
	int iMinWidth = 0;
	CSize szSize;
	CString strText = GetDisplayedText() + _T("i"); 

	pDC = GetWindowFromHandle()->GetDC();

	SelectFont(pDC);

	if (m_strText != _T(""))
	{
		szSize = pDC->GetTextExtent(strText);
		iMinWidth = szSize.cx;
	}
	iMinWidth += IMAGE_SIZE;
	return iMinWidth;
}

const RECT &CCellCheckBox::GetTextRect() const
{
	return m_rcClickRect;
}

void CCellCheckBox::AddToCtrlTypeStyle(DWORD dwFlags)
{
	m_dwCheckBoxStyle |= dwFlags;
}

void CCellCheckBox::RemoveFromCtrlTypeStyle(DWORD dwFlags)
{
	m_dwCheckBoxStyle &= ~dwFlags;
}

LONG CCellCheckBox::GetStyle()
{
	return m_dwCheckBoxStyle | m_dwStyle;
}

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
United Kingdom United Kingdom
This member has not yet provided a Biography. Assume it's interesting and varied, and probably something to do with programming.

Comments and Discussions