home
***
CD-ROM
|
disk
|
FTP
|
other
***
search
/
OS/2 Shareware BBS: 5 Edit
/
05-Edit.zip
/
EPMATR.ZIP
/
EPMCALC.E
< prev
next >
Wrap
Text File
|
1989-06-29
|
14KB
|
356 lines
/*
This file contains a demo of the use of attributes to implement text buttons.
Starting the Demo.
Simply linking EPMCALC will start this demo.
It is a simple calculator that only handles
positive numbers less than 65536. It uses reverse polish notation just like
Hewlett Packard calculators. The buttons are activated by placing the cursor
over the button to be pressed and invoking the ExecuteCursor command.
(ExecuteCursor can be found in the BUTTONS.E file.) The meaning of most
of the buttons is obvious, but the button with the < character in it is
a delete character.
I recommend that ExecuteCursor be bound to a keystroke or mouse action
to improve the useablility of this calculator.
How is it done.
This calculator is done by simply using the functions provided in
BUTTONS.E to create "buttons" in the text of the document linked to
commands defined in this file. For information about how buttons are
implemented browse the buttons.e file.
The following paragraph is no longer true, but it remains here for
illustrative purposes. The enhancement it suggests has been
implemented.
The calculator stack is kept as a bunch of
attribute records placed near the top left corner
of the calculator. As presently implmented the
value field of each of these attribute records
represents a value within the calculator stack.
Since the value field of attribute records can only
contain values in the range 0..65535, our
calculator can only deal with values in this range.
A good enhancement to this calulator would be to
use the associated text attribute class to store
arbitrary values on the calculator heap.
The button functions of this calculator are not bound to any
particular calculator stack. This means that a user could use the block
copy functions of E to duplicate the calculator. If several calculators
exist in the file, then the button action functions look for the nearest
calculator stack and perform their action on that stack. This means that
a user could use E's block copy function to move the keys around on the
calculator face... and even move the buttons any place in the document.
(Don't ask me why? But that is a neat Gee Whiz thing to do in demos.)
*/
/*
FindCalc
finds the location of the calculator's stack. The
calculator's stack consist's of a sequence of
CALCSTACK_CLASS attributes. (See ---- for the
allocation of this class.) If multiple calculators
exist, then the one closest to the cursor location
is returned.
*/
/* return true if found one */
defproc FindCalc(var BestLine, var BestColm, var BestFile)
universal CALCSTACK_CLASS
universal FIND_NEXT_ATTR_SUBOP
universal FIND_PREV_ATTR_SUBOP
VeryLarge1 = 1000000000
OldLine = .line; OldColm = .col; getfileid OldFileId
BestFit = VeryLarge1
TheOffset = 0
TheColm = OldColm
TheLine = OldLine
TheFile = OldFileId
TheClass = CALCSTACK_CLASS
attribute_action FIND_NEXT_ATTR_SUBOP, TheClass, TheOffset, TheColm, TheLine
while (TheClass<>0) do
Distance = ((TheLine-OldLine)*(TheLine-OldLine))
if TheColm>OldColm then Distance = Distance + ((TheColm-OldColm)*(TheColm-OldColm))
else Distance = Distance + ((OldColm-TheColm)*(OldColm-TheColm))
endif
if Distance<BestFit then
BestLine = TheLine; BestColm = TheColm; getfileid BestFileId; BestFit=Distance
endif
TheColm = TheColm+1
TheOffset = 0
TheClass = CALCSTACK_CLASS
attribute_action FIND_NEXT_ATTR_SUBOP, TheClass, TheOffset, TheColm, TheLine
endwhile
TheOffset = 0
TheColm = OldColm
TheLine = OldLine
TheFile = OldFileId
TheClass = CALCSTACK_CLASS
attribute_action FIND_PREV_ATTR_SUBOP, TheClass, TheOffset, TheColm, TheLine
while (TheClass<>0) do
Distance = ((OldLine-TheLine)*(OldLine-TheLine))
if TheColm>OldColm then Distance = Distance + ((TheColm-OldColm)*(TheColm-OldColm))
else Distance = Distance + ((OldColm-TheColm)*(OldColm-TheColm))
endif
if Distance<BestFit then
BestLine = TheLine; BestColm = TheColm; getfileid BestFileId; BestFit=Distance
endif
TheColm = TheColm
TheOffset = -300
TheClass = CALCSTACK_CLASS
attribute_action FIND_PREV_ATTR_SUBOP, TheClass, TheOffset, TheColm, TheLine
endwhile
return BestFit<>VeryLarge1
/*
CalcPop
This proc pops an entry off of the calculator's stack
and returns that value.
*/
defproc CalcPop(CalcLine, CalcColm, CalcFileId)
universal CALCSTACK_CLASS
universal FIND_PREV_ATTR_SUBOP
universal DELETE_ATTR_SUBOP
universal ASSOCCLASS
getfileid OldFileid
activatefile CalcFileid
call psave_pos(OldPos)
-- check for errors
TheOffset = 0
TheColm = CalcColm
TheLine = CalcLine
TheFile = CalcFileId
TheClass = CALCSTACK_CLASS
attribute_action FIND_PREV_ATTR_SUBOP, TheClass, TheOffset, TheColm, TheLine
if (TheClass==0) or (TheColm<>CalcColm) or (TheLine<>CalcLine) or (TheOffset<>-2) then
call prestore_pos(OldPos)
return 0
endif
-- get value at top of stack
CalcLine
.col = CalcColm
TheValue = Associated_Phrase(CALCSTACK_CLASS)
-- delete the top of the calc stack
TheOffset = -1
attribute_action DELETE_ATTR_SUBOP, TheClass, TheOffset, TheColm, TheLine -- delete association
attribute_action DELETE_ATTR_SUBOP, TheClass, TheOffset, TheColm, TheLine -- delete push calc
TheOffset = 1
attribute_action DELETE_ATTR_SUBOP, TheClass, TheOffset, TheColm, TheLine -- delete pop calc
call prestore_pos(OldPos)
return TheValue
/*
CalcPush
Pushs the given value onto the calculator's stack
at a given location.
*/
defproc CalcPush(ThePhrase, CalcLine, CalcColm, CalcFileId)
universal CALCSTACK_CLASS
universal ASSOCCLASS
TheValue = StashPhrase(ThePhrase)
insert_attribute CALCSTACK_CLASS, TheValue, /*ispush:=push*/ 1, -1, CalcColm, CalcLine, CalcFileId
insert_attribute CALCSTACK_CLASS, TheValue, /*ispush:=pop */ 0, 1, CalcColm, CalcLine, CalcFileId
insert_attribute ASSOCCLASS, TheValue, /*ispush:=tag */ 2, -1, CalcColm, CalcLine, CalcFileId
/*
UpdateCalcScreen
Draw the value at the top of the calculator's stack
onto the screen of the calculator.
*/
defproc UpdateCalcScreen(CalcLine, CalcColm, CalcFileId)
universal CALCSTACK_CLASS
universal FIND_NEXT_ATTR_SUBOP
universal FIND_PREV_ATTR_SUBOP
compile if EVERSION < 5
cursordata
compile endif
getfileid OldFileid
activatefile CalcFileid
call psave_pos(OldPos)
CalcLine
.col = CalcColm
TheValue = Associated_phrase(CALCSTACK_CLASS)
.col = CalcColm + 3
CalcLine
if insertstate() then
inserttoggle
endif
keyin substr(TheValue, 1, 15)
call prestore_pos(OldPos)
activatefile OldFileid
/*
StartCalc
Build a calculator from scratch.
*/
defc StartCalc
universal CALCSTACK_CLASS
universal ASSOCCLASS
universal BUTTONCLASS
"e /c jcalcxxx.tst"
getfileid CalcFileid
.filename = "EPM Calculator Demo"
.autosave = 0
insertline "╔══════════════════════╗", 1,CalcFileid
insertline "║-| 5 |-║", 2,CalcFileid
insertline "║EPM ┌─┐┌─┐┌─┐┌─┐ ║", 3,CalcFileid
insertline "║Calc │0││1││2││3│ ║", 4,CalcFileid
insertline "║ ┌───┐└─┘└─┘└─┘└─┘ ║", 5,CalcFileid
insertline "║ ┌─┐│ E │┌─┐┌─┐┌─┐┌─┐ ║", 6,CalcFileid
insertline "║ │+││ N ││4││5││6││7│ ║", 7,CalcFileid
insertline "║ └─┘│ T │└─┘└─┘└─┘└─┘ ║", 8,CalcFileid
insertline "║ ┌─┐│ E │┌─┐┌─┐┌─┐┌─┐ ║", 9,CalcFileid
insertline "║ │-││ R ││8││9││.││<│ ║",10,CalcFileid
insertline "║ └─┘└───┘└─┘└─┘└─┘└─┘ ║",11,CalcFileid
insertline "╚══════════════════════╝",12,CalcFileid
insertline "Use alt-dblclick-button1",13,CalcFileid
insert_attribute CALCSTACK_CLASS, 0, 1/*ispush*/, -1, /*col:*/2, /*line:*/ 2 ;
insert_attribute ASSOCCLASS, StashPhrase("0"), 2/*ispush*/, -1, /*col:*/2, /*line:*/ 2 ;
insert_attribute CALCSTACK_CLASS, 0, 0/*ispush*/, 1, /*col:*/2, /*line:*/ 2 ;
call pset_mark(1, 12, 1, 24, "BLOCK", CalcFileid)
"associate_phrase_with_mark "BUTTONCLASS" CalcKeyed HELP"
call pset_mark(6, 8, 3, 5, "BLOCK", CalcFileid)
"associate_phrase_with_mark "BUTTONCLASS" CalcKeyed +"
call pset_mark(9, 11, 3, 5, "BLOCK", CalcFileid)
"associate_phrase_with_mark "BUTTONCLASS" CalcKeyed -"
call pset_mark(5, 11, 6, 10, "BLOCK", CalcFileid)
"associate_phrase_with_mark "BUTTONCLASS" CalcKeyed ENTER"
call pset_mark(3, 5, 11, 13, "BLOCK", CalcFileid)
"associate_phrase_with_mark "BUTTONCLASS" CalcKeyed 0"
call pset_mark(3, 5, 14, 16, "BLOCK", CalcFileid)
"associate_phrase_with_mark "BUTTONCLASS" CalcKeyed 1"
call pset_mark(3, 5, 17, 19, "BLOCK", CalcFileid)
"associate_phrase_with_mark "BUTTONCLASS" CalcKeyed 2"
call pset_mark(3, 5, 20, 22, "BLOCK", CalcFileid)
"associate_phrase_with_mark "BUTTONCLASS" CalcKeyed 3"
call pset_mark(6, 8, 11, 13, "BLOCK", CalcFileid)
"associate_phrase_with_mark "BUTTONCLASS" CalcKeyed 4"
call pset_mark(6, 8, 14, 16, "BLOCK", CalcFileid)
"associate_phrase_with_mark "BUTTONCLASS" CalcKeyed 5"
call pset_mark(6, 8, 17, 19, "BLOCK", CalcFileid)
"associate_phrase_with_mark "BUTTONCLASS" CalcKeyed 6"
call pset_mark(6, 8, 20, 22, "BLOCK", CalcFileid)
"associate_phrase_with_mark "BUTTONCLASS" CalcKeyed 7"
call pset_mark(9, 11, 11, 13, "BLOCK", CalcFileid)
"associate_phrase_with_mark "BUTTONCLASS" CalcKeyed 8"
call pset_mark(9, 11, 14, 16, "BLOCK", CalcFileid)
"associate_phrase_with_mark "BUTTONCLASS" CalcKeyed 9"
call pset_mark(9, 11, 17, 19, "BLOCK", CalcFileid)
"associate_phrase_with_mark "BUTTONCLASS" CalcKeyed ."
call pset_mark(9, 11, 20, 22, "BLOCK", CalcFileid)
"associate_phrase_with_mark "BUTTONCLASS" CalcKeyed <"
unmark
call UpdateCalcScreen(2, 2, CalcFileId)
call prestore_pos("4 12 12 4"); -- .line .col .cursorx .cursory
"enable_attr_keys"
/*
CalcKeyed
The arithmetic guts of the calculator. It takes its
argument, applies the argument to the calculator stack,
and redisplays the screen of the calculator. This
command is generally invoked by pressing calculator
buttons, but it can also be called from the command
line.
*/
defc CalcKeyed
compile if EVERSION < 5
cursordata
compile endif
call psave_pos(OldPos)
CalcLine = .line; CalcCol = .col; getfileid CalcFile
FoundCalc = FindCalc(CalcLine, CalcCol, CalcFile)
if (FoundCalc==0) and (arg(1)<>"HELP") then
call showmessage(" Sorry, the calculator could not be found.")
return
else
endif
if arg(1)=="ENTER" then
call CalcPush(0, CalcLine, CalcCol, CalcFile)
elseif arg(1)=="HELP" then
call showmessage(" EPM Calc Help: ",
" This is a trivial reverse-Polish ",
" notation calculator. Just ",
" alt-doubleclick with button 1. ")
elseif arg(1)=="+" then
Arg1 = CalcPop(CalcLine, CalcCol, CalcFile)
Arg2 = CalcPop(CalcLine, CalcCol, CalcFile)
call CalcPush(Arg1+Arg2, CalcLine, CalcCol, CalcFile)
elseif arg(1)=="-" then
Arg1 = CalcPop(CalcLine, CalcCol, CalcFile)
Arg2 = CalcPop(CalcLine, CalcCol, CalcFile)
call CalcPush(Arg2-Arg1, CalcLine, CalcCol, CalcFile)
elseif arg(1)=="/" then
Arg1 = CalcPop(CalcLine, CalcCol, CalcFile)
if Arg1=0 then
call messagenwait("Division by zero not supported.")
call CalcPush(Arg1, CalcLine, CalcCol, CalcFile)
else
Arg2 = CalcPop(CalcLine, CalcCol, CalcFile)
call CalcPush(Arg2/Arg1, CalcLine, CalcCol, CalcFile)
endif
elseif arg(1)=="%" then
Arg1 = CalcPop(CalcLine, CalcCol, CalcFile)
if Arg1=0 then
call messagenwait("Division by zero not supported.")
call CalcPush(Arg1, CalcLine, CalcCol, CalcFile)
else
Arg2 = CalcPop(CalcLine, CalcCol, CalcFile)
call CalcPush(Arg2%Arg1, CalcLine, CalcCol, CalcFile)
endif
elseif arg(1)=="//" then
Arg1 = CalcPop(CalcLine, CalcCol, CalcFile)
if Arg1=0 then
call messagenwait("Division by zero not supported.")
call CalcPush(Arg1, CalcLine, CalcCol, CalcFile)
else
Arg2 = CalcPop(CalcLine, CalcCol, CalcFile)
call CalcPush(Arg2//Arg1, CalcLine, CalcCol, CalcFile)
endif
elseif (arg(1)=="+-") or (arg(1)=="-+") then
Arg1 = CalcPop(CalcLine, CalcCol, CalcFile)
call CalcPush(-1 * Arg1, CalcLine, CalcCol, CalcFile)
elseif arg(1)=="." then
call showmessage(" Sorry, non natural numbers are not yet officially supported.");
elseif arg(1)=="<" then
Arg1 = CalcPop(CalcLine, CalcCol, CalcFile)
call CalcPush(Arg1%10, CalcLine, CalcCol, CalcFile)
elseif (arg(1)>="0") and (arg(1)<="9") then
Arg1 = CalcPop(CalcLine, CalcCol, CalcFile)
Result = ( Arg1||arg(1) ) + 0 -- handles zero, positive and negatives.
call CalcPush(Result, CalcLine, CalcCol, CalcFile)
else
call showmessage(" Sorry, I don't understand that key.")
endif
call UpdateCalcScreen(CalcLine, CalcCol, CalcFile)
call prestore_pos(OldPos)
definit
sayerror "bozoxo1"
"link buttons"
sayerror "bozoxo2"
"startcalc"