📄 scicomm.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 );
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -