3 #define HTMLHELP_PATH(_pt) TEXT("%systemroot%\\Help\\calc.chm::") TEXT(_pt)
5 #define MAKE_BITMASK4(_show_b16, _show_b10, _show_b8, _show_b2) \
11 #define MAKE_BITMASK5(_transl, _is_stats, _is_ctrl, _show_b16, _show_b10, _show_b8, _show_b2) \
12 (((_show_b2) << 0) | \
14 ((_show_b10) << 2) | \
15 ((_show_b16) << 3) | \
17 ((_is_stats) << 6) | \
20 #define KEY_IS_UP 0x80000000
21 #define KEY_WAS_DOWN 0x40000000
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
31 #define CALC_CLR_RED 0x000000FF
32 #define CALC_CLR_BLUE 0x00FF0000
33 #define CALC_CLR_PURP 0x00FF00FF
36 CHAR key
; // Virtual key identifier
37 WORD idc
; // IDC for posting message
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
47 #define CTRL_FLAG 0x100
48 #define ALT_FLAG 0x200
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')
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
, },
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
, },
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
, },
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
165 typedef void (*rpn_callback1
)(calc_number_t
*);
171 rpn_callback1 direct
;
172 rpn_callback1 inverse
;
173 rpn_callback1 hyperb
;
174 rpn_callback1 inv_hyp
;
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
);
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
, },
222 static void load_config(void)
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
;
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)
237 calc
.usesep
= (tmp
== 1) ? TRUE
: FALSE
;
239 /* memory is empty at startup */
240 calc
.is_memory
= FALSE
;
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
));
247 static void save_config(void)
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"));
256 static LRESULT
post_key_press(LPARAM lParam
, WORD idc
)
258 HWND hCtlWnd
= GetDlgItem(calc
.hWnd
,idc
);
261 /* check if the key is enabled! */
262 if (!IsWindowEnabled(hCtlWnd
))
265 if (!GetClassName(hCtlWnd
, ClassName
, SIZEOF(ClassName
)))
268 if (!_tcscmp(ClassName
, TEXT("Button"))) {
269 DWORD dwStyle
= GetWindowLong(hCtlWnd
, GWL_STYLE
) & 0xF;
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);
276 if ((lParam
& KEY_IS_UP
)) {
277 PostMessage(hCtlWnd
, BM_SETSTATE
, 0, 0);
278 PostMessage(hCtlWnd
, BM_CLICK
, 0, 0);
283 /* default action: simple click event at key release */
284 if ((lParam
& KEY_IS_UP
)) {
285 PostMessage(hCtlWnd
, BM_CLICK
, 0, 0);
290 static int vk2ascii(unsigned int vk
)
292 unsigned short int s
;
295 HKL layout
=GetKeyboardLayout(0);
297 if(!GetKeyboardState(state
))
300 scan
=MapVirtualKeyEx(vk
, 0, layout
);
302 if (ToAsciiEx(vk
, scan
, state
, &s
, 0, layout
)>0) {
303 /* convert to upper case */
304 if (s
>= 'a' && s
<= 'z')
306 /* add check to CTRL key */
307 if (vk
>= 'A' && vk
<= 'Z' &&
308 s
>= CTRL_A
&& s
<= CTRL_Z
)
311 if (GetAsyncKeyState(VK_MENU
) < 0)
318 static int process_vk_key(WPARAM wParam
, LPARAM lParam
)
322 unsigned short int ch
;
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);
331 /* Test for "paste" from clipboard */
332 if (ch
== (CTRL_V
|CTRL_FLAG
)) {
333 SendMessage(calc
.hWnd
, WM_COMMAND
, IDM_EDIT_PASTE
, 0);
336 /* Test of help menu */
337 if (LOWORD(wParam
) == VK_F1
) {
338 SendMessage(calc
.hWnd
, WM_COMMAND
, IDM_HELP_HELP
, 0);
343 for (x
=0; x
<SIZEOF(key2code
); x
++) {
344 int key
= key2code
[x
].key
;
345 if (key2code
[x
].mask
& BITMASK_IS_CTRL
)
347 if ((key
== ch
&& (key2code
[x
].mask
& BITMASK_IS_ASCII
)) ||
348 (key
== LOWORD(wParam
) && !(key2code
[x
].mask
& BITMASK_IS_ASCII
))
350 if (GetDlgItem(calc
.hWnd
, key2code
[x
].idc
) == NULL
)
352 return post_key_press(lParam
, key2code
[x
].idc
);
355 if (calc
.layout
== CALC_LAYOUT_SCIENTIFIC
) {
356 if (calc
.base
== IDC_RADIO_DEC
) {
358 x
= SIZEOF(key2code_base10
);
361 x
= SIZEOF(key2code_base16
);
364 if (k
->key
== LOWORD(wParam
)) {
365 return post_key_press(lParam
, k
->idc
);
373 #ifdef USE_KEYBOARD_HOOK
374 static LRESULT CALLBACK
375 KeyboardHookProc(int nCode
, WPARAM wParam
, LPARAM lParam
)
377 if(nCode
<0 || calc
.is_menu_on
)
378 return CallNextHookEx(calc
.hKeyboardHook
,nCode
,wParam
,lParam
);
381 if (process_vk_key(wParam
, lParam
))
384 return CallNextHookEx(calc
.hKeyboardHook
,nCode
,wParam
,lParam
);
388 static void update_lcd_display(HWND hwnd
)
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'.
395 TCHAR
*tmp
= (TCHAR
*)alloca(sizeof(calc
.buffer
)*2+2*sizeof(TCHAR
));
397 if (calc
.buffer
[0] == TEXT('\0'))
398 _tcscpy(tmp
, TEXT("0"));
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("."));
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'));
413 if (p
== NULL
) p
= e
;
427 if (++n
== t
&& *(p
-1) != TEXT('-')) {
428 memmove(p
+1, p
, (e
-p
+1)*sizeof(TCHAR
));
434 /* if decimal mode, apply regional settings */
435 if (calc
.base
== IDC_RADIO_DEC
) {
437 TCHAR
*e
= _tcschr(tmp
, TEXT('.'));
439 /* searching for thousands default separator */
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
;
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
));
453 TCHAR
*p
= _tcschr(tmp
, TEXT('.'));
455 /* update decimal point when usesep is false */
457 memmove(p
+calc
.sDecimal_len
, p
+1, _tcslen(p
)*sizeof(TCHAR
));
458 memcpy(p
, calc
.sDecimal
, calc
.sDecimal_len
*sizeof(TCHAR
));
461 SendDlgItemMessage(hwnd
, IDC_TEXT_OUTPUT
, WM_SETTEXT
, (WPARAM
)0, (LPARAM
)tmp
);
464 static void update_parent_display(HWND hWnd
)
467 int n
= eval_parent_count();
472 _stprintf(str
,TEXT("(=%d"), n
);
473 SendDlgItemMessage(hWnd
, IDC_TEXT_PARENT
, WM_SETTEXT
, 0, (LPARAM
)str
);
476 static void build_operand(HWND hwnd
, DWORD idc
)
478 unsigned int i
= 0, n
;
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
);
489 /* if pressed dot and it's already in the string, then return */
490 if (_tcschr(calc
.buffer
, TEXT('.')) != NULL
)
493 if (idc
!= IDC_STATIC
) {
494 while (idc
!= key2code
[i
].idc
) i
++;
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
);
510 if (n
>= SIZEOF(calc
.buffer
)-1)
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
);
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
);
523 update_lcd_display(hwnd
);
536 calc
.ptr
+= _stprintf(calc
.ptr
, TEXT("%C"), key2code
[i
].key
);
537 update_lcd_display(hwnd
);
540 static void prepare_rpn_result(calc_number_t
*rpn
, TCHAR
*buffer
, int size
, int base
)
543 rpn_zero(&calc
.code
);
544 LoadString(calc
.hInstance
, IDS_MATH_ERROR
, buffer
, size
);
547 prepare_rpn_result_2(rpn
, buffer
, size
, base
);
550 static void display_rpn_result(HWND hwnd
, calc_number_t
*rpn
)
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
);
560 static int get_modifiers(HWND hwnd
)
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
;
572 static void convert_text2number(calc_number_t
*a
)
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 */
583 rpn_copy(a
, &calc
.code
);
586 /* ZERO is the default value for all numeric bases */
588 convert_text2number_2(a
);
591 static const struct _update_check_menus
{
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
, },
615 static void update_menu(HWND hwnd
)
617 HMENU hMenu
= GetSubMenu(GetMenu(hwnd
), 1);
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);
625 CheckMenuItem(hMenu
, upd
[x
].idm
, MF_BYCOMMAND
|MF_CHECKED
);
626 SendMessage((HWND
)GetDlgItem(hwnd
,upd
[x
].idc
),BM_SETCHECK
,TRUE
,0L);
629 CheckMenuItem(hMenu
, IDM_VIEW_GROUP
, MF_BYCOMMAND
|(calc
.usesep
? MF_CHECKED
: MF_UNCHECKED
));
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) },
648 static void enable_allowed_controls(HWND hwnd
, DWORD base
)
655 mask
= BITMASK_DEC_MASK
;
658 mask
= BITMASK_HEX_MASK
;
661 mask
= BITMASK_OCT_MASK
;
664 mask
= BITMASK_BIN_MASK
;
669 for (n
=0; n
<SIZEOF(key2code
); n
++) {
670 if (key2code
[n
].mask
!= 0) {
671 HWND hCtlWnd
= GetDlgItem(hwnd
, key2code
[n
].idc
);
674 if ((key2code
[n
].mask
& BITMASK_IS_STATS
))
675 current
= IsWindow(calc
.hStatWnd
) ? TRUE
: FALSE
;
677 current
= (key2code
[n
].mask
& mask
) ? TRUE
: FALSE
;
678 if (IsWindowEnabled(hCtlWnd
) != current
)
679 EnableWindow(hCtlWnd
, current
);
684 static void update_radio(HWND hwnd
, unsigned int base
)
693 lpMenuId
= MAKEINTRESOURCE(IDR_MENU_SCIENTIFIC_1
);
694 mask
= BITMASK_DEC_MASK
;
697 lpMenuId
= MAKEINTRESOURCE(IDR_MENU_SCIENTIFIC_2
);
698 mask
= BITMASK_HEX_MASK
;
701 lpMenuId
= MAKEINTRESOURCE(IDR_MENU_SCIENTIFIC_2
);
702 mask
= BITMASK_OCT_MASK
;
705 lpMenuId
= MAKEINTRESOURCE(IDR_MENU_SCIENTIFIC_2
);
706 mask
= BITMASK_BIN_MASK
;
712 if (calc
.base
!= base
) {
713 convert_text2number(&calc
.code
);
714 convert_real_integer(base
);
716 display_rpn_result(hwnd
, &calc
.code
);
718 hMenu
= GetMenu(hwnd
);
720 hMenu
= LoadMenu(calc
.hInstance
, lpMenuId
);
721 SetMenu(hwnd
, hMenu
);
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
);
727 enable_allowed_controls(hwnd
, base
);
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);
734 SendDlgItemMessage(hwnd
, calc
.size
, BM_SETCHECK
, BST_CHECKED
, 0);
737 static void update_memory_flag(HWND hWnd
, BOOL mem_flag
)
739 calc
.is_memory
= mem_flag
;
740 SendDlgItemMessage(hWnd
, IDC_TEXT_MEMORY
, WM_SETTEXT
, 0, (LPARAM
)(mem_flag
? TEXT("M") : TEXT("")));
743 static void update_n_stats_items(HWND hWnd
, TCHAR
*buffer
)
745 unsigned int n
= SendDlgItemMessage(hWnd
, IDC_LIST_STAT
, LB_GETCOUNT
, 0, 0);
747 _stprintf(buffer
, TEXT("n=%d"), n
);
748 SendDlgItemMessage(hWnd
, IDC_TEXT_NITEMS
, WM_SETTEXT
, 0, (LPARAM
)buffer
);
751 static void clean_stat_list(void)
753 statistic_t
*p
= calc
.stat
;
757 p
= (statistic_t
*)(p
->next
);
764 static void delete_stat_item(int n
)
766 statistic_t
*p
= calc
.stat
;
770 calc
.stat
= (statistic_t
*)p
->next
;
774 s
= (statistic_t
*)p
->next
;
777 s
= (statistic_t
*)p
->next
;
785 static char *ReadConversion(const char *formula
)
787 unsigned int len
= 256, n
;
790 const char *p
= formula
;
793 TCHAR buffer
[SIZEOF(calc
.buffer
)];
795 char cbuffer
[SIZEOF(calc
.buffer
)];
798 str
= (char *)malloc(len
);
802 /* prepare code string */
804 convert_text2number(&x
);
805 prepare_rpn_result(&x
,
806 buffer
, SIZEOF(buffer
),
811 WideCharToMultiByte(CP_ACP
, 0, buffer
, -1, cbuffer
, SIZEOF(cbuffer
), NULL
, NULL
);
827 str
= (char *)realloc(str
, len
+= 16);
843 str
= (char *)realloc(str
, len
+= 16);
850 /* clear display content before proceeding */
851 calc
.ptr
= calc
.buffer
;
852 calc
.buffer
[0] = TEXT('\0');
857 static LRESULT CALLBACK
DlgStatProc(HWND hWnd
, UINT msg
, WPARAM wp
, LPARAM lp
)
859 TCHAR buffer
[SIZEOF(calc
.buffer
)];
866 switch (LOWORD(wp
)) {
868 if (HIWORD(wp
) == CBN_DBLCLK
)
869 SendMessage(hWnd
, WM_COMMAND
, (WPARAM
)IDC_BUTTON_LOAD
, 0);
872 SetFocus(GetDlgItem(GetParent(hWnd
), IDC_BUTTON_FOCUS
));
874 case IDC_BUTTON_LOAD
:
875 n
= SendDlgItemMessage(hWnd
, IDC_LIST_STAT
, LB_GETCURSEL
, 0, 0);
878 PostMessage(GetParent(hWnd
), WM_LOAD_STAT
, (WPARAM
)n
, 0);
881 n
= SendDlgItemMessage(hWnd
, IDC_LIST_STAT
, LB_GETCURSEL
, 0, 0);
884 SendDlgItemMessage(hWnd
, IDC_LIST_STAT
, LB_DELETESTRING
, (WPARAM
)n
, 0);
885 update_n_stats_items(hWnd
, buffer
);
889 SendDlgItemMessage(hWnd
, IDC_LIST_STAT
, LB_RESETCONTENT
, 0, 0);
891 update_n_stats_items(hWnd
, buffer
);
900 PostMessage(GetParent(hWnd
), WM_CLOSE_STATS
, 0, 0);
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
);
913 static WPARAM
idm_2_idc(int idm
)
917 for (x
=0; x
<SIZEOF(upd
); x
++) {
918 if (upd
[x
].idm
== idm
)
921 return (WPARAM
)(upd
[x
].idc
);
924 static void CopyMemToClipboard(void *ptr
)
926 if(OpenClipboard(NULL
)) {
931 clipbuffer
= GlobalAlloc(GMEM_DDESHARE
, (_tcslen(ptr
)+1)*sizeof(TCHAR
));
932 buffer
= (TCHAR
*)GlobalLock(clipbuffer
);
933 _tcscpy(buffer
, ptr
);
934 GlobalUnlock(clipbuffer
);
936 SetClipboardData(CF_UNICODETEXT
,clipbuffer
);
938 SetClipboardData(CF_TEXT
,clipbuffer
);
944 static void handle_copy_command(HWND hWnd
)
946 TCHAR display
[sizeof(calc
.buffer
)];
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
);
954 static char *ReadClipboard(void)
958 if (OpenClipboard(NULL
)) {
959 HANDLE hData
= GetClipboardData(CF_TEXT
);
963 fromClipboard
= (char *)GlobalLock(hData
);
964 if (strlen(fromClipboard
))
965 buffer
= _strupr(_strdup(fromClipboard
));
966 GlobalUnlock( hData
);
973 static char *handle_sequence_input(HWND hwnd
, sequence_t
*seq
)
975 char *ptr
= seq
->ptr
;
980 PostMessage(hwnd
, WM_COMMAND
, (WPARAM
)IDC_BUTTON_DAT
, 0);
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;
995 for (x
=0; x
<SIZEOF(key2code
); x
++) {
996 if (!(key2code
[x
].mask
& BITMASK_IS_ASCII
) ||
997 (key2code
[x
].mask
& BITMASK_IS_CTRL
))
999 if (key2code
[x
].key
== ch
) {
1000 PostMessage(hwnd
, WM_COMMAND
, (WPARAM
)key2code
[x
].idc
, 0);
1007 PostMessage(hwnd
, seq
->wm_msg
, 0, 0);
1010 seq
->data
= seq
->ptr
= ptr
= NULL
;
1015 static void run_dat_sta(calc_number_t
*a
)
1017 statistic_t
*s
= (statistic_t
*)malloc(sizeof(statistic_t
));
1018 statistic_t
*p
= calc
.stat
;
1021 rpn_copy(&s
->num
, a
);
1022 s
->base
= calc
.base
;
1027 while (p
->next
!= NULL
)
1028 p
= (statistic_t
*)(p
->next
);
1031 PostMessage(calc
.hStatWnd
, WM_INSERT_STAT
, 0, (LPARAM
)s
);
1034 static void run_mp(calc_number_t
*c
)
1039 cn
.base
= calc
.base
;
1040 run_operator(&calc
.memory
, &calc
.memory
, &cn
, RPN_OPERATOR_ADD
);
1041 update_memory_flag(calc
.hWnd
, TRUE
);
1044 static void run_mm(calc_number_t
*c
)
1049 cn
.base
= calc
.base
;
1050 run_operator(&calc
.memory
, &calc
.memory
, &cn
, RPN_OPERATOR_SUB
);
1051 update_memory_flag(calc
.hWnd
, TRUE
);
1054 static void run_ms(calc_number_t
*c
)
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
);
1061 static void run_mw(calc_number_t
*c
)
1065 rpn_copy(&tmp
, &calc
.memory
.number
);
1066 rpn_copy(&calc
.memory
.number
, c
);
1067 calc
.memory
.base
= calc
.base
;
1070 update_memory_flag(calc
.hWnd
, rpn_is_zero(&calc
.memory
.number
) ? FALSE
: TRUE
);
1073 static statistic_t
*upload_stat_number(int n
)
1075 statistic_t
*p
= calc
.stat
;
1081 p
= (statistic_t
*)(p
->next
);
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
;
1091 calc
.code
.i
= (__int64
)p
->num
.f
;
1092 apply_int_mask(&calc
.code
);
1096 rpn_copy(&calc
.code
, &p
->num
);
1098 calc
.is_nan
= FALSE
;
1103 static void run_pow(calc_number_t
*number
)
1105 exec_infix2postfix(number
, RPN_OPERATOR_POW
);
1108 static void run_sqr(calc_number_t
*number
)
1110 exec_infix2postfix(number
, RPN_OPERATOR_SQR
);
1113 static void run_fe(calc_number_t
*number
)
1115 calc
.sci_out
= ((calc
.sci_out
== TRUE
) ? FALSE
: TRUE
);
1118 static void handle_context_menu(HWND hWnd
, WPARAM wp
, LPARAM lp
)
1121 HMENU hMenu
= CreatePopupMenu();
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
,
1134 #ifndef DISABLE_HTMLHELP_SUPPORT
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
);
1154 static void run_canc(calc_number_t
*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);
1166 static void run_rpar(calc_number_t
*c
)
1168 exec_closeparent(c
);
1171 static void run_lpar(calc_number_t
*c
)
1173 exec_infix2postfix(c
, RPN_OPERATOR_PARENT
);
1176 static LRESULT CALLBACK
SubclassButtonProc(HWND hWnd
, WPARAM wp
, LPARAM lp
)
1178 LPDRAWITEMSTRUCT dis
= (LPDRAWITEMSTRUCT
)lp
;
1186 if(dis
->CtlType
== ODT_BUTTON
) {
1188 * little exception: 1/x has different color
1189 * in standard and scientific modes
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
);
1196 for (dx
=0; dx
<SIZEOF(key2code
); dx
++) {
1197 if (key2code
[dx
].idc
== dis
->CtlID
) {
1198 SetTextColor(dis
->hDC
, key2code
[dx
].col
);
1202 /* button text to write */
1203 len
= GetWindowText(dis
->hwndItem
, text
, SIZEOF(text
));
1204 /* default state: unpushed & enabled */
1207 if ((dis
->itemState
& ODS_DISABLED
))
1208 dwText
= DSS_DISABLED
;
1209 if ((dis
->itemState
& ODS_SELECTED
))
1210 dwStyle
= DFCS_PUSHED
;
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
)) {
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
);
1227 static LRESULT CALLBACK
DlgMainProc(HWND hWnd
, UINT msg
, WPARAM wp
, LPARAM lp
)
1234 return SubclassButtonProc(hWnd
, wp
, lp
);
1239 #ifdef USE_KEYBOARD_HOOK
1240 calc
.hKeyboardHook
=SetWindowsHookEx(
1244 GetCurrentThreadId()
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
);
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
)
1269 /* Restore the window at the same position it was */
1270 if (calc
.x_coord
>= 0 && calc
.y_coord
>= 0) {
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
);
1283 case WM_CTLCOLORSTATIC
:
1284 if ((HWND
)lp
== GetDlgItem(hWnd
, IDC_TEXT_OUTPUT
))
1285 return (LRESULT
)GetStockObject(WHITE_BRUSH
);
1287 case WM_HANDLE_CLIPBOARD
:
1288 handle_sequence_input(hWnd
, &calc
.Clipboard
);
1292 * if selection of category is changed, we must
1293 * updatethe content of the "from/to" combo boxes.
1295 if (wp
== MAKEWPARAM(IDC_COMBO_CATEGORY
, CBN_SELCHANGE
)) {
1296 ConvAdjust(hWnd
, SendDlgItemMessage(hWnd
, IDC_COMBO_CATEGORY
, CB_GETCURSEL
, 0, 0));
1299 if (HIWORD(wp
) != BN_CLICKED
&& HIWORD(wp
) != BN_DBLCLK
)
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
);
1309 #ifndef DISABLE_HTMLHELP_SUPPORT
1310 HtmlHelp(hWnd
, HTMLHELP_PATH("/general_information.htm"), HH_DISPLAY_TOPIC
, (DWORD_PTR
)NULL
);
1313 case IDM_VIEW_STANDARD
:
1314 calc
.layout
= CALC_LAYOUT_STANDARD
;
1315 calc
.action
= IDM_VIEW_STANDARD
;
1316 DestroyWindow(hWnd
);
1319 case IDM_VIEW_SCIENTIFIC
:
1320 calc
.layout
= CALC_LAYOUT_SCIENTIFIC
;
1321 calc
.action
= IDM_VIEW_SCIENTIFIC
;
1322 DestroyWindow(hWnd
);
1325 case IDM_VIEW_CONVERSION
:
1326 calc
.layout
= CALC_LAYOUT_CONVERSION
;
1327 calc
.action
= IDM_VIEW_CONVERSION
;
1328 DestroyWindow(hWnd
);
1338 case IDM_VIEW_QWORD
:
1339 case IDM_VIEW_DWORD
:
1342 SendMessage(hWnd
, WM_COMMAND
, idm_2_idc(LOWORD(wp
)), 0);
1345 handle_copy_command(hWnd
);
1347 case IDM_EDIT_PASTE
:
1348 if (calc
.Clipboard
.data
!= NULL
)
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
);
1359 case IDM_VIEW_GROUP
:
1360 calc
.usesep
= (calc
.usesep
? FALSE
: TRUE
);
1362 update_lcd_display(hWnd
);
1365 case IDC_BUTTON_CONVERT
:
1368 case IDC_BUTTON_CE
: {
1371 display_rpn_result(hWnd
, &tmp
);
1378 /* GNU WINDRES is bugged so I must always force radio update */
1379 /* (Fix for Win95/98) */
1381 if (calc
.base
== LOWORD(wp
))
1384 calc
.is_nan
= FALSE
;
1385 update_radio(hWnd
, LOWORD(wp
));
1389 case IDC_RADIO_GRAD
:
1390 /* GNU WINDRES is bugged so I must always force radio update */
1391 /* (Fix for Win95/98) */
1393 if (calc
.degr
== LOWORD(wp
))
1396 calc
.degr
= LOWORD(wp
);
1397 calc
.is_nan
= FALSE
;
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) */
1407 if (calc
.size
== LOWORD(wp
))
1410 calc
.size
= LOWORD(wp
);
1411 calc
.is_nan
= FALSE
;
1414 * update the content of the display
1416 convert_text2number(&calc
.code
);
1417 apply_int_mask(&calc
.code
);
1418 display_rpn_result(hWnd
, &calc
.code
);
1430 case IDC_BUTTON_DOT
:
1437 calc
.is_nan
= FALSE
;
1438 build_operand(hWnd
, LOWORD(wp
));
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
:
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;
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.
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);
1463 for (x
=0; x
<SIZEOF(operator_codes
); x
++) {
1464 if (LOWORD(wp
) == operator_codes
[x
]) {
1465 convert_text2number(&calc
.code
);
1467 if (calc
.ptr
== calc
.buffer
) {
1468 if (calc
.last_operator
!= x
) {
1469 if (x
!= RPN_OPERATOR_EQUAL
)
1470 exec_change_infix();
1472 if (x
== RPN_OPERATOR_EQUAL
) {
1473 exec_infix2postfix(&calc
.code
, calc
.prev_operator
);
1474 rpn_copy(&calc
.code
, &calc
.prev
);
1478 /* if no change then quit silently, */
1479 /* without display updates */
1480 if (!exec_infix2postfix(&calc
.code
, x
))
1483 display_rpn_result(hWnd
, &calc
.code
);
1488 case IDC_BUTTON_BACK
:
1490 if (calc
.esp
== 0) {
1493 calc
.sci_in
= FALSE
;
1494 ptr
= _tcschr(calc
.ptr
, TEXT('e'));
1497 update_lcd_display(hWnd
);
1500 build_operand(hWnd
, IDC_STATIC
);
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');
1511 update_lcd_display(hWnd
);
1515 rpn_zero(&calc
.memory
.number
);
1516 update_memory_flag(hWnd
, FALSE
);
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
);
1525 case IDC_BUTTON_EXP
:
1526 if (calc
.sci_in
|| calc
.is_nan
|| calc
.buffer
== calc
.ptr
)
1530 build_operand(hWnd
, IDC_STATIC
);
1532 case IDC_BUTTON_SIGN
:
1534 calc
.esp
= 0-calc
.esp
;
1535 build_operand(hWnd
, IDC_STATIC
);
1537 if (calc
.is_nan
|| calc
.buffer
[0] == TEXT('\0'))
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
)
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('.'))
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
)
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
);
1565 case IDC_BUTTON_RIGHTPAR
:
1566 case IDC_BUTTON_LEFTPAR
:
1567 case IDC_BUTTON_CANC
:
1569 case IDC_BUTTON_DAT
:
1571 case IDC_BUTTON_DMS
:
1572 case IDC_BUTTON_SQRT
:
1574 case IDC_BUTTON_SUM
:
1575 case IDC_BUTTON_AVE
:
1578 case IDC_BUTTON_LOG
:
1579 case IDC_BUTTON_Xe2
:
1580 case IDC_BUTTON_Xe3
:
1582 case IDC_BUTTON_NOT
:
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
:
1590 for (x
=0; x
<SIZEOF(function_table
); x
++) {
1591 if (LOWORD(wp
) == function_table
[x
].idc
) {
1592 rpn_callback1 cb
= NULL
;
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
;
1599 switch (get_modifiers(hWnd
) & function_table
[x
].range
) {
1601 cb
= function_table
[x
].direct
;
1604 cb
= function_table
[x
].inverse
;
1607 cb
= function_table
[x
].hyperb
;
1609 case MODIFIER_INV
|MODIFIER_HYP
:
1610 cb
= function_table
[x
].inv_hyp
;
1614 convert_text2number(&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);
1625 case IDC_BUTTON_STA
:
1626 if (IsWindow(calc
.hStatWnd
))
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);
1637 case WM_CLOSE_STATS
:
1638 enable_allowed_controls(hWnd
, calc
.base
);
1641 if (upload_stat_number((int)LOWORD(wp
)) != NULL
)
1642 display_rpn_result(hWnd
, &calc
.code
);
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);
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
));
1659 handle_sequence_input(hWnd
, &calc
.Convert
[1]);
1662 calc
.action
= IDC_STATIC
;
1663 DestroyWindow(hWnd
);
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
);
1675 case WM_CONTEXTMENU
:
1676 if ((HWND
)wp
!= hWnd
)
1677 handle_context_menu(hWnd
, wp
, lp
);
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),
1685 (IsClipboardFormatAvailable(CF_TEXT
) ?
1686 MF_ENABLED
: MF_GRAYED
));
1688 case WM_EXITMENULOOP
:
1689 calc
.is_menu_on
= FALSE
;
1695 int WINAPI
_tWinMain(HINSTANCE hInstance
, HINSTANCE hPrevInstance
, LPTSTR lpCmdLine
, int nShowCmd
)
1700 calc
.hInstance
= hInstance
;
1709 /* ignore hwnd: dialogs are already visible! */
1710 if (calc
.layout
== CALC_LAYOUT_SCIENTIFIC
)
1711 dwLayout
= IDD_DIALOG_SCIENTIFIC
;
1713 if (calc
.layout
== CALC_LAYOUT_CONVERSION
)
1714 dwLayout
= IDD_DIALOG_CONVERSION
;
1716 dwLayout
= IDD_DIALOG_STANDARD
;
1718 CreateDialog(hInstance
, MAKEINTRESOURCE(dwLayout
), NULL
, (DLGPROC
)DlgMainProc
);
1720 while (GetMessage(&msg
, NULL
, 0, 0)) {
1721 #ifndef USE_KEYBOARD_HOOK
1722 if ((msg
.message
== WM_KEYUP
||
1723 msg
.message
== WM_KEYDOWN
) &&
1725 process_vk_key(msg
.wParam
, msg
.lParam
);
1727 TranslateMessage(&msg
);
1728 DispatchMessage(&msg
);
1730 } while (calc
.action
!= IDC_STATIC
);