mirror of
https://github.com/reactos/reactos.git
synced 2024-11-29 06:23:41 +08:00
1828 lines
63 KiB
C
1828 lines
63 KiB
C
#include "calc.h"
|
|
|
|
#include <winbase.h>
|
|
#include <wingdi.h>
|
|
#include <winreg.h>
|
|
#include <shellapi.h>
|
|
#include <commctrl.h>
|
|
|
|
#define HTMLHELP_PATH(_pt) TEXT("%systemroot%\\Help\\calc.chm::") TEXT(_pt)
|
|
|
|
#define MAKE_BITMASK4(_show_b16, _show_b10, _show_b8, _show_b2) \
|
|
(((_show_b2) << 0) | \
|
|
((_show_b8) << 1) | \
|
|
((_show_b10) << 2) | \
|
|
((_show_b16) << 3))
|
|
|
|
#define MAKE_BITMASK5(_transl, _is_stats, _is_ctrl, _show_b16, _show_b10, _show_b8, _show_b2) \
|
|
(((_show_b2) << 0) | \
|
|
((_show_b8) << 1) | \
|
|
((_show_b10) << 2) | \
|
|
((_show_b16) << 3) | \
|
|
((_is_ctrl) << 5) | \
|
|
((_is_stats) << 6) | \
|
|
((_transl) << 7))
|
|
|
|
#define KEY_IS_UP 0x80000000
|
|
#define KEY_WAS_DOWN 0x40000000
|
|
|
|
#define BITMASK_IS_ASCII 0x80
|
|
#define BITMASK_IS_STATS 0x40
|
|
#define BITMASK_IS_CTRL 0x20
|
|
#define BITMASK_HEX_MASK 0x08
|
|
#define BITMASK_DEC_MASK 0x04
|
|
#define BITMASK_OCT_MASK 0x02
|
|
#define BITMASK_BIN_MASK 0x01
|
|
|
|
#define CALC_CLR_RED 0x000000FF
|
|
#define CALC_CLR_BLUE 0x00FF0000
|
|
#define CALC_CLR_PURP 0x00FF00FF
|
|
|
|
typedef struct {
|
|
CHAR key; // Virtual key identifier
|
|
WORD idc; // IDC for posting message
|
|
} key2code_t;
|
|
|
|
typedef struct {
|
|
WORD idc; // IDC for posting message
|
|
CHAR key; // Virtual key identifier
|
|
BYTE mask; // enable/disable into the various modes.
|
|
COLORREF col; // color used for drawing the text
|
|
} key3code_t;
|
|
|
|
#define CTRL_FLAG 0x100
|
|
#define ALT_FLAG 0x200
|
|
|
|
#define CTRL_A (0x0001+'A'-'A')
|
|
#define CTRL_C (0x0001+'C'-'A')
|
|
#define CTRL_D (0x0001+'D'-'A')
|
|
#define CTRL_L (0x0001+'L'-'A')
|
|
#define CTRL_M (0x0001+'M'-'A')
|
|
#define CTRL_P (0x0001+'P'-'A')
|
|
#define CTRL_R (0x0001+'R'-'A')
|
|
#define CTRL_S (0x0001+'S'-'A')
|
|
#define CTRL_T (0x0001+'T'-'A')
|
|
#define CTRL_V (0x0001+'V'-'A')
|
|
#define CTRL_Z (0x0001+'Z'-'A')
|
|
|
|
static const key3code_t key2code[] = {
|
|
/* CONTROL-ID Key asc sta ctl hex dec oct bin */
|
|
{ IDC_BUTTON_STA, CTRL_S, MAKE_BITMASK5( 1, 0, 1, 1, 1, 1, 1), CALC_CLR_BLUE, },
|
|
{ IDC_BUTTON_AVE, CTRL_A, MAKE_BITMASK5( 1, 1, 1, 1, 1, 1, 1), CALC_CLR_BLUE, },
|
|
{ IDC_BUTTON_SUM, CTRL_T, MAKE_BITMASK5( 1, 1, 1, 1, 1, 1, 1), CALC_CLR_BLUE, },
|
|
{ IDC_BUTTON_S, CTRL_D, MAKE_BITMASK5( 1, 1, 1, 1, 1, 1, 1), CALC_CLR_BLUE, },
|
|
{ IDC_BUTTON_MS, CTRL_M, MAKE_BITMASK5( 1, 0, 1, 1, 1, 1, 1), CALC_CLR_RED, },
|
|
{ IDC_BUTTON_MR, CTRL_R, MAKE_BITMASK5( 1, 0, 1, 1, 1, 1, 1), CALC_CLR_RED, },
|
|
{ IDC_BUTTON_MP, CTRL_P, MAKE_BITMASK5( 1, 0, 1, 1, 1, 1, 1), CALC_CLR_RED, },
|
|
{ IDC_BUTTON_MC, CTRL_L, MAKE_BITMASK5( 1, 0, 1, 1, 1, 1, 1), CALC_CLR_RED, },
|
|
{ IDC_BUTTON_0, '0', MAKE_BITMASK5( 1, 0, 0, 1, 1, 1, 1), CALC_CLR_BLUE, },
|
|
{ IDC_BUTTON_1, '1', MAKE_BITMASK5( 1, 0, 0, 1, 1, 1, 1), CALC_CLR_BLUE, },
|
|
{ IDC_BUTTON_2, '2', MAKE_BITMASK5( 1, 0, 0, 1, 1, 1, 0), CALC_CLR_BLUE, },
|
|
{ IDC_BUTTON_3, '3', MAKE_BITMASK5( 1, 0, 0, 1, 1, 1, 0), CALC_CLR_BLUE, },
|
|
{ IDC_BUTTON_4, '4', MAKE_BITMASK5( 1, 0, 0, 1, 1, 1, 0), CALC_CLR_BLUE, },
|
|
{ IDC_BUTTON_5, '5', MAKE_BITMASK5( 1, 0, 0, 1, 1, 1, 0), CALC_CLR_BLUE, },
|
|
{ IDC_BUTTON_6, '6', MAKE_BITMASK5( 1, 0, 0, 1, 1, 1, 0), CALC_CLR_BLUE, },
|
|
{ IDC_BUTTON_7, '7', MAKE_BITMASK5( 1, 0, 0, 1, 1, 1, 0), CALC_CLR_BLUE, },
|
|
{ IDC_BUTTON_8, '8', MAKE_BITMASK5( 1, 0, 0, 1, 1, 0, 0), CALC_CLR_BLUE, },
|
|
{ IDC_BUTTON_9, '9', MAKE_BITMASK5( 1, 0, 0, 1, 1, 0, 0), CALC_CLR_BLUE, },
|
|
{ IDC_BUTTON_DOT, '.', MAKE_BITMASK5( 1, 0, 0, 0, 1, 0, 0), CALC_CLR_BLUE, },
|
|
{ IDC_BUTTON_DOT, ',', MAKE_BITMASK5( 1, 0, 0, 0, 1, 0, 0), -1, },
|
|
{ IDC_BUTTON_ADD, '+', MAKE_BITMASK5( 1, 0, 0, 1, 1, 1, 1), CALC_CLR_RED, },
|
|
{ IDC_BUTTON_SUB, '-', MAKE_BITMASK5( 1, 0, 0, 1, 1, 1, 1), CALC_CLR_RED, },
|
|
{ IDC_BUTTON_MULT, '*', MAKE_BITMASK5( 1, 0, 0, 1, 1, 1, 1), CALC_CLR_RED, },
|
|
{ IDC_BUTTON_DIV, '/', MAKE_BITMASK5( 1, 0, 0, 1, 1, 1, 1), CALC_CLR_RED, },
|
|
{ IDC_BUTTON_AND, '&', MAKE_BITMASK5( 1, 0, 0, 1, 1, 1, 1), CALC_CLR_RED, },
|
|
{ IDC_BUTTON_OR, '|', MAKE_BITMASK5( 1, 0, 0, 1, 1, 1, 1), CALC_CLR_RED, },
|
|
{ IDC_BUTTON_XOR, '^', MAKE_BITMASK5( 1, 0, 0, 1, 1, 1, 1), CALC_CLR_RED, },
|
|
{ IDC_BUTTON_LSH, '<', MAKE_BITMASK5( 1, 0, 0, 1, 1, 1, 1), CALC_CLR_RED, },
|
|
{ IDC_BUTTON_NOT, '~', MAKE_BITMASK5( 1, 0, 0, 1, 1, 1, 1), CALC_CLR_RED, },
|
|
{ IDC_BUTTON_INT, ';', MAKE_BITMASK5( 1, 0, 0, 0, 1, 0, 0), CALC_CLR_RED, },
|
|
{ IDC_BUTTON_EQU, '=', MAKE_BITMASK5( 1, 0, 0, 1, 1, 1, 1), CALC_CLR_RED, },
|
|
{ IDC_BUTTON_A, 'A', MAKE_BITMASK5( 1, 0, 0, 1, 0, 0, 0), CALC_CLR_BLUE, },
|
|
{ IDC_BUTTON_B, 'B', MAKE_BITMASK5( 1, 0, 0, 1, 0, 0, 0), CALC_CLR_BLUE, },
|
|
{ IDC_BUTTON_C, 'C', MAKE_BITMASK5( 1, 0, 0, 1, 0, 0, 0), CALC_CLR_BLUE, },
|
|
{ IDC_BUTTON_D, 'D', MAKE_BITMASK5( 1, 0, 0, 1, 0, 0, 0), CALC_CLR_BLUE, },
|
|
{ IDC_BUTTON_E, 'E', MAKE_BITMASK5( 1, 0, 0, 1, 0, 0, 0), CALC_CLR_BLUE, },
|
|
{ IDC_BUTTON_F, 'F', MAKE_BITMASK5( 1, 0, 0, 1, 0, 0, 0), CALC_CLR_BLUE, },
|
|
{ IDC_CHECK_HYP, 'H', MAKE_BITMASK5( 1, 0, 0, 1, 1, 1, 1), -1, },
|
|
{ IDC_CHECK_INV, 'I', MAKE_BITMASK5( 1, 0, 0, 1, 1, 1, 1), -1, },
|
|
{ IDC_BUTTON_LOG, 'L', MAKE_BITMASK5( 1, 0, 0, 0, 1, 0, 0), CALC_CLR_PURP, },
|
|
{ IDC_BUTTON_DMS, 'M', MAKE_BITMASK5( 1, 0, 0, 0, 1, 0, 0), CALC_CLR_PURP, },
|
|
{ IDC_BUTTON_LN, 'N', MAKE_BITMASK5( 1, 0, 0, 0, 1, 0, 0), CALC_CLR_PURP, },
|
|
{ IDC_BUTTON_PI, 'P', MAKE_BITMASK5( 1, 0, 0, 0, 1, 0, 0), CALC_CLR_BLUE, },
|
|
{ IDC_BUTTON_RX, 'R', MAKE_BITMASK5( 1, 0, 0, 0, 1, 0, 0), CALC_CLR_PURP, },
|
|
{ IDC_BUTTON_SIN, 'S', MAKE_BITMASK5( 1, 0, 0, 0, 1, 0, 0), CALC_CLR_PURP, },
|
|
{ IDC_BUTTON_COS, 'O', MAKE_BITMASK5( 1, 0, 0, 0, 1, 0, 0), CALC_CLR_PURP, },
|
|
{ IDC_BUTTON_TAN, 'T', MAKE_BITMASK5( 1, 0, 0, 0, 1, 0, 0), CALC_CLR_PURP, },
|
|
{ IDC_BUTTON_FE, 'V', MAKE_BITMASK5( 1, 0, 0, 0, 1, 0, 0), CALC_CLR_PURP, },
|
|
{ IDC_BUTTON_EXP, 'X', MAKE_BITMASK5( 1, 0, 0, 0, 1, 0, 0), CALC_CLR_PURP, },
|
|
{ IDC_BUTTON_XeY, 'Y', MAKE_BITMASK5( 1, 0, 0, 1, 1, 1, 1), CALC_CLR_PURP, },
|
|
{ IDC_BUTTON_SQRT, '@', MAKE_BITMASK5( 1, 0, 0, 0, 1, 0, 0), CALC_CLR_BLUE, },
|
|
{ IDC_BUTTON_Xe2, '@', MAKE_BITMASK5( 1, 0, 0, 1, 1, 1, 1), CALC_CLR_PURP, },
|
|
{ IDC_BUTTON_Xe3, '#', MAKE_BITMASK5( 1, 0, 0, 1, 1, 1, 1), CALC_CLR_PURP, },
|
|
{ IDC_BUTTON_NF, '!', MAKE_BITMASK5( 1, 0, 0, 1, 1, 1, 1), CALC_CLR_PURP, },
|
|
{ IDC_BUTTON_LEFTPAR, '(', MAKE_BITMASK5( 1, 0, 0, 1, 1, 1, 1), CALC_CLR_PURP, },
|
|
{ IDC_BUTTON_RIGHTPAR, ')', MAKE_BITMASK5( 1, 0, 0, 1, 1, 1, 1), CALC_CLR_PURP, },
|
|
{ IDC_BUTTON_MOD, '%', MAKE_BITMASK5( 1, 0, 0, 1, 1, 1, 1), CALC_CLR_RED, },
|
|
{ IDC_BUTTON_PERCENT, '%', MAKE_BITMASK5( 1, 0, 0, 0, 1, 0, 0), CALC_CLR_BLUE, },
|
|
/*----------------------------------------------------------------------*/
|
|
{ IDC_BUTTON_DAT, VK_INSERT, MAKE_BITMASK5( 0, 1, 0, 1, 1, 1, 1), CALC_CLR_BLUE, },
|
|
{ IDC_BUTTON_EQU, VK_RETURN, MAKE_BITMASK5( 0, 0, 0, 1, 1, 1, 1), CALC_CLR_RED, },
|
|
{ IDC_BUTTON_CANC, VK_ESCAPE, MAKE_BITMASK5( 0, 0, 0, 1, 1, 1, 1), CALC_CLR_RED, },
|
|
{ IDC_BUTTON_CE, VK_DELETE, MAKE_BITMASK5( 0, 0, 0, 1, 1, 1, 1), CALC_CLR_RED, },
|
|
{ IDC_BUTTON_BACK, VK_BACK, MAKE_BITMASK5( 0, 0, 0, 1, 1, 1, 1), CALC_CLR_RED, },
|
|
{ IDC_RADIO_HEX, VK_F5, MAKE_BITMASK5( 0, 0, 0, 1, 1, 1, 1), -1, },
|
|
{ IDC_RADIO_DEC, VK_F6, MAKE_BITMASK5( 0, 0, 0, 1, 1, 1, 1), -1, },
|
|
{ IDC_RADIO_OCT, VK_F7, MAKE_BITMASK5( 0, 0, 0, 1, 1, 1, 1), -1, },
|
|
{ IDC_RADIO_BIN, VK_F8, MAKE_BITMASK5( 0, 0, 0, 1, 1, 1, 1), -1, },
|
|
{ IDC_BUTTON_SIGN, VK_F9, MAKE_BITMASK5( 0, 0, 0, 1, 1, 1, 1), CALC_CLR_BLUE, },
|
|
};
|
|
|
|
static const key2code_t key2code_base16[] = {
|
|
{ VK_F2, IDC_RADIO_DWORD, },
|
|
{ VK_F3, IDC_RADIO_WORD, },
|
|
{ VK_F4, IDC_RADIO_BYTE, },
|
|
{ VK_F12, IDC_RADIO_QWORD, },
|
|
};
|
|
|
|
static const key2code_t key2code_base10[] = {
|
|
{ VK_F2, IDC_RADIO_DEG, },
|
|
{ VK_F3, IDC_RADIO_RAD, },
|
|
{ VK_F4, IDC_RADIO_GRAD, },
|
|
};
|
|
|
|
static const WORD operator_codes[] = {
|
|
/* CONTROL-ID operator */
|
|
(WORD)IDC_STATIC, // RPN_OPERATOR_PARENT
|
|
IDC_BUTTON_PERCENT, // RPN_OPERATOR_PERCENT
|
|
IDC_BUTTON_EQU, // RPN_OPERATOR_EQUAL
|
|
IDC_BUTTON_OR, // RPN_OPERATOR_OR
|
|
IDC_BUTTON_XOR, // RPN_OPERATOR_XOR
|
|
IDC_BUTTON_AND, // RPN_OPERATOR_AND
|
|
IDC_BUTTON_LSH, // RPN_OPERATOR_LSH
|
|
IDC_BUTTON_RSH, // RPN_OPERATOR_RSH
|
|
IDC_BUTTON_ADD, // RPN_OPERATOR_ADD
|
|
IDC_BUTTON_SUB, // RPN_OPERATOR_SUB
|
|
IDC_BUTTON_MULT, // RPN_OPERATOR_MULT
|
|
IDC_BUTTON_DIV, // RPN_OPERATOR_DIV
|
|
IDC_BUTTON_MOD, // RPN_OPERATOR_MOD
|
|
};
|
|
|
|
typedef void (*rpn_callback1)(calc_number_t *);
|
|
|
|
typedef struct {
|
|
WORD idc;
|
|
BYTE range;
|
|
BYTE check_nan;
|
|
rpn_callback1 direct;
|
|
rpn_callback1 inverse;
|
|
rpn_callback1 hyperb;
|
|
rpn_callback1 inv_hyp;
|
|
} function_table_t;
|
|
|
|
static void run_pow(calc_number_t *number);
|
|
static void run_sqr(calc_number_t *number);
|
|
static void run_fe(calc_number_t *number);
|
|
static void run_dat_sta(calc_number_t *number);
|
|
static void run_mp(calc_number_t *c);
|
|
static void run_mm(calc_number_t *c);
|
|
static void run_ms(calc_number_t *c);
|
|
static void run_mw(calc_number_t *c);
|
|
static void run_canc(calc_number_t *c);
|
|
static void run_rpar(calc_number_t *c);
|
|
static void run_lpar(calc_number_t *c);
|
|
|
|
static const function_table_t function_table[] = {
|
|
{ IDC_BUTTON_SIN, MODIFIER_INV|MODIFIER_HYP, 1, rpn_sin, rpn_asin, rpn_sinh, rpn_asinh },
|
|
{ IDC_BUTTON_COS, MODIFIER_INV|MODIFIER_HYP, 1, rpn_cos, rpn_acos, rpn_cosh, rpn_acosh },
|
|
{ IDC_BUTTON_TAN, MODIFIER_INV|MODIFIER_HYP, 1, rpn_tan, rpn_atan, rpn_tanh, rpn_atanh },
|
|
{ IDC_BUTTON_INT, MODIFIER_INV, 1, rpn_int, rpn_frac, NULL, NULL },
|
|
{ IDC_BUTTON_RX, 0, 1, rpn_reci, NULL, NULL, NULL },
|
|
{ IDC_BUTTON_NOT, 0, 1, rpn_not, NULL, NULL, NULL },
|
|
{ IDC_BUTTON_PI, MODIFIER_INV, 0, rpn_pi, rpn_2pi, NULL, NULL },
|
|
{ IDC_BUTTON_Xe2, MODIFIER_INV, 1, rpn_exp2, rpn_sqrt, NULL, NULL },
|
|
{ IDC_BUTTON_Xe3, MODIFIER_INV, 1, rpn_exp3, rpn_cbrt, NULL, NULL },
|
|
{ IDC_BUTTON_LN, MODIFIER_INV, 1, rpn_ln, rpn_exp, NULL, NULL },
|
|
{ IDC_BUTTON_LOG, MODIFIER_INV, 1, rpn_log, rpn_exp10, NULL, NULL },
|
|
{ IDC_BUTTON_NF, 0, 1, rpn_fact, NULL, NULL, NULL },
|
|
{ IDC_BUTTON_AVE, 0, 0, rpn_ave, NULL, NULL, NULL },
|
|
{ IDC_BUTTON_SUM, 0, 0, rpn_sum, NULL, NULL, NULL },
|
|
{ IDC_BUTTON_S, MODIFIER_INV, 0, rpn_s_m1, rpn_s, NULL, NULL },
|
|
{ IDC_BUTTON_XeY, MODIFIER_INV, 1, run_pow, run_sqr, NULL, NULL },
|
|
{ IDC_BUTTON_SQRT, MODIFIER_INV, 1, rpn_sqrt, NULL, NULL, NULL },
|
|
{ IDC_BUTTON_DMS, MODIFIER_INV, 1, rpn_dec2dms, rpn_dms2dec, NULL, NULL },
|
|
{ IDC_BUTTON_FE, 0, 1, run_fe, NULL, NULL, NULL },
|
|
{ IDC_BUTTON_DAT, 0, 1, run_dat_sta, NULL, NULL, NULL, },
|
|
{ IDC_BUTTON_MP, MODIFIER_INV|NO_CHAIN, 1, run_mp, run_mm, NULL, NULL, },
|
|
{ IDC_BUTTON_MS, MODIFIER_INV|NO_CHAIN, 1, run_ms, run_mw, NULL, NULL, },
|
|
{ IDC_BUTTON_CANC, NO_CHAIN, 0, run_canc, NULL, NULL, NULL, },
|
|
{ IDC_BUTTON_RIGHTPAR, NO_CHAIN, 1, run_rpar, NULL, NULL, NULL, },
|
|
{ IDC_BUTTON_LEFTPAR, NO_CHAIN, 0, run_lpar, NULL, NULL, NULL, },
|
|
};
|
|
|
|
/*
|
|
*/
|
|
|
|
calc_t calc;
|
|
|
|
static void load_config(void)
|
|
{
|
|
DWORD tmp;
|
|
HKEY hKey;
|
|
|
|
/* If no settings are found in the registry, then use the default options */
|
|
calc.layout = CALC_LAYOUT_STANDARD;
|
|
calc.usesep = FALSE;
|
|
|
|
/* Get the configuration based on what version of Windows that's being used */
|
|
if (RegOpenKeyEx(HKEY_CURRENT_USER, TEXT("SOFTWARE\\Microsoft\\Calc"), 0, KEY_QUERY_VALUE, &hKey) == ERROR_SUCCESS)
|
|
{
|
|
/* Try to load last selected layout */
|
|
tmp = sizeof(calc.layout);
|
|
if (RegQueryValueEx(hKey, TEXT("layout"), NULL, NULL, (LPBYTE)&calc.layout, &tmp) != ERROR_SUCCESS)
|
|
calc.layout = CALC_LAYOUT_STANDARD;
|
|
|
|
/* Try to load last selected formatting option */
|
|
tmp = sizeof(calc.usesep);
|
|
if (RegQueryValueEx(hKey, TEXT("UseSep"), NULL, NULL, (LPBYTE)&calc.usesep, &tmp) != ERROR_SUCCESS)
|
|
calc.usesep = FALSE;
|
|
|
|
/* close the key */
|
|
RegCloseKey(hKey);
|
|
}
|
|
|
|
/* memory is empty at startup */
|
|
calc.is_memory = FALSE;
|
|
|
|
/* empty these values */
|
|
calc.sDecimal[0] = TEXT('\0');
|
|
calc.sThousand[0] = TEXT('\0');
|
|
|
|
/* try to open the registry */
|
|
if (RegOpenKeyEx(HKEY_CURRENT_USER, TEXT("Control Panel\\International"), 0, KEY_QUERY_VALUE, &hKey) == ERROR_SUCCESS)
|
|
{
|
|
/* get these values (ignore errors) */
|
|
tmp = sizeof(calc.sDecimal);
|
|
RegQueryValueEx(hKey, TEXT("sDecimal"), NULL, NULL, (LPBYTE)calc.sDecimal, &tmp);
|
|
|
|
tmp = sizeof(calc.sThousand);
|
|
RegQueryValueEx(hKey, TEXT("sThousand"), NULL, NULL, (LPBYTE)calc.sThousand, &tmp);
|
|
|
|
/* close the key */
|
|
RegCloseKey(hKey);
|
|
}
|
|
/* if something goes wrong, let's apply the defaults */
|
|
if (calc.sDecimal[0] == TEXT('\0'))
|
|
_tcscpy(calc.sDecimal, TEXT("."));
|
|
|
|
if (calc.sThousand[0] == TEXT('\0'))
|
|
_tcscpy(calc.sThousand, TEXT(","));
|
|
|
|
/* get the string lengths */
|
|
calc.sDecimal_len = _tcslen(calc.sDecimal);
|
|
calc.sThousand_len = _tcslen(calc.sThousand);
|
|
}
|
|
|
|
static void save_config(void)
|
|
{
|
|
HKEY hKey;
|
|
DWORD sepValue;
|
|
|
|
if (RegCreateKeyEx(HKEY_CURRENT_USER, TEXT("SOFTWARE\\Microsoft\\Calc"), 0, NULL, REG_OPTION_NON_VOLATILE, KEY_SET_VALUE, NULL, &hKey, NULL) != ERROR_SUCCESS)
|
|
{
|
|
return;
|
|
}
|
|
|
|
sepValue = (calc.usesep) ? 1 : 0;
|
|
|
|
RegSetValueEx(hKey, TEXT("layout"), 0, REG_DWORD, (const BYTE*)&calc.layout, sizeof(calc.layout));
|
|
RegSetValueEx(hKey, TEXT("UseSep"), 0, REG_DWORD, (const BYTE*)&sepValue, sizeof(sepValue));
|
|
|
|
RegCloseKey(hKey);
|
|
}
|
|
|
|
static LRESULT post_key_press(LPARAM lParam, WORD idc)
|
|
{
|
|
HWND hCtlWnd = GetDlgItem(calc.hWnd,idc);
|
|
TCHAR ClassName[64];
|
|
|
|
/* check if the key is enabled! */
|
|
if (!IsWindowEnabled(hCtlWnd))
|
|
return 1;
|
|
|
|
if (!GetClassName(hCtlWnd, ClassName, SIZEOF(ClassName)))
|
|
return 1;
|
|
|
|
if (!_tcscmp(ClassName, TEXT("Button"))) {
|
|
DWORD dwStyle = GetWindowLongPtr(hCtlWnd, GWL_STYLE) & 0xF;
|
|
|
|
/* Set states for press/release, but only for push buttons */
|
|
if (dwStyle == BS_PUSHBUTTON || dwStyle == BS_DEFPUSHBUTTON || dwStyle == BS_OWNERDRAW) {
|
|
if (!(lParam & KEY_WAS_DOWN)) {
|
|
PostMessage(hCtlWnd, BM_SETSTATE, 1, 0);
|
|
} else
|
|
if ((lParam & KEY_IS_UP)) {
|
|
PostMessage(hCtlWnd, BM_SETSTATE, 0, 0);
|
|
PostMessage(hCtlWnd, BM_CLICK, 0, 0);
|
|
}
|
|
return 1;
|
|
}
|
|
}
|
|
/* default action: simple click event at key release */
|
|
if ((lParam & KEY_IS_UP)) {
|
|
PostMessage(hCtlWnd, BM_CLICK, 0, 0);
|
|
}
|
|
return 1;
|
|
}
|
|
|
|
static int vk2ascii(unsigned int vk)
|
|
{
|
|
unsigned short int s;
|
|
int scan;
|
|
BYTE state[256];
|
|
HKL layout=GetKeyboardLayout(0);
|
|
|
|
if(!GetKeyboardState(state))
|
|
return 0;
|
|
|
|
scan=MapVirtualKeyEx(vk, 0, layout);
|
|
s = 0;
|
|
if (ToAsciiEx(vk, scan, state, &s, 0, layout)>0) {
|
|
/* convert to upper case */
|
|
if (s >= 'a' && s <= 'z')
|
|
s = s - 'a' + 'A';
|
|
/* add check to CTRL key */
|
|
if (vk >= 'A' && vk <= 'Z' &&
|
|
s >= CTRL_A && s <= CTRL_Z)
|
|
s |= CTRL_FLAG;
|
|
else
|
|
if (GetAsyncKeyState(VK_MENU) < 0)
|
|
s |= ALT_FLAG;
|
|
return s;
|
|
}
|
|
return 0;
|
|
}
|
|
|
|
static int process_vk_key(WPARAM wParam, LPARAM lParam)
|
|
{
|
|
const key2code_t *k;
|
|
unsigned int x;
|
|
unsigned short int ch;
|
|
|
|
ch = vk2ascii(LOWORD(wParam));
|
|
if ((lParam & KEY_IS_UP)) {
|
|
/* Test for "copy" to clipboard */
|
|
if (ch == (CTRL_C|CTRL_FLAG)) {
|
|
SendMessage(calc.hWnd, WM_COMMAND, IDM_EDIT_COPY, 0);
|
|
return 1;
|
|
}
|
|
/* Test for "paste" from clipboard */
|
|
if (ch == (CTRL_V|CTRL_FLAG)) {
|
|
SendMessage(calc.hWnd, WM_COMMAND, IDM_EDIT_PASTE, 0);
|
|
return 1;
|
|
}
|
|
/* Test of help menu */
|
|
if (LOWORD(wParam) == VK_F1) {
|
|
SendMessage(calc.hWnd, WM_COMMAND, IDM_HELP_HELP, 0);
|
|
return 1;
|
|
}
|
|
}
|
|
|
|
for (x=0; x<SIZEOF(key2code); x++) {
|
|
int key = key2code[x].key;
|
|
if (key2code[x].mask & BITMASK_IS_CTRL)
|
|
key |= CTRL_FLAG;
|
|
if ((key == ch && (key2code[x].mask & BITMASK_IS_ASCII)) ||
|
|
(key == LOWORD(wParam) && !(key2code[x].mask & BITMASK_IS_ASCII))
|
|
) {
|
|
if (GetDlgItem(calc.hWnd, key2code[x].idc) == NULL)
|
|
continue;
|
|
return post_key_press(lParam, key2code[x].idc);
|
|
}
|
|
}
|
|
if (calc.layout == CALC_LAYOUT_SCIENTIFIC) {
|
|
if (calc.base == IDC_RADIO_DEC) {
|
|
k = key2code_base10;
|
|
x = SIZEOF(key2code_base10);
|
|
} else {
|
|
k = key2code_base16;
|
|
x = SIZEOF(key2code_base16);
|
|
}
|
|
do {
|
|
if (k->key == LOWORD(wParam)) {
|
|
return post_key_press(lParam, k->idc);
|
|
}
|
|
k++;
|
|
} while (--x);
|
|
}
|
|
return 0;
|
|
}
|
|
|
|
#ifdef USE_KEYBOARD_HOOK
|
|
static LRESULT CALLBACK
|
|
KeyboardHookProc(int nCode, WPARAM wParam, LPARAM lParam)
|
|
{
|
|
if(nCode<0 || calc.is_menu_on)
|
|
return CallNextHookEx(calc.hKeyboardHook,nCode,wParam,lParam);
|
|
|
|
if(nCode==HC_ACTION)
|
|
if (process_vk_key(wParam, lParam))
|
|
return;
|
|
|
|
return CallNextHookEx(calc.hKeyboardHook,nCode,wParam,lParam);
|
|
}
|
|
#endif
|
|
|
|
static void update_lcd_display(HWND hwnd)
|
|
{
|
|
/*
|
|
* multiply size of calc.buffer by 2 because it may
|
|
* happen that separator is used between each digit.
|
|
* Also added little additional space for dot and '\0'.
|
|
*/
|
|
TCHAR *tmp = (TCHAR *)alloca(sizeof(calc.buffer)*2+2*sizeof(TCHAR));
|
|
|
|
if (calc.buffer[0] == TEXT('\0'))
|
|
_tcscpy(tmp, TEXT("0"));
|
|
else
|
|
_tcscpy(tmp, calc.buffer);
|
|
/* add final '.' in decimal mode (if it's missing) */
|
|
if (calc.base == IDC_RADIO_DEC) {
|
|
if (_tcschr(tmp, TEXT('.')) == NULL)
|
|
_tcscat(tmp, TEXT("."));
|
|
}
|
|
/* if separator mode is on, let's add an additional space */
|
|
if (calc.usesep && !calc.sci_in && !calc.sci_out && !calc.is_nan) {
|
|
/* go to the integer part of the string */
|
|
TCHAR *p = _tcschr(tmp, TEXT('.'));
|
|
TCHAR *e = _tcschr(tmp, TEXT('\0'));
|
|
int n=0, t;
|
|
|
|
if (p == NULL) p = e;
|
|
switch (calc.base) {
|
|
case IDC_RADIO_HEX:
|
|
case IDC_RADIO_BIN:
|
|
t = 4;
|
|
break;
|
|
default:
|
|
/* fall here for:
|
|
IDC_RADIO_DEC:
|
|
IDC_RADIO_OCT: */
|
|
t = 3;
|
|
break;
|
|
}
|
|
while (--p > tmp) {
|
|
if (++n == t && *(p-1) != TEXT('-')) {
|
|
memmove(p+1, p, (e-p+1)*sizeof(TCHAR));
|
|
e++;
|
|
*p = TEXT(' ');
|
|
n = 0;
|
|
}
|
|
}
|
|
/* if decimal mode, apply regional settings */
|
|
if (calc.base == IDC_RADIO_DEC) {
|
|
TCHAR *p = tmp;
|
|
TCHAR *e = _tcschr(tmp, TEXT('.'));
|
|
|
|
/* searching for thousands default separator */
|
|
while (p < e) {
|
|
if (*p == TEXT(' ')) {
|
|
memmove(p+calc.sThousand_len, p+1, _tcslen(p)*sizeof(TCHAR));
|
|
memcpy(p, calc.sThousand, calc.sThousand_len*sizeof(TCHAR));
|
|
p += calc.sThousand_len;
|
|
} else
|
|
p++;
|
|
}
|
|
/* update decimal point too. */
|
|
memmove(p+calc.sDecimal_len, p+1, _tcslen(p)*sizeof(TCHAR));
|
|
memcpy(p, calc.sDecimal, calc.sDecimal_len*sizeof(TCHAR));
|
|
}
|
|
} else {
|
|
TCHAR *p = _tcschr(tmp, TEXT('.'));
|
|
|
|
/* update decimal point when usesep is false */
|
|
if (p != NULL) {
|
|
memmove(p+calc.sDecimal_len, p+1, _tcslen(p)*sizeof(TCHAR));
|
|
memcpy(p, calc.sDecimal, calc.sDecimal_len*sizeof(TCHAR));
|
|
}
|
|
}
|
|
SendDlgItemMessage(hwnd, IDC_TEXT_OUTPUT, WM_SETTEXT, (WPARAM)0, (LPARAM)tmp);
|
|
}
|
|
|
|
static void update_parent_display(HWND hWnd)
|
|
{
|
|
TCHAR str[8];
|
|
int n = eval_parent_count();
|
|
|
|
if (!n)
|
|
str[0] = TEXT('\0');
|
|
else
|
|
_stprintf(str,TEXT("(=%d"), n);
|
|
SendDlgItemMessage(hWnd, IDC_TEXT_PARENT, WM_SETTEXT, 0, (LPARAM)str);
|
|
}
|
|
|
|
static void build_operand(HWND hwnd, DWORD idc)
|
|
{
|
|
unsigned int i = 0, n;
|
|
|
|
if (idc == IDC_BUTTON_DOT) {
|
|
/* if dot is the first char, it's added automatically */
|
|
if (calc.buffer == calc.ptr) {
|
|
*calc.ptr++ = TEXT('0');
|
|
*calc.ptr++ = TEXT('.');
|
|
*calc.ptr = TEXT('\0');
|
|
update_lcd_display(hwnd);
|
|
return;
|
|
}
|
|
/* if pressed dot and it's already in the string, then return */
|
|
if (_tcschr(calc.buffer, TEXT('.')) != NULL)
|
|
return;
|
|
}
|
|
if (idc != IDC_STATIC) {
|
|
while (idc != key2code[i].idc) i++;
|
|
}
|
|
n = calc.ptr - calc.buffer;
|
|
if (idc == IDC_BUTTON_0 && n == 0) {
|
|
/* no need to put the dot because it's handled by update_lcd_display() */
|
|
calc.buffer[0] = TEXT('0');
|
|
calc.buffer[1] = TEXT('\0');
|
|
update_lcd_display(hwnd);
|
|
return;
|
|
}
|
|
switch (calc.base) {
|
|
case IDC_RADIO_HEX:
|
|
if (n >= 16)
|
|
return;
|
|
break;
|
|
case IDC_RADIO_DEC:
|
|
if (n >= SIZEOF(calc.buffer)-1)
|
|
return;
|
|
if (calc.sci_in) {
|
|
if (idc != IDC_STATIC)
|
|
calc.esp = (calc.esp * 10 + (key2code[i].key-'0')) % LOCAL_EXP_SIZE;
|
|
if (calc.ptr == calc.buffer)
|
|
_stprintf(calc.ptr, TEXT("0.e%+d"), calc.esp);
|
|
else {
|
|
/* adds the dot at the end if the number has no decimal part */
|
|
if (!_tcschr(calc.buffer, TEXT('.')))
|
|
*calc.ptr++ = TEXT('.');
|
|
_stprintf(calc.ptr, TEXT("e%+d"), calc.esp);
|
|
}
|
|
update_lcd_display(hwnd);
|
|
return;
|
|
}
|
|
break;
|
|
case IDC_RADIO_OCT:
|
|
if (n >= 22)
|
|
return;
|
|
break;
|
|
case IDC_RADIO_BIN:
|
|
if (n >= 64)
|
|
return;
|
|
break;
|
|
}
|
|
calc.ptr += _stprintf(calc.ptr, TEXT("%C"), key2code[i].key);
|
|
update_lcd_display(hwnd);
|
|
}
|
|
|
|
static void prepare_rpn_result(calc_number_t *rpn, TCHAR *buffer, int size, int base)
|
|
{
|
|
if (calc.is_nan) {
|
|
rpn_zero(&calc.code);
|
|
LoadString(calc.hInstance, IDS_MATH_ERROR, buffer, size);
|
|
return;
|
|
}
|
|
prepare_rpn_result_2(rpn, buffer, size, base);
|
|
}
|
|
|
|
static void display_rpn_result(HWND hwnd, calc_number_t *rpn)
|
|
{
|
|
calc.sci_in = FALSE;
|
|
prepare_rpn_result(rpn, calc.buffer, SIZEOF(calc.buffer), calc.base);
|
|
calc.ptr = calc.buffer + _tcslen(calc.buffer);
|
|
update_lcd_display(hwnd);
|
|
calc.ptr = calc.buffer;
|
|
update_parent_display(hwnd);
|
|
}
|
|
|
|
static int get_modifiers(HWND hwnd)
|
|
{
|
|
int modifiers = 0;
|
|
|
|
if (SendDlgItemMessage(hwnd, IDC_CHECK_INV, BM_GETCHECK, 0, 0))
|
|
modifiers |= MODIFIER_INV;
|
|
if (SendDlgItemMessage(hwnd, IDC_CHECK_HYP, BM_GETCHECK, 0, 0))
|
|
modifiers |= MODIFIER_HYP;
|
|
|
|
return modifiers;
|
|
}
|
|
|
|
static void convert_text2number(calc_number_t *a)
|
|
{
|
|
/* if the screen output buffer is empty, then */
|
|
/* the operand is taken from the last input */
|
|
if (calc.buffer == calc.ptr) {
|
|
/* if pushed valued is ZERO then we should grab it */
|
|
if (!_tcscmp(calc.buffer, TEXT("0.")) ||
|
|
!_tcscmp(calc.buffer, TEXT("0")))
|
|
/* this zero is good for both integer and decimal */
|
|
rpn_zero(a);
|
|
else
|
|
rpn_copy(a, &calc.code);
|
|
return;
|
|
}
|
|
/* ZERO is the default value for all numeric bases */
|
|
rpn_zero(a);
|
|
convert_text2number_2(a);
|
|
}
|
|
|
|
static const struct _update_check_menus {
|
|
DWORD *sel;
|
|
WORD idm;
|
|
WORD idc;
|
|
} upd[] = {
|
|
{ &calc.layout, IDM_VIEW_STANDARD, CALC_LAYOUT_STANDARD },
|
|
{ &calc.layout, IDM_VIEW_SCIENTIFIC, CALC_LAYOUT_SCIENTIFIC },
|
|
{ &calc.layout, IDM_VIEW_CONVERSION, CALC_LAYOUT_CONVERSION },
|
|
/*-----------------------------------------*/
|
|
{ &calc.base, IDM_VIEW_HEX, IDC_RADIO_HEX, },
|
|
{ &calc.base, IDM_VIEW_DEC, IDC_RADIO_DEC, },
|
|
{ &calc.base, IDM_VIEW_OCT, IDC_RADIO_OCT, },
|
|
{ &calc.base, IDM_VIEW_BIN, IDC_RADIO_BIN, },
|
|
/*-----------------------------------------*/
|
|
{ &calc.degr, IDM_VIEW_DEG, IDC_RADIO_DEG, },
|
|
{ &calc.degr, IDM_VIEW_RAD, IDC_RADIO_RAD, },
|
|
{ &calc.degr, IDM_VIEW_GRAD, IDC_RADIO_GRAD, },
|
|
/*-----------------------------------------*/
|
|
{ &calc.size, IDM_VIEW_QWORD, IDC_RADIO_QWORD, },
|
|
{ &calc.size, IDM_VIEW_DWORD, IDC_RADIO_DWORD, },
|
|
{ &calc.size, IDM_VIEW_WORD, IDC_RADIO_WORD, },
|
|
{ &calc.size, IDM_VIEW_BYTE, IDC_RADIO_BYTE, },
|
|
};
|
|
|
|
static void update_menu(HWND hwnd)
|
|
{
|
|
HMENU hMenu = GetSubMenu(GetMenu(hwnd), 1);
|
|
unsigned int x;
|
|
|
|
/* Sets the state of the layout in the menu based on the configuration file */
|
|
if (calc.layout == CALC_LAYOUT_SCIENTIFIC)
|
|
{
|
|
CheckMenuRadioItem(GetMenu(hwnd),
|
|
IDM_VIEW_STANDARD,
|
|
IDM_VIEW_CONVERSION,
|
|
IDM_VIEW_SCIENTIFIC,
|
|
MF_BYCOMMAND);
|
|
}
|
|
else if (calc.layout == CALC_LAYOUT_CONVERSION)
|
|
{
|
|
CheckMenuRadioItem(GetMenu(hwnd),
|
|
IDM_VIEW_STANDARD,
|
|
IDM_VIEW_CONVERSION,
|
|
IDM_VIEW_CONVERSION,
|
|
MF_BYCOMMAND);
|
|
}
|
|
else
|
|
{
|
|
CheckMenuRadioItem(GetMenu(hwnd),
|
|
IDM_VIEW_STANDARD,
|
|
IDM_VIEW_CONVERSION,
|
|
IDM_VIEW_STANDARD,
|
|
MF_BYCOMMAND);
|
|
}
|
|
|
|
for (x=3; x<SIZEOF(upd); x++) {
|
|
if (*(upd[x].sel) != upd[x].idc) {
|
|
CheckMenuItem(hMenu, upd[x].idm, MF_BYCOMMAND|MF_UNCHECKED);
|
|
SendMessage((HWND)GetDlgItem(hwnd,upd[x].idc),BM_SETCHECK,FALSE,0L);
|
|
} else {
|
|
CheckMenuItem(hMenu, upd[x].idm, MF_BYCOMMAND|MF_CHECKED);
|
|
SendMessage((HWND)GetDlgItem(hwnd,upd[x].idc),BM_SETCHECK,TRUE,0L);
|
|
}
|
|
}
|
|
CheckMenuItem(hMenu, IDM_VIEW_GROUP, MF_BYCOMMAND|(calc.usesep ? MF_CHECKED : MF_UNCHECKED));
|
|
}
|
|
|
|
typedef struct {
|
|
WORD idc;
|
|
WORD mask;
|
|
} radio_config_t;
|
|
|
|
static const radio_config_t radio_setup[] = {
|
|
/* CONTROL-ID hex dec oct bin */
|
|
{ IDC_RADIO_QWORD, MAKE_BITMASK4( 1, 0, 1, 1) },
|
|
{ IDC_RADIO_DWORD, MAKE_BITMASK4( 1, 0, 1, 1) },
|
|
{ IDC_RADIO_WORD, MAKE_BITMASK4( 1, 0, 1, 1) },
|
|
{ IDC_RADIO_BYTE, MAKE_BITMASK4( 1, 0, 1, 1) },
|
|
{ IDC_RADIO_DEG, MAKE_BITMASK4( 0, 1, 0, 0) },
|
|
{ IDC_RADIO_RAD, MAKE_BITMASK4( 0, 1, 0, 0) },
|
|
{ IDC_RADIO_GRAD, MAKE_BITMASK4( 0, 1, 0, 0) },
|
|
};
|
|
|
|
static void enable_allowed_controls(HWND hwnd, DWORD base)
|
|
{
|
|
BYTE mask;
|
|
int n;
|
|
|
|
switch (base) {
|
|
case IDC_RADIO_DEC:
|
|
mask = BITMASK_DEC_MASK;
|
|
break;
|
|
case IDC_RADIO_HEX:
|
|
mask = BITMASK_HEX_MASK;
|
|
break;
|
|
case IDC_RADIO_OCT:
|
|
mask = BITMASK_OCT_MASK;
|
|
break;
|
|
case IDC_RADIO_BIN:
|
|
mask = BITMASK_BIN_MASK;
|
|
break;
|
|
default:
|
|
return;
|
|
}
|
|
for (n=0; n<SIZEOF(key2code); n++) {
|
|
if (key2code[n].mask != 0) {
|
|
HWND hCtlWnd = GetDlgItem(hwnd, key2code[n].idc);
|
|
BOOL current;
|
|
|
|
if ((key2code[n].mask & BITMASK_IS_STATS))
|
|
current = IsWindow(calc.hStatWnd) ? TRUE : FALSE;
|
|
else
|
|
current = (key2code[n].mask & mask) ? TRUE : FALSE;
|
|
if (IsWindowEnabled(hCtlWnd) != current)
|
|
EnableWindow(hCtlWnd, current);
|
|
}
|
|
}
|
|
}
|
|
|
|
static void update_radio(HWND hwnd, unsigned int base)
|
|
{
|
|
HMENU hMenu;
|
|
LPCTSTR lpMenuId;
|
|
WORD mask;
|
|
int n;
|
|
|
|
switch (base) {
|
|
case IDC_RADIO_DEC:
|
|
lpMenuId = MAKEINTRESOURCE(IDR_MENU_SCIENTIFIC_1);
|
|
mask = BITMASK_DEC_MASK;
|
|
break;
|
|
case IDC_RADIO_HEX:
|
|
lpMenuId = MAKEINTRESOURCE(IDR_MENU_SCIENTIFIC_2);
|
|
mask = BITMASK_HEX_MASK;
|
|
break;
|
|
case IDC_RADIO_OCT:
|
|
lpMenuId = MAKEINTRESOURCE(IDR_MENU_SCIENTIFIC_2);
|
|
mask = BITMASK_OCT_MASK;
|
|
break;
|
|
case IDC_RADIO_BIN:
|
|
lpMenuId = MAKEINTRESOURCE(IDR_MENU_SCIENTIFIC_2);
|
|
mask = BITMASK_BIN_MASK;
|
|
break;
|
|
default:
|
|
return;
|
|
}
|
|
|
|
if (calc.base != base) {
|
|
convert_text2number(&calc.code);
|
|
convert_real_integer(base);
|
|
calc.base = base;
|
|
display_rpn_result(hwnd, &calc.code);
|
|
|
|
hMenu = GetMenu(hwnd);
|
|
DestroyMenu(hMenu);
|
|
hMenu = LoadMenu(calc.hInstance, lpMenuId);
|
|
SetMenu(hwnd, hMenu);
|
|
update_menu(hwnd);
|
|
|
|
for (n=0; n<SIZEOF(radio_setup); n++)
|
|
ShowWindow(GetDlgItem(hwnd, radio_setup[n].idc), (radio_setup[n].mask & mask) ? SW_SHOW : SW_HIDE);
|
|
|
|
enable_allowed_controls(hwnd, base);
|
|
}
|
|
|
|
SendDlgItemMessage(hwnd, calc.base, BM_SETCHECK, BST_CHECKED, 0);
|
|
if (base == IDC_RADIO_DEC)
|
|
SendDlgItemMessage(hwnd, calc.degr, BM_SETCHECK, BST_CHECKED, 0);
|
|
else
|
|
SendDlgItemMessage(hwnd, calc.size, BM_SETCHECK, BST_CHECKED, 0);
|
|
}
|
|
|
|
static void update_memory_flag(HWND hWnd, BOOL mem_flag)
|
|
{
|
|
calc.is_memory = mem_flag;
|
|
SendDlgItemMessage(hWnd, IDC_TEXT_MEMORY, WM_SETTEXT, 0, (LPARAM)(mem_flag ? TEXT("M") : TEXT("")));
|
|
}
|
|
|
|
static void update_n_stats_items(HWND hWnd, TCHAR *buffer)
|
|
{
|
|
unsigned int n = SendDlgItemMessage(hWnd, IDC_LIST_STAT, LB_GETCOUNT, 0, 0);
|
|
|
|
_stprintf(buffer, TEXT("n=%d"), n);
|
|
SendDlgItemMessage(hWnd, IDC_TEXT_NITEMS, WM_SETTEXT, 0, (LPARAM)buffer);
|
|
}
|
|
|
|
static void clean_stat_list(void)
|
|
{
|
|
statistic_t *p = calc.stat;
|
|
|
|
while (p != NULL) {
|
|
statistic_t *s = p;
|
|
p = (statistic_t *)(p->next);
|
|
rpn_free(&s->num);
|
|
free(s);
|
|
}
|
|
calc.stat = p;
|
|
}
|
|
|
|
static void delete_stat_item(int n)
|
|
{
|
|
statistic_t *p = calc.stat;
|
|
statistic_t *s;
|
|
|
|
if (n == 0) {
|
|
calc.stat = (statistic_t *)p->next;
|
|
rpn_free(&p->num);
|
|
free(p);
|
|
} else {
|
|
s = (statistic_t *)p->next;
|
|
while (--n) {
|
|
p = s;
|
|
s = (statistic_t *)p->next;
|
|
}
|
|
p->next = s->next;
|
|
rpn_free(&s->num);
|
|
free(s);
|
|
}
|
|
}
|
|
|
|
static char *ReadConversion(const char *formula)
|
|
{
|
|
int len = strlen(formula);
|
|
char *str = (char *)malloc(len+3);
|
|
|
|
if (str == NULL)
|
|
return NULL;
|
|
|
|
str[0] = '(';
|
|
memcpy(str+1, formula, len);
|
|
str[len+1] = ')';
|
|
str[len+2] = '\0';
|
|
|
|
_tcscpy(calc.source, (*calc.buffer == _T('\0')) ? _T("0") : calc.buffer);
|
|
|
|
/* clear display content before proceeding */
|
|
calc.ptr = calc.buffer;
|
|
calc.buffer[0] = TEXT('\0');
|
|
|
|
return str;
|
|
}
|
|
|
|
static INT_PTR CALLBACK DlgStatProc(HWND hWnd, UINT msg, WPARAM wp, LPARAM lp)
|
|
{
|
|
TCHAR buffer[SIZEOF(calc.buffer)];
|
|
DWORD n;
|
|
|
|
switch (msg) {
|
|
case WM_INITDIALOG:
|
|
return TRUE;
|
|
case WM_COMMAND:
|
|
switch (LOWORD(wp)) {
|
|
case IDC_LIST_STAT:
|
|
if (HIWORD(wp) == CBN_DBLCLK)
|
|
SendMessage(hWnd, WM_COMMAND, (WPARAM)IDC_BUTTON_LOAD, 0);
|
|
return TRUE;
|
|
case IDC_BUTTON_RET:
|
|
SetFocus(GetDlgItem(GetParent(hWnd), IDC_BUTTON_FOCUS));
|
|
return TRUE;
|
|
case IDC_BUTTON_LOAD:
|
|
n = SendDlgItemMessage(hWnd, IDC_LIST_STAT, LB_GETCURSEL, 0, 0);
|
|
if (n == (DWORD)-1)
|
|
return TRUE;
|
|
PostMessage(GetParent(hWnd), WM_LOAD_STAT, (WPARAM)n, 0);
|
|
return TRUE;
|
|
case IDC_BUTTON_CD:
|
|
n = SendDlgItemMessage(hWnd, IDC_LIST_STAT, LB_GETCURSEL, 0, 0);
|
|
if (n == (DWORD)-1)
|
|
return TRUE;
|
|
SendDlgItemMessage(hWnd, IDC_LIST_STAT, LB_DELETESTRING, (WPARAM)n, 0);
|
|
update_n_stats_items(hWnd, buffer);
|
|
delete_stat_item(n);
|
|
return TRUE;
|
|
case IDC_BUTTON_CAD:
|
|
SendDlgItemMessage(hWnd, IDC_LIST_STAT, LB_RESETCONTENT, 0, 0);
|
|
clean_stat_list();
|
|
update_n_stats_items(hWnd, buffer);
|
|
return TRUE;
|
|
}
|
|
break;
|
|
case WM_CLOSE:
|
|
clean_stat_list();
|
|
DestroyWindow(hWnd);
|
|
return TRUE;
|
|
case WM_DESTROY:
|
|
PostMessage(GetParent(hWnd), WM_CLOSE_STATS, 0, 0);
|
|
return TRUE;
|
|
case WM_INSERT_STAT:
|
|
prepare_rpn_result(&(((statistic_t *)lp)->num),
|
|
buffer, SIZEOF(buffer),
|
|
((statistic_t *)lp)->base);
|
|
SendDlgItemMessage(hWnd, IDC_LIST_STAT, LB_ADDSTRING, 0, (LPARAM)buffer);
|
|
update_n_stats_items(hWnd, buffer);
|
|
return TRUE;
|
|
}
|
|
return FALSE;
|
|
}
|
|
|
|
static BOOL idm_2_idc(int idm, WPARAM *pIdc)
|
|
{
|
|
int x;
|
|
|
|
for (x=0; x<SIZEOF(upd); x++) {
|
|
if (upd[x].idm == idm)
|
|
{
|
|
*pIdc = (WPARAM)(upd[x].idc);
|
|
return TRUE;
|
|
}
|
|
}
|
|
return FALSE;
|
|
}
|
|
|
|
static void CopyMemToClipboard(void *ptr)
|
|
{
|
|
if(OpenClipboard(NULL)) {
|
|
HGLOBAL clipbuffer;
|
|
TCHAR *buffer;
|
|
|
|
EmptyClipboard();
|
|
clipbuffer = GlobalAlloc(GMEM_DDESHARE, (_tcslen(ptr)+1)*sizeof(TCHAR));
|
|
buffer = (TCHAR *)GlobalLock(clipbuffer);
|
|
_tcscpy(buffer, ptr);
|
|
GlobalUnlock(clipbuffer);
|
|
#ifdef UNICODE
|
|
SetClipboardData(CF_UNICODETEXT,clipbuffer);
|
|
#else
|
|
SetClipboardData(CF_TEXT,clipbuffer);
|
|
#endif
|
|
CloseClipboard();
|
|
}
|
|
}
|
|
|
|
static void handle_copy_command(HWND hWnd)
|
|
{
|
|
TCHAR display[sizeof(calc.buffer)];
|
|
|
|
SendDlgItemMessage(hWnd, IDC_TEXT_OUTPUT, WM_GETTEXT, (WPARAM)SIZEOF(display), (LPARAM)display);
|
|
if (calc.base == IDC_RADIO_DEC && _tcschr(calc.buffer, _T('.')) == NULL)
|
|
display[_tcslen(display)-calc.sDecimal_len] = TEXT('\0');
|
|
CopyMemToClipboard(display);
|
|
}
|
|
|
|
static char *ReadClipboard(void)
|
|
{
|
|
char *buffer = NULL;
|
|
|
|
if (OpenClipboard(NULL)) {
|
|
HANDLE hData = GetClipboardData(CF_TEXT);
|
|
char *fromClipboard;
|
|
|
|
if (hData != NULL) {
|
|
fromClipboard = (char *)GlobalLock(hData);
|
|
if (strlen(fromClipboard))
|
|
buffer = _strupr(_strdup(fromClipboard));
|
|
GlobalUnlock( hData );
|
|
}
|
|
CloseClipboard();
|
|
}
|
|
return buffer;
|
|
}
|
|
|
|
static char *handle_sequence_input(HWND hwnd, sequence_t *seq)
|
|
{
|
|
char *ptr = seq->ptr;
|
|
int ch, x;
|
|
|
|
ch = *ptr++;
|
|
if (ch == '\\')
|
|
PostMessage(hwnd, WM_COMMAND, (WPARAM)IDC_BUTTON_DAT, 0);
|
|
else
|
|
if (ch == ':') {
|
|
ch = *ptr;
|
|
if (ch != '\0')
|
|
ptr++;
|
|
switch (ch) {
|
|
case 'C': PostMessage(hwnd, WM_COMMAND, (WPARAM)IDC_BUTTON_MC, 0); break;
|
|
case 'E': PostMessage(hwnd, WM_COMMAND, (WPARAM)IDC_BUTTON_EXP,0); break;
|
|
case 'M': PostMessage(hwnd, WM_COMMAND, (WPARAM)IDC_BUTTON_MS, 0); break;
|
|
case 'P': PostMessage(hwnd, WM_COMMAND, (WPARAM)IDC_BUTTON_MP, 0); break;
|
|
case 'Q': PostMessage(hwnd, WM_COMMAND, (WPARAM)IDC_BUTTON_CANC, 0); break;
|
|
case 'R': PostMessage(hwnd, WM_COMMAND, (WPARAM)IDC_BUTTON_MR, 0); break;
|
|
}
|
|
} else
|
|
if (ch == '$') {
|
|
calc.ptr =
|
|
_tcscpy(calc.buffer, calc.source) +
|
|
_tcslen(calc.source);
|
|
} else {
|
|
for (x=0; x<SIZEOF(key2code); x++) {
|
|
if (!(key2code[x].mask & BITMASK_IS_ASCII) ||
|
|
(key2code[x].mask & BITMASK_IS_CTRL))
|
|
continue;
|
|
if (key2code[x].key == ch) {
|
|
PostMessage(hwnd, WM_COMMAND, (WPARAM)key2code[x].idc, 0);
|
|
break;
|
|
}
|
|
}
|
|
}
|
|
seq->ptr = ptr;
|
|
if (*ptr != '\0')
|
|
PostMessage(hwnd, seq->wm_msg, 0, 0);
|
|
else {
|
|
free(seq->data);
|
|
seq->data = seq->ptr = ptr = NULL;
|
|
}
|
|
return ptr;
|
|
}
|
|
|
|
static void run_dat_sta(calc_number_t *a)
|
|
{
|
|
statistic_t *s = (statistic_t *)malloc(sizeof(statistic_t));
|
|
statistic_t *p = calc.stat;
|
|
|
|
rpn_alloc(&s->num);
|
|
rpn_copy(&s->num, a);
|
|
s->base = calc.base;
|
|
s->next = NULL;
|
|
if (p == NULL)
|
|
calc.stat = s;
|
|
else {
|
|
while (p->next != NULL)
|
|
p = (statistic_t *)(p->next);
|
|
p->next = s;
|
|
}
|
|
PostMessage(calc.hStatWnd, WM_INSERT_STAT, 0, (LPARAM)s);
|
|
}
|
|
|
|
static void run_mp(calc_number_t *c)
|
|
{
|
|
calc_node_t cn;
|
|
|
|
cn.number = *c;
|
|
cn.base = calc.base;
|
|
run_operator(&calc.memory, &calc.memory, &cn, RPN_OPERATOR_ADD);
|
|
update_memory_flag(calc.hWnd, TRUE);
|
|
}
|
|
|
|
static void run_mm(calc_number_t *c)
|
|
{
|
|
calc_node_t cn;
|
|
|
|
cn.number = *c;
|
|
cn.base = calc.base;
|
|
run_operator(&calc.memory, &calc.memory, &cn, RPN_OPERATOR_SUB);
|
|
update_memory_flag(calc.hWnd, TRUE);
|
|
}
|
|
|
|
static void run_ms(calc_number_t *c)
|
|
{
|
|
rpn_copy(&calc.memory.number, c);
|
|
calc.memory.base = calc.base;
|
|
update_memory_flag(calc.hWnd, rpn_is_zero(&calc.memory.number) ? FALSE : TRUE);
|
|
}
|
|
|
|
static void run_mw(calc_number_t *c)
|
|
{
|
|
calc_number_t tmp;
|
|
|
|
rpn_copy(&tmp, &calc.memory.number);
|
|
rpn_copy(&calc.memory.number, c);
|
|
calc.memory.base = calc.base;
|
|
if (calc.is_memory)
|
|
rpn_copy(c, &tmp);
|
|
update_memory_flag(calc.hWnd, rpn_is_zero(&calc.memory.number) ? FALSE : TRUE);
|
|
}
|
|
|
|
static statistic_t *upload_stat_number(int n)
|
|
{
|
|
statistic_t *p = calc.stat;
|
|
|
|
if (p == NULL)
|
|
return p;
|
|
|
|
while (n--) {
|
|
p = (statistic_t *)(p->next);
|
|
if (p == NULL)
|
|
return p;
|
|
}
|
|
|
|
#ifndef ENABLE_MULTI_PRECISION
|
|
if (calc.base != p->base) {
|
|
if (calc.base == IDC_RADIO_DEC)
|
|
calc.code.f = (double)p->num.i;
|
|
else {
|
|
calc.code.i = (__int64)p->num.f;
|
|
apply_int_mask(&calc.code);
|
|
}
|
|
} else
|
|
#endif
|
|
rpn_copy(&calc.code, &p->num);
|
|
|
|
calc.is_nan = FALSE;
|
|
|
|
return p;
|
|
}
|
|
|
|
static void run_pow(calc_number_t *number)
|
|
{
|
|
exec_infix2postfix(number, RPN_OPERATOR_POW);
|
|
}
|
|
|
|
static void run_sqr(calc_number_t *number)
|
|
{
|
|
exec_infix2postfix(number, RPN_OPERATOR_SQR);
|
|
}
|
|
|
|
static void run_fe(calc_number_t *number)
|
|
{
|
|
calc.sci_out = ((calc.sci_out != FALSE) ? FALSE : TRUE);
|
|
}
|
|
|
|
static void handle_context_menu(HWND hWnd, WPARAM wp, LPARAM lp)
|
|
{
|
|
TCHAR text[64];
|
|
HMENU hMenu = CreatePopupMenu();
|
|
BOOL idm;
|
|
|
|
LoadString(calc.hInstance, IDS_QUICKHELP, text, SIZEOF(text));
|
|
AppendMenu(hMenu, MF_STRING | MF_ENABLED, IDM_HELP_HELP, text);
|
|
idm = TrackPopupMenu( hMenu,
|
|
TPM_LEFTALIGN | TPM_TOPALIGN | TPM_RETURNCMD | TPM_RIGHTBUTTON,
|
|
LOWORD(lp),
|
|
HIWORD(lp),
|
|
0,
|
|
hWnd,
|
|
NULL);
|
|
DestroyMenu(hMenu);
|
|
#ifndef DISABLE_HTMLHELP_SUPPORT
|
|
if (idm) {
|
|
HH_POPUP popup;
|
|
|
|
memset(&popup, 0, sizeof(popup));
|
|
popup.cbStruct = sizeof(HH_POPUP);
|
|
popup.clrForeground = 1;
|
|
popup.clrBackground = -1;
|
|
popup.pt.x = LOWORD(lp);
|
|
popup.pt.y = HIWORD(lp);
|
|
popup.rcMargins.top = -1;
|
|
popup.rcMargins.bottom = -1;
|
|
popup.rcMargins.left = -1;
|
|
popup.rcMargins.right = -1;
|
|
popup.idString = GetWindowLongPtr((HWND)wp, GWL_ID);
|
|
HtmlHelp((HWND)wp, HTMLHELP_PATH("/popups.txt"), HH_DISPLAY_TEXT_POPUP, (DWORD_PTR)&popup);
|
|
}
|
|
#else
|
|
(void)idm;
|
|
#endif
|
|
}
|
|
|
|
static void run_canc(calc_number_t *c)
|
|
{
|
|
flush_postfix();
|
|
rpn_zero(c);
|
|
/* clear also scientific display modes */
|
|
calc.sci_out = FALSE;
|
|
calc.sci_in = FALSE;
|
|
/* clear state of inv and hyp flags */
|
|
SendDlgItemMessage(calc.hWnd, IDC_CHECK_INV, BM_SETCHECK, 0, 0);
|
|
SendDlgItemMessage(calc.hWnd, IDC_CHECK_HYP, BM_SETCHECK, 0, 0);
|
|
}
|
|
|
|
static void run_rpar(calc_number_t *c)
|
|
{
|
|
exec_closeparent(c);
|
|
}
|
|
|
|
static void run_lpar(calc_number_t *c)
|
|
{
|
|
exec_infix2postfix(c, RPN_OPERATOR_PARENT);
|
|
}
|
|
|
|
static LRESULT CALLBACK SubclassButtonProc(HWND hWnd, WPARAM wp, LPARAM lp)
|
|
{
|
|
LPDRAWITEMSTRUCT dis = (LPDRAWITEMSTRUCT)lp;
|
|
DWORD dwStyle;
|
|
UINT dwText;
|
|
TCHAR text[64];
|
|
int dx, dy, len;
|
|
SIZE size;
|
|
POINT pt;
|
|
|
|
if(dis->CtlType == ODT_BUTTON) {
|
|
/*
|
|
* little exception: 1/x has different color
|
|
* in standard and scientific modes
|
|
*/
|
|
if ((calc.layout == CALC_LAYOUT_STANDARD ||
|
|
calc.layout == CALC_LAYOUT_CONVERSION) &&
|
|
IDC_BUTTON_RX == dis->CtlID) {
|
|
SetTextColor(dis->hDC, CALC_CLR_BLUE);
|
|
} else
|
|
for (dx=0; dx<SIZEOF(key2code); dx++) {
|
|
if (key2code[dx].idc == dis->CtlID) {
|
|
SetTextColor(dis->hDC, key2code[dx].col);
|
|
break;
|
|
}
|
|
}
|
|
/* button text to write */
|
|
len = GetWindowText(dis->hwndItem, text, SIZEOF(text));
|
|
/* default state: unpushed & enabled */
|
|
dwStyle = 0;
|
|
dwText = 0;
|
|
if ((dis->itemState & ODS_DISABLED))
|
|
dwText = DSS_DISABLED;
|
|
if ((dis->itemState & ODS_SELECTED))
|
|
dwStyle = DFCS_PUSHED;
|
|
|
|
DrawFrameControl(dis->hDC, &dis->rcItem, DFC_BUTTON, DFCS_BUTTONPUSH | dwStyle);
|
|
GetTextExtentPoint32(dis->hDC, text, len, &size);
|
|
dx = ((dis->rcItem.right-dis->rcItem.left) - size.cx) >> 1;
|
|
dy = ((dis->rcItem.bottom-dis->rcItem.top) - size.cy) >> 1;
|
|
if ((dwStyle & DFCS_PUSHED)) {
|
|
dx++;
|
|
dy++;
|
|
}
|
|
pt.x = dis->rcItem.left + dx;
|
|
pt.y = dis->rcItem.top + dy;
|
|
DrawState(dis->hDC, NULL, NULL, (LPARAM)text, 0, pt.x, pt.y, size.cx, size.cy, DST_TEXT | dwText);
|
|
}
|
|
return 1L;
|
|
}
|
|
|
|
static INT_PTR CALLBACK DlgMainProc(HWND hWnd, UINT msg, WPARAM wp, LPARAM lp)
|
|
{
|
|
unsigned int x;
|
|
RECT rc;
|
|
HMENU hMenu;
|
|
|
|
switch (msg) {
|
|
case WM_DRAWITEM:
|
|
return SubclassButtonProc(hWnd, wp, lp);
|
|
|
|
case WM_INITDIALOG:
|
|
calc.hWnd=hWnd;
|
|
|
|
#ifdef USE_KEYBOARD_HOOK
|
|
calc.hKeyboardHook=SetWindowsHookEx(
|
|
WH_KEYBOARD,
|
|
KeyboardHookProc,
|
|
NULL,
|
|
GetCurrentThreadId()
|
|
);
|
|
#endif
|
|
rpn_zero(&calc.code);
|
|
calc.sci_out = FALSE;
|
|
calc.base = IDC_RADIO_DEC;
|
|
calc.size = IDC_RADIO_QWORD;
|
|
calc.degr = IDC_RADIO_DEG;
|
|
calc.ptr = calc.buffer;
|
|
calc.is_nan = FALSE;
|
|
enable_allowed_controls(hWnd, IDC_RADIO_DEC);
|
|
update_radio(hWnd, IDC_RADIO_DEC);
|
|
update_menu(hWnd);
|
|
display_rpn_result(hWnd, &calc.code);
|
|
update_memory_flag(hWnd, calc.is_memory);
|
|
/* remove keyboard focus */
|
|
SetFocus(GetDlgItem(hWnd, IDC_BUTTON_FOCUS));
|
|
/* set our calc icon */
|
|
SendMessage(hWnd, WM_SETICON, ICON_BIG, (LPARAM)LoadIcon(calc.hInstance, MAKEINTRESOURCE(IDI_CALC_BIG)));
|
|
SendMessage(hWnd, WM_SETICON, ICON_SMALL, (LPARAM)LoadIcon(calc.hInstance, MAKEINTRESOURCE(IDI_CALC_SMALL)));
|
|
|
|
/* Sets the state of the option to group digits */
|
|
hMenu = GetSubMenu(GetMenu(hWnd), 1);
|
|
CheckMenuItem(hMenu, IDM_VIEW_GROUP, (calc.usesep ? MF_CHECKED : MF_UNCHECKED));
|
|
|
|
/* update text for decimal button */
|
|
SendDlgItemMessage(hWnd, IDC_BUTTON_DOT, WM_SETTEXT, (WPARAM)0, (LPARAM)calc.sDecimal);
|
|
/* Fill combo box for conversion */
|
|
if (calc.layout == CALC_LAYOUT_CONVERSION)
|
|
ConvInit(hWnd);
|
|
/* Restore the window at the same position it was */
|
|
if (calc.x_coord >= 0 && calc.y_coord >= 0) {
|
|
int w, h, sw, sh;
|
|
|
|
GetWindowRect(hWnd, &rc);
|
|
w = rc.right-rc.left;
|
|
h = rc.bottom-rc.top;
|
|
sw = GetSystemMetrics(SM_CXSCREEN);
|
|
sh = GetSystemMetrics(SM_CYSCREEN);
|
|
if (calc.x_coord+w > sw) calc.x_coord = sw - w;
|
|
if (calc.y_coord+h > sh) calc.y_coord = sh - h;
|
|
MoveWindow(hWnd, calc.x_coord, calc.y_coord, w, h, FALSE);
|
|
}
|
|
break;
|
|
case WM_CTLCOLORSTATIC:
|
|
if ((HWND)lp == GetDlgItem(hWnd, IDC_TEXT_OUTPUT))
|
|
return (LRESULT)GetStockObject(WHITE_BRUSH);
|
|
break;
|
|
case WM_HANDLE_CLIPBOARD:
|
|
handle_sequence_input(hWnd, &calc.Clipboard);
|
|
return TRUE;
|
|
case WM_COMMAND:
|
|
/*
|
|
* if selection of category is changed, we must
|
|
* updatethe content of the "from/to" combo boxes.
|
|
*/
|
|
if (wp == MAKEWPARAM(IDC_COMBO_CATEGORY, CBN_SELCHANGE)) {
|
|
ConvAdjust(hWnd, SendDlgItemMessage(hWnd, IDC_COMBO_CATEGORY, CB_GETCURSEL, 0, 0));
|
|
return TRUE;
|
|
}
|
|
if (HIWORD(wp) != BN_CLICKED && HIWORD(wp) != BN_DBLCLK)
|
|
break;
|
|
/* avoid flicker if the user selects from keyboard */
|
|
if (GetFocus() != GetDlgItem(hWnd, IDC_BUTTON_FOCUS))
|
|
SetFocus(GetDlgItem(hWnd, IDC_BUTTON_FOCUS));
|
|
switch (LOWORD(wp)) {
|
|
case IDM_HELP_ABOUT:
|
|
{
|
|
TCHAR infotitle[100];
|
|
TCHAR infotext[200];
|
|
LoadString(calc.hInstance, IDS_CALC_NAME, infotitle, SIZEOF(infotitle));
|
|
LoadString(calc.hInstance, IDS_AUTHOR, infotext, SIZEOF(infotext));
|
|
ShellAbout(hWnd, infotitle, infotext, (HICON)LoadIcon(calc.hInstance, MAKEINTRESOURCE(IDI_CALC_BIG)));
|
|
return TRUE;
|
|
}
|
|
case IDM_HELP_HELP:
|
|
#ifndef DISABLE_HTMLHELP_SUPPORT
|
|
HtmlHelp(hWnd, HTMLHELP_PATH("/general_information.htm"), HH_DISPLAY_TOPIC, (DWORD_PTR)NULL);
|
|
#endif
|
|
return TRUE;
|
|
case IDM_VIEW_STANDARD:
|
|
if (calc.layout != CALC_LAYOUT_STANDARD)
|
|
{
|
|
calc.layout = CALC_LAYOUT_STANDARD;
|
|
calc.action = IDM_VIEW_STANDARD;
|
|
DestroyWindow(hWnd);
|
|
save_config();
|
|
|
|
CheckMenuRadioItem(GetMenu(hWnd),
|
|
IDM_VIEW_STANDARD,
|
|
IDM_VIEW_CONVERSION,
|
|
IDM_VIEW_STANDARD,
|
|
MF_BYCOMMAND);
|
|
}
|
|
return TRUE;
|
|
case IDM_VIEW_SCIENTIFIC:
|
|
if (calc.layout != CALC_LAYOUT_SCIENTIFIC)
|
|
{
|
|
calc.layout = CALC_LAYOUT_SCIENTIFIC;
|
|
calc.action = IDM_VIEW_SCIENTIFIC;
|
|
DestroyWindow(hWnd);
|
|
save_config();
|
|
|
|
CheckMenuRadioItem(GetMenu(hWnd),
|
|
IDM_VIEW_STANDARD,
|
|
IDM_VIEW_CONVERSION,
|
|
IDM_VIEW_SCIENTIFIC,
|
|
MF_BYCOMMAND);
|
|
}
|
|
return TRUE;
|
|
case IDM_VIEW_CONVERSION:
|
|
if (calc.layout != CALC_LAYOUT_CONVERSION)
|
|
{
|
|
calc.layout = CALC_LAYOUT_CONVERSION;
|
|
calc.action = IDM_VIEW_CONVERSION;
|
|
DestroyWindow(hWnd);
|
|
save_config();
|
|
|
|
CheckMenuRadioItem(GetMenu(hWnd),
|
|
IDM_VIEW_STANDARD,
|
|
IDM_VIEW_CONVERSION,
|
|
IDM_VIEW_CONVERSION,
|
|
MF_BYCOMMAND);
|
|
}
|
|
return TRUE;
|
|
case IDM_VIEW_HEX:
|
|
case IDM_VIEW_DEC:
|
|
case IDM_VIEW_OCT:
|
|
case IDM_VIEW_BIN:
|
|
case IDM_VIEW_DEG:
|
|
case IDM_VIEW_RAD:
|
|
case IDM_VIEW_GRAD:
|
|
case IDM_VIEW_QWORD:
|
|
case IDM_VIEW_DWORD:
|
|
case IDM_VIEW_WORD:
|
|
case IDM_VIEW_BYTE:
|
|
{
|
|
WPARAM idc;
|
|
if(idm_2_idc(LOWORD(wp), &idc))
|
|
{
|
|
SendMessage(hWnd, WM_COMMAND, idc, 0);
|
|
return TRUE;
|
|
}
|
|
return FALSE;
|
|
}
|
|
case IDM_EDIT_COPY:
|
|
handle_copy_command(hWnd);
|
|
return TRUE;
|
|
case IDM_EDIT_PASTE:
|
|
if (calc.Clipboard.data != NULL)
|
|
break;
|
|
calc.Clipboard.data = ReadClipboard();
|
|
if (calc.Clipboard.data != NULL) {
|
|
/* clear the content of the display before pasting */
|
|
PostMessage(hWnd, WM_COMMAND, IDC_BUTTON_CE, 0);
|
|
calc.Clipboard.ptr = calc.Clipboard.data;
|
|
calc.Clipboard.wm_msg = WM_HANDLE_CLIPBOARD;
|
|
handle_sequence_input(hWnd, &calc.Clipboard);
|
|
}
|
|
return TRUE;
|
|
case IDM_VIEW_GROUP:
|
|
calc.usesep = (calc.usesep ? FALSE : TRUE);
|
|
update_menu(hWnd);
|
|
update_lcd_display(hWnd);
|
|
save_config();
|
|
return TRUE;
|
|
case IDC_BUTTON_CONVERT:
|
|
ConvExecute(hWnd);
|
|
return TRUE;
|
|
case IDC_BUTTON_CE: {
|
|
calc_number_t tmp;
|
|
rpn_zero(&tmp);
|
|
display_rpn_result(hWnd, &tmp);
|
|
}
|
|
return TRUE;
|
|
case IDC_RADIO_DEC:
|
|
case IDC_RADIO_HEX:
|
|
case IDC_RADIO_OCT:
|
|
case IDC_RADIO_BIN:
|
|
/* GNU WINDRES is bugged so I must always force radio update */
|
|
/* (Fix for Win95/98) */
|
|
#ifdef _MSC_VER
|
|
if (calc.base == LOWORD(wp))
|
|
break;
|
|
#endif
|
|
calc.is_nan = FALSE;
|
|
update_radio(hWnd, LOWORD(wp));
|
|
return TRUE;
|
|
case IDC_RADIO_DEG:
|
|
case IDC_RADIO_RAD:
|
|
case IDC_RADIO_GRAD:
|
|
/* GNU WINDRES is bugged so I must always force radio update */
|
|
/* (Fix for Win95/98) */
|
|
#ifdef _MSC_VER
|
|
if (calc.degr == LOWORD(wp))
|
|
break;
|
|
#endif
|
|
calc.degr = LOWORD(wp);
|
|
calc.is_nan = FALSE;
|
|
update_menu(hWnd);
|
|
return TRUE;
|
|
case IDC_RADIO_QWORD:
|
|
case IDC_RADIO_DWORD:
|
|
case IDC_RADIO_WORD:
|
|
case IDC_RADIO_BYTE:
|
|
/* GNU WINDRES is bugged so I must always force radio update */
|
|
/* (Fix for Win95/98) */
|
|
#ifdef _MSC_VER
|
|
if (calc.size == LOWORD(wp))
|
|
break;
|
|
#endif
|
|
calc.size = LOWORD(wp);
|
|
calc.is_nan = FALSE;
|
|
update_menu(hWnd);
|
|
/*
|
|
* update the content of the display
|
|
*/
|
|
convert_text2number(&calc.code);
|
|
apply_int_mask(&calc.code);
|
|
display_rpn_result(hWnd, &calc.code);
|
|
return TRUE;
|
|
case IDC_BUTTON_1:
|
|
case IDC_BUTTON_2:
|
|
case IDC_BUTTON_3:
|
|
case IDC_BUTTON_4:
|
|
case IDC_BUTTON_5:
|
|
case IDC_BUTTON_6:
|
|
case IDC_BUTTON_7:
|
|
case IDC_BUTTON_8:
|
|
case IDC_BUTTON_9:
|
|
case IDC_BUTTON_0:
|
|
case IDC_BUTTON_DOT:
|
|
case IDC_BUTTON_A:
|
|
case IDC_BUTTON_B:
|
|
case IDC_BUTTON_C:
|
|
case IDC_BUTTON_D:
|
|
case IDC_BUTTON_E:
|
|
case IDC_BUTTON_F:
|
|
calc.is_nan = FALSE;
|
|
build_operand(hWnd, LOWORD(wp));
|
|
return TRUE;
|
|
case IDC_BUTTON_PERCENT:
|
|
case IDC_BUTTON_ADD:
|
|
case IDC_BUTTON_SUB:
|
|
case IDC_BUTTON_MULT:
|
|
case IDC_BUTTON_DIV:
|
|
case IDC_BUTTON_MOD:
|
|
case IDC_BUTTON_AND:
|
|
case IDC_BUTTON_OR:
|
|
case IDC_BUTTON_XOR:
|
|
case IDC_BUTTON_LSH:
|
|
case IDC_BUTTON_RSH:
|
|
case IDC_BUTTON_EQU:
|
|
if (calc.is_nan) break;
|
|
/*
|
|
* LSH button holds the RSH function too with INV modifier,
|
|
* but since it's a two operand operator, it must be handled here.
|
|
*/
|
|
if (LOWORD(wp) == IDC_BUTTON_LSH &&
|
|
(get_modifiers(hWnd) & MODIFIER_INV)) {
|
|
PostMessage(hWnd, WM_COMMAND, MAKEWPARAM(IDC_BUTTON_RSH, BN_CLICKED), 0);
|
|
SendDlgItemMessage(hWnd, IDC_CHECK_INV, BM_SETCHECK, 0, 0);
|
|
break;
|
|
}
|
|
for (x=0; x<SIZEOF(operator_codes); x++) {
|
|
if (LOWORD(wp) == operator_codes[x]) {
|
|
convert_text2number(&calc.code);
|
|
|
|
if (calc.ptr == calc.buffer) {
|
|
if (calc.last_operator != x) {
|
|
if (x != RPN_OPERATOR_EQUAL)
|
|
exec_change_infix();
|
|
} else
|
|
if (x == RPN_OPERATOR_EQUAL) {
|
|
exec_infix2postfix(&calc.code, calc.prev_operator);
|
|
rpn_copy(&calc.code, &calc.prev);
|
|
} else
|
|
break;
|
|
}
|
|
|
|
/* if no change then quit silently, */
|
|
/* without display updates */
|
|
if (!exec_infix2postfix(&calc.code, x))
|
|
break;
|
|
|
|
display_rpn_result(hWnd, &calc.code);
|
|
break;
|
|
}
|
|
}
|
|
return TRUE;
|
|
case IDC_BUTTON_BACK:
|
|
if (calc.sci_in) {
|
|
if (calc.esp == 0) {
|
|
TCHAR *ptr;
|
|
|
|
calc.sci_in = FALSE;
|
|
ptr = _tcschr(calc.ptr, TEXT('e'));
|
|
if (ptr)
|
|
*ptr = TEXT('\0');
|
|
update_lcd_display(hWnd);
|
|
} else {
|
|
calc.esp /= 10;
|
|
build_operand(hWnd, IDC_STATIC);
|
|
}
|
|
} else
|
|
if (calc.ptr != calc.buffer) {
|
|
*--calc.ptr = TEXT('\0');
|
|
if (!_tcscmp(calc.buffer, TEXT("-")) ||
|
|
!_tcscmp(calc.buffer, TEXT("-0")) ||
|
|
!_tcscmp(calc.buffer, TEXT("0"))) {
|
|
calc.ptr = calc.buffer;
|
|
calc.buffer[0] = TEXT('\0');
|
|
}
|
|
update_lcd_display(hWnd);
|
|
}
|
|
return TRUE;
|
|
case IDC_BUTTON_MC:
|
|
rpn_zero(&calc.memory.number);
|
|
update_memory_flag(hWnd, FALSE);
|
|
return TRUE;
|
|
case IDC_BUTTON_MR:
|
|
if (calc.is_memory) {
|
|
calc.is_nan = FALSE;
|
|
rpn_copy(&calc.code, &calc.memory.number);
|
|
display_rpn_result(hWnd, &calc.code);
|
|
}
|
|
return TRUE;
|
|
case IDC_BUTTON_EXP:
|
|
if (calc.sci_in || calc.is_nan || calc.buffer == calc.ptr)
|
|
break;
|
|
calc.sci_in = TRUE;
|
|
calc.esp = 0;
|
|
build_operand(hWnd, IDC_STATIC);
|
|
return TRUE;
|
|
case IDC_BUTTON_SIGN:
|
|
if (calc.sci_in) {
|
|
calc.esp = 0-calc.esp;
|
|
build_operand(hWnd, IDC_STATIC);
|
|
} else {
|
|
if (calc.is_nan || calc.buffer[0] == TEXT('\0'))
|
|
break;
|
|
|
|
if (calc.buffer[0] == TEXT('-')) {
|
|
/* make the number positive */
|
|
memmove(calc.buffer, calc.buffer+1, sizeof(calc.buffer)-1);
|
|
if (calc.buffer != calc.ptr)
|
|
calc.ptr--;
|
|
} else {
|
|
/* if first char is '0' and no dot, it isn't valid */
|
|
if (calc.buffer[0] == TEXT('0') &&
|
|
calc.buffer[1] != TEXT('.'))
|
|
break;
|
|
/* make the number negative */
|
|
memmove(calc.buffer+1, calc.buffer, sizeof(calc.buffer)-1);
|
|
calc.buffer[0] = TEXT('-');
|
|
if (calc.buffer != calc.ptr)
|
|
calc.ptr++;
|
|
}
|
|
/* If the input buffer is empty, then
|
|
we change also the sign of calc.code
|
|
because it could be the result of a
|
|
previous calculation. */
|
|
if (calc.buffer == calc.ptr)
|
|
rpn_sign(&calc.code);
|
|
update_lcd_display(hWnd);
|
|
}
|
|
return TRUE;
|
|
case IDC_BUTTON_RIGHTPAR:
|
|
case IDC_BUTTON_LEFTPAR:
|
|
case IDC_BUTTON_CANC:
|
|
case IDC_BUTTON_MP:
|
|
case IDC_BUTTON_DAT:
|
|
case IDC_BUTTON_FE:
|
|
case IDC_BUTTON_DMS:
|
|
case IDC_BUTTON_SQRT:
|
|
case IDC_BUTTON_S:
|
|
case IDC_BUTTON_SUM:
|
|
case IDC_BUTTON_AVE:
|
|
case IDC_BUTTON_NF:
|
|
case IDC_BUTTON_LN:
|
|
case IDC_BUTTON_LOG:
|
|
case IDC_BUTTON_Xe2:
|
|
case IDC_BUTTON_Xe3:
|
|
case IDC_BUTTON_PI:
|
|
case IDC_BUTTON_NOT:
|
|
case IDC_BUTTON_RX:
|
|
case IDC_BUTTON_INT:
|
|
case IDC_BUTTON_SIN:
|
|
case IDC_BUTTON_COS:
|
|
case IDC_BUTTON_TAN:
|
|
case IDC_BUTTON_XeY:
|
|
case IDC_BUTTON_MS:
|
|
for (x=0; x<SIZEOF(function_table); x++) {
|
|
if (LOWORD(wp) == function_table[x].idc) {
|
|
rpn_callback1 cb = NULL;
|
|
|
|
/* test if NaN state is important or not */
|
|
if (calc.is_nan && function_table[x].check_nan) break;
|
|
/* otherwise, it's cleared */
|
|
calc.is_nan = FALSE;
|
|
|
|
switch (get_modifiers(hWnd) & function_table[x].range) {
|
|
case 0:
|
|
cb = function_table[x].direct;
|
|
break;
|
|
case MODIFIER_INV:
|
|
cb = function_table[x].inverse;
|
|
break;
|
|
case MODIFIER_HYP:
|
|
cb = function_table[x].hyperb;
|
|
break;
|
|
case MODIFIER_INV|MODIFIER_HYP:
|
|
cb = function_table[x].inv_hyp;
|
|
break;
|
|
}
|
|
if (cb != NULL) {
|
|
convert_text2number(&calc.code);
|
|
cb(&calc.code);
|
|
display_rpn_result(hWnd, &calc.code);
|
|
if (!(function_table[x].range & NO_CHAIN))
|
|
exec_infix2postfix(&calc.code, RPN_OPERATOR_NONE);
|
|
if (function_table[x].range & MODIFIER_INV)
|
|
SendDlgItemMessage(hWnd, IDC_CHECK_INV, BM_SETCHECK, 0, 0);
|
|
if (function_table[x].range & MODIFIER_HYP)
|
|
SendDlgItemMessage(hWnd, IDC_CHECK_HYP, BM_SETCHECK, 0, 0);
|
|
}
|
|
}
|
|
}
|
|
return TRUE;
|
|
case IDC_BUTTON_STA:
|
|
if (IsWindow(calc.hStatWnd))
|
|
break;
|
|
calc.hStatWnd = CreateDialog(calc.hInstance,
|
|
MAKEINTRESOURCE(IDD_DIALOG_STAT), hWnd, DlgStatProc);
|
|
if (calc.hStatWnd != NULL) {
|
|
enable_allowed_controls(hWnd, calc.base);
|
|
SendMessage(calc.hStatWnd, WM_SETFOCUS, 0, 0);
|
|
}
|
|
return TRUE;
|
|
}
|
|
break;
|
|
case WM_CLOSE_STATS:
|
|
enable_allowed_controls(hWnd, calc.base);
|
|
return TRUE;
|
|
case WM_LOAD_STAT:
|
|
if (upload_stat_number((int)LOWORD(wp)) != NULL)
|
|
display_rpn_result(hWnd, &calc.code);
|
|
return TRUE;
|
|
case WM_START_CONV:
|
|
x = LOWORD(lp);
|
|
calc.Convert[x].data = ReadConversion(calc.Convert[x].data);
|
|
if (calc.Convert[x].data != NULL) {
|
|
calc.Convert[x].ptr = calc.Convert[x].data;
|
|
PostMessage(hWnd, HIWORD(lp), 0, 0);
|
|
}
|
|
return TRUE;
|
|
case WM_HANDLE_FROM:
|
|
if (calc.is_nan)
|
|
break;
|
|
if (handle_sequence_input(hWnd, &calc.Convert[0]) == NULL)
|
|
PostMessage(hWnd, WM_START_CONV, 0,
|
|
MAKELPARAM(0x0001, WM_HANDLE_TO));
|
|
return TRUE;
|
|
case WM_HANDLE_TO:
|
|
if (!calc.is_nan)
|
|
handle_sequence_input(hWnd, &calc.Convert[1]);
|
|
return TRUE;
|
|
case WM_CLOSE:
|
|
calc.action = IDC_STATIC;
|
|
DestroyWindow(hWnd);
|
|
return TRUE;
|
|
case WM_DESTROY:
|
|
/* Get (x,y) position of the calculator */
|
|
GetWindowRect(hWnd, &rc);
|
|
calc.x_coord = rc.left;
|
|
calc.y_coord = rc.top;
|
|
#ifdef USE_KEYBOARD_HOOK
|
|
UnhookWindowsHookEx(calc.hKeyboardHook);
|
|
#endif
|
|
PostQuitMessage(0);
|
|
return TRUE;
|
|
case WM_CONTEXTMENU:
|
|
if ((HWND)wp != hWnd)
|
|
handle_context_menu(hWnd, wp, lp);
|
|
return TRUE;
|
|
case WM_ENTERMENULOOP:
|
|
calc.is_menu_on = TRUE;
|
|
/* Check if a valid format is available in the clipboard */
|
|
EnableMenuItem(GetSubMenu(GetMenu(hWnd), 0),
|
|
IDM_EDIT_PASTE,
|
|
MF_BYCOMMAND|
|
|
(IsClipboardFormatAvailable(CF_TEXT) ?
|
|
MF_ENABLED : MF_GRAYED));
|
|
break;
|
|
case WM_EXITMENULOOP:
|
|
calc.is_menu_on = FALSE;
|
|
break;
|
|
}
|
|
return FALSE;
|
|
}
|
|
|
|
#if defined(__GNUC__) && !defined(__REACTOS__)
|
|
int WINAPI WinMain(HINSTANCE hInstance, HINSTANCE hPrevInstance, LPSTR lpCmdLine, int nShowCmd)
|
|
#else
|
|
int WINAPI _tWinMain(HINSTANCE hInstance, HINSTANCE hPrevInstance, LPTSTR lpCmdLine, int nShowCmd)
|
|
#endif
|
|
{
|
|
MSG msg;
|
|
DWORD dwLayout;
|
|
|
|
InitCommonControls();
|
|
|
|
calc.hInstance = hInstance;
|
|
|
|
calc.x_coord = -1;
|
|
calc.y_coord = -1;
|
|
|
|
load_config();
|
|
start_rpn_engine();
|
|
|
|
do {
|
|
/* ignore hwnd: dialogs are already visible! */
|
|
if (calc.layout == CALC_LAYOUT_SCIENTIFIC)
|
|
dwLayout = IDD_DIALOG_SCIENTIFIC;
|
|
else if (calc.layout == CALC_LAYOUT_CONVERSION)
|
|
dwLayout = IDD_DIALOG_CONVERSION;
|
|
else
|
|
dwLayout = IDD_DIALOG_STANDARD;
|
|
|
|
/* This call will always fail if UNICODE for Win9x */
|
|
if (NULL == CreateDialog(hInstance, MAKEINTRESOURCE(dwLayout), NULL, DlgMainProc))
|
|
break;
|
|
|
|
while (GetMessage(&msg, NULL, 0, 0)) {
|
|
#ifndef USE_KEYBOARD_HOOK
|
|
if ((msg.message == WM_KEYUP ||
|
|
msg.message == WM_KEYDOWN) &&
|
|
!calc.is_menu_on)
|
|
process_vk_key(msg.wParam, msg.lParam);
|
|
#endif
|
|
TranslateMessage(&msg);
|
|
DispatchMessage(&msg);
|
|
}
|
|
} while (calc.action != IDC_STATIC);
|
|
|
|
stop_rpn_engine();
|
|
|
|
return 0;
|
|
}
|