Click here to Skip to main content
15,885,366 members
Articles / Desktop Programming / WTL

ListCtrl - A WTL list control with Windows Vista style item selection

Rate me:
Please Sign up or sign in to vote.
4.91/5 (107 votes)
18 Apr 2006CPOL9 min read 516.1K   11.7K   259  
A flexible WTL list control that supports Windows Vista style selection and cell editing.
#pragma once

#include "ListTypes.h"

#define DATE_STRING					32

class CListDate : public CWindowImpl< CListDate, CDateTimePickerCtrl >
{
public:
	CListDate()
	{
		m_nItem = NULL_ITEM;
		m_nSubItem = NULL_SUBITEM;
		m_nFlags = ITEM_FLAGS_NONE;
		m_nExitChar = 0;
	}
	
	~CListDate()
	{
	}

protected:
	int m_nItem;
	int m_nSubItem;
	UINT m_nFlags;
	TCHAR m_nExitChar;
	CFont m_fntDateFont;
	
public:
	BOOL Create( HWND hWndParent, int nItem, int nSubItem, CRect& rcRect, UINT nFlags, SYSTEMTIME& stItemDate )
	{
		m_nItem = nItem;
		m_nSubItem = nSubItem;
		m_nFlags = nFlags;
		m_nExitChar = 0;
		
		// destroy old date control...
		if ( IsWindow() )
			DestroyWindow();
			
		DWORD dwStyle = WS_CHILD | WS_CLIPCHILDREN;
		
		if ( nFlags & ITEM_FLAGS_DATETIME_NONE )
			dwStyle |= DTS_SHOWNONE;
		
		if ( nFlags & ITEM_FLAGS_TIME_ONLY )
			dwStyle |= DTS_UPDOWN;
		
		// create date-time control
		if ( CWindowImpl< CListDate, CDateTimePickerCtrl >::Create( hWndParent, CRect( rcRect.left + 3, rcRect.top + 2, rcRect.right - 3, rcRect.bottom - 2 ), NULL, dwStyle ) == NULL )
			return FALSE;
		
		// remove border
		ModifyStyleEx( WS_EX_CLIENTEDGE, 0, SWP_FRAMECHANGED );
		
		// get system message font
		CLogFont logFont;
		logFont.SetMessageBoxFont();
		if ( !m_fntDateFont.IsNull() )
			m_fntDateFont.DeleteObject();
		if ( m_fntDateFont.CreateFontIndirect( &logFont ) == NULL )
			return FALSE;
		SetMonthCalFont( m_fntDateFont );
		SetFont( m_fntDateFont );
		
		TCHAR szDateFormat[ DATE_STRING ];
		GetLocaleInfo( LOCALE_USER_DEFAULT, LOCALE_SSHORTDATE, szDateFormat, DATE_STRING );
		
		TCHAR szTimeFormat[ DATE_STRING ];
		GetLocaleInfo( LOCALE_USER_DEFAULT, LOCALE_STIMEFORMAT, szTimeFormat, DATE_STRING );
		
		if ( nFlags & ITEM_FLAGS_DATE_ONLY )
			SetFormat( szDateFormat );
		else if ( nFlags & ITEM_FLAGS_TIME_ONLY )
			SetFormat( szTimeFormat );
		else
			SetFormat( CString( szDateFormat ) + _T( " " ) + CString( szTimeFormat ) );
		
		// get current date if setting time-only
		if ( nFlags & ITEM_FLAGS_TIME_ONLY )
		{
			SYSTEMTIME stCurrentDate;
			if ( GetSystemTime( &stCurrentDate ) == GDT_VALID )
			{
				stItemDate.wYear = stCurrentDate.wYear;
				stItemDate.wMonth = stCurrentDate.wMonth;
				stItemDate.wDay = stCurrentDate.wDay;
			}
		}
		
		SetSystemTime( ( !( nFlags & ITEM_FLAGS_TIME_ONLY ) && stItemDate.wYear == 0 ) ? GDT_NONE : GDT_VALID, &stItemDate );
		
		// show date-time control
		ShowWindow( SW_SHOW );
		
		SetFocus();
		
		return TRUE;
	}
		
	BEGIN_MSG_MAP_EX(CListDate)
		MSG_WM_KILLFOCUS(OnKillFocus)
		REFLECTED_NOTIFY_CODE_HANDLER_EX(DTN_CLOSEUP, OnCloseUp)
		MSG_WM_GETDLGCODE(OnGetDlgCode)
		MSG_WM_CHAR(OnChar)
		DEFAULT_REFLECTION_HANDLER()
	END_MSG_MAP_EX()
	
	void OnKillFocus( HWND hNewWnd )
	{
		// have we dropped down the calendar control?
		if ( hNewWnd != NULL && GetMonthCal() == hNewWnd )
			return;
		
		// have we selected a new date from the calendar control?
		if ( GetFocus() == m_hWnd )
			return;
		
		// hide calendar control in case it's not closed by losing focus
		if ( GetMonthCal().IsWindow() )
			GetMonthCal().ShowWindow( SW_HIDE );
		
		CWindow wndParent( GetParent() );
		if ( wndParent.IsWindow() )
		{
			SYSTEMTIME stItemDate;
			BOOL bValidDate = ( GetSystemTime( &stItemDate ) == GDT_VALID );
			if ( !bValidDate )
				ZeroMemory( &stItemDate, sizeof( SYSTEMTIME ) );
			
			if ( m_nFlags & ITEM_FLAGS_DATE_ONLY )
			{
				stItemDate.wHour = 0;
				stItemDate.wMinute = 0;
				stItemDate.wSecond = 0;
				stItemDate.wMilliseconds = 0;
			}
			
			if ( m_nFlags & ITEM_FLAGS_TIME_ONLY )
			{
				stItemDate.wYear = 0;
				stItemDate.wMonth = 0;
				stItemDate.wDay = 0;
				stItemDate.wDayOfWeek = 0;				
			}
				
			CListNotify listNotify;
			listNotify.m_hdrNotify.hwndFrom = m_hWnd;
			listNotify.m_hdrNotify.idFrom = GetDlgCtrlID();
			listNotify.m_hdrNotify.code = LCN_ENDEDIT;
			listNotify.m_nItem = m_nItem;
			listNotify.m_nSubItem = m_nSubItem;
			listNotify.m_nExitChar = m_nExitChar;
			listNotify.m_lpszItemText = bValidDate ? _T( "1" ) : _T( "0" );
			listNotify.m_lpItemDate = &stItemDate;

			// forward notification to parent
			FORWARD_WM_NOTIFY( wndParent, listNotify.m_hdrNotify.idFrom, &listNotify.m_hdrNotify, ::SendMessage );
		}
		
		ShowWindow( SW_HIDE );
	}
	
	LRESULT OnCloseUp( LPNMHDR lpNMHDR )
	{
		SetMsgHandled( FALSE );
		SetFocus();
		return TRUE;
	}
	
	UINT OnGetDlgCode( LPMSG lpMessage )
	{
		return DLGC_WANTALLKEYS;
	}
	
	void OnChar( TCHAR nChar, UINT nRepCnt, UINT nFlags )
	{
		switch ( nChar )
		{
			case VK_TAB:
			case VK_RETURN:
			case VK_ESCAPE:	{
								m_nExitChar = nChar;
								CWindow wndParent( GetParent() );
								if ( wndParent.IsWindow() )
									wndParent.SetFocus();
							}
							break;
			default:		SetMsgHandled( FALSE );
							break;
		}
	}
};

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
Alan has been developing applications for a very long time (~10 years), but he's not bitter about this at all. My main area of expertise is C++. He lives in Sweden with his beautiful wife, daughter and son and enjoys climbing mountains and kayaking in his spare time (which isn't much).

Comments and Discussions