Click here to Skip to main content
15,885,546 members
Articles / Web Development / HTML

A Comprehensive CE Class Library to Replace ATL and MFC

Rate me:
Please Sign up or sign in to vote.
4.48/5 (14 votes)
4 Oct 2000CPOL 278.7K   998   70  
A collection of classes for CE that do not use ATL or MFC, plus an FTP client, database viewer, and sample application that solves beam deflection equations.
#include "stdafx.h"
#include "CeLabel.h"
#include "CeMisc.h"
#include "CeString.h"

#include <commctrl.h>
#include <wtypes.h>

#ifdef IDC_STATIC
#undef IDC_STATIC
#endif
#define IDC_STATIC		(65535)		// all static controls

/* The VarDateFromStr and VarBstrFromDate functions also accept the
 * VAR_TIMEVALUEONLY and VAR_DATEVALUEONLY flags
 */

#ifndef VAR_TIMEVALUEONLY
#  define VAR_TIMEVALUEONLY       ((DWORD)0x00000001)    /* return time value */
#  define VAR_DATEVALUEONLY       ((DWORD)0x00000002)    /* return date value */
#endif

static TCHAR s_szEmptyText[] = _T("<...>");
static HRESULT (STDAPICALLTYPE *g_pfnVarDateFromStr)(OLECHAR FAR* strIn, LCID lcid, unsigned long dwFlags, DATE FAR* pdateOut) = NULL;
static HRESULT (STDAPICALLTYPE *g_pfnVariantTimeToSystemTime)(double vtime, LPSYSTEMTIME lpSystemTime) = NULL;


///////////////////////////////////////////////////////////////////////////////

class CeDottedBrush
{
public:
	HBRUSH m_hPatternBrush;

	// Create a brush that will be used to draw the dotted lines, this
	// only has to be done once
	CeDottedBrush()
	{
		// Create a dotted monochrome bitmap
		WORD b[8] = { 0xAAAA, 0x5555, 0xAAAA, 0x5555, 0xAAAA, 0x5555, 0xAAAA, 0x5555 };
		HBITMAP hbm = ::CreateBitmap(16, 8, 1, 1, b);

		// Create the brush from the bitmap bits
		m_hPatternBrush = ::CreatePatternBrush(hbm);

		// Delete the bitmap
		::DeleteObject(hbm);
	}

	~CeDottedBrush()
	{
		// Delete the patterned brush
		::DeleteObject(m_hPatternBrush);
	}

	void DrawLine(HDC hDC, POINT ptStart, INT nWidth, COLORREF cr)
	{
		//Dotted lines are drawn using PatBlt() : 

		// Select the patterned brush into the DC
		HBRUSH oldBrush = (HBRUSH) ::SelectObject(hDC, m_hPatternBrush);

		// Draw an horizontal line
		::PatBlt(hDC, ptStart.x, ptStart.y, nWidth, 1, PATCOPY);

	// Clean up
		::SelectObject(hDC, oldBrush);
	}

} dottedbrush;


#define IDC_EDIT_CTRL	101
#define IDC_COMBO_CTRL	102
#define IDC_DATE_CTRL	103

///////////////////////////////////////////////////////////////////////////////

static BOOL LoadProc(FARPROC* pProc, LPCTSTR pszFuncName, LPCTSTR pszLibName)
{
	HINSTANCE hInst = LoadLibrary(pszLibName);
	if (NULL == hInst)
		return FALSE;

	return ((*pProc = GetProcAddress(hInst, pszFuncName)) != NULL);
}


CeLabelEdit::CeLabelEdit(EDITTYPE wType)
{
	m_wType = wType;
	m_bReadOnly = false;
	m_hFont = NULL;
	m_hBuddy = NULL;
	m_bDown = false;
	m_dwCombo = 0;
	m_nCombo = -1;

	m_fStyles = LESS_LABEL;


	// Initialize our one automation function for 2.01 clients,
	// the DLL will stay loaded "forever"
#ifdef _WIN32_WCE
	LoadProc((FARPROC*) &g_pfnVarDateFromStr, _T("VarDateFromStr"), _T(CEPLAT_WCE_OLEAUT32_DLL));
	LoadProc((FARPROC*) &g_pfnVariantTimeToSystemTime, _T("VariantTimeToSystemTime"), _T(CEPLAT_WCE_OLEAUT32_DLL));
#else
	LoadProc((FARPROC*) &g_pfnVarDateFromStr, _T("VarDateFromStr"), _T("oleaut32.dll"));
	LoadProc((FARPROC*) &g_pfnVariantTimeToSystemTime, _T("VariantTimeToSystemTime"), _T("oleaut32.dll"));
#endif
}


///////////////////////////////////////////////////////////////////////////////

BOOL CeLabelEdit::Create(DWORD dwStyle, DWORD dwStyleEx, const RECT& rect, HWND hWndParent, UINT nID, HINSTANCE hInst)
{
	return CeWnd::Create(TEXT(""), hWndParent, rect, _T(""), dwStyle, dwStyleEx, nID, hInst);
}


BOOL CeLabelEdit::ReplaceWindow(UINT nID, HWND hParent, DWORD dwStyle, HINSTANCE hInst)
{
	HWND hCtrl = ::GetDlgItem(hParent, nID);
	if (! hCtrl)
		return FALSE;

	HFONT hFont = (HFONT) ::SendMessage(hCtrl, WM_GETFONT, 0, 0);

	CeRect rc;
	::GetWindowRect(hCtrl, &rc);

	rc.ScreenToClient(hParent);

	// create the window
	BOOL bRet = Create(dwStyle, 0, rc, hParent, nID, hInst);

	// place it in the z-order after the current control
	SetWindowPos(hCtrl, 0, 0, 0, 0, SWP_NOMOVE|SWP_NOSIZE);

	// set the font and text
	CeString str(hCtrl);
	SetFont(hFont, TRUE);
	SetWindowText(str);

	// destroy the old control
	::DestroyWindow(hCtrl);
	return bRet;
}


int CeLabelEdit::OnCreate( LPCREATESTRUCT lpCS, bool& bHandled )
{
	bHandled = true;
	BOOL bRet = CeWnd::OnCreate(lpCS, bHandled);

	if ((m_fStyles & LESS_LABEL) && *lpCS->lpszName == 0 && m_hWnd != NULL)
		SetWindowText(s_szEmptyText);

	return bRet;
}

void CeLabelEdit::OnPaint( bool& bHandled )
{
	bHandled = true;

	PAINTSTRUCT ps;
	HDC hDC = BeginPaint(&ps);

	CeRect rc, rcPaint;
	GetClientRect(&rc);
	rcPaint = rc;

	// get the appropriate background brush for a static control
	HBRUSH hBrush =	(HBRUSH) ::SendMessage(
		GetParent(),
		WM_CTLCOLORSTATIC,
		(WPARAM) hDC,
		(LPARAM) m_hWnd);

	::FillRect(hDC, &rc, hBrush);

	if (! m_bReadOnly && (m_wType != leEdit))
	{
		// note: for the Palmsized PC, the combo box arrow is the width of the
		// scroll bar, for the HPC, I'm not sure, it was square, but the
		// might be the width of the scroll bar on a HPC.
		
		if (m_wType != leEditLookup)
			rc.left = rc.right - rc.Height();
		else
			rc.left = rc.right - (GetSystemMetrics(SM_CYHSCROLL) + 2);

		// keep the rcPaint rectangle off the button we're painting
		rcPaint.right = rc.left - 1;

		rc.top += 2;
		rc.bottom -= 2;
		rc.right -= 2;

		if (m_wType == leEditLookup)
		{
			// now paint a button
			if (m_bDown)
				::DrawFrameControl(hDC, &rc, DFC_SCROLL, DFCS_SCROLLUP|DFCS_PUSHED);
			else
				::DrawFrameControl(hDC, &rc, DFC_SCROLL, DFCS_SCROLLUP);
		}
		else if (m_wType == leTime ||
			m_wType == leTimeInterval ||
			m_wType == leEditNumeric ||
			m_wType == leDate && (GetStyle() & DTS_UPDOWN))
		{
			// paint updown control
			int nSave = rc.bottom;
			rc.bottom -= rc.Height() / 2;
			::DrawFrameControl(hDC, &rc, DFC_SCROLL, DFCS_SCROLLUP);
			rc.top = rc.bottom + 1;
			rc.bottom = nSave;
			::DrawFrameControl(hDC, &rc, DFC_SCROLL, DFCS_SCROLLDOWN);
		}
		else
		{
			// now paint a scroll down button
			::DrawFrameControl(hDC, &rc, DFC_SCROLL, DFCS_SCROLLCOMBOBOX);
		}
	}

	// paint the static control
	rcPaint.left += 4;

	// in the case of a password edit control, paint only the password char
	CeString strText;
	if (m_wType == leEdit && (GetStyle() & ES_PASSWORD))
		strText.Set(_T('*'), 14);
	else
		strText.GetWindowText(m_hWnd);
	
	LOGBRUSH lb;
	COLORREF clr;

	HFONT hOldFont = (HFONT) ::SelectObject(hDC, m_hFont);

	if (! ::GetObject(hBrush, sizeof LOGBRUSH, &lb))
	{
		#ifdef _WIN32_WCE
		clr = GetSysColor(COLOR_STATIC);
		#else
		clr = GetSysColor(COLOR_3DFACE);
		#endif
	}
	else
		clr = lb.lbColor;

	COLORREF clrText = ::SetTextColor(hDC, RGB(0,0,0));
	COLORREF clrBk = ::SetBkColor(hDC, clr);

	if (! m_bReadOnly  && (m_fStyles & LESS_UNDERLINE))
	{
		// underline the text with a dotted-line
		CePoint ptBottomLeft(rcPaint.left-2, rcPaint.bottom-2);
		dottedbrush.DrawLine(hDC, ptBottomLeft, rcPaint.Width()-2, clrText);
		rcPaint.bottom--;
	}

	// paint the text
	::DrawText(hDC, strText, strText.GetLength(), &rcPaint, DT_LEFT|DT_VCENTER|DT_SINGLELINE);

	::SetTextColor(hDC, clrText);
	::SetBkColor(hDC, clrBk);
	::SelectObject(hDC, hOldFont);

	EndPaint(&ps);
}

BOOL CeLabelEdit::OnEraseBkgnd( HDC hDC, bool& bHandled )
{
	bHandled = true;
	return TRUE;
}

void CeLabelEdit::OnSize( UINT nType, int cx, int cy, bool& bHandled )
{
	bHandled = false;
}


void CeLabelEdit::OnLButtonDown( UINT nFlags, POINT point, bool& bHandled )
{
	bHandled = true;
	if (m_edit == GetFocus() && m_wType == leEditLookup)
	{
		::SetCapture(m_hWnd);
		TRACE0("SetCapture\n");
		m_bDown = true;
	}

	SetFocus();
}

void CeLabelEdit::OnLButtonUp( UINT nFlags, POINT point, bool& bHandled )
{
	bHandled = true;
	if (::GetCapture() == m_hWnd)
	{
		::ReleaseCapture();
		TRACE0("ReleaseCapture\n");
		m_bDown = false;

		CeRect rc;
		GetClientRect(&rc);
		rc.left = rc.right - rc.Height();
		rc.top += 2;
		rc.bottom -= 2;
		rc.right -= 2;

		InvalidateRect(&rc);

		OnLookup();
	}
}

void CeLabelEdit::OnMouseMove( UINT nFlags, POINT point, bool& bHandled )
{
	bHandled = true;
	if (::GetCapture() == m_hWnd)
	{
		;
	}
}


BOOL CeLabelEdit::OnCommand(WPARAM wParam, LPARAM lParam, bool& bHandled)
{
	if (lParam)
	{
		PASSTHRU passthru;
		passthru.command.wNotifyCode = HIWORD(wParam);
		passthru.command.wCtrlId = GetDlgCtrlID();
		passthru.command.hwndCtrl = m_hWnd;

		switch (LOWORD(wParam))
		{
		case IDC_EDIT_CTRL:
			if (HIWORD(wParam) == EN_KILLFOCUS)
			{
				TRACE0("EN_KILLFOCUS\n");
				CeString str(m_edit.m_hWnd);
				SetWindowText(str);
				OnControlDestroy(m_edit.m_hWnd);
				m_edit.DestroyWindow();
				InvalidateRect(NULL, TRUE);
				if (m_hBuddy)
				{
					::DestroyWindow(m_hBuddy);
					m_hBuddy = NULL;
				}

				OnChanged();
			}
			else if (HIWORD(wParam) == EN_UPDATE)
			{
				TRACE0("EN_UPDATE\n");
				CeString str(m_edit.m_hWnd);
				SetWindowText(str);

				OnChanged();
			}

			OnPassThru(&passthru);
			break;

		case IDC_DATE_CTRL:
			TRACE1(TEXT("DateTime: OnCommand: %d\n"), HIWORD(wParam));
			break;

		case IDC_COMBO_CTRL:
			if (HIWORD(wParam) == CBN_KILLFOCUS)
			{
				TRACE0("CBN_KILLFOCUS\n");
				CeString str(m_combo.m_hWnd);
				SetWindowText(str);
				OnControlDestroy(m_combo.m_hWnd);
				m_combo.DestroyWindow();
				InvalidateRect(NULL, TRUE);
			}
			else if (HIWORD(wParam) == CBN_SELENDOK)
			{
				TRACE0("CBN_SELENDOK\n");
				CeString str(m_combo.m_hWnd);
				SetWindowText(str);

				OnChanged();
			}

			OnPassThru(&passthru);
			break;
		}
	}

	return CeWnd::OnCommand(wParam, lParam, bHandled);
}


LRESULT CeLabelEdit::OnNotify(int nCtrlId, LPNMHDR pNMH, bool& bHandled)
{
	if (nCtrlId == IDC_DATE_CTRL)
	{
		PASSTHRU passthru;
		passthru.notify.idCtrl = GetDlgCtrlID();
		passthru.notify.pnmh = pNMH;

		switch (pNMH->code)
		{
		case DTN_DROPDOWN:
			TRACE0("DateTime: DTN_DROPDOWN\n");
			m_bDown = true;
			break;

		case DTN_CLOSEUP:
			TRACE0("DateTime: DTN_CLOSEUP\n");
			m_bDown = false;
			m_date.SetFocus();
			break;

		case DTN_DATETIMECHANGE:
			TRACE0("DateTime: DTN_DATETIMECHANGE\n");
			{
				//NMDATETIMECHANGE* pChange = (NMDATETIMECHANGE *) pNMH;
				CeString str(m_date.m_hWnd);
				SetWindowText(str);

				OnChanged();
			}
			break;

		case NM_KILLFOCUS:
			TRACE0("DateTime: KILL_FOCUS\n");
			if (! m_bDown)
			{
				CeString str(m_date.m_hWnd);
				SetWindowText(str);
				OnControlDestroy(m_date.m_hWnd);
				m_date.DestroyWindow();
				InvalidateRect(NULL, TRUE);
				return 0;
			}
			break;
		}

		OnPassThru(&passthru);
	}

	return CeWnd::OnNotify(nCtrlId, pNMH, bHandled);
}



LRESULT CeLabelEdit::OnMessage(UINT uMsg, WPARAM wParam, LPARAM lParam, bool& bHandled)
{
	switch (uMsg)
	{
	case WM_CTLCOLOREDIT:
	case WM_CTLCOLORBTN:
	case WM_CTLCOLORDLG:
	case WM_CTLCOLORSCROLLBAR:
	case WM_CTLCOLORSTATIC:
		bHandled = true;
		return Default();

	case WM_CTLCOLORLISTBOX:
		bHandled = true;
		return Default();

	case WM_SETFONT:
		bHandled = true;
		m_hFont = (HFONT) wParam;
		break;

	case WM_GETFONT:
		bHandled = true;
		return (LRESULT) m_hFont;

	case WM_SETFOCUS:
		OnSetFocus((HWND) wParam, bHandled);
		break;

	case WM_KILLFOCUS:
		OnKillFocus((HWND) wParam, bHandled);
		break;

	case WM_SETTEXT:
		if ( *((LPCTSTR)lParam) == 0 && (m_fStyles & LESS_LABEL))
		{
			SetWindowText(s_szEmptyText);
			bHandled = true;
		}
		Invalidate(FALSE);
		break;

	default:
		break;
	}

	return 0;
}


void CeLabelEdit::OnKillFocus(HWND hNewWnd, bool& bHandled)
{
	TRACE0("CeLabelEdit: OnKillFocus\n");
	bHandled = false;
}


void CeLabelEdit::OnSetFocus(HWND hOldWnd, bool& bHandled)
{
	TRACE0("OnSetFocus()\n");

	if (m_bReadOnly)
		return;

	CeString strVal(m_hWnd);

	CeRect rc, rcTmp;
	GetClientRect(&rc);

	bHandled = true;

	// use the lower bits of the control style for actual control
	DWORD dwStyle = GetStyle() & 0xffff;
	// add basic styles we need
	dwStyle |= (WS_CHILD|WS_TABSTOP);

	HWND hControl = NULL;

	switch (m_wType)
	{
	case leEdit:
	case leEditLookup:
	case leEditNumeric:
		if (! m_edit.m_hWnd)
		{
			DWORD dwStyleEx = 0;

			if (m_bReadOnly)
				rc.DeflateRect(2, 2);
			else
				dwStyleEx = WS_EX_CLIENTEDGE;

			if (m_wType == leEditLookup)
				rc.right -= (rc.Height() + 2);

			m_edit.Create(strVal, dwStyle, dwStyleEx, rc, m_hWnd, IDC_EDIT_CTRL);
			m_edit.SetFont(m_hFont, TRUE);
			m_edit.SetWindowText(strVal);
		}

		m_edit.SetReadOnly(m_bReadOnly);
		m_edit.SetSel(0, -1);

		hControl = m_edit.m_hWnd;
		break;

	case leCombo:
		if (! m_combo.m_hWnd)
		{
			DWORD dwStyleEx = 0;
			m_combo.Create(strVal, dwStyle, dwStyleEx, rc, m_hWnd, IDC_COMBO_CTRL);
			m_combo.SetFont(m_hFont, TRUE);
		}

		rc.bottom += 60;

		hControl = m_combo.m_hWnd;
		break;

	case leDate:
	case leTime:
	case leTimeInterval:

		if (! m_date.m_hWnd)
		{
			DWORD dwStyleEx = 0;
			dwStyleEx = WS_EX_CLIENTEDGE;

			m_date.Create(strVal, dwStyle, dwStyleEx, rc, m_hWnd, IDC_DATE_CTRL);
			m_date.SetFont(m_hFont, TRUE);
			m_date.SetMonthCalFont(m_hFont, TRUE);

			if (strVal.IsEmpty() && (GetStyle() & DTS_SHOWNONE))
				m_date.SetSystemtime(GDT_NONE, NULL);
			else
			{
				DATE date;
				HRESULT hr;
#ifdef _WIN32_WCE
				if (m_wType == leDate)
					hr = g_pfnVarDateFromStr((LPWSTR)(LPCWSTR)strVal, LANG_SYSTEM_DEFAULT, VAR_DATEVALUEONLY, &date);
				else
					hr = g_pfnVarDateFromStr((LPTSTR)(LPCTSTR)strVal, LANG_SYSTEM_DEFAULT, VAR_TIMEVALUEONLY, &date);
#endif
				SYSTEMTIME st;
				g_pfnVariantTimeToSystemTime(date, &st);
				m_date.SetSystemtime(GDT_VALID, &st);
			}
		}

		switch (m_wType)
		{
		case leTimeInterval:	m_date.SetFormat(_T("H: mm"));	break;
		case leTime:			m_date.SetFormat(_T("hh: mm tt"));	break;
		case leDate:			m_date.SetFormat(_T("dd/MM/yyy"));	break;
		}

		hControl = m_date.m_hWnd;
		break;
	}

	// allow virtual override or parent to fill the control with
	// data or set style values before the control is displayed
	OnControlCreate(hControl);

	switch (m_wType)
	{
	case leEdit:
	case leEditLookup:
	case leEditNumeric:
		m_edit.SetWindowPos(HWND_TOP, &rc, SWP_SHOWWINDOW);
		m_edit.SetFocus();

		if (m_wType == leEditNumeric)
			AddSpinner();
		break;

	case leCombo:
		{
			m_combo.SetWindowPos(HWND_TOP, &rc, SWP_SHOWWINDOW);
			m_combo.SetFocus();

			// find the curent selection
			int nSel = 0;
			if (!strVal.IsEmpty())
				nSel = m_combo.FindStringExact(-1, strVal);
			m_combo.SetCurSel(nSel);

			// popdown the lookup list
			m_combo.ShowDropDown();
		}
		break;

	case leDate:
	case leTime:
	case leTimeInterval:
		m_date.SetWindowPos(HWND_TOP, &rc, SWP_SHOWWINDOW);
		m_date.SetFocus();
		break;
	}
}


BOOL CeLabelEdit::AddSpinner()
{
	if (NULL != m_hBuddy)
		return FALSE;

	DWORD dwStyles = WS_CHILD | WS_BORDER |	WS_VISIBLE |
		UDS_WRAP |
		UDS_ALIGNRIGHT |
		UDS_ARROWKEYS |
		UDS_AUTOBUDDY |
		UDS_SETBUDDYINT;

	HINSTANCE hInst = CeGetAppInstance();
	
	m_hBuddy = ::CreateWindowEx(0, UPDOWN_CLASS,
		NULL, dwStyles, 0, 0, 16, 16, m_hWnd,
		(HMENU)IDC_STATIC, hInst, NULL);
	
	if (! m_hBuddy)
		return FALSE;

	// place immediately after this window in the tab order
	//::SetWindowPos(m_hBuddy, m_edit.m_hWnd, 0, 0, 0, 0, SWP_NOMOVE|SWP_NOSIZE);

	return TRUE;
}


void CeLabelEdit::OnControlCreate(HWND hControl)
{
	::SendMessage(GetParent(), WM_COMMAND,
		MAKEWPARAM(GetDlgCtrlID(), LEN_CONTROLCREATE), (LPARAM) hControl);
}

void CeLabelEdit::OnControlDestroy(HWND hControl)
{
	::SendMessage(GetParent(), WM_COMMAND,
		MAKEWPARAM(GetDlgCtrlID(), LEN_CONTROLDESTROY), (LPARAM) hControl);
}

void CeLabelEdit::OnLookup()
{
	::SendMessage(GetParent(), WM_COMMAND,
		MAKEWPARAM(GetDlgCtrlID(), LEN_LOOKUP), (LPARAM) m_hWnd);
}

LPARAM CeLabelEdit::OnPassThru(PASSTHRU* pPassThru)
{
	::SendMessage(GetParent(), WM_COMMAND,
		MAKEWPARAM(GetDlgCtrlID(), LEN_PASSTHRU), (LPARAM) pPassThru);
	return 0;
}

void CeLabelEdit::OnChanged()
{
	::SendMessage(GetParent(), WM_COMMAND,
		MAKEWPARAM(GetDlgCtrlID(), LEN_CHANGED), (LPARAM) m_hWnd);
}

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 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