#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;
#if defined(_WIN32_WCE_POCKETPC)
m_fStyles = LESS_LABEL | LESS_UNDERLINE;
#else
m_fStyles = LESS_LABEL;
#endif
// 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 )
{
CeRect rc;
GetClientRect(&rc);
switch (m_wType)
{
case leEdit:
case leEditLookup:
case leEditNumeric:
if (m_edit)
m_edit.SetWindowPos(HWND_TOP, &rc, SWP_SHOWWINDOW);
break;
case leCombo:
if (m_combo)
m_combo.SetWindowPos(HWND_TOP, &rc, SWP_SHOWWINDOW);
break;
case leDate:
case leTime:
case leTimeInterval:
if (m_date)
m_date.SetWindowPos(HWND_TOP, &rc, SWP_SHOWWINDOW);
break;
}
bHandled = true;
}
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);
#ifndef _WIN32_WCE_POCKETPC
else
dwStyleEx = WS_EX_CLIENTEDGE;
#else
dwStyle |= WS_BORDER;
#endif
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);
}