737 lines
22 KiB
C
737 lines
22 KiB
C
/****************************Module*Header***********************************\
|
|
* Module Name: SCICOMM.C
|
|
*
|
|
* Module Descripton:
|
|
*
|
|
* Warnings:
|
|
*
|
|
* Created:
|
|
*
|
|
* Author:
|
|
\****************************************************************************/
|
|
|
|
#include "scicalc.h"
|
|
#include "calchelp.h"
|
|
#include "unifunc.h"
|
|
#include "input.h"
|
|
|
|
extern HWND hStatBox;
|
|
extern HNUMOBJ ghnoNum, ghnoLastNum, ghnoMem;
|
|
extern HNUMOBJ ghnoParNum[25], ghnoPrecNum[25];
|
|
|
|
extern eNUMOBJ_FMT nFE;
|
|
extern INT nTempCom, nParNum, nPrecNum, gcIntDigits,
|
|
nOpCode, nOp[25], nPrecOp[25];
|
|
extern BOOL bError;
|
|
extern TCHAR szBlank[6];
|
|
extern TCHAR *rgpsz[CSTRINGS];
|
|
|
|
|
|
int nLastCom; // Last command entered.
|
|
CALCINPUTOBJ gcio; // Global calc input object for decimal strings
|
|
BOOL gbRecord; // Global mode: recording or displaying
|
|
|
|
|
|
/* Puts up the wait cursor if the calc will take a long time */
|
|
HCURSOR ghcurOld = NULL;
|
|
|
|
BOOL SetWaitCursor( BOOL fOn ) {
|
|
if (fOn && ghcurOld == NULL) {
|
|
ghcurOld = SetCursor( LoadCursor(NULL, IDC_WAIT) );
|
|
} else if (!fOn && ghcurOld != NULL) {
|
|
SetCursor( ghcurOld );
|
|
ghcurOld = NULL;
|
|
}
|
|
|
|
return (fOn && ghcurOld != NULL);
|
|
}
|
|
|
|
/* Process all keyclicks whether by mouse or accelerator. */
|
|
VOID NEAR RealProcessCommands(WPARAM wParam);
|
|
|
|
VOID NEAR ProcessCommands(WPARAM wParam)
|
|
{
|
|
if (wParam != IDM_ABOUT)
|
|
{
|
|
TimeCalc(TRUE);
|
|
}
|
|
|
|
try
|
|
{
|
|
RealProcessCommands( wParam );
|
|
}
|
|
catch( ... )
|
|
{
|
|
// note: it should be impossible for a throw to reach this level, this is put here as an
|
|
// emergency backup only. Throws are normally caught at the boundry between calc and ratpak.
|
|
ASSERT( 0 );
|
|
MessageBox( g_hwndDlg, TEXT("An unknown error has occured."), TEXT("Error"), MB_OK );
|
|
}
|
|
|
|
if (wParam != IDM_ABOUT)
|
|
{
|
|
TimeCalc(FALSE);
|
|
}
|
|
}
|
|
|
|
VOID NEAR RealProcessCommands(WPARAM wParam)
|
|
{
|
|
static BOOL bNoPrevEqu=TRUE, /* Flag for previous equals. */
|
|
bChangeOp=FALSE; /* Flag for changing operation. */
|
|
INT nx, ni;
|
|
TCHAR szJunk[50], szTemp[50];
|
|
static BYTE rgbPrec[24]={ 0,0, IDC_OR,0, IDC_XOR,0, IDC_AND,1,
|
|
IDC_ADD,2, IDC_SUB,2, RSHF,3, IDC_LSHF,3,
|
|
IDC_MOD,3, IDC_DIV,3, IDC_MUL,3, IDC_PWR,4};
|
|
|
|
// Make sure we're only getting commands we understand.
|
|
|
|
ASSERT( xwParam(IDC_FIRSTCONTROL, IDC_LASTCONTROL) || // Is it a button?
|
|
xwParam(IDM_FIRSTMENU, IDM_LASTMENU) ); // or a menu command?
|
|
|
|
// Save the last command. Some commands are not saved in this manor, these
|
|
// commands are:
|
|
// Inv, Hyp, Deg, Rad, Grad, Stat, FE, MClear, Back, and Exp. The excluded
|
|
// commands are not
|
|
// really mathematical operations, rather they are GUI mode settings.
|
|
|
|
if ( !xwParam(IDC_INV, IDC_HYP) && !xwParam(IDM_HEX, IDM_BIN) &&
|
|
!xwParam(IDM_QWORD, IDM_BYTE) && !xwParam(IDM_DEG, IDM_GRAD) &&
|
|
wParam!=IDC_STAT && wParam!=IDC_FE &&
|
|
wParam!=IDC_MCLEAR && wParam!=IDC_BACK && wParam!=IDC_EXP)
|
|
{
|
|
nLastCom=nTempCom;
|
|
nTempCom=(INT)wParam;
|
|
}
|
|
|
|
// If error and not a clear key or help key, BEEP.
|
|
|
|
if (bError && (wParam !=IDC_CLEAR) && (wParam !=IDC_CENTR) &&
|
|
(wParam != IDM_HELPTOPICS))
|
|
{
|
|
MessageBeep(0);
|
|
return;
|
|
}
|
|
|
|
// Toggle Record/Display mode if appropriate.
|
|
|
|
if (gbRecord)
|
|
{
|
|
if (xwParam(IDC_AND, IDC_MPLUS) ||
|
|
xwParam(IDC_AVE, IDC_CLOSEP) ||
|
|
xwParam(IDC_INV, IDC_HYP) ||
|
|
xwParam(IDM_HEX, IDM_BIN) ||
|
|
xwParam(IDM_QWORD, IDM_BYTE) ||
|
|
xwParam(IDM_DEG, IDM_GRAD) ||
|
|
wParam == IDM_PASTE)
|
|
{
|
|
gbRecord = FALSE;
|
|
SetWaitCursor(TRUE);
|
|
CIO_vConvertToNumObj(&ghnoNum, &gcio);
|
|
DisplayNum(); // Causes 3.000 to shrink to 3. on first op.
|
|
SetWaitCursor(FALSE);
|
|
}
|
|
}
|
|
else
|
|
{
|
|
if ( xwParam(IDC_0, IDC_F) || wParam == IDC_PNT)
|
|
{
|
|
gbRecord = TRUE;
|
|
CIO_vClear(&gcio);
|
|
}
|
|
}
|
|
|
|
// Interpret digit keys.
|
|
|
|
if (xwParam(IDC_0, IDC_F))
|
|
{
|
|
int iValue = (int)(wParam-IDC_0);
|
|
|
|
// this is redundant, illegal keys are disabled
|
|
if (iValue >= nRadix)
|
|
{
|
|
//ASSERT( 0 );
|
|
MessageBeep(0);
|
|
return;
|
|
}
|
|
|
|
|
|
if (!CIO_bAddDigit(&gcio, iValue))
|
|
{
|
|
MessageBeep(0);
|
|
return;
|
|
}
|
|
|
|
DisplayNum();
|
|
return;
|
|
}
|
|
|
|
|
|
// STATISTICAL FUNCTIONS:
|
|
if (xwParam(IDC_AVE,IDC_DATA))
|
|
{
|
|
/* Do statistics functions on data in fpStatNum array. */
|
|
if (hStatBox)
|
|
{
|
|
DisplayNum(); // Make sure gpszNum has the correct string
|
|
try
|
|
{
|
|
StatFunctions (wParam);
|
|
}
|
|
catch ( ... )
|
|
{
|
|
ASSERT( 0 ); // the only thing stat box should be able to throw is out of memory
|
|
// which in previous versions of calc caused a program crash
|
|
}
|
|
if (!bError)
|
|
DisplayNum ();
|
|
}
|
|
else
|
|
/* Beep if the stat box is not active. */
|
|
MessageBeep(0);
|
|
|
|
/* Reset the inverse flag since some functions use it. */
|
|
SetBox (IDC_INV, bInv=FALSE);
|
|
return;
|
|
}
|
|
|
|
|
|
// BINARY OPERATORS:
|
|
if (xwParam(IDC_AND,IDC_PWR))
|
|
{
|
|
if (bInv && wParam==IDC_LSHF)
|
|
{
|
|
SetBox (IDC_INV, bInv=FALSE);
|
|
wParam=RSHF;
|
|
}
|
|
|
|
/* Change the operation if last input was operation. */
|
|
if (nLastCom >=IDC_AND && nLastCom <=IDC_PWR)
|
|
{
|
|
nOpCode=(INT)wParam;
|
|
return;
|
|
}
|
|
|
|
/* bChangeOp is true if there was an operation done and the */
|
|
/* current ghnoNum is the result of that operation. This is so */
|
|
/* entering 3+4+5= gives 7 after the first + and 12 after the */
|
|
/* the =. The rest of this stuff attempts to do precedence in*/
|
|
/* Scientific mode. */
|
|
if (bChangeOp)
|
|
{
|
|
DoPrecedenceCheckAgain:
|
|
|
|
nx=0;
|
|
while (wParam!=rgbPrec[nx*2] && nx <12)
|
|
nx++;
|
|
|
|
ni=0;
|
|
while (nOpCode!=rgbPrec[ni*2] && ni <12)
|
|
ni++;
|
|
|
|
if (nx==12) nx=0;
|
|
if (ni==12) ni=0;
|
|
|
|
if (rgbPrec[nx*2+1] > rgbPrec[ni*2+1] && nCalc==0)
|
|
{
|
|
if (nPrecNum <25)
|
|
{
|
|
NumObjAssign( &ghnoPrecNum[nPrecNum], ghnoLastNum );
|
|
nPrecOp[nPrecNum]=nOpCode;
|
|
}
|
|
else
|
|
{
|
|
nPrecNum=24;
|
|
MessageBeep(0);
|
|
}
|
|
nPrecNum++;
|
|
}
|
|
else
|
|
{
|
|
/* do the last operation and then if the precedence array is not
|
|
* empty or the top is not the '(' demarcator then pop the top
|
|
* of the array and recheck precedence against the new operator
|
|
*/
|
|
|
|
SetWaitCursor(TRUE);
|
|
|
|
DoOperation(nOpCode, &ghnoNum, ghnoLastNum);
|
|
|
|
SetWaitCursor(FALSE);
|
|
|
|
if ((nPrecNum !=0) && (nPrecOp[nPrecNum-1]))
|
|
{
|
|
nPrecNum--;
|
|
nOpCode=nPrecOp[nPrecNum] ;
|
|
if (NumObjOK( ghnoPrecNum[nPrecNum] ))
|
|
NumObjAssign(&ghnoLastNum , ghnoPrecNum[nPrecNum]);
|
|
else
|
|
NumObjAssign(&ghnoLastNum, HNO_ZERO);
|
|
|
|
goto DoPrecedenceCheckAgain ;
|
|
}
|
|
|
|
if (!bError)
|
|
DisplayNum ();
|
|
}
|
|
}
|
|
|
|
NumObjAssign(&ghnoLastNum, ghnoNum);
|
|
NumObjAssign(&ghnoNum, HNO_ZERO);
|
|
nOpCode=(INT)wParam;
|
|
bNoPrevEqu=bChangeOp=TRUE;
|
|
return;
|
|
}
|
|
|
|
// UNARY OPERATORS:
|
|
if (xwParam(IDC_CHOP,IDC_PERCENT))
|
|
{
|
|
/* Functions are unary operations. */
|
|
|
|
/* If the last thing done was an operator, ghnoNum was cleared. */
|
|
/* In that case we better use the number before the operator */
|
|
/* was entered, otherwise, things like 5+ 1/x give Divide By */
|
|
/* zero. This way 5+=gives 10 like most calculators do. */
|
|
if (nLastCom >= IDC_AND && nLastCom <= IDC_PWR)
|
|
NumObjAssign( &ghnoNum, ghnoLastNum );
|
|
|
|
SetWaitCursor(TRUE);
|
|
SciCalcFunctions ( &ghnoNum, (DWORD)wParam);
|
|
SetWaitCursor(FALSE);
|
|
|
|
if (bError)
|
|
return;
|
|
|
|
/* Display the result, reset flags, and reset indicators. */
|
|
DisplayNum ();
|
|
|
|
/* reset the bInv and bHyp flags and indicators if they are set
|
|
and have been used */
|
|
|
|
if (bInv &&
|
|
(wParam == IDC_CHOP || wParam == IDC_SIN || wParam == IDC_COS ||
|
|
wParam == IDC_TAN || wParam == IDC_SQR || wParam == IDC_CUB ||
|
|
wParam == IDC_LOG || wParam == IDC_LN || wParam == IDC_DMS))
|
|
{
|
|
bInv=FALSE;
|
|
SetBox (IDC_INV, FALSE);
|
|
}
|
|
|
|
if (bHyp &&
|
|
(wParam == IDC_SIN || wParam == IDC_COS || wParam == IDC_TAN))
|
|
{
|
|
bHyp = FALSE;
|
|
SetBox (IDC_HYP, FALSE);
|
|
}
|
|
bNoPrevEqu=TRUE;
|
|
return;
|
|
}
|
|
|
|
// BASE CHANGES:
|
|
if (xwParam(IDM_HEX, IDM_BIN))
|
|
{
|
|
// Change radix and update display.
|
|
if (nCalc==1)
|
|
{
|
|
wParam=IDM_DEC;
|
|
}
|
|
|
|
SetRadix((DWORD)wParam);
|
|
return;
|
|
}
|
|
|
|
SetWaitCursor(TRUE);
|
|
|
|
/* Now branch off to do other commands and functions. */
|
|
switch(wParam)
|
|
{
|
|
case IDM_COPY:
|
|
case IDM_PASTE:
|
|
case IDM_ABOUT:
|
|
case IDM_SC:
|
|
case IDM_SSC:
|
|
case IDM_USE_SEPARATOR:
|
|
case IDM_HELPTOPICS:
|
|
// Jump to menu command handler in scimenu.c.
|
|
MenuFunctions((DWORD)wParam);
|
|
DisplayNum();
|
|
break;
|
|
|
|
case IDC_CLEAR: /* Total clear. */
|
|
NumObjAssign( &ghnoLastNum, HNO_ZERO );
|
|
nPrecNum=nTempCom=nLastCom=nOpCode=nParNum=bChangeOp=FALSE;
|
|
nFE = FMT_FLOAT; // back to the default number format
|
|
bNoPrevEqu=TRUE;
|
|
|
|
/* clear the paranthesis status box indicator, this will not be
|
|
cleared for CENTR */
|
|
|
|
SetDlgItemText(g_hwndDlg, IDC_PARTEXT, szBlank);
|
|
|
|
/* fall through */
|
|
|
|
case IDC_CENTR: /* Clear only temporary values. */
|
|
NumObjAssign( &ghnoNum, HNO_ZERO );
|
|
|
|
if (!nCalc)
|
|
{
|
|
// Clear the INV, HYP indicators & leave (=xx indicator active
|
|
|
|
SetBox (IDC_INV, bInv=FALSE);
|
|
SetBox (IDC_HYP, bHyp=FALSE);
|
|
}
|
|
|
|
bError=FALSE;
|
|
CIO_vClear(&gcio);
|
|
gbRecord = TRUE;
|
|
DisplayNum ();
|
|
break;
|
|
|
|
case IDC_STAT: /* Shift focus to Statistix Box if it's active. */
|
|
if (hStatBox)
|
|
SetFocus(hStatBox);
|
|
else
|
|
SetStat (TRUE);
|
|
break;
|
|
|
|
case IDC_BACK:
|
|
// Divide number by the current radix and truncate.
|
|
// Only allow backspace if we're recording.
|
|
if (gbRecord)
|
|
{
|
|
if (!CIO_bBackspace(&gcio))
|
|
MessageBeep(0);
|
|
|
|
DisplayNum();
|
|
}
|
|
else
|
|
MessageBeep(0);
|
|
break;
|
|
|
|
/* EQU enables the user to press it multiple times after and */
|
|
/* operation to enable repeats of the last operation. I don't */
|
|
/* know if I can explain what the [censored] I did here... */
|
|
case IDC_EQU:
|
|
do {
|
|
// NOTE: the number pointed to by hnoHold won't get freed until process termination.
|
|
static HNUMOBJ hnoHold;
|
|
|
|
/* Last thing keyed in was an operator. Lets do the op on*/
|
|
/* a duplicate of the last entry. */
|
|
if ((nLastCom >= IDC_AND) && (nLastCom <= IDC_PWR))
|
|
NumObjAssign( &ghnoNum, ghnoLastNum );
|
|
|
|
if (nOpCode) /* Is there a valid operation around? */
|
|
{
|
|
/* If this is the first EQU in a string, set hnoHold=ghnoNum */
|
|
/* Otherwise let ghnoNum=hnoTemp. This keeps ghnoNum constant */
|
|
/* through all EQUs in a row. */
|
|
if (bNoPrevEqu)
|
|
NumObjAssign(&hnoHold, ghnoNum);
|
|
else
|
|
NumObjAssign(&ghnoNum, hnoHold);
|
|
|
|
/* Do the current or last operation. */
|
|
DoOperation (nOpCode, &ghnoNum, ghnoLastNum);
|
|
NumObjAssign(&ghnoLastNum, ghnoNum );
|
|
|
|
/* Check for errors. If this wasn't done, DisplayNum */
|
|
/* would immediately overwrite any error message. */
|
|
if (!bError)
|
|
DisplayNum ();
|
|
|
|
/* No longer the first EQU. */
|
|
bNoPrevEqu=FALSE;
|
|
}
|
|
else if (!bError)
|
|
DisplayNum();
|
|
|
|
if (nPrecNum==0 || nCalc==1)
|
|
break;
|
|
|
|
nOpCode=nPrecOp[--nPrecNum];
|
|
if (NumObjOK( ghnoPrecNum[nPrecNum] ))
|
|
NumObjAssign(&ghnoLastNum , ghnoPrecNum[nPrecNum]);
|
|
else
|
|
NumObjAssign(&ghnoLastNum, HNO_ZERO);
|
|
bNoPrevEqu=TRUE;
|
|
} while (nPrecNum >= 0);
|
|
|
|
bChangeOp=FALSE;
|
|
break;
|
|
|
|
|
|
case IDC_OPENP:
|
|
case IDC_CLOSEP:
|
|
nx=0;
|
|
if (wParam==IDC_OPENP)
|
|
nx=1;
|
|
|
|
// -IF- the Paren holding array is full and we try to add a paren
|
|
// -OR- the paren holding array is empty and we try to remove a
|
|
// paren
|
|
// -OR- the the precidence holding array is full
|
|
if ((nParNum >= 25 && nx) || (!nParNum && !nx)
|
|
|| ( (nPrecNum >= 25 && nPrecOp[nPrecNum-1]!=0) ) )
|
|
{
|
|
MessageBeep(0);
|
|
break;
|
|
}
|
|
|
|
if (nx)
|
|
{
|
|
/* Open level of parentheses, save number and operation. */
|
|
NumObjAssign( &ghnoParNum[nParNum], ghnoLastNum);
|
|
nOp[nParNum++]=nOpCode;
|
|
|
|
/* save a special marker on the precedence array */
|
|
nPrecOp[nPrecNum++]=0 ;
|
|
|
|
NumObjAssign( &ghnoLastNum, HNO_ZERO );
|
|
nTempCom=0;
|
|
nOpCode=IDC_ADD;
|
|
}
|
|
else
|
|
{
|
|
/* Get the operation and number and return result. */
|
|
DoOperation (nOpCode, &ghnoNum, ghnoLastNum);
|
|
|
|
/* now process the precedence stack till we get to an
|
|
opcode which is zero. */
|
|
|
|
while (nOpCode = nPrecOp[--nPrecNum])
|
|
{
|
|
if (NumObjOK( ghnoPrecNum[nPrecNum] ))
|
|
NumObjAssign(&ghnoLastNum , ghnoPrecNum[nPrecNum]);
|
|
else
|
|
NumObjAssign(&ghnoLastNum, HNO_ZERO);
|
|
|
|
DoOperation (nOpCode, &ghnoNum, ghnoLastNum);
|
|
}
|
|
|
|
/* now get back the operation and opcode at the begining
|
|
of this paranthesis pair */
|
|
|
|
nParNum -= 1;
|
|
NumObjAssign( &ghnoLastNum, ghnoParNum[nParNum] );
|
|
nOpCode=nOp[nParNum];
|
|
|
|
/* if nOpCode is a valid operator then set bChangeOp to
|
|
be true else set it false */
|
|
|
|
if (nOpCode)
|
|
bChangeOp=TRUE;
|
|
else
|
|
bChangeOp=FALSE ;
|
|
}
|
|
|
|
/* Set the "(=xx" indicator. */
|
|
lstrcpy(szJunk, TEXT("(="));
|
|
lstrcat(szJunk, UToDecT(nParNum, szTemp));
|
|
SetDlgItemText(g_hwndDlg, IDC_PARTEXT,
|
|
(nParNum) ? (szJunk) : (szBlank));
|
|
|
|
if (bError)
|
|
break;
|
|
|
|
if (nx)
|
|
{
|
|
/* Build a display string of nParNum "("'s. */
|
|
for (nx=0; nx < nParNum; nx++)
|
|
szJunk[nx]=TEXT('(');
|
|
|
|
szJunk[nx]=0; /* Null-terminate. */
|
|
SetDisplayText(g_hwndDlg, szJunk);
|
|
bChangeOp=FALSE;
|
|
}
|
|
else
|
|
DisplayNum ();
|
|
break;
|
|
|
|
case IDM_QWORD:
|
|
case IDM_DWORD:
|
|
case IDM_WORD:
|
|
case IDM_BYTE:
|
|
case IDM_DEG:
|
|
case IDM_RAD:
|
|
case IDM_GRAD:
|
|
|
|
if (!F_INTMATH())
|
|
{
|
|
// in decimal mode, these buttons simply set a flag which is
|
|
// passed to the ratpak to handle angle conversions
|
|
|
|
if (xwParam(IDM_DEG, IDM_GRAD))
|
|
{
|
|
nDecMode = (ANGLE_TYPE)(wParam - IDM_DEG);
|
|
|
|
CheckMenuRadioItem(GetSubMenu(GetMenu(g_hwndDlg), 1),
|
|
IDM_DEG, IDM_GRAD, IDM_DEG+nDecMode,
|
|
MF_BYCOMMAND);
|
|
|
|
CheckRadioButton(g_hwndDlg, IDC_DEG, IDC_GRAD,
|
|
IDC_DEG+nDecMode);
|
|
}
|
|
}
|
|
else
|
|
{
|
|
if (xwParam(IDM_DEG, IDM_GRAD))
|
|
{
|
|
// if in hex mode, but we got a decimal key press this
|
|
// likely is the accelorator. map this to the correct key
|
|
|
|
wParam=IDM_DWORD+(wParam-IDM_DEG);
|
|
}
|
|
|
|
if ( gbRecord )
|
|
{
|
|
CIO_vConvertToNumObj(&ghnoNum, &gcio);
|
|
gbRecord = FALSE;
|
|
}
|
|
|
|
// Compat. mode BaseX: Qword, Dword, Word, Byte
|
|
nHexMode = (int)(wParam - IDM_QWORD);
|
|
switch (nHexMode)
|
|
{
|
|
case 0: dwWordBitWidth = 64; break;
|
|
case 1: dwWordBitWidth = 32; break;
|
|
case 2: dwWordBitWidth = 16; break;
|
|
case 3: dwWordBitWidth = 8; break;
|
|
default:
|
|
ASSERT( 0 ); // Invalid Word Size
|
|
break;
|
|
}
|
|
|
|
// different wordsize means the new wordsize determines
|
|
// the precision
|
|
|
|
BaseOrPrecisionChanged();
|
|
|
|
CheckMenuRadioItem(GetSubMenu(GetMenu(g_hwndDlg), 1),
|
|
IDM_QWORD, IDM_BYTE, IDM_QWORD+nHexMode,
|
|
MF_BYCOMMAND);
|
|
|
|
CheckRadioButton(g_hwndDlg, IDC_QWORD, IDC_BYTE,
|
|
IDC_QWORD+nHexMode);
|
|
|
|
}
|
|
|
|
|
|
// REARCHITECT: the call to display number is what actually does the
|
|
// chop. it would make more sense to do the chop here when the
|
|
// wordsize changes. the chop must be done when a different
|
|
// wordsize is selected AND when the base is changed to non-decimal
|
|
DisplayNum();
|
|
break;
|
|
|
|
case IDC_SIGN:
|
|
// Change the sign.
|
|
if (gbRecord)
|
|
CIO_vToggleSign(&gcio);
|
|
else {
|
|
NumObjNegate( &ghnoNum );
|
|
}
|
|
|
|
DisplayNum();
|
|
break;
|
|
|
|
case IDC_RECALL:
|
|
/* Recall immediate memory value. */
|
|
NumObjAssign( &ghnoNum, ghnoMem );
|
|
|
|
DisplayNum ();
|
|
break;
|
|
|
|
case IDC_MPLUS:
|
|
/* MPLUS adds ghnoNum to immediate memory and kills the "mem" */
|
|
/* indicator if the result is zero. */
|
|
addrat( &ghnoMem, ghnoNum);
|
|
SetDlgItemText(g_hwndDlg,IDC_MEMTEXT,
|
|
!NumObjIsZero(ghnoMem) ? (TEXT(" M")):(szBlank));
|
|
break;
|
|
|
|
case IDC_STORE:
|
|
case IDC_MCLEAR:
|
|
if (wParam==IDC_STORE)
|
|
{
|
|
NumObjAssign( &ghnoMem, ghnoNum );
|
|
}
|
|
else
|
|
{
|
|
NumObjAssign( &ghnoMem, HNO_ZERO );
|
|
}
|
|
SetDlgItemText(g_hwndDlg,IDC_MEMTEXT,
|
|
!NumObjIsZero(ghnoMem) ? (TEXT(" M")):(szBlank));
|
|
break;
|
|
|
|
case IDC_PI:
|
|
if (!F_INTMATH())
|
|
{
|
|
/* Return PI if bInv==FALSE, or 2PI if bInv==TRUE. */
|
|
if (bInv)
|
|
NumObjAssign( &ghnoNum, HNO_2PI );
|
|
else
|
|
NumObjAssign( &ghnoNum, HNO_PI );
|
|
|
|
DisplayNum();
|
|
SetBox(IDC_INV, bInv=FALSE);
|
|
}
|
|
else
|
|
MessageBeep(0);
|
|
break;
|
|
|
|
case IDC_FE:
|
|
// Toggle exponential notation display.
|
|
nFE = NUMOBJ_FMT(!(int)nFE);
|
|
DisplayNum();
|
|
break;
|
|
|
|
case IDC_EXP:
|
|
if (gbRecord && !F_INTMATH())
|
|
if (CIO_bExponent(&gcio))
|
|
{
|
|
DisplayNum();
|
|
break;
|
|
}
|
|
MessageBeep(0);
|
|
break;
|
|
|
|
case IDC_PNT:
|
|
if (gbRecord && !F_INTMATH()) {
|
|
if (CIO_bAddDecimalPt(&gcio)) {
|
|
|
|
DisplayNum();
|
|
break;
|
|
}
|
|
}
|
|
MessageBeep(0);
|
|
break;
|
|
|
|
case IDC_INV:
|
|
SetBox((int)wParam, bInv=!bInv);
|
|
break;
|
|
|
|
case IDC_HYP:
|
|
SetBox((int)wParam, bHyp=!bHyp);
|
|
break;
|
|
}
|
|
|
|
SetWaitCursor(FALSE);
|
|
}
|
|
|
|
|
|
// change the display area from a static text to an editbox, which has the focus can make
|
|
// Magnifer (Accessibility tool) work
|
|
BOOL SetDisplayText(HWND hDlg, LPCTSTR szText)
|
|
{
|
|
HWND hDispEdit = GetDlgItem(hDlg, IDC_DISPLAY);
|
|
int nLen = lstrlen(szText);
|
|
|
|
SetWindowText(hDispEdit, szText);
|
|
SetFocus(hDispEdit);
|
|
|
|
// make sure the number just typed is shown at the center of Magnifier
|
|
SendMessage(hDispEdit, EM_SETSEL, nLen, nLen);
|
|
return TRUE;
|
|
}
|