-- VMenusImpl.mesa
-- Russ Atkinson, June 14, 1982 10:31 pm

DIRECTORY
Buttons USING
[Button, ButtonProc, Create],
Labels USING
[Create, Label],
Rope USING
[Flatten, ROPE, Size, Text],
ViewerOps USING
[CreateViewer],
VMenus,
VFonts,
UserTerminal USING
[BlinkDisplay];

VMenusImpl: CEDAR PROGRAM
IMPORTS Buttons, Labels, Rope, UserTerminal, ViewerOps, VFonts
EXPORTS VMenus
= PUBLIC BEGIN OPEN Rope, VMenus;

wOff: INTEGER ← 8; -- width offset for buttons
hOff: INTEGER ← 4; -- height offset for buttons

Create: PROC
[name: ROPE, buttons: VButtonList ← NIL, parent: Viewer ← NIL,
x,y: INTEGER ← 0]
RETURNS [ViewerList] = TRUSTED {
w,h,max: INTEGER ← 0;
text: Rope.Text ← name.Flatten[];
head,tail: ViewerList ← NIL;
IF name.Size = 0 THEN text ← "??";
[w,h] ← ComputeStringInfo[text];
max ← w;
FOR bl: VButtonList ← buttons, bl.rest UNTIL bl = NIL DO
btext: Rope.Text ← bl.first.name.Flatten[];
[w,h] ← ComputeStringInfo[btext];
IF w > max THEN max ← w;
ENDLOOP;
-- we now know the max size for the button texts
w ← max + wOff;
h ← h + hOff;
IF parent = NIL
THEN
{-- create a container from the air
parent ← ViewerOps.CreateViewer
[flavor: $Container,
info: [name: text, iconic: FALSE, column: right],
paint: TRUE];
  head ← LIST[parent]}
ELSE
  {-- use the current parent
  label: Labels.Label ← Labels.Create
  [[name: text, parent: parent, wx: x, wy: y, ww: w, wh: h, border: FALSE]];
  head ← LIST[label];
  y ← y + h};
tail ← head;
FOR bl: VButtonList ← buttons, bl.rest UNTIL bl = NIL DO
bh: VButtonRec ← bl.first;
btext: Rope.Text ← bh.name.Flatten[];
 proc: Buttons.ButtonProc ← bh.proc;
 button: Buttons.Button ←
  Buttons.Create
  [info: [name: btext, parent: parent, wx: x, wy: y, ww: w, wh: h],
  proc: IF proc = NIL THEN DefaultVButtonProc ELSE proc,
  clientData: bh.data, fork: bh.fork];
 tail.rest ← LIST[button];
 tail ← tail.rest;
 y ← y + h - 1;
ENDLOOP;
RETURN [head];
};

GetDimensions: PROC
[list: ViewerList] RETURNS [xmin,ymin,xmax,ymax: INTEGER] = {
-- returns the dimensions of the vertical menu
-- given by the list of viewers
xmin ← ymin ← 0;
xmax ← ymax ← -1;
FOR vl: ViewerList ← list, vl.rest UNTIL vl = NIL DO
vh: Viewer ← vl.first;
xm: INTEGER ← vh.wx + vh.ww - 1;
ym: INTEGER ← vh.wy + vh.wh - 1;
IF xmin > vh.wx THEN xmin ← vh.wx;
IF ymin > vh.wy THEN ymin ← vh.wy;
IF xmax < xm THEN xmax ← xm;
IF ymax < ym THEN ymax ← ym;
ENDLOOP;
};

TestVButtonList: VButtonList ←
LIST[[name: "First", proc: NIL, fork: TRUE, data: NIL],
[name: "Second", proc: NIL, fork: TRUE, data: NIL]];

DefaultVButtonProc: Buttons.ButtonProc = TRUSTED {
UserTerminal.BlinkDisplay[];
};

ComputeStringInfo: PROC [r: ROPE] RETURNS [w,h: INTEGER] = TRUSTED {
w ← VFonts.StringWidth[r];
h ← VFonts.FontHeight[];
};

END.