📄 winecalc.c
字号:
/*
* WineCalc (winecalc.c)
*
* Copyright 2003 James Briggs
*
* This library is free software; you can redistribute it and/or
* modify it under the terms of the GNU Lesser General Public
* License as published by the Free Software Foundation; either
* version 2.1 of the License, or (at your option) any later version.
*
* This library is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public
* License along with this library; if not, write to the Free Software
* Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
*/
#include <stdio.h> // sprintf
#include <math.h>
#include <stdlib.h>
#include <windows.h>
#include <tchar.h>
// #include <commctrl.h>
#include "winecalc.h"
#include "dialog.h"
#include "stats.h"
#include "resource.h"
// lame M$ math library doesn't support hyp functions
//#ifdef _MSC_VER
#define atanh(X) atan(X)
#define asinh(X) asin(X)
#define acosh(X) acos(X)
//#endif
// How winecalc works
//
// 1. In the original calculator, numbers are "extended precision".
// We emulate with calcfloat (calcfloat floating point) for now.
// Note that recent M$ compilers 5.0 and later do not implement double float,
// and do not support 80-bit numbers. Max width is 64-bits.
//
// 2. 4 temp areas:
//
// i) current edit buffer value for keystrokes
// ii) computed value area for last computation
// iii) memory area for MR, MC, MS, M+
// iv) formatted display buffer
//
// 3. Memory Store works off current buffer, not value
//
// 4. display limit is 32 numbers plus 10 commas plus one period = 43 characters
//
// 5. original calc is better called SciCalc and saves settings in win.ini:
//
// [SciCalc]
// layout=1 (0 = scientific mode, 1 = basic mode)
// UseSep=1 (0 = no digits separator, 1 = enable digits separator)
//
// 6. Window Menus
//
// The menus know their own states, so we don't need to track them
// When switching to Standard Calculator Mode, number base is changed to Decimal and Trig Mode to Degrees,
// but Word Size Mode is unchanged
//
// 7. It would be nice to add command line parsing for batch files
//
// various display error messages
static TCHAR err_invalid [CALC_BUF_SIZE];
static TCHAR err_divide_by_zero [CALC_BUF_SIZE];
static TCHAR err_undefined [CALC_BUF_SIZE];
// calculator state is kept here
CALC calc;
static RECT rFiller;
static int keys[CALC_NS_COUNT]['f'+1]; // note: sparse array
// map from button press to calc[] index
// 0, ... 9, A, B, C, D, E, F,FE,DMS,SIN,COS,TAN,EXP, PI
static const int h[] = {
0, 0, 33, 34, 21, 22, 23, 10, 11, 12, 54, 55, 56 ,57, 58 ,59, 6, 17, 28, 39, 50, 18, 53 };
// enable status of various buttons on sci mode depending on number base
static const int btn_toggle[CALC_NS_COUNT][TOGGLE_COUNT] =
// 0, ... 9, A, B, C, D, E, F,FE,DMS,SIN,COS,TAN,EXP,PI
{
{ 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 0, 0, 0, 0, 0, 0, 0 },
{ 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 1, 1, 1 },
{ 1, 1, 1, 1, 1, 1, 1, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 },
{ 1, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 ,0 }
};
static int hms[] = { 64, 65, 66 };
static int hws[] = { 69, 70, 71, 72 };
static int sta[] = { 16, 27, 38, 49 };
static HMENU menus[3];
static TCHAR appname[40];
static int debug;
int parse(int wParam, int lParam);
HWND hWndDlgStats;
extern HWND hWndListBox;
HINSTANCE hInstance;
int WINAPI WinMain( HINSTANCE hInst, HINSTANCE hPrevInst, LPSTR cmdline, int cmdshow )
{
MSG msg;
WNDCLASS wc;
HWND hWnd;
HACCEL haccel;
TCHAR s[CALC_BUF_SIZE];
int r;
hInstance = hInst;
r = GetProfileString(TEXT("SciCalc"),
TEXT("layout"),
TEXT("0"),
s,
CALC_BUF_SIZE
);
calc.sciMode = _ttoi(s);
if (calc.sciMode != 0 &&
calc.sciMode != 1)
calc.sciMode = 1; // Standard Mode
r = GetProfileString(TEXT("SciCalc"),
TEXT("UseSep"),
TEXT("0"),
s,
CALC_BUF_SIZE
);
calc.digitGrouping = _ttoi(s);
if (calc.digitGrouping != 0 &&
calc.digitGrouping != 1)
calc.digitGrouping = 1;
calc.new = 1; // initialize struct values
if (!LoadString( hInst, IDS_APPNAME, appname, sizeof(appname) / sizeof(appname[0])))
exit(1);
if (!LoadString( hInst, IDS_ERR_INVALID_INPUT, err_invalid, sizeof(err_invalid) / sizeof(err_invalid[0])))
exit(1);
if (!LoadString( hInst, IDS_ERR_DIVIDE_BY_ZERO, err_divide_by_zero, sizeof(err_divide_by_zero) / sizeof(err_divide_by_zero[0])))
exit(1);
if (!LoadString( hInst, IDS_ERR_UNDEFINED, err_undefined, sizeof(err_undefined) / sizeof(err_undefined[0])))
exit(1);
wc.style = CS_HREDRAW | CS_VREDRAW;
wc.lpfnWndProc = MainProc;
wc.cbClsExtra = 0;
wc.cbWndExtra = 0;
wc.hInstance = hInst;
wc.hIcon = LoadIcon(hInst, MAKEINTRESOURCE(IDI_CALCICON));
wc.hCursor = LoadCursor( NULL, IDI_APPLICATION );
wc.hbrBackground = (HBRUSH)(COLOR_BTNFACE+1);
wc.lpszMenuName = NULL;
wc.lpszClassName = appname;
if (!RegisterClass(&wc)) exit(1);
hWnd = CreateWindow( appname,
appname,
WS_CLIPSIBLINGS | (WS_OVERLAPPEDWINDOW & ~WS_THICKFRAME & ~WS_MAXIMIZEBOX),
CW_USEDEFAULT,
CW_USEDEFAULT,
calc.sciMode ? CALC_STANDARD_WIDTH : CALC_SCIENTIFIC_WIDTH,
calc.sciMode ? CALC_STANDARD_HEIGHT : CALC_SCIENTIFIC_HEIGHT,
NULL,
NULL,
hInst,
NULL );
if (!hWnd)
exit(1);
ShowWindow( hWnd, cmdshow );
UpdateWindow( hWnd );
if (!(haccel = LoadAccelerators(hInst, TEXT("MAIN_MENU"))))
exit(1);
while( GetMessage(&msg, NULL, 0, 0) ) {
if (hWndDlgStats == 0 || !IsDialogMessage(hWndDlgStats, &msg)) {
if (!TranslateAccelerator( hWnd, haccel, &msg )) {
TranslateMessage( &msg );
DispatchMessage( &msg );
}
}
}
return msg.wParam;
}
LRESULT WINAPI MainProc( HWND hWnd, UINT msg, WPARAM wParam, LPARAM lParam)
{
HDC hdc;
PAINTSTRUCT ps;
switch (msg) {
case WM_CREATE:
calc.hInst = ((LPCREATESTRUCT) lParam)->hInstance;
calc.hWnd = hWnd;
InitLuts();
InitCalc( &calc );
InitMenus(calc.hInst);
if (calc.sciMode)
SetMenu(hWnd, menus[MENU_STD]);
else
SetMenu(hWnd, menus[MENU_SCIMS]);
calc_buffer_display(&calc);
return 0;
case WM_PAINT:
{
HDC hMemDC;
hdc = BeginPaint( hWnd, &ps );
hMemDC = CreateCompatibleDC( hdc );
DrawCalc( hdc, hMemDC, &ps, &calc );
DeleteDC( hMemDC );
EndPaint( hWnd, &ps );
return 0;
}
case WM_MOVE:
calc.pos.x = (unsigned) LOWORD(lParam);
calc.pos.y = (unsigned) HIWORD(lParam);
return 0;
case WM_DESTROY:
{
int r;
TCHAR s[CALC_BUF_SIZE];
_stprintf(s, TEXT("%d"), calc.sciMode);
r = WriteProfileString(TEXT("SciCalc"), TEXT("layout"), s);
_stprintf(s, TEXT("%d"), calc.digitGrouping);
r = WriteProfileString(TEXT("SciCalc"), TEXT("UseSep"), s);
}
DestroyCalc( &calc );
DestroyMenus();
PostQuitMessage( 0 );
return 0;
case WM_KEYDOWN:
switch (wParam) {
case VK_F1:
calc.next = 1;
MessageBox(hWnd, TEXT("No Help Available"), TEXT("Windows Help"), MB_OK);
return 0;
case VK_F2: // DWORD
calc.next = 1;
if (!calc.sciMode) {
if (calc.numBase == NBASE_DECIMAL)
SendMessage(hWnd, WM_COMMAND, ID_CALC_MS_DEGREES, lParam);
else
SendMessage(hWnd, WM_COMMAND, ID_CALC_WS_DWORD, lParam);
}
return 0;
case VK_F3: // WORD
calc.next = 1;
if (!calc.sciMode) {
if (calc.numBase == NBASE_DECIMAL)
SendMessage(hWnd, WM_COMMAND, ID_CALC_MS_RADIANS, lParam);
else
SendMessage(hWnd, WM_COMMAND, ID_CALC_WS_WORD, lParam);
}
return 0;
case VK_F4: // Byte
// Grad
calc.next = 1;
if (!calc.sciMode) {
if (calc.numBase == NBASE_DECIMAL)
SendMessage(hWnd, WM_COMMAND, ID_CALC_MS_GRADS, lParam);
else
SendMessage(hWnd, WM_COMMAND, ID_CALC_WS_BYTE, lParam);
}
return 0;
case VK_F5: // Hex
calc.next = 1;
if (!calc.sciMode)
SendMessage(hWnd, WM_COMMAND, ID_CALC_NS_HEX, lParam);
return 0;
case VK_F6: // Decimal
calc.next = 1;
if (!calc.sciMode)
SendMessage(hWnd, WM_COMMAND, ID_CALC_NS_DEC, lParam);
return 0;
case VK_F7: // Octal
calc.next = 1;
if (!calc.sciMode)
SendMessage(hWnd, WM_COMMAND, ID_CALC_NS_OCT, lParam);
return 0;
case VK_F8: // Binary
calc.next = 1;
if (!calc.sciMode)
SendMessage(hWnd, WM_COMMAND, ID_CALC_NS_BIN, lParam);
return 0;
case VK_F12: // QWORD
calc.next = 1;
if (!calc.sciMode)
SendMessage(hWnd, WM_COMMAND, ID_CALC_WS_QWORD, lParam);
return 0;
case VK_F9: // +/-
if (!calc.sciMode)
SendMessage(hWnd, WM_CHAR, 'Z', lParam);
return 0;
case VK_INSERT: // Dat
calc.next = 1;
SendMessage(hWndListBox, LB_INSERTSTRING, -1, (LPARAM)calc.buffer);
InvalidateRect(hWndDlgStats, NULL, TRUE); // update list count at bottom edge of dialog
UpdateWindow(hWndDlgStats);
return 0;
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -