#! /usr/local/bin/wish
#
# Tk-based RPN calculator
#
# $Header: /home/neil/src/tcl/calc/RCS/rpncalc,v 1.5 2000/12/28 15:14:33 neil Exp $
#
# LICENSE:
#
# This program may be used in any way you see fit; the author
# is putting it in the public domain. However, the author assumes
# no liability for any direct or indirect damages which occur
# due to the use of this program; in particular, the calculations
# performed by this program are NOT guaranteed to any particular
# degree of accuracy. Indeed, they are not guaranteed to be
# correct at all.

# CONFIGURE: set this directory to the location where the
# calculator source files reside.

set calcSrcDir "/home/neil/src/tcl/calc"

# Set precision to the max.

set tcl_precision 17

# Source the necessary files.

source [file join $calcSrcDir calcentr]
source [file join $calcSrcDir calcstck]
source [file join $calcSrcDir calcmem]

# Set up the top menu bar.

menu .menubar
.menubar add cascade -label File -menu .menubar.file
.menubar add cascade -label Help -menu .menubar.help

menu .menubar.file
.menubar.file add command -label "Quit" -command exit

# DisplayText displays text "txt" in a text widget, along
# with an "OK" button for getting rid of the window.

proc DisplayText {txt} {
    set suffix 1
    while {[winfo exists ".t$suffix"]} {
	incr suffix
    }
    set path ".t$suffix"
    toplevel $path

    text $path.txt -height 16 -yscrollcommand [list $path.vscroll set]
    scrollbar $path.vscroll -orient vertical -command [list $path.txt yview]
    button $path.ok -text OK -command [list destroy $path]
    grid $path.txt -row 0 -column 0 -sticky nsew
    grid $path.vscroll -row 0 -column 1 -sticky ns
    grid $path.ok -row 1 -column 0 -columnspan 2

    grid rowconfigure $path 0 -weight 1
    grid columnconfigure $path 0 -weight 1

    $path.txt insert end $txt
    $path.txt configure -state disabled
}

# DisplayAbout displays information for the "About"
# entry in the help menu.

proc DisplayAbout {} {
    DisplayText {
Rpncalc is in the public domain; it may be used in any way you
see fit. It was written by  Neil McKay, who would appreciate
an acknowlegement if you use the code for some other purpose.
However, the author accepts no liability for any damages incurred
through rpncalc's use. In particular, the accuracy of the calculations
performed by rpncalc are not guaranteed to any degree whatsoever.}
}

# DisplayUsage displays usage information for the "Usage"
# entry in the help menu.

proc DisplayUsage {} {
    DisplayText {Rpncalc is a calculator program written in Tcl/Tk.
Numbers are entered in the entry widget on the left side
of the display, either by typing directly into the entry
area or by clicking on the keys on the keypad. Pressing
the "Push/Enter" button pushes the contents of the entry
area onto the operation stack.

The operation stack grows downward, and can grow arbitrarily
large; there is no limit on the number of entries in the
stack. Operations are performed by pressing the buttons
in the keypad to the right of the stack. The operations
are performed on the last item (or items) on the stack.
There are no keys for moving items on the stack, e.g.
exchanging the two items on top of the stack, or doing a
stack roll; these operations (and many more) can be performed
by clicking on a stack entry, and dragging it to the desired
location.

The memory area has buttons for storing the top stack entry
into memory, recalling the memory value (i.e. pushing it onto
the stack), clearing the memory cell, adding the top of the
stack to the memory cell, and subtracting the top stack value
from the memory cell. The memory value itself can be modified
by typing into the cell. The label area doesn't really do
anything; it's just there so you can write yourself a note
reminding you what you stored in the cell.
}
}

# Create the "Help" menu.

menu .menubar.help
.menubar.help add command -label "About" -command DisplayAbout
.menubar.help add command -label "Usage" -command DisplayUsage

# Create the menubar.

. configure -menu .menubar

# Make the other stuff.

label .entlab -text "Data Entry"
frame .entry -borderwidth 5 -relief ridge
label .stacklab -text "Operation Stack"
frame .stack -borderwidth 5 -relief ridge
label .memlab -text "Memory"
frame .mem -borderwidth 5 -relief ridge

grid .entlab -row 0 -column 0
grid .entry -row 1 -column 0 -sticky nsew
grid .stacklab -row 0 -column 1
grid .stack -row 1 -column 1 -sticky nsew

label .msgwin -text "" -borderwidth 5 -relief ridge
grid .msgwin -row 2 -column 0 -columnspan 2 -sticky ew

grid .memlab -row 3 -column 0 -columnspan 2 -sticky ew
grid .mem -row 4 -column 0 -columnspan 2 -sticky ew

grid columnconfigure . 1 -weight 1

# pushProc is a procedure for pushing a number on the stack.

proc pushProc {f} {
    if {![ValidFloat $f]} {
	Error "Invalid floating-point number"
	return
    }

    PushStack .stack $f
}

# Error puts up an error message.

proc Error {txt} {
    .msgwin configure -text $txt
    update
    if {[string compare $txt ""] != 0} {
	bell
    }
}

# MemGetProc returns what's on top of the stack;
# the memory box needs this.

proc MemGetProc {} {
    return [StackTop .stack]
}

# Make the various parts of the calculator.

MakeEntryBox .entry pushProc
MakeStackBox .stack
MakeMemBox .mem pushProc MemGetProc

