Commit a10a5871 authored by Charles Ferguson's avatar Charles Ferguson
Browse files

I wrote a calculator!

parents
SillyCalc
=========
This is a silly calculator. Enter expressions in the writeable icon. When
you press return the result will be displayed in the display icon.
Press escape or close the window to quit the application.
Please be nice to me becuase this is my first desktop application.
It doesn't even deserve an icon.
Licence
-------
You may not distribute this application except as supplied. No cutting it
up and giving away your bits. No. Really.
Note about this release
-----------------------
This is an extra special release.
It has a reporter box that tells you what the error is.
The application multitasks whilst it's doing it.
The program doesn't recurse in doing so.
Once the user has made their response (OK, in this case) the program performs
some action.
All this in about half an hour.
In a program I've not used for a year and a half, in a language that isn't
even used all that often for Wimp programs.
See 'do_evaluate' for the call to the dialogue box creation. Notice the use
of a function pointer for the post-user interaction. Ok, so it's actually
a function object, but JS doesn't really have function pointers so you'll
just have to live with that.
Notice that 'dbox_show' includes no heavy trickery.
Notice that the click handler (case 6 in the Poll loop) triggers the
function pointer ('dbox_do_this_after') and closes the window.
If you had more dboxes you might duplicate the window on the fly and keep
track of them through a list. But that's just implementation detail.
Set SillyCalc$Dir <Obey$Dir>
Run <SillyCalc$Dir>.JSTest <SillyCalc$Dir>.!RunImage 2> t
/* Remap plain print to output to !Console */
print = print_debug;
Registers.prototype.throwSWI = function(swi)
{
var err = this.callSWI(swi);
if (err)
throw(err);
};
init_wimp();
load_templates();
open_window_front(Main_Window);
set_caret_end(Main_Window,1)
Quit = 0;
while (!Quit)
{
wimp_poll();
}
/* Load a single template */
function load_template(name)
{
var R = new Registers;
/* 1. Read the size of the template */
R[1] = 0;
R[2] = 0;
R[3] = 0;
R[4] = 0;
R[5] = new Alloc(String(name));
R[6] = 0;
R.throwSWI("Wimp_LoadTemplate");
print("Needs "+R[1]+" for window and icons and "+ R[2]+" for indirect\n");
/* 2. Allocate space for blocks */
var window_data = new Alloc(R[1]);
var indirect_data = new Alloc(R[2]);
/* 3. Load the template */
R[1] = window_data;
R[2] = indirect_data;
R[3] = indirect_data + indirect_data.length;
R[4] = -1;
R[5] = new Alloc(String(name));
R[6] = 0;
R.throwSWI("Wimp_LoadTemplate");
/* 4. Ensure that our indirect data is not released by putting it in
a global variable.
Note that the window data will be destroyed by garbage collection
at some point after we leave this function - it goes out of
scope. */
IndirectData.push(indirect_data);
/* 5. Create the window */
R[1] = window_data;
R.throwSWI("Wimp_CreateWindow");
/* 6. Return the window handle */
return R[0];
}
/* Load all our templates */
function load_templates()
{
var R = new Registers;
/* 0. Initial global object so that we don't lose our indirect data
at some later point during garbage collection */
IndirectData = new Array;
/* 1. Open the templates file */
R[1] = new Alloc("<SillyCalc$Dir>.Templates");
R.throwSWI("Wimp_OpenTemplate");
/* 2. Load each template */
Main_Window = load_template("example");
Report_Window = load_template("dbox");
/* 3. Close the template */
R.throwSWI("Wimp_CloseTemplate");
}
function open_window_front(window)
{
var R = new Registers;
var state = new Alloc(36);
/* Get window state */
state.Word[0] = window;
R[1] = state;
R.throwSWI("Wimp_GetWindowState");
/* Open at front */
state.Word[28] = -1; /* Front */
R.throwSWI("Wimp_OpenWindow");
}
/* Display a message in a dialogue box */
function dbox_show(message, what_to_do_after)
{
/* Remember what we do after the user responds */
dbox_do_this_after = what_to_do_after;
set_icon_text(Report_Window, 0, message);
open_window_front(Report_Window);
}
function init_wimp()
{
var R = new Registers;
R[0] = 310;
R[1] = 0x4b534154;
R[2] = new Alloc("JavaScript application");
R[3] = message_list = new Alloc(4);
message_list.Word[0] = 0;
err = R.throwSWI("Wimp_Initialise");
if (err)
throw(err);
}
function wimp_poll()
{
var poll_block = new Alloc(256);
var reason;
var err;
var R = new Registers;
R[0] = 1<<24; /* Mask (save FP state) */
R[1] = poll_block;
err = R.throwSWI("Wimp_Poll");
if (err)
throw(err);
reason = R[0];
switch (reason)
{
case 2: /* Open window request */
R[1] = poll_block;
R.throwSWI("Wimp_OpenWindow");
break;
case 3: /* Close window request */
Quit = 1;
break;
case 6: /* Mouse click */
var win = poll_block.Word[12];
var icon = poll_block.Word[16];
if (win == Report_Window)
{
if (icon == 1)
{
/* They clicked ok so trigger the operation */
dbox_do_this_after(1);
/* 1 because we might have some other response later; hell this
is only a demo */
/* And remember to close the dbox too */
R[1] = poll_block;
poll_block.Word[0] = Report_Window;
R.throwSWI("Wimp_CloseWindow");
}
}
break;
case 8: /* Key press */
var key = poll_block.Word[24];
print("Key = "+key+"\n");
switch (key)
{
case 13: /* return */
do_evaluate();
break;
case 27: /* Escape */
Quit=1;
break;
}
break;
case 17:
case 18:
var msg = poll_block.Word[16];
print("Message "+ hex(msg) + "\n");
switch (msg)
{
case 0:
Quit=1;
break;
}
break;
}
}
function get_icon_text(window, icon)
{
var R = new Registers;
var gis = new Alloc(8+32);
gis.Word[0] = window;
gis.Word[4] = icon;
R[1] = gis;
R.throwSWI("Wimp_GetIconState");
var flags = gis.Word[8+16];
if ((flags & 0x101) != 0x101)
return "";
return Core.StringC[gis.Word[8+20]];
}
function set_caret_end(window, icon)
{
var R = new Registers;
var str = get_icon_text(window, icon);
R[0] = window;
R[1] = icon;
R[2] = 0;
R[3] = 0;
R[4] = -1;
R[5] = str.length;
R.throwSWI("Wimp_SetCaretPosition");
}
function set_icon_text(window, icon, string)
{
var R = new Registers;
var gis = new Alloc(8+32);
gis.Word[0] = window;
gis.Word[4] = icon;
R[1] = gis;
R.throwSWI("Wimp_GetIconState");
var flags = gis.Word[8+16];
if ((flags & 0x101) != 0x101)
return;
string = String(string);
Core.StringC[gis.Word[8+20]] = string.substr(0, gis.Word[8+28]-1);
/* Rememer to force an update of the icon */
gis.Word[8] = 0;
gis.Word[12] = 0;
R.throwSWI("Wimp_SetIconState");
}
function do_evaluate()
{
var str = get_icon_text(Main_Window, 1);
var result;
try {
print("Trying '"+str+"'\n");
result = eval(str);
print("Got '"+result+"'\n");
}
catch(err)
{
print("Failed: "+err+"'\n");
dbox_show(err, function(num) { print("User clicked dbox\n"); } );
result="ERROR";
}
set_icon_text(Main_Window, 3, result);
}
function print_debug()
{
var str, i;
var R;
R = new Registers;
str = new String("");
for (i=0; i<arguments.length; i++)
str += arguments[i];
R.throwSWI(0x104); /* OS_WriteI+4 */
R[0] = new Alloc(str);
R.throwSWI("OS_Write0");
}
Markdown is supported
0% or .
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment