2025-11-27 16:46:48 +09:00

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;
}