eigenmath/MainXP.cpp

2384 lines
43 KiB
C++

/* Eigenmath by George Weigt
This file does all the things required by the Windows API.
The starting point for a symbolic computation is in run.c
Input is scanned in scan.c
Expression evaluation is done in eval.c
Output is formatted in cmdisplay.c
The window display code is in window.c
*/
#include "stdafx.h"
#include <commdlg.h>
#include <stdio.h>
#define _USE_MATH_DEFINES // for MS C++
#include <math.h>
#include <time.h>
#include "help.h"
extern void run(char *);
extern void clear(void);
extern void draw_display(void);
extern void printstr(char *);
extern void update_cmd_history(char *);
extern void echo_input(char *);
extern void print_mem_info(void);
extern char *get_cmd_history(void);
void update_display(void);
int line_height = 20;
int left_margin = 5;
int right_margin = 5;
int main_client_width;
int main_client_height;
static int scroll_bar_width;
int display_x;
int display_y;
int display_width;
int display_height;
int max_x;
int max_y;
int total_w;
int total_h;
int update_display_request;
extern int esc_flag;
static int running;
static unsigned int timer;
static int edit_mode;
HINSTANCE hinst;
HINSTANCE hInst;
HWND main_window;
HWND input_window;
HWND edit_window;
HWND hscroll;
HWND vscroll;
#define NBUTTON 8
HWND button[NBUTTON];
HDC draw_hdc;
HDC run_hdc;
HMENU main_menu;
#define NFONT 11
HFONT display_font[NFONT];
struct text_metric {
int ascent, descent, width;
} text_metric[NFONT];
#define SMALL_FONT 1
#define DEFAULT_FONT 2
#define TIMES_FONT 3
#define ITALIC_TIMES_FONT 4
#define SYMBOL_FONT 5
#define ITALIC_SYMBOL_FONT 6
#define SMALL_TIMES_FONT 7
#define SMALL_ITALIC_TIMES_FONT 8
#define SMALL_SYMBOL_FONT 9
#define SMALL_ITALIC_SYMBOL_FONT 10
#define DRAW_HRULE 20
#define DRAW_LEFT_BRACKET 21
#define DRAW_RIGHT_BRACKET 22
#define DRAW_LINE 23
static void MyRegisterClass(HINSTANCE hInstance);
BOOL InitInstance(HINSTANCE, int);
LRESULT CALLBACK WndProc(HWND, UINT, WPARAM, LPARAM);
void do_up_arrow(void);
void do_down_arrow(void);
void do_fonts(void);
void fill_font_metric_array(void);
void do_more_setup(void);
static void goto_edit_mode(void);
static void goto_calc_mode(void);
static void move_input_window(void);
static void move_edit_window(void);
static void move_buttons(void);
static void move_scroll_bars(void);
static void create_menu(void);
static void do_vscroll(int, int);
static void do_hscroll(int, int);
static void update_scroll_bars(void);
static void move_bits_up(int);
static void move_bits_down(int);
static void run_script(void);
static void do_new(void);
static void do_save(void);
static void do_saveas(void);
static void do_open(void);
static void save_file(void);
static void do_page_setup(void);
static void do_print(void);
static void do_button(char *);
static void do_enter(void);
static void send_user_event(void);
static void activate_controls(void);
static void deactivate_controls(void);
static void process_user_event(void);
static void copy_all(void);
static void do_create_script(void);
void update_curr_cmd(char *);
enum {
ID_BASE = 40000,
// events
ID_USER_EVENT,
ID_ESC,
ID_ENTER,
ID_UP_ARROW,
ID_DOWN_ARROW,
// application buttons
ID_CLEAR,
ID_DERIVATIVE,
ID_DRAW,
ID_FLOAT,
ID_INTEGRAL,
ID_SIMPLIFY,
ID_EDIT_SCRIPT,
ID_RUN_SCRIPT,
// file menu
ID_NEW,
ID_OPEN,
ID_SAVE,
ID_SAVEAS,
ID_PAGE_SETUP,
ID_PRINT,
// edit menu
ID_UNDO,
ID_CUT,
ID_COPY,
ID_PASTE,
// asterisk menu
ID_COPY_DISPLAY,
ID_CREATE_SCRIPT,
// help menu
ID_HELP_ABS,
ID_HELP_ADJ,
ID_HELP_ARCCOS,
ID_HELP_ARCCOSH,
ID_HELP_ARCSIN,
ID_HELP_ARCSINH,
ID_HELP_ARCTAN,
ID_HELP_ARCTANH,
ID_HELP_ARG,
ID_HELP_BESSELJ,
ID_HELP_CHOOSE,
ID_HELP_CIRCEXP,
ID_HELP_COEFF,
ID_HELP_COFACTOR,
ID_HELP_CONJ,
ID_HELP_CONTRACT,
ID_HELP_COS,
ID_HELP_COSH,
ID_HELP_DEG,
ID_HELP_DENOMINATOR,
ID_HELP_DERIVATIVE,
ID_HELP_DET,
ID_HELP_DOT,
ID_HELP_ERF,
ID_HELP_ERFC,
ID_HELP_EVAL,
ID_HELP_EXP,
ID_HELP_EXPCOS,
ID_HELP_EXPSIN,
ID_HELP_FACTOR,
ID_HELP_FACTORIAL,
ID_HELP_FOR,
ID_HELP_GRADIENT,
ID_HELP_HERMITE,
ID_HELP_IMAG,
ID_HELP_INTEGRAL,
ID_HELP_INV,
ID_HELP_LAGUERRE,
ID_HELP_LEGENDRE,
ID_HELP_LOG,
ID_HELP_MAG,
ID_HELP_NUMERATOR,
ID_HELP_OUTER,
ID_HELP_POLAR,
ID_HELP_PRODUCT,
ID_HELP_QUOTIENT,
ID_HELP_REAL,
ID_HELP_RECT,
ID_HELP_SIN,
ID_HELP_SINH,
ID_HELP_SQRT,
ID_HELP_SUM,
ID_HELP_TAN,
ID_HELP_TANH,
ID_HELP_TAYLOR,
ID_HELP_TRANSPOSE,
ID_HELP_UNIT,
ID_HELP_ZERO,
};
#define NACCEL 7
ACCEL accel[NACCEL] = {
{FCONTROL, 15, ID_OPEN}, // ^O
{FCONTROL, 19, ID_SAVE}, // ^S
{FCONTROL, 26, ID_UNDO}, // ^Z
{FCONTROL, 24, ID_CUT}, // ^X
{FCONTROL, 3, ID_COPY}, // ^C
{FCONTROL, 22, ID_PASTE}, // ^V
{FCONTROL, 27, ID_ESC}, // ^[
};
int APIENTRY _tWinMain(HINSTANCE hInstance,
HINSTANCE hPrevInstance,
LPTSTR lpCmdLine,
int nCmdShow)
{
int tmp;
MSG msg;
HACCEL haccel;
hinst = hInstance;
MyRegisterClass(hInstance);
// Perform application initialization:
if (!InitInstance (hInstance, nCmdShow))
{
return FALSE;
}
do_fonts();
fill_font_metric_array();
create_menu();
do_more_setup();
haccel = CreateAcceleratorTable(accel, NACCEL);
SetTimer(main_window, 0, 1000, NULL);
while (1) {
tmp = GetMessage(&msg, NULL, 0, 0);
if (tmp < 1)
break;
tmp = TranslateAccelerator(main_window, haccel, &msg);
if (tmp == 0) {
TranslateMessage(&msg);
DispatchMessage(&msg);
}
if (msg.hwnd == input_window && msg.message == WM_KEYDOWN) {
switch (msg.wParam) {
case 13:
PostMessage(main_window, ID_ENTER, 0, 0);
break;
case VK_UP:
PostMessage(main_window, ID_UP_ARROW, 0, 0);
break;
case VK_DOWN:
PostMessage(main_window, ID_DOWN_ARROW, 0, 0);
break;
case VK_PRIOR:
PostMessage(
main_window,
WM_VSCROLL,
SB_PAGEUP,
(LPARAM) vscroll);
break;
case VK_NEXT:
PostMessage(
main_window,
WM_VSCROLL,
SB_PAGEDOWN,
(LPARAM) vscroll);
break;
case VK_HOME:
PostMessage(
main_window,
WM_VSCROLL,
SB_TOP,
(LPARAM) vscroll);
break;
case VK_END:
PostMessage(
main_window,
WM_VSCROLL,
SB_BOTTOM,
(LPARAM) vscroll);
break;
default:
break;
}
}
}
return (int) msg.wParam;
}
//
// FUNCTION: MyRegisterClass()
//
// PURPOSE: Registers the window class.
//
// COMMENTS:
//
// This function and its usage are only necessary if you want this code
// to be compatible with Win32 systems prior to the 'RegisterClassEx'
// function that was added to Windows 95. It is important to call this function
// so that the application will get 'well formed' small icons associated
// with it.
//
static void
MyRegisterClass(HINSTANCE hInstance)
{
static WNDCLASSEX wcex;
wcex.cbSize = sizeof(WNDCLASSEX);
wcex.style = CS_HREDRAW | CS_VREDRAW;
wcex.lpfnWndProc = (WNDPROC)WndProc;
wcex.cbClsExtra = 0;
wcex.cbWndExtra = 0;
wcex.hInstance = hInstance;
wcex.hIcon = LoadIcon(hInstance, (LPCSTR) IDI_ICON1);
//wcex.hIcon = CreateIcon(hInstance, 0, 0, 0, 0, NULL, NULL);
wcex.hCursor = LoadCursor(NULL, IDC_ARROW);
wcex.hbrBackground = (HBRUSH)(COLOR_WINDOW + 1);
wcex.lpszMenuName = NULL;
wcex.lpszClassName = "Eigenmath";
wcex.hIconSm = NULL;
RegisterClassEx(&wcex);
}
//
// FUNCTION: InitInstance(HANDLE, int)
//
// PURPOSE: Saves instance handle and creates main window
//
// COMMENTS:
//
// In this function, we save the instance handle in a global variable and
// create and display the main program window.
//
BOOL InitInstance(HINSTANCE hInstance, int nCmdShow)
{
hInst = hInstance; // Store instance handle in our global variable
main_window = CreateWindow(
"Eigenmath",
"Eigenmath 129",
WS_OVERLAPPEDWINDOW,
CW_USEDEFAULT, 0,
// CW_USEDEFAULT, 0,
800, 540,
NULL,
NULL,
hInstance,
NULL);
ShowWindow(main_window, nCmdShow);
UpdateWindow(main_window);
return TRUE;
}
static struct {
char *s;
long long id;
} main_button[NBUTTON] = {
{"Clear", ID_CLEAR},
{"Draw", ID_DRAW},
{"Simplify", ID_SIMPLIFY},
{"Float", ID_FLOAT},
{"Derivative", ID_DERIVATIVE},
{"Integral", ID_INTEGRAL},
{"Edit Script", ID_EDIT_SCRIPT},
{"Run Script", ID_RUN_SCRIPT},
};
void
do_more_setup(void)
{
int h, i, j, k, w, x, y;
RECT r;
GetClientRect(main_window, &r);
main_client_width = r.right;
main_client_height = r.bottom;
vscroll = CreateWindow(
"SCROLLBAR",
NULL,
WS_CHILD | WS_VISIBLE | SBS_VERT | SBS_RIGHTALIGN,
0, 0,
main_client_width, main_client_height - 3 * line_height,
main_window,
NULL,
hinst,
NULL);
GetWindowRect(vscroll, &r);
scroll_bar_width = r.right - r.left;
display_width = main_client_width - scroll_bar_width;
display_height = main_client_height - 3 * line_height - scroll_bar_width;
// move the scroll bar to adjust for its width
x = display_width;
y = 0;
w = scroll_bar_width;
h = display_height;
MoveWindow(vscroll, x, y, w, h, TRUE);
x = 0;
y = display_height;
w = display_width;
h = scroll_bar_width;
hscroll = CreateWindow(
"SCROLLBAR",
NULL,
WS_CHILD | WS_VISIBLE | SBS_HORZ,
x, y,
w, h,
main_window,
NULL,
hinst,
NULL);
x = 0;
y = main_client_height - 3 * line_height;
w = main_client_width;
h = line_height;
input_window = CreateWindow(
"EDIT",
NULL,
WS_CHILD | WS_VISIBLE | ES_AUTOHSCROLL,
x, y,
w, h,
main_window,
NULL,
hinst,
NULL);
SendMessage(input_window, WM_SETFONT, (WPARAM) display_font[DEFAULT_FONT], 0);
SetFocus(input_window);
edit_window = CreateWindow(
"EDIT",
NULL,
WS_CHILD | WS_VSCROLL | ES_MULTILINE | ES_AUTOVSCROLL | ES_WANTRETURN,
0, 0,
main_client_width, main_client_height - 2 * line_height,
main_window,
NULL,
hinst,
NULL);
SendMessage(edit_window, WM_SETFONT, (WPARAM) display_font[DEFAULT_FONT], 0);
// create buttons
for (i = 0; i < NBUTTON; i++) {
j = i * main_client_width / NBUTTON;
k = (i + 1) * main_client_width / NBUTTON;
button[i] = CreateWindow(
"BUTTON",
main_button[i].s,
WS_CHILD | WS_VISIBLE | BS_PUSHBUTTON,
j, main_client_height - 2 * line_height,
k - j, 2 * line_height,
main_window,
(HMENU) main_button[i].id,
hinst,
NULL);
SendMessage(
button[i],
WM_SETFONT,
(WPARAM) GetStockObject(ANSI_VAR_FONT),
0);
#if 0
button[2 * i + 1] = CreateWindow(
"BUTTON",
main_button[2 * i + 1].s,
WS_CHILD | WS_VISIBLE | BS_PUSHBUTTON,
j, main_client_height - line_height,
k - j, line_height,
main_window,
(HMENU) main_button[2 * i + 1].id,
hinst,
NULL);
SendMessage(
button[2 * i + 1],
WM_SETFONT,
(WPARAM) GetStockObject(ANSI_VAR_FONT),
0);
#endif
}
update_scroll_bars();
}
static struct {
char *s;
int id;
} menu[] = {
{"File", 0},
{"New", ID_NEW},
{"Open\tCtrl+O", ID_OPEN},
{"Save\tCtrl+S", ID_SAVE},
{"Save As", ID_SAVEAS},
//{"-", 0},
//{"Page Setup", ID_PAGE_SETUP},
//{"Print", ID_PRINT},
{0, 0},
{"Edit", 0},
{"Undo\tCtrl+Z", ID_UNDO},
{"Cut\tCtrl+X", ID_CUT},
{"Copy\tCtrl+C", ID_COPY},
{"Paste\tCtrl+V", ID_PASTE},
{0, 0},
{"*", 0},
{"Copy display to clipboard", ID_COPY_DISPLAY},
{"Create script from command history", ID_CREATE_SCRIPT},
{0, 0},
{"Help", 0},
{"Complex number functions", 0},
{"arg", ID_HELP_ARG},
{"conj", ID_HELP_CONJ},
{"imag", ID_HELP_IMAG},
{"mag", ID_HELP_MAG},
{"polar", ID_HELP_POLAR},
{"real", ID_HELP_REAL},
{"rect", ID_HELP_RECT},
{0, 0},
{"Polynomial functions", 0},
{"coeff", ID_HELP_COEFF},
{"deg", ID_HELP_DEG},
{"quotient", ID_HELP_QUOTIENT},
{0, 0},
{"Linear algebra functions", 0},
{"adj", ID_HELP_ADJ},
{"cofactor", ID_HELP_COFACTOR},
{"contract", ID_HELP_CONTRACT},
{"det", ID_HELP_DET},
{"dot", ID_HELP_DOT},
{"inv", ID_HELP_INV},
{"outer", ID_HELP_OUTER},
{"transpose", ID_HELP_TRANSPOSE},
{"unit", ID_HELP_UNIT},
{"zero", ID_HELP_ZERO},
{0, 0},
{"Calculus functions", 0},
{"derivative", ID_HELP_DERIVATIVE},
{"gradient", ID_HELP_GRADIENT},
{"integral", ID_HELP_INTEGRAL},
{"taylor", ID_HELP_TAYLOR},
{0, 0},
{"Exponential functions", 0},
{"circexp", ID_HELP_CIRCEXP},
{"exp", ID_HELP_EXP},
{"expcos", ID_HELP_EXPCOS},
{"expsin", ID_HELP_EXPSIN},
{"log", ID_HELP_LOG},
{0, 0},
{"Circular functions", 0},
{"arccos", ID_HELP_ARCCOS},
{"arcsin", ID_HELP_ARCSIN},
{"arctan", ID_HELP_ARCTAN},
{"cos", ID_HELP_COS},
{"sin", ID_HELP_SIN},
{"tan", ID_HELP_TAN},
{0, 0},
{"Hyperbolic functions", 0},
{"arccosh", ID_HELP_ARCCOSH},
{"arcsinh", ID_HELP_ARCSINH},
{"arctanh", ID_HELP_ARCTANH},
{"cosh", ID_HELP_COSH},
{"sinh", ID_HELP_SINH},
{"tanh", ID_HELP_TANH},
{0, 0},
{"Special functions", 0},
{"besselj", ID_HELP_BESSELJ},
{"hermite", ID_HELP_HERMITE},
{"laguerre", ID_HELP_LAGUERRE},
{"legendre", ID_HELP_LEGENDRE},
{0, 0},
{"Other functions", 0},
{"abs", ID_HELP_ABS},
{"choose", ID_HELP_CHOOSE},
{"denominator", ID_HELP_DENOMINATOR},
{"erf", ID_HELP_ERF},
{"erfc", ID_HELP_ERFC},
{"eval", ID_HELP_EVAL},
{"factor", ID_HELP_FACTOR},
{"factorial", ID_HELP_FACTORIAL},
{"for", ID_HELP_FOR},
{"numerator", ID_HELP_NUMERATOR},
{"product", ID_HELP_PRODUCT},
{"sqrt", ID_HELP_SQRT},
{"sum", ID_HELP_SUM},
{0, 0},
{0, 0}, // end of 'examples' menu
{0, 0}, // end
};
static void
create_menu(void)
{
int k = 0, level = 0;
char *s[2];
HMENU hmenu[3];
hmenu[0] = CreateMenu();
while (1) {
if (menu[k].s == NULL) {
if (level) {
AppendMenu(
hmenu[level - 1],
MF_POPUP | MF_ENABLED | MF_STRING,
(UINT_PTR) hmenu[level],
s[level - 1]);
level--;
k++;
continue;
} else
break;
}
if (menu[k].s[0] == '-') {
AppendMenu(
hmenu[level],
MF_SEPARATOR,
0,
0);
k++;
continue;
}
if (menu[k].id == 0) {
s[level] = menu[k].s;
level++;
hmenu[level] = CreatePopupMenu();
k++;
continue;
}
AppendMenu(
hmenu[level],
MF_ENABLED | MF_STRING,
menu[k].id,
menu[k].s);
k++;
}
SetMenu(main_window, hmenu[0]);
main_menu = hmenu[0];
}
// FUNCTION: WndProc(HWND, unsigned, WORD, LONG)
//
// PURPOSE: Processes messages for the main window.
//
// WM_COMMAND - process the application menu
// WM_PAINT - Paint the main window
// WM_DESTROY - post a quit message and return
//
//
LRESULT CALLBACK WndProc(HWND hWnd, UINT message, WPARAM wParam, LPARAM lParam)
{
int hi, lo;
PAINTSTRUCT ps;
RECT r;
switch (message) {
case ID_USER_EVENT:
process_user_event();
break;
case ID_ENTER:
if (running)
break;
do_enter();
break;
case ID_UP_ARROW:
if (running)
break;
do_up_arrow();
break;
case ID_DOWN_ARROW:
if (running)
break;
do_down_arrow();
break;
case WM_TIMER:
if (running == 1)
send_user_event();
break;
case WM_ACTIVATE:
if (edit_mode == 0)
SetFocus(input_window);
else
return DefWindowProc(hWnd, message, wParam, lParam);
break;
case WM_SIZE:
GetClientRect(main_window, &r);
main_client_width = r.right;
main_client_height = r.bottom;
display_width = main_client_width - scroll_bar_width;
display_height = main_client_height - 3 * line_height - scroll_bar_width;
move_input_window();
move_edit_window();
move_buttons();
move_scroll_bars();
max_y = total_h - display_height;
if (max_y < 0)
max_y = 0;
if (display_y > max_y)
display_y = max_y;
update_scroll_bars();
PostMessage(main_window, WM_PAINT, 0, 0);
break;
case WM_COMMAND:
hi = HIWORD(wParam);
lo = LOWORD(wParam);
switch (lo) {
case ID_ESC:
esc_flag = 1;
break;
case ID_NEW:
if (running)
break;
do_new();
break;
case ID_OPEN:
if (running)
break;
do_open();
break;
case ID_SAVE:
do_save();
break;
case ID_SAVEAS:
do_saveas();
break;
// case ID_PAGE_SETUP:
// do_page_setup();
// break;
// case ID_PRINT:
// do_print();
// break;
case ID_UNDO:
if (running)
break;
if (edit_mode == 0)
SendMessage(input_window, WM_UNDO, 0, 0);
else
SendMessage(edit_window, WM_UNDO, 0, 0);
break;
case ID_CUT:
if (running)
break;
if (edit_mode == 0)
SendMessage(input_window, WM_CUT, 0, 0);
else
SendMessage(edit_window, WM_CUT, 0, 0);
break;
case ID_COPY:
if (running)
break;
if (edit_mode == 0)
SendMessage(input_window, WM_COPY, 0, 0);
else
SendMessage(edit_window, WM_COPY, 0, 0);
break;
case ID_PASTE:
if (running)
break;
if (edit_mode == 0)
SendMessage(input_window, WM_PASTE, 0, 0);
else
SendMessage(edit_window, WM_PASTE, 0, 0);
break;
// "asterisk" pull-down menu
case ID_COPY_DISPLAY:
copy_all();
break;
case ID_CREATE_SCRIPT:
if (running)
break;
do_create_script();
break;
// linear algebra
case ID_HELP_ADJ:
HELP(help_adj);
break;
case ID_HELP_COFACTOR:
HELP(help_cofactor);
break;
case ID_HELP_CONTRACT:
HELP(help_contract);
break;
case ID_HELP_DET:
HELP(help_det);
break;
case ID_HELP_DOT:
HELP(help_dot);
break;
case ID_HELP_INV:
HELP(help_inv);
break;
case ID_HELP_OUTER:
HELP(help_outer);
break;
case ID_HELP_TRANSPOSE:
HELP(help_transpose);
break;
case ID_HELP_UNIT:
HELP(help_unit);
break;
case ID_HELP_ZERO:
HELP(help_zero);
break;
// calculus
case ID_HELP_DERIVATIVE:
HELP(help_derivative);
break;
case ID_HELP_GRADIENT:
HELP(help_gradient);
break;
case ID_HELP_INTEGRAL:
HELP(help_integral);
break;
// complex number functions
case ID_HELP_ARG:
HELP(help_arg);
break;
case ID_HELP_CONJ:
HELP(help_conj);
break;
case ID_HELP_IMAG:
HELP(help_imag);
break;
case ID_HELP_MAG:
HELP(help_mag);
break;
case ID_HELP_POLAR:
HELP(help_polar);
break;
case ID_HELP_REAL:
HELP(help_real);
break;
case ID_HELP_RECT:
HELP(help_rect);
break;
// circular functions
case ID_HELP_ARCCOS:
HELP(help_arccos);
break;
case ID_HELP_ARCSIN:
HELP(help_arcsin);
break;
case ID_HELP_ARCTAN:
HELP(help_arctan);
break;
case ID_HELP_COS:
HELP(help_cos);
break;
case ID_HELP_SIN:
HELP(help_sin);
break;
case ID_HELP_TAN:
HELP(help_tan);
break;
// hyperbolic functions
case ID_HELP_ARCCOSH:
HELP(help_arccosh);
break;
case ID_HELP_ARCSINH:
HELP(help_arcsinh);
break;
case ID_HELP_ARCTANH:
HELP(help_arctanh);
break;
case ID_HELP_COSH:
HELP(help_cosh);
break;
case ID_HELP_SINH:
HELP(help_sinh);
break;
case ID_HELP_TANH:
HELP(help_tanh);
break;
// special functions
case ID_HELP_BESSELJ:
HELP(help_besselj);
break;
case ID_HELP_HERMITE:
HELP(help_hermite);
break;
case ID_HELP_LAGUERRE:
HELP(help_laguerre);
break;
case ID_HELP_LEGENDRE:
HELP(help_legendre);
break;
// polynomial functions
case ID_HELP_COEFF:
HELP(help_coeff);
break;
case ID_HELP_DEG:
HELP(help_deg);
break;
case ID_HELP_QUOTIENT:
HELP(help_quotient);
break;
// other functions
case ID_HELP_ABS:
HELP(help_abs);
break;
case ID_HELP_CHOOSE:
HELP(help_choose);
break;
case ID_HELP_CIRCEXP:
HELP(help_circexp);
break;
case ID_HELP_DENOMINATOR:
HELP(help_denominator);
break;
case ID_HELP_ERF:
HELP(help_erf);
break;
case ID_HELP_ERFC:
HELP(help_erfc);
break;
case ID_HELP_EVAL:
HELP(help_eval);
break;
case ID_HELP_EXP:
HELP(help_exp);
break;
case ID_HELP_EXPCOS:
HELP(help_expcos);
break;
case ID_HELP_EXPSIN:
HELP(help_expsin);
break;
case ID_HELP_FACTOR:
HELP(help_factor);
break;
case ID_HELP_FACTORIAL:
HELP(help_factorial);
break;
case ID_HELP_FOR:
HELP(help_for);
break;
case ID_HELP_LOG:
HELP(help_log);
break;
case ID_HELP_NUMERATOR:
HELP(help_numerator);
break;
case ID_HELP_PRODUCT:
HELP(help_product);
break;
case ID_HELP_SQRT:
HELP(help_sqrt);
break;
case ID_HELP_SUM:
HELP(help_sum);
break;
case ID_HELP_TAYLOR:
HELP(help_taylor);
break;
// window buttons, clear, draw, etc.
case ID_CLEAR:
do_button("clear");
break;
case ID_DRAW:
do_button("draw");
break;
case ID_SIMPLIFY:
do_button("simplify");
break;
case ID_FLOAT:
do_button("float");
break;
case ID_DERIVATIVE:
do_button("derivative");
break;
case ID_INTEGRAL:
do_button("integral");
break;
case ID_EDIT_SCRIPT:
if (running)
break;
if (edit_mode == 0)
goto_edit_mode();
else
goto_calc_mode();
break;
case ID_RUN_SCRIPT:
run_script();
break;
default:
return DefWindowProc(hWnd, message, wParam, lParam);
}
break;
case WM_PAINT:
draw_hdc = BeginPaint(hWnd, &ps);
if (edit_mode == 0) {
SetBkMode(draw_hdc, TRANSPARENT);
draw_display();
update_scroll_bars();
}
// paint the little square between the scroll bars
r.left = display_width;
r.top = display_height;
r.right = r.left + scroll_bar_width + 1;
r.bottom = r.top + scroll_bar_width + 1;
FillRect(draw_hdc, &r, (HBRUSH) (COLOR_BTNFACE + 1));
EndPaint(hWnd, &ps);
break;
case WM_DESTROY:
PostQuitMessage(0);
break;
case WM_VSCROLL:
if ((HWND) lParam == vscroll)
do_vscroll(LOWORD(wParam), HIWORD(wParam));
else
return DefWindowProc(hWnd, message, wParam, lParam);
break;
case WM_HSCROLL:
if ((HWND) lParam == hscroll)
do_hscroll(LOWORD(wParam), HIWORD(wParam));
else
return DefWindowProc(hWnd, message, wParam, lParam);
break;
case WM_KEYDOWN:
if (edit_mode == 0)
switch (wParam) {
case VK_PRIOR:
SendMessage(
main_window,
WM_VSCROLL,
MAKELONG(SB_PAGEUP, 0),
(LPARAM) vscroll);
break;
case VK_NEXT:
SendMessage(
main_window,
WM_VSCROLL,
MAKELONG(SB_PAGEDOWN, 0),
(LPARAM) vscroll);
break;
default:
return DefWindowProc(hWnd, message, wParam, lParam);
}
else
return DefWindowProc(hWnd, message, wParam, lParam);
break;
default:
return DefWindowProc(hWnd, message, wParam, lParam);
}
return 0;
}
char *
get_curr_cmd(void)
{
int i, len;
char *s;
len = GetWindowTextLength(input_window);
s = (char *) malloc(len + 1);
GetWindowText(input_window, s, len + 1);
// trim trailing spaces
for (i = len - 1; i >= 0; i--) {
if (isspace(s[i]))
s[i] = 0;
else
break;
}
return s;
}
void
update_curr_cmd(char *s)
{
SetWindowText(input_window, s);
}
void
do_fonts(void)
{
static LOGFONT lf;
lf.lfQuality = ANTIALIASED_QUALITY;
lf.lfPitchAndFamily = FF_ROMAN + VARIABLE_PITCH;
lf.lfHeight = 36;
lf.lfItalic = FALSE;
lf.lfCharSet = ANSI_CHARSET;
strcpy(lf.lfFaceName, "Times");
display_font[TIMES_FONT] = CreateFontIndirect(&lf);
lf.lfItalic = TRUE;
lf.lfCharSet = ANSI_CHARSET;
strcpy(lf.lfFaceName, "Times");
display_font[ITALIC_TIMES_FONT] = CreateFontIndirect(&lf);
lf.lfItalic = FALSE;
lf.lfCharSet = SYMBOL_CHARSET;
strcpy(lf.lfFaceName, "Symbol");
display_font[SYMBOL_FONT] = CreateFontIndirect(&lf);
lf.lfItalic = TRUE;
lf.lfCharSet = SYMBOL_CHARSET;
strcpy(lf.lfFaceName, "Symbol");
display_font[ITALIC_SYMBOL_FONT] = CreateFontIndirect(&lf);
lf.lfHeight = 24;
lf.lfItalic = FALSE;
lf.lfCharSet = ANSI_CHARSET;
strcpy(lf.lfFaceName, "Times");
display_font[SMALL_TIMES_FONT] = CreateFontIndirect(&lf);
lf.lfItalic = TRUE;
lf.lfCharSet = ANSI_CHARSET;
strcpy(lf.lfFaceName, "Times");
display_font[SMALL_ITALIC_TIMES_FONT] = CreateFontIndirect(&lf);
lf.lfItalic = FALSE;
lf.lfCharSet = SYMBOL_CHARSET;
strcpy(lf.lfFaceName, "Symbol");
display_font[SMALL_SYMBOL_FONT] = CreateFontIndirect(&lf);
lf.lfItalic = TRUE;
lf.lfCharSet = SYMBOL_CHARSET;
strcpy(lf.lfFaceName, "Symbol");
display_font[SMALL_ITALIC_SYMBOL_FONT] = CreateFontIndirect(&lf);
// DEFAULT_FONT
lf.lfHeight = 20;
lf.lfItalic = FALSE;
lf.lfWeight = FW_BOLD;
lf.lfCharSet = ANSI_CHARSET;
lf.lfQuality = ANTIALIASED_QUALITY;
lf.lfPitchAndFamily = FF_MODERN;
strcpy(lf.lfFaceName, "");
display_font[DEFAULT_FONT] = CreateFontIndirect(&lf);
// SMALL_FONT
display_font[SMALL_FONT] = (HFONT) GetStockObject(ANSI_FIXED_FONT);
}
void
fill_font_metric_array(void)
{
int i;
HDC hdc;
TEXTMETRIC tm;
hdc = GetDC(main_window);
for (i = 1; i < NFONT; i++) {
SelectObject(hdc, display_font[i]);
GetTextMetrics(hdc, &tm);
text_metric[i].ascent = tm.tmAscent;
text_metric[i].descent = tm.tmDescent;
text_metric[i].width = tm.tmAveCharWidth;
}
ReleaseDC(main_window, hdc);
}
static void
goto_edit_mode(void)
{
int i;
if (edit_mode == 1)
return;
edit_mode = 1;
// dim buttons
for (i = 0; i < NBUTTON - 2; i++)
EnableWindow(button[i], FALSE);
SendMessage(button[NBUTTON - 2], WM_SETTEXT, 0, (LPARAM) "<<");
ShowWindow(input_window, SW_HIDE);
ShowWindow(vscroll, SW_HIDE);
ShowWindow(hscroll, SW_HIDE);
ShowWindow(edit_window, SW_SHOW);
SetFocus(edit_window);
}
static void
goto_calc_mode(void)
{
int i;
if (edit_mode == 0)
return;
edit_mode = 0;
// light buttons
for (i = 0; i < NBUTTON - 2; i++)
EnableWindow(button[i], TRUE);
SendMessage(button[NBUTTON - 2], WM_SETTEXT, 0, (LPARAM) "Edit Script");
ShowWindow(edit_window, SW_HIDE);
ShowWindow(input_window, SW_SHOW);
ShowWindow(vscroll, SW_SHOW);
ShowWindow(hscroll, SW_SHOW);
SetFocus(input_window);
}
// TextOut can only handle 4,000 or so chars at a time
void
draw_text(int font, int x, int y, char *s, int len)
{
SelectObject(draw_hdc, display_font[font]);
TextOut(draw_hdc, x, y, s, len);
#if 0
SIZE size;
SelectObject(draw_hdc, display_font[font]);
while (len > 4000) {
TextOut(hdc, x, y, s, 4000);
GetTextExtentPoint32(hdc, s, 4000, &size);
x += size.cx;
s += 4000;
len -= 4000;
}
if (len)
TextOut(draw_hdc, x, y, (char *) s, len);
#endif
}
int
text_width(int font, char *s)
{
SIZE size;
SelectObject(run_hdc, display_font[font]);
GetTextExtentPoint32(run_hdc, s, (int) strlen(s), &size);
return (int) size.cx;
}
void
get_height_width(int *h, int *w, int font, char *s)
{
SIZE size;
SelectObject(run_hdc, display_font[font]);
GetTextExtentPoint32(run_hdc, s, (int) strlen(s), &size);
*h = size.cy;
*w = size.cx;
}
void
draw_hrule(int x, int y, int w)
{
MoveToEx(draw_hdc, x, y, NULL);
LineTo(draw_hdc, x + w, y);
}
// Example: w = 5, h = 7
//
// 0 1 2 3 4
// 0 B x x x A
// 1 x
// 2 x
// 3 x
// 4 x
// 5 x
// 6 C x x x D
//
// A = (x + w - 1, y)
//
// B = (x, y)
//
// C = (x, y + h - 1)
//
// D = (x + w - 1, y + h - 1)
//
// Since the last pixel is not drawn, use D = (x + w, y + h - 1).
void
draw_left_bracket(int x, int y, int w, int h)
{
MoveToEx(draw_hdc, x + w - 1, y, NULL);
LineTo(draw_hdc, x, y);
LineTo(draw_hdc, x, y + h - 1);
LineTo(draw_hdc, x + w, y + h - 1);
// extra stem width
MoveToEx(draw_hdc, x + 1, y, NULL);
LineTo(draw_hdc, x + 1, y + h - 1);
}
// Example: w = 5, h = 7
//
// 0 1 2 3 4
// 0 A x x x B
// 1 x
// 2 x
// 3 x
// 4 x
// 5 x
// 6 D x x x C
//
// A = (x, y)
//
// B = (x + w - 1, y)
//
// C = (x + w - 1, y + h - 1)
//
// D = (x, y + h - 1)
//
// Since the last pixel is not drawn, use D = (x - 1, y + h - 1).
void
draw_right_bracket(int x, int y, int w, int h)
{
MoveToEx(draw_hdc, x, y, NULL);
LineTo(draw_hdc, x + w - 1, y);
LineTo(draw_hdc, x + w - 1, y + h - 1);
LineTo(draw_hdc, x - 1, y + h - 1);
// extra stem width
MoveToEx(draw_hdc, x + w - 2, y, NULL);
LineTo(draw_hdc, x + w - 2, y + h - 1);
}
void
draw_line(int x1, int y1, int x2, int y2)
{
MoveToEx(draw_hdc, x1, y1, NULL);
LineTo(draw_hdc, x2, y2);
}
static int draw_mode;
static HPEN original_pen;
static HBRUSH original_brush;
void
use_graph_pen(void)
{
HPEN pen;
HBRUSH brush;
LOGBRUSH tmp;
if (draw_mode == 1)
return;
draw_mode = 1;
pen = CreatePen(PS_SOLID, 1, RGB(0, 0, 0));
tmp.lbStyle = BS_SOLID;
tmp.lbColor = RGB(0, 0, 0);
tmp.lbHatch = 0;
brush = CreateBrushIndirect(&tmp);
original_pen = (HPEN) SelectObject(draw_hdc, pen);
original_brush = (HBRUSH) SelectObject(draw_hdc, brush);
}
void
use_normal_pen(void)
{
HPEN pen;
HBRUSH brush;
if (draw_mode == 0)
return;
draw_mode = 0;
pen = (HPEN) SelectObject(draw_hdc, original_pen);
brush = (HBRUSH) SelectObject(draw_hdc, original_brush);
DeleteObject(pen);
DeleteObject(brush);
}
void
draw_box(int x1, int y1, int x2, int y2)
{
#if 1
HBRUSH brush;
LOGBRUSH tmp;
use_normal_pen();
tmp.lbStyle = BS_SOLID;
tmp.lbColor = RGB(255, 255, 239);
tmp.lbHatch = 0;
brush = CreateBrushIndirect(&tmp);
SelectObject(draw_hdc, brush);
Rectangle(draw_hdc, x1, y1, x2 + 1, y2 + 1);
brush = (HBRUSH) GetStockObject(WHITE_BRUSH);
brush = (HBRUSH) SelectObject(draw_hdc, brush);
DeleteObject(brush);
#else
MoveToEx(draw_hdc, x1, y1, NULL);
LineTo(draw_hdc, x2, y1);
LineTo(draw_hdc, x2, y2);
LineTo(draw_hdc, x1, y2);
LineTo(draw_hdc, x1, y1);
#endif
}
void
draw_point(int x, int dx, int y, int dy)
{
//Rectangle(draw_hdc, x - 1, y - 1, x + 2, y + 2);
RECT r;
r.left = x + dx - 1;
r.top = y + dy - 1;
r.right = x + dx + 2;
r.bottom = y + dy + 2;
if (dx == 0)
r.left++;
if (dy == 0)
r.top++;
if (dx == 300)
r.right--;
if (dy == 300)
r.bottom--;
FillRect(draw_hdc, &r, (HBRUSH) GetStockObject(BLACK_BRUSH));
}
static void
move_input_window(void)
{
int h, w, x, y;
x = 0;
y = main_client_height - 3 * line_height;
w = main_client_width;
h = line_height;
MoveWindow(input_window, x, y, w, h, TRUE);
}
static void
move_edit_window(void)
{
int h, w, x, y;
x = 0;
y = 0;
w = main_client_width;
h = main_client_height - 2 * line_height;
MoveWindow(edit_window, x, y, w, h, TRUE);
}
static void
move_buttons(void)
{
int i, j, k;
for (i = 0; i < NBUTTON; i++) {
j = i * main_client_width / NBUTTON;
k = (i + 1) * main_client_width / NBUTTON;
MoveWindow(
button[i],
j, main_client_height - 2 * line_height,
k - j, 2 * line_height,
TRUE);
}
}
static void
move_scroll_bars(void)
{
int h, w, x, y;
x = display_width;
y = 0;
w = scroll_bar_width,
h = display_height;
MoveWindow(vscroll, x, y, w, h, TRUE);
x = 0;
y = display_height;
w = display_width;
h = scroll_bar_width;
MoveWindow(hscroll, x, y, w, h, TRUE);
}
// Cannot use "pos" because it is too small (16 bits). Use GetScrollInfo instead.
static void
do_vscroll(int cmd, int pos)
{
int y;
SCROLLINFO info;
y = display_y;
switch (cmd) {
case SB_TOP:
display_y = 0;
break;
case SB_BOTTOM:
display_y = max_y;
break;
case SB_LINEUP:
display_y -= line_height;
break;
case SB_LINEDOWN:
display_y += line_height;
break;
case SB_PAGEUP:
display_y -= display_height;
break;
case SB_PAGEDOWN:
display_y += display_height;
break;
case SB_THUMBTRACK:
case SB_THUMBPOSITION:
info.cbSize = sizeof (SCROLLINFO);
info.fMask = SIF_TRACKPOS;
GetScrollInfo(vscroll, SB_CTL, &info);
display_y = info.nTrackPos;
break;
default:
break;
}
if (display_y < 0)
display_y = 0;
if (display_y > max_y)
display_y = max_y;
if (display_y < y)
move_bits_down(y - display_y);
if (display_y > y)
move_bits_up(display_y - y);
update_scroll_bars();
}
static void
move_bits_down(int dy)
{
RECT r;
HRGN hrgn;
//ScrollWindowEx(main_window, 0, dy, NULL, NULL, NULL, NULL, SW_ERASE | SW_INVALIDATE);
//return;
draw_hdc = GetDC(main_window);
if (dy < display_height)
BitBlt(
draw_hdc,
0, dy,
display_width, display_height - dy,
draw_hdc,
0, 0,
SRCCOPY);
else
dy = display_height;
r.left = 0;
r.top = 0;
r.right = display_width;
r.bottom = dy;
// have to draw instead of update to stay ahead of next scroll event
// display bitmap has to be valid before next scroll event
FillRect(draw_hdc, &r, (HBRUSH) GetStockObject(WHITE_BRUSH));
hrgn = CreateRectRgnIndirect(&r);
SelectClipRgn(draw_hdc, hrgn);
SetBkMode(draw_hdc, TRANSPARENT);
draw_display();
DeleteObject(hrgn);
ReleaseDC(main_window, draw_hdc);
}
static void
move_bits_up(int dy)
{
RECT r;
HRGN hrgn;
//ScrollWindowEx(main_window, 0, -dy, NULL, NULL, NULL, NULL, SW_ERASE | SW_INVALIDATE);
//return;
draw_hdc = GetDC(main_window);
if (dy < display_height)
BitBlt(
draw_hdc,
0, 0,
display_width, display_height - dy,
draw_hdc,
0, dy,
SRCCOPY);
else
dy = display_height;
r.left = 0;
r.top = display_height - dy;
r.right = display_width;
r.bottom = display_height;
// have to draw instead of update to stay ahead of next scroll event
// display bitmap has to be valid before next scroll event
FillRect(draw_hdc, &r, (HBRUSH) GetStockObject(WHITE_BRUSH));
hrgn = CreateRectRgnIndirect(&r);
SelectClipRgn(draw_hdc, hrgn);
SetBkMode(draw_hdc, TRANSPARENT);
draw_display();
DeleteObject(hrgn);
ReleaseDC(main_window, draw_hdc);
}
// According to MS documentation...
//
// MaxScrollPos = MaxRangeValue - (PageSize - 1)
//
// Since we want MaxScrollPos = max_y, we set nMax = max_y + display_height - 1.
//
// nMax = max_y + display_height - 1
//
// nPage = display_height
//
// MaxScrollPos = max_y + display_height - 1 - (display_height - 1) = max_y
static void
update_scroll_bars(void)
{
SCROLLINFO info;
info.cbSize = sizeof (SCROLLINFO);
info.fMask = SIF_ALL;
info.nMin = 0;
info.nMax = max_y + display_height - 1;
info.nPage = display_height;
info.nPos = display_y;
SetScrollInfo(vscroll, SB_CTL, &info, TRUE);
info.cbSize = sizeof (SCROLLINFO);
info.fMask = SIF_ALL;
info.nMin = 0;
info.nMax = max_x + display_width - 1;
info.nPage = display_width;
info.nPos = display_x;
SetScrollInfo(hscroll, SB_CTL, &info, TRUE);
}
// Cannot use "pos" because it is too small (16 bits). Use GetScrollInfo instead.
static void move_bits_left(int);
static void move_bits_right(int);
void
do_hscroll(int cmd, int pos)
{
int x;
SCROLLINFO info;
x = display_x;
switch (cmd) {
case SB_LEFT:
display_x = 0;
break;
case SB_RIGHT:
display_x = max_x;
break;
case SB_LINELEFT:
display_x -= line_height;
break;
case SB_LINERIGHT:
display_x += line_height;
break;
case SB_PAGELEFT:
display_x -= display_width;
break;
case SB_PAGERIGHT:
display_x += display_width;
break;
case SB_THUMBTRACK:
case SB_THUMBPOSITION:
info.cbSize = sizeof (SCROLLINFO);
info.fMask = SIF_TRACKPOS;
GetScrollInfo(hscroll, SB_CTL, &info);
display_x = info.nTrackPos;
break;
default:
break;
}
if (display_x < 0)
display_x = 0;
if (display_x > max_x)
display_x = max_x;
if (display_x < x)
move_bits_right(x - display_x);
if (display_x > x)
move_bits_left(display_x - x);
update_scroll_bars();
}
static void
move_bits_right(int dx)
{
int h, w, x, y;
RECT r;
HRGN hrgn;
draw_hdc = GetDC(main_window);
if (dx < display_width) {
// Example: dx = 2
//
// x x x x x x x x x x
// x x x
// x x x
// x x x
// x x x
// x x x x x x x x x x
// \ \
// \ \
// \ \
// \ \
// x x x x x x x x x x
// x x x
// x x x
// x x x
// x x x
// x x x x x x x x x x
// dimensions of dst rectangle
x = dx;
y = 0;
w = display_width - dx;
h = display_height;
BitBlt(
draw_hdc,
x, y,
w, h,
draw_hdc,
0, 0, // src
SRCCOPY);
} else
dx = display_width;
// set update rectangle
if (dx == 1) dx = 2; // bug in windows 2000
r.left = 0;
r.top = 0;
r.right = dx;
r.bottom = display_height;
// have to draw instead of update to stay ahead of next scroll event
// display bitmap has to be valid before next scroll event
FillRect(draw_hdc, &r, (HBRUSH) GetStockObject(WHITE_BRUSH));
hrgn = CreateRectRgnIndirect(&r);
SelectClipRgn(draw_hdc, hrgn);
SetBkMode(draw_hdc, TRANSPARENT);
draw_display();
DeleteObject(hrgn);
ReleaseDC(main_window, draw_hdc);
}
static void
move_bits_left(int dx)
{
int h, w, x, y;
RECT r;
HRGN hrgn;
draw_hdc = GetDC(main_window);
if (dx < display_width) {
// Example: dx = 2
//
// x x x x x x x x x x
// x x x
// x x x
// x x x
// x x x
// x x x x x x x x x x
// / /
// / /
// / /
// / /
// x x x x x x x x x x
// x x x
// x x x
// x x x
// x x x
// x x x x x x x x x x
// dimensions of dst rectangle
x = 0;
y = 0;
w = display_width - dx;
h = display_height;
BitBlt(
draw_hdc,
x, y,
w, h,
draw_hdc,
dx, 0, // src
SRCCOPY);
} else
dx = display_width;
// set update rectangle
if (dx == 1) dx = 2; // bug in windows 2000
r.left = display_width - dx;
r.top = 0;
r.right = display_width;
r.bottom = display_height;
// have to draw instead of update to stay ahead of next scroll event
// display bitmap has to be valid before next scroll event
FillRect(draw_hdc, &r, (HBRUSH) GetStockObject(WHITE_BRUSH));
hrgn = CreateRectRgnIndirect(&r);
SelectClipRgn(draw_hdc, hrgn);
SetBkMode(draw_hdc, TRANSPARENT);
draw_display();
DeleteObject(hrgn);
ReleaseDC(main_window, draw_hdc);
}
#if 0
void
redraw_window_now(void)
{
RECT r;
HRGN hrgn;
draw_hdc = GetDC(main_window);
r.left = 0;
r.top = 0;
r.right = display_width;
r.bottom = display_height;
FillRect(draw_hdc, &r, (HBRUSH) GetStockObject(WHITE_BRUSH));
hrgn = CreateRectRgnIndirect(&r);
SelectClipRgn(draw_hdc, hrgn);
SetBkMode(draw_hdc, TRANSPARENT);
draw_display();
DeleteObject(hrgn);
ReleaseDC(main_window, draw_hdc);
update_scroll_bars();
SetFocus(input_window);
}
#endif
void
update_display(void)
{
RECT r;
if (update_display_request == 0)
return;
r.left = 0;
r.top = 0;
r.right = display_width;
r.bottom = display_height;
RedrawWindow(main_window, &r, NULL, RDW_ERASE | RDW_INVALIDATE);
}
OPENFILENAME ofn;
char filename[1000];
// f = fopen(s, "rb"); // must do rb for msdos files else \r changes to \n
static void
do_create_script(void)
{
char *s;
*filename = 0;
s = get_cmd_history();
SetWindowText(edit_window, s);
free(s);
goto_edit_mode();
}
static void
do_new(void)
{
char buf[1];
*filename = 0;
buf[0] = 0;
SetWindowText(edit_window, buf);
goto_edit_mode();
}
static void
do_open(void)
{
int len;
FILE *f;
char *buf;
ofn.lStructSize = sizeof (OPENFILENAME);
ofn.hwndOwner = main_window;
ofn.lpstrFile = filename;
ofn.nMaxFile = 1000;
if (GetOpenFileName(&ofn) == 0)
return;
buf = (char *) malloc(100001);
if (buf == 0)
return;
f = fopen(filename, "rb"); // must do rb for msdos files else \r changes to \n
if (f == 0) {
free(buf);
return;
}
len = (int) fread(buf, 1, 100000, f);
fclose(f);
buf[len] = 0;
SetWindowText(edit_window, buf);
free(buf);
goto_edit_mode();
}
static void
do_save(void)
{
if (*filename)
save_file();
else
do_saveas();
}
static void
do_saveas(void)
{
ofn.lStructSize = sizeof (OPENFILENAME);
ofn.hwndOwner = main_window;
ofn.lpstrFile = filename;
ofn.nMaxFile = 1000;
if (GetSaveFileName(&ofn) == 0)
return;
save_file();
}
static void
save_file(void)
{
int len;
FILE *f;
char *buf;
len = GetWindowTextLength(edit_window);
buf = (char *) malloc(len + 1);
if (buf == 0) {
printstr("Error writing file.\n");
update_display();
return;
}
GetWindowText(edit_window, buf, len + 1);
f = fopen(filename, "wb");
if (f == NULL) {
free(buf);
printstr("Error writing file.\n");
update_display();
return;
}
if (fwrite(buf, 1, len, f) != len) {
printstr("Error writing file.\n");
update_display();
}
fclose(f);
free(buf);
}
PAGESETUPDLG page;
static void
do_page_setup(void)
{
page.lStructSize = sizeof page;
page.hwndOwner = main_window;
PageSetupDlg(&page);
}
PRINTDLG pd;
static void
do_print(void)
{
if (pd.lStructSize == 0) {
pd.lStructSize = sizeof pd;
pd.hwndOwner = main_window;
pd.hDevMode = NULL;
pd.hDevNames = NULL;
pd.Flags = PD_USEDEVMODECOPIESANDCOLLATE | PD_RETURNDC;
pd.nCopies = 1;
pd.nFromPage = 1;
pd.nToPage = 1;
pd.nMinPage = 1;
pd.nMaxPage = 0xffff;
}
if (PrintDlg(&pd) == TRUE) {
DeleteDC(pd.hDC);
}
}
static char *inp;
static HANDLE thread;
static DWORD WINAPI
task(LPVOID p)
{
run_hdc = GetDC(main_window);
run(inp);
ReleaseDC(main_window, run_hdc);
running = 2;
send_user_event();
return 0;
}
static void
create_task(void)
{
DWORD id;
timer = (unsigned int) time(NULL);
running = 1;
thread = CreateThread(
NULL,
1024 * 1024,
task,
NULL,
0,
&id);
}
static void
send_user_event(void)
{
PostMessage(main_window, ID_USER_EVENT, 0, 0);
}
static void
process_user_event(void)
{
unsigned int dt;
static char buf[1000];
if (running == 0)
return;
if (running == 2) {
CloseHandle(thread);
update_curr_cmd("");
update_display();
activate_controls();
running = 0;
return;
}
dt = (unsigned int) time(NULL) - timer;
if (dt > 1) {
deactivate_controls();
sprintf(buf, "Working on it for %d seconds. Esc might interrupt, otherwise close this window to quit.", dt);
update_curr_cmd(buf);
update_display();
}
}
static int shunted;
static void
deactivate_controls(void)
{
int i;
if (shunted == 1)
return;
shunted = 1;
for (i = 0; i < NBUTTON; i++)
EnableWindow(button[i], FALSE);
EnableWindow(input_window, FALSE);
}
static void
activate_controls(void)
{
int i;
if (shunted == 0)
return;
shunted = 0;
for (i = 0; i < NBUTTON; i++)
EnableWindow(button[i], TRUE);
EnableWindow(input_window, TRUE);
SetFocus(input_window);
}
static void
do_enter(void)
{
if (running || edit_mode)
return;
if (inp)
free(inp);
inp = get_curr_cmd();
update_cmd_history(inp); // reset history pointer no matter what
if (*inp == 0)
return;
echo_input(inp);
update_curr_cmd("");
create_task();
}
static void
do_button(char *s)
{
char *tmp;
if (edit_mode == 0)
SetFocus(input_window);
if (running || edit_mode)
return;
if (inp)
free(inp);
inp = get_curr_cmd();
update_cmd_history(inp); // reset history pointer no matter what
if (*inp == 0) {
free(inp);
inp = (char *) malloc(strlen(s) + 7);
strcpy(inp, s);
} else {
tmp = (char *) malloc(strlen(s) + strlen(inp) + 3);
if (strcmp(s, "derivative") == 0)
strcpy(tmp, "d");
else
strcpy(tmp, s);
strcat(tmp, "(");
strcat(tmp, inp);
strcat(tmp, ")");
free(inp);
inp = tmp;
}
update_cmd_history(inp);
echo_input(inp);
update_curr_cmd("");
create_task();
}
static void
run_script(void)
{
int len;
if (edit_mode == 0)
SetFocus(input_window); // move focus from run button
if (running)
return;
if (inp)
free(inp);
len = GetWindowTextLength(edit_window);
inp = (char *) malloc(len + 1);
GetWindowText(edit_window, inp, len + 1);
goto_calc_mode();
deactivate_controls();
clear();
update_display();
create_task();
update_curr_cmd("Working...");
}
static void
copy_all(void)
{
HDC tmp;
RECT r;
HBITMAP bitmap;
if (total_h == 0)
return;
tmp = GetDC(main_window);
draw_hdc = CreateCompatibleDC(tmp);
r.left = 0;
r.top = 0;
r.right = display_width;
r.bottom = total_h - display_y;
if (r.bottom > display_height)
r.bottom = display_height;
bitmap = CreateCompatibleBitmap(tmp, r.right, r.bottom);
SelectObject(draw_hdc, bitmap);
FillRect(draw_hdc, &r, (HBRUSH) GetStockObject(WHITE_BRUSH));
SetBkMode(draw_hdc, TRANSPARENT);
draw_display();
OpenClipboard(main_window);
EmptyClipboard();
SetClipboardData(CF_BITMAP, bitmap);
CloseClipboard();
DeleteObject(bitmap);
DeleteDC(draw_hdc);
DeleteDC(tmp);
}
static void
do_special(char *s)
{
if (inp)
free(inp);
inp = strdup(s);
update_cmd_history(inp);
echo_input(inp);
update_curr_cmd("");
run(inp);
}
static void
do_help(char **s, int n)
{
int i;
if (running)
return;
goto_calc_mode();
run_hdc = GetDC(main_window);
do_special("clear");
for (i = 0; i < n; i++)
do_special(s[i]);
ReleaseDC(main_window, run_hdc);
update_display();
}