361 lines
14 KiB
C
361 lines
14 KiB
C
|
/**************************************************************************/
|
||
|
/*** SCICALC Scientific Calculator for Windows 3.00.12 ***/
|
||
|
/*** By Kraig Brockschmidt, Microsoft Co-op, Contractor, 1988-1989 ***/
|
||
|
/*** (c)1989 Microsoft Corporation. All Rights Reserved. ***/
|
||
|
/*** ***/
|
||
|
/*** scimenu.c ***/
|
||
|
/*** ***/
|
||
|
/*** Functions contained: ***/
|
||
|
/*** MenuFunctions--handles menu options. ***/
|
||
|
/*** ***/
|
||
|
/*** Functions called: ***/
|
||
|
/*** DisplayNum ***/
|
||
|
/*** ***/
|
||
|
/*** Last modification Thu 06-Dec-1989 ***/
|
||
|
/*** (-by- Amit Chatterjee [amitc]) ***/
|
||
|
/*** ***/
|
||
|
/*** Modified the 'PASTE' menu to check for unary minus, e, e+ & e- ***/
|
||
|
/*** in DEC mode. ***/
|
||
|
/*** ***/
|
||
|
/*** Also modified the COPY code to not copy the last '.' in the display***/
|
||
|
/*** if a decimal point has not been hit. ***/
|
||
|
/*** ***/
|
||
|
/**************************************************************************/
|
||
|
|
||
|
#include "scicalc.h"
|
||
|
#include "unifunc.h"
|
||
|
#include "input.h"
|
||
|
#include <shellapi.h>
|
||
|
#include <ctype.h>
|
||
|
|
||
|
#define CHARSCAN 66
|
||
|
|
||
|
extern HWND hEdit, hStatBox;
|
||
|
extern TCHAR szAppName[10], szDec[5], gszSep[5], *rgpsz[CSTRINGS];
|
||
|
extern LPTSTR gpszNum;
|
||
|
extern BOOL bError;
|
||
|
extern INT nLayout;
|
||
|
|
||
|
extern HMENU g_hDecMenu;
|
||
|
extern HMENU g_hHexMenu;
|
||
|
|
||
|
extern CALCINPUTOBJ gcio;
|
||
|
extern BOOL gbRecord;
|
||
|
extern BOOL gbUseSep;
|
||
|
|
||
|
/* Menu handling routine for COPY, PASTE, ABOUT, and HELP. */
|
||
|
VOID NEAR PASCAL MemErrorMessage(VOID)
|
||
|
{
|
||
|
MessageBeep(0);
|
||
|
MessageBox(g_hwndDlg,rgpsz[IDS_STATMEM],NULL,MB_OK|MB_ICONHAND);
|
||
|
}
|
||
|
|
||
|
VOID APIENTRY MenuFunctions(DWORD nFunc)
|
||
|
{
|
||
|
INT nx;
|
||
|
static const int rgbMap[CHARSCAN * 2]=
|
||
|
{
|
||
|
TEXT('0'),IDC_0, TEXT('1'),IDC_1,
|
||
|
TEXT('2'),IDC_2, TEXT('3'),IDC_3,
|
||
|
|
||
|
TEXT('4'),IDC_4, TEXT('5'),IDC_5,
|
||
|
TEXT('6'),IDC_6, TEXT('7'),IDC_7,
|
||
|
|
||
|
TEXT('8'),IDC_8, TEXT('9'),IDC_9,
|
||
|
TEXT('A'),IDC_A, TEXT('B'),IDC_B,
|
||
|
|
||
|
TEXT('C'),IDC_C, TEXT('D'),IDC_D,
|
||
|
TEXT('E'),IDC_E, TEXT('F'),IDC_F,
|
||
|
|
||
|
TEXT('!'),IDC_FAC, TEXT('S'),IDC_SIN,
|
||
|
TEXT('O'),IDC_COS, TEXT('T'),IDC_TAN,
|
||
|
|
||
|
TEXT('R'),IDC_REC, TEXT('Y'),IDC_PWR,
|
||
|
TEXT('#'),IDC_CUB, TEXT('@'),IDC_SQR,
|
||
|
|
||
|
TEXT('M'),IDM_DEG, TEXT('N'),IDC_LN,
|
||
|
TEXT('L'),IDC_LOG, TEXT('V'),IDC_FE,
|
||
|
|
||
|
TEXT('X'),IDC_EXP, TEXT('I'),IDC_INV,
|
||
|
TEXT('H'),IDC_HYP, TEXT('P'),IDC_PI,
|
||
|
|
||
|
TEXT('/'),IDC_DIV, TEXT('*'),IDC_MUL,
|
||
|
TEXT('%'),IDC_MOD, TEXT('-'),IDC_SUB,
|
||
|
|
||
|
TEXT('='),IDC_EQU, TEXT('+'),IDC_ADD,
|
||
|
TEXT('&'),IDC_AND, TEXT('|'),IDC_OR,
|
||
|
|
||
|
TEXT('^'),IDC_XOR, TEXT('~'),IDC_COM,
|
||
|
TEXT(';'),IDC_CHOP, TEXT('<'),IDC_LSHF,
|
||
|
|
||
|
|
||
|
TEXT('('),IDC_OPENP,TEXT(')'),IDC_CLOSEP,
|
||
|
|
||
|
TEXT('\\'), IDC_DATA,
|
||
|
TEXT('Q'), IDC_CLEAR,
|
||
|
TEXT('Q')+128, IDC_CLEAR, // ":Q"=="Q"=>CLEAR
|
||
|
TEXT('S')+128, IDC_STAT, // ":S"=>CTRL-S
|
||
|
TEXT('M')+128, IDC_STORE, // ":M"=>CTRL-M
|
||
|
TEXT('P')+128, IDC_MPLUS, // ":P"=>CTRL-P
|
||
|
TEXT('C')+128, IDC_MCLEAR, // ":C"=>CTRL-C
|
||
|
TEXT('R')+128, IDC_RECALL, // ":R"=>CTRL-R
|
||
|
TEXT('A')+128, IDC_AVE, // ":A"=>CTRL-A
|
||
|
TEXT('T')+128, IDC_B_SUM, // ":T"=>CTRL-T
|
||
|
TEXT('D')+128, IDC_DEV, // ":D"=>CTRL-D
|
||
|
TEXT('2')+128, IDC_DWORD, // ":2"=>F2 IDC_DWORD
|
||
|
TEXT('3')+128, IDC_RAD, // ":3"=>F3 IDC_WORD
|
||
|
TEXT('4')+128, IDC_GRAD, // ":4"=>F4 IDC_BYTE
|
||
|
TEXT('5')+128, IDC_HEX, // ":5"=>F5
|
||
|
TEXT('6')+128, IDC_DEC, // ":6"=>F6
|
||
|
TEXT('7')+128, IDC_OCT, // ":7"=>F7
|
||
|
TEXT('8')+128, IDC_BIN, // ":8"=>F8
|
||
|
TEXT('9')+128, IDC_SIGN, // ":9"=>F9
|
||
|
TEXT('9')+3+128, IDC_QWORD // ":9"+2=>F12 (64 bit)
|
||
|
};
|
||
|
|
||
|
switch (nFunc)
|
||
|
{
|
||
|
case IDM_COPY:
|
||
|
{
|
||
|
TCHAR szJunk[256];
|
||
|
|
||
|
// Copy the string into a work buffer. It may be modified.
|
||
|
if (gbRecord)
|
||
|
CIO_vConvertToString(&gpszNum, &gcio, nRadix);
|
||
|
|
||
|
lstrcpy(szJunk, gpszNum);
|
||
|
|
||
|
// Strip a trailing decimal point if it wasn't explicitly entered.
|
||
|
if (!gbRecord || !CIO_bDecimalPt(&gcio))
|
||
|
{
|
||
|
nx = lstrlen(szJunk);
|
||
|
if (szJunk[nx - 1] == szDec[0])
|
||
|
szJunk[nx - 1] = 0;
|
||
|
}
|
||
|
|
||
|
/* Copy text to the clipboard through the hidden edit control.*/
|
||
|
SetWindowText(hEdit, szJunk);
|
||
|
SendMessage(hEdit, EM_SETSEL, 0, -1); // select all text
|
||
|
SendMessage(hEdit, WM_CUT, 0, 0L);
|
||
|
break;
|
||
|
}
|
||
|
|
||
|
case IDM_PASTE:
|
||
|
{
|
||
|
HANDLE hClipData;
|
||
|
char * lpClipData;
|
||
|
char * lpEndOfBuffer; // used to ensure we don't GPF even if the clipboard data isn't NULL terminated
|
||
|
WORD b, bLast;
|
||
|
INT nControl;
|
||
|
BOOL bNeedIDC_SIGN = FALSE;
|
||
|
|
||
|
/* Get a handle on the clipboard data and paste by sending the*/
|
||
|
/* contents one character at a time like it was typed. */
|
||
|
if (!OpenClipboard(g_hwndDlg))
|
||
|
{
|
||
|
MessageBox(g_hwndDlg, rgpsz[IDS_NOPASTE], rgpsz[IDS_CALC],
|
||
|
MB_OK | MB_ICONEXCLAMATION);
|
||
|
break;
|
||
|
}
|
||
|
|
||
|
hClipData=GetClipboardData(CF_TEXT);
|
||
|
if (hClipData)
|
||
|
{
|
||
|
lpClipData=(char *)GlobalLock(hClipData);
|
||
|
if (lpClipData)
|
||
|
{
|
||
|
lpEndOfBuffer = lpClipData + GlobalSize(hClipData);
|
||
|
bLast=0;
|
||
|
|
||
|
/* Continue this as long as no error occurs. If one */
|
||
|
/* does then it's useless to continue pasting. */
|
||
|
while (!bError && lpClipData < lpEndOfBuffer)
|
||
|
{
|
||
|
// we know that lpClipData points to a NULL terminated ansi
|
||
|
// string because this is the format we requested the data in.
|
||
|
// As a result we call CharNextA.
|
||
|
|
||
|
b = *lpClipData;
|
||
|
lpClipData = CharNextA( lpClipData );
|
||
|
|
||
|
/* Skip spaces and LF and CR. */
|
||
|
if (b==32 || b==10 || b==13 || b==gszSep[0])
|
||
|
continue;
|
||
|
|
||
|
/* We're done if we get to a NULL character */
|
||
|
if ( b==0 )
|
||
|
break;
|
||
|
|
||
|
if (b == szDec[0])
|
||
|
{
|
||
|
bLast = b;
|
||
|
b = IDC_PNT;
|
||
|
goto MappingDone;
|
||
|
}
|
||
|
|
||
|
/*-----------------------------------------------------------------------------;
|
||
|
; Now we will check for certain special cases. These are: ;
|
||
|
; ;
|
||
|
; (1) Unary Minus. If bLast is still 0 and b is '-' we will force b to ;
|
||
|
; be the code for 'SIGN'. ;
|
||
|
; (2) If b is 'x' we will make it the code for EXP ;
|
||
|
; (3) if bLast is 'x' and b is '+' we will ignore b, as '+' is the dflt. ;
|
||
|
; (4) if bLast is 'x' and b is '-' we will force b to be SIGN. ;
|
||
|
; ;
|
||
|
; In case (3) we will go back to the top of the loop else we will jmp off ;
|
||
|
; to the sendmessage point, bypassing the table lookup. ;
|
||
|
;-----------------------------------------------------------------------------*/
|
||
|
|
||
|
/* check for unary minuses */
|
||
|
if (!bLast && b == TEXT('-'))
|
||
|
{
|
||
|
/* Doesn't work.
|
||
|
bLast = b ;
|
||
|
b = IDC_SIGN ;
|
||
|
goto MappingDone ;
|
||
|
*/
|
||
|
bNeedIDC_SIGN = TRUE ;
|
||
|
continue ;
|
||
|
}
|
||
|
|
||
|
/* check for 'x' */
|
||
|
if ((b == TEXT('x') || b == TEXT('e')) && nRadix == 10)
|
||
|
{
|
||
|
bLast = TEXT('x') ;
|
||
|
b = IDC_EXP ;
|
||
|
goto MappingDone ;
|
||
|
}
|
||
|
|
||
|
/* if the last character was a 'x' & this is '+' - ignore */
|
||
|
if (bLast==TEXT('x') && b ==TEXT('+') && nRadix == 10)
|
||
|
continue ;
|
||
|
|
||
|
/* if the last character was a 'x' & this is '-' - change
|
||
|
it to be the code for SIGN */
|
||
|
if (bLast==TEXT('x') && b==TEXT('-') && nRadix == 10)
|
||
|
{
|
||
|
bLast = b ;
|
||
|
b = IDC_SIGN ;
|
||
|
goto MappingDone ;
|
||
|
}
|
||
|
|
||
|
/* -by- AmitC */
|
||
|
/*--------------------------------------------------------------------------*/
|
||
|
|
||
|
|
||
|
/* Check for control character. */
|
||
|
if (bLast==TEXT(':'))
|
||
|
nControl=128;
|
||
|
else
|
||
|
nControl=0;
|
||
|
|
||
|
bLast=b;
|
||
|
if (b==TEXT(':'))
|
||
|
continue;
|
||
|
|
||
|
b=toupper(b)+nControl;
|
||
|
|
||
|
nx=0;
|
||
|
while (b!=rgbMap[nx*2] && nx < CHARSCAN)
|
||
|
nx++;
|
||
|
|
||
|
if (nx==CHARSCAN)
|
||
|
break;
|
||
|
|
||
|
b=(WORD)rgbMap[(nx*2)+1];
|
||
|
|
||
|
if (nRadix != 10)
|
||
|
{
|
||
|
switch(b)
|
||
|
{
|
||
|
case IDC_DEG:
|
||
|
case IDC_RAD:
|
||
|
case IDC_GRAD:
|
||
|
b=IDC_DWORD+(b-IDC_DEG);
|
||
|
break;
|
||
|
}
|
||
|
}
|
||
|
|
||
|
// REVIEW NOTE:
|
||
|
// Conversion of IDC_MOD to IDC_PERCENT done in WM_COMMAND
|
||
|
// processing so that keyboard accelerator and paste are
|
||
|
// handled in the same place. The old conversion was broken
|
||
|
// anyway and actually happened in
|
||
|
|
||
|
MappingDone:
|
||
|
/* Send the message to the window. */
|
||
|
SendMessage(g_hwndDlg, WM_COMMAND, GET_WM_COMMAND_MPS(b, 0, 1));
|
||
|
/* Note that we may need to apply the "+/-" key (IDC_SIGN)
|
||
|
now. (If it had been applied earlier, it would have
|
||
|
been ignored.) Note further that it can't be applied if we
|
||
|
have seen only the "-0" of something like "-0.1". */
|
||
|
if(bNeedIDC_SIGN && (IDC_0 != b))
|
||
|
{
|
||
|
SendMessage(g_hwndDlg, WM_COMMAND, GET_WM_COMMAND_MPS(IDC_SIGN, 0, 1));
|
||
|
bNeedIDC_SIGN = FALSE;
|
||
|
}
|
||
|
}
|
||
|
GlobalUnlock(hClipData);
|
||
|
}
|
||
|
}
|
||
|
CloseClipboard();
|
||
|
break;
|
||
|
}
|
||
|
|
||
|
case IDM_ABOUT:
|
||
|
/* Start the About Box. */
|
||
|
if(ShellAbout(g_hwndDlg, rgpsz[IDS_CALC], NULL, LoadIcon(hInst, (LPTSTR)TEXT("SC"))) == -1)
|
||
|
MemErrorMessage();
|
||
|
|
||
|
break;
|
||
|
|
||
|
case IDM_SC:
|
||
|
case IDM_SSC:
|
||
|
{
|
||
|
INT nTemp;
|
||
|
TCHAR szWinIni[2];
|
||
|
|
||
|
nTemp = (INT) nFunc - IDM_SC;
|
||
|
if (nCalc != nTemp)
|
||
|
{
|
||
|
szWinIni[0] = TEXT('0') + nTemp;
|
||
|
szWinIni[1]=0;
|
||
|
WriteProfileString(szAppName, TEXT("layout"), szWinIni);
|
||
|
|
||
|
if (hStatBox && !nCalc)
|
||
|
SetStat(FALSE);
|
||
|
|
||
|
nCalc = nTemp;
|
||
|
InitSciCalc(TRUE);
|
||
|
}
|
||
|
break;
|
||
|
}
|
||
|
|
||
|
case IDM_USE_SEPARATOR:
|
||
|
{
|
||
|
gbUseSep = !gbUseSep;
|
||
|
|
||
|
CheckMenuItem(g_hDecMenu, IDM_USE_SEPARATOR,
|
||
|
MF_BYCOMMAND|(gbUseSep ? MF_CHECKED : MF_UNCHECKED));
|
||
|
|
||
|
if (g_hHexMenu)
|
||
|
{
|
||
|
CheckMenuItem(g_hHexMenu, IDM_USE_SEPARATOR,
|
||
|
MF_BYCOMMAND | \
|
||
|
(gbUseSep ? MF_CHECKED:MF_UNCHECKED));
|
||
|
}
|
||
|
|
||
|
WriteProfileString(szAppName,TEXT("UseSep"),
|
||
|
(gbUseSep ? TEXT("1") : TEXT("0")));
|
||
|
|
||
|
break;
|
||
|
}
|
||
|
|
||
|
case IDM_HELPTOPICS:
|
||
|
HtmlHelp(GetDesktopWindow(), rgpsz[IDS_CHMHELPFILE], HH_DISPLAY_TOPIC, 0L);
|
||
|
break;
|
||
|
}
|
||
|
|
||
|
return;
|
||
|
}
|