[NTOSKRNL]
[reactos.git] / base / applications / calc / winmain.c
1 #include "calc.h"
2
3 #define HTMLHELP_PATH(_pt) TEXT("%systemroot%\\Help\\calc.chm::") TEXT(_pt)
4
5 #define MAKE_BITMASK4(_show_b16, _show_b10, _show_b8, _show_b2) \
6 (((_show_b2) << 0) | \
7 ((_show_b8) << 1) | \
8 ((_show_b10) << 2) | \
9 ((_show_b16) << 3))
10
11 #define MAKE_BITMASK5(_transl, _is_stats, _is_ctrl, _show_b16, _show_b10, _show_b8, _show_b2) \
12 (((_show_b2) << 0) | \
13 ((_show_b8) << 1) | \
14 ((_show_b10) << 2) | \
15 ((_show_b16) << 3) | \
16 ((_is_ctrl) << 5) | \
17 ((_is_stats) << 6) | \
18 ((_transl) << 7))
19
20 #define KEY_IS_UP 0x80000000
21 #define KEY_WAS_DOWN 0x40000000
22
23 #define BITMASK_IS_ASCII 0x80
24 #define BITMASK_IS_STATS 0x40
25 #define BITMASK_IS_CTRL 0x20
26 #define BITMASK_HEX_MASK 0x08
27 #define BITMASK_DEC_MASK 0x04
28 #define BITMASK_OCT_MASK 0x02
29 #define BITMASK_BIN_MASK 0x01
30
31 #define CALC_CLR_RED 0x000000FF
32 #define CALC_CLR_BLUE 0x00FF0000
33 #define CALC_CLR_PURP 0x00FF00FF
34
35 typedef struct {
36 CHAR key; // Virtual key identifier
37 WORD idc; // IDC for posting message
38 } key2code_t;
39
40 typedef struct {
41 WORD idc; // IDC for posting message
42 CHAR key; // Virtual key identifier
43 BYTE mask; // enable/disable into the various modes.
44 COLORREF col; // color used for drawing the text
45 } key3code_t;
46
47 #define CTRL_FLAG 0x100
48 #define ALT_FLAG 0x200
49
50 #define CTRL_A (0x0001+'A'-'A')
51 #define CTRL_C (0x0001+'C'-'A')
52 #define CTRL_D (0x0001+'D'-'A')
53 #define CTRL_L (0x0001+'L'-'A')
54 #define CTRL_M (0x0001+'M'-'A')
55 #define CTRL_P (0x0001+'P'-'A')
56 #define CTRL_R (0x0001+'R'-'A')
57 #define CTRL_S (0x0001+'S'-'A')
58 #define CTRL_T (0x0001+'T'-'A')
59 #define CTRL_V (0x0001+'V'-'A')
60 #define CTRL_Z (0x0001+'Z'-'A')
61
62 static const key3code_t key2code[] = {
63 /* CONTROL-ID Key asc sta ctl hex dec oct bin */
64 { IDC_BUTTON_STA, CTRL_S, MAKE_BITMASK5( 1, 0, 1, 1, 1, 1, 1), CALC_CLR_BLUE, },
65 { IDC_BUTTON_AVE, CTRL_A, MAKE_BITMASK5( 1, 1, 1, 1, 1, 1, 1), CALC_CLR_BLUE, },
66 { IDC_BUTTON_SUM, CTRL_T, MAKE_BITMASK5( 1, 1, 1, 1, 1, 1, 1), CALC_CLR_BLUE, },
67 { IDC_BUTTON_S, CTRL_D, MAKE_BITMASK5( 1, 1, 1, 1, 1, 1, 1), CALC_CLR_BLUE, },
68 { IDC_BUTTON_MS, CTRL_M, MAKE_BITMASK5( 1, 0, 1, 1, 1, 1, 1), CALC_CLR_RED, },
69 { IDC_BUTTON_MR, CTRL_R, MAKE_BITMASK5( 1, 0, 1, 1, 1, 1, 1), CALC_CLR_RED, },
70 { IDC_BUTTON_MP, CTRL_P, MAKE_BITMASK5( 1, 0, 1, 1, 1, 1, 1), CALC_CLR_RED, },
71 { IDC_BUTTON_MC, CTRL_L, MAKE_BITMASK5( 1, 0, 1, 1, 1, 1, 1), CALC_CLR_RED, },
72 { IDC_BUTTON_0, '0', MAKE_BITMASK5( 1, 0, 0, 1, 1, 1, 1), CALC_CLR_BLUE, },
73 { IDC_BUTTON_1, '1', MAKE_BITMASK5( 1, 0, 0, 1, 1, 1, 1), CALC_CLR_BLUE, },
74 { IDC_BUTTON_2, '2', MAKE_BITMASK5( 1, 0, 0, 1, 1, 1, 0), CALC_CLR_BLUE, },
75 { IDC_BUTTON_3, '3', MAKE_BITMASK5( 1, 0, 0, 1, 1, 1, 0), CALC_CLR_BLUE, },
76 { IDC_BUTTON_4, '4', MAKE_BITMASK5( 1, 0, 0, 1, 1, 1, 0), CALC_CLR_BLUE, },
77 { IDC_BUTTON_5, '5', MAKE_BITMASK5( 1, 0, 0, 1, 1, 1, 0), CALC_CLR_BLUE, },
78 { IDC_BUTTON_6, '6', MAKE_BITMASK5( 1, 0, 0, 1, 1, 1, 0), CALC_CLR_BLUE, },
79 { IDC_BUTTON_7, '7', MAKE_BITMASK5( 1, 0, 0, 1, 1, 1, 0), CALC_CLR_BLUE, },
80 { IDC_BUTTON_8, '8', MAKE_BITMASK5( 1, 0, 0, 1, 1, 0, 0), CALC_CLR_BLUE, },
81 { IDC_BUTTON_9, '9', MAKE_BITMASK5( 1, 0, 0, 1, 1, 0, 0), CALC_CLR_BLUE, },
82 { IDC_BUTTON_DOT, '.', MAKE_BITMASK5( 1, 0, 0, 0, 1, 0, 0), CALC_CLR_BLUE, },
83 { IDC_BUTTON_DOT, ',', MAKE_BITMASK5( 1, 0, 0, 0, 1, 0, 0), -1, },
84 { IDC_BUTTON_ADD, '+', MAKE_BITMASK5( 1, 0, 0, 1, 1, 1, 1), CALC_CLR_RED, },
85 { IDC_BUTTON_SUB, '-', MAKE_BITMASK5( 1, 0, 0, 1, 1, 1, 1), CALC_CLR_RED, },
86 { IDC_BUTTON_MULT, '*', MAKE_BITMASK5( 1, 0, 0, 1, 1, 1, 1), CALC_CLR_RED, },
87 { IDC_BUTTON_DIV, '/', MAKE_BITMASK5( 1, 0, 0, 1, 1, 1, 1), CALC_CLR_RED, },
88 { IDC_BUTTON_AND, '&', MAKE_BITMASK5( 1, 0, 0, 1, 1, 1, 1), CALC_CLR_RED, },
89 { IDC_BUTTON_OR, '|', MAKE_BITMASK5( 1, 0, 0, 1, 1, 1, 1), CALC_CLR_RED, },
90 { IDC_BUTTON_XOR, '^', MAKE_BITMASK5( 1, 0, 0, 1, 1, 1, 1), CALC_CLR_RED, },
91 { IDC_BUTTON_LSH, '<', MAKE_BITMASK5( 1, 0, 0, 1, 1, 1, 1), CALC_CLR_RED, },
92 { IDC_BUTTON_NOT, '~', MAKE_BITMASK5( 1, 0, 0, 1, 1, 1, 1), CALC_CLR_RED, },
93 { IDC_BUTTON_INT, ';', MAKE_BITMASK5( 1, 0, 0, 0, 1, 0, 0), CALC_CLR_RED, },
94 { IDC_BUTTON_EQU, '=', MAKE_BITMASK5( 1, 0, 0, 1, 1, 1, 1), CALC_CLR_RED, },
95 { IDC_BUTTON_A, 'A', MAKE_BITMASK5( 1, 0, 0, 1, 0, 0, 0), CALC_CLR_BLUE, },
96 { IDC_BUTTON_B, 'B', MAKE_BITMASK5( 1, 0, 0, 1, 0, 0, 0), CALC_CLR_BLUE, },
97 { IDC_BUTTON_C, 'C', MAKE_BITMASK5( 1, 0, 0, 1, 0, 0, 0), CALC_CLR_BLUE, },
98 { IDC_BUTTON_D, 'D', MAKE_BITMASK5( 1, 0, 0, 1, 0, 0, 0), CALC_CLR_BLUE, },
99 { IDC_BUTTON_E, 'E', MAKE_BITMASK5( 1, 0, 0, 1, 0, 0, 0), CALC_CLR_BLUE, },
100 { IDC_BUTTON_F, 'F', MAKE_BITMASK5( 1, 0, 0, 1, 0, 0, 0), CALC_CLR_BLUE, },
101 { IDC_CHECK_HYP, 'H', MAKE_BITMASK5( 1, 0, 0, 1, 1, 1, 1), -1, },
102 { IDC_CHECK_INV, 'I', MAKE_BITMASK5( 1, 0, 0, 1, 1, 1, 1), -1, },
103 { IDC_BUTTON_LOG, 'L', MAKE_BITMASK5( 1, 0, 0, 0, 1, 0, 0), CALC_CLR_PURP, },
104 { IDC_BUTTON_DMS, 'M', MAKE_BITMASK5( 1, 0, 0, 0, 1, 0, 0), CALC_CLR_PURP, },
105 { IDC_BUTTON_LN, 'N', MAKE_BITMASK5( 1, 0, 0, 0, 1, 0, 0), CALC_CLR_PURP, },
106 { IDC_BUTTON_PI, 'P', MAKE_BITMASK5( 1, 0, 0, 0, 1, 0, 0), CALC_CLR_BLUE, },
107 { IDC_BUTTON_RX, 'R', MAKE_BITMASK5( 1, 0, 0, 0, 1, 0, 0), CALC_CLR_PURP, },
108 { IDC_BUTTON_SIN, 'S', MAKE_BITMASK5( 1, 0, 0, 0, 1, 0, 0), CALC_CLR_PURP, },
109 { IDC_BUTTON_COS, 'O', MAKE_BITMASK5( 1, 0, 0, 0, 1, 0, 0), CALC_CLR_PURP, },
110 { IDC_BUTTON_TAN, 'T', MAKE_BITMASK5( 1, 0, 0, 0, 1, 0, 0), CALC_CLR_PURP, },
111 { IDC_BUTTON_FE, 'V', MAKE_BITMASK5( 1, 0, 0, 0, 1, 0, 0), CALC_CLR_PURP, },
112 { IDC_BUTTON_EXP, 'X', MAKE_BITMASK5( 1, 0, 0, 0, 1, 0, 0), CALC_CLR_PURP, },
113 { IDC_BUTTON_XeY, 'Y', MAKE_BITMASK5( 1, 0, 0, 1, 1, 1, 1), CALC_CLR_PURP, },
114 { IDC_BUTTON_SQRT, '@', MAKE_BITMASK5( 1, 0, 0, 0, 1, 0, 0), CALC_CLR_BLUE, },
115 { IDC_BUTTON_Xe2, '@', MAKE_BITMASK5( 1, 0, 0, 1, 1, 1, 1), CALC_CLR_PURP, },
116 { IDC_BUTTON_Xe3, '#', MAKE_BITMASK5( 1, 0, 0, 1, 1, 1, 1), CALC_CLR_PURP, },
117 { IDC_BUTTON_NF, '!', MAKE_BITMASK5( 1, 0, 0, 1, 1, 1, 1), CALC_CLR_PURP, },
118 { IDC_BUTTON_LEFTPAR, '(', MAKE_BITMASK5( 1, 0, 0, 1, 1, 1, 1), CALC_CLR_PURP, },
119 { IDC_BUTTON_RIGHTPAR, ')', MAKE_BITMASK5( 1, 0, 0, 1, 1, 1, 1), CALC_CLR_PURP, },
120 { IDC_BUTTON_MOD, '%', MAKE_BITMASK5( 1, 0, 0, 1, 1, 1, 1), CALC_CLR_RED, },
121 { IDC_BUTTON_PERCENT, '%', MAKE_BITMASK5( 1, 0, 0, 0, 1, 0, 0), CALC_CLR_BLUE, },
122 /*----------------------------------------------------------------------*/
123 { IDC_BUTTON_DAT, VK_INSERT, MAKE_BITMASK5( 0, 1, 0, 1, 1, 1, 1), CALC_CLR_BLUE, },
124 { IDC_BUTTON_EQU, VK_RETURN, MAKE_BITMASK5( 0, 0, 0, 1, 1, 1, 1), CALC_CLR_RED, },
125 { IDC_BUTTON_CANC, VK_ESCAPE, MAKE_BITMASK5( 0, 0, 0, 1, 1, 1, 1), CALC_CLR_RED, },
126 { IDC_BUTTON_CE, VK_DELETE, MAKE_BITMASK5( 0, 0, 0, 1, 1, 1, 1), CALC_CLR_RED, },
127 { IDC_BUTTON_BACK, VK_BACK, MAKE_BITMASK5( 0, 0, 0, 1, 1, 1, 1), CALC_CLR_RED, },
128 { IDC_RADIO_HEX, VK_F5, MAKE_BITMASK5( 0, 0, 0, 1, 1, 1, 1), -1, },
129 { IDC_RADIO_DEC, VK_F6, MAKE_BITMASK5( 0, 0, 0, 1, 1, 1, 1), -1, },
130 { IDC_RADIO_OCT, VK_F7, MAKE_BITMASK5( 0, 0, 0, 1, 1, 1, 1), -1, },
131 { IDC_RADIO_BIN, VK_F8, MAKE_BITMASK5( 0, 0, 0, 1, 1, 1, 1), -1, },
132 { IDC_BUTTON_SIGN, VK_F9, MAKE_BITMASK5( 0, 0, 0, 1, 1, 1, 1), CALC_CLR_BLUE, },
133 };
134
135 static const key2code_t key2code_base16[] = {
136 { VK_F2, IDC_RADIO_DWORD, },
137 { VK_F3, IDC_RADIO_WORD, },
138 { VK_F4, IDC_RADIO_BYTE, },
139 { VK_F12, IDC_RADIO_QWORD, },
140 };
141
142 static const key2code_t key2code_base10[] = {
143 { VK_F2, IDC_RADIO_DEG, },
144 { VK_F3, IDC_RADIO_RAD, },
145 { VK_F4, IDC_RADIO_GRAD, },
146 };
147
148 static const WORD operator_codes[] = {
149 /* CONTROL-ID operator */
150 (WORD)IDC_STATIC, // RPN_OPERATOR_PARENT
151 IDC_BUTTON_PERCENT, // RPN_OPERATOR_PERCENT
152 IDC_BUTTON_EQU, // RPN_OPERATOR_EQUAL
153 IDC_BUTTON_OR, // RPN_OPERATOR_OR
154 IDC_BUTTON_XOR, // RPN_OPERATOR_XOR
155 IDC_BUTTON_AND, // RPN_OPERATOR_AND
156 IDC_BUTTON_LSH, // RPN_OPERATOR_LSH
157 IDC_BUTTON_RSH, // RPN_OPERATOR_RSH
158 IDC_BUTTON_ADD, // RPN_OPERATOR_ADD
159 IDC_BUTTON_SUB, // RPN_OPERATOR_SUB
160 IDC_BUTTON_MULT, // RPN_OPERATOR_MULT
161 IDC_BUTTON_DIV, // RPN_OPERATOR_DIV
162 IDC_BUTTON_MOD, // RPN_OPERATOR_MOD
163 };
164
165 typedef void (*rpn_callback1)(calc_number_t *);
166
167 typedef struct {
168 WORD idc;
169 BYTE range;
170 BYTE check_nan;
171 rpn_callback1 direct;
172 rpn_callback1 inverse;
173 rpn_callback1 hyperb;
174 rpn_callback1 inv_hyp;
175 } function_table_t;
176
177 static void run_pow(calc_number_t *number);
178 static void run_sqr(calc_number_t *number);
179 static void run_fe(calc_number_t *number);
180 static void run_dat_sta(calc_number_t *number);
181 static void run_mp(calc_number_t *c);
182 static void run_mm(calc_number_t *c);
183 static void run_ms(calc_number_t *c);
184 static void run_mw(calc_number_t *c);
185 static void run_canc(calc_number_t *c);
186 static void run_rpar(calc_number_t *c);
187 static void run_lpar(calc_number_t *c);
188
189 static const function_table_t function_table[] = {
190 { IDC_BUTTON_SIN, MODIFIER_INV|MODIFIER_HYP, 1, rpn_sin, rpn_asin, rpn_sinh, rpn_asinh },
191 { IDC_BUTTON_COS, MODIFIER_INV|MODIFIER_HYP, 1, rpn_cos, rpn_acos, rpn_cosh, rpn_acosh },
192 { IDC_BUTTON_TAN, MODIFIER_INV|MODIFIER_HYP, 1, rpn_tan, rpn_atan, rpn_tanh, rpn_atanh },
193 { IDC_BUTTON_INT, MODIFIER_INV, 1, rpn_int, rpn_frac, NULL, NULL },
194 { IDC_BUTTON_RX, 0, 1, rpn_reci, NULL, NULL, NULL },
195 { IDC_BUTTON_NOT, 0, 1, rpn_not, NULL, NULL, NULL },
196 { IDC_BUTTON_PI, MODIFIER_INV, 0, rpn_pi, rpn_2pi, NULL, NULL },
197 { IDC_BUTTON_Xe2, MODIFIER_INV, 1, rpn_exp2, rpn_sqrt, NULL, NULL },
198 { IDC_BUTTON_Xe3, MODIFIER_INV, 1, rpn_exp3, rpn_cbrt, NULL, NULL },
199 { IDC_BUTTON_LN, MODIFIER_INV, 1, rpn_ln, rpn_exp, NULL, NULL },
200 { IDC_BUTTON_LOG, MODIFIER_INV, 1, rpn_log, rpn_exp10, NULL, NULL },
201 { IDC_BUTTON_NF, 0, 1, rpn_fact, NULL, NULL, NULL },
202 { IDC_BUTTON_AVE, 0, 0, rpn_ave, NULL, NULL, NULL },
203 { IDC_BUTTON_SUM, 0, 0, rpn_sum, NULL, NULL, NULL },
204 { IDC_BUTTON_S, MODIFIER_INV, 0, rpn_s_m1, rpn_s, NULL, NULL },
205 { IDC_BUTTON_XeY, MODIFIER_INV, 1, run_pow, run_sqr, NULL, NULL },
206 { IDC_BUTTON_SQRT, MODIFIER_INV, 1, rpn_sqrt, NULL, NULL, NULL },
207 { IDC_BUTTON_DMS, MODIFIER_INV, 1, rpn_dec2dms, rpn_dms2dec, NULL, NULL },
208 { IDC_BUTTON_FE, 0, 1, run_fe, NULL, NULL, NULL },
209 { IDC_BUTTON_DAT, 0, 1, run_dat_sta, NULL, NULL, NULL, },
210 { IDC_BUTTON_MP, MODIFIER_INV, 1, run_mp, run_mm, NULL, NULL, },
211 { IDC_BUTTON_MS, MODIFIER_INV, 1, run_ms, run_mw, NULL, NULL, },
212 { IDC_BUTTON_CANC, NO_CHAIN, 0, run_canc, NULL, NULL, NULL, },
213 { IDC_BUTTON_RIGHTPAR, NO_CHAIN, 1, run_rpar, NULL, NULL, NULL, },
214 { IDC_BUTTON_LEFTPAR, NO_CHAIN, 0, run_lpar, NULL, NULL, NULL, },
215 };
216
217 /*
218 */
219
220 calc_t calc;
221
222 static void load_config(void)
223 {
224 TCHAR buf[32];
225 DWORD tmp;
226 #if _WIN32_WINNT >= 0x0500
227 HKEY hKey;
228 #endif
229
230 /* Try to load last selected layout */
231 GetProfileString(TEXT("SciCalc"), TEXT("layout"), TEXT("0"), buf, SIZEOF(buf));
232 if (_stscanf(buf, TEXT("%ld"), &calc.layout) != 1)
233 calc.layout = CALC_LAYOUT_STANDARD;
234
235 /* Try to load last selected formatting option */
236 GetProfileString(TEXT("SciCalc"), TEXT("UseSep"), TEXT("0"), buf, SIZEOF(buf));
237 if (_stscanf(buf, TEXT("%ld"), &tmp) != 1)
238 calc.usesep = FALSE;
239 else
240 calc.usesep = (tmp == 1) ? TRUE : FALSE;
241
242 /* memory is empty at startup */
243 calc.is_memory = FALSE;
244
245 #if _WIN32_WINNT >= 0x0500
246 /* empty these values */
247 calc.sDecimal[0] = TEXT('\0');
248 calc.sThousand[0] = TEXT('\0');
249
250 /* try to open the registry */
251 if (RegOpenKeyEx(HKEY_CURRENT_USER,
252 TEXT("Control Panel\\International"),
253 0,
254 KEY_QUERY_VALUE,
255 &hKey) == ERROR_SUCCESS) {
256 /* get these values (ignore errors) */
257 tmp = sizeof(calc.sDecimal);
258 RegQueryValueEx(hKey, TEXT("sDecimal"), NULL, NULL, (LPBYTE)calc.sDecimal, &tmp);
259
260 tmp = sizeof(calc.sThousand);
261 RegQueryValueEx(hKey, TEXT("sThousand"), NULL, NULL, (LPBYTE)calc.sThousand, &tmp);
262
263 /* close the key */
264 RegCloseKey(hKey);
265 }
266 /* if something goes wrong, let's apply the defaults */
267 if (calc.sDecimal[0] == TEXT('\0'))
268 _tcscpy(calc.sDecimal, TEXT("."));
269
270 if (calc.sThousand[0] == TEXT('\0'))
271 _tcscpy(calc.sThousand, TEXT(","));
272
273 /* get the string lengths */
274 calc.sDecimal_len = _tcslen(calc.sDecimal);
275 calc.sThousand_len = _tcslen(calc.sThousand);
276 #else
277 /* acquire regional settings */
278 calc.sDecimal_len = GetProfileString(TEXT("intl"), TEXT("sDecimal"), TEXT("."), calc.sDecimal, SIZEOF(calc.sDecimal));
279 calc.sThousand_len = GetProfileString(TEXT("intl"), TEXT("sThousand"), TEXT(","), calc.sThousand, SIZEOF(calc.sThousand));
280 #endif
281 }
282
283 static void save_config(void)
284 {
285 TCHAR buf[32];
286
287 _stprintf(buf, TEXT("%lu"), calc.layout);
288 WriteProfileString(TEXT("SciCalc"), TEXT("layout"), buf);
289 WriteProfileString(TEXT("SciCalc"), TEXT("UseSep"), (calc.usesep==TRUE) ? TEXT("1") : TEXT("0"));
290 }
291
292 static LRESULT post_key_press(LPARAM lParam, WORD idc)
293 {
294 HWND hCtlWnd = GetDlgItem(calc.hWnd,idc);
295 TCHAR ClassName[64];
296
297 /* check if the key is enabled! */
298 if (!IsWindowEnabled(hCtlWnd))
299 return 1;
300
301 if (!GetClassName(hCtlWnd, ClassName, SIZEOF(ClassName)))
302 return 1;
303
304 if (!_tcscmp(ClassName, TEXT("Button"))) {
305 DWORD dwStyle = GetWindowLongPtr(hCtlWnd, GWL_STYLE) & 0xF;
306
307 /* Set states for press/release, but only for push buttons */
308 if (dwStyle == BS_PUSHBUTTON || dwStyle == BS_DEFPUSHBUTTON || dwStyle == BS_OWNERDRAW) {
309 if (!(lParam & KEY_WAS_DOWN)) {
310 PostMessage(hCtlWnd, BM_SETSTATE, 1, 0);
311 } else
312 if ((lParam & KEY_IS_UP)) {
313 PostMessage(hCtlWnd, BM_SETSTATE, 0, 0);
314 PostMessage(hCtlWnd, BM_CLICK, 0, 0);
315 }
316 return 1;
317 }
318 }
319 /* default action: simple click event at key release */
320 if ((lParam & KEY_IS_UP)) {
321 PostMessage(hCtlWnd, BM_CLICK, 0, 0);
322 }
323 return 1;
324 }
325
326 static int vk2ascii(unsigned int vk)
327 {
328 unsigned short int s;
329 int scan;
330 BYTE state[256];
331 HKL layout=GetKeyboardLayout(0);
332
333 if(!GetKeyboardState(state))
334 return 0;
335
336 scan=MapVirtualKeyEx(vk, 0, layout);
337 s = 0;
338 if (ToAsciiEx(vk, scan, state, &s, 0, layout)>0) {
339 /* convert to upper case */
340 if (s >= 'a' && s <= 'z')
341 s = s - 'a' + 'A';
342 /* add check to CTRL key */
343 if (vk >= 'A' && vk <= 'Z' &&
344 s >= CTRL_A && s <= CTRL_Z)
345 s |= CTRL_FLAG;
346 else
347 if (GetAsyncKeyState(VK_MENU) < 0)
348 s |= ALT_FLAG;
349 return s;
350 }
351 return 0;
352 }
353
354 static int process_vk_key(WPARAM wParam, LPARAM lParam)
355 {
356 const key2code_t *k;
357 unsigned int x;
358 unsigned short int ch;
359
360 ch = vk2ascii(LOWORD(wParam));
361 if ((lParam & KEY_IS_UP)) {
362 /* Test for "copy" to clipboard */
363 if (ch == (CTRL_C|CTRL_FLAG)) {
364 SendMessage(calc.hWnd, WM_COMMAND, IDM_EDIT_COPY, 0);
365 return 1;
366 }
367 /* Test for "paste" from clipboard */
368 if (ch == (CTRL_V|CTRL_FLAG)) {
369 SendMessage(calc.hWnd, WM_COMMAND, IDM_EDIT_PASTE, 0);
370 return 1;
371 }
372 /* Test of help menu */
373 if (LOWORD(wParam) == VK_F1) {
374 SendMessage(calc.hWnd, WM_COMMAND, IDM_HELP_HELP, 0);
375 return 1;
376 }
377 }
378
379 for (x=0; x<SIZEOF(key2code); x++) {
380 int key = key2code[x].key;
381 if (key2code[x].mask & BITMASK_IS_CTRL)
382 key |= CTRL_FLAG;
383 if ((key == ch && (key2code[x].mask & BITMASK_IS_ASCII)) ||
384 (key == LOWORD(wParam) && !(key2code[x].mask & BITMASK_IS_ASCII))
385 ) {
386 if (GetDlgItem(calc.hWnd, key2code[x].idc) == NULL)
387 continue;
388 return post_key_press(lParam, key2code[x].idc);
389 }
390 }
391 if (calc.layout == CALC_LAYOUT_SCIENTIFIC) {
392 if (calc.base == IDC_RADIO_DEC) {
393 k = key2code_base10;
394 x = SIZEOF(key2code_base10);
395 } else {
396 k = key2code_base16;
397 x = SIZEOF(key2code_base16);
398 }
399 do {
400 if (k->key == LOWORD(wParam)) {
401 return post_key_press(lParam, k->idc);
402 }
403 k++;
404 } while (--x);
405 }
406 return 0;
407 }
408
409 #ifdef USE_KEYBOARD_HOOK
410 static LRESULT CALLBACK
411 KeyboardHookProc(int nCode, WPARAM wParam, LPARAM lParam)
412 {
413 if(nCode<0 || calc.is_menu_on)
414 return CallNextHookEx(calc.hKeyboardHook,nCode,wParam,lParam);
415
416 if(nCode==HC_ACTION)
417 if (process_vk_key(wParam, lParam))
418 return;
419
420 return CallNextHookEx(calc.hKeyboardHook,nCode,wParam,lParam);
421 }
422 #endif
423
424 static void update_lcd_display(HWND hwnd)
425 {
426 /*
427 * muliply size of calc.buffer by 2 because it may
428 * happen that separator is used between each digit.
429 * Also added little additional space for dot and '\0'.
430 */
431 TCHAR *tmp = (TCHAR *)alloca(sizeof(calc.buffer)*2+2*sizeof(TCHAR));
432
433 if (calc.buffer[0] == TEXT('\0'))
434 _tcscpy(tmp, TEXT("0"));
435 else
436 _tcscpy(tmp, calc.buffer);
437 /* add final '.' in decimal mode (if it's missing) */
438 if (calc.base == IDC_RADIO_DEC) {
439 if (_tcschr(tmp, TEXT('.')) == NULL)
440 _tcscat(tmp, TEXT("."));
441 }
442 /* if separator mode is on, let's add an additional space */
443 if (calc.usesep && !calc.sci_in && !calc.sci_out && !calc.is_nan) {
444 /* go to the integer part of the string */
445 TCHAR *p = _tcschr(tmp, TEXT('.'));
446 TCHAR *e = _tcschr(tmp, TEXT('\0'));
447 int n=0, t;
448
449 if (p == NULL) p = e;
450 switch (calc.base) {
451 case IDC_RADIO_HEX:
452 case IDC_RADIO_BIN:
453 t = 4;
454 break;
455 default:
456 /* fall here for:
457 IDC_RADIO_DEC:
458 IDC_RADIO_OCT: */
459 t = 3;
460 break;
461 }
462 while (--p > tmp) {
463 if (++n == t && *(p-1) != TEXT('-')) {
464 memmove(p+1, p, (e-p+1)*sizeof(TCHAR));
465 e++;
466 *p = TEXT(' ');
467 n = 0;
468 }
469 }
470 /* if decimal mode, apply regional settings */
471 if (calc.base == IDC_RADIO_DEC) {
472 TCHAR *p = tmp;
473 TCHAR *e = _tcschr(tmp, TEXT('.'));
474
475 /* searching for thousands default separator */
476 while (p < e) {
477 if (*p == TEXT(' ')) {
478 memmove(p+calc.sThousand_len, p+1, _tcslen(p)*sizeof(TCHAR));
479 memcpy(p, calc.sThousand, calc.sThousand_len*sizeof(TCHAR));
480 p += calc.sThousand_len;
481 } else
482 p++;
483 }
484 /* update decimal point too. */
485 memmove(p+calc.sDecimal_len, p+1, _tcslen(p)*sizeof(TCHAR));
486 memcpy(p, calc.sDecimal, calc.sDecimal_len*sizeof(TCHAR));
487 }
488 } else {
489 TCHAR *p = _tcschr(tmp, TEXT('.'));
490
491 /* update decimal point when usesep is false */
492 if (p != NULL) {
493 memmove(p+calc.sDecimal_len, p+1, _tcslen(p)*sizeof(TCHAR));
494 memcpy(p, calc.sDecimal, calc.sDecimal_len*sizeof(TCHAR));
495 }
496 }
497 SendDlgItemMessage(hwnd, IDC_TEXT_OUTPUT, WM_SETTEXT, (WPARAM)0, (LPARAM)tmp);
498 }
499
500 static void update_parent_display(HWND hWnd)
501 {
502 TCHAR str[8];
503 int n = eval_parent_count();
504
505 if (!n)
506 str[0] = TEXT('\0');
507 else
508 _stprintf(str,TEXT("(=%d"), n);
509 SendDlgItemMessage(hWnd, IDC_TEXT_PARENT, WM_SETTEXT, 0, (LPARAM)str);
510 }
511
512 static void build_operand(HWND hwnd, DWORD idc)
513 {
514 unsigned int i = 0, n;
515
516 if (idc == IDC_BUTTON_DOT) {
517 /* if dot is the first char, it's added automatically */
518 if (calc.buffer == calc.ptr) {
519 *calc.ptr++ = TEXT('0');
520 *calc.ptr++ = TEXT('.');
521 *calc.ptr = TEXT('\0');
522 update_lcd_display(hwnd);
523 return;
524 }
525 /* if pressed dot and it's already in the string, then return */
526 if (_tcschr(calc.buffer, TEXT('.')) != NULL)
527 return;
528 }
529 if (idc != IDC_STATIC) {
530 while (idc != key2code[i].idc) i++;
531 }
532 n = calc.ptr - calc.buffer;
533 if (idc == IDC_BUTTON_0 && n == 0) {
534 /* no need to put the dot because it's handled by update_lcd_display() */
535 calc.buffer[0] = TEXT('0');
536 calc.buffer[1] = TEXT('\0');
537 update_lcd_display(hwnd);
538 return;
539 }
540 switch (calc.base) {
541 case IDC_RADIO_HEX:
542 if (n >= 16)
543 return;
544 break;
545 case IDC_RADIO_DEC:
546 if (n >= SIZEOF(calc.buffer)-1)
547 return;
548 if (calc.sci_in) {
549 if (idc != IDC_STATIC)
550 calc.esp = (calc.esp * 10 + (key2code[i].key-'0')) % LOCAL_EXP_SIZE;
551 if (calc.ptr == calc.buffer)
552 _stprintf(calc.ptr, TEXT("0.e%+d"), calc.esp);
553 else {
554 /* adds the dot at the end if the number has no decimal part */
555 if (!_tcschr(calc.buffer, TEXT('.')))
556 *calc.ptr++ = TEXT('.');
557 _stprintf(calc.ptr, TEXT("e%+d"), calc.esp);
558 }
559 update_lcd_display(hwnd);
560 return;
561 }
562 break;
563 case IDC_RADIO_OCT:
564 if (n >= 22)
565 return;
566 break;
567 case IDC_RADIO_BIN:
568 if (n >= 64)
569 return;
570 break;
571 }
572 calc.ptr += _stprintf(calc.ptr, TEXT("%C"), key2code[i].key);
573 update_lcd_display(hwnd);
574 }
575
576 static void prepare_rpn_result(calc_number_t *rpn, TCHAR *buffer, int size, int base)
577 {
578 if (calc.is_nan) {
579 rpn_zero(&calc.code);
580 LoadString(calc.hInstance, IDS_MATH_ERROR, buffer, size);
581 return;
582 }
583 prepare_rpn_result_2(rpn, buffer, size, base);
584 }
585
586 static void display_rpn_result(HWND hwnd, calc_number_t *rpn)
587 {
588 calc.sci_in = FALSE;
589 prepare_rpn_result(rpn, calc.buffer, SIZEOF(calc.buffer), calc.base);
590 calc.ptr = calc.buffer + _tcslen(calc.buffer);
591 update_lcd_display(hwnd);
592 calc.ptr = calc.buffer;
593 update_parent_display(hwnd);
594 }
595
596 static int get_modifiers(HWND hwnd)
597 {
598 int modifiers = 0;
599
600 if (SendDlgItemMessage(hwnd, IDC_CHECK_INV, BM_GETCHECK, 0, 0))
601 modifiers |= MODIFIER_INV;
602 if (SendDlgItemMessage(hwnd, IDC_CHECK_HYP, BM_GETCHECK, 0, 0))
603 modifiers |= MODIFIER_HYP;
604
605 return modifiers;
606 }
607
608 static void convert_text2number(calc_number_t *a)
609 {
610 /* if the screen output buffer is empty, then */
611 /* the operand is taken from the last input */
612 if (calc.buffer == calc.ptr) {
613 /* if pushed valued is ZERO then we should grab it */
614 if (!_tcscmp(calc.buffer, TEXT("0.")) ||
615 !_tcscmp(calc.buffer, TEXT("0")))
616 /* this zero is good for both integer and decimal */
617 rpn_zero(a);
618 else
619 rpn_copy(a, &calc.code);
620 return;
621 }
622 /* ZERO is the default value for all numeric bases */
623 rpn_zero(a);
624 convert_text2number_2(a);
625 }
626
627 static const struct _update_check_menus {
628 DWORD *sel;
629 WORD idm;
630 WORD idc;
631 } upd[] = {
632 { &calc.layout, IDM_VIEW_STANDARD, CALC_LAYOUT_STANDARD },
633 { &calc.layout, IDM_VIEW_SCIENTIFIC, CALC_LAYOUT_SCIENTIFIC },
634 { &calc.layout, IDM_VIEW_CONVERSION, CALC_LAYOUT_CONVERSION },
635 /*-----------------------------------------*/
636 { &calc.base, IDM_VIEW_HEX, IDC_RADIO_HEX, },
637 { &calc.base, IDM_VIEW_DEC, IDC_RADIO_DEC, },
638 { &calc.base, IDM_VIEW_OCT, IDC_RADIO_OCT, },
639 { &calc.base, IDM_VIEW_BIN, IDC_RADIO_BIN, },
640 /*-----------------------------------------*/
641 { &calc.degr, IDM_VIEW_DEG, IDC_RADIO_DEG, },
642 { &calc.degr, IDM_VIEW_RAD, IDC_RADIO_RAD, },
643 { &calc.degr, IDM_VIEW_GRAD, IDC_RADIO_GRAD, },
644 /*-----------------------------------------*/
645 { &calc.size, IDM_VIEW_QWORD, IDC_RADIO_QWORD, },
646 { &calc.size, IDM_VIEW_DWORD, IDC_RADIO_DWORD, },
647 { &calc.size, IDM_VIEW_WORD, IDC_RADIO_WORD, },
648 { &calc.size, IDM_VIEW_BYTE, IDC_RADIO_BYTE, },
649 };
650
651 static void update_menu(HWND hwnd)
652 {
653 HMENU hMenu = GetSubMenu(GetMenu(hwnd), 1);
654 unsigned int x;
655
656 for (x=0; x<SIZEOF(upd); x++) {
657 if (*(upd[x].sel) != upd[x].idc) {
658 CheckMenuItem(hMenu, upd[x].idm, MF_BYCOMMAND|MF_UNCHECKED);
659 SendMessage((HWND)GetDlgItem(hwnd,upd[x].idc),BM_SETCHECK,FALSE,0L);
660 } else {
661 CheckMenuItem(hMenu, upd[x].idm, MF_BYCOMMAND|MF_CHECKED);
662 SendMessage((HWND)GetDlgItem(hwnd,upd[x].idc),BM_SETCHECK,TRUE,0L);
663 }
664 }
665 CheckMenuItem(hMenu, IDM_VIEW_GROUP, MF_BYCOMMAND|(calc.usesep ? MF_CHECKED : MF_UNCHECKED));
666 }
667
668 typedef struct {
669 WORD idc;
670 WORD mask;
671 } radio_config_t;
672
673 static const radio_config_t radio_setup[] = {
674 /* CONTROL-ID hex dec oct bin */
675 { IDC_RADIO_QWORD, MAKE_BITMASK4( 1, 0, 1, 1) },
676 { IDC_RADIO_DWORD, MAKE_BITMASK4( 1, 0, 1, 1) },
677 { IDC_RADIO_WORD, MAKE_BITMASK4( 1, 0, 1, 1) },
678 { IDC_RADIO_BYTE, MAKE_BITMASK4( 1, 0, 1, 1) },
679 { IDC_RADIO_DEG, MAKE_BITMASK4( 0, 1, 0, 0) },
680 { IDC_RADIO_RAD, MAKE_BITMASK4( 0, 1, 0, 0) },
681 { IDC_RADIO_GRAD, MAKE_BITMASK4( 0, 1, 0, 0) },
682 };
683
684 static void enable_allowed_controls(HWND hwnd, DWORD base)
685 {
686 BYTE mask;
687 int n;
688
689 switch (base) {
690 case IDC_RADIO_DEC:
691 mask = BITMASK_DEC_MASK;
692 break;
693 case IDC_RADIO_HEX:
694 mask = BITMASK_HEX_MASK;
695 break;
696 case IDC_RADIO_OCT:
697 mask = BITMASK_OCT_MASK;
698 break;
699 case IDC_RADIO_BIN:
700 mask = BITMASK_BIN_MASK;
701 break;
702 default:
703 return;
704 }
705 for (n=0; n<SIZEOF(key2code); n++) {
706 if (key2code[n].mask != 0) {
707 HWND hCtlWnd = GetDlgItem(hwnd, key2code[n].idc);
708 BOOL current;
709
710 if ((key2code[n].mask & BITMASK_IS_STATS))
711 current = IsWindow(calc.hStatWnd) ? TRUE : FALSE;
712 else
713 current = (key2code[n].mask & mask) ? TRUE : FALSE;
714 if (IsWindowEnabled(hCtlWnd) != current)
715 EnableWindow(hCtlWnd, current);
716 }
717 }
718 }
719
720 static void update_radio(HWND hwnd, unsigned int base)
721 {
722 HMENU hMenu;
723 LPCTSTR lpMenuId;
724 WORD mask;
725 int n;
726
727 switch (base) {
728 case IDC_RADIO_DEC:
729 lpMenuId = MAKEINTRESOURCE(IDR_MENU_SCIENTIFIC_1);
730 mask = BITMASK_DEC_MASK;
731 break;
732 case IDC_RADIO_HEX:
733 lpMenuId = MAKEINTRESOURCE(IDR_MENU_SCIENTIFIC_2);
734 mask = BITMASK_HEX_MASK;
735 break;
736 case IDC_RADIO_OCT:
737 lpMenuId = MAKEINTRESOURCE(IDR_MENU_SCIENTIFIC_2);
738 mask = BITMASK_OCT_MASK;
739 break;
740 case IDC_RADIO_BIN:
741 lpMenuId = MAKEINTRESOURCE(IDR_MENU_SCIENTIFIC_2);
742 mask = BITMASK_BIN_MASK;
743 break;
744 default:
745 return;
746 }
747
748 if (calc.base != base) {
749 convert_text2number(&calc.code);
750 convert_real_integer(base);
751 calc.base = base;
752 display_rpn_result(hwnd, &calc.code);
753
754 hMenu = GetMenu(hwnd);
755 DestroyMenu(hMenu);
756 hMenu = LoadMenu(calc.hInstance, lpMenuId);
757 SetMenu(hwnd, hMenu);
758 update_menu(hwnd);
759
760 for (n=0; n<SIZEOF(radio_setup); n++)
761 ShowWindow(GetDlgItem(hwnd, radio_setup[n].idc), (radio_setup[n].mask & mask) ? SW_SHOW : SW_HIDE);
762
763 enable_allowed_controls(hwnd, base);
764 }
765
766 SendDlgItemMessage(hwnd, calc.base, BM_SETCHECK, BST_CHECKED, 0);
767 if (base == IDC_RADIO_DEC)
768 SendDlgItemMessage(hwnd, calc.degr, BM_SETCHECK, BST_CHECKED, 0);
769 else
770 SendDlgItemMessage(hwnd, calc.size, BM_SETCHECK, BST_CHECKED, 0);
771 }
772
773 static void update_memory_flag(HWND hWnd, BOOL mem_flag)
774 {
775 calc.is_memory = mem_flag;
776 SendDlgItemMessage(hWnd, IDC_TEXT_MEMORY, WM_SETTEXT, 0, (LPARAM)(mem_flag ? TEXT("M") : TEXT("")));
777 }
778
779 static void update_n_stats_items(HWND hWnd, TCHAR *buffer)
780 {
781 unsigned int n = SendDlgItemMessage(hWnd, IDC_LIST_STAT, LB_GETCOUNT, 0, 0);
782
783 _stprintf(buffer, TEXT("n=%d"), n);
784 SendDlgItemMessage(hWnd, IDC_TEXT_NITEMS, WM_SETTEXT, 0, (LPARAM)buffer);
785 }
786
787 static void clean_stat_list(void)
788 {
789 statistic_t *p = calc.stat;
790
791 while (p != NULL) {
792 statistic_t *s = p;
793 p = (statistic_t *)(p->next);
794 rpn_free(&s->num);
795 free(s);
796 }
797 calc.stat = p;
798 }
799
800 static void delete_stat_item(int n)
801 {
802 statistic_t *p = calc.stat;
803 statistic_t *s;
804
805 if (n == 0) {
806 calc.stat = (statistic_t *)p->next;
807 rpn_free(&p->num);
808 free(p);
809 } else {
810 s = (statistic_t *)p->next;
811 while (--n) {
812 p = s;
813 s = (statistic_t *)p->next;
814 }
815 p->next = s->next;
816 rpn_free(&s->num);
817 free(s);
818 }
819 }
820
821 static char *ReadConversion(const char *formula)
822 {
823 int len = strlen(formula);
824 char *str = (char *)malloc(len+3);
825
826 if (str == NULL)
827 return NULL;
828
829 str[0] = '(';
830 memcpy(str+1, formula, len);
831 str[len+1] = ')';
832 str[len+2] = '\0';
833
834 _tcscpy(calc.source, (*calc.buffer == _T('\0')) ? _T("0") : calc.buffer);
835
836 /* clear display content before proceeding */
837 calc.ptr = calc.buffer;
838 calc.buffer[0] = TEXT('\0');
839
840 return str;
841 }
842
843 static INT_PTR CALLBACK DlgStatProc(HWND hWnd, UINT msg, WPARAM wp, LPARAM lp)
844 {
845 TCHAR buffer[SIZEOF(calc.buffer)];
846 DWORD n;
847
848 switch (msg) {
849 case WM_INITDIALOG:
850 return TRUE;
851 case WM_COMMAND:
852 switch (LOWORD(wp)) {
853 case IDC_LIST_STAT:
854 if (HIWORD(wp) == CBN_DBLCLK)
855 SendMessage(hWnd, WM_COMMAND, (WPARAM)IDC_BUTTON_LOAD, 0);
856 return TRUE;
857 case IDC_BUTTON_RET:
858 SetFocus(GetDlgItem(GetParent(hWnd), IDC_BUTTON_FOCUS));
859 return TRUE;
860 case IDC_BUTTON_LOAD:
861 n = SendDlgItemMessage(hWnd, IDC_LIST_STAT, LB_GETCURSEL, 0, 0);
862 if (n == (DWORD)-1)
863 return TRUE;
864 PostMessage(GetParent(hWnd), WM_LOAD_STAT, (WPARAM)n, 0);
865 return TRUE;
866 case IDC_BUTTON_CD:
867 n = SendDlgItemMessage(hWnd, IDC_LIST_STAT, LB_GETCURSEL, 0, 0);
868 if (n == (DWORD)-1)
869 return TRUE;
870 SendDlgItemMessage(hWnd, IDC_LIST_STAT, LB_DELETESTRING, (WPARAM)n, 0);
871 update_n_stats_items(hWnd, buffer);
872 delete_stat_item(n);
873 return TRUE;
874 case IDC_BUTTON_CAD:
875 SendDlgItemMessage(hWnd, IDC_LIST_STAT, LB_RESETCONTENT, 0, 0);
876 clean_stat_list();
877 update_n_stats_items(hWnd, buffer);
878 return TRUE;
879 }
880 break;
881 case WM_CLOSE:
882 clean_stat_list();
883 DestroyWindow(hWnd);
884 return TRUE;
885 case WM_DESTROY:
886 PostMessage(GetParent(hWnd), WM_CLOSE_STATS, 0, 0);
887 return TRUE;
888 case WM_INSERT_STAT:
889 prepare_rpn_result(&(((statistic_t *)lp)->num),
890 buffer, SIZEOF(buffer),
891 ((statistic_t *)lp)->base);
892 SendDlgItemMessage(hWnd, IDC_LIST_STAT, LB_ADDSTRING, 0, (LPARAM)buffer);
893 update_n_stats_items(hWnd, buffer);
894 return TRUE;
895 }
896 return FALSE;
897 }
898
899 static WPARAM idm_2_idc(int idm)
900 {
901 int x;
902
903 for (x=0; x<SIZEOF(upd); x++) {
904 if (upd[x].idm == idm)
905 break;
906 }
907 return (WPARAM)(upd[x].idc);
908 }
909
910 static void CopyMemToClipboard(void *ptr)
911 {
912 if(OpenClipboard(NULL)) {
913 HGLOBAL clipbuffer;
914 TCHAR *buffer;
915
916 EmptyClipboard();
917 clipbuffer = GlobalAlloc(GMEM_DDESHARE, (_tcslen(ptr)+1)*sizeof(TCHAR));
918 buffer = (TCHAR *)GlobalLock(clipbuffer);
919 _tcscpy(buffer, ptr);
920 GlobalUnlock(clipbuffer);
921 #ifdef UNICODE
922 SetClipboardData(CF_UNICODETEXT,clipbuffer);
923 #else
924 SetClipboardData(CF_TEXT,clipbuffer);
925 #endif
926 CloseClipboard();
927 }
928 }
929
930 static void handle_copy_command(HWND hWnd)
931 {
932 TCHAR display[sizeof(calc.buffer)];
933
934 SendDlgItemMessage(hWnd, IDC_TEXT_OUTPUT, WM_GETTEXT, (WPARAM)SIZEOF(display), (LPARAM)display);
935 if (calc.base == IDC_RADIO_DEC && _tcschr(calc.buffer, _T('.')) == NULL)
936 display[_tcslen(display)-calc.sDecimal_len] = TEXT('\0');
937 CopyMemToClipboard(display);
938 }
939
940 static char *ReadClipboard(void)
941 {
942 char *buffer = NULL;
943
944 if (OpenClipboard(NULL)) {
945 HANDLE hData = GetClipboardData(CF_TEXT);
946 char *fromClipboard;
947
948 if (hData != NULL) {
949 fromClipboard = (char *)GlobalLock(hData);
950 if (strlen(fromClipboard))
951 buffer = _strupr(_strdup(fromClipboard));
952 GlobalUnlock( hData );
953 }
954 CloseClipboard();
955 }
956 return buffer;
957 }
958
959 static char *handle_sequence_input(HWND hwnd, sequence_t *seq)
960 {
961 char *ptr = seq->ptr;
962 int ch, x;
963
964 ch = *ptr++;
965 if (ch == '\\')
966 PostMessage(hwnd, WM_COMMAND, (WPARAM)IDC_BUTTON_DAT, 0);
967 else
968 if (ch == ':') {
969 ch = *ptr;
970 if (ch != '\0')
971 ptr++;
972 switch (ch) {
973 case 'C': PostMessage(hwnd, WM_COMMAND, (WPARAM)IDC_BUTTON_MC, 0); break;
974 case 'E': PostMessage(hwnd, WM_COMMAND, (WPARAM)IDC_BUTTON_EXP,0); break;
975 case 'M': PostMessage(hwnd, WM_COMMAND, (WPARAM)IDC_BUTTON_MS, 0); break;
976 case 'P': PostMessage(hwnd, WM_COMMAND, (WPARAM)IDC_BUTTON_MP, 0); break;
977 case 'Q': PostMessage(hwnd, WM_COMMAND, (WPARAM)IDC_BUTTON_CANC, 0); break;
978 case 'R': PostMessage(hwnd, WM_COMMAND, (WPARAM)IDC_BUTTON_MR, 0); break;
979 }
980 } else
981 if (ch == '$') {
982 calc.ptr =
983 _tcscpy(calc.buffer, calc.source) +
984 _tcslen(calc.source);
985 } else {
986 for (x=0; x<SIZEOF(key2code); x++) {
987 if (!(key2code[x].mask & BITMASK_IS_ASCII) ||
988 (key2code[x].mask & BITMASK_IS_CTRL))
989 continue;
990 if (key2code[x].key == ch) {
991 PostMessage(hwnd, WM_COMMAND, (WPARAM)key2code[x].idc, 0);
992 break;
993 }
994 }
995 }
996 seq->ptr = ptr;
997 if (*ptr != '\0')
998 PostMessage(hwnd, seq->wm_msg, 0, 0);
999 else {
1000 free(seq->data);
1001 seq->data = seq->ptr = ptr = NULL;
1002 }
1003 return ptr;
1004 }
1005
1006 static void run_dat_sta(calc_number_t *a)
1007 {
1008 statistic_t *s = (statistic_t *)malloc(sizeof(statistic_t));
1009 statistic_t *p = calc.stat;
1010
1011 rpn_alloc(&s->num);
1012 rpn_copy(&s->num, a);
1013 s->base = calc.base;
1014 s->next = NULL;
1015 if (p == NULL)
1016 calc.stat = s;
1017 else {
1018 while (p->next != NULL)
1019 p = (statistic_t *)(p->next);
1020 p->next = s;
1021 }
1022 PostMessage(calc.hStatWnd, WM_INSERT_STAT, 0, (LPARAM)s);
1023 }
1024
1025 static void run_mp(calc_number_t *c)
1026 {
1027 calc_node_t cn;
1028
1029 cn.number = *c;
1030 cn.base = calc.base;
1031 run_operator(&calc.memory, &calc.memory, &cn, RPN_OPERATOR_ADD);
1032 update_memory_flag(calc.hWnd, TRUE);
1033 }
1034
1035 static void run_mm(calc_number_t *c)
1036 {
1037 calc_node_t cn;
1038
1039 cn.number = *c;
1040 cn.base = calc.base;
1041 run_operator(&calc.memory, &calc.memory, &cn, RPN_OPERATOR_SUB);
1042 update_memory_flag(calc.hWnd, TRUE);
1043 }
1044
1045 static void run_ms(calc_number_t *c)
1046 {
1047 rpn_copy(&calc.memory.number, c);
1048 calc.memory.base = calc.base;
1049 update_memory_flag(calc.hWnd, rpn_is_zero(&calc.memory.number) ? FALSE : TRUE);
1050 }
1051
1052 static void run_mw(calc_number_t *c)
1053 {
1054 calc_number_t tmp;
1055
1056 rpn_copy(&tmp, &calc.memory.number);
1057 rpn_copy(&calc.memory.number, c);
1058 calc.memory.base = calc.base;
1059 if (calc.is_memory)
1060 rpn_copy(c, &tmp);
1061 update_memory_flag(calc.hWnd, rpn_is_zero(&calc.memory.number) ? FALSE : TRUE);
1062 }
1063
1064 static statistic_t *upload_stat_number(int n)
1065 {
1066 statistic_t *p = calc.stat;
1067
1068 if (p == NULL)
1069 return p;
1070
1071 while (n--) {
1072 p = (statistic_t *)(p->next);
1073 if (p == NULL)
1074 return p;
1075 }
1076
1077 #ifndef ENABLE_MULTI_PRECISION
1078 if (calc.base != p->base) {
1079 if (calc.base == IDC_RADIO_DEC)
1080 calc.code.f = (double)p->num.i;
1081 else {
1082 calc.code.i = (__int64)p->num.f;
1083 apply_int_mask(&calc.code);
1084 }
1085 } else
1086 #endif
1087 rpn_copy(&calc.code, &p->num);
1088
1089 calc.is_nan = FALSE;
1090
1091 return p;
1092 }
1093
1094 static void run_pow(calc_number_t *number)
1095 {
1096 exec_infix2postfix(number, RPN_OPERATOR_POW);
1097 }
1098
1099 static void run_sqr(calc_number_t *number)
1100 {
1101 exec_infix2postfix(number, RPN_OPERATOR_SQR);
1102 }
1103
1104 static void run_fe(calc_number_t *number)
1105 {
1106 calc.sci_out = ((calc.sci_out == TRUE) ? FALSE : TRUE);
1107 }
1108
1109 static void handle_context_menu(HWND hWnd, WPARAM wp, LPARAM lp)
1110 {
1111 TCHAR text[64];
1112 HMENU hMenu = CreatePopupMenu();
1113 BOOL idm;
1114
1115 LoadString(calc.hInstance, IDS_QUICKHELP, text, SIZEOF(text));
1116 AppendMenu(hMenu, MF_STRING | MF_ENABLED, IDM_HELP_HELP, text);
1117 idm = TrackPopupMenu( hMenu,
1118 TPM_LEFTALIGN | TPM_TOPALIGN | TPM_RETURNCMD | TPM_RIGHTBUTTON,
1119 LOWORD(lp),
1120 HIWORD(lp),
1121 0,
1122 hWnd,
1123 NULL);
1124 DestroyMenu(hMenu);
1125 #ifndef DISABLE_HTMLHELP_SUPPORT
1126 if (idm) {
1127 HH_POPUP popup;
1128
1129 memset(&popup, 0, sizeof(popup));
1130 popup.cbStruct = sizeof(HH_POPUP);
1131 popup.clrForeground = 1;
1132 popup.clrBackground = -1;
1133 popup.pt.x = LOWORD(lp);
1134 popup.pt.y = HIWORD(lp);
1135 popup.rcMargins.top = -1;
1136 popup.rcMargins.bottom = -1;
1137 popup.rcMargins.left = -1;
1138 popup.rcMargins.right = -1;
1139 popup.idString = GetWindowLongPtr((HWND)wp, GWL_ID);
1140 HtmlHelp((HWND)wp, HTMLHELP_PATH("/popups.txt"), HH_DISPLAY_TEXT_POPUP, (DWORD_PTR)&popup);
1141 }
1142 #else
1143 (void)idm;
1144 #endif
1145 }
1146
1147 static void run_canc(calc_number_t *c)
1148 {
1149 flush_postfix();
1150 rpn_zero(c);
1151 /* clear also scientific display modes */
1152 calc.sci_out = FALSE;
1153 calc.sci_in = FALSE;
1154 /* clear state of inv and hyp flags */
1155 SendDlgItemMessage(calc.hWnd, IDC_CHECK_INV, BM_SETCHECK, 0, 0);
1156 SendDlgItemMessage(calc.hWnd, IDC_CHECK_HYP, BM_SETCHECK, 0, 0);
1157 }
1158
1159 static void run_rpar(calc_number_t *c)
1160 {
1161 exec_closeparent(c);
1162 }
1163
1164 static void run_lpar(calc_number_t *c)
1165 {
1166 exec_infix2postfix(c, RPN_OPERATOR_PARENT);
1167 }
1168
1169 static LRESULT CALLBACK SubclassButtonProc(HWND hWnd, WPARAM wp, LPARAM lp)
1170 {
1171 LPDRAWITEMSTRUCT dis = (LPDRAWITEMSTRUCT)lp;
1172 DWORD dwStyle;
1173 UINT dwText;
1174 TCHAR text[64];
1175 int dx, dy, len;
1176 SIZE size;
1177 POINT pt;
1178
1179 if(dis->CtlType == ODT_BUTTON) {
1180 /*
1181 * little exception: 1/x has different color
1182 * in standard and scientific modes
1183 */
1184 if ((calc.layout == CALC_LAYOUT_STANDARD ||
1185 calc.layout == CALC_LAYOUT_CONVERSION) &&
1186 IDC_BUTTON_RX == dis->CtlID) {
1187 SetTextColor(dis->hDC, CALC_CLR_BLUE);
1188 } else
1189 for (dx=0; dx<SIZEOF(key2code); dx++) {
1190 if (key2code[dx].idc == dis->CtlID) {
1191 SetTextColor(dis->hDC, key2code[dx].col);
1192 break;
1193 }
1194 }
1195 /* button text to write */
1196 len = GetWindowText(dis->hwndItem, text, SIZEOF(text));
1197 /* default state: unpushed & enabled */
1198 dwStyle = 0;
1199 dwText = 0;
1200 if ((dis->itemState & ODS_DISABLED))
1201 dwText = DSS_DISABLED;
1202 if ((dis->itemState & ODS_SELECTED))
1203 dwStyle = DFCS_PUSHED;
1204
1205 DrawFrameControl(dis->hDC, &dis->rcItem, DFC_BUTTON, DFCS_BUTTONPUSH | dwStyle);
1206 GetTextExtentPoint32(dis->hDC, text, len, &size);
1207 dx = ((dis->rcItem.right-dis->rcItem.left) - size.cx) >> 1;
1208 dy = ((dis->rcItem.bottom-dis->rcItem.top) - size.cy) >> 1;
1209 if ((dwStyle & DFCS_PUSHED)) {
1210 dx++;
1211 dy++;
1212 }
1213 pt.x = dis->rcItem.left + dx;
1214 pt.y = dis->rcItem.top + dy;
1215 DrawState(dis->hDC, NULL, NULL, (LPARAM)text, 0, pt.x, pt.y, size.cx, size.cy, DST_TEXT | dwText);
1216 }
1217 return 1L;
1218 }
1219
1220 static INT_PTR CALLBACK DlgMainProc(HWND hWnd, UINT msg, WPARAM wp, LPARAM lp)
1221 {
1222 unsigned int x;
1223 RECT rc;
1224
1225 switch (msg) {
1226 case WM_DRAWITEM:
1227 return SubclassButtonProc(hWnd, wp, lp);
1228
1229 case WM_INITDIALOG:
1230 calc.hWnd=hWnd;
1231
1232 #ifdef USE_KEYBOARD_HOOK
1233 calc.hKeyboardHook=SetWindowsHookEx(
1234 WH_KEYBOARD,
1235 KeyboardHookProc,
1236 NULL,
1237 GetCurrentThreadId()
1238 );
1239 #endif
1240 rpn_zero(&calc.code);
1241 calc.sci_out = FALSE;
1242 calc.base = IDC_RADIO_DEC;
1243 calc.size = IDC_RADIO_QWORD;
1244 calc.degr = IDC_RADIO_DEG;
1245 calc.ptr = calc.buffer;
1246 calc.is_nan = FALSE;
1247 enable_allowed_controls(hWnd, IDC_RADIO_DEC);
1248 update_radio(hWnd, IDC_RADIO_DEC);
1249 update_menu(hWnd);
1250 display_rpn_result(hWnd, &calc.code);
1251 update_memory_flag(hWnd, calc.is_memory);
1252 /* remove keyboard focus */
1253 SetFocus(GetDlgItem(hWnd, IDC_BUTTON_FOCUS));
1254 /* set our calc icon */
1255 SendMessage(hWnd, WM_SETICON, ICON_BIG, (LPARAM)LoadIcon(calc.hInstance, MAKEINTRESOURCE(IDI_CALC_BIG)));
1256 SendMessage(hWnd, WM_SETICON, ICON_SMALL, (LPARAM)LoadIcon(calc.hInstance, MAKEINTRESOURCE(IDI_CALC_SMALL)));
1257 /* update text for decimal button */
1258 SendDlgItemMessage(hWnd, IDC_BUTTON_DOT, WM_SETTEXT, (WPARAM)0, (LPARAM)calc.sDecimal);
1259 /* Fill combo box for conversion */
1260 if (calc.layout == CALC_LAYOUT_CONVERSION)
1261 ConvInit(hWnd);
1262 /* Restore the window at the same position it was */
1263 if (calc.x_coord >= 0 && calc.y_coord >= 0) {
1264 int w, h, sw, sh;
1265
1266 GetWindowRect(hWnd, &rc);
1267 w = rc.right-rc.left;
1268 h = rc.bottom-rc.top;
1269 sw = GetSystemMetrics(SM_CXSCREEN);
1270 sh = GetSystemMetrics(SM_CYSCREEN);
1271 if (calc.x_coord+w > sw) calc.x_coord = sw - w;
1272 if (calc.y_coord+h > sh) calc.y_coord = sh - h;
1273 MoveWindow(hWnd, calc.x_coord, calc.y_coord, w, h, FALSE);
1274 }
1275 break;
1276 case WM_CTLCOLORSTATIC:
1277 if ((HWND)lp == GetDlgItem(hWnd, IDC_TEXT_OUTPUT))
1278 return (LRESULT)GetStockObject(WHITE_BRUSH);
1279 break;
1280 case WM_HANDLE_CLIPBOARD:
1281 handle_sequence_input(hWnd, &calc.Clipboard);
1282 return TRUE;
1283 case WM_COMMAND:
1284 /*
1285 * if selection of category is changed, we must
1286 * updatethe content of the "from/to" combo boxes.
1287 */
1288 if (wp == MAKEWPARAM(IDC_COMBO_CATEGORY, CBN_SELCHANGE)) {
1289 ConvAdjust(hWnd, SendDlgItemMessage(hWnd, IDC_COMBO_CATEGORY, CB_GETCURSEL, 0, 0));
1290 return TRUE;
1291 }
1292 if (HIWORD(wp) != BN_CLICKED && HIWORD(wp) != BN_DBLCLK)
1293 break;
1294 /* avoid flicker if the user selects from keyboard */
1295 if (GetFocus() != GetDlgItem(hWnd, IDC_BUTTON_FOCUS))
1296 SetFocus(GetDlgItem(hWnd, IDC_BUTTON_FOCUS));
1297 switch (LOWORD(wp)) {
1298 case IDM_HELP_ABOUT:
1299 DialogBox(calc.hInstance,MAKEINTRESOURCE(IDD_DIALOG_ABOUT), hWnd, AboutDlgProc);
1300 return TRUE;
1301 case IDM_HELP_HELP:
1302 #ifndef DISABLE_HTMLHELP_SUPPORT
1303 HtmlHelp(hWnd, HTMLHELP_PATH("/general_information.htm"), HH_DISPLAY_TOPIC, (DWORD_PTR)NULL);
1304 #endif
1305 return TRUE;
1306 case IDM_VIEW_STANDARD:
1307 calc.layout = CALC_LAYOUT_STANDARD;
1308 calc.action = IDM_VIEW_STANDARD;
1309 DestroyWindow(hWnd);
1310 save_config();
1311 return TRUE;
1312 case IDM_VIEW_SCIENTIFIC:
1313 calc.layout = CALC_LAYOUT_SCIENTIFIC;
1314 calc.action = IDM_VIEW_SCIENTIFIC;
1315 DestroyWindow(hWnd);
1316 save_config();
1317 return TRUE;
1318 case IDM_VIEW_CONVERSION:
1319 calc.layout = CALC_LAYOUT_CONVERSION;
1320 calc.action = IDM_VIEW_CONVERSION;
1321 DestroyWindow(hWnd);
1322 save_config();
1323 return TRUE;
1324 case IDM_VIEW_HEX:
1325 case IDM_VIEW_DEC:
1326 case IDM_VIEW_OCT:
1327 case IDM_VIEW_BIN:
1328 case IDM_VIEW_DEG:
1329 case IDM_VIEW_RAD:
1330 case IDM_VIEW_GRAD:
1331 case IDM_VIEW_QWORD:
1332 case IDM_VIEW_DWORD:
1333 case IDM_VIEW_WORD:
1334 case IDM_VIEW_BYTE:
1335 SendMessage(hWnd, WM_COMMAND, idm_2_idc(LOWORD(wp)), 0);
1336 return TRUE;
1337 case IDM_EDIT_COPY:
1338 handle_copy_command(hWnd);
1339 return TRUE;
1340 case IDM_EDIT_PASTE:
1341 if (calc.Clipboard.data != NULL)
1342 break;
1343 calc.Clipboard.data = ReadClipboard();
1344 if (calc.Clipboard.data != NULL) {
1345 /* clear the content of the display before pasting */
1346 PostMessage(hWnd, WM_COMMAND, IDC_BUTTON_CE, 0);
1347 calc.Clipboard.ptr = calc.Clipboard.data;
1348 calc.Clipboard.wm_msg = WM_HANDLE_CLIPBOARD;
1349 handle_sequence_input(hWnd, &calc.Clipboard);
1350 }
1351 return TRUE;
1352 case IDM_VIEW_GROUP:
1353 calc.usesep = (calc.usesep ? FALSE : TRUE);
1354 update_menu(hWnd);
1355 update_lcd_display(hWnd);
1356 save_config();
1357 return TRUE;
1358 case IDC_BUTTON_CONVERT:
1359 ConvExecute(hWnd);
1360 return TRUE;
1361 case IDC_BUTTON_CE: {
1362 calc_number_t tmp;
1363 rpn_zero(&tmp);
1364 display_rpn_result(hWnd, &tmp);
1365 }
1366 return TRUE;
1367 case IDC_RADIO_DEC:
1368 case IDC_RADIO_HEX:
1369 case IDC_RADIO_OCT:
1370 case IDC_RADIO_BIN:
1371 /* GNU WINDRES is bugged so I must always force radio update */
1372 /* (Fix for Win95/98) */
1373 #ifdef _MSC_VER
1374 if (calc.base == LOWORD(wp))
1375 break;
1376 #endif
1377 calc.is_nan = FALSE;
1378 update_radio(hWnd, LOWORD(wp));
1379 return TRUE;
1380 case IDC_RADIO_DEG:
1381 case IDC_RADIO_RAD:
1382 case IDC_RADIO_GRAD:
1383 /* GNU WINDRES is bugged so I must always force radio update */
1384 /* (Fix for Win95/98) */
1385 #ifdef _MSC_VER
1386 if (calc.degr == LOWORD(wp))
1387 break;
1388 #endif
1389 calc.degr = LOWORD(wp);
1390 calc.is_nan = FALSE;
1391 update_menu(hWnd);
1392 return TRUE;
1393 case IDC_RADIO_QWORD:
1394 case IDC_RADIO_DWORD:
1395 case IDC_RADIO_WORD:
1396 case IDC_RADIO_BYTE:
1397 /* GNU WINDRES is bugged so I must always force radio update */
1398 /* (Fix for Win95/98) */
1399 #ifdef _MSC_VER
1400 if (calc.size == LOWORD(wp))
1401 break;
1402 #endif
1403 calc.size = LOWORD(wp);
1404 calc.is_nan = FALSE;
1405 update_menu(hWnd);
1406 /*
1407 * update the content of the display
1408 */
1409 convert_text2number(&calc.code);
1410 apply_int_mask(&calc.code);
1411 display_rpn_result(hWnd, &calc.code);
1412 return TRUE;
1413 case IDC_BUTTON_1:
1414 case IDC_BUTTON_2:
1415 case IDC_BUTTON_3:
1416 case IDC_BUTTON_4:
1417 case IDC_BUTTON_5:
1418 case IDC_BUTTON_6:
1419 case IDC_BUTTON_7:
1420 case IDC_BUTTON_8:
1421 case IDC_BUTTON_9:
1422 case IDC_BUTTON_0:
1423 case IDC_BUTTON_DOT:
1424 case IDC_BUTTON_A:
1425 case IDC_BUTTON_B:
1426 case IDC_BUTTON_C:
1427 case IDC_BUTTON_D:
1428 case IDC_BUTTON_E:
1429 case IDC_BUTTON_F:
1430 calc.is_nan = FALSE;
1431 build_operand(hWnd, LOWORD(wp));
1432 return TRUE;
1433 case IDC_BUTTON_PERCENT:
1434 case IDC_BUTTON_ADD:
1435 case IDC_BUTTON_SUB:
1436 case IDC_BUTTON_MULT:
1437 case IDC_BUTTON_DIV:
1438 case IDC_BUTTON_MOD:
1439 case IDC_BUTTON_AND:
1440 case IDC_BUTTON_OR:
1441 case IDC_BUTTON_XOR:
1442 case IDC_BUTTON_LSH:
1443 case IDC_BUTTON_RSH:
1444 case IDC_BUTTON_EQU:
1445 if (calc.is_nan) break;
1446 /*
1447 * LSH button holds the RSH function too with INV modifier,
1448 * but since it's a two operand operator, it must be handled here.
1449 */
1450 if (LOWORD(wp) == IDC_BUTTON_LSH &&
1451 (get_modifiers(hWnd) & MODIFIER_INV)) {
1452 PostMessage(hWnd, WM_COMMAND, MAKEWPARAM(IDC_BUTTON_RSH, BN_CLICKED), 0);
1453 SendDlgItemMessage(hWnd, IDC_CHECK_INV, BM_SETCHECK, 0, 0);
1454 break;
1455 }
1456 for (x=0; x<SIZEOF(operator_codes); x++) {
1457 if (LOWORD(wp) == operator_codes[x]) {
1458 convert_text2number(&calc.code);
1459
1460 if (calc.ptr == calc.buffer) {
1461 if (calc.last_operator != x) {
1462 if (x != RPN_OPERATOR_EQUAL)
1463 exec_change_infix();
1464 } else
1465 if (x == RPN_OPERATOR_EQUAL) {
1466 exec_infix2postfix(&calc.code, calc.prev_operator);
1467 rpn_copy(&calc.code, &calc.prev);
1468 } else
1469 break;
1470 }
1471
1472 /* if no change then quit silently, */
1473 /* without display updates */
1474 if (!exec_infix2postfix(&calc.code, x))
1475 break;
1476
1477 display_rpn_result(hWnd, &calc.code);
1478 break;
1479 }
1480 }
1481 return TRUE;
1482 case IDC_BUTTON_BACK:
1483 if (calc.sci_in) {
1484 if (calc.esp == 0) {
1485 TCHAR *ptr;
1486
1487 calc.sci_in = FALSE;
1488 ptr = _tcschr(calc.ptr, TEXT('e'));
1489 if (ptr)
1490 *ptr = TEXT('\0');
1491 update_lcd_display(hWnd);
1492 } else {
1493 calc.esp /= 10;
1494 build_operand(hWnd, IDC_STATIC);
1495 }
1496 } else
1497 if (calc.ptr != calc.buffer) {
1498 *--calc.ptr = TEXT('\0');
1499 if (!_tcscmp(calc.buffer, TEXT("-")) ||
1500 !_tcscmp(calc.buffer, TEXT("-0")) ||
1501 !_tcscmp(calc.buffer, TEXT("0"))) {
1502 calc.ptr = calc.buffer;
1503 calc.buffer[0] = TEXT('\0');
1504 }
1505 update_lcd_display(hWnd);
1506 }
1507 return TRUE;
1508 case IDC_BUTTON_MC:
1509 rpn_zero(&calc.memory.number);
1510 update_memory_flag(hWnd, FALSE);
1511 return TRUE;
1512 case IDC_BUTTON_MR:
1513 if (calc.is_memory) {
1514 calc.is_nan = FALSE;
1515 rpn_copy(&calc.code, &calc.memory.number);
1516 display_rpn_result(hWnd, &calc.code);
1517 }
1518 return TRUE;
1519 case IDC_BUTTON_EXP:
1520 if (calc.sci_in || calc.is_nan || calc.buffer == calc.ptr)
1521 break;
1522 calc.sci_in = TRUE;
1523 calc.esp = 0;
1524 build_operand(hWnd, IDC_STATIC);
1525 return TRUE;
1526 case IDC_BUTTON_SIGN:
1527 if (calc.sci_in) {
1528 calc.esp = 0-calc.esp;
1529 build_operand(hWnd, IDC_STATIC);
1530 } else {
1531 if (calc.is_nan || calc.buffer[0] == TEXT('\0'))
1532 break;
1533
1534 if (calc.buffer[0] == TEXT('-')) {
1535 /* make the number positive */
1536 memmove(calc.buffer, calc.buffer+1, sizeof(calc.buffer)-1);
1537 if (calc.buffer != calc.ptr)
1538 calc.ptr--;
1539 } else {
1540 /* if first char is '0' and no dot, it isn't valid */
1541 if (calc.buffer[0] == TEXT('0') &&
1542 calc.buffer[1] != TEXT('.'))
1543 break;
1544 /* make the number negative */
1545 memmove(calc.buffer+1, calc.buffer, sizeof(calc.buffer)-1);
1546 calc.buffer[0] = TEXT('-');
1547 if (calc.buffer != calc.ptr)
1548 calc.ptr++;
1549 }
1550 /* If the input buffer is empty, then
1551 we change also the sign of calc.code
1552 because it could be the result of a
1553 previous calculation. */
1554 if (calc.buffer == calc.ptr)
1555 rpn_sign(&calc.code);
1556 update_lcd_display(hWnd);
1557 }
1558 return TRUE;
1559 case IDC_BUTTON_RIGHTPAR:
1560 case IDC_BUTTON_LEFTPAR:
1561 case IDC_BUTTON_CANC:
1562 case IDC_BUTTON_MP:
1563 case IDC_BUTTON_DAT:
1564 case IDC_BUTTON_FE:
1565 case IDC_BUTTON_DMS:
1566 case IDC_BUTTON_SQRT:
1567 case IDC_BUTTON_S:
1568 case IDC_BUTTON_SUM:
1569 case IDC_BUTTON_AVE:
1570 case IDC_BUTTON_NF:
1571 case IDC_BUTTON_LN:
1572 case IDC_BUTTON_LOG:
1573 case IDC_BUTTON_Xe2:
1574 case IDC_BUTTON_Xe3:
1575 case IDC_BUTTON_PI:
1576 case IDC_BUTTON_NOT:
1577 case IDC_BUTTON_RX:
1578 case IDC_BUTTON_INT:
1579 case IDC_BUTTON_SIN:
1580 case IDC_BUTTON_COS:
1581 case IDC_BUTTON_TAN:
1582 case IDC_BUTTON_XeY:
1583 case IDC_BUTTON_MS:
1584 for (x=0; x<SIZEOF(function_table); x++) {
1585 if (LOWORD(wp) == function_table[x].idc) {
1586 rpn_callback1 cb = NULL;
1587
1588 /* test if NaN state is important or not */
1589 if (calc.is_nan && function_table[x].check_nan) break;
1590 /* otherwise, it's cleared */
1591 calc.is_nan = FALSE;
1592
1593 switch (get_modifiers(hWnd) & function_table[x].range) {
1594 case 0:
1595 cb = function_table[x].direct;
1596 break;
1597 case MODIFIER_INV:
1598 cb = function_table[x].inverse;
1599 break;
1600 case MODIFIER_HYP:
1601 cb = function_table[x].hyperb;
1602 break;
1603 case MODIFIER_INV|MODIFIER_HYP:
1604 cb = function_table[x].inv_hyp;
1605 break;
1606 }
1607 if (cb != NULL) {
1608 convert_text2number(&calc.code);
1609 cb(&calc.code);
1610 display_rpn_result(hWnd, &calc.code);
1611 if (!(function_table[x].range & NO_CHAIN))
1612 exec_infix2postfix(&calc.code, RPN_OPERATOR_NONE);
1613 if (function_table[x].range & MODIFIER_INV)
1614 SendDlgItemMessage(hWnd, IDC_CHECK_INV, BM_SETCHECK, 0, 0);
1615 if (function_table[x].range & MODIFIER_HYP)
1616 SendDlgItemMessage(hWnd, IDC_CHECK_HYP, BM_SETCHECK, 0, 0);
1617 }
1618 }
1619 }
1620 return TRUE;
1621 case IDC_BUTTON_STA:
1622 if (IsWindow(calc.hStatWnd))
1623 break;
1624 calc.hStatWnd = CreateDialog(calc.hInstance,
1625 MAKEINTRESOURCE(IDD_DIALOG_STAT), hWnd, (DLGPROC)DlgStatProc);
1626 if (calc.hStatWnd != NULL) {
1627 enable_allowed_controls(hWnd, calc.base);
1628 SendMessage(calc.hStatWnd, WM_SETFOCUS, 0, 0);
1629 }
1630 return TRUE;
1631 }
1632 break;
1633 case WM_CLOSE_STATS:
1634 enable_allowed_controls(hWnd, calc.base);
1635 return TRUE;
1636 case WM_LOAD_STAT:
1637 if (upload_stat_number((int)LOWORD(wp)) != NULL)
1638 display_rpn_result(hWnd, &calc.code);
1639 return TRUE;
1640 case WM_START_CONV:
1641 x = LOWORD(lp);
1642 calc.Convert[x].data = ReadConversion(calc.Convert[x].data);
1643 if (calc.Convert[x].data != NULL) {
1644 calc.Convert[x].ptr = calc.Convert[x].data;
1645 PostMessage(hWnd, HIWORD(lp), 0, 0);
1646 }
1647 return TRUE;
1648 case WM_HANDLE_FROM:
1649 if (calc.is_nan)
1650 break;
1651 if (handle_sequence_input(hWnd, &calc.Convert[0]) == NULL)
1652 PostMessage(hWnd, WM_START_CONV, 0,
1653 MAKELPARAM(0x0001, WM_HANDLE_TO));
1654 return TRUE;
1655 case WM_HANDLE_TO:
1656 if (!calc.is_nan)
1657 handle_sequence_input(hWnd, &calc.Convert[1]);
1658 return TRUE;
1659 case WM_CLOSE:
1660 calc.action = IDC_STATIC;
1661 DestroyWindow(hWnd);
1662 return TRUE;
1663 case WM_DESTROY:
1664 /* Get (x,y) position of the calculator */
1665 GetWindowRect(hWnd, &rc);
1666 calc.x_coord = rc.left;
1667 calc.y_coord = rc.top;
1668 #ifdef USE_KEYBOARD_HOOK
1669 UnhookWindowsHookEx(calc.hKeyboardHook);
1670 #endif
1671 PostQuitMessage(0);
1672 return TRUE;
1673 case WM_CONTEXTMENU:
1674 if ((HWND)wp != hWnd)
1675 handle_context_menu(hWnd, wp, lp);
1676 return TRUE;
1677 case WM_ENTERMENULOOP:
1678 calc.is_menu_on = TRUE;
1679 /* Check if a valid format is available in the clipboard */
1680 EnableMenuItem(GetSubMenu(GetMenu(hWnd), 0),
1681 IDM_EDIT_PASTE,
1682 MF_BYCOMMAND|
1683 (IsClipboardFormatAvailable(CF_TEXT) ?
1684 MF_ENABLED : MF_GRAYED));
1685 break;
1686 case WM_EXITMENULOOP:
1687 calc.is_menu_on = FALSE;
1688 break;
1689 }
1690 return FALSE;
1691 }
1692
1693 #if defined(__GNUC__) && !defined(__REACTOS__)
1694 int WINAPI WinMain(HINSTANCE hInstance, HINSTANCE hPrevInstance, LPSTR lpCmdLine, int nShowCmd)
1695 #else
1696 int WINAPI _tWinMain(HINSTANCE hInstance, HINSTANCE hPrevInstance, LPTSTR lpCmdLine, int nShowCmd)
1697 #endif
1698 {
1699 MSG msg;
1700 DWORD dwLayout;
1701
1702 calc.hInstance = hInstance;
1703
1704 calc.x_coord = -1;
1705 calc.y_coord = -1;
1706
1707 load_config();
1708 start_rpn_engine();
1709
1710 do {
1711 /* ignore hwnd: dialogs are already visible! */
1712 if (calc.layout == CALC_LAYOUT_SCIENTIFIC)
1713 dwLayout = IDD_DIALOG_SCIENTIFIC;
1714 else
1715 if (calc.layout == CALC_LAYOUT_CONVERSION)
1716 dwLayout = IDD_DIALOG_CONVERSION;
1717 else
1718 dwLayout = IDD_DIALOG_STANDARD;
1719
1720 /* This call will always fail if UNICODE for Win9x */
1721 if (NULL == CreateDialog(hInstance, MAKEINTRESOURCE(dwLayout), NULL, (DLGPROC)DlgMainProc))
1722 break;
1723
1724 while (GetMessage(&msg, NULL, 0, 0)) {
1725 #ifndef USE_KEYBOARD_HOOK
1726 if ((msg.message == WM_KEYUP ||
1727 msg.message == WM_KEYDOWN) &&
1728 !calc.is_menu_on)
1729 process_vk_key(msg.wParam, msg.lParam);
1730 #endif
1731 TranslateMessage(&msg);
1732 DispatchMessage(&msg);
1733 }
1734 } while (calc.action != IDC_STATIC);
1735
1736 stop_rpn_engine();
1737
1738 return 0;
1739 }