2 * ReactOS Calc (main program)
4 * Copyright 2007-2017, Carlo Bramini
6 * This program is free software; you can redistribute it and/or
7 * modify it under the terms of the GNU Lesser General Public
8 * License as published by the Free Software Foundation; either
9 * version 2 of the License, or (at your option) any later version.
11 * This library is distributed in the hope that it will be useful,
12 * but WITHOUT ANY WARRANTY; without even the implied warranty of
13 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
14 * Lesser General Public License for more details.
16 * You should have received a copy of the GNU Lesser General Public
17 * License along with this library; if not, write to the Free Software
18 * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
23 #define HTMLHELP_PATH(_pt) _T("%systemroot%\\Help\\calc.chm::") _T(_pt)
25 #define MAKE_BITMASK4(_show_b16, _show_b10, _show_b8, _show_b2) \
26 (((_show_b2) << 0) | \
28 ((_show_b10) << 2) | \
31 #define MAKE_BITMASK5(_transl, _is_stats, _is_ctrl, _show_b16, _show_b10, _show_b8, _show_b2) \
32 (((_show_b2) << 0) | \
34 ((_show_b10) << 2) | \
35 ((_show_b16) << 3) | \
37 ((_is_stats) << 6) | \
40 #define KEY_IS_UP 0x80000000
41 #define KEY_WAS_DOWN 0x40000000
43 #define BITMASK_IS_ASCII 0x80
44 #define BITMASK_IS_STATS 0x40
45 #define BITMASK_IS_CTRL 0x20
46 #define BITMASK_HEX_MASK 0x08
47 #define BITMASK_DEC_MASK 0x04
48 #define BITMASK_OCT_MASK 0x02
49 #define BITMASK_BIN_MASK 0x01
51 #define CALC_CLR_RED RGB(0xFF, 0x00, 0x00)
52 #define CALC_CLR_BLUE RGB(0x00, 0x00, 0xFF)
53 #define CALC_CLR_PURP RGB(0xFF, 0x00, 0xFF)
56 CHAR key
; // Virtual key identifier
57 WORD idc
; // IDC for posting message
61 WORD idc
; // IDC for posting message
62 CHAR key
; // Virtual key identifier
63 BYTE mask
; // enable/disable into the various modes.
64 COLORREF col
; // color used for drawing the text
67 #define CTRL_FLAG 0x100
68 #define ALT_FLAG 0x200
70 #define CTRL_A (0x0001+'A'-'A')
71 #define CTRL_C (0x0001+'C'-'A')
72 #define CTRL_D (0x0001+'D'-'A')
73 #define CTRL_L (0x0001+'L'-'A')
74 #define CTRL_M (0x0001+'M'-'A')
75 #define CTRL_P (0x0001+'P'-'A')
76 #define CTRL_R (0x0001+'R'-'A')
77 #define CTRL_S (0x0001+'S'-'A')
78 #define CTRL_T (0x0001+'T'-'A')
79 #define CTRL_V (0x0001+'V'-'A')
80 #define CTRL_Z (0x0001+'Z'-'A')
82 static const key3code_t key2code
[] = {
83 /* CONTROL-ID Key asc sta ctl hex dec oct bin */
84 { IDC_BUTTON_STA
, CTRL_S
, MAKE_BITMASK5( 1, 0, 1, 1, 1, 1, 1), CALC_CLR_BLUE
, },
85 { IDC_BUTTON_AVE
, CTRL_A
, MAKE_BITMASK5( 1, 1, 1, 1, 1, 1, 1), CALC_CLR_BLUE
, },
86 { IDC_BUTTON_SUM
, CTRL_T
, MAKE_BITMASK5( 1, 1, 1, 1, 1, 1, 1), CALC_CLR_BLUE
, },
87 { IDC_BUTTON_S
, CTRL_D
, MAKE_BITMASK5( 1, 1, 1, 1, 1, 1, 1), CALC_CLR_BLUE
, },
88 { IDC_BUTTON_MS
, CTRL_M
, MAKE_BITMASK5( 1, 0, 1, 1, 1, 1, 1), CALC_CLR_RED
, },
89 { IDC_BUTTON_MR
, CTRL_R
, MAKE_BITMASK5( 1, 0, 1, 1, 1, 1, 1), CALC_CLR_RED
, },
90 { IDC_BUTTON_MP
, CTRL_P
, MAKE_BITMASK5( 1, 0, 1, 1, 1, 1, 1), CALC_CLR_RED
, },
91 { IDC_BUTTON_MC
, CTRL_L
, MAKE_BITMASK5( 1, 0, 1, 1, 1, 1, 1), CALC_CLR_RED
, },
92 { IDC_BUTTON_0
, '0', MAKE_BITMASK5( 1, 0, 0, 1, 1, 1, 1), CALC_CLR_BLUE
, },
93 { IDC_BUTTON_1
, '1', MAKE_BITMASK5( 1, 0, 0, 1, 1, 1, 1), CALC_CLR_BLUE
, },
94 { IDC_BUTTON_2
, '2', MAKE_BITMASK5( 1, 0, 0, 1, 1, 1, 0), CALC_CLR_BLUE
, },
95 { IDC_BUTTON_3
, '3', MAKE_BITMASK5( 1, 0, 0, 1, 1, 1, 0), CALC_CLR_BLUE
, },
96 { IDC_BUTTON_4
, '4', MAKE_BITMASK5( 1, 0, 0, 1, 1, 1, 0), CALC_CLR_BLUE
, },
97 { IDC_BUTTON_5
, '5', MAKE_BITMASK5( 1, 0, 0, 1, 1, 1, 0), CALC_CLR_BLUE
, },
98 { IDC_BUTTON_6
, '6', MAKE_BITMASK5( 1, 0, 0, 1, 1, 1, 0), CALC_CLR_BLUE
, },
99 { IDC_BUTTON_7
, '7', MAKE_BITMASK5( 1, 0, 0, 1, 1, 1, 0), CALC_CLR_BLUE
, },
100 { IDC_BUTTON_8
, '8', MAKE_BITMASK5( 1, 0, 0, 1, 1, 0, 0), CALC_CLR_BLUE
, },
101 { IDC_BUTTON_9
, '9', MAKE_BITMASK5( 1, 0, 0, 1, 1, 0, 0), CALC_CLR_BLUE
, },
102 { IDC_BUTTON_DOT
, '.', MAKE_BITMASK5( 1, 0, 0, 0, 1, 0, 0), CALC_CLR_BLUE
, },
103 { IDC_BUTTON_DOT
, ',', MAKE_BITMASK5( 1, 0, 0, 0, 1, 0, 0), -1, },
104 { IDC_BUTTON_ADD
, '+', MAKE_BITMASK5( 1, 0, 0, 1, 1, 1, 1), CALC_CLR_RED
, },
105 { IDC_BUTTON_SUB
, '-', MAKE_BITMASK5( 1, 0, 0, 1, 1, 1, 1), CALC_CLR_RED
, },
106 { IDC_BUTTON_MULT
, '*', MAKE_BITMASK5( 1, 0, 0, 1, 1, 1, 1), CALC_CLR_RED
, },
107 { IDC_BUTTON_DIV
, '/', MAKE_BITMASK5( 1, 0, 0, 1, 1, 1, 1), CALC_CLR_RED
, },
108 { IDC_BUTTON_AND
, '&', MAKE_BITMASK5( 1, 0, 0, 1, 1, 1, 1), CALC_CLR_RED
, },
109 { IDC_BUTTON_OR
, '|', MAKE_BITMASK5( 1, 0, 0, 1, 1, 1, 1), CALC_CLR_RED
, },
110 { IDC_BUTTON_XOR
, '^', MAKE_BITMASK5( 1, 0, 0, 1, 1, 1, 1), CALC_CLR_RED
, },
111 { IDC_BUTTON_LSH
, '<', MAKE_BITMASK5( 1, 0, 0, 1, 1, 1, 1), CALC_CLR_RED
, },
112 { IDC_BUTTON_NOT
, '~', MAKE_BITMASK5( 1, 0, 0, 1, 1, 1, 1), CALC_CLR_RED
, },
113 { IDC_BUTTON_INT
, ';', MAKE_BITMASK5( 1, 0, 0, 0, 1, 0, 0), CALC_CLR_RED
, },
114 { IDC_BUTTON_EQU
, '=', MAKE_BITMASK5( 1, 0, 0, 1, 1, 1, 1), CALC_CLR_RED
, },
115 { IDC_BUTTON_A
, 'A', MAKE_BITMASK5( 1, 0, 0, 1, 0, 0, 0), CALC_CLR_BLUE
, },
116 { IDC_BUTTON_B
, 'B', MAKE_BITMASK5( 1, 0, 0, 1, 0, 0, 0), CALC_CLR_BLUE
, },
117 { IDC_BUTTON_C
, 'C', MAKE_BITMASK5( 1, 0, 0, 1, 0, 0, 0), CALC_CLR_BLUE
, },
118 { IDC_BUTTON_D
, 'D', MAKE_BITMASK5( 1, 0, 0, 1, 0, 0, 0), CALC_CLR_BLUE
, },
119 { IDC_BUTTON_E
, 'E', MAKE_BITMASK5( 1, 0, 0, 1, 0, 0, 0), CALC_CLR_BLUE
, },
120 { IDC_BUTTON_F
, 'F', MAKE_BITMASK5( 1, 0, 0, 1, 0, 0, 0), CALC_CLR_BLUE
, },
121 { IDC_CHECK_HYP
, 'H', MAKE_BITMASK5( 1, 0, 0, 1, 1, 1, 1), -1, },
122 { IDC_CHECK_INV
, 'I', MAKE_BITMASK5( 1, 0, 0, 1, 1, 1, 1), -1, },
123 { IDC_BUTTON_LOG
, 'L', MAKE_BITMASK5( 1, 0, 0, 0, 1, 0, 0), CALC_CLR_PURP
, },
124 { IDC_BUTTON_DMS
, 'M', MAKE_BITMASK5( 1, 0, 0, 0, 1, 0, 0), CALC_CLR_PURP
, },
125 { IDC_BUTTON_LN
, 'N', MAKE_BITMASK5( 1, 0, 0, 0, 1, 0, 0), CALC_CLR_PURP
, },
126 { IDC_BUTTON_PI
, 'P', MAKE_BITMASK5( 1, 0, 0, 0, 1, 0, 0), CALC_CLR_BLUE
, },
127 { IDC_BUTTON_RX
, 'R', MAKE_BITMASK5( 1, 0, 0, 0, 1, 0, 0), CALC_CLR_PURP
, },
128 { IDC_BUTTON_SIN
, 'S', MAKE_BITMASK5( 1, 0, 0, 0, 1, 0, 0), CALC_CLR_PURP
, },
129 { IDC_BUTTON_COS
, 'O', MAKE_BITMASK5( 1, 0, 0, 0, 1, 0, 0), CALC_CLR_PURP
, },
130 { IDC_BUTTON_TAN
, 'T', MAKE_BITMASK5( 1, 0, 0, 0, 1, 0, 0), CALC_CLR_PURP
, },
131 { IDC_BUTTON_FE
, 'V', MAKE_BITMASK5( 1, 0, 0, 0, 1, 0, 0), CALC_CLR_PURP
, },
132 { IDC_BUTTON_EXP
, 'X', MAKE_BITMASK5( 1, 0, 0, 0, 1, 0, 0), CALC_CLR_PURP
, },
133 { IDC_BUTTON_XeY
, 'Y', MAKE_BITMASK5( 1, 0, 0, 1, 1, 1, 1), CALC_CLR_PURP
, },
134 { IDC_BUTTON_SQRT
, '@', MAKE_BITMASK5( 1, 0, 0, 0, 1, 0, 0), CALC_CLR_BLUE
, },
135 { IDC_BUTTON_Xe2
, '@', MAKE_BITMASK5( 1, 0, 0, 1, 1, 1, 1), CALC_CLR_PURP
, },
136 { IDC_BUTTON_Xe3
, '#', MAKE_BITMASK5( 1, 0, 0, 1, 1, 1, 1), CALC_CLR_PURP
, },
137 { IDC_BUTTON_NF
, '!', MAKE_BITMASK5( 1, 0, 0, 1, 1, 1, 1), CALC_CLR_PURP
, },
138 { IDC_BUTTON_LEFTPAR
, '(', MAKE_BITMASK5( 1, 0, 0, 1, 1, 1, 1), CALC_CLR_PURP
, },
139 { IDC_BUTTON_RIGHTPAR
, ')', MAKE_BITMASK5( 1, 0, 0, 1, 1, 1, 1), CALC_CLR_PURP
, },
140 { IDC_BUTTON_MOD
, '%', MAKE_BITMASK5( 1, 0, 0, 1, 1, 1, 1), CALC_CLR_RED
, },
141 { IDC_BUTTON_PERCENT
, '%', MAKE_BITMASK5( 1, 0, 0, 0, 1, 0, 0), CALC_CLR_BLUE
, },
142 /*----------------------------------------------------------------------*/
143 { IDC_BUTTON_DAT
, VK_INSERT
, MAKE_BITMASK5( 0, 1, 0, 1, 1, 1, 1), CALC_CLR_BLUE
, },
144 { IDC_BUTTON_EQU
, VK_RETURN
, MAKE_BITMASK5( 0, 0, 0, 1, 1, 1, 1), CALC_CLR_RED
, },
145 { IDC_BUTTON_CANC
, VK_ESCAPE
, MAKE_BITMASK5( 0, 0, 0, 1, 1, 1, 1), CALC_CLR_RED
, },
146 { IDC_BUTTON_CE
, VK_DELETE
, MAKE_BITMASK5( 0, 0, 0, 1, 1, 1, 1), CALC_CLR_RED
, },
147 { IDC_BUTTON_BACK
, VK_BACK
, MAKE_BITMASK5( 0, 0, 0, 1, 1, 1, 1), CALC_CLR_RED
, },
148 { IDC_RADIO_HEX
, VK_F5
, MAKE_BITMASK5( 0, 0, 0, 1, 1, 1, 1), -1, },
149 { IDC_RADIO_DEC
, VK_F6
, MAKE_BITMASK5( 0, 0, 0, 1, 1, 1, 1), -1, },
150 { IDC_RADIO_OCT
, VK_F7
, MAKE_BITMASK5( 0, 0, 0, 1, 1, 1, 1), -1, },
151 { IDC_RADIO_BIN
, VK_F8
, MAKE_BITMASK5( 0, 0, 0, 1, 1, 1, 1), -1, },
152 { IDC_BUTTON_SIGN
, VK_F9
, MAKE_BITMASK5( 0, 0, 0, 1, 1, 1, 1), CALC_CLR_BLUE
, },
155 static const key2code_t key2code_base16
[] = {
156 { VK_F2
, IDC_RADIO_DWORD
, },
157 { VK_F3
, IDC_RADIO_WORD
, },
158 { VK_F4
, IDC_RADIO_BYTE
, },
159 { VK_F12
, IDC_RADIO_QWORD
, },
162 static const key2code_t key2code_base10
[] = {
163 { VK_F2
, IDC_RADIO_DEG
, },
164 { VK_F3
, IDC_RADIO_RAD
, },
165 { VK_F4
, IDC_RADIO_GRAD
, },
168 static const WORD operator_codes
[] = {
169 /* CONTROL-ID operator */
170 (WORD
)IDC_STATIC
, // RPN_OPERATOR_PARENT
171 IDC_BUTTON_PERCENT
, // RPN_OPERATOR_PERCENT
172 IDC_BUTTON_EQU
, // RPN_OPERATOR_EQUAL
173 IDC_BUTTON_OR
, // RPN_OPERATOR_OR
174 IDC_BUTTON_XOR
, // RPN_OPERATOR_XOR
175 IDC_BUTTON_AND
, // RPN_OPERATOR_AND
176 IDC_BUTTON_LSH
, // RPN_OPERATOR_LSH
177 IDC_BUTTON_RSH
, // RPN_OPERATOR_RSH
178 IDC_BUTTON_ADD
, // RPN_OPERATOR_ADD
179 IDC_BUTTON_SUB
, // RPN_OPERATOR_SUB
180 IDC_BUTTON_MULT
, // RPN_OPERATOR_MULT
181 IDC_BUTTON_DIV
, // RPN_OPERATOR_DIV
182 IDC_BUTTON_MOD
, // RPN_OPERATOR_MOD
183 IDC_BUTTON_XeY
, // RPN_OPERATOR_POW
184 IDC_BUTTON_XrY
, // RPN_OPERATOR_SQR
187 typedef void (*rpn_callback1
)(calc_number_t
*);
193 rpn_callback1 direct
;
194 rpn_callback1 inverse
;
195 rpn_callback1 hyperb
;
196 rpn_callback1 inv_hyp
;
199 static void run_fe(calc_number_t
*number
);
200 static void run_dat_sta(calc_number_t
*number
);
201 static void run_mp(calc_number_t
*c
);
202 static void run_mm(calc_number_t
*c
);
203 static void run_ms(calc_number_t
*c
);
204 static void run_mw(calc_number_t
*c
);
205 static void run_canc(calc_number_t
*c
);
206 static void run_rpar(calc_number_t
*c
);
207 static void run_lpar(calc_number_t
*c
);
209 static const function_table_t function_table
[] = {
210 { IDC_BUTTON_SIN
, MODIFIER_INV
|MODIFIER_HYP
, 1, rpn_sin
, rpn_asin
, rpn_sinh
, rpn_asinh
},
211 { IDC_BUTTON_COS
, MODIFIER_INV
|MODIFIER_HYP
, 1, rpn_cos
, rpn_acos
, rpn_cosh
, rpn_acosh
},
212 { IDC_BUTTON_TAN
, MODIFIER_INV
|MODIFIER_HYP
, 1, rpn_tan
, rpn_atan
, rpn_tanh
, rpn_atanh
},
213 { IDC_BUTTON_INT
, MODIFIER_INV
, 1, rpn_int
, rpn_frac
, NULL
, NULL
},
214 { IDC_BUTTON_RX
, 0, 1, rpn_reci
, NULL
, NULL
, NULL
},
215 { IDC_BUTTON_NOT
, 0, 1, rpn_not
, NULL
, NULL
, NULL
},
216 { IDC_BUTTON_PI
, MODIFIER_INV
, 0, rpn_pi
, rpn_2pi
, NULL
, NULL
},
217 { IDC_BUTTON_Xe2
, MODIFIER_INV
, 1, rpn_exp2
, rpn_sqrt
, NULL
, NULL
},
218 { IDC_BUTTON_Xe3
, MODIFIER_INV
, 1, rpn_exp3
, rpn_cbrt
, NULL
, NULL
},
219 { IDC_BUTTON_LN
, MODIFIER_INV
, 1, rpn_ln
, rpn_exp
, NULL
, NULL
},
220 { IDC_BUTTON_LOG
, MODIFIER_INV
, 1, rpn_log
, rpn_exp10
, NULL
, NULL
},
221 { IDC_BUTTON_NF
, 0, 1, rpn_fact
, NULL
, NULL
, NULL
},
222 { IDC_BUTTON_AVE
, MODIFIER_INV
, 0, rpn_ave
, rpn_ave2
, NULL
, NULL
},
223 { IDC_BUTTON_SUM
, MODIFIER_INV
, 0, rpn_sum
, rpn_sum2
, NULL
, NULL
},
224 { IDC_BUTTON_S
, MODIFIER_INV
, 0, rpn_s_m1
, rpn_s
, NULL
, NULL
},
225 { IDC_BUTTON_SQRT
, MODIFIER_INV
, 1, rpn_sqrt
, NULL
, NULL
, NULL
},
226 { IDC_BUTTON_DMS
, MODIFIER_INV
, 1, rpn_dec2dms
, rpn_dms2dec
, NULL
, NULL
},
227 { IDC_BUTTON_FE
, 0, 1, run_fe
, NULL
, NULL
, NULL
},
228 { IDC_BUTTON_DAT
, 0, 1, run_dat_sta
, NULL
, NULL
, NULL
, },
229 { IDC_BUTTON_MP
, MODIFIER_INV
|NO_CHAIN
, 1, run_mp
, run_mm
, NULL
, NULL
, },
230 { IDC_BUTTON_MS
, MODIFIER_INV
|NO_CHAIN
, 1, run_ms
, run_mw
, NULL
, NULL
, },
231 { IDC_BUTTON_CANC
, NO_CHAIN
, 0, run_canc
, NULL
, NULL
, NULL
, },
232 { IDC_BUTTON_RIGHTPAR
, NO_CHAIN
, 1, run_rpar
, NULL
, NULL
, NULL
, },
233 { IDC_BUTTON_LEFTPAR
, NO_CHAIN
, 0, run_lpar
, NULL
, NULL
, NULL
, },
236 /* Sub-classing information for theming support */
240 } BTNINFO
,*LPBTNINFO
;
244 * Global variable declaration
249 /* Hot-state info for theming support */
250 BTNINFO BtnInfo
[255];
253 static void UpdateNumberIntl(void)
255 /* Get current user defaults */
256 if (!GetLocaleInfo(LOCALE_USER_DEFAULT
, LOCALE_SDECIMAL
, calc
.sDecimal
, SIZEOF(calc
.sDecimal
)))
257 _tcscpy(calc
.sDecimal
, _T("."));
259 if (!GetLocaleInfo(LOCALE_USER_DEFAULT
, LOCALE_STHOUSAND
, calc
.sThousand
, SIZEOF(calc
.sThousand
)))
260 _tcscpy(calc
.sThousand
, _T(","));
262 /* get the string lengths */
263 calc
.sDecimal_len
= _tcslen(calc
.sDecimal
);
264 calc
.sThousand_len
= _tcslen(calc
.sThousand
);
267 static int LoadRegInt(LPCTSTR lpszApp
, LPCTSTR lpszKey
, int iDefault
)
273 if (RegOpenKeyEx(HKEY_CURRENT_USER
, lpszApp
, 0, KEY_QUERY_VALUE
, &hKey
) == ERROR_SUCCESS
)
275 /* Try to load integer value */
278 if (RegQueryValueEx(hKey
, lpszKey
, NULL
, NULL
, (LPBYTE
)&iValue
, &tmp
) == ERROR_SUCCESS
)
288 static void SaveRegInt(LPCTSTR lpszApp
, LPCTSTR lpszKey
, int iValue
)
292 if (RegCreateKeyEx(HKEY_CURRENT_USER
, lpszApp
, 0, NULL
, REG_OPTION_NON_VOLATILE
, KEY_SET_VALUE
, NULL
, &hKey
, NULL
) == ERROR_SUCCESS
)
294 RegSetValueEx(hKey
, lpszKey
, 0, REG_DWORD
, (const BYTE
*)&iValue
, sizeof(int));
301 static void load_config(void)
305 osvi
.dwOSVersionInfoSize
= sizeof(osvi
);
308 switch (osvi
.dwPlatformId
) {
309 case VER_PLATFORM_WIN32s
:
310 case VER_PLATFORM_WIN32_WINDOWS
:
311 /* Try to load last selected layout */
312 calc
.layout
= GetProfileInt(_T("SciCalc"), _T("layout"), CALC_LAYOUT_STANDARD
);
314 /* Try to load last selected formatting option */
315 calc
.usesep
= (GetProfileInt(_T("SciCalc"), _T("UseSep"), FALSE
)) ? TRUE
: FALSE
;
318 default: /* VER_PLATFORM_WIN32_NT */
319 /* Try to load last selected layout */
320 calc
.layout
= LoadRegInt(_T("SOFTWARE\\Microsoft\\Calc"), _T("layout"), CALC_LAYOUT_STANDARD
);
322 /* Try to load last selected formatting option */
323 calc
.usesep
= (LoadRegInt(_T("SOFTWARE\\Microsoft\\Calc"), _T("UseSep"), FALSE
)) ? TRUE
: FALSE
;
327 /* memory is empty at startup */
328 calc
.is_memory
= FALSE
;
330 /* Get locale info for numbers */
334 static void save_config(void)
339 osvi
.dwOSVersionInfoSize
= sizeof(osvi
);
342 switch (osvi
.dwPlatformId
) {
343 case VER_PLATFORM_WIN32s
:
344 case VER_PLATFORM_WIN32_WINDOWS
:
345 _stprintf(buf
, _T("%lu"), calc
.layout
);
346 WriteProfileString(_T("SciCalc"), _T("layout"), buf
);
347 WriteProfileString(_T("SciCalc"), _T("UseSep"), (calc
.usesep
==TRUE
) ? _T("1") : _T("0"));
350 default: /* VER_PLATFORM_WIN32_NT */
351 SaveRegInt(_T("SOFTWARE\\Microsoft\\Calc"), _T("layout"), calc
.layout
);
352 SaveRegInt(_T("SOFTWARE\\Microsoft\\Calc"), _T("UseSep"), calc
.usesep
);
357 static LRESULT
post_key_press(LPARAM lParam
, WORD idc
)
359 HWND hCtlWnd
= GetDlgItem(calc
.hWnd
,idc
);
362 /* check if the key is enabled! */
363 if (!IsWindowEnabled(hCtlWnd
))
366 if (!GetClassName(hCtlWnd
, ClassName
, SIZEOF(ClassName
)))
369 if (!_tcscmp(ClassName
, WC_BUTTON
)) {
370 DWORD dwStyle
= GetWindowLongPtr(hCtlWnd
, GWL_STYLE
) & 0xF;
372 /* Set states for press/release, but only for push buttons */
373 if (dwStyle
== BS_PUSHBUTTON
|| dwStyle
== BS_DEFPUSHBUTTON
|| dwStyle
== BS_OWNERDRAW
) {
374 if (!(lParam
& KEY_WAS_DOWN
)) {
375 PostMessage(hCtlWnd
, BM_SETSTATE
, 1, 0);
377 if ((lParam
& KEY_IS_UP
)) {
378 PostMessage(hCtlWnd
, BM_SETSTATE
, 0, 0);
379 PostMessage(hCtlWnd
, BM_CLICK
, 0, 0);
384 /* default action: simple click event at key release */
385 if ((lParam
& KEY_IS_UP
)) {
386 PostMessage(hCtlWnd
, BM_CLICK
, 0, 0);
391 static int vk2ascii(unsigned int vk
)
393 unsigned short int s
;
396 HKL layout
=GetKeyboardLayout(0);
398 if(!GetKeyboardState(state
))
401 scan
=MapVirtualKeyEx(vk
, 0, layout
);
403 if (ToAsciiEx(vk
, scan
, state
, &s
, 0, layout
)>0) {
404 /* convert to upper case */
405 if (s
>= 'a' && s
<= 'z')
407 /* add check to CTRL key */
408 if (vk
>= 'A' && vk
<= 'Z' &&
409 s
>= CTRL_A
&& s
<= CTRL_Z
)
412 if (GetAsyncKeyState(VK_MENU
) < 0)
419 static int process_vk_key(WPARAM wParam
, LPARAM lParam
)
423 unsigned short int ch
;
425 ch
= vk2ascii(LOWORD(wParam
));
426 if ((lParam
& KEY_IS_UP
)) {
427 /* Test for "copy" to clipboard */
428 if (ch
== (CTRL_C
|CTRL_FLAG
)) {
429 SendMessage(calc
.hWnd
, WM_COMMAND
, IDM_EDIT_COPY
, 0);
432 /* Test for "paste" from clipboard */
433 if (ch
== (CTRL_V
|CTRL_FLAG
)) {
434 SendMessage(calc
.hWnd
, WM_COMMAND
, IDM_EDIT_PASTE
, 0);
437 /* Test of help menu */
438 if (LOWORD(wParam
) == VK_F1
) {
439 SendMessage(calc
.hWnd
, WM_COMMAND
, IDM_HELP_HELP
, 0);
444 for (x
=0; x
<SIZEOF(key2code
); x
++) {
445 int key
= key2code
[x
].key
;
446 if (key2code
[x
].mask
& BITMASK_IS_CTRL
)
448 if ((key
== ch
&& (key2code
[x
].mask
& BITMASK_IS_ASCII
)) ||
449 (key
== LOWORD(wParam
) && !(key2code
[x
].mask
& BITMASK_IS_ASCII
))
451 if (GetDlgItem(calc
.hWnd
, key2code
[x
].idc
) == NULL
)
453 return post_key_press(lParam
, key2code
[x
].idc
);
456 if (calc
.layout
== CALC_LAYOUT_SCIENTIFIC
) {
457 if (calc
.base
== IDC_RADIO_DEC
) {
459 x
= SIZEOF(key2code_base10
);
462 x
= SIZEOF(key2code_base16
);
465 if (k
->key
== LOWORD(wParam
)) {
466 return post_key_press(lParam
, k
->idc
);
474 #ifdef USE_KEYBOARD_HOOK
475 static LRESULT CALLBACK
476 KeyboardHookProc(int nCode
, WPARAM wParam
, LPARAM lParam
)
478 if(nCode
<0 || calc
.is_menu_on
)
479 return CallNextHookEx(calc
.hKeyboardHook
,nCode
,wParam
,lParam
);
482 if (process_vk_key(wParam
, lParam
))
485 return CallNextHookEx(calc
.hKeyboardHook
,nCode
,wParam
,lParam
);
489 static void update_lcd_display(HWND hwnd
)
492 * multiply size of calc.buffer by 2 because it may
493 * happen that separator is used between each digit.
494 * Also added little additional space for dot and '\0'.
496 TCHAR tmp
[MAX_CALC_SIZE
* 2 + 2];
498 if (calc
.buffer
[0] == _T('\0'))
499 _tcscpy(tmp
, _T("0"));
501 _tcscpy(tmp
, calc
.buffer
);
503 /* Add final '.' in decimal mode (if it's missing), but
504 * only if it's a result: no append if it prints "ERROR".
506 if (calc
.base
== IDC_RADIO_DEC
&& !calc
.is_nan
) {
507 if (_tcschr(tmp
, _T('.')) == NULL
)
508 _tcscat(tmp
, _T("."));
510 /* if separator mode is on, let's add an additional space */
511 if (calc
.usesep
&& !calc
.sci_in
&& !calc
.sci_out
&& !calc
.is_nan
) {
512 /* go to the integer part of the string */
513 TCHAR
*p
= _tcschr(tmp
, _T('.'));
514 TCHAR
*e
= _tcschr(tmp
, _T('\0'));
517 if (p
== NULL
) p
= e
;
531 if (++n
== t
&& *(p
-1) != _T('-')) {
532 memmove(p
+1, p
, (e
-p
+1)*sizeof(TCHAR
));
538 /* if decimal mode, apply regional settings */
539 if (calc
.base
== IDC_RADIO_DEC
) {
541 TCHAR
*e
= _tcschr(tmp
, _T('.'));
543 /* searching for thousands default separator */
546 memmove(p
+calc
.sThousand_len
, p
+1, _tcslen(p
)*sizeof(TCHAR
));
547 memcpy(p
, calc
.sThousand
, calc
.sThousand_len
*sizeof(TCHAR
));
548 p
+= calc
.sThousand_len
;
552 /* update decimal point too. */
553 memmove(p
+calc
.sDecimal_len
, p
+1, _tcslen(p
)*sizeof(TCHAR
));
554 memcpy(p
, calc
.sDecimal
, calc
.sDecimal_len
*sizeof(TCHAR
));
557 TCHAR
*p
= _tcschr(tmp
, _T('.'));
559 /* update decimal point when usesep is false */
561 memmove(p
+calc
.sDecimal_len
, p
+1, _tcslen(p
)*sizeof(TCHAR
));
562 memcpy(p
, calc
.sDecimal
, calc
.sDecimal_len
*sizeof(TCHAR
));
565 SetDlgItemText(hwnd
, IDC_TEXT_OUTPUT
, tmp
);
568 static void update_parent_display(HWND hWnd
)
571 int n
= eval_parent_count();
576 _stprintf(str
,_T("(=%d"), n
);
577 SetDlgItemText(hWnd
, IDC_TEXT_PARENT
, str
);
580 static void build_operand(HWND hwnd
, DWORD idc
)
582 unsigned int i
= 0, n
;
584 if (idc
== IDC_BUTTON_DOT
) {
585 /* if dot is the first char, it's added automatically */
586 if (calc
.buffer
== calc
.ptr
) {
587 *calc
.ptr
++ = _T('0');
588 *calc
.ptr
++ = _T('.');
589 *calc
.ptr
= _T('\0');
590 update_lcd_display(hwnd
);
593 /* if pressed dot and it's already in the string, then return */
594 if (_tcschr(calc
.buffer
, _T('.')) != NULL
)
597 if (idc
!= IDC_STATIC
) {
598 while (idc
!= key2code
[i
].idc
) i
++;
600 n
= calc
.ptr
- calc
.buffer
;
601 if (idc
== IDC_BUTTON_0
&& n
== 0) {
602 /* no need to put the dot because it's handled by update_lcd_display() */
603 calc
.buffer
[0] = _T('0');
604 calc
.buffer
[1] = _T('\0');
605 update_lcd_display(hwnd
);
614 if (n
>= SIZEOF(calc
.buffer
)-1)
617 if (idc
!= IDC_STATIC
)
618 calc
.esp
= (calc
.esp
* 10 + (key2code
[i
].key
-'0')) % LOCAL_EXP_SIZE
;
619 if (calc
.ptr
== calc
.buffer
)
620 _stprintf(calc
.ptr
, _T("0.e%+d"), calc
.esp
);
622 /* adds the dot at the end if the number has no decimal part */
623 if (!_tcschr(calc
.buffer
, _T('.')))
624 *calc
.ptr
++ = _T('.');
625 _stprintf(calc
.ptr
, _T("e%+d"), calc
.esp
);
627 update_lcd_display(hwnd
);
640 calc
.ptr
+= _stprintf(calc
.ptr
, _T("%C"), key2code
[i
].key
);
641 update_lcd_display(hwnd
);
644 static void prepare_rpn_result(calc_number_t
*rpn
, TCHAR
*buffer
, int size
, int base
)
647 rpn_zero(&calc
.code
);
648 LoadString(calc
.hInstance
, IDS_MATH_ERROR
, buffer
, size
);
651 prepare_rpn_result_2(rpn
, buffer
, size
, base
);
654 static void set_rpn_result(HWND hwnd
, calc_number_t
*rpn
)
657 prepare_rpn_result(rpn
, calc
.buffer
, SIZEOF(calc
.buffer
), calc
.base
);
658 calc
.ptr
= calc
.buffer
+ _tcslen(calc
.buffer
);
659 update_lcd_display(hwnd
);
660 update_parent_display(hwnd
);
663 static void display_rpn_result(HWND hwnd
, calc_number_t
*rpn
)
665 set_rpn_result(hwnd
, rpn
);
666 calc
.ptr
= calc
.buffer
;
669 static int get_modifiers(HWND hWnd
)
673 if (IsDlgButtonChecked(hWnd
, IDC_CHECK_INV
) == BST_CHECKED
)
674 modifiers
|= MODIFIER_INV
;
675 if (IsDlgButtonChecked(hWnd
, IDC_CHECK_HYP
) == BST_CHECKED
)
676 modifiers
|= MODIFIER_HYP
;
681 static void convert_text2number(calc_number_t
*a
)
683 /* if the screen output buffer is empty, then */
684 /* the operand is taken from the last input */
685 if (calc
.buffer
== calc
.ptr
) {
686 /* if pushed valued is ZERO then we should grab it */
687 if (!_tcscmp(calc
.buffer
, _T("0.")) ||
688 !_tcscmp(calc
.buffer
, _T("0")))
689 /* this zero is good for both integer and decimal */
692 rpn_copy(a
, &calc
.code
);
695 /* ZERO is the default value for all numeric bases */
697 convert_text2number_2(a
);
700 static const struct _update_check_menus
{
705 { &calc
.layout
, IDM_VIEW_STANDARD
, CALC_LAYOUT_STANDARD
},
706 { &calc
.layout
, IDM_VIEW_SCIENTIFIC
, CALC_LAYOUT_SCIENTIFIC
},
707 { &calc
.layout
, IDM_VIEW_CONVERSION
, CALC_LAYOUT_CONVERSION
},
708 /*-----------------------------------------*/
709 { &calc
.base
, IDM_VIEW_HEX
, IDC_RADIO_HEX
, },
710 { &calc
.base
, IDM_VIEW_DEC
, IDC_RADIO_DEC
, },
711 { &calc
.base
, IDM_VIEW_OCT
, IDC_RADIO_OCT
, },
712 { &calc
.base
, IDM_VIEW_BIN
, IDC_RADIO_BIN
, },
713 /*-----------------------------------------*/
714 { &calc
.degr
, IDM_VIEW_DEG
, IDC_RADIO_DEG
, },
715 { &calc
.degr
, IDM_VIEW_RAD
, IDC_RADIO_RAD
, },
716 { &calc
.degr
, IDM_VIEW_GRAD
, IDC_RADIO_GRAD
, },
717 /*-----------------------------------------*/
718 { &calc
.size
, IDM_VIEW_QWORD
, IDC_RADIO_QWORD
, },
719 { &calc
.size
, IDM_VIEW_DWORD
, IDC_RADIO_DWORD
, },
720 { &calc
.size
, IDM_VIEW_WORD
, IDC_RADIO_WORD
, },
721 { &calc
.size
, IDM_VIEW_BYTE
, IDC_RADIO_BYTE
, },
724 static void update_menu(HWND hWnd
)
726 HMENU hMenu
= GetSubMenu(GetMenu(hWnd
), 1);
729 for (x
=0; x
<SIZEOF(upd
); x
++) {
730 if (*(upd
[x
].sel
) != upd
[x
].idc
) {
731 CheckMenuItem(hMenu
, upd
[x
].idm
, MF_BYCOMMAND
|MF_UNCHECKED
);
732 CheckDlgButton(hWnd
, upd
[x
].idc
, BST_UNCHECKED
);
734 CheckMenuItem(hMenu
, upd
[x
].idm
, MF_BYCOMMAND
|MF_CHECKED
);
735 CheckDlgButton(hWnd
, upd
[x
].idc
, BST_CHECKED
);
738 CheckMenuItem(hMenu
, IDM_VIEW_GROUP
, MF_BYCOMMAND
|(calc
.usesep
? MF_CHECKED
: MF_UNCHECKED
));
746 static const radio_config_t radio_setup
[] = {
747 /* CONTROL-ID hex dec oct bin */
748 { IDC_RADIO_QWORD
, MAKE_BITMASK4( 1, 0, 1, 1) },
749 { IDC_RADIO_DWORD
, MAKE_BITMASK4( 1, 0, 1, 1) },
750 { IDC_RADIO_WORD
, MAKE_BITMASK4( 1, 0, 1, 1) },
751 { IDC_RADIO_BYTE
, MAKE_BITMASK4( 1, 0, 1, 1) },
752 { IDC_RADIO_DEG
, MAKE_BITMASK4( 0, 1, 0, 0) },
753 { IDC_RADIO_RAD
, MAKE_BITMASK4( 0, 1, 0, 0) },
754 { IDC_RADIO_GRAD
, MAKE_BITMASK4( 0, 1, 0, 0) },
757 static void enable_allowed_controls(HWND hwnd
, DWORD base
)
764 mask
= BITMASK_DEC_MASK
;
767 mask
= BITMASK_HEX_MASK
;
770 mask
= BITMASK_OCT_MASK
;
773 mask
= BITMASK_BIN_MASK
;
778 for (n
=0; n
<SIZEOF(key2code
); n
++) {
779 if (key2code
[n
].mask
!= 0) {
780 HWND hCtlWnd
= GetDlgItem(hwnd
, key2code
[n
].idc
);
783 if ((key2code
[n
].mask
& BITMASK_IS_STATS
))
784 current
= IsWindow(calc
.hStatWnd
) ? TRUE
: FALSE
;
786 current
= (key2code
[n
].mask
& mask
) ? TRUE
: FALSE
;
787 if (IsWindowEnabled(hCtlWnd
) != current
)
788 EnableWindow(hCtlWnd
, current
);
793 static void update_radio(HWND hwnd
, unsigned int base
)
802 lpMenuId
= MAKEINTRESOURCE(IDR_MENU_SCIENTIFIC_1
);
803 mask
= BITMASK_DEC_MASK
;
806 lpMenuId
= MAKEINTRESOURCE(IDR_MENU_SCIENTIFIC_2
);
807 mask
= BITMASK_HEX_MASK
;
810 lpMenuId
= MAKEINTRESOURCE(IDR_MENU_SCIENTIFIC_2
);
811 mask
= BITMASK_OCT_MASK
;
814 lpMenuId
= MAKEINTRESOURCE(IDR_MENU_SCIENTIFIC_2
);
815 mask
= BITMASK_BIN_MASK
;
821 if (calc
.base
!= base
) {
822 convert_text2number(&calc
.code
);
823 convert_real_integer(base
);
825 display_rpn_result(hwnd
, &calc
.code
);
827 hMenu
= GetMenu(hwnd
);
829 hMenu
= LoadMenu(calc
.hInstance
, lpMenuId
);
830 SetMenu(hwnd
, hMenu
);
833 for (n
=0; n
<SIZEOF(radio_setup
); n
++)
834 ShowWindow(GetDlgItem(hwnd
, radio_setup
[n
].idc
), (radio_setup
[n
].mask
& mask
) ? SW_SHOW
: SW_HIDE
);
836 enable_allowed_controls(hwnd
, base
);
839 CheckRadioButton(hwnd
, IDC_RADIO_HEX
, IDC_RADIO_BIN
, calc
.base
);
841 if (base
== IDC_RADIO_DEC
)
842 CheckRadioButton(hwnd
, IDC_RADIO_DEG
, IDC_RADIO_GRAD
, calc
.degr
);
844 CheckRadioButton(hwnd
, IDC_RADIO_QWORD
, IDC_RADIO_BYTE
, calc
.size
);
847 static void update_memory_flag(HWND hWnd
, BOOL mem_flag
)
849 calc
.is_memory
= mem_flag
;
850 SetDlgItemText(hWnd
, IDC_TEXT_MEMORY
, mem_flag
? _T("M") : _T(""));
853 static void update_n_stats_items(HWND hWnd
, TCHAR
*buffer
)
855 unsigned int n
= SendDlgItemMessage(hWnd
, IDC_LIST_STAT
, LB_GETCOUNT
, 0, 0);
857 _stprintf(buffer
, _T("n=%u"), n
);
858 SetDlgItemText(hWnd
, IDC_TEXT_NITEMS
, buffer
);
861 static void clean_stat_list(void)
863 statistic_t
*p
= calc
.stat
;
867 p
= (statistic_t
*)(p
->next
);
874 static void delete_stat_item(int n
)
876 statistic_t
*p
= calc
.stat
;
880 calc
.stat
= (statistic_t
*)p
->next
;
884 s
= (statistic_t
*)p
->next
;
887 s
= (statistic_t
*)p
->next
;
895 static char *ReadConversion(const char *formula
)
897 size_t len
= strlen(formula
);
898 char *str
= (char *)malloc(len
+3);
904 memcpy(str
+1, formula
, len
);
908 _tcscpy(calc
.source
, (*calc
.buffer
== _T('\0')) ? _T("0") : calc
.buffer
);
910 /* clear display content before proceeding */
911 calc
.ptr
= calc
.buffer
;
912 calc
.buffer
[0] = _T('\0');
917 static INT_PTR CALLBACK
DlgStatProc(HWND hWnd
, UINT msg
, WPARAM wp
, LPARAM lp
)
919 TCHAR buffer
[SIZEOF(calc
.buffer
)];
926 switch (LOWORD(wp
)) {
928 if (HIWORD(wp
) == CBN_DBLCLK
)
929 SendMessage(hWnd
, WM_COMMAND
, (WPARAM
)IDC_BUTTON_LOAD
, 0);
932 SetFocus(GetDlgItem(GetParent(hWnd
), IDC_BUTTON_FOCUS
));
934 case IDC_BUTTON_LOAD
:
935 n
= SendDlgItemMessage(hWnd
, IDC_LIST_STAT
, LB_GETCURSEL
, 0, 0);
938 PostMessage(GetParent(hWnd
), WM_LOAD_STAT
, (WPARAM
)n
, 0);
941 n
= SendDlgItemMessage(hWnd
, IDC_LIST_STAT
, LB_GETCURSEL
, 0, 0);
944 SendDlgItemMessage(hWnd
, IDC_LIST_STAT
, LB_DELETESTRING
, (WPARAM
)n
, 0);
945 update_n_stats_items(hWnd
, buffer
);
949 SendDlgItemMessage(hWnd
, IDC_LIST_STAT
, LB_RESETCONTENT
, 0, 0);
951 update_n_stats_items(hWnd
, buffer
);
960 PostMessage(GetParent(hWnd
), WM_CLOSE_STATS
, 0, 0);
963 prepare_rpn_result(&(((statistic_t
*)lp
)->num
),
964 buffer
, SIZEOF(buffer
),
965 ((statistic_t
*)lp
)->base
);
966 SendDlgItemMessage(hWnd
, IDC_LIST_STAT
, LB_ADDSTRING
, 0, (LPARAM
)buffer
);
967 update_n_stats_items(hWnd
, buffer
);
973 static WPARAM
idm_2_idc(int idm
)
977 for (x
=0; x
<SIZEOF(upd
); x
++) {
978 if (upd
[x
].idm
== idm
)
981 return (WPARAM
)(upd
[x
].idc
);
984 static void CopyMemToClipboard(void *ptr
)
986 if(OpenClipboard(NULL
)) {
991 clipbuffer
= GlobalAlloc(GMEM_DDESHARE
, (_tcslen(ptr
)+1)*sizeof(TCHAR
));
992 buffer
= (TCHAR
*)GlobalLock(clipbuffer
);
993 _tcscpy(buffer
, ptr
);
994 GlobalUnlock(clipbuffer
);
996 SetClipboardData(CF_UNICODETEXT
,clipbuffer
);
998 SetClipboardData(CF_TEXT
,clipbuffer
);
1004 static void handle_copy_command(HWND hWnd
)
1006 TCHAR display
[MAX_CALC_SIZE
];
1009 n
= GetDlgItemText(hWnd
, IDC_TEXT_OUTPUT
, display
, SIZEOF(display
));
1011 if (calc
.base
== IDC_RADIO_DEC
&& _tcschr(calc
.buffer
, _T('.')) == NULL
)
1012 display
[n
- calc
.sDecimal_len
] = _T('\0');
1014 CopyMemToClipboard(display
);
1017 static char *ReadClipboard(void)
1019 char *buffer
= NULL
;
1021 if (OpenClipboard(NULL
)) {
1022 HANDLE hData
= GetClipboardData(CF_TEXT
);
1023 char *fromClipboard
;
1025 if (hData
!= NULL
) {
1026 fromClipboard
= (char *)GlobalLock(hData
);
1027 if (fromClipboard
[0])
1028 buffer
= _strupr(_strdup(fromClipboard
));
1029 GlobalUnlock( hData
);
1036 static char *handle_sequence_input(HWND hwnd
, sequence_t
*seq
)
1038 char *ptr
= seq
->ptr
;
1043 PostMessage(hwnd
, WM_COMMAND
, (WPARAM
)IDC_BUTTON_DAT
, 0);
1050 case 'C': PostMessage(hwnd
, WM_COMMAND
, (WPARAM
)IDC_BUTTON_MC
, 0); break;
1051 case 'E': PostMessage(hwnd
, WM_COMMAND
, (WPARAM
)IDC_BUTTON_EXP
,0); break;
1052 case 'M': PostMessage(hwnd
, WM_COMMAND
, (WPARAM
)IDC_BUTTON_MS
, 0); break;
1053 case 'P': PostMessage(hwnd
, WM_COMMAND
, (WPARAM
)IDC_BUTTON_MP
, 0); break;
1054 case 'Q': PostMessage(hwnd
, WM_COMMAND
, (WPARAM
)IDC_BUTTON_CANC
, 0); break;
1055 case 'R': PostMessage(hwnd
, WM_COMMAND
, (WPARAM
)IDC_BUTTON_MR
, 0); break;
1060 _tcscpy(calc
.buffer
, calc
.source
) +
1061 _tcslen(calc
.source
);
1063 for (x
=0; x
<SIZEOF(key2code
); x
++) {
1064 if (!(key2code
[x
].mask
& BITMASK_IS_ASCII
) ||
1065 (key2code
[x
].mask
& BITMASK_IS_CTRL
))
1067 if (key2code
[x
].key
== ch
) {
1068 PostMessage(hwnd
, WM_COMMAND
, (WPARAM
)key2code
[x
].idc
, 0);
1077 PostMessage(hwnd
, seq
->wm_msg
, 0, 0);
1080 seq
->data
= seq
->ptr
= ptr
= NULL
;
1085 static void run_dat_sta(calc_number_t
*a
)
1087 statistic_t
*s
= (statistic_t
*)malloc(sizeof(statistic_t
));
1088 statistic_t
*p
= calc
.stat
;
1091 rpn_copy(&s
->num
, a
);
1092 s
->base
= calc
.base
;
1097 while (p
->next
!= NULL
)
1098 p
= (statistic_t
*)(p
->next
);
1101 PostMessage(calc
.hStatWnd
, WM_INSERT_STAT
, 0, (LPARAM
)s
);
1104 static void run_mp(calc_number_t
*c
)
1109 cn
.base
= calc
.base
;
1110 run_operator(&calc
.memory
, &calc
.memory
, &cn
, RPN_OPERATOR_ADD
);
1111 update_memory_flag(calc
.hWnd
, TRUE
);
1114 static void run_mm(calc_number_t
*c
)
1119 cn
.base
= calc
.base
;
1120 run_operator(&calc
.memory
, &calc
.memory
, &cn
, RPN_OPERATOR_SUB
);
1121 update_memory_flag(calc
.hWnd
, TRUE
);
1124 static void run_ms(calc_number_t
*c
)
1126 rpn_copy(&calc
.memory
.number
, c
);
1127 calc
.memory
.base
= calc
.base
;
1128 update_memory_flag(calc
.hWnd
, rpn_is_zero(&calc
.memory
.number
) ? FALSE
: TRUE
);
1131 static void run_mw(calc_number_t
*c
)
1135 rpn_copy(&tmp
, &calc
.memory
.number
);
1136 rpn_copy(&calc
.memory
.number
, c
);
1137 calc
.memory
.base
= calc
.base
;
1140 update_memory_flag(calc
.hWnd
, rpn_is_zero(&calc
.memory
.number
) ? FALSE
: TRUE
);
1143 static statistic_t
*upload_stat_number(int n
)
1145 statistic_t
*p
= calc
.stat
;
1151 p
= (statistic_t
*)(p
->next
);
1156 #ifndef ENABLE_MULTI_PRECISION
1157 if (calc
.base
!= p
->base
) {
1158 if (calc
.base
== IDC_RADIO_DEC
)
1159 calc
.code
.f
= (double)p
->num
.i
;
1161 calc
.code
.i
= (__int64
)p
->num
.f
;
1162 apply_int_mask(&calc
.code
);
1166 rpn_copy(&calc
.code
, &p
->num
);
1168 calc
.is_nan
= FALSE
;
1173 static void run_fe(calc_number_t
*number
)
1175 calc
.sci_out
= ((calc
.sci_out
!= FALSE
) ? FALSE
: TRUE
);
1178 static void handle_context_menu(HWND hWnd
, WPARAM wp
, LPARAM lp
)
1181 HMENU hMenu
= CreatePopupMenu();
1184 LoadString(calc
.hInstance
, IDS_QUICKHELP
, text
, SIZEOF(text
));
1185 AppendMenu(hMenu
, MF_STRING
| MF_ENABLED
, IDM_HELP_HELP
, text
);
1186 idm
= TrackPopupMenu( hMenu
,
1187 TPM_LEFTALIGN
| TPM_TOPALIGN
| TPM_RETURNCMD
| TPM_RIGHTBUTTON
,
1194 #ifndef DISABLE_HTMLHELP_SUPPORT
1198 memset(&popup
, 0, sizeof(popup
));
1199 popup
.cbStruct
= sizeof(HH_POPUP
);
1200 popup
.clrForeground
= 1;
1201 popup
.clrBackground
= -1;
1202 popup
.pt
.x
= LOWORD(lp
);
1203 popup
.pt
.y
= HIWORD(lp
);
1204 popup
.rcMargins
.top
= -1;
1205 popup
.rcMargins
.bottom
= -1;
1206 popup
.rcMargins
.left
= -1;
1207 popup
.rcMargins
.right
= -1;
1208 popup
.idString
= GetWindowLongPtr((HWND
)wp
, GWL_ID
);
1209 calc_HtmlHelp((HWND
)wp
, HTMLHELP_PATH("/popups.txt"), HH_DISPLAY_TEXT_POPUP
, (DWORD_PTR
)&popup
);
1216 static void run_canc(calc_number_t
*c
)
1221 /* clear also scientific display modes */
1222 calc
.sci_out
= FALSE
;
1223 calc
.sci_in
= FALSE
;
1225 /* clear state of inv and hyp flags */
1226 CheckDlgButton(calc
.hWnd
, IDC_CHECK_INV
, BST_UNCHECKED
);
1227 CheckDlgButton(calc
.hWnd
, IDC_CHECK_HYP
, BST_UNCHECKED
);
1230 static void run_rpar(calc_number_t
*c
)
1232 exec_closeparent(c
);
1235 static void run_lpar(calc_number_t
*c
)
1237 exec_infix2postfix(c
, RPN_OPERATOR_PARENT
);
1240 static LRESULT CALLBACK
SubclassButtonProc(HWND hWnd
, WPARAM wp
, LPARAM lp
)
1242 LPDRAWITEMSTRUCT dis
= (LPDRAWITEMSTRUCT
)lp
;
1249 if(dis
->CtlType
== ODT_BUTTON
)
1251 HTHEME hTheme
= NULL
;
1252 LPBTNINFO lpBtnInfo
;
1254 if (calc_IsAppThemed() && calc_IsThemeActive())
1255 hTheme
= calc_OpenThemeData(hWnd
, L
"Button");
1261 if ((dis
->itemState
& ODS_DISABLED
))
1262 iState
|= PBS_DISABLED
;
1263 if ((dis
->itemState
& ODS_SELECTED
))
1264 iState
|= PBS_PRESSED
;
1266 lpBtnInfo
= (LPBTNINFO
)GetWindowLongPtr(dis
->hwndItem
, GWLP_USERDATA
);
1267 if (lpBtnInfo
!= NULL
)
1269 if (lpBtnInfo
->bHover
)
1273 if (calc_IsThemeBackgroundPartiallyTransparent(hTheme
, BP_PUSHBUTTON
, iState
))
1275 calc_DrawThemeParentBackground(dis
->hwndItem
, dis
->hDC
, &dis
->rcItem
);
1278 // Draw the frame around the control
1279 calc_DrawThemeBackground(hTheme
, dis
->hDC
, BP_PUSHBUTTON
, iState
, &dis
->rcItem
, NULL
);
1281 calc_CloseThemeData(hTheme
);
1283 /* default state: unpushed */
1286 if ((dis
->itemState
& ODS_SELECTED
))
1287 dwStyle
= DFCS_PUSHED
;
1289 DrawFrameControl(dis
->hDC
, &dis
->rcItem
, DFC_BUTTON
, DFCS_BUTTONPUSH
| dwStyle
);
1292 /* button text to write */
1293 len
= GetWindowText(dis
->hwndItem
, text
, SIZEOF(text
));
1296 * little exception: 1/x has different color
1297 * in standard and scientific modes
1299 if ((calc
.layout
== CALC_LAYOUT_STANDARD
||
1300 calc
.layout
== CALC_LAYOUT_CONVERSION
) &&
1301 IDC_BUTTON_RX
== dis
->CtlID
) {
1302 SetTextColor(dis
->hDC
, CALC_CLR_BLUE
);
1304 for (dx
=0; dx
<SIZEOF(key2code
); dx
++) {
1305 if (key2code
[dx
].idc
== dis
->CtlID
) {
1306 SetTextColor(dis
->hDC
, key2code
[dx
].col
);
1311 /* No background, to avoid corruption of the texture */
1312 SetBkMode(dis
->hDC
, TRANSPARENT
);
1314 /* Default state: enabled */
1316 if ((dis
->itemState
& ODS_DISABLED
))
1317 dwText
= DSS_DISABLED
;
1319 /* Draw the text in the button */
1320 GetTextExtentPoint32(dis
->hDC
, text
, len
, &size
);
1321 dx
= ((dis
->rcItem
.right
-dis
->rcItem
.left
) - size
.cx
) >> 1;
1322 dy
= ((dis
->rcItem
.bottom
-dis
->rcItem
.top
) - size
.cy
) >> 1;
1323 if ((dis
->itemState
& ODS_SELECTED
)) {
1327 pt
.x
= dis
->rcItem
.left
+ dx
;
1328 pt
.y
= dis
->rcItem
.top
+ dy
;
1329 DrawState(dis
->hDC
, NULL
, NULL
, (LPARAM
)text
, 0, pt
.x
, pt
.y
, size
.cx
, size
.cy
, DST_TEXT
| dwText
);
1334 static INT_PTR CALLBACK
HotButtonProc(HWND hWnd
, UINT msg
, WPARAM wp
, LPARAM lp
)
1336 LPBTNINFO lpBtnInfo
= (LPBTNINFO
)GetWindowLongPtr(hWnd
, GWLP_USERDATA
);
1337 TRACKMOUSEEVENT mouse_event
;
1341 mouse_event
.cbSize
= sizeof(TRACKMOUSEEVENT
);
1342 mouse_event
.dwFlags
= TME_QUERY
;
1343 if (!TrackMouseEvent(&mouse_event
) || !(mouse_event
.dwFlags
& (TME_HOVER
|TME_LEAVE
)))
1345 mouse_event
.dwFlags
= TME_HOVER
|TME_LEAVE
;
1346 mouse_event
.hwndTrack
= hWnd
;
1347 mouse_event
.dwHoverTime
= 1;
1348 TrackMouseEvent(&mouse_event
);
1353 lpBtnInfo
->bHover
= TRUE
;
1354 InvalidateRect(hWnd
, NULL
, FALSE
);
1358 lpBtnInfo
->bHover
= FALSE
;
1359 InvalidateRect(hWnd
, NULL
, FALSE
);
1363 return CallWindowProc(lpBtnInfo
->oldProc
, hWnd
, msg
, wp
, lp
);
1366 static BOOL CALLBACK
EnumChildProc(HWND hWnd
, LPARAM lParam
)
1370 if (!GetClassName(hWnd
, szClass
, SIZEOF(szClass
)))
1373 if (!_tcscmp(szClass
, WC_BUTTON
))
1375 int *pnCtrls
= (int *)lParam
;
1376 int nCtrls
= *pnCtrls
;
1378 BtnInfo
[nCtrls
].oldProc
= (WNDPROC
)GetWindowLongPtr(hWnd
, GWLP_WNDPROC
);
1379 BtnInfo
[nCtrls
].bHover
= FALSE
;
1381 SetWindowLongPtr(hWnd
, GWLP_USERDATA
, (LONG_PTR
)&BtnInfo
[nCtrls
]);
1382 SetWindowLongPtr(hWnd
, GWLP_WNDPROC
, (LONG_PTR
)HotButtonProc
);
1384 *pnCtrls
= ++nCtrls
;
1389 static INT_PTR CALLBACK
OnSettingChange(HWND hWnd
, WPARAM wParam
, LPARAM lParam
)
1391 /* Check for user policy and area string valid */
1392 if (wParam
== 0 && lParam
!= 0)
1394 LPTSTR lpArea
= (LPTSTR
)lParam
;
1396 /* Check if a parameter has been changed into the locale settings */
1397 if (!_tcsicmp(lpArea
, _T("intl")))
1399 /* Re-load locale parameters */
1402 /* Update text for decimal button */
1403 SetDlgItemText(hWnd
, IDC_BUTTON_DOT
, calc
.sDecimal
);
1405 /* Update text into the output display */
1406 update_lcd_display(hWnd
);
1412 static INT_PTR CALLBACK
DlgMainProc(HWND hWnd
, UINT msg
, WPARAM wp
, LPARAM lp
)
1419 return SubclassButtonProc(hWnd
, wp
, lp
);
1422 #ifdef DISABLE_HTMLHELP_SUPPORT
1423 EnableMenuItem(GetMenu(hWnd
), IDM_HELP_HELP
, MF_BYCOMMAND
| MF_GRAYED
);
1426 /* Enumerate children and apply hover function */
1428 EnumChildWindows(hWnd
, EnumChildProc
, (LPARAM
)&BtnCount
);
1430 #ifdef USE_KEYBOARD_HOOK
1431 calc
.hKeyboardHook
=SetWindowsHookEx(
1435 GetCurrentThreadId()
1438 rpn_zero(&calc
.code
);
1439 calc
.sci_out
= FALSE
;
1440 calc
.base
= IDC_RADIO_DEC
;
1441 calc
.size
= IDC_RADIO_QWORD
;
1442 calc
.degr
= IDC_RADIO_DEG
;
1443 calc
.ptr
= calc
.buffer
;
1444 calc
.is_nan
= FALSE
;
1445 enable_allowed_controls(hWnd
, IDC_RADIO_DEC
);
1446 update_radio(hWnd
, IDC_RADIO_DEC
);
1448 display_rpn_result(hWnd
, &calc
.code
);
1449 update_memory_flag(hWnd
, calc
.is_memory
);
1450 /* remove keyboard focus */
1451 SetFocus(GetDlgItem(hWnd
, IDC_BUTTON_FOCUS
));
1452 /* set our calc icon */
1453 SendMessage(hWnd
, WM_SETICON
, ICON_BIG
, (LPARAM
)calc
.hBgIcon
);
1454 SendMessage(hWnd
, WM_SETICON
, ICON_SMALL
, (LPARAM
)calc
.hSmIcon
);
1455 /* update text for decimal button */
1456 SetDlgItemText(hWnd
, IDC_BUTTON_DOT
, calc
.sDecimal
);
1457 /* Fill combo box for conversion */
1458 if (calc
.layout
== CALC_LAYOUT_CONVERSION
)
1460 /* Restore the window at the same position it was */
1461 if (calc
.x_coord
>= 0 && calc
.y_coord
>= 0) {
1464 GetWindowRect(hWnd
, &rc
);
1465 w
= rc
.right
-rc
.left
;
1466 h
= rc
.bottom
-rc
.top
;
1467 sw
= GetSystemMetrics(SM_CXSCREEN
);
1468 sh
= GetSystemMetrics(SM_CYSCREEN
);
1469 if (calc
.x_coord
+w
> sw
) calc
.x_coord
= sw
- w
;
1470 if (calc
.y_coord
+h
> sh
) calc
.y_coord
= sh
- h
;
1471 MoveWindow(hWnd
, calc
.x_coord
, calc
.y_coord
, w
, h
, FALSE
);
1474 case WM_CTLCOLORSTATIC
:
1475 if ((HWND
)lp
== GetDlgItem(hWnd
, IDC_TEXT_OUTPUT
))
1476 return (LRESULT
)GetStockObject(WHITE_BRUSH
);
1478 case WM_HANDLE_CLIPBOARD
:
1479 handle_sequence_input(hWnd
, &calc
.Clipboard
);
1483 * if selection of category is changed, we must
1484 * update the content of the "from/to" combo boxes.
1486 if (wp
== MAKEWPARAM(IDC_COMBO_CATEGORY
, CBN_SELCHANGE
)) {
1487 ConvAdjust(hWnd
, SendDlgItemMessage(hWnd
, IDC_COMBO_CATEGORY
, CB_GETCURSEL
, 0, 0));
1490 if (HIWORD(wp
) != BN_CLICKED
&& HIWORD(wp
) != BN_DBLCLK
)
1492 /* avoid flicker if the user selects from keyboard */
1493 if (GetFocus() != GetDlgItem(hWnd
, IDC_BUTTON_FOCUS
))
1494 SetFocus(GetDlgItem(hWnd
, IDC_BUTTON_FOCUS
));
1495 switch (LOWORD(wp
)) {
1496 case IDM_HELP_ABOUT
:
1498 TCHAR infotitle
[100];
1499 TCHAR infotext
[200];
1500 LoadString(calc
.hInstance
, IDS_CALC_NAME
, infotitle
, SIZEOF(infotitle
));
1501 LoadString(calc
.hInstance
, IDS_AUTHOR
, infotext
, SIZEOF(infotext
));
1502 ShellAbout(hWnd
, infotitle
, infotext
, calc
.hBgIcon
);
1506 #ifndef DISABLE_HTMLHELP_SUPPORT
1507 calc_HtmlHelp(hWnd
, HTMLHELP_PATH("/general_information.htm"), HH_DISPLAY_TOPIC
, (DWORD_PTR
)NULL
);
1510 case IDM_VIEW_STANDARD
:
1511 calc
.layout
= CALC_LAYOUT_STANDARD
;
1512 calc
.action
= IDM_VIEW_STANDARD
;
1513 DestroyWindow(hWnd
);
1515 case IDM_VIEW_SCIENTIFIC
:
1516 calc
.layout
= CALC_LAYOUT_SCIENTIFIC
;
1517 calc
.action
= IDM_VIEW_SCIENTIFIC
;
1518 DestroyWindow(hWnd
);
1520 case IDM_VIEW_CONVERSION
:
1521 calc
.layout
= CALC_LAYOUT_CONVERSION
;
1522 calc
.action
= IDM_VIEW_CONVERSION
;
1523 DestroyWindow(hWnd
);
1532 case IDM_VIEW_QWORD
:
1533 case IDM_VIEW_DWORD
:
1536 SendMessage(hWnd
, WM_COMMAND
, idm_2_idc(LOWORD(wp
)), 0);
1539 handle_copy_command(hWnd
);
1541 case IDM_EDIT_PASTE
:
1542 if (calc
.Clipboard
.data
!= NULL
)
1544 calc
.Clipboard
.data
= ReadClipboard();
1545 if (calc
.Clipboard
.data
!= NULL
) {
1546 /* clear the content of the display before pasting */
1547 PostMessage(hWnd
, WM_COMMAND
, IDC_BUTTON_CE
, 0);
1548 calc
.Clipboard
.ptr
= calc
.Clipboard
.data
;
1549 calc
.Clipboard
.wm_msg
= WM_HANDLE_CLIPBOARD
;
1550 handle_sequence_input(hWnd
, &calc
.Clipboard
);
1553 case IDM_VIEW_GROUP
:
1554 calc
.usesep
= (calc
.usesep
? FALSE
: TRUE
);
1556 update_lcd_display(hWnd
);
1558 case IDC_BUTTON_CONVERT
:
1561 case IDC_BUTTON_CE
: {
1564 display_rpn_result(hWnd
, &tmp
);
1571 /* GNU WINDRES is bugged so I must always force radio update */
1572 /* (Fix for Win95/98) */
1574 if (calc
.base
== LOWORD(wp
))
1577 calc
.is_nan
= FALSE
;
1578 update_radio(hWnd
, LOWORD(wp
));
1582 case IDC_RADIO_GRAD
:
1583 /* GNU WINDRES is bugged so I must always force radio update */
1584 /* (Fix for Win95/98) */
1586 if (calc
.degr
== LOWORD(wp
))
1589 calc
.degr
= LOWORD(wp
);
1590 calc
.is_nan
= FALSE
;
1593 case IDC_RADIO_QWORD
:
1594 case IDC_RADIO_DWORD
:
1595 case IDC_RADIO_WORD
:
1596 case IDC_RADIO_BYTE
:
1597 /* GNU WINDRES is bugged so I must always force radio update */
1598 /* (Fix for Win95/98) */
1600 if (calc
.size
== LOWORD(wp
))
1603 calc
.size
= LOWORD(wp
);
1604 calc
.is_nan
= FALSE
;
1607 * update the content of the display
1609 convert_text2number(&calc
.code
);
1610 apply_int_mask(&calc
.code
);
1611 display_rpn_result(hWnd
, &calc
.code
);
1623 case IDC_BUTTON_DOT
:
1630 calc
.is_nan
= FALSE
;
1631 build_operand(hWnd
, LOWORD(wp
));
1633 case IDC_BUTTON_PERCENT
:
1634 case IDC_BUTTON_ADD
:
1635 case IDC_BUTTON_SUB
:
1636 case IDC_BUTTON_MULT
:
1637 case IDC_BUTTON_DIV
:
1638 case IDC_BUTTON_MOD
:
1639 case IDC_BUTTON_AND
:
1641 case IDC_BUTTON_XOR
:
1642 case IDC_BUTTON_LSH
:
1643 case IDC_BUTTON_RSH
:
1644 case IDC_BUTTON_EQU
:
1645 case IDC_BUTTON_XeY
:
1646 case IDC_BUTTON_XrY
:
1647 if (calc
.is_nan
) break;
1649 * LSH and XeY buttons hold also the RSH and XrY functions with INV modifier,
1650 * but since they are two operand operators, they must be handled here.
1652 if ((get_modifiers(hWnd
) & MODIFIER_INV
))
1654 WPARAM IdcSim
= IDC_STATIC
;
1656 switch (LOWORD(wp
)) {
1657 case IDC_BUTTON_LSH
: IdcSim
= MAKEWPARAM(IDC_BUTTON_RSH
, BN_CLICKED
); break;
1658 case IDC_BUTTON_XeY
: IdcSim
= MAKEWPARAM(IDC_BUTTON_XrY
, BN_CLICKED
); break;
1661 if (IdcSim
!= IDC_STATIC
)
1663 PostMessage(hWnd
, WM_COMMAND
, IdcSim
, 0);
1664 CheckDlgButton(hWnd
, IDC_CHECK_INV
, BST_UNCHECKED
);
1669 for (x
=0; x
<SIZEOF(operator_codes
); x
++) {
1670 if (LOWORD(wp
) == operator_codes
[x
]) {
1671 convert_text2number(&calc
.code
);
1673 if (calc
.ptr
== calc
.buffer
) {
1674 if (calc
.last_operator
!= x
) {
1675 if (x
!= RPN_OPERATOR_EQUAL
)
1676 exec_change_infix();
1678 if (x
== RPN_OPERATOR_EQUAL
) {
1679 exec_infix2postfix(&calc
.code
, calc
.prev_operator
);
1680 rpn_copy(&calc
.code
, &calc
.prev
);
1685 /* if no change then quit silently, */
1686 /* without display updates */
1687 if (!exec_infix2postfix(&calc
.code
, x
))
1690 display_rpn_result(hWnd
, &calc
.code
);
1695 case IDC_BUTTON_BACK
:
1697 if (calc
.esp
== 0) {
1700 calc
.sci_in
= FALSE
;
1701 ptr
= _tcschr(calc
.ptr
, _T('e'));
1704 update_lcd_display(hWnd
);
1707 build_operand(hWnd
, IDC_STATIC
);
1710 if (calc
.ptr
!= calc
.buffer
) {
1711 *--calc
.ptr
= _T('\0');
1712 if (!_tcscmp(calc
.buffer
, _T("-")) ||
1713 !_tcscmp(calc
.buffer
, _T("-0")) ||
1714 !_tcscmp(calc
.buffer
, _T("0"))) {
1715 calc
.ptr
= calc
.buffer
;
1716 calc
.buffer
[0] = _T('\0');
1718 update_lcd_display(hWnd
);
1722 rpn_zero(&calc
.memory
.number
);
1723 update_memory_flag(hWnd
, FALSE
);
1726 if (calc
.is_memory
) {
1727 calc
.is_nan
= FALSE
;
1728 rpn_copy(&calc
.code
, &calc
.memory
.number
);
1729 display_rpn_result(hWnd
, &calc
.code
);
1732 case IDC_BUTTON_EXP
:
1733 if (calc
.sci_in
|| calc
.is_nan
|| calc
.buffer
== calc
.ptr
)
1737 build_operand(hWnd
, IDC_STATIC
);
1739 case IDC_BUTTON_SIGN
:
1741 calc
.esp
= 0-calc
.esp
;
1742 build_operand(hWnd
, IDC_STATIC
);
1744 if (calc
.is_nan
|| calc
.buffer
[0] == _T('\0'))
1747 if (calc
.buffer
[0] == _T('-')) {
1748 /* make the number positive */
1749 memmove(calc
.buffer
, calc
.buffer
+1, sizeof(calc
.buffer
)-1);
1750 if (calc
.buffer
!= calc
.ptr
)
1753 /* if first char is '0' and no dot, it isn't valid */
1754 if (calc
.buffer
[0] == _T('0') &&
1755 calc
.buffer
[1] != _T('.'))
1757 /* make the number negative */
1758 memmove(calc
.buffer
+1, calc
.buffer
, sizeof(calc
.buffer
)-1);
1759 calc
.buffer
[0] = _T('-');
1760 if (calc
.buffer
!= calc
.ptr
)
1763 /* If the input buffer is empty, then
1764 we change also the sign of calc.code
1765 because it could be the result of a
1766 previous calculation. */
1767 if (calc
.buffer
== calc
.ptr
)
1768 rpn_sign(&calc
.code
);
1769 update_lcd_display(hWnd
);
1772 case IDC_BUTTON_RIGHTPAR
:
1773 case IDC_BUTTON_LEFTPAR
:
1774 case IDC_BUTTON_CANC
:
1776 case IDC_BUTTON_DAT
:
1778 case IDC_BUTTON_DMS
:
1779 case IDC_BUTTON_SQRT
:
1781 case IDC_BUTTON_SUM
:
1782 case IDC_BUTTON_AVE
:
1785 case IDC_BUTTON_LOG
:
1786 case IDC_BUTTON_Xe2
:
1787 case IDC_BUTTON_Xe3
:
1789 case IDC_BUTTON_NOT
:
1791 case IDC_BUTTON_INT
:
1792 case IDC_BUTTON_SIN
:
1793 case IDC_BUTTON_COS
:
1794 case IDC_BUTTON_TAN
:
1796 for (x
=0; x
<SIZEOF(function_table
); x
++) {
1797 if (LOWORD(wp
) == function_table
[x
].idc
) {
1798 rpn_callback1 cb
= NULL
;
1800 /* test if NaN state is important or not */
1801 if (calc
.is_nan
&& function_table
[x
].check_nan
) break;
1802 /* otherwise, it's cleared */
1803 calc
.is_nan
= FALSE
;
1805 switch (get_modifiers(hWnd
) & function_table
[x
].range
) {
1807 cb
= function_table
[x
].direct
;
1810 cb
= function_table
[x
].inverse
;
1813 cb
= function_table
[x
].hyperb
;
1815 case MODIFIER_INV
|MODIFIER_HYP
:
1816 cb
= function_table
[x
].inv_hyp
;
1820 convert_text2number(&calc
.code
);
1822 // display_rpn_result(hWnd, &calc.code);
1823 set_rpn_result(hWnd
, &calc
.code
);
1825 if ((function_table
[x
].range
& NO_CHAIN
))
1826 calc
.ptr
= calc
.buffer
;
1828 // if (!(function_table[x].range & NO_CHAIN))
1829 // exec_infix2postfix(&calc.code, RPN_OPERATOR_NONE);
1830 if (function_table
[x
].range
& MODIFIER_INV
)
1831 CheckDlgButton(hWnd
, IDC_CHECK_INV
, BST_UNCHECKED
);
1832 if (function_table
[x
].range
& MODIFIER_HYP
)
1833 CheckDlgButton(hWnd
, IDC_CHECK_HYP
, BST_UNCHECKED
);
1839 case IDC_BUTTON_STA
:
1840 if (IsWindow(calc
.hStatWnd
))
1842 calc
.hStatWnd
= CreateDialog(calc
.hInstance
,
1843 MAKEINTRESOURCE(IDD_DIALOG_STAT
), hWnd
, DlgStatProc
);
1844 if (calc
.hStatWnd
!= NULL
) {
1845 enable_allowed_controls(hWnd
, calc
.base
);
1846 SendMessage(calc
.hStatWnd
, WM_SETFOCUS
, 0, 0);
1851 case WM_CLOSE_STATS
:
1852 calc
.hStatWnd
= NULL
;
1853 enable_allowed_controls(hWnd
, calc
.base
);
1856 if (upload_stat_number((int)LOWORD(wp
)) != NULL
)
1857 display_rpn_result(hWnd
, &calc
.code
);
1861 calc
.Convert
[x
].data
= ReadConversion(calc
.Convert
[x
].data
);
1862 if (calc
.Convert
[x
].data
!= NULL
) {
1863 calc
.Convert
[x
].ptr
= calc
.Convert
[x
].data
;
1864 PostMessage(hWnd
, HIWORD(lp
), 0, 0);
1867 case WM_HANDLE_FROM
:
1870 if (handle_sequence_input(hWnd
, &calc
.Convert
[0]) == NULL
)
1871 PostMessage(hWnd
, WM_START_CONV
, 0,
1872 MAKELPARAM(0x0001, WM_HANDLE_TO
));
1876 handle_sequence_input(hWnd
, &calc
.Convert
[1]);
1879 calc
.action
= IDC_STATIC
;
1880 DestroyWindow(hWnd
);
1884 /* Get (x,y) position of the calculator */
1885 GetWindowRect(hWnd
, &rc
);
1886 calc
.x_coord
= rc
.left
;
1887 calc
.y_coord
= rc
.top
;
1888 #ifdef USE_KEYBOARD_HOOK
1889 UnhookWindowsHookEx(calc
.hKeyboardHook
);
1893 case WM_CONTEXTMENU
:
1894 if ((HWND
)wp
!= hWnd
)
1895 handle_context_menu(hWnd
, wp
, lp
);
1897 case WM_ENTERMENULOOP
:
1898 calc
.is_menu_on
= TRUE
;
1899 /* Check if a valid format is available in the clipboard */
1900 EnableMenuItem(GetSubMenu(GetMenu(hWnd
), 0),
1903 (IsClipboardFormatAvailable(CF_TEXT
) ?
1904 MF_ENABLED
: MF_GRAYED
));
1906 case WM_EXITMENULOOP
:
1907 calc
.is_menu_on
= FALSE
;
1910 case WM_SETTINGCHANGE
:
1911 return OnSettingChange(hWnd
, wp
, lp
);
1913 case WM_THEMECHANGED
:
1914 InvalidateRect(hWnd
, NULL
, FALSE
);
1920 #if defined(__GNUC__) && !defined(__REACTOS__)
1921 int WINAPI
WinMain(HINSTANCE hInstance
, HINSTANCE hPrevInstance
, LPSTR lpCmdLine
, int nShowCmd
)
1923 int WINAPI
_tWinMain(HINSTANCE hInstance
, HINSTANCE hPrevInstance
, LPTSTR lpCmdLine
, int nShowCmd
)
1929 /* Initialize controls for theming & manifest support */
1930 InitCommonControls();
1932 calc
.hInstance
= hInstance
;
1940 HtmlHelp_Start(hInstance
);
1942 Theme_Start(hInstance
);
1944 calc
.hBgIcon
= LoadImage(
1946 MAKEINTRESOURCE(IDI_CALC
),
1948 GetSystemMetrics(SM_CXICON
),
1949 GetSystemMetrics(SM_CYICON
),
1952 calc
.hSmIcon
= LoadImage(
1954 MAKEINTRESOURCE(IDI_CALC
),
1956 GetSystemMetrics(SM_CXSMICON
),
1957 GetSystemMetrics(SM_CYSMICON
),
1961 /* ignore hwnd: dialogs are already visible! */
1962 if (calc
.layout
== CALC_LAYOUT_SCIENTIFIC
)
1963 dwLayout
= IDD_DIALOG_SCIENTIFIC
;
1965 if (calc
.layout
== CALC_LAYOUT_CONVERSION
)
1966 dwLayout
= IDD_DIALOG_CONVERSION
;
1968 dwLayout
= IDD_DIALOG_STANDARD
;
1970 /* This call will always fail if UNICODE for Win9x */
1971 if (NULL
== CreateDialog(hInstance
, MAKEINTRESOURCE(dwLayout
), NULL
, DlgMainProc
))
1974 while (GetMessage(&msg
, NULL
, 0, 0)) {
1975 #ifndef USE_KEYBOARD_HOOK
1976 if ((msg
.message
== WM_KEYUP
||
1977 msg
.message
== WM_KEYDOWN
) &&
1979 process_vk_key(msg
.wParam
, msg
.lParam
);
1981 TranslateMessage(&msg
);
1982 DispatchMessage(&msg
);
1986 } while (calc
.action
!= IDC_STATIC
);
1988 if (calc
.hBgIcon
!= NULL
)
1989 DestroyIcon(calc
.hBgIcon
);
1991 if (calc
.hSmIcon
!= NULL
)
1992 DestroyIcon(calc
.hSmIcon
);