Click here to Skip to main content
11,645,087 members (66,027 online)
Click here to Skip to main content
Add your own
alternative version

Internet Explorer AdBlock

, 17 Jan 2008 GPL3 39.5K 1.8K 41
Internet Explorer AdBlock Add-on
ieadblock_src.zip
IE AdBlockPS
IE AdBlockps.def
IE AdBlock
AdBlockBand.rgs
AdBlockBHO.rgs
bin
XListCtrlSSDU.lib
XListCtrlSSRU.lib
IE AdBlock.def
IE AdBlock.rgs
res
bmpToolbar.bmp
checkboxes.bmp
icoSettings.ico
XListCtrl
checkboxes.bmp
/////////////////////////////////////////////////////////////////////////////
// AdvComboBox.cpp : implementation file
// 
// CAdvComboBox Control
// Version: 2.1
// Date: September 2002
// Author: Mathias Tunared
// Email: Mathias@inorbit.com
// Copyright (c) 2002. All Rights Reserved.
//
// This code, in compiled form or as source code, may be redistributed 
// unmodified PROVIDING it is not sold for profit without the authors 
// written consent, and providing that this notice and the authors name 
// and all copyright notices remains intact.
//
// This file is provided "as is" with no expressed or implied warranty.
// The author accepts no liability for any damage/loss of business that
// this product may cause.
//
/////////////////////////////////////////////////////////////////////////////

#include "stdafx.h"
#include "AdvComboBox.h"
#include "VisualStylesXP.h"

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

#define IDC_COMBOEDIT 108


/////////////////////////////////////////////////////////////////////////////
// CAdvComboBox
IMPLEMENT_DYNAMIC(CAdvComboBox, CWnd) 

CAdvComboBox::CAdvComboBox( BOOL bInst, CWnd * pParent ) :
	m_pDropWnd(0),
	m_bDropListVisible(0),
	m_bInst( bInst ),
	m_pParent(pParent)
{
	XLISTCTRL_TRACE(_T("in CAdvComboBox::CAdvComboBox\n"));
	RegisterWindowClass();
	m_pEdit = NULL;
	m_zDelta = 0;
	m_nCurSel = -1;
	m_bDropRectStored= false;
	m_bHasFocus = false;
	m_bHasSentFocus = false;
	m_bSelItem = false;
	m_bFirstPaint = true;
	m_nMinVisItems = 5;
	m_bCodeCreate = false;
	m_bAutoAppend = TRUE;
	m_bDropButtonHot = false;
	m_bTrackMouseLeave = false;
	m_nDefaultDropItems = -1;

	m_dwACBStyle = 0;
	m_dwACBStyle |= ACBS_STANDARD;

	m_pFont = NULL;
}

CAdvComboBox::~CAdvComboBox()
{
	XLISTCTRL_TRACE(_T("in CAdvComboBox::~CAdvComboBox\n"));

	delete m_pFont;
	if( m_pDropWnd )
	{
		m_pDropWnd->ShowWindow( SW_HIDE );
		m_bDropListVisible = FALSE;
		m_pDropWnd->DestroyWindow();
		delete m_pDropWnd;
		m_pDropWnd = NULL;
	}
	if( m_pEdit )
	{
		m_pEdit->DestroyWindow();
		delete m_pEdit;
	}
}

BEGIN_MESSAGE_MAP(CAdvComboBox, CWnd)
	//{{AFX_MSG_MAP(CAdvComboBox)
	ON_WM_CREATE()
	ON_WM_PAINT()
	ON_WM_ERASEBKGND()
	ON_WM_LBUTTONDOWN()
	ON_WM_MOUSEWHEEL()
	ON_WM_SIZE()
	ON_WM_SETFOCUS()
	ON_WM_KILLFOCUS()
	ON_WM_SHOWWINDOW()
	ON_WM_ENABLE()
	ON_WM_CHILDACTIVATE()
	ON_WM_MOUSEMOVE()
	ON_WM_TIMER()
	ON_WM_CHAR()
	ON_WM_KEYDOWN()
	//ON_WM_ACTIVATEAPP()
	//}}AFX_MSG_MAP
	ON_MESSAGE( WM_SELECTED_ITEM, OnSelectedItem )
	ON_MESSAGE( WM_ON_DROPDOWN_BUTTON, OnDropdownButton )
	ON_MESSAGE( WM_DESTROY_DROPLIST, OnDestroyDropdownList )
	ON_EN_KILLFOCUS(IDC_COMBOEDIT, OnKillfocusEdit)
	ON_EN_SETFOCUS(IDC_COMBOEDIT, OnSetfocusEdit)
	ON_EN_CHANGE(IDC_COMBOEDIT, OnChangeEdit)
	ON_EN_UPDATE(IDC_COMBOEDIT, OnUpdateEdit)

	ON_MESSAGE( CB_ADDSTRING, OnAddString )
	ON_MESSAGE( CB_SETCURSEL, OnSetCurSel )
	ON_MESSAGE( CB_GETCURSEL, OnGetCurSel )
	ON_MESSAGE( CB_SELECTSTRING, OnSelectString )
	ON_MESSAGE( CB_GETCOUNT, OnGetCount )
	ON_MESSAGE( CB_RESETCONTENT, OnResetContent )
	ON_MESSAGE( CB_GETLBTEXT, OnGetLBText )
	ON_MESSAGE( CB_GETLBTEXTLEN, OnGetLBTextLen )
	ON_MESSAGE( CB_GETTOPINDEX, OnGetTopIndex )
	ON_MESSAGE( CB_SETTOPINDEX, OnSetTopIndex )

END_MESSAGE_MAP()


/////////////////////////////////////////////////////////////////////////////
// CAdvComboBox message handlers

LONG CAdvComboBox::OnAddString( WPARAM /*wParam*/, LPARAM lString )
{
	TCHAR* pStr = (TCHAR*)lString;
	return AddString( pStr );
}

LONG CAdvComboBox::OnSetCurSel( WPARAM wIndex, LPARAM /*lParam*/ )
{
	int nIndex = (int)wIndex;
	return SetCurSel( nIndex );
}

LONG CAdvComboBox::OnGetCurSel( WPARAM /*wParam*/, LPARAM /*lParam*/ )
{
	return GetCurSel();
}

LONG CAdvComboBox::OnSelectString( WPARAM wItemStart, LPARAM lString )
{
	int nItem = (int)wItemStart;
	TCHAR* pStr = (TCHAR*)lString;
	int nIndex = FindStringExact( nItem, pStr );
	return SetCurSel( nIndex );
}

LONG CAdvComboBox::OnGetCount( WPARAM /*wParam*/, LPARAM /*lParam*/ )
{
	return GetCount();
}

LONG CAdvComboBox::OnResetContent( WPARAM /*wParam*/, LPARAM /*lParam*/ )
{
	m_list.clear();
	m_strEdit = _T("");
	m_nCurSel = -1;
	SetWindowText( _T("") );
	if( m_pEdit )
	{
		m_pEdit->SetWindowText( _T("") );
	}
	Invalidate();
	return CB_OKAY;
}

LONG CAdvComboBox::OnGetLBText( WPARAM wIndex, LPARAM lString )
{
	int nIndex = (int)wIndex;
	TCHAR* pOutStr = (TCHAR*)lString;
	return GetLBText( nIndex, pOutStr );
}


LONG CAdvComboBox::OnGetLBTextLen( WPARAM wIndex, LPARAM /*lParam*/ )
{
	int nIndex = (int)wIndex;
	return GetLBTextLen( nIndex );
}

LONG CAdvComboBox::OnGetTopIndex( WPARAM /*wParam*/, LPARAM /*lParam*/ )
{
	return GetTopIndex();
}

LONG CAdvComboBox::OnSetTopIndex( WPARAM wIndex, LPARAM /*lParam*/ )
{
	return SetTopIndex(wIndex);
}

BOOL CAdvComboBox::RegisterWindowClass()
{
	WNDCLASS wndcls;
	HINSTANCE hInst;
	hInst = AfxGetInstanceHandle();

	ASSERT( hInst != 0 );

    if( !(::GetClassInfo(hInst, ADVCOMBOBOXCTRL_CLASSNAME, &wndcls)) )
    {
        wndcls.style            = CS_DBLCLKS | CS_HREDRAW | CS_VREDRAW;
        wndcls.lpfnWndProc      = ::DefWindowProc;
        wndcls.cbClsExtra       = 0;
		wndcls.cbWndExtra		= 0;
        wndcls.hInstance        = hInst;
        wndcls.hIcon            = NULL;
        wndcls.hCursor          = AfxGetApp()->LoadStandardCursor(IDC_ARROW);
        wndcls.hbrBackground    = (HBRUSH) (COLOR_WINDOW);
        wndcls.lpszMenuName     = NULL;
        wndcls.lpszClassName    = ADVCOMBOBOXCTRL_CLASSNAME;

        if( !AfxRegisterClass(&wndcls) )
        {
            AfxThrowResourceException();
            return FALSE;
        }
    }
    return TRUE;
}

BOOL CAdvComboBox::Create( DWORD dwStyle, const RECT& rect, CWnd* pParentWnd, UINT nID )
{
	XLISTCTRL_TRACE(_T("in CAdvComboBox::Create\n"));
	m_rcCombo = rect;
	m_bCodeCreate = true;

	m_dwACBStyle |= ACBS_STANDARD;
	m_dwStyle = dwStyle;

	LoadString( nID );
	
	BOOL bRet = CWnd::Create(NULL, _T(""), dwStyle, m_rcCombo, pParentWnd, nID );

	return bRet;
}

void CAdvComboBox::LoadString( UINT nStringID )
{
	UINT nIDS;
	if( nStringID )
		nIDS = nStringID;
	else
	{
		nIDS = GetWindowLong( GetSafeHwnd(), GWL_ID );
	}

	//
	// Load string from resources
	CString strItems;
	if( !strItems.LoadString( nIDS ) )
	{
		return;
	}

	//
	// Clear the list
	m_list.clear();

	//
	// Go through the string and look after '\n'.
	TCHAR seps[] = _T("\n");
	TCHAR *token;
	int nLen = strItems.GetLength();
	TCHAR* szTok = new TCHAR[nLen+5];
	memset( szTok, 0, (nLen+5)*sizeof(TCHAR) );
	_tcscpy( szTok, (LPCTSTR)strItems );

	token = _tcstok( szTok, seps );
	while( token != NULL )
	{
		AddString( token );
		token = _tcstok( NULL, seps );
	}

	//
	// Add item to list

	//+++
	delete [] szTok;
}

int CAdvComboBox::OnCreate(LPCREATESTRUCT lpCreateStruct) 
{
	XLISTCTRL_TRACE(_T("in CAdvComboBox::OnCreate\n"));

	if (CWnd::OnCreate(lpCreateStruct) == -1)
		return -1;
	
	if( !m_pFont )
	{
		LOGFONT logFont;
		memset( &logFont, 0, sizeof(LOGFONT) );
		CFont* pF = m_pParent->GetFont();
		ASSERT(pF);
		pF->GetLogFont( &logFont );
		m_pFont = new CFont;
		m_pFont->CreateFontIndirect(&logFont);
		SetFont( m_pFont );
	}

	return 0;
}

void CAdvComboBox::PreSubclassWindow() 
{
	XLISTCTRL_TRACE(_T("in CAdvComboBox::PreSubclassWindow\n"));

	if (m_pParent == NULL)
		m_pParent = GetParent();
	ASSERT(m_pParent);

	// TODO: Add your specialized code here and/or call the base class
	LoadString();

	if( !m_pFont )
	{
		LOGFONT logFont;
		memset( &logFont, 0, sizeof(LOGFONT) );
		CFont* pF = m_pParent->GetFont();
		ASSERT(pF);
		pF->GetLogFont( &logFont );
		m_pFont = new CFont;
		m_pFont->CreateFontIndirect(&logFont);
		SetFont( m_pFont );
	}

	if( !m_bCodeCreate )
	{
		//
		// Do we need to show an edit control. (CBS_DROPDOWN)
		if( (GetStyle() & CBS_DROPDOWN) && !(GetStyle() & CBS_SIMPLE) )	// == CBS_DROPDOWN
		{
			if( !m_pEdit )
			{
				CRect rect;
				GetClientRect(rect);
				rect.right = rect.right - ::GetSystemMetrics(SM_CXHSCROLL);
				if( m_dwACBStyle & ACBS_STANDARD )
				{
					rect.DeflateRect( 2, 2 );
					rect.left += 1;
					rect.top += 2;
					//rect.bottom += 2;
				}

				XLISTCTRL_TRACE(_T("creating edit\n"));
				m_pEdit = new CAdvComboEdit;	//+++
				ASSERT(m_pEdit);
				DWORD dwStyle = 0;
				dwStyle = WS_VISIBLE | WS_CHILD;
				if( GetStyle() & CBS_AUTOHSCROLL )
				{
					dwStyle |= ES_AUTOHSCROLL;
				}
				VERIFY(m_pEdit->Create( dwStyle, rect, this, IDC_COMBOEDIT ));
				m_pEdit->SetFont( m_pFont );
				m_pEdit->SetWindowText( m_strEdit.c_str() );
			}
		}
	}
	CWnd::PreSubclassWindow();
}

void CAdvComboBox::OnChildActivate() 
{
	CWnd::OnChildActivate();
	
	// TODO: Add your message handler code here
	if( !m_pFont )
	{
		LOGFONT logFont;
		memset( &logFont, 0, sizeof(LOGFONT) );
		CFont* pF = m_pParent->GetFont();
		pF->GetLogFont( &logFont );
		m_pFont = new CFont;
		m_pFont->CreateFontIndirect(&logFont);
		SetFont( m_pFont );
	}
	if( m_bCodeCreate )
	{
		//
		// Do we need to show an edit control. (CBS_DROPDOWN)
		if( (GetStyle() & CBS_DROPDOWN) && !(GetStyle() & CBS_SIMPLE) )	// == CBS_DROPDOWN
		{
			if( !m_pEdit )
			{
				CRect rect;
				GetClientRect(rect);
				rect.right = rect.right - ::GetSystemMetrics(SM_CXHSCROLL);
				if( m_dwACBStyle & ACBS_STANDARD )
				{
					rect.DeflateRect( 2, 2 );
					rect.left += 1;
					rect.top += 2;
					//rect.bottom += 2;
				}

				m_pEdit = new CAdvComboEdit;	//+++
				DWORD dwStyle = 0;
				dwStyle = WS_VISIBLE | WS_CHILD;
				if( GetStyle() & CBS_AUTOHSCROLL )
				{
					dwStyle |= ES_AUTOHSCROLL;
				}
				m_pEdit->Create( dwStyle, rect, this, IDC_COMBOEDIT );
				m_pEdit->SetFont( m_pFont );
				m_pEdit->SetWindowText( m_strEdit.c_str() );
			}
		}
	}
}

void CAdvComboBox::OnPaint() 
{
	CPaintDC dc(this); // device context for painting

	if( m_nCurSel != -1 )
	{
		m_iter = m_list.begin();
		advance( m_iter, m_nCurSel );
		if( m_iter != m_list.end() )
		{
			m_strEdit = m_iter->strText;
		}
		if( m_bFirstPaint )
		{
			if( m_pEdit )
			{
				m_pEdit->SetWindowText( m_strEdit.c_str() );
				m_bFirstPaint = false;
				m_pEdit->EnableWindow( IsWindowEnabled() );
			}
		}
	}
	
	CRect rect;
	CRect rcText;

	GetClientRect(rect);
	rcText = rect;
	rect.left = rect.right - ::GetSystemMetrics(SM_CXHSCROLL);
	rcText.right = rect.left-1;

	m_rcDropButton = rect;
	GetClientRect(rect);

	BOOL bWndEnabled = IsWindowEnabled();

	COLORREF clrDisabledBkg = ::GetSysColor(COLOR_BTNFACE);
	COLORREF clrDisabledBorder = ::GetSysColor(COLOR_3DDKSHADOW);
	COLORREF clrDisabledText = ::GetSysColor(COLOR_GRAYTEXT);

	if( !bWndEnabled )
	{
		if( 1 ) // Draw disabled flat control with border? Change to '0'.
		{
			dc.FillSolidRect( rect, clrDisabledBkg );
		}
		else
		{
			CBrush brDisabled(clrDisabledBkg);
			CBrush* pOldBrush = dc.SelectObject(&brDisabled);
			CPen penDisabled( PS_SOLID, 0, clrDisabledBorder);
			CPen* pOldPen = dc.SelectObject(&penDisabled);
			dc.Rectangle(rect);
			dc.SelectObject(pOldBrush);
			dc.SelectObject(pOldPen);
		}
	}
	else
	{
		COLORREF clrEnabledBkg = ::GetSysColor(COLOR_WINDOW);
		dc.FillSolidRect( rect, clrEnabledBkg );
	}


	DWORD dwBtnStyle = 0;
	if( !bWndEnabled )
	{
		dwBtnStyle |= DFCS_INACTIVE;
	}
	dwBtnStyle |= m_bDropListVisible ? (DFCS_SCROLLDOWN|DFCS_PUSHED|DFCS_FLAT) : DFCS_SCROLLDOWN;


	BOOL bThemeActive = FALSE;
	HRESULT hr;

	bThemeActive = g_xpStyle.UseVisualStyles();

	HTHEME hTheme = NULL;
	if( bThemeActive )
		hTheme = g_xpStyle.OpenThemeData( m_hWnd, L"COMBOBOX" );

	// Theme drop btn style
	int nDropBtnThemeStyle = 0;
	if( m_bDropListVisible )
	{
		nDropBtnThemeStyle = CBXS_PRESSED;
	}
	else
	{
		nDropBtnThemeStyle = CBXS_NORMAL;
		if( m_bDropButtonHot )
			nDropBtnThemeStyle = CBXS_HOT;
		if( !bWndEnabled )
			nDropBtnThemeStyle = CBXS_DISABLED;
	}

#if 0  // -----------------------------------------------------------
	if( m_dwACBStyle & ACBS_FLAT )
	{
		if( bThemeActive )
		{
			hr = g_xpStyle.DrawThemeBackground( hTheme, dc.m_hDC, CP_DROPDOWNBUTTON, nDropBtnThemeStyle, &m_rcDropButton, NULL);
		}
		else
		{
			dc.DrawFrameControl(m_rcDropButton, DFC_SCROLL, dwBtnStyle );
		}
	}
	else
	if( m_dwACBStyle & ACBS_STANDARD )
#endif // -----------------------------------------------------------
	{
		if( bThemeActive )
		{
			COLORREF clrBorder;
			hr = g_xpStyle.GetThemeColor( hTheme, BP_PUSHBUTTON, bWndEnabled ? PBS_NORMAL : PBS_DISABLED, TMT_BORDERCOLOR, &clrBorder );
			if( FAILED( hr ) )
			{
				clrBorder = RGB(0,0,0);
			}
			CPen penBorder( PS_SOLID, 0, clrBorder );
			CPen* oldBorderPen = dc.SelectObject( &penBorder );
			dc.Rectangle( &rect );
			m_rcDropButton.DeflateRect(0,1,0,1);
			m_rcDropButton.left -= 1;
			m_rcDropButton.right -= 1;

			if( !bWndEnabled )
			{
				COLORREF clrDisabledLightBorder;
				COLORREF clrDisabledFill;
				hr = g_xpStyle.GetThemeColor( hTheme, BP_PUSHBUTTON, bWndEnabled ? PBS_NORMAL : PBS_DISABLED, TMT_FILLCOLOR, &clrDisabledLightBorder );
				if( FAILED( hr ) )
				{
					clrDisabledLightBorder = RGB(255,255,255);
				}
				hr = g_xpStyle.GetThemeColor( hTheme, WP_DIALOG, 0, TMT_FILLCOLOR, &clrDisabledFill );
				if( FAILED( hr ) )
				{
					clrDisabledFill = RGB(255,0,0);
				}
				CPen penDisBorder( PS_SOLID, 0, clrDisabledLightBorder );
				CBrush brFill( clrDisabledBkg );//clrDisabledFill );
				CRect rcl = rect;
				rcl.DeflateRect(1,1);
				rcl.right = m_rcDropButton.left;
				CBrush *oldBr = dc.SelectObject( &brFill );
				dc.SelectObject( &penDisBorder );
				dc.Rectangle( &rcl );
				dc.SelectObject( oldBr );
			}

			dc.SelectObject( &oldBorderPen );
			// Button
			hr = g_xpStyle.DrawThemeBackground( hTheme, dc.m_hDC, CP_DROPDOWNBUTTON, nDropBtnThemeStyle, &m_rcDropButton, NULL);
		}
		else
		{
			COLORREF clrTopLeft = ::GetSysColor(COLOR_3DSHADOW);
			COLORREF clrBottomRight = ::GetSysColor(COLOR_3DHILIGHT);
			dc.Draw3dRect( &rect, clrTopLeft, clrBottomRight );
			clrTopLeft = ::GetSysColor(COLOR_3DDKSHADOW);
			clrBottomRight = ::GetSysColor(COLOR_3DLIGHT);
			rect.DeflateRect(1,1);
			dc.Draw3dRect( &rect, clrTopLeft, clrBottomRight );
			m_rcDropButton.DeflateRect(0,2,0,2);
			m_rcDropButton.left -= 2;
			m_rcDropButton.right -= 2;
			// Button
			dc.DrawFrameControl(m_rcDropButton, DFC_SCROLL, dwBtnStyle );
		}

		//
		// Adjust rects
		rcText.DeflateRect(4,3,2,3);
	}

	if( bThemeActive )
		hr = g_xpStyle.CloseThemeData( hTheme );



	if( (GetStyle() & CBS_DROPDOWN) && (GetStyle() & CBS_SIMPLE) )  // == CBS_DROPDOWNLIST
	{
		//
		// Draw Text as selected
		COLORREF clrBackground;
		COLORREF clrOldBkColor;
		COLORREF clrOldTextColor;
		clrBackground = ::GetSysColor(COLOR_HIGHLIGHT);
		clrOldBkColor = dc.SetBkColor( clrBackground );
	//	clrOldTextColor = dc.SetTextColor( ::GetSysColor(COLOR_HIGHLIGHTTEXT) );
		int nOldBkMode = dc.SetBkMode( TRANSPARENT );
		CFont* pOldFont = dc.SelectObject( m_pFont );
		rcText.top -= 2;
		rcText.bottom += 2;
		rcText.left -= 2;
		rcText.right += 1;

		if( m_bHasFocus && !m_bDropListVisible )
		{
			dc.FillSolidRect( rcText, bWndEnabled ? clrBackground : clrDisabledBkg );
			clrOldTextColor = dc.SetTextColor( 
				bWndEnabled ? ::GetSysColor(COLOR_HIGHLIGHTTEXT) : clrDisabledText );
			dc.DrawText( m_strEdit.c_str(), &rcText, DT_SINGLELINE|DT_VCENTER);
		}
		else
		{
			//+++dc.FillSolidRect( rcText, 
			//+++	bWndEnabled ? ::GetSysColor(COLOR_HIGHLIGHTTEXT) : clrDisabledBkg );
			dc.FillSolidRect( rcText, 
				bWndEnabled ? ::GetSysColor(COLOR_WINDOW) : clrDisabledBkg );
			clrOldTextColor = dc.SetTextColor( 
				bWndEnabled ? ::GetSysColor(COLOR_BTNTEXT) : clrDisabledText );
			dc.DrawText( m_strEdit.c_str(), &rcText, DT_SINGLELINE|DT_VCENTER);
		}

		dc.SelectObject( pOldFont );
		dc.SetBkMode( nOldBkMode );
	}
	else
	{
		if( m_pEdit )
		{
			m_pEdit->SetFont( m_pFont );
		}
	}
	// Do not call CWnd::OnPaint() for painting messages
}

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


int CAdvComboBox::SetItemHeight(int nIndex, int nHeight)
{
	if( nIndex == -1 )
	{
		if( nHeight < 10 || nHeight > 50 )
		{
			return CB_ERR;
		}
		else
		{
			//
			// Button rect
			GetClientRect(m_rcDropButton);
			m_rcDropButton.left = m_rcDropButton.right - ::GetSystemMetrics(SM_CXHSCROLL);

			return 0;
		}
	}
	return CB_ERR;
}

void CAdvComboBox::OnLButtonDown(UINT nFlags, CPoint point) 
{
	if( GetFocus() != this )
	{
		SetFocus();
	}

	//
	// Is mouse over drop button?
	if( (GetStyle() & CBS_DROPDOWN) && !(GetStyle() & CBS_SIMPLE) )	// == CBS_DROPDOWN
	{
		if( m_rcDropButton.PtInRect( point ) )
		{
			SendMessage( WM_ON_DROPDOWN_BUTTON );
			InvalidateRect( m_rcDropButton );
			Invalidate();
		}
	}
	else
	if( (GetStyle() & CBS_DROPDOWN) && (GetStyle() & CBS_SIMPLE) )	// == CBS_DROPDOWNLIST
	{
		CRect rc = m_rcCombo;
		GetClientRect( &rc );
		if( rc.PtInRect( point ) )
		{
			SendMessage( WM_ON_DROPDOWN_BUTTON );
			Invalidate();
		}
	}
	CWnd::OnLButtonDown(nFlags, point);
}

LONG CAdvComboBox::OnSelectedItem( WPARAM wParam, LPARAM /*lParam*/ )
{
	list<LIST_ITEM> itemlist;
	list<LIST_ITEM>::iterator itemiter;

	int nPos = (int)wParam;
	itemlist = m_pDropWnd->GetList();
	itemiter = itemlist.begin();
	advance( itemiter, nPos );
	m_strEdit = itemiter->strText;

	m_nCurSel = FindStringExact( 0, m_strEdit.c_str() );

	SetWindowText( m_strEdit.c_str() );
	if( (GetStyle() & CBS_DROPDOWN) && !(GetStyle() & CBS_SIMPLE) )	// == CBS_DROPDOWN
	{
		if( m_pEdit )
		{
			m_pEdit->SetWindowText( m_strEdit.c_str() );
			m_pEdit->SetFocus();
			m_pEdit->SetSel( 0, -1, TRUE );
		}
	}
	// Send message to parent(dialog)
	m_bSelItem = true;
	int nId = GetDlgCtrlID();
	m_pParent->SendMessage( WM_COMMAND, MAKEWPARAM(nId,CBN_SELENDOK), (LPARAM)m_hWnd );

	Invalidate();
	OnDestroyDropdownList(0,0);

	//
	// See to it that the drop button is redrawn
	InvalidateRect( m_rcDropButton );

	m_pParent->SendMessage( WM_COMMAND, MAKEWPARAM(nId,CBN_SELCHANGE), (LPARAM)m_hWnd );

	return TRUE;
}

LONG CAdvComboBox::OnDropdownButton( WPARAM /*wParam*/, LPARAM /*lParam*/ )
{
	XLISTCTRL_TRACE(_T("in CAdvComboBox::OnDropdownButton\n"));
	//
	//
	if( !m_bDropListVisible )
	{
		//
		// Button is pressed
		//
		// Create list
		if( !m_pDropWnd )
		{
			CreateDropList( m_list );
		}
		m_pDropWnd->ShowWindow( SW_SHOW );
		m_bDropListVisible = TRUE;
	}
	else
	{
		OnDestroyDropdownList(0,0);
	}

	// Return TRUE if OK to go back, else return FALSE.
	return TRUE;
}

LONG CAdvComboBox::OnDestroyDropdownList( WPARAM /*wParam*/, LPARAM /*lParam*/ )
{
	XLISTCTRL_TRACE(_T("in CAdvComboBox::OnDestroyDropdownList\n"));
	//
	// 
	if( m_pDropWnd )
	{
		m_pDropWnd->GetWindowRect( &m_rcDropWnd );
		m_bDropRectStored = true;
		m_pDropWnd->ShowWindow( SW_HIDE );
		m_bDropListVisible = FALSE;
		m_pDropWnd->DestroyWindow();
		delete m_pDropWnd;
		m_pDropWnd = NULL;

		InvalidateRect( &m_rcDropButton );
		int nId = GetDlgCtrlID();
		if( !m_bSelItem )
		{
			m_pParent->SendMessage( WM_COMMAND, MAKEWPARAM(nId,CBN_SELENDCANCEL), 
				(LPARAM)m_hWnd );
		}
		else
		{
			m_bSelItem = false;
		}
		m_pParent->SendMessage( WM_COMMAND, MAKEWPARAM(nId,CBN_CLOSEUP), (LPARAM)m_hWnd );
	}
	else
	{
		OnComboComplete();
	}

	return TRUE;
}

void CAdvComboBox::CreateDropList( list<LIST_ITEM> &droplist)
{
	XLISTCTRL_TRACE(_T("in CAdvComboBox::CreateDropList\n"));
	CRect rc;
	if( m_pDropWnd )
		ASSERT(0);
	m_pDropWnd = new CDropWnd( this, droplist, m_dwACBStyle );
	GetWindowRect( &rc );
	rc.top = rc.bottom ;

	//
	// Get screen size
	CRect rcWorkArea;
	SystemParametersInfo( SPI_GETWORKAREA, 0, (LPRECT)rcWorkArea, 0) ;
	if( rc.bottom >= rcWorkArea.bottom )
	{
		rc.bottom = rcWorkArea.bottom;
	}
	else
	{
	}

	int nStyle = WS_CHILD|/*WS_BORDER|*/LBS_DISABLENOSCROLL|LBS_NOTIFY;
	m_pDropWnd->Create( 0, 0, nStyle , rc, 1 ? GetDesktopWindow() : this, 6 );

	//+++
	if (m_nCurSel > ((int)droplist.size() - 1))
		m_nCurSel = 0;

	m_pDropWnd->GetListBoxPtr()->SetCurSel( m_nCurSel );

	m_pDropWnd->SetFont( m_pFont );

	// Send message to parent(dialog)
	int nId = GetDlgCtrlID();
	m_pParent->SendMessage( WM_COMMAND, MAKEWPARAM(nId,CBN_DROPDOWN), (LPARAM)m_hWnd );

}

int CAdvComboBox::GetLBText(int nIndex, LPTSTR lpszText)
{
	m_iter = m_list.begin();
	advance( m_iter, nIndex );
	if( m_iter == m_list.end() || nIndex > (int)m_list.size() )
	{
		return CB_ERR;
	}

	_tcscpy( lpszText, m_iter->strText.c_str() );
	return m_iter->strText.length()+1;
}

void CAdvComboBox::GetLBText(int nIndex, CString &rString)
{
	m_iter = m_list.begin();
	advance( m_iter, nIndex );
	if( m_iter == m_list.end() || nIndex > (int)m_list.size() )
	{
		rString = "";
		return;
	}
	rString = m_iter->strText.c_str();
}

int CAdvComboBox::GetLBTextLen(int nIndex )
{
	m_iter = m_list.begin();
	advance( m_iter, nIndex );
	if( m_iter == m_list.end() || nIndex > (int)m_list.size() )
	{
		return CB_ERR;
	}

	return m_iter->strText.length()+1;
}

int CAdvComboBox::AddString(LPCTSTR lpszString)	//+++
{
	LIST_ITEM item;
	item.strText = lpszString;
	item.bChecked = false;
	item.bDisabled = false;
	item.vpItemData = NULL;
	m_list.push_back( item );

	// this takes too long -
	// sorting is handled in CXListCtrl::SetComboBox()

	//if( GetStyle() & CBS_SORT )
	//{
	//	m_list.sort();
	// Find new item
	//	return FindString( -1, item.strText.c_str() );
	//}
	//else
		return m_list.size()-1;
}

int CAdvComboBox::GetText(LPTSTR lpszText)
{
	if( m_pEdit )
	{	
		CString str;
		m_pEdit->GetWindowText( str );
		_tcscpy( lpszText, (LPCTSTR)str );
		return str.GetLength();
	}
	else
	{
		_tcscpy( lpszText, m_strEdit.c_str() );
		return m_strEdit.length();
	}
}

void CAdvComboBox::GetText(CString &rString)
{
	if( m_pEdit )
	{	
		m_pEdit->GetWindowText( rString );
	}
	else
	{
		rString = m_strEdit.c_str();
	}
}

void CAdvComboBox::SetText(LPCTSTR lpszText)
{
	if( m_pEdit )
	{	
		m_pEdit->SetWindowText( lpszText );
	}
	m_strEdit = lpszText;
}

BOOL CAdvComboBox::PointInWindow(CPoint ptScreenPoint)
{
	CRect rc;
	GetWindowRect( &rc );
	return rc.PtInRect( ptScreenPoint );
}

BOOL CAdvComboBox::OnMouseWheel(UINT /*nFlags*/, short zDelta, CPoint /*pt*/) 
{
	// TODO: Add your message handler code here and/or call default
	if( !m_bDropListVisible )
	{
		string str;
		//
		// Select another string from the map
		m_zDelta += zDelta;
		if( m_zDelta >= WHEEL_DELTA )
		{
			//
			// Select item upwards
			m_zDelta = 0;
			SelPrevItem();
		}
		else
		if( m_zDelta <= -WHEEL_DELTA )
		{
			//
			// Select item downwards
			m_zDelta = 0;
			SelNextItem();
		}
	}
	else
	{
		//
		// Handle mousewheel for the droplist here
		//
		// Select another string from the map
		m_zDelta += zDelta;
		if( m_zDelta >= WHEEL_DELTA )
		{
			//
			// Scroll list upwards
			m_zDelta = 0;
			int nTop = m_pDropWnd->GetListBoxPtr()->GetTopIndex();
			nTop -= 3;
			nTop = nTop < 0 ? 0 : nTop;
			m_pDropWnd->GetListBoxPtr()->SetTopIdx( nTop, TRUE );
		}
		else
		if( m_zDelta <= -WHEEL_DELTA )
		{
			//
			// Scroll list downwards
			m_zDelta = 0;
			int nTop = m_pDropWnd->GetListBoxPtr()->GetTopIndex();
			nTop += 3;
			nTop = nTop > m_pDropWnd->GetListBoxPtr()->GetCount() ? 
						m_pDropWnd->GetListBoxPtr()->GetCount() : nTop;
			m_pDropWnd->GetListBoxPtr()->SetTopIdx( nTop, TRUE );
		}
	}
	return TRUE;
//	return CWnd::OnMouseWheel(nFlags, zDelta, pt);
}

void CAdvComboBox::OnSize(UINT nType, int cx, int cy) 
{
	CWnd::OnSize(nType, cx, cy);
	
	//
	// Move Dropdown?
}


void CAdvComboBox::OnSetFocus(CWnd* pOldWnd) 
{
	CWnd::OnSetFocus(pOldWnd);
	
	// TODO: Add your message handler code here
	m_bHasFocus = true;
	Invalidate();
	//
	// Set focus to the edit control? (CBS_DROPDOWN)
	if( (GetStyle() & CBS_DROPDOWN) && !(GetStyle() & CBS_SIMPLE) )	// == CBS_DROPDOWN
	{
		if( m_pEdit )
		{
			m_pEdit->SetFocus();
		}
	}
	BOOL bDropdownList = (GetStyle() & CBS_DROPDOWN) && (GetStyle() & CBS_SIMPLE);
	if( bDropdownList )
	{
		// Send message to parent(dialog)
		int nId = GetDlgCtrlID();
		m_pParent->SendMessage( WM_COMMAND, MAKEWPARAM(nId,CBN_SETFOCUS), (LPARAM)m_hWnd );
	}
}

void CAdvComboBox::OnSetfocusEdit() 
{
	m_bHasFocus = false;

	//CWnd* pWnd = GetFocus();

	//+++
	if (m_pEdit)
	{
		m_pEdit->PostMessage(EM_SETSEL, 0, -1);
	}

	if( !m_bHasSentFocus )
	{
		// Send message to parent(dialog)
		int nId = GetDlgCtrlID();
		m_pParent->SendMessage( WM_COMMAND, MAKEWPARAM(nId,CBN_SETFOCUS), (LPARAM)m_hWnd );
		m_bHasSentFocus = true;
	}
}

void CAdvComboBox::OnKillFocus(CWnd* pNewWnd) 
{
	XLISTCTRL_TRACE(_T("in CAdvComboBox::OnKillFocus\n"));
	CWnd::OnKillFocus(pNewWnd);

	OnEscapeKey();

	//+++
#if 0  // -----------------------------------------------------------
	// Needed for keydown's like 'Alt-C'("&Cancel" button)
	if( m_pDropWnd ) 
	{
		OnDestroyDropdownList(0,0);
	//}
	m_bHasFocus = false;
	Invalidate();

	BOOL bDropdownList = (GetStyle() & CBS_DROPDOWN) && (GetStyle() & CBS_SIMPLE);
	if( bDropdownList && !m_pDropWnd )
	{
		// Send message to parent(dialog)
		int nId = GetDlgCtrlID();
		m_pParent->SendMessage( WM_COMMAND, MAKEWPARAM(nId,CBN_SELENDCANCEL), (LPARAM)m_hWnd );
		m_pParent->SendMessage( WM_COMMAND, MAKEWPARAM(nId,CBN_KILLFOCUS), (LPARAM)m_hWnd );
	}
	}
	else
	{
		OnEscapeKey();
	}
#endif // -----------------------------------------------------------
}

void CAdvComboBox::OnKillfocusEdit() 
{
	m_bHasFocus = false;
	Invalidate();

	CWnd* pWnd = GetFocus();
	if( !m_pDropWnd && pWnd != this )
	{
		// Send message to parent(dialog)
		int nId = GetDlgCtrlID();
		m_pParent->SendMessage( WM_COMMAND, MAKEWPARAM(nId,CBN_SELENDCANCEL), (LPARAM)m_hWnd );
		m_pParent->SendMessage( WM_COMMAND, MAKEWPARAM(nId,CBN_KILLFOCUS), (LPARAM)m_hWnd );
		m_bHasSentFocus = false;
		m_pEdit->SetSel(0,0);
	}

	//+++
	if (m_pDropWnd)
	{
		OnDestroyDropdownList(0,0);
	}
}

void CAdvComboBox::OnShowWindow(BOOL bShow, UINT nStatus) 
{
	CWnd::OnShowWindow(bShow, nStatus);
	
}

void CAdvComboBox::ModifyACBStyle(UINT nRemoveStyle, UINT nAddStyle)
{
	if( nAddStyle & ACBS_FLAT )
	{
		nRemoveStyle |= ACBS_STANDARD;
	}
	else
	if( nAddStyle & ACBS_STANDARD )
	{
		nRemoveStyle |= ACBS_FLAT;
	}
	m_dwACBStyle &= ~nRemoveStyle;
	m_dwACBStyle |= nAddStyle;
	Invalidate();
}

int CAdvComboBox::GetCount()
{
	return m_list.size();
}

int CAdvComboBox::GetCurSel()
{
	CString str;
	GetText( str );
	return FindStringExact( -1, str );
}

int CAdvComboBox::SetCurSel(int nSelect)
{
	if( nSelect == -1 )
	{
		m_nCurSel = nSelect;
		m_strEdit = _T("");
		Invalidate();
		return CB_ERR;
	}
	else
	if( m_list.size() == 0 )
	{
		m_nCurSel = nSelect;
		return CB_ERR;
	}
	else
	if( nSelect < -1 || nSelect > (int)m_list.size()-1 )
	{
		return CB_ERR;
	}
	else
	{
		m_nCurSel = nSelect;
		m_iter = m_list.begin();
		advance( m_iter, nSelect );
		m_strEdit = m_iter->strText;
		Invalidate();
		return m_nCurSel;
	}
}

int CAdvComboBox::FindString(int nStartAfter, LPCTSTR lpszString)
{
	int nPos = 0;
	m_iter = m_list.begin();
	if( nStartAfter != -1 )
	{
		advance( m_iter, nStartAfter );
		nPos = nStartAfter;
	}
	for( m_iter; m_iter != m_list.end(); ++m_iter )
	{
		if( _tcsncmp( m_iter->strText.c_str(), lpszString, _tcslen(lpszString) ) == 0 )
		{
			return nPos;
		}
		nPos++;
	}
	return CB_ERR;
}

int CAdvComboBox::FindStringExact(int nIndexStart, LPCTSTR lpszFind)
{
	XLISTCTRL_TRACE(_T("in CAdvComboBox::FindStringExact:  nIndexStart=%d\n"), nIndexStart);

	if( nIndexStart > (int)m_list.size() && nIndexStart != -1 )
		return CB_ERR;

	int nPos = 0;
	m_iter = m_list.begin();
	if( nIndexStart != -1 )
	{
		advance( m_iter, nIndexStart );
		nPos = nIndexStart;
	}
	for( m_iter; m_iter != m_list.end(); ++m_iter )
	{
		if( _tcscmp( m_iter->strText.c_str(), lpszFind ) == 0 )
		{
			XLISTCTRL_TRACE(_T("CAdvComboBox::FindStringExact returning %d\n"), nPos);
			return nPos;
		}
		nPos++;
	}
	return CB_ERR;
}

int CAdvComboBox::SelectString(int nStartAfter, LPCTSTR lpszString)
{
	if( nStartAfter > (int)m_list.size() )
		return CB_ERR;

	int nPos = 0;
	m_iter = m_list.begin();
	if( nStartAfter != -1 )
	{
		advance( m_iter, nStartAfter );
		nPos = nStartAfter;
	}
	for( m_iter; m_iter != m_list.end(); ++m_iter )
	{
		if( _tcscmp( m_iter->strText.c_str(), lpszString ) == 0 )
		{
			m_nCurSel = nPos;
			m_strEdit = m_iter->strText;
			Invalidate();
			return nPos;
		}
		nPos++;
	}
	return CB_ERR;
}

int CAdvComboBox::SetItemData(int nIndex, DWORD dwItemData)
{
	m_iter = m_list.begin();
	advance( m_iter, nIndex );
	if( m_iter == m_list.end() || nIndex > (int)m_list.size() )
	{
		return CB_ERR;
	}
	m_iter->vpItemData = (void*)dwItemData;
	return CB_OKAY;
}

DWORD CAdvComboBox::GetItemData(int nIndex)
{
	m_iter = m_list.begin();
	advance( m_iter, nIndex );
	if( m_iter == m_list.end() || nIndex > (int)m_list.size() )
	{
		return (DWORD)CB_ERR;
	}
	return (DWORD)m_iter->vpItemData;
}

int CAdvComboBox::SetItemDataPtr(int nIndex, void *pData)
{
	m_iter = m_list.begin();
	advance( m_iter, nIndex );
	if( m_iter == m_list.end() || nIndex > (int)m_list.size() )
	{
		return (DWORD)CB_ERR;
	}
	m_iter->vpItemData = pData;
	return CB_OKAY;
}

void* CAdvComboBox::GetItemDataPtr(int nIndex)
{
	m_iter = m_list.begin();
	advance( m_iter, nIndex );
	if( m_iter == m_list.end() || nIndex > (int)m_list.size() )
	{
		return (void*)CB_ERR;
	}
	return m_iter->vpItemData;
}

void CAdvComboBox::ResetContent()
{
	m_list.clear();
	m_strEdit = _T("");
	Invalidate();
}

void AFXAPI DDX_ACBIndex( CDataExchange* pDX, int nIDC, int& index )
{
	/*HWND hWnd =*/ pDX->PrepareCtrl( nIDC );
	if( pDX->m_bSaveAndValidate )
	{
		CAdvComboBox* pACB = (CAdvComboBox*)pDX->m_pDlgWnd->GetDlgItem( nIDC );
		index = pACB->GetCurSel();
	}
	else
	{
		CAdvComboBox* pACB = (CAdvComboBox*)pDX->m_pDlgWnd->GetDlgItem( nIDC );
		pACB->SetCurSel( index );
	}
}

void AFXAPI DDX_ACBString( CDataExchange* pDX, int nIDC, CString& value )
{
	/*HWND hWnd =*/ pDX->PrepareCtrl( nIDC );
	if( pDX->m_bSaveAndValidate )
	{
		CAdvComboBox* pACB = (CAdvComboBox*)pDX->m_pDlgWnd->GetDlgItem( nIDC );
		pACB->GetText( value );
	}
	else
	{
		CAdvComboBox* pACB = (CAdvComboBox*)pDX->m_pDlgWnd->GetDlgItem( nIDC );
		pACB->SetText( value );
	}
}

BOOL CAdvComboBox::GetItemDisabled( int nIndex )
{
	if( nIndex > (int)m_list.size() )
		return CB_ERR;

	m_iter = m_list.begin();
	advance( m_iter, nIndex );
	return m_iter->bDisabled;
}

void CAdvComboBox::SetItemDisabled(int nIndex, BOOL bDisabled)
{
	if( nIndex > (int)m_list.size() )
		return;

	m_iter = m_list.begin();
	advance( m_iter, nIndex );
	m_iter->bDisabled = bDisabled;
}

BOOL CAdvComboBox::GetItemChecked( int nIndex )
{
	if( nIndex > (int)m_list.size() )
		return CB_ERR;

	m_iter = m_list.begin();
	advance( m_iter, nIndex );
	return m_iter->bChecked;
}

void CAdvComboBox::SetItemChecked(int nIndex, BOOL bChecked)
{
	if( nIndex > (int)m_list.size() )
		return;

	m_iter = m_list.begin();
	advance( m_iter, nIndex );
	m_iter->bChecked = bChecked;
}

BOOL CAdvComboBox::PreTranslateMessage(MSG* pMsg) 
{
	if( pMsg->message == WM_KEYDOWN )
	{
		m_bAutoAppend = TRUE;

		XLISTCTRL_TRACE(_T("CAdvComboBox: Key was pressed(AdvComboBox)\n"));

		if( pMsg->wParam == VK_RETURN )
		{
			XLISTCTRL_TRACE(_T("CAdvComboBox: VK_RETURN\n"));
			if( m_pDropWnd )
			{
				int nPos = m_pDropWnd->GetListBoxPtr()->GetCurSel();
				if (nPos != LB_ERR)	//+++
					SendMessage( WM_SELECTED_ITEM, (WPARAM)nPos );
				//else				//+++
					OnDestroyDropdownList(0,0);	//+++
			}
			else
			{
				return CWnd::PreTranslateMessage(pMsg);
			}
		}
		else
		if( pMsg->wParam == VK_ESCAPE )
		{
			XLISTCTRL_TRACE(_T("CAdvComboBox: VK_ESCAPE\n"));
			if( m_pDropWnd )
			{
				OnDestroyDropdownList(0,0);
				Invalidate();
			}
			else	//+++
			{
				OnEscapeKey();
				return CWnd::PreTranslateMessage(pMsg);
			}
		}
		else
		if( pMsg->wParam == VK_F4 )
		{
			SendMessage( WM_ON_DROPDOWN_BUTTON );
			Invalidate();
		}
		else
		if( pMsg->wParam == VK_UP )
		{
			SelPrevItem();
		}
		else
		if( pMsg->wParam == VK_DOWN )
		{
			SelNextItem();
		}
		else
		if( pMsg->wParam == VK_PRIOR )	//+++
		{
			SelPrevPage();
		}
		else
		if( pMsg->wParam == VK_NEXT )	//+++
		{
			SelNextPage();
		}
		else
		if( pMsg->wParam == VK_DELETE || pMsg->wParam == VK_BACK )
		{
			m_bAutoAppend = FALSE;
			return CWnd::PreTranslateMessage(pMsg);
		}
		else
		if( pMsg->wParam == VK_RIGHT )
		{
			if( m_dwACBStyle & ACBS_AUTOAPPEND )
			{
				// If the cursor is at the end of the text, show autosuggest text
				if( m_pEdit )
				{
					int nS, nE;
					m_pEdit->GetSel( nS, nE );
					if( nS == nE && nS == m_pEdit->LineLength() )
					{
						OnUpdateEdit();
					}
					else
					{
						return CWnd::PreTranslateMessage(pMsg);
					}
				}
			}
			else
			{
				return CWnd::PreTranslateMessage(pMsg);
			}
		}
		else
		{
			return CWnd::PreTranslateMessage(pMsg);
		}
		return TRUE;
	}
	else
	if( pMsg->message == WM_SYSKEYDOWN )
	{
		if( pMsg->wParam == VK_DOWN ||
			pMsg->wParam == VK_UP )
		{
			SendMessage( WM_ON_DROPDOWN_BUTTON );
			Invalidate();
		}
	}

	return CWnd::PreTranslateMessage(pMsg);
}

void CAdvComboBox::SelPrevItem()
{
	if( m_pDropWnd )
	{
		int nPos = m_pDropWnd->GetListBoxPtr()->GetCurSel();
		if( nPos > 0 )
		{
			m_pDropWnd->GetListBoxPtr()->SetCurSel( --nPos );
		}
	}
	else
	{
		m_iter = m_list.begin();
		advance( m_iter, m_nCurSel );
		--m_iter;
		int nOldSel = m_nCurSel;
		int nPos = m_nCurSel;
		while( m_iter != m_list.end() )
		{
			nPos--;
			if( !m_iter->bDisabled )
			{
				m_strEdit = m_iter->strText;
				if( m_pEdit )
					m_pEdit->SetWindowText( m_strEdit.c_str() );
				m_nCurSel = nPos;
				Invalidate();
				break;
			}
			--m_iter;
		}
		if( nOldSel != m_nCurSel )
		{
			// Send message to parent(dialog)
			int nId = GetDlgCtrlID();
			m_pParent->SendMessage( WM_COMMAND, MAKEWPARAM(nId,CBN_SELENDOK), (LPARAM)m_hWnd );
			m_pParent->SendMessage( WM_COMMAND, MAKEWPARAM(nId,CBN_SELCHANGE), (LPARAM)m_hWnd );
		}
	}
}

void CAdvComboBox::SelNextItem()
{
	if( m_pDropWnd )
	{
		int nPos = m_pDropWnd->GetListBoxPtr()->GetCurSel();
		if( nPos < m_pDropWnd->GetListBoxPtr()->GetCount() )
		{
			m_pDropWnd->GetListBoxPtr()->SetCurSel( ++nPos );
		}
	}
	else
	{
		m_iter = m_list.begin();
		advance( m_iter, m_nCurSel );
		++m_iter;
		int nOldSel = m_nCurSel;
		int nPos = m_nCurSel;
		while( m_iter != m_list.end() )
		{
			nPos++;
			if( !m_iter->bDisabled )
			{
				m_strEdit = m_iter->strText;
				if( m_pEdit )
					m_pEdit->SetWindowText( m_strEdit.c_str() );
				Invalidate();
				m_nCurSel = nPos;
				break;
			}
			++m_iter;
		}
		if( nOldSel != m_nCurSel )
		{
			// Send message to parent(dialog)
			int nId = GetDlgCtrlID();
			m_pParent->SendMessage( WM_COMMAND, MAKEWPARAM(nId,CBN_SELENDOK), (LPARAM)m_hWnd );
			m_pParent->SendMessage( WM_COMMAND, MAKEWPARAM(nId,CBN_SELCHANGE), (LPARAM)m_hWnd );
		}
	}
}

//+++
void CAdvComboBox::SelNextPage()
{
	XLISTCTRL_TRACE(_T("in CAdvComboBox::SelNextPage\n"));
	if (m_pDropWnd)
	{
		CDropListBox * pListBox = m_pDropWnd->GetListBoxPtr();
		ASSERT(pListBox);

		int nPos        = pListBox->GetCurSel();
		int nCount      = pListBox->GetCount();
		int nMaxVisible = pListBox->GetMaxVisibleItems();
		int nTop        = pListBox->GetTopIndex();

		if (nPos == LB_ERR)							// no selection
			nPos = 0;
		else if (nPos == (nCount - 1))				// end of list
			/*nPos = -1*/;
		else if (nPos < (nTop + nMaxVisible - 1))	// middle of listbox window
			nPos = nTop + nMaxVisible - 1;
		else										// at end of listbox window
			nPos = nTop + nMaxVisible + nMaxVisible - 2;

		if (nPos >= nCount)							// moved past end, reset
			nPos = nCount - 1;

		pListBox->SetCurSel(nPos);
		
		int nSel = pListBox->GetCurSel();
		if (nSel == LB_ERR)
		{
		}
		else
		{
			CString str = _T("");
			pListBox->GetText(nSel, str);
			SetWindowText(str);
		}
	}
	else
	{
		// combo list not dropped

		int nSize = m_list.size();
		m_iter = m_list.begin();
		if (m_nCurSel < 0 || m_nCurSel >= nSize)
			m_nCurSel = 0;
		advance(m_iter, m_nCurSel);
		int nOldSel = m_nCurSel;
		int nPos = m_nCurSel;

		// Page Down goes forward by 10
		for (int i = 0; i < 10; i++)  
		{
			if (nPos >= (nSize-1))
			{
				nPos = nSize - 1;
				break;
			}

			nPos++;
			m_iter++;
		}

		if (nOldSel != nPos)
		{
			m_strEdit = m_iter->strText;
			if (m_pEdit)
				m_pEdit->SetWindowText(m_strEdit.c_str());
			Invalidate();
			m_nCurSel = nPos;

			// Send message to parent(dialog)
			int nId = GetDlgCtrlID();
			m_pParent->SendMessage( WM_COMMAND, MAKEWPARAM(nId,CBN_SELENDOK), (LPARAM)m_hWnd );
			m_pParent->SendMessage( WM_COMMAND, MAKEWPARAM(nId,CBN_SELCHANGE), (LPARAM)m_hWnd );
		}
	}
}

//+++
void CAdvComboBox::SelPrevPage()
{
	if (m_pDropWnd)
	{
		CDropListBox * pListBox = m_pDropWnd->GetListBoxPtr();
		ASSERT(pListBox);

		int nPos        = pListBox->GetCurSel();
		int nCount      = pListBox->GetCount();
		int nMaxVisible = pListBox->GetMaxVisibleItems();
		int nTop        = pListBox->GetTopIndex();

		if (nPos <= 0)
			return;

		if (nPos == LB_ERR)					// no selection
			nPos = nCount - 1;
		else if (nPos == 0)					// top of list
			/*nPos = -1*/;
		else if (nPos == nTop)				// at top of listbox window
		{
			nPos = nTop - nMaxVisible + 1;	// this might be = -1
			if (nPos < 0)
				nPos = 0;
		}
		else								// middle of listbox window
			nPos = nTop;

		pListBox->SetCurSel(nPos);
		
		int nSel = pListBox->GetCurSel();
		if (nSel == LB_ERR)
		{
		}
		else
		{
			CString str = _T("");
			pListBox->GetText(nSel, str);
			SetWindowText(str);
		}
	}
	else
	{
		// combo list not dropped

		int nSize = m_list.size();
		m_iter = m_list.begin();
		if (m_nCurSel < 0 || m_nCurSel >= nSize)
			m_nCurSel = 0;
		advance(m_iter, m_nCurSel);
		int nOldSel = m_nCurSel;
		int nPos = m_nCurSel;

		// Page Up goes back by 10
		for (int i = 0; i < 10; i++)  
		{
			if (nPos <= 0)
			{
				nPos = 0;
				break;
			}

			nPos--;
			m_iter--;
		}

		if (nOldSel != nPos)
		{
			m_strEdit = m_iter->strText;
			if (m_pEdit)
				m_pEdit->SetWindowText(m_strEdit.c_str());
			Invalidate();
			m_nCurSel = nPos;

			// Send message to parent(dialog)
			int nId = GetDlgCtrlID();
			m_pParent->SendMessage( WM_COMMAND, MAKEWPARAM(nId,CBN_SELENDOK), (LPARAM)m_hWnd );
			m_pParent->SendMessage( WM_COMMAND, MAKEWPARAM(nId,CBN_SELCHANGE), (LPARAM)m_hWnd );
		}
	}
}

int CAdvComboBox::GetTopIndex()
{
	if( m_bDropListVisible )
	{
		if( m_pDropWnd )
		{
			return m_pDropWnd->GetListBoxPtr()->GetTopIndex();
		}
	}
	return CB_ERR;
}

int CAdvComboBox::SetTopIndex(int nIndex)
{
	if( m_bDropListVisible )
	{
		if( m_pDropWnd )
		{
			return m_pDropWnd->GetListBoxPtr()->SetTopIndex(nIndex);
		}
	}
	return CB_ERR;
}

//
// Will not allocate anything. I can't see the need in doing that.
// Everything is stored in a STL list.
int CAdvComboBox::InitStorage(int nItems, UINT /*nBytes*/)
{
	return nItems;
}

void CAdvComboBox::ShowDropDown(BOOL bShowIt)
{
	if( bShowIt )
	{
		if( !m_bDropListVisible )
		{
			SendMessage( WM_ON_DROPDOWN_BUTTON );
			Invalidate();
		}
	}
	else
	{
		if( m_bDropListVisible )
		{
			SendMessage( WM_DESTROY_DROPLIST );
			Invalidate();
		}
	}
}

void CAdvComboBox::GetDroppedControlRect(LPRECT lprect)
{
	if( m_bDropListVisible )
	{
		m_pDropWnd->GetWindowRect( lprect );
	}
}

BOOL CAdvComboBox::GetDroppedState()
{
	return m_bDropListVisible;
}

int CAdvComboBox::SetExtendedUI(BOOL /*bExtended*/)
{
	return CB_OKAY;
}

BOOL CAdvComboBox::GetExtendedUI()
{
	return FALSE;
}

int CAdvComboBox::DeleteString(UINT nIndex)
{
	m_iter = m_list.begin();
	advance( m_iter, nIndex );
	if( m_iter != m_list.end() || nIndex > m_list.size() )
	{
		m_list.erase( m_iter );
		return m_list.size();
	}
	else
	{
		return CB_ERR;
	}
}

int CAdvComboBox::InsertString(int nIndex, LPCTSTR lpszString)
{
	LIST_ITEM item;
	item.strText = lpszString;
	if( nIndex == -1 || (nIndex > (int)m_list.size()) )
	{
		m_list.push_back( item );
		return m_list.size()-1;
	}

	if( nIndex == 0 && (m_list.size()==0) )
	{
		m_list.push_back( item );
		return 0;
	}

	m_iter = m_list.begin();
	advance( m_iter, nIndex );
	if( m_iter != m_list.end() )
	{
		m_iter = m_list.insert( m_iter, item );
		int nPos = 0;
		while( m_iter != m_list.begin() )
		{
			nPos++;
			--m_iter;
		}
		if( nIndex <= m_nCurSel )
		{
			m_nCurSel++;
		}
		return nPos;
	}
	return CB_ERR;
}

DWORD CAdvComboBox::GetEditSel()
{
	if( (GetStyle() & CBS_DROPDOWN) && !(GetStyle() & CBS_SIMPLE) )	// == CBS_DROPDOWN
	{
		if( m_pEdit )
		{
			return m_pEdit->GetSel();
		}
	}
	return (DWORD)CB_ERR;
}

BOOL CAdvComboBox::SetEditSel(int nStartChar, int nEndChar)
{
	if( (GetStyle() & CBS_DROPDOWN) && !(GetStyle() & CBS_SIMPLE) )	// == CBS_DROPDOWN
	{
		if( m_pEdit )
		{
			m_pEdit->SetSel( nStartChar, nEndChar, TRUE );
			return TRUE;
		}
	}
	return CB_ERR;
}


void CAdvComboBox::OnChangeEdit()
{
	if( !m_pDropWnd )
	{
		// Send message to parent(dialog)
		int nId = GetDlgCtrlID();
		m_pParent->SendMessage( WM_COMMAND, MAKEWPARAM(nId,CBN_EDITCHANGE), (LPARAM)m_hWnd );
	}
}

void CAdvComboBox::OnUpdateEdit()
{
	static bool bAutoAppendInProgress;
	CString strEdit;
	m_pEdit->GetWindowText( strEdit );
	if( GetFocus() == m_pEdit )
	{
		if( !bAutoAppendInProgress )
		{
//			m_nCurSel = -1;
			if( m_dwACBStyle & ACBS_AUTOAPPEND && m_bAutoAppend )
			{
				tstring str = (LPCTSTR)strEdit;
				int nEditLen = str.length();
				if( !nEditLen )
					return;
				int nStartSel;
				int nEndSel;

				m_pEdit->GetSel( nStartSel, nEndSel );

				LIST_ITEM item;
				m_iter = m_list.begin();
				while( m_iter != m_list.end() )
				{
					item = *m_iter;
					int nPos = m_iter->strText.find( str, 0 );
					if( nPos == 0 )
					{
						bAutoAppendInProgress = true;
						m_pEdit->SetWindowText( m_iter->strText.c_str() );
						m_pEdit->SetSel( nEditLen, m_iter->strText.length(), TRUE );
						bAutoAppendInProgress = false;
						break;
					}
					++m_iter;
				}
			}
		}

		if( !bAutoAppendInProgress )
		{
			if( m_dwACBStyle & ACBS_AUTOSUGGEST )
			{
				list<LIST_ITEM> suggestlist;
				list<LIST_ITEM>::iterator suggestiter;
				tstring str = (LPCTSTR)strEdit;
				int nEditLen = str.length();
				if( !nEditLen )
				{
					if( m_pDropWnd )
						SendMessage( WM_DESTROY_DROPLIST );
					return;
				}
				int nStartSel;
				int nEndSel;

				m_pEdit->GetSel( nStartSel, nEndSel );

				LIST_ITEM item;
				m_iter = m_list.begin();
				while( m_iter != m_list.end() )
				{
					item = *m_iter;
					int nPos = m_iter->strText.find( str, 0 );
					if( nPos == 0 )
					{
						if (m_iter->strText != str)			//+++
							suggestlist.push_back( item );
					}
					++m_iter;
				}
				if( m_pDropWnd )
					SendMessage( WM_DESTROY_DROPLIST );
				//+++if( suggestlist.size() != 0 )
				if( suggestlist.size() > 1 )	//+++
				{
					m_nCurSel = 0;		//+++
					CreateDropList( suggestlist );
				}
			}
		}
	}

	if( !m_pDropWnd )
	{
		// Send message to parent(dialog)
		int nId = GetDlgCtrlID();
		m_pParent->SendMessage( WM_COMMAND, MAKEWPARAM(nId,CBN_EDITUPDATE), (LPARAM)m_hWnd );
	}
}

void CAdvComboBox::OnEnable(BOOL bEnable) 
{
	CWnd::OnEnable(bEnable);
	
	Invalidate();
	if( m_pEdit )
	{
		m_pEdit->EnableWindow( bEnable );
	}
	
}

BOOL CAdvComboBox::LimitText(int nMaxChars)
{
	if( m_pEdit )
	{
		int nCh = !nMaxChars ? 65535 : nMaxChars;
		m_pEdit->SetLimitText( nCh );
		return TRUE;
	}
	else
	{
		return CB_ERR;
	}
}

void CAdvComboBox::SetMinVisibleItems(int nMinItems)
{
	m_nMinVisItems = nMinItems;
}

int CAdvComboBox::GetMinVisibleItems()
{
	return m_nMinVisItems;
}

void CAdvComboBox::OnMouseMove(UINT nFlags, CPoint point) 
{
	bool bChange = m_bDropButtonHot;

	if( (GetStyle() & CBS_DROPDOWN) && !(GetStyle() & CBS_SIMPLE) )  // == CBS_DROPDOWN
	{
		if( m_rcDropButton.PtInRect( point ) )
		{
			m_bDropButtonHot = true;
		}
		else
		{
			m_bDropButtonHot = false;
		}
	}
	else
	if( (GetStyle() & CBS_DROPDOWN) && (GetStyle() & CBS_SIMPLE) )  // == CBS_DROPDOWNLIST
	{
		GetClientRect( &m_rcCombo );
		if( m_rcCombo.PtInRect( point ) )
		{
			m_bDropButtonHot = true;
		}
		else
		{
			m_bDropButtonHot = false;
		}
	}


	if( bChange != m_bDropButtonHot )
	{
		if( !m_bTrackMouseLeave )
		{
			//
			// Could not use TrackMouseEvent() under Release. A bug appeared 
			// the second time the dropwindow was shown, and I did not 
			// have to strenght to go look for it. :)
/*			TRACKMOUSEEVENT tme;
			tme.cbSize = sizeof(tme);
			tme.dwFlags = TME_LEAVE;
			tme.hwndTrack = m_hWnd;
			TrackMouseEvent(&tme);*/

			m_bTrackMouseLeave = true;
			SetTimer(1, 50, NULL);
		}

		InvalidateRect( &m_rcDropButton );
	}

	CWnd::OnMouseMove(nFlags, point);
}

void CAdvComboBox::OnMouseLeave() 
{
	// TODO: Add your message handler code here and/or call default
	bool bChange = m_bDropButtonHot;
	m_bDropButtonHot = false;
	m_bTrackMouseLeave = false;

	if( bChange != m_bDropButtonHot )
		InvalidateRect( &m_rcDropButton );
}

void CAdvComboBox::OnTimer(UINT nIDEvent) 
{
	if( nIDEvent == 1 )
	{
		CPoint point;
		GetCursorPos( &point );
		ScreenToClient( &point );
		if( (GetStyle() & CBS_DROPDOWN) && !(GetStyle() & CBS_SIMPLE) )  // == CBS_DROPDOWN
		{
			if( !m_rcDropButton.PtInRect( point ) )
			{
				KillTimer( 1 );
				OnMouseLeave();
			}
		}
		else
		if( (GetStyle() & CBS_DROPDOWN) && (GetStyle() & CBS_SIMPLE) )  // == CBS_DROPDOWNLIST
		{
			GetClientRect( &m_rcCombo );
			if( !m_rcCombo.PtInRect( point ) )
			{
				KillTimer( 1 );
				OnMouseLeave();
			}
		}
	}
	CWnd::OnTimer(nIDEvent);
}


int CAdvComboBox::GetDefaultVisibleItems()
{
	return m_nDefaultDropItems;
}

void CAdvComboBox::SetDefaultVisibleItems(int nItems)
{
	m_nDefaultDropItems = nItems;
}

//+++
// function to get combo width based on strings
UINT CAdvComboBox::GetComboWidth()
{
	CDC * pDC = GetDC();
	CFont * pFont = GetFont();

	CFont* pOldFont = pDC->SelectObject(pFont);

	TEXTMETRIC tm;
	pDC->GetTextMetrics(&tm);

	CString str = _T("");
	CSize sz;
	UINT dx = 0;

	for (int i = 0; i < GetCount(); i++)
	{
		GetLBText(i, str);
		sz = pDC->GetTextExtent(str);

		sz.cx += tm.tmAveCharWidth;
		if (sz.cx > (int)dx)
			dx = sz.cx;
	}

	pDC->SelectObject(pOldFont);
	ReleaseDC(pDC);

	dx += ::GetSystemMetrics(SM_CXVSCROLL) + 2*::GetSystemMetrics(SM_CXEDGE) + 5;

	return dx;
}

//+++
void CAdvComboBox::OnChar(UINT nChar, UINT nRepCnt, UINT nFlags) 
{
	// handle escape and return, in case combo's edit does NOT have focus

	if (m_pParent)
	{
		if (nChar == VK_ESCAPE)
		{
			OnEscapeKey();
			return;
		}
		else if (nChar == VK_RETURN)
		{
			OnComboComplete();
			return;
		}
		else if (nChar == VK_DOWN)
		{
			SelNextItem();
		}
	}
	
	CWnd::OnChar(nChar, nRepCnt, nFlags);
}

void CAdvComboBox::OnKeyDown(UINT nChar, UINT nRepCnt, UINT nFlags) 
{
	XLISTCTRL_TRACE(_T("in CAdvComboBox::OnKeyDown\n"));

	if (nChar == VK_DOWN)
		SelNextItem();
	else if (nChar == VK_UP)
		SelPrevItem();
	else if (nChar == VK_NEXT)
		SelNextPage();
	else if (nChar == VK_PRIOR)
		SelPrevPage();

	CWnd::OnKeyDown(nChar, nRepCnt, nFlags);
}

#if _MFC_VER < 0x700
void CAdvComboBox::OnActivateApp(BOOL bActive, HTASK hTask) 
#else
void CAdvComboBox::OnActivateApp(BOOL bActive, DWORD hTask) 
#endif
{
	XLISTCTRL_TRACE(_T("in CAdvComboBox::OnActivateApp\n"));
	CWnd::OnActivateApp(bActive, hTask);
}

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 GNU General Public License (GPLv3)

Share

About the Author

Geert van Horrik
Software Developer CatenaLogic
Netherlands Netherlands
I am Geert van Horrik, and I have studied Computer Science in the Netherlands.

I love to write software using .NET (especially the combination of WPF and C#). I am also the lead developer of Catel, an open-source application development framework for WPF, Silverlight, WP7 and WinRT with the focus on MVVM.

I have my own company since January 1st 2007, called CatenaLogic. This company develops commercial and non-commercial software.

To download (or buy) applications I have written, visit my website: http://www.catenalogic.com

You may also be interested in...

| Advertise | Privacy | Terms of Use | Mobile
Web01 | 2.8.150731.1 | Last Updated 17 Jan 2008
Article Copyright 2008 by Geert van Horrik
Everything else Copyright © CodeProject, 1999-2015
Layout: fixed | fluid