Click here to Skip to main content
15,881,613 members
Articles / Programming Languages / C++

Address Book

Rate me:
Please Sign up or sign in to vote.
4.48/5 (21 votes)
6 Aug 2000CPOL3 min read 284.2K   5.5K   93  
Address Book application
// GfxInCombo.cpp : implementation file
//

#include "stdafx.h"
#include "Address.h"


#include "GfxInCombo.h"

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

/////////////////////////////////////////////////////////////////////////////
// CGfxInCombo

CGfxInCombo::CGfxInCombo(int iItem, int iSubItem, CString sInitText, CStringArray * pComboArray, bool _bEditable, bool _bMouseSelect)
{
	bMouseSelect = _bMouseSelect;
	pArray = pComboArray;
	m_iItem = iItem;
	m_iSubItem = iSubItem;
	m_bESC = FALSE;
	hArrow = LoadBitmap(NULL, MAKEINTRESOURCE(32738));
	ASSERT(hArrow);
	m_sInitText = sInitText;
	wndList.pCombo = this;
	wndEdit.pCombo = this;
	wndStatic.pCombo = this;
	iButtonDx = GetSystemMetrics(SM_CXHSCROLL);
//	pFont = NULL;
	hFontHandle = NULL;
	bEditable = _bEditable;
	m_bAutoComplete = true;
	iCurSel = -1;

	bProcessed = false;
	bLightBorder = true;

	crColor = GetSysColor(COLOR_WINDOWTEXT);
}

CGfxInCombo::~CGfxInCombo()
{
	if (pArray)
	{
		pArray->RemoveAll();
		delete pArray;
	}
}


BEGIN_MESSAGE_MAP(CGfxInCombo, CWnd)
	//{{AFX_MSG_MAP(CGfxInCombo)
	ON_WM_CREATE()
	ON_WM_PAINT()
	ON_WM_SIZE()
	ON_WM_KILLFOCUS()
	ON_WM_NCDESTROY()
	ON_WM_ERASEBKGND()
	ON_WM_LBUTTONDOWN()
	ON_WM_CHAR()
	ON_WM_SETFOCUS()
	ON_WM_LBUTTONDBLCLK()
	//}}AFX_MSG_MAP
	ON_MESSAGE(WM_USER_SELENDOK, OnSelendOk)
END_MESSAGE_MAP()


/////////////////////////////////////////////////////////////////////////////
// CGfxInCombo message handlers

int CGfxInCombo::OnCreate(LPCREATESTRUCT lpCreateStruct) 
{
	if (CWnd::OnCreate(lpCreateStruct) == -1)
		return -1;
	
	CRect rc;
	GetClientRect(rc);
	CRect btrc(rc.left, rc.top, rc.right - iButtonDx, rc.bottom);

	CFont* font = hFontHandle ? CFont::FromHandle(hFontHandle) : GetFont();
	SetFont(font);

	if (bEditable)
	{
		wndEdit.bMouseSelect = bMouseSelect;
		wndEdit.Create(WS_CHILD|WS_VISIBLE|ES_AUTOHSCROLL, btrc, this, GetDlgCtrlID() + 1);
		wndEdit.SetFont(font);
		wndEdit.SetWindowText(m_sInitText);

				
		CHARFORMAT chf;
		chf.cbSize = sizeof(CHARFORMAT);
		chf.crTextColor = crColor;
		chf.dwMask = CFM_COLOR;

		CHARRANGE cr;
		wndEdit.GetSel(cr);

		wndEdit.SetSel(0,-1);
		wndEdit.SetDefaultCharFormat(chf);
		wndEdit.SetSelectionCharFormat(chf);

		wndEdit.SetSel(cr);
	}
	else
	{
		wndStatic.Create(m_sInitText, WS_VISIBLE|WS_CHILD, btrc, this, GetDlgCtrlID() + 1);
		wndStatic.SetFont(font);

		wndStatic.crColor = crColor;
	}
	iCurSel = FindStringExact(-1, m_sInitText);
	SetFocus();
	return 0;
}

void CGfxInCombo::OnPaint() 
{
	CPaintDC dc(this);

	CRect rc;
	GetClientRect(rc);
	CRect btrc(rc.right - iButtonDx, rc.top, rc.right, rc.bottom);
	DrawButton(&dc, wndList.GetSafeHwnd() && wndList.IsWindowVisible());
}

void CGfxInCombo::DrawButton(CDC * pDC, const bool bPressed)
{
	CRect rc;
	GetClientRect(rc);
	CRect btrc(rc.right - iButtonDx, rc.top, rc.right, rc.bottom);
	pDC->FillSolidRect(btrc, GetSysColor(COLOR_3DFACE));

	CBitmap * pBmp = CBitmap::FromHandle(hArrow);

	CDC dcImage;
	if (dcImage.CreateCompatibleDC(pDC))
	{ 
		BITMAP bm;
		pBmp->GetBitmap(&bm);

		int x = btrc.left + (btrc.Width() - bm.bmWidth) / 2;
		int y = btrc.top + (btrc.Height() - bm.bmHeight) / 2;
		CBitmap* pOldBitmap = dcImage.SelectObject(pBmp);
		pDC->BitBlt(x, y, bm.bmWidth, bm.bmHeight, &dcImage, 0, 0, SRCCOPY);
		dcImage.SelectObject(pOldBitmap);
	}

	if (bPressed) 
	{
		pDC->Draw3dRect(btrc, GetSysColor(COLOR_3DSHADOW), GetSysColor(COLOR_3DHILIGHT));
		if (!bLightBorder)
		{
			btrc.InflateRect(-1,-1);
			pDC->Draw3dRect(btrc, RGB(0,0,0), GetSysColor(COLOR_3DFACE));
		}
	}
	else 
	{
		if (!bLightBorder)
		{
			pDC->Draw3dRect(btrc, GetSysColor(COLOR_3DFACE),RGB(0,0,0));
			btrc.InflateRect(-1,-1);
		}
		pDC->Draw3dRect(btrc, GetSysColor(COLOR_3DHILIGHT),GetSysColor(COLOR_3DSHADOW));
	}

}

void CGfxInCombo::OnSize(UINT nType, int cx, int cy) 
{
	CWnd::OnSize(nType, cx, cy);
	if (wndStatic.GetSafeHwnd()) wndStatic.SetWindowPos(0,0,0,cx - iButtonDx, cy, SWP_NOZORDER);
	if (wndEdit.GetSafeHwnd())   wndEdit.SetWindowPos(0,0,0,cx - iButtonDx, cy, SWP_NOZORDER);
}

bool CGfxInCombo::Create(DWORD dwFlag, CRect rc, CWnd * pParent, int id)
{
	return CWnd::Create(NULL, "", dwFlag|WS_CHILD, rc, pParent, id) ? true : false;
}

void CGfxInCombo::OnKillFocus(CWnd* pNewWnd) 
{
	CWnd::OnKillFocus(pNewWnd);
	if (m_bESC)
	{
		//PostMessage(WM_CLOSE);
		DestroyWindow();
		return;
	}
	
	if (!IsChild(pNewWnd) && pNewWnd->GetSafeHwnd() != wndList.GetSafeHwnd()) 
	{
		ProcessSelect();
		DestroyWindow();
		//PostMessage(WM_CLOSE);
	}
}

void CGfxInCombo::OnNcDestroy() 
{
	CWnd::OnNcDestroy();
//	delete this;	
}

BOOL CGfxInCombo::OnEraseBkgnd(CDC* pDC) 
{
	CRect rc;
	GetClientRect(rc);
	pDC->FillSolidRect(rc, GetSysColor(COLOR_WINDOW));
	return true;	
}

void CGfxInCombo::OnLButtonDown(UINT nFlags, CPoint point) 
{
	CRect rc, rc1;
	GetClientRect(rc);
	CFont* font = GetParent()->GetFont(); 
	{
		CClientDC dc(this);
		CFont * of = dc.SelectObject(font);
		CSize sz = dc.GetTextExtent("X");
		sz.cy += 3;
		dc.SelectObject(of);
		int icy = pArray ? sz.cy * (pArray->GetSize()+1) : 100;
		if (icy > 100) icy = 100;
		if (icy == 0) icy = 20;
		rc1.SetRect(rc.left, rc.bottom, rc.right, rc.bottom + icy);
	}

	rc.left = rc.right - iButtonDx;
	if (pArray && pArray->GetSize() > 0 && rc.PtInRect(point))
	{
		if (wndList.GetSafeHwnd()) wndList.PostMessage(WM_CLOSE);//wndList.DestroyWindow();
		else
		{
			ClientToScreen(rc1);
			GetParent()->ScreenToClient(rc1);

			wndList.Create(WS_BORDER|WS_VISIBLE|WS_CHILD|WS_VSCROLL|LBS_SORT, rc1, GetParent(), GetDlgCtrlID() + 2);
			if (pArray)
			{
				for (int t = 0; t < pArray->GetSize(); t++)
					wndList.AddString((*pArray)[t]);
			}
			int icy = wndList.GetItemHeight(0) * pArray->GetSize();
			wndList.SetWindowPos(&wndTopMost, 0,0,rc1.Width(),icy > 100 ? 100 : icy, SWP_NOMOVE);
			wndList.SetFont(font);

			CString str;

			if (bEditable) wndEdit.GetWindowText(str);
			else wndStatic.GetWindowText(str);

			wndList.SetCurSel(wndList.FindStringExact(-1, str));
			wndList.SetFocus();
		}
		InvalidateButton();
	}
	else
	{
		if (wndList.GetSafeHwnd()) wndList.DestroyWindow();
		InvalidateButton();
	}
	CWnd::OnLButtonDown(nFlags, point);
}

void CGfxInCombo::InvalidateButton()
{
	CRect rc;
	GetClientRect(rc);
	CRect btrc(rc.right - iButtonDx, rc.top, rc.right, rc.bottom);
	InvalidateRect(btrc);
}

BOOL CGfxInCombo::PreTranslateMessage(MSG* pMsg) 
{
	CWnd * pParent = GetParent();
	ASSERT(pParent);
	if (pMsg->message == WM_NCHITTEST)
	{
		int x = LOWORD(pMsg->lParam);
		int y = HIWORD(pMsg->lParam);
		CPoint pt(x,y);
		CWnd *pw = WindowFromPoint(pt);
		if (pw && !IsChild(pw) && pw->GetSafeHwnd() != wndList.GetSafeHwnd()) 
		{
			//PostMessage(WM_CLOSE);
			DestroyWindow();
			return TRUE;
		}
	}
	if (pMsg->message == WM_KEYDOWN || pMsg->message == WM_CHAR)
	{
		if (pMsg->wParam == VK_UP)   SetCurSel(iCurSel - 1);
		if (pMsg->wParam == VK_DOWN) SetCurSel(iCurSel + 1);
		if (pMsg->wParam == VK_RETURN)
		{
			ProcessSelect();
			pParent->SetFocus();
			return TRUE;
		}
		if (pMsg->wParam == VK_ESCAPE)
		{
			m_bESC = TRUE;
			pParent->SetFocus();
			return TRUE;
		}
		if (pMsg->wParam == VK_TAB)
		{
			SHORT sh = GetKeyState(VK_SHIFT);
			if (sh < 0) PreviousTab();
			else NextTab();
			return TRUE;
		}

		if (pMsg->wParam == VK_LEFT)
		{
			LeftCell();
			return TRUE;
		}
		if (pMsg->wParam == VK_RIGHT)
		{
			RightCell();
			return TRUE;
		}


		if (!bEditable) 
		{
			if (((char) pMsg->wParam >= 'a' && (char) pMsg->wParam >= 'z') || ((char) pMsg->wParam >= 'A' && (char) pMsg->wParam >= 'Z') || ((char) pMsg->wParam >= '0' && (char) pMsg->wParam >= '9'))
			{
				CString cs = FindFromCharPressed((char) pMsg->wParam);
				if (cs != "") 
				{
					wndStatic.SetWindowText(cs);
					wndStatic.Invalidate();
				}
			}
		}

		::TranslateMessage(pMsg);
		::DispatchMessage(pMsg);
		return TRUE;
	}
	
	return CWnd::PreTranslateMessage(pMsg);
}

LRESULT CGfxInCombo::OnSelendOk(WPARAM wParam, LPARAM lParam)
{
	if (bEditable) wndEdit.SetWindowText((char *) lParam);
	else 
	{
		wndStatic.SetWindowText((char *) lParam);
		wndStatic.Invalidate();
	}
	if ((int) wParam >= 0) iCurSel = (int) wParam;

	return 1L;
}

void CGfxInCombo::OnChar(UINT nChar, UINT nRepCnt, UINT nFlags) 
{
	if (nChar == VK_ESCAPE) 
	{
		m_bESC = TRUE;
		GetParent()->SetFocus();
		return;
	}
	
	CWnd::OnChar(nChar, nRepCnt, nFlags);
}

int CGfxInCombo::FindStringExact(const int iStart, const char * cText)
{
	if (pArray)
	{
		CString csText(cText);
		for (int t = 0; t < pArray->GetSize(); t++)
			if ((*pArray)[t] != "" && (*pArray)[t] == csText && t >= iStart) return t;
	}
	return -1;
}

CString CGfxInCombo::FindFromCharPressed(char c)
{
	CString cs;
	int iActSel = iCurSel;

	if (pArray)
	{
		int t;
		CString csText(c);

		for (t = iCurSel >= 0 ? iCurSel : 0; t < pArray->GetSize(); t++)
		{
			CString item = (*pArray)[t];
			if ((*pArray)[t] != "")
			{
				if (item.Left(1) == csText)
				{
					iCurSel = t;
					return item;
				}
			}
		}
		if (iCurSel > 0)
		{
			for (t = 0; t < iCurSel; t++)
			{
				CString item = (*pArray)[t];
				if ((*pArray)[t] != "")
				{
					if (item.Left(1) == csText)
					{
						iCurSel = t;
						return item;
					}
				}
			}
		}
	}
	return cs;
}

int CGfxInCombo::SetCurSel(const int iSel)
{
	if (iSel >= 0 && (pArray != NULL && iSel < pArray->GetSize()))
	{
		iCurSel = iSel;
		CString cs = (*pArray)[iCurSel];
		if (bEditable) wndEdit.SetWindowText(cs);
		else 
		{
			wndStatic.SetWindowText(cs);
			wndStatic.Invalidate();
		}
	}
	return -1;
}

void CGfxInCombo::ProcessSelect(const char * cForceText)
{
//	if (bProcessed) return;
//	bProcessed = true;
	if (!GetSafeHwnd() || !IsWindow(GetSafeHwnd())) return;
	CString str;

	if (cForceText) 
	{
		str = cForceText;
	}
	else
	{
		if (bEditable) 
		{
			if (wndEdit.GetSafeHwnd()) wndEdit.GetWindowText(str);
			else str = wndEdit.csLstText;
		}
		else wndStatic.GetWindowText(str);
	}

	if (m_sInitText != str) 
	{
		m_sInitText = str;
		LV_DISPINFO dispinfo;
		dispinfo.hdr.hwndFrom = GetParent()->m_hWnd;
		dispinfo.hdr.idFrom = GetDlgCtrlID();
		dispinfo.hdr.code = LVN_ENDLABELEDIT;

		dispinfo.item.mask = LVIF_TEXT;
		dispinfo.item.iItem = m_iItem;
		dispinfo.item.iSubItem = m_iSubItem;
		dispinfo.item.pszText = m_bESC ? NULL : LPTSTR((LPCTSTR)str);
		dispinfo.item.cchTextMax = str.GetLength();

		GetParent()->SendMessage(WM_NOTIFY, GetParent()->GetDlgCtrlID(), (LPARAM)&dispinfo);
		
	}
}

int CGfxInCombo::FindString(int nStartAfter, CString find)
{
	if (pArray)
	{
		for (int t = nStartAfter >= 0 ? nStartAfter : 0; t < pArray->GetSize(); t++)
		{
			CString item = (*pArray)[t];
			if (item.GetLength() >= find.GetLength())
				if (item.Left(find.GetLength()).CompareNoCase(find) == 0) return t;
		}
	}
	return -1;
}

void CGfxInCombo::OnSetFocus(CWnd* pOldWnd) 
{
	CWnd::OnSetFocus(pOldWnd);
	if (bEditable && wndEdit.GetSafeHwnd()) wndEdit.SetFocus();
}

void CGfxInCombo::LeftCell()
{
	CWnd * pParent = GetParent();
	int ip[2] = { m_iItem, m_iSubItem };
	ProcessSelect();
	//PostMessage(WM_CLOSE);
	DestroyWindow();
	pParent->SendMessage(WM_USER_TAB, 2, (LPARAM) &ip);
}

void CGfxInCombo::RightCell()
{
	CWnd * pParent = GetParent();
	int ip[2] = { m_iItem, m_iSubItem };
	ProcessSelect();
	DestroyWindow();
	//PostMessage(WM_CLOSE);
	pParent->SendMessage(WM_USER_TAB, 3, (LPARAM) &ip);
}

void CGfxInCombo::UpCell()
{

}

void CGfxInCombo::DownCell()
{

}

void CGfxInCombo::NextTab()
{
	CWnd * pParent = GetParent();
	int ip[2] = { m_iItem, m_iSubItem };
	ProcessSelect();
	DestroyWindow();
	//PostMessage(WM_CLOSE);
	pParent->SendMessage(WM_USER_TAB, 0, (LPARAM) &ip);
}

void CGfxInCombo::PreviousTab()
{
	CWnd * pParent = GetParent();
	int ip[2] = { m_iItem, m_iSubItem };
	ProcessSelect();
	DestroyWindow();
	//PostMessage(WM_CLOSE);
	pParent->SendMessage(WM_USER_TAB, 1, (LPARAM) &ip);
}

void CGfxInCombo::OnLButtonDblClk(UINT nFlags, CPoint point) 
{
	CWnd::OnLButtonDblClk(nFlags, point);
	NMHDR nh;
	nh.hwndFrom = GetParent()->GetSafeHwnd();
	nh.idFrom = GetParent()->GetDlgCtrlID();
	nh.code = NM_DBLCLK;
	GetParent()->GetParent()->PostMessage(WM_NOTIFY, GetParent()->GetDlgCtrlID(), (LPARAM) &nh);
}

void CGfxInCombo::PostNcDestroy() 
{
	CWnd::PostNcDestroy();
	delete this;	
}

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

Comments and Discussions