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