1516 lines
36 KiB
C++
1516 lines
36 KiB
C++
// OXCalculatorCtrl.cpp : implementation file
|
|
//
|
|
// Version: 9.3
|
|
|
|
|
|
#include "stdafx.h"
|
|
#include "OXCalculatorCtrl.h"
|
|
|
|
#include <math.h>
|
|
|
|
#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)<MAX_DIGIT_COUNT)
|
|
{
|
|
if(m_bAddingFractional)
|
|
{
|
|
double dFractional=1;
|
|
for(int nIndex=0; nIndex<=m_nFractionalCount;nIndex++)
|
|
{
|
|
dFractional/=(double)10;
|
|
}
|
|
m_nFractionalCount++;
|
|
// SetOperand might change the number of fractional digits
|
|
SetOperand(m_dOperand+sign*dDigit*dFractional);
|
|
}
|
|
else
|
|
SetOperand(m_dOperand*(double)10+sign*dDigit);
|
|
}
|
|
break;
|
|
}
|
|
case ID_NUMBERSYSTEM_HEXADECIMAL:
|
|
{
|
|
SetOperand(m_dOperand*16+sign*dDigit);
|
|
break;
|
|
}
|
|
case ID_NUMBERSYSTEM_OCTAL:
|
|
{
|
|
SetOperand(m_dOperand*8+sign*dDigit);
|
|
break;
|
|
}
|
|
case ID_NUMBERSYSTEM_BINARY:
|
|
{
|
|
SetOperand(m_dOperand*2+sign*dDigit);
|
|
break;
|
|
}
|
|
default:
|
|
ASSERT(FALSE);
|
|
}
|
|
}
|
|
|
|
|
|
void COXCalculatorCtrl::RemoveLastDigit()
|
|
{
|
|
if(!m_bOperandAvailable)
|
|
return;
|
|
|
|
switch(m_nNumberSystem)
|
|
{
|
|
case ID_NUMBERSYSTEM_DECIMAL:
|
|
{
|
|
if(m_bAddingFractional)
|
|
{
|
|
ASSERT(m_nFractionalCount>0);
|
|
double dFractional=10;
|
|
double dFractionalMultiplier=1;
|
|
for(int nIndex=0; nIndex<m_nFractionalCount; nIndex++)
|
|
{
|
|
dFractional/=(double)10;
|
|
dFractionalMultiplier*=(double)10;
|
|
}
|
|
double dFractionalPart, dIntegerPart;
|
|
dFractionalPart=modf(m_dOperand,&dIntegerPart);
|
|
dFractionalPart*=dFractionalMultiplier;
|
|
dFractionalPart=dFractionalPart/(double)10-
|
|
fmod(dFractionalPart,(double)10)/(double)10;
|
|
dFractionalPart*=dFractional;
|
|
m_nFractionalCount--;
|
|
SetOperand(dIntegerPart+dFractionalPart);
|
|
if(m_nFractionalCount==0)
|
|
m_bAddingFractional=FALSE;
|
|
}
|
|
else
|
|
SetOperand(m_dOperand/(double)10-
|
|
fmod(m_dOperand,(double)10)/(double)10);
|
|
break;
|
|
}
|
|
case ID_NUMBERSYSTEM_HEXADECIMAL:
|
|
{
|
|
SetOperand(m_dOperand/(double)16-
|
|
fmod(m_dOperand,(double)16)/(double)16);
|
|
break;
|
|
}
|
|
case ID_NUMBERSYSTEM_OCTAL:
|
|
{
|
|
SetOperand(m_dOperand/(double)8-
|
|
fmod(m_dOperand,(double)8)/(double)8);
|
|
break;
|
|
}
|
|
case ID_NUMBERSYSTEM_BINARY:
|
|
{
|
|
SetOperand(m_dOperand/(double)2-
|
|
fmod(m_dOperand,(double)2)/(double)2);
|
|
break;
|
|
}
|
|
default:
|
|
ASSERT(FALSE);
|
|
}
|
|
}
|
|
|
|
|
|
int COXCalculatorCtrl::GetDecimalDigitCount(double dValue) const
|
|
{
|
|
int nCount=0;
|
|
double dIntegerPart=dValue;
|
|
while(TRUE)
|
|
{
|
|
modf(dIntegerPart,&dIntegerPart);
|
|
if(dIntegerPart==(double)0)
|
|
break;
|
|
nCount++;
|
|
dIntegerPart/=(double)10;
|
|
}
|
|
|
|
return nCount;
|
|
}
|
|
|
|
|
|
int COXCalculatorCtrl::GetFractionalDigitCount(double dValue) const
|
|
{
|
|
int decimal, sign;
|
|
#if _MSC_VER >= 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; dIndex<dIntegerPart; dIndex++)
|
|
m_dValue*=dValue;
|
|
}
|
|
break;
|
|
case OpSin:
|
|
m_dValue=sin(m_dOperand);
|
|
break;
|
|
case OpCos:
|
|
m_dValue=cos(m_dOperand);
|
|
break;
|
|
case OpTan:
|
|
m_dValue=tan(m_dOperand);
|
|
break;
|
|
case OpCotan:
|
|
m_dValue=tanh(m_dOperand);
|
|
break;
|
|
case OpFactorial:
|
|
{
|
|
double dIntegerPart;
|
|
modf(m_dOperand,&dIntegerPart);
|
|
if((int)dIntegerPart!=0)
|
|
{
|
|
m_dValue=1;
|
|
while(dIntegerPart>0)
|
|
{
|
|
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;
|
|
}
|
|
|
|
|