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