// OXCalculatorCtrl.cpp : implementation file // // Version: 9.3 #include "stdafx.h" #include "OXCalculatorCtrl.h" #include #include "UTBStrOp.h" #include "UTB64Bit.h" #ifdef _DEBUG #define new DEBUG_NEW #undef THIS_FILE static char THIS_FILE[] = __FILE__; #endif ///////////////////////////////////////////////////////////////////////////// // COXCalculatorCtrl dialog COXCalculatorCtrl::COXCalculatorCtrl(CWnd* pParent /*=NULL*/, double dValue/*=0*/) : CDialog(COXCalculatorCtrl::IDD, pParent) { //{{AFX_DATA_INIT(COXCalculatorCtrl) m_bScientific=FALSE; m_nNumberSystem=0; m_sDisplayString = _T(""); //}}AFX_DATA_INIT m_nFractionalCount=0; m_dValue=dValue; SetOperand(m_dValue,TRUE); m_operator=OpNone; m_lastCompletedOperator=OpNone; // get loacale setting m_chDecimalSeparator=_T('.'); int nLength=::GetLocaleInfo(LOCALE_USER_DEFAULT,LOCALE_SDECIMAL,NULL,0); if(nLength>0) { ::GetLocaleInfo(LOCALE_USER_DEFAULT,LOCALE_SDECIMAL, &m_chDecimalSeparator,nLength); } // Note that LoadAccelerator does not require DestroyAcceleratorTable m_hAccel=LoadAccelerators(AfxGetResourceHandle(),MAKEINTRESOURCE(IDD)); } BOOL COXCalculatorCtrl::Create(CWnd* pParentWnd) { ASSERT(pParentWnd!=NULL); return CDialog::Create(IDD,pParentWnd); } void COXCalculatorCtrl::DoDataExchange(CDataExchange* pDX) { CDialog::DoDataExchange(pDX); //{{AFX_DATA_MAP(COXCalculatorCtrl) DDX_Control(pDX, IDC_OX_COMBO_NUMBER_SYSTEM, m_comboNumberSystem); DDX_Control(pDX, IDC_OX_BUTTON_NATURAL_LOGARITHM, m_btnNaturalAlgorithm); DDX_Control(pDX, IDC_OX_BUTTON_LOGARITHM, m_btnLogarithm); DDX_Control(pDX, IDC_OX_BUTTON_F, m_btnF); DDX_Control(pDX, IDC_OX_BUTTON_E, m_btnE); DDX_Control(pDX, IDC_OX_BUTTON_D, m_btnD); DDX_Control(pDX, IDC_OX_BUTTON_C, m_btnC); DDX_Control(pDX, IDC_OX_BUTTON_B, m_btnB); DDX_Control(pDX, IDC_OX_BUTTON_A, m_btnA); DDX_Control(pDX, IDC_OX_STATIC_DISPLAY, m_ctlDisplay); DDX_Control(pDX, IDC_OX_BUTTON_TAN, m_btnTan); DDX_Control(pDX, IDC_OX_BUTTON_SIN, m_btnSin); DDX_Control(pDX, IDC_OX_BUTTON_POWER, m_btnPower); DDX_Control(pDX, IDC_OX_BUTTON_PI, m_btnPi); DDX_Control(pDX, IDC_OX_BUTTON_FACTORIAL, m_btnFactorial); DDX_Control(pDX, IDC_OX_BUTTON_COTAN, m_btnCotan); DDX_Control(pDX, IDC_OX_BUTTON_COS, m_btnCos); DDX_Control(pDX, IDC_OX_BUTTON_SUBTRACT, m_btnSubtract); DDX_Control(pDX, IDC_OX_BUTTON_SQRT, m_btnSqrt); DDX_Control(pDX, IDC_OX_BUTTON_RECIPROCAL, m_btnReciprocal); DDX_Control(pDX, IDC_OX_BUTTON_MULTIPLY, m_btnMultiply); DDX_Control(pDX, IDC_OX_BUTTON_MOD, m_btnMod); DDX_Control(pDX, IDC_OX_BUTTON_EQUAL, m_btnEqual); DDX_Control(pDX, IDC_OX_BUTTON_DIVIDE, m_btnDivide); DDX_Control(pDX, IDC_OX_BUTTON_DELIMITER, m_btnDelimiter); DDX_Control(pDX, IDC_OX_BUTTON_CLEARNUMBER, m_btnClearNumber); DDX_Control(pDX, IDC_OX_BUTTON_CLEAR, m_btnClear); DDX_Control(pDX, IDC_OX_BUTTON_CHANGESIGN, m_btnChangeSign); DDX_Control(pDX, IDC_OX_BUTTON_BACK, m_btnBack); DDX_Control(pDX, IDC_OX_BUTTON_ADD, m_btnAdd); DDX_Control(pDX, IDC_OX_BUTTON_9, m_btn9); DDX_Control(pDX, IDC_OX_BUTTON_8, m_btn8); DDX_Control(pDX, IDC_OX_BUTTON_7, m_btn7); DDX_Control(pDX, IDC_OX_BUTTON_6, m_btn6); DDX_Control(pDX, IDC_OX_BUTTON_5, m_btn5); DDX_Control(pDX, IDC_OX_BUTTON_4, m_btn4); DDX_Control(pDX, IDC_OX_BUTTON_3, m_btn3); DDX_Control(pDX, IDC_OX_BUTTON_2, m_btn2); DDX_Control(pDX, IDC_OX_BUTTON_1, m_btn1); DDX_Control(pDX, IDC_OX_BUTTON_0, m_btn0); DDX_Check(pDX, IDC_OX_CHECK_SCIENTIFIC, m_bScientific); DDX_CBIndex(pDX, IDC_OX_COMBO_NUMBER_SYSTEM, m_nNumberSystem); DDX_Text(pDX, IDC_OX_STATIC_DISPLAY, m_sDisplayString); //}}AFX_DATA_MAP } BEGIN_MESSAGE_MAP(COXCalculatorCtrl, CDialog) //{{AFX_MSG_MAP(COXCalculatorCtrl) ON_BN_CLICKED(IDC_OX_BUTTON_0, OnButton0) ON_BN_CLICKED(IDC_OX_BUTTON_1, OnButton1) ON_BN_CLICKED(IDC_OX_BUTTON_2, OnButton2) ON_BN_CLICKED(IDC_OX_BUTTON_3, OnButton3) ON_BN_CLICKED(IDC_OX_BUTTON_4, OnButton4) ON_BN_CLICKED(IDC_OX_BUTTON_5, OnButton5) ON_BN_CLICKED(IDC_OX_BUTTON_6, OnButton6) ON_BN_CLICKED(IDC_OX_BUTTON_7, OnButton7) ON_BN_CLICKED(IDC_OX_BUTTON_8, OnButton8) ON_BN_CLICKED(IDC_OX_BUTTON_9, OnButton9) ON_BN_CLICKED(IDC_OX_BUTTON_ADD, OnButtonAdd) ON_BN_CLICKED(IDC_OX_BUTTON_BACK, OnButtonBack) ON_BN_CLICKED(IDC_OX_BUTTON_CHANGESIGN, OnButtonChangesign) ON_BN_CLICKED(IDC_OX_BUTTON_CLEAR, OnButtonClear) ON_BN_CLICKED(IDC_OX_BUTTON_CLEARNUMBER, OnButtonClearnumber) ON_BN_CLICKED(IDC_OX_BUTTON_DELIMITER, OnButtonDelimiter) ON_BN_CLICKED(IDC_OX_BUTTON_DIVIDE, OnButtonDivide) ON_BN_CLICKED(IDC_OX_BUTTON_EQUAL, OnButtonEqual) ON_BN_CLICKED(IDC_OX_BUTTON_MOD, OnButtonMod) ON_BN_CLICKED(IDC_OX_BUTTON_MULTIPLY, OnButtonMultiply) ON_BN_CLICKED(IDC_OX_BUTTON_RECIPROCAL, OnButtonReciprocal) ON_BN_CLICKED(IDC_OX_BUTTON_SQRT, OnButtonSqrt) ON_BN_CLICKED(IDC_OX_BUTTON_SUBTRACT, OnButtonSubtract) ON_BN_CLICKED(IDC_OX_BUTTON_A, OnButtonA) ON_BN_CLICKED(IDC_OX_BUTTON_B, OnButtonB) ON_BN_CLICKED(IDC_OX_BUTTON_C, OnButtonC) ON_BN_CLICKED(IDC_OX_BUTTON_COS, OnButtonCos) ON_BN_CLICKED(IDC_OX_BUTTON_COTAN, OnButtonCotan) ON_BN_CLICKED(IDC_OX_BUTTON_D, OnButtonD) ON_BN_CLICKED(IDC_OX_BUTTON_E, OnButtonE) ON_BN_CLICKED(IDC_OX_BUTTON_F, OnButtonF) ON_BN_CLICKED(IDC_OX_BUTTON_FACTORIAL, OnButtonFactorial) ON_BN_CLICKED(IDC_OX_BUTTON_LOGARITHM, OnButtonLogarithm) ON_BN_CLICKED(IDC_OX_BUTTON_NATURAL_LOGARITHM, OnButtonNaturalLogarithm) ON_BN_CLICKED(IDC_OX_BUTTON_PI, OnButtonPi) ON_BN_CLICKED(IDC_OX_BUTTON_POWER, OnButtonPower) ON_BN_CLICKED(IDC_OX_BUTTON_SIN, OnButtonSin) ON_BN_CLICKED(IDC_OX_BUTTON_TAN, OnButtonTan) ON_BN_CLICKED(IDC_OX_CHECK_SCIENTIFIC, OnCheckScientific) ON_CBN_SELCHANGE(IDC_OX_COMBO_NUMBER_SYSTEM, OnSelchangeComboNumberSystem) //}}AFX_MSG_MAP END_MESSAGE_MAP() ///////////////////////////////////////////////////////////////////////////// // COXCalculatorCtrl message handlers BOOL COXCalculatorCtrl::PreTranslateMessage(MSG* pMsg) { // TODO: Add your specialized code here and/or call the base class if((pMsg->message==WM_KEYDOWN) && (pMsg->wParam==VK_RETURN || pMsg->wParam==VK_ESCAPE)) { ::TranslateMessage(pMsg); ::DispatchMessage(pMsg); return TRUE; } if(m_hAccel!=NULL && ::TranslateAccelerator(GetSafeHwnd(),m_hAccel,pMsg)) { return TRUE; } return CDialog::PreTranslateMessage(pMsg); } BOOL COXCalculatorCtrl::OnInitDialog() { CDialog::OnInitDialog(); // TODO: Add extra initialization here // allow navigating using TAB key ModifyStyleEx(0,WS_EX_CONTROLPARENT); // setup culculator buttons // SetupButton(&m_btnF,RGB(0,0,128)); SetupButton(&m_btnE,RGB(0,0,128)); SetupButton(&m_btnD,RGB(0,0,128)); SetupButton(&m_btnC,RGB(0,0,128)); SetupButton(&m_btnB,RGB(0,0,128)); SetupButton(&m_btnA,RGB(0,0,128)); SetupButton(&m_btnPi,RGB(0,0,128)); SetupButton(&m_btnNaturalAlgorithm,RGB(255,0,0)); SetupButton(&m_btnLogarithm,RGB(255,0,0)); SetupButton(&m_btnTan,RGB(255,0,0)); SetupButton(&m_btnSin,RGB(255,0,0)); SetupButton(&m_btnPower,RGB(255,0,0)); SetupButton(&m_btnFactorial,RGB(255,0,0)); SetupButton(&m_btnCotan,RGB(255,0,0)); SetupButton(&m_btnCos,RGB(255,0,0)); SetupButton(&m_btnSubtract,RGB(255,0,0)); SetupButton(&m_btnSqrt,RGB(255,0,0)); SetupButton(&m_btnReciprocal,RGB(255,0,0)); SetupButton(&m_btnMultiply,RGB(255,0,0)); SetupButton(&m_btnMod,RGB(255,0,0)); SetupButton(&m_btnEqual,RGB(255,0,0)); SetupButton(&m_btnDivide,RGB(255,0,0)); SetupButton(&m_btnAdd,RGB(255,0,0)); SetupButton(&m_btnClearNumber,RGB(128,0,0)); SetupButton(&m_btnClear,RGB(128,0,0)); SetupButton(&m_btnBack,RGB(128,0,0)); SetupButton(&m_btnDelimiter,RGB(0,0,255)); SetupButton(&m_btnChangeSign,RGB(0,0,255)); SetupButton(&m_btn9,RGB(0,0,255)); SetupButton(&m_btn8,RGB(0,0,255)); SetupButton(&m_btn7,RGB(0,0,255)); SetupButton(&m_btn6,RGB(0,0,255)); SetupButton(&m_btn5,RGB(0,0,255)); SetupButton(&m_btn4,RGB(0,0,255)); SetupButton(&m_btn3,RGB(0,0,255)); SetupButton(&m_btn2,RGB(0,0,255)); SetupButton(&m_btn1,RGB(0,0,255)); SetupButton(&m_btn0,RGB(0,0,255)); // ///////////////////////////////////// m_ctlDisplay.SetBkColor(::GetSysColor(COLOR_WINDOW)); ShowControls(); return TRUE; // return TRUE unless you set the focus to a control // EXCEPTION: OCX Property Pages should return FALSE } void COXCalculatorCtrl::SetupButton(COXBitmapButton* pButton, COLORREF clrText) { ASSERT(pButton!=NULL); pButton->SetToolTip(TRUE); pButton->SetTextColor(clrText); pButton->SetTextOffset(CPoint(-4,-4)); pButton->SetInnerFocusOffset(CPoint(-3,-3)); static CFont font; if((HFONT)font==NULL) { font.CreateFont(-8,0,0,0,FW_BOLD,FALSE,FALSE,FALSE,NULL,NULL,NULL,NULL,NULL, _T("MS Sans Serif")); } pButton->SetTextFont(&font); } void COXCalculatorCtrl::ShowControls() { if(!::IsWindow(GetSafeHwnd())) return; UpdateData(TRUE); m_btnNaturalAlgorithm.EnableWindow(m_bScientific); m_btnLogarithm.EnableWindow(m_bScientific); m_btnF.EnableWindow(m_bScientific && m_nNumberSystem==ID_NUMBERSYSTEM_HEXADECIMAL); m_btnE.EnableWindow(m_bScientific && m_nNumberSystem==ID_NUMBERSYSTEM_HEXADECIMAL); m_btnD.EnableWindow(m_bScientific && m_nNumberSystem==ID_NUMBERSYSTEM_HEXADECIMAL); m_btnC.EnableWindow(m_bScientific && m_nNumberSystem==ID_NUMBERSYSTEM_HEXADECIMAL); m_btnB.EnableWindow(m_bScientific && m_nNumberSystem==ID_NUMBERSYSTEM_HEXADECIMAL); m_btnA.EnableWindow(m_bScientific && m_nNumberSystem==ID_NUMBERSYSTEM_HEXADECIMAL); m_btnTan.EnableWindow(m_bScientific); m_btnSin.EnableWindow(m_bScientific); m_btnPower.EnableWindow(m_bScientific); m_btnFactorial.EnableWindow(m_bScientific); m_btnCotan.EnableWindow(m_bScientific); m_btnCos.EnableWindow(m_bScientific); m_btn2.EnableWindow(m_nNumberSystem!=ID_NUMBERSYSTEM_BINARY); m_btn3.EnableWindow(m_nNumberSystem!=ID_NUMBERSYSTEM_BINARY); m_btn4.EnableWindow(m_nNumberSystem!=ID_NUMBERSYSTEM_BINARY); m_btn5.EnableWindow(m_nNumberSystem!=ID_NUMBERSYSTEM_BINARY); m_btn6.EnableWindow(m_nNumberSystem!=ID_NUMBERSYSTEM_BINARY); m_btn7.EnableWindow(m_nNumberSystem!=ID_NUMBERSYSTEM_BINARY); m_btn8.EnableWindow(m_nNumberSystem!=ID_NUMBERSYSTEM_BINARY && m_nNumberSystem!=ID_NUMBERSYSTEM_OCTAL); m_btn9.EnableWindow(m_nNumberSystem!=ID_NUMBERSYSTEM_BINARY && m_nNumberSystem!=ID_NUMBERSYSTEM_OCTAL); m_btnPi.EnableWindow(m_nNumberSystem==ID_NUMBERSYSTEM_DECIMAL); m_comboNumberSystem.EnableWindow(m_bScientific); m_btnDelimiter.EnableWindow(m_nNumberSystem==0); if(!m_bScientific) { ASSERT(m_nNumberSystem==0); } switch(m_errorState) { case ErrNone: if(m_bOperandAvailable) m_sDisplayString=GetDisplayString(m_dOperand,m_nFractionalCount); else m_sDisplayString=GetDisplayString(m_dValue); break; case ErrDivideByZero: VERIFY(m_sDisplayString.LoadString(IDS_OX_CALCDIVIDEZERO)); //"Cannot divide by zero" break; case ErrOverflow: VERIFY(m_sDisplayString.LoadString(IDS_OX_RESULTTOOLARGE)); //"Result is too large" break; default: ASSERT(FALSE); } UpdateData(FALSE); } void COXCalculatorCtrl::OnCheckScientific() { // TODO: Add your control notification handler code here UpdateData(); if(!m_bScientific && GetNumberSystem()!=ID_NUMBERSYSTEM_DECIMAL) SetNumberSystem(ID_NUMBERSYSTEM_DECIMAL); else ShowControls(); } void COXCalculatorCtrl::OnSelchangeComboNumberSystem() { // TODO: Add your control notification handler code here int nOldNumberSystem=m_nNumberSystem; UpdateData(); int nNewNumberSystem=m_nNumberSystem; m_nNumberSystem=nOldNumberSystem; SetNumberSystem(nNewNumberSystem); } CString COXCalculatorCtrl::GetDisplayString(double dValue, int nFractionalCount/*=-1*/) const { CString sText; switch(m_nNumberSystem) { case ID_NUMBERSYSTEM_DECIMAL: { int decimal, sign; #if _MSC_VER >= 1400 char buffer[MAX_PATH]; _fcvt_s(buffer, MAX_PATH, dValue, (nFractionalCount==-1 ? GetFractionalDigitCount(dValue) : nFractionalCount), &decimal,&sign); #else char *buffer=fcvt(dValue,(nFractionalCount==-1 ? GetFractionalDigitCount(dValue) : nFractionalCount), &decimal,&sign); #endif int nSymbolCount=PtrToInt(strlen(buffer)); TCHAR* chInputData=new TCHAR[nSymbolCount+1]; #ifdef _UNICODE UTBStr::mbstowcs(chInputData,nSymbolCount + 1,buffer,nSymbolCount); #else UTBStr::strncpy(chInputData,nSymbolCount + 1,buffer,nSymbolCount); #endif chInputData[nSymbolCount]=_T('\0'); sText=chInputData; CString sDecimalSeparator(GetDecimalSeparator()); if(!sText.IsEmpty()) { for(int nIndex=decimal; nIndex<1; nIndex++) { sText=_T("0")+sText; decimal++; nSymbolCount++; } sText=sText.Left(decimal)+ sDecimalSeparator+sText.Mid(decimal); if(sign!=0) sText=_T("-")+sText; } else sText=_T("0."); delete[] chInputData; break; } case ID_NUMBERSYSTEM_HEXADECIMAL: { sText.Format(_T("%x"),(int)dValue); break; } case ID_NUMBERSYSTEM_OCTAL: { sText.Format(_T("%o"),(int)dValue); break; } case ID_NUMBERSYSTEM_BINARY: { sText.Format(_T("%u"),(int)dValue); break; } default: ASSERT(FALSE); } return sText; } void COXCalculatorCtrl::SetNumberSystem(int nNumberSystem) { ASSERT(nNumberSystem==ID_NUMBERSYSTEM_DECIMAL || ((nNumberSystem==ID_NUMBERSYSTEM_HEXADECIMAL || nNumberSystem==ID_NUMBERSYSTEM_OCTAL || nNumberSystem==ID_NUMBERSYSTEM_BINARY) & m_bScientific)); if(m_nNumberSystem!=nNumberSystem) { m_nNumberSystem=nNumberSystem; UpdateData(FALSE); if(m_bOperandAvailable) { SetResult(m_dOperand); m_bOperandAvailable=FALSE; } if(m_nNumberSystem!=ID_NUMBERSYSTEM_DECIMAL) { m_bAddingFractional=FALSE; } ShowControls(); } } void COXCalculatorCtrl::SetDecimalSeparator(TCHAR chDecimalSeparator) { ASSERT(!((chDecimalSeparator>=_T('0') && chDecimalSeparator<=_T('9')) || chDecimalSeparator==_T('-') || chDecimalSeparator==NULL)); if(m_chDecimalSeparator!=chDecimalSeparator) { m_chDecimalSeparator=chDecimalSeparator; if(::IsWindow(GetSafeHwnd())) ShowControls(); } } void COXCalculatorCtrl::AddDigit(double dDigit) { // check the digit switch(m_nNumberSystem) { case ID_NUMBERSYSTEM_DECIMAL: { if(dDigit<0 || dDigit>9) return; break; } case ID_NUMBERSYSTEM_HEXADECIMAL: { if(dDigit<0 || dDigit>15) return; break; } case ID_NUMBERSYSTEM_OCTAL: { if(dDigit<0 || dDigit>7) return; break; } case ID_NUMBERSYSTEM_BINARY: { if(dDigit<0 || dDigit>1) return; break; } default: ASSERT(FALSE); } // ///////////////////// if(!m_bOperandAvailable) { m_dOperand=0; m_bAddingFractional=FALSE; m_bOperandAvailable=TRUE; m_nFractionalCount=0; } int sign=(m_dOperand<0 ? -1 : 1); switch(m_nNumberSystem) { case ID_NUMBERSYSTEM_DECIMAL: { if(m_nFractionalCount+GetDecimalDigitCount(m_dOperand)0); double dFractional=10; double dFractionalMultiplier=1; for(int nIndex=0; nIndex= 1400 int count = MAX_DIGIT_COUNT+MAX_FRACTIONAL_COUNT+2; char buffer[MAX_PATH]; _fcvt_s(buffer, MAX_PATH, dValue, count, &decimal,&sign); #else char *buffer=fcvt(dValue,MAX_DIGIT_COUNT,&decimal,&sign); #endif int nSymbolCount=PtrToInt(strlen(buffer)); int nCount=nSymbolCount-decimal; for(int nIndex=nSymbolCount-1; nIndex>=decimal; nIndex--) { if(buffer[nIndex]!='0') break; nCount--; } ASSERT(nCount>=0); return nCount; } void COXCalculatorCtrl::SetOperand(double dOperand, BOOL bRecalcLayout/*=FALSE*/) { m_dOperand=dOperand; m_bOperandAvailable=TRUE; m_errorState=ErrNone; if(bRecalcLayout) { double dFractionalPart, dIntegerPart; dFractionalPart=modf(m_dOperand,&dIntegerPart); if(dFractionalPart!=(double)0) { m_bAddingFractional=TRUE; m_nFractionalCount=GetFractionalDigitCount(m_dOperand); if(m_nFractionalCount>MAX_FRACTIONAL_COUNT) m_nFractionalCount=MAX_FRACTIONAL_COUNT; } else { m_bAddingFractional=FALSE; m_nFractionalCount=0; } } ShowControls(); } void COXCalculatorCtrl::SetResult(double dValue) { m_dValue=dValue; m_bOperandAvailable=FALSE; m_errorState=ErrNone; m_nFractionalCount=0; ShowControls(); } void COXCalculatorCtrl::PerformUnaryOperation(Operator oper) { m_operator=oper; if(!m_bOperandAvailable) m_dOperand=m_dValue; PerformLastOperation(); m_operator=OpNone; m_lastCompletedOperator=OpNone; } void COXCalculatorCtrl::PerformBinaryOperation(Operator oper) { if(m_bOperandAvailable) PerformLastOperation(); m_operator=oper; if(!m_bOperandAvailable) m_dOperand=m_dValue; } void COXCalculatorCtrl::PerformLastOperation() { // Return if in an invalid state if (m_errorState != ErrNone) return; // Perform the selected operation switch(m_operator) { case OpNone: m_dValue=m_dOperand; break; case OpSubtract: m_dValue-=m_dOperand; break; case OpAdd: m_dValue+=m_dOperand; break; case OpMultiply: m_dValue*=m_dOperand; break; case OpDivide: m_dValue/=m_dOperand; break; case OpMod: m_dValue=fmod(m_dValue,m_dOperand); break; case OpRaiseToPower: { double dValue=m_dValue; m_dValue=1; double dIntegerPart; modf(m_dOperand,&dIntegerPart); for(double dIndex=0; dIndex0) { m_dValue*=dIntegerPart; dIntegerPart--; } } else m_dValue=0; } break; case OpLogarithm: m_dValue=log10(m_dOperand); break; case OpNaturalLogarithm: m_dValue=log(m_dOperand); break; case OpReciprocal: m_dValue=(double)1/m_dOperand; break; case OpSqrt: m_dValue=sqrt(m_dOperand); break; default: ASSERT(FALSE); } m_lastCompletedOperator=m_operator; m_bOperandAvailable=FALSE; ShowControls(); } void COXCalculatorCtrl::OnButton0() { // TODO: Add your control notification handler code here AddDigit(0); } void COXCalculatorCtrl::OnButton1() { // TODO: Add your control notification handler code here AddDigit(1); } void COXCalculatorCtrl::OnButton2() { // TODO: Add your control notification handler code here AddDigit(2); } void COXCalculatorCtrl::OnButton3() { // TODO: Add your control notification handler code here AddDigit(3); } void COXCalculatorCtrl::OnButton4() { // TODO: Add your control notification handler code here AddDigit(4); } void COXCalculatorCtrl::OnButton5() { // TODO: Add your control notification handler code here AddDigit(5); } void COXCalculatorCtrl::OnButton6() { // TODO: Add your control notification handler code here AddDigit(6); } void COXCalculatorCtrl::OnButton7() { // TODO: Add your control notification handler code here AddDigit(7); } void COXCalculatorCtrl::OnButton8() { // TODO: Add your control notification handler code here AddDigit(8); } void COXCalculatorCtrl::OnButton9() { // TODO: Add your control notification handler code here AddDigit(9); } void COXCalculatorCtrl::OnButtonA() { // TODO: Add your control notification handler code here AddDigit(10); } void COXCalculatorCtrl::OnButtonB() { // TODO: Add your control notification handler code here AddDigit(11); } void COXCalculatorCtrl::OnButtonC() { // TODO: Add your control notification handler code here AddDigit(12); } void COXCalculatorCtrl::OnButtonD() { // TODO: Add your control notification handler code here AddDigit(13); } void COXCalculatorCtrl::OnButtonE() { // TODO: Add your control notification handler code here AddDigit(14); } void COXCalculatorCtrl::OnButtonF() { // TODO: Add your control notification handler code here AddDigit(15); } void COXCalculatorCtrl::OnButtonBack() { // TODO: Add your control notification handler code here RemoveLastDigit(); } void COXCalculatorCtrl::OnButtonChangesign() { // TODO: Add your control notification handler code here if(m_bOperandAvailable) SetOperand(m_dOperand*-1); else SetResult(m_dValue*-1); } void COXCalculatorCtrl::OnButtonClear() { // TODO: Add your control notification handler code here SetResult(0); } void COXCalculatorCtrl::OnButtonClearnumber() { // TODO: Add your control notification handler code here if(m_bOperandAvailable) SetOperand(0,TRUE); else SetResult(0); } void COXCalculatorCtrl::OnButtonDelimiter() { // TODO: Add your control notification handler code here if(GetNumberSystem()==ID_NUMBERSYSTEM_DECIMAL) { if(!m_bOperandAvailable) { m_dOperand=0; m_bOperandAvailable=TRUE; ShowControls(); } m_bAddingFractional=TRUE; } } void COXCalculatorCtrl::OnButtonPi() { // TODO: Add your control notification handler code here if(GetNumberSystem()==ID_NUMBERSYSTEM_DECIMAL) SetOperand(PI,TRUE); } void COXCalculatorCtrl::OnButtonCos() { // TODO: Add your control notification handler code here PerformUnaryOperation(OpCos); } void COXCalculatorCtrl::OnButtonCotan() { // TODO: Add your control notification handler code here PerformUnaryOperation(OpCotan); } void COXCalculatorCtrl::OnButtonReciprocal() { // TODO: Add your control notification handler code here PerformUnaryOperation(OpReciprocal); } void COXCalculatorCtrl::OnButtonSqrt() { // TODO: Add your control notification handler code here PerformUnaryOperation(OpSqrt); } void COXCalculatorCtrl::OnButtonFactorial() { // TODO: Add your control notification handler code here PerformUnaryOperation(OpFactorial); } void COXCalculatorCtrl::OnButtonLogarithm() { // TODO: Add your control notification handler code here PerformUnaryOperation(OpLogarithm); } void COXCalculatorCtrl::OnButtonNaturalLogarithm() { // TODO: Add your control notification handler code here PerformUnaryOperation(OpNaturalLogarithm); } void COXCalculatorCtrl::OnButtonSin() { // TODO: Add your control notification handler code here PerformUnaryOperation(OpSin); } void COXCalculatorCtrl::OnButtonTan() { // TODO: Add your control notification handler code here PerformUnaryOperation(OpTan); } void COXCalculatorCtrl::OnButtonAdd() { // TODO: Add your control notification handler code here PerformBinaryOperation(OpAdd); } void COXCalculatorCtrl::OnButtonDivide() { // TODO: Add your control notification handler code here PerformBinaryOperation(OpDivide); } void COXCalculatorCtrl::OnButtonMod() { // TODO: Add your control notification handler code here PerformBinaryOperation(OpMod); } void COXCalculatorCtrl::OnButtonMultiply() { // TODO: Add your control notification handler code here PerformBinaryOperation(OpMultiply); } void COXCalculatorCtrl::OnButtonSubtract() { // TODO: Add your control notification handler code here PerformBinaryOperation(OpSubtract); } void COXCalculatorCtrl::OnButtonPower() { // TODO: Add your control notification handler code here PerformBinaryOperation(OpRaiseToPower); } void COXCalculatorCtrl::OnButtonEqual() { // TODO: Add your control notification handler code here if(!m_bOperandAvailable) { if(m_operator==OpNone) { m_operator=m_lastCompletedOperator; } } PerformLastOperation(); m_operator=OpNone; } //////////////////////////////////////////////////////////////// COXCalculatorPopup::COXCalculatorPopup() { m_pParentWnd=NULL; } COXCalculatorPopup::~COXCalculatorPopup() { } BEGIN_MESSAGE_MAP(COXCalculatorPopup, CWnd) //{{AFX_MSG_MAP(COXCalculatorPopup) ON_BN_CLICKED(IDOK, OnOk) ON_BN_CLICKED(IDCANCEL, OnCancel) //}}AFX_MSG_MAP END_MESSAGE_MAP() BOOL COXCalculatorPopup::Create(CWnd* pParentWnd/*=NULL*/, HBRUSH hbrBackground/*=NULL*/) { ASSERT(pParentWnd==NULL || ::IsWindow(pParentWnd->GetSafeHwnd())); // creation of window // if(hbrBackground==NULL) { hbrBackground=(HBRUSH)(COLOR_BTNFACE+1); } // define our own window class WNDCLASS wndClass; wndClass.style=CS_SAVEBITS; wndClass.lpfnWndProc=AfxWndProc; wndClass.cbClsExtra=0; wndClass.cbWndExtra=0; wndClass.hInstance=AfxGetInstanceHandle(); wndClass.hIcon=0; wndClass.hCursor=::LoadCursor(NULL,IDC_ARROW); wndClass.hbrBackground=hbrBackground; wndClass.lpszMenuName=NULL; wndClass.lpszClassName=_T("CalculatorPopupWindow"); if(!AfxRegisterClass(&wndClass)) { return FALSE; } CRect rect(0,0,0,0); if(!CWnd::CreateEx( WS_EX_DLGMODALFRAME|WS_EX_CONTROLPARENT,wndClass.lpszClassName,_T(""), WS_POPUP,rect,pParentWnd,0,NULL)) { TRACE(_T("COXCalculatorPopup::Create: failed to create popup window\n")); return FALSE; } // create calculator control if(!m_calculator.Create(this)) { DestroyWindow(); TRACE(_T("COXCalculatorPopup::Create: failed to create calculator control\n")); return FALSE; } m_calculator.ModifyStyle(NULL,WS_VISIBLE); // create "Ok" and "Cancel" buttons CString sName; VERIFY(sName.LoadString(IDS_OX_CALCOKBUTTON)); //"OK" if(!m_btnOk.Create(sName, WS_CHILD|WS_VISIBLE|WS_TABSTOP|BS_PUSHBUTTON|BS_OWNERDRAW,rect,this,IDOK)) { DestroyWindow(); TRACE(_T("COXCalculatorPopup::Create: failed to create 'OK' button\n")); return FALSE; } VERIFY(sName.LoadString(IDS_OX_CALCCANCELBUTTON));//"Cancel" if(!m_btnCancel.Create(sName, WS_CHILD|WS_VISIBLE|WS_TABSTOP|BS_PUSHBUTTON|BS_OWNERDRAW,rect,this,IDCANCEL)) { DestroyWindow(); TRACE(_T("COXCalculatorPopup::Create: failed to create 'Cancel' button\n")); return FALSE; } m_pParentWnd=pParentWnd; return TRUE; } BOOL COXCalculatorPopup::Pick(double dStartValue/*=0*/, int nAlignment/*=ID_OXCALCULATOR_ALIGNBOTTOM*/, CRect rectParent/*=CRect(0,0,0,0)*/, CSize szOffset/*=CSize(0,0)*/) { ASSERT(::IsWindow(GetSafeHwnd())); ASSERT(::IsWindow(m_calculator.GetSafeHwnd())); ASSERT(::IsWindow(m_btnOk.GetSafeHwnd())); ASSERT(::IsWindow(m_btnCancel.GetSafeHwnd())); // now we've got to calculate size of the window and the controls // positioning if(!CalcWindowSize()) { return FALSE; } // we've got size of window but we have to display it // in a nice spot (at least in the place user wants us to put in) if(!AdjustWindowPos(nAlignment,rectParent,szOffset)) { return FALSE; } // it's show time! SetWindowPos(NULL,m_rect.left,m_rect.top,m_rect.Width(),m_rect.Height(), SWP_NOZORDER|SWP_NOACTIVATE); m_calculator.MoveWindow(m_rectCalculator); m_btnOk.MoveWindow(m_rectBtnOk); m_btnCancel.MoveWindow(m_rectBtnCancel); ShowWindow(SW_SHOWNA); m_calculator.SetFocus(); // set operand's value m_calculator.SetOperand(dStartValue,TRUE); m_calculator.m_operator=OpNone; m_calculator.m_lastCompletedOperator=OpNone; // init message loop // m_nState = 0 - control is active // m_nState = 1 - user pressed 'OK' // m_nState = 2 - user left the window without choosing any number m_nState=0; while(m_nState==0) { MSG msg; VERIFY(::GetMessage(&msg,NULL,0,0)); if(msg.message==WM_COMMAND) { ASSERT(FALSE); } CWnd* pWndHasFocus=GetFocus(); if(pWndHasFocus!=this) { if(pWndHasFocus==NULL || !IsDescendant(this,pWndHasFocus)) break; } if((msg.message==WM_KEYDOWN)) { if(msg.wParam==VK_RETURN) { if(m_calculator.m_operator==OpNone && m_calculator.m_lastCompletedOperator==OpNone) { m_calculator.PerformLastOperation(); } OnOk(); continue; } else if(msg.wParam==VK_ESCAPE) { OnCancel(); continue; } } if(!m_calculator.PreTranslateMessage(&msg)) { ::DispatchMessage(&msg); } } ShowWindow(SW_HIDE); BOOL bResult=m_nState==1 ? TRUE : FALSE; return bResult; } void COXCalculatorPopup::OnOk() { m_nState=1; } void COXCalculatorPopup::OnCancel() { m_nState=2; } BOOL COXCalculatorPopup::CalcWindowSize() { ASSERT(::IsWindow(GetSafeHwnd())); ASSERT(::IsWindow(m_calculator.GetSafeHwnd())); ASSERT(::IsWindow(m_btnOk.GetSafeHwnd())); ASSERT(::IsWindow(m_btnCancel.GetSafeHwnd())); // calcurator position CRect rectCalculator; m_calculator.GetWindowRect(rectCalculator); m_rectCalculator.TopLeft()= CPoint(OXCALCULATORPOPUP_XMARGIN,OXCALCULATORPOPUP_YMARGIN); m_rectCalculator.right=OXCALCULATORPOPUP_XMARGIN+rectCalculator.Width(); m_rectCalculator.bottom=OXCALCULATORPOPUP_YMARGIN+rectCalculator.Height(); // OK button position m_rectBtnOk.left=m_rectCalculator.left; m_rectBtnOk.top=m_rectCalculator.bottom+OXCALCULATORPOPUP_YMARGIN; m_rectBtnOk.right=m_rectBtnOk.left+m_rectCalculator.Width()/2- OXCALCULATORPOPUP_XMARGIN; m_rectBtnOk.bottom=m_rectBtnOk.top+OXCALCULATORPOPUP_BUTTON_HEIGHT; // Cancel button position m_rectBtnCancel.right=m_rectCalculator.right; m_rectBtnCancel.top=m_rectBtnOk.top; m_rectBtnCancel.left=m_rectBtnCancel.right-m_rectCalculator.Width()/2+ OXCALCULATORPOPUP_XMARGIN; m_rectBtnCancel.bottom=m_rectBtnOk.bottom; // popup window size m_rect.SetRectEmpty(); m_rect.right=m_rectCalculator.Width()+OXCALCULATORPOPUP_XMARGIN*2+ ::GetSystemMetrics(SM_CXDLGFRAME)*2; m_rect.bottom=m_rectCalculator.Height()+OXCALCULATORPOPUP_YMARGIN*3+ OXCALCULATORPOPUP_BUTTON_HEIGHT+::GetSystemMetrics(SM_CYDLGFRAME)*2; return TRUE; } BOOL COXCalculatorPopup::AdjustWindowPos(int nAlignment/*=ID_OXCALCULATOR_ALIGNBOTTOM*/, CRect rectParent/*=CRect(0,0,0,0)*/, CSize szOffset/*=CSize(0,0)*/) { ASSERT(::IsWindow(GetSafeHwnd())); ASSERT(nAlignment==ID_OXCALCULATOR_ALIGNLEFT || nAlignment==ID_OXCALCULATOR_ALIGNRIGHT || nAlignment==ID_OXCALCULATOR_ALIGNTOP || nAlignment==ID_OXCALCULATOR_ALIGNBOTTOM || nAlignment==ID_OXCALCULATOR_ALIGNLEFTBOTTOM || nAlignment==ID_OXCALCULATOR_ALIGNRIGHTBOTTOM || nAlignment==ID_OXCALCULATOR_ALIGNTOPRIGHT || nAlignment==ID_OXCALCULATOR_ALIGNBOTTOMRIGHT); CRect rect; ::SystemParametersInfo(SPI_GETWORKAREA,0,&rect,0); int nScreenWidth=rect.Width(); int nScreenHeight=rect.Height(); if(m_rect.Width()>nScreenWidth || m_rect.Height()>nScreenHeight) { return FALSE; } CSize sizeOffset; if(rectParent.IsRectEmpty()) { if(m_pParentWnd!=NULL) m_pParentWnd->GetWindowRect(rectParent); else { ASSERT(GetParent()!=NULL); GetParent()->GetWindowRect(rectParent); } } switch(nAlignment) { case ID_OXCALCULATOR_ALIGNLEFT: { sizeOffset.cx=rectParent.left-szOffset.cx-m_rect.Width(); sizeOffset.cy=rectParent.top+szOffset.cy; if(sizeOffset.cx<0) { sizeOffset.cx=rectParent.right+szOffset.cx; if(sizeOffset.cx+m_rect.Width()>nScreenWidth) { return FALSE; } } m_rect.OffsetRect(sizeOffset); break; } case ID_OXCALCULATOR_ALIGNLEFTBOTTOM: { sizeOffset.cx=rectParent.left-szOffset.cx-m_rect.Width(); sizeOffset.cy=rectParent.bottom-szOffset.cy-m_rect.Height(); if(sizeOffset.cx<0) { sizeOffset.cx=rectParent.right+szOffset.cx; if(sizeOffset.cx+m_rect.Width()>nScreenWidth) { return FALSE; } } m_rect.OffsetRect(sizeOffset); break; } case ID_OXCALCULATOR_ALIGNRIGHT: { sizeOffset.cx=rectParent.right+szOffset.cx; sizeOffset.cy=rectParent.top+szOffset.cy; if(sizeOffset.cx+m_rect.Width()>nScreenWidth) { sizeOffset.cx=rectParent.left-szOffset.cx-m_rect.Width(); if(sizeOffset.cx<0) { return FALSE; } } m_rect.OffsetRect(sizeOffset); break; } case ID_OXCALCULATOR_ALIGNRIGHTBOTTOM: { sizeOffset.cx=rectParent.right+szOffset.cx; sizeOffset.cy=rectParent.bottom-szOffset.cy-m_rect.Height(); if(sizeOffset.cx+m_rect.Width()>nScreenWidth) { sizeOffset.cx=rectParent.left-szOffset.cx-m_rect.Width(); if(sizeOffset.cx<0) { return FALSE; } } m_rect.OffsetRect(sizeOffset); break; } case ID_OXCALCULATOR_ALIGNTOP: { sizeOffset.cx=rectParent.left+szOffset.cx; sizeOffset.cy=rectParent.top-szOffset.cy-m_rect.Height(); if(sizeOffset.cy<0) { sizeOffset.cy=rectParent.bottom+szOffset.cy; if(sizeOffset.cy+m_rect.Height()>nScreenHeight) { return FALSE; } } m_rect.OffsetRect(sizeOffset); break; } case ID_OXCALCULATOR_ALIGNTOPRIGHT: { sizeOffset.cx=rectParent.right-szOffset.cx-m_rect.Width(); sizeOffset.cy=rectParent.top-szOffset.cy-m_rect.Height(); if(sizeOffset.cy<0) { sizeOffset.cy=rectParent.bottom+szOffset.cy; if(sizeOffset.cy+m_rect.Height()>nScreenHeight) { return FALSE; } } m_rect.OffsetRect(sizeOffset); break; } case ID_OXCALCULATOR_ALIGNBOTTOM: { sizeOffset.cx=rectParent.left+szOffset.cx; sizeOffset.cy=rectParent.bottom+szOffset.cy; if(sizeOffset.cy+m_rect.Height()>nScreenHeight) { sizeOffset.cy=rectParent.top-szOffset.cy-m_rect.Height(); if(sizeOffset.cy<0) { return FALSE; } } m_rect.OffsetRect(sizeOffset); break; } case ID_OXCALCULATOR_ALIGNBOTTOMRIGHT: { sizeOffset.cx=rectParent.right-szOffset.cx-m_rect.Width(); sizeOffset.cy=rectParent.bottom+szOffset.cy; if(sizeOffset.cy+m_rect.Height()>nScreenHeight) { sizeOffset.cy=rectParent.top-szOffset.cy-m_rect.Height(); if(sizeOffset.cy<0) { return FALSE; } } m_rect.OffsetRect(sizeOffset); break; } } sizeOffset.cx=0; sizeOffset.cy=0; if(m_rect.left<0) { sizeOffset.cx=-m_rect.left; } else if(m_rect.right>nScreenWidth) { sizeOffset.cx=nScreenWidth-m_rect.right; } if(m_rect.top<0) { sizeOffset.cy=-m_rect.top; } else if(m_rect.bottom>nScreenHeight) { sizeOffset.cy=nScreenHeight-m_rect.bottom; } m_rect.OffsetRect(sizeOffset); return TRUE; } BOOL COXCalculatorPopup::IsDescendant(CWnd* pWndParent, CWnd* pWndChild) // helper for detecting whether child descendent of parent // (works with owned popups as well) { ASSERT(pWndParent!=NULL); ASSERT(::IsWindow(pWndParent->GetSafeHwnd())); ASSERT(pWndChild!=NULL); ASSERT(::IsWindow(pWndChild->GetSafeHwnd())); HWND hWndParent=pWndParent->GetSafeHwnd(); HWND hWndChild=pWndChild->GetSafeHwnd(); do { if (hWndParent == hWndChild) return TRUE; // check for permanent-owned window first CWnd* pWnd=CWnd::FromHandlePermanent(hWndChild); if(pWnd!=NULL) hWndChild=pWnd->GetOwner()->GetSafeHwnd(); else hWndChild=(::GetWindowLongPtr(hWndChild,GWL_STYLE)&WS_CHILD) ? ::GetParent(hWndChild) : ::GetWindow(hWndChild,GW_OWNER); } while (hWndChild != NULL); return FALSE; }