// ========================================================================== // Class Implementation : COXPhysicalEdit // ========================================================================== // Source file : OXPhysicalEdit.cpp // Version: 9.3 // This software along with its related components, documentation and files ("The Libraries") // is © 1994-2007 The Code Project (1612916 Ontario Limited) and use of The Libraries is // governed by a software license agreement ("Agreement"). Copies of the Agreement are // available at The Code Project (www.codeproject.com), as part of the package you downloaded // to obtain this file, or directly from our office. For a copy of the license governing // this software, you may contact us at legalaffairs@codeproject.com, or by calling 416-849-8900. // ////////////////////////////////////////////////////////////////////////// #include "StdAfx.h" // standard MFC include #include "OXPhysicalEdit.h" #include "UTB64Bit.h" #ifdef _DEBUG #define new DEBUG_NEW #undef THIS_FILE static char THIS_FILE[] = __FILE__; #endif IMPLEMENT_DYNAMIC(COXPhysicalEdit, COXNumericEdit) ///////////////////////////////////////////////////////////////////////////// // Definition of static members // Data members ------------------------------------------------------------- // protected: // int m_nUnitIndex; // --- The last used unit (during SetValue or construction) of this edit control // COXConversionData* m_pConversionData; // --- Pointer to the conversion data or NULL // private: // Member functions --------------------------------------------------------- // public: BEGIN_MESSAGE_MAP(COXPhysicalEdit, COXNumericEdit) //{{AFX_MSG_MAP(COXPhysicalEdit) //}}AFX_MSG_MAP ON_COMMAND_RANGE(ID_OXPHYSICALEDIT_INDEXBASE,0xffff,OnChangeUnit) END_MESSAGE_MAP() COXPhysicalEdit::COXPhysicalEdit() : m_nUnitIndex(-1), m_pConversionData(NULL), m_bShowUnit(FALSE) { } COXPhysicalEdit::COXPhysicalEdit(COXConversionData* pConversionData, int nDefaultUnitIndex /* = -1 */, BOOL bShowUnit/*=TRUE*/) : m_nUnitIndex(nDefaultUnitIndex), m_pConversionData(pConversionData), m_bShowUnit(FALSE) { if (nDefaultUnitIndex == -1) { // No default unit was specified, than valid conversion data must be supplied, // so we can extract a default unit from that data ASSERT(pConversionData != NULL); ASSERT(AfxIsValidAddress(pConversionData, sizeof(COXConversionData))); m_nUnitIndex = pConversionData->m_nDefaultUnitIndex; } if(pConversionData!=NULL) { VERIFY(m_menu.CreatePopupMenu()); LPCTSTR* arrUnitNames=GetUnitNames(); for(int nIndex=0; nIndex=0); for(int nIndex=0; nIndex0); m_arrRightLiterals.RemoveAt(nOffset-sUnitName.GetLength()); } } m_bShowUnit=bShowUnit; Update(-1); } } double COXPhysicalEdit::Convert(double dValue, int nUnitFrom, int nUnitTo) { ASSERT_VALID(this); // MAke a call to the static version return ConversionHelper(dValue, nUnitFrom, nUnitTo, GetConversionParams()); } double COXPhysicalEdit::ConversionHelper(double dValue, int nUnitFrom, int nUnitTo, COXConversionParams* pConversionParams) { ASSERT(pConversionParams != NULL); ASSERT(AfxIsValidAddress(pConversionParams, sizeof(COXConversionParams))); // ... Convert value to default unit double dDefValue = (dValue + pConversionParams[nUnitFrom].m_dPreTerm) * pConversionParams[nUnitFrom].m_dFactor + pConversionParams[nUnitFrom].m_dPostTerm; // ... and then to requested unit ASSERT(pConversionParams[nUnitTo].m_dFactor != 0); double dRequestValue = (dDefValue - pConversionParams[nUnitTo].m_dPostTerm) / pConversionParams[nUnitTo].m_dFactor - pConversionParams[nUnitTo].m_dPreTerm; return dRequestValue; } int COXPhysicalEdit::GetNumberOfUnits() { ASSERT_VALID(this); // If this function is called, m_pConversionData should point to valid data // If you do not want to use m_pConversionData, you should override this function // in a derived class ASSERT(m_pConversionData != NULL); return m_pConversionData->m_nNumberOfUnits; } int COXPhysicalEdit::GetDefaultUnit() { ASSERT_VALID(this); // If this function is called, m_pConversionData should point to valid data // If you do not want to use m_pConversionData, you should override this function // in a derived class ASSERT(m_pConversionData != NULL); return m_pConversionData->m_nDefaultUnitIndex; } LPCTSTR* COXPhysicalEdit::GetUnitNames() { ASSERT_VALID(this); // If this function is called, m_pConversionData should point to valid data // If you do not want to use m_pConversionData, you should override this function // in a derived class ASSERT(m_pConversionData != NULL); return m_pConversionData->m_ppszUnitNames; } COXConversionParams* COXPhysicalEdit::GetConversionParams() { ASSERT_VALID(this); // If this function is called, m_pConversionData should point to valid data // If you do not want to use m_pConversionData, you should override this function // in a derived class ASSERT(m_pConversionData != NULL); return m_pConversionData->m_pConversionParams; } void COXPhysicalEdit::ShowErrorMessage(LPCTSTR pszUnit) { SetFocus(); CString sMessage; CString sFullMessage; // If this function is called, m_pConversionData should point to valid data // If you do not want to use m_pConversionData, you should override this function // in a derived class ASSERT(m_pConversionData != NULL); if ((m_pConversionData != NULL) && (m_pConversionData->m_pszErrorMsg != NULL)) { if (HIWORD(m_pConversionData->m_pszErrorMsg) == NULL) { // Implicit resource ID specified, load it UINT nID = LOWORD((DWORD_PTR)m_pConversionData->m_pszErrorMsg); sMessage.LoadString(LOWORD((DWORD)nID)); } else // Explicit string pointer sMessage = m_pConversionData->m_pszErrorMsg; } // ... Fill in the value if the string contains "%1" AfxFormatStrings(sFullMessage, (LPCTSTR)sMessage, &pszUnit, 1); // Show a message box to the user AfxMessageBox(sFullMessage, MB_ICONEXCLAMATION | MB_OK); } void COXPhysicalEdit::OnChangeUnit(UINT nID) { if((int)nID=ID_OXPHYSICALEDIT_INDEXBASE+GetNumberOfUnits()) { // don't handle it return; } nID-=ID_OXPHYSICALEDIT_INDEXBASE; SetValue(GetValue(nID),nID); UpdateInsertionPointForward(0); } #ifdef _DEBUG void COXPhysicalEdit::AssertValid() const { CEdit::AssertValid(); CString sDummy; // ... A valid unit index has to be specified ! ASSERT(0 <= m_nUnitIndex); // If conversion data is supplied, check that it is valid if(m_pConversionData != NULL) { ASSERT(AfxIsValidAddress(m_pConversionData, sizeof(COXConversionData))); // ... Should have at least one unit ASSERT(0 < m_pConversionData->m_nNumberOfUnits); // ... Default unit index has to be valid ASSERT(0 <= m_pConversionData->m_nDefaultUnitIndex); if(m_pConversionData->m_pszErrorMsg != NULL) { if (HIWORD(m_pConversionData->m_pszErrorMsg)!=NULL) { // Explicit string pointer ASSERT(AfxIsValidString(m_pConversionData->m_pszErrorMsg)); } } // Array should be valid ASSERT(AfxIsValidAddress( m_pConversionData->m_ppszUnitNames, sizeof(LPCTSTR*) * m_pConversionData->m_nNumberOfUnits)); ASSERT(AfxIsValidAddress( m_pConversionData->m_pConversionParams, sizeof(COXConversionParams*) * m_pConversionData->m_nNumberOfUnits)); for(int nUnitIndex = 0; nUnitIndex < m_pConversionData->m_nNumberOfUnits; nUnitIndex++) { ASSERT(AfxIsValidString(m_pConversionData->m_ppszUnitNames[nUnitIndex])); ASSERT(AfxIsValidAddress( &m_pConversionData->m_pConversionParams[nUnitIndex], sizeof(COXConversionParams))); // ... Multiplication factor should never be 0 ASSERT(m_pConversionData->m_pConversionParams[nUnitIndex].m_dFactor != 0); } } } void COXPhysicalEdit::Dump(CDumpContext& dc) const { COXNumericEdit::Dump(dc); } #endif //_DEBUG COXPhysicalEdit::~COXPhysicalEdit() { ASSERT_VALID(this); } // protected: // private: // global: void AFXAPI DDX_OXPhysicalEdit(CDataExchange* pDX, int nIDC, double& dValue, int nUnits) { // be sure that the control is a COXTimeEdit COXPhysicalEdit* pEdit = (COXPhysicalEdit*)pDX->m_pDlgWnd->GetDlgItem(nIDC); ASSERT(pEdit->IsKindOf(RUNTIME_CLASS(COXPhysicalEdit))); ASSERT_VALID(pEdit); if (pDX->m_bSaveAndValidate) { // retreive data dValue = pEdit->GetValue(nUnits); } else { // set data pEdit->SetValue(dValue, nUnits); } } // ==========================================================================