/////////////////////////////////////////////////////////////////////////////////////////
// Project: SP Numeric Edit Control 1.0
//
// File: NumericEditCore.h
//
// Developer(s): Sergei Pavlovsky
// sergei_vp@hotmail.com
// Copyright (c) 2004
//
// Description: Interface for CCoreFormatter class
// Declaration of CCoreNumericEdit class template.
//
// Platforms: Win32
//
// This code may be used in compiled form in any way you desire. This file may be
// redistributed unmodified by any means PROVIDING it is not sold for profit without
// the authors written consent, and providing that this notice and the authors name
// is included. If the source code in this file is used in any commercial application
// then acknowledgement must be made to the author of this file (in whatever form
// you wish).
//
// 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.
/////////////////////////////////////////////////////////////////////////////////////////
#pragma once
#include "resource.h"
#include "SpDataFormatter.h"
/////////////////////////////////////////////////////////////////////////////////////////
// Types
/////////////////////////////////////////////////////////////////////////////////////////
enum FormatModeEnum
{
FM_NON = 0x00000000,
FM_DISPLAY = 0x00000001,
FM_EDITING = 0x00000002
};
/////////////////////////////////////////////////////////////////////////////////////////
// CCoreFormatter class
/////////////////////////////////////////////////////////////////////////////////////////
class CCoreFormatter
{
// Constants
private:
enum StateMasksEnum
{
SM_SIZE = 0x00ff,
SM_STATE = 0xff00
};
enum StatesEnum
{
FS_USECUSTOMDISPLAYMASK = 0x0100,
FS_USECUSTOMEDITINGMASK = 0x0200
};
// Types
public:
struct PROPERTY
{
PROPERTY()
{
}
PROPERTY(SP::CDataFormatter::PropertiesEnum enID,
LPCTSTR lpcszValue)
: m_enID(enID),
m_sValue(lpcszValue)
{
}
PROPERTY(SP::CDataFormatter::PropertiesEnum enID,
LPCTSTR lpcValue, UINT_PTR cchValue)
: m_enID(enID),
m_sValue(lpcValue, cchValue)
{
}
SP::CDataFormatter::PropertiesEnum m_enID;
tstring m_sValue;
};
typedef std::vector<PROPERTY> CPropertyVector;
// Construction & destruction
public:
CCoreFormatter()
: m_fState(0),
m_pDisplayFmt(NULL),
m_pEditingFmt(NULL)
{
}
~CCoreFormatter()
{
if ( m_pDisplayFmt )
m_pDisplayFmt->Release();
if ( m_pEditingFmt )
m_pEditingFmt->Release();
}
// Helpers: Formatter configuration
private:
static BOOL SetDefaultMask(SP::CDataFormatter* pcFormatter, DWORD fOptions);
const SP::CDataFormatter* GetFmtForMode(FormatModeEnum enMode) const
{
switch( enMode )
{
case FM_DISPLAY:
return m_pDisplayFmt;
case FM_EDITING:
return m_pEditingFmt;
}
return NULL;
}
SP::CDataFormatter* GetFmtForMode(FormatModeEnum enMode)
{
switch( enMode )
{
case FM_DISPLAY:
return m_pDisplayFmt;
case FM_EDITING:
return m_pEditingFmt;
}
return NULL;
}
void SetUseCustomMaskFlag(FormatModeEnum enMode, BOOL bValue)
{
WORD wFlag;
switch( enMode )
{
case FM_DISPLAY:
wFlag = FS_USECUSTOMDISPLAYMASK;
break;
case FM_EDITING:
wFlag = FS_USECUSTOMEDITINGMASK;
break;
default:
return;
}
if ( bValue )
m_fState |= wFlag;
else
m_fState &= (~wFlag);
}
// Helpes: Value
private:
void SetValueSize(size_t size)
{
ATLASSERT( size <= 0xff );
m_fState &= (~SM_SIZE);
m_fState |= WORD(size);
}
WORD GetState() const
{
return m_fState & SM_STATE;
}
// Operations: Value
private:
void UpdateValueTypeParams(SP::CDataFormatter::TypeEnum enType);
static DWORD GetMaskCompositionOptions(FormatModeEnum enMode)
{
switch ( enMode )
{
case FM_DISPLAY:
return 0;
case FM_EDITING:
return SP::CDataFormatter::CMO_OPTFRACTIONPART|
SP::CDataFormatter::CMO_OPTEXPONENTPART;
}
return 0;
}
// Utilities: Formatter configuration
private:
static SP::CDataFormatter* CreateDisplayFormatter(
SP::CDataFormatter::TypeEnum enType, DWORD fTraits,
const PROPERTY* rgFmtProps = NULL,
UINT_PTR cchFmtProps = 0,
LPCTSTR lpcszMask = NULL);
static SP::CDataFormatter* CreateEditingFormatter(
SP::CDataFormatter::TypeEnum enType, DWORD fTraits,
const PROPERTY* rgFmtProps = NULL,
UINT_PTR cchFmtProps = 0,
LPCTSTR lpcszMask = NULL);
// Utilities: Formatter configuration
public:
static BOOL IsPropertyUsed(SP::CDataFormatter::TypeEnum enType, DWORD fTraits,
SP::CDataFormatter::PropertiesEnum enProperty);
// Operations: Formatter configuration
public:
BOOL Configure(SP::CDataFormatter::TypeEnum enType, DWORD fFmtTraits,
const PROPERTY* rgDisplayFmtProps = NULL,
UINT_PTR cchDisplayFmtProps = 0,
LPCTSTR lpcszDisplayMask = NULL,
const PROPERTY* rgEditingFmtProps = NULL,
UINT_PTR cchEditingFmtProps = 0,
LPCTSTR lpcszEditingMask = NULL);
void Unconfigure()
{
ATLASSERT( m_pDisplayFmt && m_pEditingFmt);
m_pDisplayFmt->Release();
m_pDisplayFmt = NULL;
m_pEditingFmt->Release();
m_pEditingFmt = NULL;
m_fState = 0;
}
BOOL IsConfigured() const
{
ATLASSERT( (m_pDisplayFmt && m_pEditingFmt) ||
(!m_pDisplayFmt && !m_pEditingFmt) );
return m_pDisplayFmt != NULL;
}
// Operations: Formatting
public:
UINT_PTR FormatDisplayText(const void* lpcValue, LPTSTR lpBuffer,
UINT_PTR cchBuffer) const
{
ATLASSERT( !lpcValue || !::IsBadReadPtr(lpcValue, GetDataSize()) );
ATLASSERT( !::IsBadWritePtr(lpBuffer, cchBuffer * sizeof(TCHAR)) );
ATLASSERT( m_pDisplayFmt );
return m_pDisplayFmt->Format(lpcValue, lpBuffer, cchBuffer);
}
UINT_PTR FormatEditingText(const void* lpcValue, LPTSTR lpBuffer,
UINT_PTR cchBuffer) const
{
ATLASSERT( !lpcValue || !::IsBadReadPtr(lpcValue, GetDataSize()) );
ATLASSERT( !::IsBadWritePtr(lpBuffer, cchBuffer * sizeof(TCHAR)) );
ATLASSERT( m_pEditingFmt );
return m_pEditingFmt->Format(lpcValue, lpBuffer, cchBuffer);
}
BOOL ScanEditingText(LPCTSTR lpszText, UINT_PTR cchText, void* lpValue,
BOOL* pbIsValid, BOOL* pbIsNull) const
{
ATLASSERT( !::IsBadReadPtr(lpszText, cchText * sizeof(TCHAR)) );
ATLASSERT( !::IsBadWritePtr(lpValue, GetDataSize()) );
ATLASSERT( !::IsBadWritePtr(pbIsNull, sizeof(BOOL)) );
ATLASSERT( !::IsBadWritePtr(pbIsValid, sizeof(BOOL)) );
ATLASSERT( m_pEditingFmt );
// Read value from text
bool bIsNotNull;
UINT_PTR unResult = m_pEditingFmt->Scan(lpszText, cchText,
lpValue, &bIsNotNull);
ATLASSERT( unResult != SP::CDataFormatter::ERROR_FAIL );
if ( unResult == SP::CDataFormatter::ERROR_FAIL )
{
SP::AccountError(SP::AE_LOG, IDS_ELS_SPCONVERSION, 0,
IDS_ERCW_SCANNINGTEXT);
return FALSE;
}
*pbIsValid = unResult == SP::CDataFormatter::STATUS_TRUE;
*pbIsNull = !bIsNotNull;
return TRUE;
}
// Accessors & mutators
public:
SP::CDataFormatter::TypeEnum GetType() const
{
ATLASSERT( IsConfigured() );
return m_pDisplayFmt->GetType();
}
DWORD GetTraits() const
{
ATLASSERT( IsConfigured() );
return m_pDisplayFmt->GetTraits();
}
SIZE_T GetDataSize() const
{
ATLASSERT( IsConfigured() );
return SIZE_T(m_fState & SM_SIZE);
}
BOOL IsPropertyUserValue(FormatModeEnum enMode,
SP::CDataFormatter::PropertiesEnum enID) const
{
ATLASSERT( IsConfigured() );
ATLASSERT( GetFmtForMode(enMode) );
return GetFmtForMode(enMode)->IsPropertyUserValue(enID);
}
UINT_PTR GetPropertyValue(FormatModeEnum enMode,
SP::CDataFormatter::PropertiesEnum enID,
LPTSTR lpBuf, UINT_PTR cchBuf) const
{
ATLASSERT( IsConfigured() );
ATLASSERT( GetFmtForMode(enMode) );
return GetFmtForMode(enMode)->GetProperty(enID, lpBuf, cchBuf);
}
BOOL SetPropertyValue(FormatModeEnum enMode,
SP::CDataFormatter::PropertiesEnum enID,
LPCTSTR lpcValue, UINT_PTR cchValue)
{
ATLASSERT( IsConfigured() );
ATLASSERT( GetFmtForMode(enMode) );
return GetFmtForMode(enMode)->SetProperty(enID, lpcValue, cchValue);
}
void DiscardPropertyUserValue(FormatModeEnum enMode,
SP::CDataFormatter::PropertiesEnum enID)
{
ATLASSERT( IsConfigured() );
ATLASSERT( GetFmtForMode(enMode) );
GetFmtForMode(enMode)->DiscardPropertyUserValue(enID);
}
BOOL IsMaskCustomized(FormatModeEnum enMode) const
{
ATLASSERT( IsConfigured() );
switch( enMode )
{
case FM_DISPLAY:
return m_fState & FS_USECUSTOMDISPLAYMASK;
case FM_EDITING:
return m_fState & FS_USECUSTOMEDITINGMASK;
}
return FALSE;
}
BOOL DiscardCustomizedMask(FormatModeEnum enMode)
{
ATLASSERT( IsConfigured() );
BOOL bResult = SetDefaultMask(GetFmtForMode(enMode),
GetMaskCompositionOptions(enMode));
if ( bResult )
{
SetUseCustomMaskFlag(enMode, FALSE);
}
return bResult;
}
UINT_PTR GetMask(FormatModeEnum enMode, LPTSTR lpszMask, UINT_PTR cchMask) const
{
ATLASSERT( IsConfigured() );
ATLASSERT( GetFmtForMode(enMode) );
return GetFmtForMode(enMode)->GetMask(lpszMask, cchMask);
}
// Data members
private:
WORD m_fState;
SP::CDataFormatter* m_pDisplayFmt;
SP::CDataFormatter* m_pEditingFmt;
};
/////////////////////////////////////////////////////////////////////////////////////////
// CCoreNumericEditEvents class
/////////////////////////////////////////////////////////////////////////////////////////
class CCoreNumericEditEventSink
{
// Event
public:
virtual void _OnModified() = 0;
virtual BOOL _OnValueChanging(const void* lpcNewValue, BOOL bValid) = 0;
virtual void _OnValueChanged() = 0;
virtual void _OnError() = 0;
};
/////////////////////////////////////////////////////////////////////////////////////////
// CCoreNumericEdit class template
/////////////////////////////////////////////////////////////////////////////////////////
template < class TWindow, class TFormatter, class TParams >
class CCoreNumericEdit : public TParams,
public TWindow
{
// Constants
private:
enum ValueStatusesEnum
{
VS_VALUENULL = 0x0001,
VS_VALUEVALID = 0x0002
};
// Types
private:
union Numeric
{
char Int8;
unsigned char UInt8;
short Int16;
unsigned short UInt16;
int Int32;
unsigned int UInt32;
__int64 Int64;
unsigned __int64 UInt64;
float Float;
double Double;
};
// Construction & destruction
protected:
CCoreNumericEdit()
: m_fVlaueStatus(VS_VALUENULL|VS_VALUEVALID),
m_lpszEditText(NULL),
m_hbrBkg(NULL),
m_pEventSink(NULL)
{
::ZeroMemory(m_rgValue, sizeof(Numeric));
}
~CCoreNumericEdit(void)
{
if ( m_hbrBkg )
::DeleteObject(m_hbrBkg);
free(m_lpszEditText);
}
// Helpers
private:
BOOL IsSameValue(const BYTE* lpcValue, WORD fValueStatus) const
{
ATLASSERT( m_formatter.IsConfigured() );
ATLASSERT( !lpcValue || !::IsBadReadPtr(lpcValue, m_formatter.GetDataSize()) );
if ( fValueStatus != m_fVlaueStatus )
return FALSE;
if ( IsValueValid() && !IsValueNull() )
{
const SIZE_T sizeValue = m_formatter.GetDataSize();
for ( SIZE_T i = 0; i < sizeValue; i++ )
{
if ( lpcValue[i] != m_rgValue[i] )
return FALSE;
}
}
return TRUE;
}
BOOL SetEditingText()
{
ATLASSERT( IsWindow() );
if ( IsValueValid() )
{
UINT_PTR cchText = GetEditingText(NULL, 0);
ATLASSERT( cchText != SP::CDataFormatter::ERROR_FAIL );
if ( cchText == SP::CDataFormatter::ERROR_FAIL )
{
SP::AccountError(SP::AE_LOG, IDS_ELS_SPNUMERICEDITBOX, 0,
IDS_ERCW_FORMATEDITINGTEXT);
return FALSE;
}
BOOL bResult = ReallocEditTextBuf(cchText);
ATLASSERT( bResult );
if ( !bResult )
return FALSE;
cchText = GetEditingText(m_lpszEditText, cchText);
ATLASSERT( cchText != SP::CDataFormatter::ERROR_FAIL );
if ( cchText == SP::CDataFormatter::ERROR_FAIL )
{
SP::AccountError(SP::AE_LOG, IDS_ELS_SPNUMERICEDITBOX, 0,
IDS_ERCW_FORMATEDITINGTEXT);
return FALSE;
}
m_lpszEditText[cchText] = _T('\x0');
}
// Set text in the control
SetWindowText(m_lpszEditText);
return TRUE;
}
BOOL SetDisplayText()
{
ATLASSERT( m_formatter.IsConfigured() );
ATLASSERT( IsWindow() );
if ( IsValueValid() )
{
UINT_PTR cchText = GetDisplayText(NULL, 0);
ATLASSERT( cchText != SP::CDataFormatter::ERROR_FAIL );
if ( cchText == SP::CDataFormatter::ERROR_FAIL )
{
SP::AccountError(SP::AE_LOG, IDS_ELS_SPNUMERICEDITBOX, 0,
IDS_ERCW_FORMATDISPLAYTEXT);
return FALSE;
}
BOOL bResult = ReallocEditTextBuf(cchText);
ATLASSERT( bResult );
if ( !bResult )
return FALSE;
cchText = GetDisplayText(m_lpszEditText, cchText);
ATLASSERT( cchText != SP::CDataFormatter::ERROR_FAIL );
if ( cchText == SP::CDataFormatter::ERROR_FAIL )
{
SP::AccountError(SP::AE_LOG, IDS_ELS_SPNUMERICEDITBOX, 0,
IDS_ERCW_FORMATDISPLAYTEXT);
return FALSE;
}
m_lpszEditText[cchText] = _T('\x0');
// Set text in the control
SetWindowText(m_lpszEditText);
}
else
{
UINT_PTR cchText = GetDisplayText(NULL, 0);
ATLASSERT( cchText != SP::CDataFormatter::ERROR_FAIL );
if ( cchText == SP::CDataFormatter::ERROR_FAIL )
{
SP::AccountError(SP::AE_LOG, IDS_ELS_SPNUMERICEDITBOX, 0,
IDS_ERCW_FORMATDISPLAYTEXT);
return FALSE;
}
LPTSTR lpszText = (LPTSTR)_alloca((cchText + 1) * sizeof(TCHAR));
cchText = GetDisplayText(lpszText, cchText);
ATLASSERT( cchText != SP::CDataFormatter::ERROR_FAIL );
if ( cchText == SP::CDataFormatter::ERROR_FAIL )
{
SP::AccountError(SP::AE_LOG, IDS_ELS_SPNUMERICEDITBOX, 0,
IDS_ERCW_FORMATDISPLAYTEXT);
return FALSE;
}
lpszText[cchText] = _T('\x0');
// Set text in the control
SetWindowText(lpszText);
}
return TRUE;
}
BOOL SaveEditText() const
{
ATLASSERT( IsWindow() );
// Save edit text
int cchText = GetWindowTextLength();
BOOL bResult = ReallocEditTextBuf(cchText);
ATLASSERT( bResult );
if ( !bResult )
return FALSE;
GetWindowText(m_lpszEditText, cchText + 1);
return TRUE;
}
BOOL ScanValue() const
{
ATLASSERT( m_formatter.IsConfigured() );
ATLASSERT( IsWindow() );
const SIZE_T sizeValue = m_formatter.GetDataSize();
WORD fNewVlaueState = 0;
BYTE rgNewValue[sizeof(Numeric)];
BOOL bIsValid;
BOOL bIsNull;
// Read value from control
if ( !m_formatter.ScanEditingText(m_lpszEditText, _tcslen(m_lpszEditText),
rgNewValue, &bIsValid, &bIsNull) )
{
SP::AccountError(SP::AE_LOG, IDS_ELS_SPNUMERICEDITBOX, 0,
IDS_ERCW_SCANEDITINGTEXT);
return FALSE;
}
if ( bIsValid )
fNewVlaueState |= VS_VALUEVALID;
if ( bIsNull )
fNewVlaueState |= VS_VALUENULL;
// Assign new value
if ( !IsSameValue(rgNewValue, fNewVlaueState) )
{
if ( m_pEventSink )
{
// Fire OnValueChanging
if ( m_pEventSink->_OnValueChanging(bIsNull ? NULL : rgNewValue,
bIsValid) )
{
// Set new value
m_fVlaueStatus = fNewVlaueState;
CopyMemory(m_rgValue, rgNewValue, sizeValue);
// Fire OnValueChanged
m_pEventSink->_OnValueChanged();
}
}
else
{
// Set new value
m_fVlaueStatus = fNewVlaueState;
CopyMemory(m_rgValue, rgNewValue, sizeValue);
}
}
return TRUE;
}
// Operations
public:
BOOL BeginEdit()
{
ATLASSERT( IsWindow() );
if ( m_formatter.IsConfigured() )
{
// Set editing text
BOOL bResult = SetEditingText();
ATLASSERT( bResult );
if ( !bResult )
{
SP::AccountError(SP::AE_LOG, IDS_ELS_SPNUMERICEDITBOX, 0,
IDS_ERCW_SETEDITINGTEXT);
return FALSE;
}
// Change state
_SetEditing(TRUE);
}
// Update modified flag
SendMessage(EM_SETMODIFY, _GetModify());
return TRUE;
}
BOOL EndEdit()
{
if ( m_formatter.IsConfigured() )
{
BOOL bResult;
// Save text edit control
if ( _GetEditing() )
{
bResult = SaveEditText();
ATLASSERT( bResult );
// Change state
_SetEditing(FALSE);
if ( !bResult )
{
SP::AccountError(SP::AE_LOG, IDS_ELS_SPNUMERICEDITBOX, 0,
IDS_ERCW_SAVEEDITTEXT);
return FALSE;
}
}
// Get user value
bResult = ScanValue();
ATLASSERT( bResult );
if ( !bResult )
{
SP::AccountError(SP::AE_LOG, IDS_ELS_SPNUMERICEDITBOX, 0,
IDS_ERCW_SCANEDITTEXT);
return FALSE;
}
// Update display text
bResult = SetDisplayText();
ATLASSERT( bResult );
if ( !bResult )
{
SP::AccountError(SP::AE_LOG, IDS_ELS_SPNUMERICEDITBOX, 0,
IDS_ERCW_SETDISPLAYTEXT);
return FALSE;
}
}
return TRUE;
}
// Operations: Event Sink
public:
void AdviseEventSink(CCoreNumericEditEventSink* pEventSink)
{
ATLASSERT( pEventSink );
ATLASSERT( !m_pEventSink );
m_pEventSink = pEventSink;
}
void UnadviseEventSink()
{
ATLASSERT( m_pEventSink );
m_pEventSink = NULL;
}
// Event handlers
public:
void _OnAppearanceChanged()
{
ATLTRACE( _T("CCoreNumericEdit::_OnAppearanceChanged\n") );
if ( IsWindow() )
{
UpdateWindowStyles(MES_APPEARANCE);
}
}
void _OnBorderVisibleChanged()
{
ATLTRACE( _T("CCoreNumericEdit::_OnBorderVisibleChanged\n") );
if ( IsWindow() )
{
UpdateWindowStyles(MES_BORDER);
}
}
void _OnAlignmentChanged()
{
ATLTRACE( _T("CCoreNumericEdit::_OnAlignmentChanged\n") );
if ( IsWindow() )
{
UpdateWindowStyles(MES_ALIGNMENT);
}
}
void _OnForeColorChanged()
{
ATLTRACE( _T("CCoreNumericEdit::_OnForeColorChanged\n") );
if ( IsWindow() && !_GetReadOnly() )
{
InvalidateRect(NULL);
}
}
void _OnBackColorChanged()
{
ATLTRACE( _T("CCoreNumericEdit::_OnBackColorChanged\n") );
if ( IsWindow() && !_GetReadOnly() )
{
if ( m_hbrBkg )
::DeleteObject(m_hbrBkg);
m_hbrBkg = ::CreateSolidBrush(_GetBackColor());
InvalidateRect(NULL);
}
}
void _OnReadOnlyForeColorChanged()
{
ATLTRACE( _T("CCoreNumericEdit::_OnReadOnlyForeColorChanged\n") );
if ( IsWindow() && _GetReadOnly() )
{
InvalidateRect(NULL);
}
}
void _OnReadOnlyBackColorChanged()
{
ATLTRACE( _T("CCoreNumericEdit::_OnReadOnlyBackColorChanged\n") );
if ( IsWindow() && _GetReadOnly() )
{
if ( m_hbrBkg )
::DeleteObject(m_hbrBkg);
m_hbrBkg = ::CreateSolidBrush(_GetReadOnlyBackColor());
InvalidateRect(NULL);
}
}
void _OnFontChanging()
{
ATLTRACE( _T("CCoreNumericEdit::_OnFontChanging\n") );
if ( IsWindow() )
{
HFONT hFont = GetFont();
if ( hFont )
{
SetFont(NULL, FALSE);
_FreeFontHandle(hFont);
}
}
}
void _OnFontChanged()
{
ATLTRACE( _T("CCoreNumericEdit::_OnFontChanged\n") );
if ( IsWindow() )
{
if ( HFONT hFont = _GetFontHandle() )
SetFont(hFont, TRUE);
InvalidateRect(NULL);
}
}
void _OnReadOnlyChanged()
{
ATLTRACE( _T("CCoreNumericEdit::_OnReadOnlyChanged\n") );
if ( IsWindow() )
{
UpdateReadOnly(_GetReadOnly());
}
}
void _OnRightToLeftChanged()
{
ATLTRACE( _T("CCoreNumericEdit::_OnRightToLeftChanged\n") );
if ( IsWindow() )
{
UpdateWindowStyles(MES_RIGHTTOLEFT);
}
}
void _OnErrorSymbolChanged()
{
ATLTRACE( _T("CCoreNumericEdit::_OnErrorSymbolChanged\n") );
if ( IsWindow() && !_GetEditing() && !IsValueValid() )
{
SetDisplayText();
}
}
void _OnFormatterChanged(BOOL bValueTypeChanged)
{
ATLTRACE( _T("CCoreNumericEdit::_OnFormatterChanged\n") );
// Update current text
if ( IsWindow() )
{
if ( bValueTypeChanged )
{
m_fVlaueStatus = VS_VALUENULL|VS_VALUEVALID;
}
UpdateReadOnly(_GetReadOnly() || !m_formatter.IsConfigured());
BOOL bResult;
if ( _GetEditing() )
bResult = SetEditingText();
else
bResult = SetDisplayText();
ATLASSERT( bResult );
if ( !bResult && m_pEventSink )
{
const UINT nErrID = _GetEditing() ? IDS_ERCW_SETEDITINGTEXT
: IDS_ERCW_SETDISPLAYTEXT;
SP::AccountError(SP::AE_LOG, IDS_ELS_SPNUMERICEDITBOX, 0, nErrID);
m_pEventSink->_OnError();
}
}
}
void _OnModifyChanged()
{
ATLTRACE( _T("CCoreNumericEdit::_OnModifyChanged\n") );
}
void _OnValueChanged()
{
ATLTRACE( _T("CCoreNumericEdit::_OnValueChanged\n") );
// Update current text
if ( IsWindow() )
{
BOOL bResult;
if ( _GetEditing() )
bResult = SetEditingText();
else
bResult = SetDisplayText();
ATLASSERT( bResult );
if ( !bResult && m_pEventSink )
{
const UINT nErrID = _GetEditing() ? IDS_ERCW_SETEDITINGTEXT
: IDS_ERCW_SETDISPLAYTEXT;
SP::AccountError(SP::AE_LOG, IDS_ELS_SPNUMERICEDITBOX, 0, nErrID);
m_pEventSink->_OnError();
}
}
}
// Operations: Window
public:
void DefineWindowStyles(DWORD* pdwStyle, DWORD* pdwStyleEx, DWORD fProperties) const
{
ATLASSERT( !::IsBadReadPtr(pdwStyle, sizeof(DWORD)) );
ATLASSERT( !::IsBadReadPtr(pdwStyleEx, sizeof(DWORD)) );
// Set Autoscroll
*pdwStyle |= ES_AUTOHSCROLL;
// Set border
if ( fProperties & MES_BORDER )
{
const DWORD fBorderMask = WS_BORDER;
const DWORD fBorderMaskEx = WS_EX_CLIENTEDGE|WS_EX_STATICEDGE;
*pdwStyle &= (~fBorderMask);
*pdwStyleEx &= (~fBorderMaskEx);
if ( _GetBorderVisible() )
{
switch ( _GetAppearance() )
{
case acFlat:
*pdwStyle |= WS_BORDER;
break;
case ac3D:
*pdwStyleEx |= WS_EX_CLIENTEDGE;
break;
case acSoft:
*pdwStyleEx |= WS_EX_STATICEDGE;
break;
}
}
}
// Set Text alignment
if ( fProperties & MES_ALIGNMENT )
{
const DWORD fAlignmentMask = ES_LEFT|ES_CENTER|ES_RIGHT;
*pdwStyle &= (~fAlignmentMask);
switch ( _GetAlignment() )
{
case alGeneral:
*pdwStyle |= ES_RIGHT;
break;
case alLeft:
*pdwStyle |= ES_LEFT;
break;
case alCenter:
*pdwStyle |= ES_CENTER;
break;
case alRight:
*pdwStyle |= ES_RIGHT;
break;
}
}
// Set ReadOnly
if ( fProperties & MES_READONLY )
{
if ( _GetReadOnly() || !m_formatter.IsConfigured() )
*pdwStyle |= ES_READONLY;
else
*pdwStyle &= (~ES_READONLY);
}
// Set RightToLeft
if ( fProperties & MES_RIGHTTOLEFT)
{
if ( _GetRightToLeft() )
{
*pdwStyleEx &= (~WS_EX_LTRREADING);
*pdwStyleEx |= WS_EX_RTLREADING;
}
else
{
*pdwStyleEx &= (~WS_EX_RTLREADING);
*pdwStyleEx |= WS_EX_LTRREADING;
}
}
}
void UpdateWindowStyles(DWORD fProperties)
{
ATLASSERT( IsWindow() );
// Get current window styles
DWORD dwStyle = GetWindowLong(GWL_STYLE);
DWORD dwStyleEx = GetWindowLong(GWL_EXSTYLE);
// Correct styles
DefineWindowStyles(&dwStyle, &dwStyleEx, fProperties);
// Update window styles
SetWindowLong(GWL_STYLE, dwStyle);
SetWindowLong(GWL_EXSTYLE, dwStyleEx);
// Redraw window
if ( fProperties & (MES_BORDER|MES_APPEARANCE) )
{
const DWORD fOptions = SWP_NOSIZE|SWP_NOMOVE|SWP_NOZORDER|
SWP_NOACTIVATE|SWP_FRAMECHANGED;
SetWindowPos(NULL, 0, 0, 0, 0, fOptions);
}
if ( fProperties & (MES_ALIGNMENT|MES_READONLY|MES_RIGHTTOLEFT) )
{
InvalidateRect(NULL);
}
}
void UpdateFont()
{
ATLASSERT( IsWindow() );
HFONT hFont = GetFont();
if ( hFont )
{
SetFont(NULL, FALSE);
_FreeFontHandle(hFont);
}
if ( _GetRefFont() )
{
hFont = _GetFontHandle();
if ( hFont )
SetFont(hFont, FALSE);
}
}
void UpdateReadOnly(BOOL bReadOnly)
{
ATLASSERT( IsWindow() );
if ( m_hbrBkg )
::DeleteObject(m_hbrBkg);
if ( bReadOnly )
m_hbrBkg = ::CreateSolidBrush(_GetReadOnlyBackColor());
else
m_hbrBkg = ::CreateSolidBrush(_GetBackColor());
SendMessage(EM_SETREADONLY, bReadOnly);
}
BOOL UpdateEditDC(HDC hdc, HBRUSH* phbrBkg)
{
ATLASSERT( !::IsBadWritePtr(phbrBkg, sizeof(HBRUSH)) );
::SetTextColor(hdc, _GetForeColor());
::SetBkColor(hdc, _GetBackColor());
*phbrBkg = m_hbrBkg;
return TRUE;
}
BOOL UpdateStaticDC(HDC hdc, HBRUSH* phbrBkg)
{
ATLASSERT( !::IsBadWritePtr(phbrBkg, sizeof(HBRUSH)) );
::SetTextColor(hdc, _GetReadOnlyForeColor());
::SetBkColor(hdc, _GetReadOnlyBackColor());
*phbrBkg = m_hbrBkg;
return TRUE;
}
// Accessors & mutators
public:
// Formatter
const TFormatter& GetFormatter() const
{
return m_formatter;
}
TFormatter& GetFormatter()
{
return m_formatter;
}
// Value
BOOL IsValueNull() const
{
return m_fVlaueStatus & VS_VALUENULL;
}
BOOL IsValueValid() const
{
return m_fVlaueStatus & VS_VALUEVALID;
}
const void* GetValue() const
{
ATLASSERT( m_formatter.IsConfigured() );
if ( _GetEditing() )
{
// Save text edit control
BOOL bResult = SaveEditText();
ATLASSERT( bResult );
if ( !bResult )
{
SP::AccountError(SP::AE_LOG, IDS_ELS_SPNUMERICEDITBOX, 0,
IDS_ERCW_SAVEEDITTEXT);
return FALSE;
}
// Get user value
bResult = ScanValue();
ATLASSERT( bResult );
if ( !bResult )
{
SP::AccountError(SP::AE_LOG, IDS_ELS_SPNUMERICEDITBOX, 0,
IDS_ERCW_SCANEDITTEXT);
return FALSE;
}
}
return IsValueNull() ? NULL : m_rgValue;
}
void SetValue(const void* lpcValue, BOOL bValid)
{
ATLASSERT( m_formatter.IsConfigured() );
ATLASSERT( !lpcValue || !::IsBadReadPtr(lpcValue, m_formatter.GetDataSize()) );
if ( bValid )
{
if ( lpcValue )
{
::CopyMemory(m_rgValue, lpcValue, m_formatter.GetDataSize());
m_fVlaueStatus &= (~VS_VALUENULL);
}
else
{
m_fVlaueStatus |= VS_VALUENULL;
}
m_fVlaueStatus |= VS_VALUEVALID;
}
else
{
m_fVlaueStatus &= (~VS_VALUEVALID);
}
}
// Edit text
LPCTSTR GetEditText() const
{
return m_lpszEditText;
}
LPTSTR GetEditText()
{
return m_lpszEditText;
}
BOOL ReallocEditTextBuf(UINT_PTR cchBuf) const
{
void* lpBuf = realloc(m_lpszEditText, (cchBuf + 1) * sizeof(TCHAR));
ATLASSERT( lpBuf );
if ( !lpBuf )
{
SP::AccountError(SP::AE_LOG|SP::AE_SETMSG, IDS_ELS_CRT, 2, IDS_ELR_OUTOFMEMORY);
return FALSE;
}
m_lpszEditText = reinterpret_cast<LPTSTR>(lpBuf);
return TRUE;
}
BOOL SetEditText(LPCTSTR lpszEditText)
{
ATLASSERT( lpszEditText );
return SetEditText(lpszEditText, _tcslen(lpszEditText));
}
BOOL SetEditText(LPCTSTR lpcEditText, UINT_PTR cchText)
{
bool bResult = ReallocEditTextBuf(cchText);
ATLASSERT( bResult );
if ( !bResult )
return FALSE;
_tcsncpy(m_lpszEditText, lpcEditText, cchText);
return TRUE;
}
UINT_PTR GetDisplayText(LPTSTR lpszText, UINT_PTR cchText) const
{
ATLASSERT( !::IsBadWritePtr(lpszText, cchText * sizeof(TCHAR)) );
ATLASSERT( m_formatter.IsConfigured() );
if ( IsValueValid() )
{
return m_formatter.FormatDisplayText(GetValue(), lpszText, cchText);
}
else if ( m_lpszEditText )
{
LPCTSTR lpcszErrorSymbol = _GetErrorSymbol();
ATLASSERT( lpcszErrorSymbol );
UINT_PTR cchErrorSymbol = _tcslen(lpcszErrorSymbol);
UINT_PTR cchResult = _tcslen(m_lpszEditText) * cchErrorSymbol;
if ( cchResult > 64 )
cchResult = 64;
if ( lpszText )
{
UINT_PTR iSrcErrorSymbol = 0;
for ( UINT_PTR i = 0; i < cchText; i++ )
{
lpszText[i] = lpcszErrorSymbol[iSrcErrorSymbol];
if ( ++iSrcErrorSymbol == cchErrorSymbol )
iSrcErrorSymbol = 0;
}
return i;
}
else
{
return cchResult;
}
}
return 0;
}
UINT_PTR GetEditingText(LPTSTR lpszText, UINT_PTR cchText) const
{
ATLASSERT( !::IsBadWritePtr(lpszText, cchText * sizeof(TCHAR)) );
ATLASSERT( m_formatter.IsConfigured() );
if ( IsValueValid() )
{
return m_formatter.FormatEditingText(GetValue(), lpszText, cchText);
}
else if ( m_lpszEditText )
{
if ( lpszText )
{
for ( UINT_PTR i = 0; i < cchText && m_lpszEditText[i]; i++ )
lpszText[i] = m_lpszEditText[i];
return i;
}
else
{
return _tcslen(m_lpszEditText);
}
}
return 0;
}
// Data members
private:
TFormatter m_formatter;
mutable WORD m_fVlaueStatus;
mutable BYTE m_rgValue[sizeof(Numeric)];
mutable LPTSTR m_lpszEditText;
HBRUSH m_hbrBkg;
CCoreNumericEditEventSink* m_pEventSink;
};