/*
 
JujuCalc
Copyright ©2001-2005 etc
Mark Pursey
A wacky JujuScript application
 
Note that because the eval function is used,
(see function Eval() below)
this is more powerful than it looks...
eg you could type "5! * sin(pi/3)"
 
*/
 
var apptext = "jujucalc 1.0";
 
// globals
dialog win; // the calculator window
object state; // this will hold variables created within the eval loop
 
 
if (true)
{
var rc = rect(0,0,200,240);
with win {
: "color 0.5 0.5 1";
: "size %d %d" << [rc.Width(), rc.Height()];
: "set text " + apptext;
: "new button close set text X";
: "item close set pos %g %g %g %g" << rc.([hi.x - 20, lo.y+4, 15,15]);
}
 
// title bar
rc.lo.y += 20;
 
// allow margins
rc.Expand(-4);
 
var rc2 = rect(0, 0, 1, 0.32);
 
with win {
: "new text lcd";
: "item lcd set pos %g %g %g %g" << (rc*rc2).(Expand(-1),[lo.x, lo.y, Width(), Height()]);
}
 
//rc.lo.y = 100;
 
var rowSet = [
[7,8,9,"+","ac"],
[4,5,6,"-","ms"],
[1,2,3,"*","m+"],
[0, ".", "=", "/","mr"]
];
 
for (var r = 0; r < rowSet.Length(); r++)
{
var &row = rowSet[r];
for (var c = 0; c < row.Length(); c++)
{
with rc2 {
lo = point(c, r+2);
hi = lo + point(1,1);
}
 
with rc2 with (lo, hi) x /= 5, y /= 6;
 
string id = row[c];
string txt = id.Upper();// == "*" ? "x" : id;
 
//rc2 = rect(0,0,1,1);
with win {
: "new button %s set text %s" << [id,txt];
: "item %s set pos %g %g %g %g" << (rc*rc2).(Expand(-1),[id, lo.x, lo.y, Width(), Height()]);
}
}
}
}
 
// find the display ("lcd")
control textControl = win.Find("lcd");
 
with textControl
{
if (IsEmpty())
throw "ERROR: failed to find display!";
 
: "set font size 40";
//Command("set para align 0.5");
// allow display to change size to fit
: "set shrink 0.35";
//Command("set font bold 1");
 
if (commandline.Length() > 0)
SetText(commandline);
else
SetText("");
}
 
string g_memory = textControl.GetText(); // remembers thingy
 
// display the calculator
win.Start();
 
// focus on the display, so key presses will go there
textControl.SetFocus();
 
// a counter for messages, for interest's sake
 
if (true)
{
int i = 0;
while (win.Wait() != 0) // while there is a useful message here
{
string mess = win.Message().Lower();
 
if (mess >> "cancel") // ESC
{
if (textControl.GetText() == "")
win.Close();
else
textControl.SetText("");
}
else if (mess >> "ok")
Eval(textControl);
 
else if (mess >> "click")
{
if (mess >> "ac")
textControl.SetText("");
else if (mess >> "close")
win.Close();
else if (mess >> "=")
Eval(textControl);
else if (mess >> "link") // the hyperlink
{
win: "color " + Math.random() + " " + Math.random() + " " + Math.random();
}
else if (mess >> "mr")
textControl.SetText(System.ReadClipboard());
else if (mess >> "m+")
{
Eval(textControl);
System.WriteClipboard(eval(System.ReadClipboard() + "+" + textControl.GetText()));
}
 
else if (mess >> "ms")
{
if (textControl.GetText().Length() > 0) // only save if not nothing!
System.WriteClipboard(textControl.GetText());
}
else if (mess.Length() == 1)
{
if ("-+/*".Find(mess,0) >= 0)
Eval(textControl);
 
textControl: "paste " + mess; // SetText(textControl.GetText()+mess);
}
}
 
i++;
textControl.SetFocus(); // refocus on display
}
}
 
var a_ret = textControl.GetText();
 
// end modal dialog
win.End();
 
// return number of messages received, just for fun
return a_ret;
 
 
/*
 
Following are functions used by the main body above
 
*/
 
// eval contents of the control and the put result back
function Eval(control &textControl)
{
// now execute the eval within state's context, for access to variables
 
with state
{
var a_res = eval(textControl.GetText().Lower());
string a_str = dump(a_res);
 
if (a_res is string)
{
if (a_res[0] == '#')
{
//a_str = "ERROR";
a_str = a_res;
a_str = "ERROR:\n" + a_str.Mid(2);
//a_str += "\nPress AC to clear";
}
}
else if (a_res is void)
{
a_str = "";
}
 
textControl.SetText(a_str);
}
}
 
 
// add a factorial function (eg 5! = 120)
function operator!postfix(int a)
{
for (real a_ret = 1; a > 1; )
{
a_ret *= a;
a--;
}
return a_ret;
}
 
// force ints to real precision for muliplies and divides
function operator/(int a, int b) { return (real)a / (real)b; }
function operator*(int a, int b) { return (real)a * (real)b; }
 
// add some math functions for convenience [no namespace support yet]
 
function sin(a) { return Math.sin(a); }
function cos(a) { return Math.cos(a); }
function tan(a) { return Math.tan(a); }
function log(a,b) { return Math.log(a,b); }
function ln(a) { return Math.ln(a); }
function sqrt(a) { return Math.sqrt(a); }
 
// polynomial solver [real roots only]
function operator!(array a)
{
real v[];
for (var e in a)
v += e;
 
return Math.Solve(v);
}
 
// constants
static real pi = Math.PI;
 
// miscellaneous
function quad(a,b,c)
{
var det = b*b - 4*a*c;
if (det < 0) // no roots
return []; //void;
 
array root;
root[0] = (-b - sqrt(det)) / (2*a);
root[1] = (-b + sqrt(det)) / (2*a);
return root;
}