A library for Menus
The following definitions introduce types and operators to use menus in
Galileo programs. Note how the interaction changes when inchar
is substituted for getchar.
let rec type menuStruct <->
[ title: string;
items: var seq menuItem;
private display := meth() :int is
use c := var 0 in
(newlines(2);
printstring(self.title);
newlines(1);
loop (at self.items) do display(c);
newlines(1);
printstring("Type a number");
newlines(1);
at(c)
);
interact := meth() :null is
% See the effect of changing getchar with inchar %
use rec noBlanks := fun(x: string):string is
use s := explode(x)
in
if first(s) = " "
then noBlanks(implode(rest(s)))
else x
in
if emptyseq(at self.items) then nil
else
use validItems := self.display
ext char := var first (explodeascii(getchar()))
ext one := first (explodeascii("1"))
ext last := one + validItems - 1
in (while ((at char < one) Or (at char > last)) do
(newlines(1);
printstring
(implode({"Retry: the digits must be between 1 and ";
noBlanks(stringofint(validItems))}));
newlines(1);
char <- first (explodeascii(getchar())) );
use numHit := var (at char - first (explodeascii("0")))
in loop i In (at self.items) do
(if i.IamNth(numHit) then
(i.operation(i);
if i.tailAction is enterMenu
then (i.tailAction as enterMenu).interact
else nil;
exit)
else nil));
addItem := meth(newItem: menuItem, position:int): menuItem is
use rec addOrd := fun(itemNum:int, itemList: seq menuItem)
: seq menuItem is
if position <= itemNum then newItem :: itemList
else if emptyseq(itemList) then {newItem}
else first(itemList) :: addOrd(itemNum+1, rest(itemList))
in (if some (at self.items) with id = newItem.id
then failwith "duplicated item id"
else nil;
self.items <- addOrd(1, at(self.items));
newItem);
remItem := meth(itemId: int): null is
self.items <- (at self.items) where Not(id = itemId);
itemWithId := meth(itemId: int): menuItem is
(get x In (at self.items) where (x.id = itemId)).x
iffails failwith "No item with such id";
itemWithName := meth(itemName: string): menuItem is
pick((at self.items) where name = itemName)
iffails failwith "No item with such name"
]
and type menuItem <->
[ name: string;
id: int;
operation: menuItem -> null;
tailAction: (| quitMenu or enterMenu: menuStruct |);
private active: var bool;
private visible: var bool;
setActive := meth() :null is self.active <- true;
setVisible := meth() :null is self.visible <- true;
setInvisible := meth() :null is self.visible <- false;
setInactive := meth() :null is self.active <- false;
IamNth := meth(c:var int): bool is
(if (at self.visible) And (at self.active)
then c <- at c - 1
else nil;
(at c) = 0);
display := meth(c:var int):null is
(if (at self.visible) then
(newlines(1);
if (at self.active) then
(c <- at c + 1;
printint(at c))
else printstring("-");
printstring(")");
blanks(3);
printstring(self.name);
newlines(1)
)
else nil
)
];
% Redefinition of the constructors %
let mkMenu :=
fun(title:string): menuStruct is
mkmenuStruct ([title := title;
items := var({}:seq menuItem)]);
let mkItem := fun(name: string, id:int, op: menuItem -> null, tail:
(| quitMenu or enterMenu: menuStruct|)): menuItem is
mkmenuItem([name := name;
id := id;
operation := op;
tailAction := tail;
active := var true;
visible := var true]);
let NullOperation := fun (x:menuItem):null is nil;
% Declarations for the simple menu version %
let private lastIdSelected := var 0
ext
mkSimpleMenu :=
use idOp := fun(i: menuItem): null is lastIdSelected <- i.id
ext mkSimpleItem :=
fun(name: string, id:int): menuItem is
mkmenuItem([name := name;
id := id;
operation := idOp;
tailAction := (|quitMenu|);
active := var true;
visible := var true])
in fun(title: string, items: seq string): menuStruct is
mkmenuStruct ([title := title;
items := var
(use c := var 0
in select ( c <- (at c) + 1;
mkSimpleItem(i, (at c)))
from i In items
)])
ext
simpleInteract :=
fun(m: menuStruct): int is
(m.interact;
at lastIdSelected);
% Elimination of the standard constructors %
let mkmenuStruct :=
fun(x:[title : string; items : var seq menuItem]): none is
failwith "To create a menuStruct please use mkSimpleMenu or mkMenu";
let mkmenuItem := fun(
x:[name : string; id: int;
operation: menuItem -> null;
tailAction: (| quitMenu or enterMenu: menuStruct |);
active: var bool; visible: var bool]): none is
failwith "To create a menuItem please use mkItem";