Source code of Windows XP (NT5)
You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

360 lines
14 KiB

  1. /**************************************************************************/
  2. /*** SCICALC Scientific Calculator for Windows 3.00.12 ***/
  3. /*** By Kraig Brockschmidt, Microsoft Co-op, Contractor, 1988-1989 ***/
  4. /*** (c)1989 Microsoft Corporation. All Rights Reserved. ***/
  5. /*** ***/
  6. /*** scimenu.c ***/
  7. /*** ***/
  8. /*** Functions contained: ***/
  9. /*** MenuFunctions--handles menu options. ***/
  10. /*** ***/
  11. /*** Functions called: ***/
  12. /*** DisplayNum ***/
  13. /*** ***/
  14. /*** Last modification Thu 06-Dec-1989 ***/
  15. /*** (-by- Amit Chatterjee [amitc]) ***/
  16. /*** ***/
  17. /*** Modified the 'PASTE' menu to check for unary minus, e, e+ & e- ***/
  18. /*** in DEC mode. ***/
  19. /*** ***/
  20. /*** Also modified the COPY code to not copy the last '.' in the display***/
  21. /*** if a decimal point has not been hit. ***/
  22. /*** ***/
  23. /**************************************************************************/
  24. #include "scicalc.h"
  25. #include "unifunc.h"
  26. #include "input.h"
  27. #include <shellapi.h>
  28. #include <ctype.h>
  29. #define CHARSCAN 66
  30. extern HWND hEdit, hStatBox;
  31. extern TCHAR szAppName[10], szDec[5], gszSep[5], *rgpsz[CSTRINGS];
  32. extern LPTSTR gpszNum;
  33. extern BOOL bError;
  34. extern INT nLayout;
  35. extern HMENU g_hDecMenu;
  36. extern HMENU g_hHexMenu;
  37. extern CALCINPUTOBJ gcio;
  38. extern BOOL gbRecord;
  39. extern BOOL gbUseSep;
  40. /* Menu handling routine for COPY, PASTE, ABOUT, and HELP. */
  41. VOID NEAR PASCAL MemErrorMessage(VOID)
  42. {
  43. MessageBeep(0);
  44. MessageBox(g_hwndDlg,rgpsz[IDS_STATMEM],NULL,MB_OK|MB_ICONHAND);
  45. }
  46. VOID APIENTRY MenuFunctions(DWORD nFunc)
  47. {
  48. INT nx;
  49. static const int rgbMap[CHARSCAN * 2]=
  50. {
  51. TEXT('0'),IDC_0, TEXT('1'),IDC_1,
  52. TEXT('2'),IDC_2, TEXT('3'),IDC_3,
  53. TEXT('4'),IDC_4, TEXT('5'),IDC_5,
  54. TEXT('6'),IDC_6, TEXT('7'),IDC_7,
  55. TEXT('8'),IDC_8, TEXT('9'),IDC_9,
  56. TEXT('A'),IDC_A, TEXT('B'),IDC_B,
  57. TEXT('C'),IDC_C, TEXT('D'),IDC_D,
  58. TEXT('E'),IDC_E, TEXT('F'),IDC_F,
  59. TEXT('!'),IDC_FAC, TEXT('S'),IDC_SIN,
  60. TEXT('O'),IDC_COS, TEXT('T'),IDC_TAN,
  61. TEXT('R'),IDC_REC, TEXT('Y'),IDC_PWR,
  62. TEXT('#'),IDC_CUB, TEXT('@'),IDC_SQR,
  63. TEXT('M'),IDM_DEG, TEXT('N'),IDC_LN,
  64. TEXT('L'),IDC_LOG, TEXT('V'),IDC_FE,
  65. TEXT('X'),IDC_EXP, TEXT('I'),IDC_INV,
  66. TEXT('H'),IDC_HYP, TEXT('P'),IDC_PI,
  67. TEXT('/'),IDC_DIV, TEXT('*'),IDC_MUL,
  68. TEXT('%'),IDC_MOD, TEXT('-'),IDC_SUB,
  69. TEXT('='),IDC_EQU, TEXT('+'),IDC_ADD,
  70. TEXT('&'),IDC_AND, TEXT('|'),IDC_OR,
  71. TEXT('^'),IDC_XOR, TEXT('~'),IDC_COM,
  72. TEXT(';'),IDC_CHOP, TEXT('<'),IDC_LSHF,
  73. TEXT('('),IDC_OPENP,TEXT(')'),IDC_CLOSEP,
  74. TEXT('\\'), IDC_DATA,
  75. TEXT('Q'), IDC_CLEAR,
  76. TEXT('Q')+128, IDC_CLEAR, // ":Q"=="Q"=>CLEAR
  77. TEXT('S')+128, IDC_STAT, // ":S"=>CTRL-S
  78. TEXT('M')+128, IDC_STORE, // ":M"=>CTRL-M
  79. TEXT('P')+128, IDC_MPLUS, // ":P"=>CTRL-P
  80. TEXT('C')+128, IDC_MCLEAR, // ":C"=>CTRL-C
  81. TEXT('R')+128, IDC_RECALL, // ":R"=>CTRL-R
  82. TEXT('A')+128, IDC_AVE, // ":A"=>CTRL-A
  83. TEXT('T')+128, IDC_B_SUM, // ":T"=>CTRL-T
  84. TEXT('D')+128, IDC_DEV, // ":D"=>CTRL-D
  85. TEXT('2')+128, IDC_DWORD, // ":2"=>F2 IDC_DWORD
  86. TEXT('3')+128, IDC_RAD, // ":3"=>F3 IDC_WORD
  87. TEXT('4')+128, IDC_GRAD, // ":4"=>F4 IDC_BYTE
  88. TEXT('5')+128, IDC_HEX, // ":5"=>F5
  89. TEXT('6')+128, IDC_DEC, // ":6"=>F6
  90. TEXT('7')+128, IDC_OCT, // ":7"=>F7
  91. TEXT('8')+128, IDC_BIN, // ":8"=>F8
  92. TEXT('9')+128, IDC_SIGN, // ":9"=>F9
  93. TEXT('9')+3+128, IDC_QWORD // ":9"+2=>F12 (64 bit)
  94. };
  95. switch (nFunc)
  96. {
  97. case IDM_COPY:
  98. {
  99. TCHAR szJunk[256];
  100. // Copy the string into a work buffer. It may be modified.
  101. if (gbRecord)
  102. CIO_vConvertToString(&gpszNum, &gcio, nRadix);
  103. lstrcpy(szJunk, gpszNum);
  104. // Strip a trailing decimal point if it wasn't explicitly entered.
  105. if (!gbRecord || !CIO_bDecimalPt(&gcio))
  106. {
  107. nx = lstrlen(szJunk);
  108. if (szJunk[nx - 1] == szDec[0])
  109. szJunk[nx - 1] = 0;
  110. }
  111. /* Copy text to the clipboard through the hidden edit control.*/
  112. SetWindowText(hEdit, szJunk);
  113. SendMessage(hEdit, EM_SETSEL, 0, -1); // select all text
  114. SendMessage(hEdit, WM_CUT, 0, 0L);
  115. break;
  116. }
  117. case IDM_PASTE:
  118. {
  119. HANDLE hClipData;
  120. char * lpClipData;
  121. char * lpEndOfBuffer; // used to ensure we don't GPF even if the clipboard data isn't NULL terminated
  122. WORD b, bLast;
  123. INT nControl;
  124. BOOL bNeedIDC_SIGN = FALSE;
  125. /* Get a handle on the clipboard data and paste by sending the*/
  126. /* contents one character at a time like it was typed. */
  127. if (!OpenClipboard(g_hwndDlg))
  128. {
  129. MessageBox(g_hwndDlg, rgpsz[IDS_NOPASTE], rgpsz[IDS_CALC],
  130. MB_OK | MB_ICONEXCLAMATION);
  131. break;
  132. }
  133. hClipData=GetClipboardData(CF_TEXT);
  134. if (hClipData)
  135. {
  136. lpClipData=(char *)GlobalLock(hClipData);
  137. if (lpClipData)
  138. {
  139. lpEndOfBuffer = lpClipData + GlobalSize(hClipData);
  140. bLast=0;
  141. /* Continue this as long as no error occurs. If one */
  142. /* does then it's useless to continue pasting. */
  143. while (!bError && lpClipData < lpEndOfBuffer)
  144. {
  145. // we know that lpClipData points to a NULL terminated ansi
  146. // string because this is the format we requested the data in.
  147. // As a result we call CharNextA.
  148. b = *lpClipData;
  149. lpClipData = CharNextA( lpClipData );
  150. /* Skip spaces and LF and CR. */
  151. if (b==32 || b==10 || b==13 || b==gszSep[0])
  152. continue;
  153. /* We're done if we get to a NULL character */
  154. if ( b==0 )
  155. break;
  156. if (b == szDec[0])
  157. {
  158. bLast = b;
  159. b = IDC_PNT;
  160. goto MappingDone;
  161. }
  162. /*-----------------------------------------------------------------------------;
  163. ; Now we will check for certain special cases. These are: ;
  164. ; ;
  165. ; (1) Unary Minus. If bLast is still 0 and b is '-' we will force b to ;
  166. ; be the code for 'SIGN'. ;
  167. ; (2) If b is 'x' we will make it the code for EXP ;
  168. ; (3) if bLast is 'x' and b is '+' we will ignore b, as '+' is the dflt. ;
  169. ; (4) if bLast is 'x' and b is '-' we will force b to be SIGN. ;
  170. ; ;
  171. ; In case (3) we will go back to the top of the loop else we will jmp off ;
  172. ; to the sendmessage point, bypassing the table lookup. ;
  173. ;-----------------------------------------------------------------------------*/
  174. /* check for unary minuses */
  175. if (!bLast && b == TEXT('-'))
  176. {
  177. /* Doesn't work.
  178. bLast = b ;
  179. b = IDC_SIGN ;
  180. goto MappingDone ;
  181. */
  182. bNeedIDC_SIGN = TRUE ;
  183. continue ;
  184. }
  185. /* check for 'x' */
  186. if ((b == TEXT('x') || b == TEXT('e')) && nRadix == 10)
  187. {
  188. bLast = TEXT('x') ;
  189. b = IDC_EXP ;
  190. goto MappingDone ;
  191. }
  192. /* if the last character was a 'x' & this is '+' - ignore */
  193. if (bLast==TEXT('x') && b ==TEXT('+') && nRadix == 10)
  194. continue ;
  195. /* if the last character was a 'x' & this is '-' - change
  196. it to be the code for SIGN */
  197. if (bLast==TEXT('x') && b==TEXT('-') && nRadix == 10)
  198. {
  199. bLast = b ;
  200. b = IDC_SIGN ;
  201. goto MappingDone ;
  202. }
  203. /* -by- AmitC */
  204. /*--------------------------------------------------------------------------*/
  205. /* Check for control character. */
  206. if (bLast==TEXT(':'))
  207. nControl=128;
  208. else
  209. nControl=0;
  210. bLast=b;
  211. if (b==TEXT(':'))
  212. continue;
  213. b=toupper(b)+nControl;
  214. nx=0;
  215. while (b!=rgbMap[nx*2] && nx < CHARSCAN)
  216. nx++;
  217. if (nx==CHARSCAN)
  218. break;
  219. b=(WORD)rgbMap[(nx*2)+1];
  220. if (nRadix != 10)
  221. {
  222. switch(b)
  223. {
  224. case IDC_DEG:
  225. case IDC_RAD:
  226. case IDC_GRAD:
  227. b=IDC_DWORD+(b-IDC_DEG);
  228. break;
  229. }
  230. }
  231. // REVIEW NOTE:
  232. // Conversion of IDC_MOD to IDC_PERCENT done in WM_COMMAND
  233. // processing so that keyboard accelerator and paste are
  234. // handled in the same place. The old conversion was broken
  235. // anyway and actually happened in
  236. MappingDone:
  237. /* Send the message to the window. */
  238. SendMessage(g_hwndDlg, WM_COMMAND, GET_WM_COMMAND_MPS(b, 0, 1));
  239. /* Note that we may need to apply the "+/-" key (IDC_SIGN)
  240. now. (If it had been applied earlier, it would have
  241. been ignored.) Note further that it can't be applied if we
  242. have seen only the "-0" of something like "-0.1". */
  243. if(bNeedIDC_SIGN && (IDC_0 != b))
  244. {
  245. SendMessage(g_hwndDlg, WM_COMMAND, GET_WM_COMMAND_MPS(IDC_SIGN, 0, 1));
  246. bNeedIDC_SIGN = FALSE;
  247. }
  248. }
  249. GlobalUnlock(hClipData);
  250. }
  251. }
  252. CloseClipboard();
  253. break;
  254. }
  255. case IDM_ABOUT:
  256. /* Start the About Box. */
  257. if(ShellAbout(g_hwndDlg, rgpsz[IDS_CALC], NULL, LoadIcon(hInst, (LPTSTR)TEXT("SC"))) == -1)
  258. MemErrorMessage();
  259. break;
  260. case IDM_SC:
  261. case IDM_SSC:
  262. {
  263. INT nTemp;
  264. TCHAR szWinIni[2];
  265. nTemp = (INT) nFunc - IDM_SC;
  266. if (nCalc != nTemp)
  267. {
  268. szWinIni[0] = TEXT('0') + nTemp;
  269. szWinIni[1]=0;
  270. WriteProfileString(szAppName, TEXT("layout"), szWinIni);
  271. if (hStatBox && !nCalc)
  272. SetStat(FALSE);
  273. nCalc = nTemp;
  274. InitSciCalc(TRUE);
  275. }
  276. break;
  277. }
  278. case IDM_USE_SEPARATOR:
  279. {
  280. gbUseSep = !gbUseSep;
  281. CheckMenuItem(g_hDecMenu, IDM_USE_SEPARATOR,
  282. MF_BYCOMMAND|(gbUseSep ? MF_CHECKED : MF_UNCHECKED));
  283. if (g_hHexMenu)
  284. {
  285. CheckMenuItem(g_hHexMenu, IDM_USE_SEPARATOR,
  286. MF_BYCOMMAND | \
  287. (gbUseSep ? MF_CHECKED:MF_UNCHECKED));
  288. }
  289. WriteProfileString(szAppName,TEXT("UseSep"),
  290. (gbUseSep ? TEXT("1") : TEXT("0")));
  291. break;
  292. }
  293. case IDM_HELPTOPICS:
  294. HtmlHelp(GetDesktopWindow(), rgpsz[IDS_CHMHELPFILE], HH_DISPLAY_TOPIC, 0L);
  295. break;
  296. }
  297. return;
  298. }