2136 lines
39 KiB
C++
2136 lines
39 KiB
C++
// George Weigt
|
|
// gweigt@yahoo.com
|
|
//
|
|
// 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>
|
|
#include "htmlhelp.h"
|
|
#define _USE_MATH_DEFINES // for MS C++
|
|
#include <math.h>
|
|
#include <time.h>
|
|
|
|
extern void run(char *);
|
|
extern void draw_display(void);
|
|
extern void printstr(char *);
|
|
extern void clear_term(void);
|
|
extern void update_cmd_history(char *);
|
|
extern void echo_input(char *);
|
|
|
|
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;
|
|
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 12
|
|
HWND button[NBUTTON];
|
|
HDC draw_hdc;
|
|
HDC run_hdc;
|
|
HMENU main_menu;
|
|
|
|
#define NFONT 11
|
|
|
|
HFONT display_font[NFONT];
|
|
|
|
struct {
|
|
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 init(void);
|
|
void defn(void);
|
|
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 do_example(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_main_help(int);
|
|
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);
|
|
|
|
enum {
|
|
|
|
ID_BASE = 40000,
|
|
|
|
ID_USER_EVENT,
|
|
ID_ESC,
|
|
ID_ENTER,
|
|
ID_UP_ARROW,
|
|
ID_DOWN_ARROW,
|
|
|
|
ID_NEW,
|
|
ID_OPEN,
|
|
ID_SAVE,
|
|
ID_SAVEAS,
|
|
ID_PAGE_SETUP,
|
|
ID_PRINT,
|
|
|
|
ID_UNDO,
|
|
ID_CUT,
|
|
ID_COPY,
|
|
ID_PASTE,
|
|
ID_COPY_ALL,
|
|
|
|
ID_CONDENSE,
|
|
ID_DERIVATIVE,
|
|
ID_DRAW,
|
|
ID_EXPAND,
|
|
ID_FACTOR,
|
|
ID_FLOAT,
|
|
ID_INTEGRAL,
|
|
ID_RATIONALIZE,
|
|
ID_ROOTS,
|
|
ID_SIMPLIFY,
|
|
ID_EDIT_SCRIPT,
|
|
ID_RUN_SCRIPT,
|
|
|
|
ID_SAMPLE_GMA,
|
|
ID_SAMPLE_VC,
|
|
ID_SAMPLE_RM,
|
|
ID_SAMPLE_QHO,
|
|
ID_SAMPLE_HW,
|
|
ID_SAMPLE_SSM,
|
|
ID_SAMPLE_FPDE,
|
|
|
|
ID_HELP_PAGES,
|
|
ID_HELP_EXPONENT,
|
|
ID_HELP_MULTIPLY,
|
|
ID_HELP_DRAW,
|
|
ID_HELP_FACTOR_POLYNOMIAL,
|
|
ID_HELP_FACTOR_NUMBER,
|
|
ID_HELP_SYMBOL,
|
|
ID_HELP_FUNCTION,
|
|
ID_HELP_SPECIAL_NOTE,
|
|
ID_HELP_TYPE_VECTOR,
|
|
ID_HELP_TYPE_MATRIX,
|
|
ID_HELP_MATRIX_TIMES_VECTOR,
|
|
ID_HELP_INVERT_MATRIX,
|
|
ID_HELP_DRAW_CIRCLE,
|
|
ID_HELP_ABOUT,
|
|
|
|
ID_BUY_LICENSE,
|
|
ID_NOT_NOW,
|
|
};
|
|
|
|
#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;
|
|
|
|
init();
|
|
|
|
defn();
|
|
|
|
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.
|
|
//
|
|
|
|
HICON hicon;
|
|
|
|
static void
|
|
MyRegisterClass(HINSTANCE hInstance)
|
|
{
|
|
static WNDCLASSEX wcex;
|
|
|
|
hicon = (HICON) LoadImage(
|
|
hInstance,
|
|
"small.ico",
|
|
IMAGE_ICON,
|
|
0, 0,
|
|
LR_LOADFROMFILE);
|
|
|
|
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 = hicon;
|
|
wcex.hCursor = LoadCursor(NULL, IDC_ARROW);
|
|
wcex.hbrBackground = (HBRUSH)(COLOR_WINDOW + 1);
|
|
wcex.lpszMenuName = NULL;
|
|
wcex.lpszClassName = "Eigenmath";
|
|
wcex.hIconSm = hicon;
|
|
|
|
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 101",
|
|
WS_OVERLAPPEDWINDOW /* | WS_VSCROLL */ ,
|
|
CW_USEDEFAULT, 0,
|
|
CW_USEDEFAULT, 0,
|
|
//400, 400,
|
|
NULL,
|
|
NULL,
|
|
hInstance,
|
|
NULL);
|
|
|
|
ShowWindow(main_window, nCmdShow);
|
|
UpdateWindow(main_window);
|
|
|
|
return TRUE;
|
|
}
|
|
|
|
static struct {
|
|
char *s;
|
|
long long id;
|
|
} main_button[NBUTTON] = {
|
|
{"Derivative", ID_DERIVATIVE},
|
|
{"Integral", ID_INTEGRAL},
|
|
{"Condense", ID_CONDENSE},
|
|
{"Expand", ID_EXPAND},
|
|
{"Rationalize", ID_RATIONALIZE},
|
|
{"Simplify", ID_SIMPLIFY},
|
|
{"Factor", ID_FACTOR},
|
|
{"Roots", ID_ROOTS},
|
|
{"Draw", ID_DRAW},
|
|
{"Float", ID_FLOAT},
|
|
{"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) GetStockObject(OEM_FIXED_FONT), 0);
|
|
|
|
// create buttons
|
|
|
|
for (i = 0; i < 6; i++) {
|
|
j = i * main_client_width / 6;
|
|
k = (i + 1) * main_client_width / 6;
|
|
button[2 * i] = CreateWindow(
|
|
"BUTTON",
|
|
main_button[2 * i].s,
|
|
WS_CHILD | WS_VISIBLE | BS_PUSHBUTTON,
|
|
j, main_client_height - 2 * line_height,
|
|
k - j, line_height,
|
|
main_window,
|
|
(HMENU) main_button[2 * i].id,
|
|
hinst,
|
|
NULL);
|
|
SendMessage(
|
|
button[2 * i],
|
|
WM_SETFONT,
|
|
(WPARAM) GetStockObject(ANSI_VAR_FONT),
|
|
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);
|
|
}
|
|
|
|
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},
|
|
{"Copy Result Window", ID_COPY_ALL},
|
|
{0, 0},
|
|
|
|
{"Help", 0},
|
|
{"Help Pages", ID_HELP_PAGES},
|
|
{"-", 0},
|
|
{"Type ^ for exponent", ID_HELP_EXPONENT},
|
|
{"Type a space to multiply", ID_HELP_MULTIPLY},
|
|
{"How to draw a graph", ID_HELP_DRAW},
|
|
{"How to factor a polynomial", ID_HELP_FACTOR_POLYNOMIAL},
|
|
{"How to factor a number", ID_HELP_FACTOR_NUMBER},
|
|
{"How to define a symbol", ID_HELP_SYMBOL},
|
|
{"How to define a function", ID_HELP_FUNCTION},
|
|
{"A special note about functions", ID_HELP_SPECIAL_NOTE},
|
|
{"How to define a vector", ID_HELP_TYPE_VECTOR},
|
|
{"How to define a matrix", ID_HELP_TYPE_MATRIX},
|
|
{"How to multiply a matrix and vector", ID_HELP_MATRIX_TIMES_VECTOR},
|
|
{"How to invert a matrix", ID_HELP_INVERT_MATRIX},
|
|
{"How to draw a parametric graph", ID_HELP_DRAW_CIRCLE},
|
|
{"Sample Scripts", 0},
|
|
{"Gamma Matrix Algebra", ID_SAMPLE_GMA},
|
|
{"Vector Calculus", ID_SAMPLE_VC},
|
|
{"Rotation Matrix", ID_SAMPLE_RM},
|
|
{"Quantum Harmonic Oscillator", ID_SAMPLE_QHO},
|
|
{"Hydrogenic Wavefunctions", ID_SAMPLE_HW},
|
|
{"Static Spherical Metric", ID_SAMPLE_SSM},
|
|
{"Free Particle Dirac Equation", ID_SAMPLE_FPDE},
|
|
{0, 0},
|
|
//{"About", ID_HELP_ABOUT},
|
|
{0, 0},
|
|
|
|
{0, 0},
|
|
};
|
|
|
|
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;
|
|
case ID_COPY_ALL:
|
|
copy_all();
|
|
break;
|
|
case ID_HELP_EXPONENT:
|
|
do_main_help(1);
|
|
break;
|
|
case ID_HELP_MULTIPLY:
|
|
do_main_help(2);
|
|
break;
|
|
case ID_HELP_DRAW:
|
|
do_main_help(3);
|
|
break;
|
|
case ID_HELP_FACTOR_POLYNOMIAL:
|
|
do_main_help(4);
|
|
break;
|
|
case ID_HELP_FACTOR_NUMBER:
|
|
do_main_help(5);
|
|
break;
|
|
case ID_HELP_SYMBOL:
|
|
do_main_help(6);
|
|
break;
|
|
case ID_HELP_FUNCTION:
|
|
do_main_help(7);
|
|
break;
|
|
case ID_HELP_SPECIAL_NOTE:
|
|
do_main_help(8);
|
|
break;
|
|
case ID_HELP_TYPE_VECTOR:
|
|
do_main_help(9);
|
|
break;
|
|
case ID_HELP_TYPE_MATRIX:
|
|
do_main_help(10);
|
|
break;
|
|
case ID_HELP_MATRIX_TIMES_VECTOR:
|
|
do_main_help(11);
|
|
break;
|
|
case ID_HELP_INVERT_MATRIX:
|
|
do_main_help(12);
|
|
break;
|
|
case ID_HELP_DRAW_CIRCLE:
|
|
do_main_help(13);
|
|
break;
|
|
case ID_HELP_PAGES:
|
|
HtmlHelp(main_window, "help.chm", HH_DISPLAY_TOPIC, NULL);
|
|
break;
|
|
case ID_EDIT_SCRIPT:
|
|
if (running)
|
|
break;
|
|
if (edit_mode == 0)
|
|
goto_edit_mode();
|
|
else
|
|
goto_calc_mode();
|
|
break;
|
|
case ID_CONDENSE:
|
|
do_button("condense");
|
|
break;
|
|
case ID_DERIVATIVE:
|
|
do_button("d");
|
|
break;
|
|
case ID_DRAW:
|
|
do_button("draw");
|
|
break;
|
|
case ID_EXPAND:
|
|
do_button("expand");
|
|
break;
|
|
case ID_FACTOR:
|
|
do_button("factor");
|
|
break;
|
|
case ID_FLOAT:
|
|
do_button("float");
|
|
break;
|
|
case ID_INTEGRAL:
|
|
do_button("integral");
|
|
break;
|
|
case ID_RATIONALIZE:
|
|
do_button("rationalize");
|
|
break;
|
|
case ID_ROOTS:
|
|
do_button("roots");
|
|
break;
|
|
case ID_SIMPLIFY:
|
|
do_button("simplify");
|
|
break;
|
|
case ID_RUN_SCRIPT:
|
|
run_script();
|
|
break;
|
|
case ID_SAMPLE_GMA:
|
|
do_example(0);
|
|
break;
|
|
case ID_SAMPLE_VC:
|
|
do_example(1);
|
|
break;
|
|
case ID_SAMPLE_RM:
|
|
do_example(2);
|
|
break;
|
|
case ID_SAMPLE_QHO:
|
|
do_example(3);
|
|
break;
|
|
case ID_SAMPLE_HW:
|
|
do_example(4);
|
|
break;
|
|
case ID_SAMPLE_SSM:
|
|
do_example(5);
|
|
break;
|
|
case ID_SAMPLE_FPDE:
|
|
do_example(6);
|
|
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_SWISS | VARIABLE_PITCH;
|
|
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 < 10; i++)
|
|
EnableWindow(button[i], FALSE);
|
|
|
|
SendMessage(button[10], WM_SETTEXT, 0, (LPARAM) "OK");
|
|
|
|
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 < 10; i++)
|
|
EnableWindow(button[i], TRUE);
|
|
|
|
SendMessage(button[10], 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
|
|
}
|
|
|
|
// I'm guessing that FillRect is faster than Rectangle.
|
|
|
|
void
|
|
draw_point(int x, int y)
|
|
{
|
|
//Rectangle(draw_hdc, x - 1, y - 1, x + 2, y + 2);
|
|
RECT r;
|
|
r.left = x - 1;
|
|
r.top = y - 1;
|
|
r.right = x + 2;
|
|
r.bottom = y + 2;
|
|
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;
|
|
j = 0;
|
|
for (i = 0; i < 6; i++) {
|
|
j = i * main_client_width / 6;
|
|
k = (i + 1) * main_client_width / 6;
|
|
MoveWindow(
|
|
button[2 * i],
|
|
j, main_client_height - 2 * line_height,
|
|
k - j, line_height,
|
|
TRUE);
|
|
MoveWindow(
|
|
button[2 * i + 1],
|
|
j, main_client_height - line_height,
|
|
k - j, 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
|
|
|
|
extern char *example_script[7];
|
|
|
|
static void
|
|
do_example(int k)
|
|
{
|
|
if (running)
|
|
return;
|
|
*filename = 0;
|
|
SetWindowText(edit_window, example_script[k]);
|
|
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);
|
|
}
|
|
}
|
|
|
|
extern void do_help(int);
|
|
|
|
static void
|
|
do_main_help(int n)
|
|
{
|
|
if (running)
|
|
return;
|
|
goto_calc_mode();
|
|
run_hdc = GetDC(main_window);
|
|
do_help(n);
|
|
ReleaseDC(main_window, run_hdc);
|
|
update_display();
|
|
}
|
|
|
|
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;
|
|
update_curr_cmd("");
|
|
esc_flag = 0;
|
|
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 < 12; 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 < 12; 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);
|
|
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);
|
|
strcat(inp, "(last)");
|
|
} else {
|
|
tmp = (char *) malloc(strlen(s) + strlen(inp) + 3);
|
|
strcpy(tmp, s);
|
|
strcat(tmp, "(");
|
|
strcat(tmp, inp);
|
|
strcat(tmp, ")");
|
|
free(inp);
|
|
inp = tmp;
|
|
}
|
|
update_cmd_history(inp);
|
|
echo_input(inp);
|
|
create_task();
|
|
}
|
|
|
|
static void
|
|
run_script(void)
|
|
{
|
|
int len;
|
|
if (edit_mode == 0)
|
|
SetFocus(input_window);
|
|
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();
|
|
create_task();
|
|
}
|
|
|
|
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);
|
|
}
|