-- Compiler menu/nb
-- MStone November 26, 1980 5:50 PM
-- Tiberi January 25, 1980 1:37 PM
-- MStone February 15, 1984 11:24:17 am PST
DIRECTORY
MenuDefs: FROM "MenuDefs",
Graphics USING [Context],
ControllerDefs USING [AppendFont, CurrentStyle],
Rope USING [Length,ROPE],
ScreenDefs USING [SetFunction, SetFillParms, BoxFill, InvertBox, GreyType, EraseBox],
ScreenDefsExtras USING [ShowMenuString],
StyleDefs: FROM "StyleDefs",
RefreshDefs: FROM "RefreshDefs",
GriffinFontDefs: FROM "GriffinFontDefs",
PointDefs: FROM "PointDefs",
GraphicsColor USING [IntensityToColor],
ObjectDefs: FROM "ObjectDefs"
USING [MenuOrientation, StartObject, ObjectProc,
ForAllObjects, ReplotBoxFromObject, Object],
GriffinMemoryDefs USING [CZone];
GriffinMenu: PROGRAM
IMPORTS Rope, ObjectDefs, GriffinFontDefs,
GriffinMemoryDefs, ScreenDefs, ControllerDefs,
RefreshDefs, GraphicsColor, PointDefs, ScreenDefsExtras
EXPORTS MenuDefs =
BEGIN OPEN MenuDefs, ObjectDefs, GriffinMemoryDefs;
X: INTEGER = PointDefs.X;
Y: INTEGER = PointDefs.Y;
ROPE: TYPE = Rope.ROPE;
menuLineWidth: INTEGER = 3;
menuMargin: INTEGER = 4;
menuTopMargin: INTEGER = 1;
menuStyle: StyleDefs.StyleHandle ← NIL;
menuFont: GriffinFontDefs.FontDescriptorHandle ← CZone.NEW[GriffinFontDefs.FontDescriptor ←
[name: "Cream", rotation: 0, face: 0, points: 10]];
menuHeight: INTEGER ← 0;
menuBaseLine: REAL ← 0;
menuGrey: ScreenDefs.GreyType ← GraphicsColor.IntensityToColor[.5];
twoLineWidth: INTEGER = 2*menuLineWidth;
MenuStyle: PUBLIC PROCEDURE RETURNS [StyleDefs.StyleHandle] =
BEGIN
RETURN [menuStyle]
END;
CreateMenu: PUBLIC PROCEDURE [orientation: MenuOrientation, tl: PointDefs.ScrPt, title: ROPE] RETURNS [menu: MenuHandle] =
BEGIN
menu ← NARROW [StartObject [menu]];
-- a MenuHandle is a REF menu Object
menu.head ← NIL;
menu.validEncoding ← TRUE;
menu.style ← menuStyle;
menu.orientation ← orientation;
menu.visible ← FALSE;
menu.tl ← tl; -- leave space for enclosing box
SELECT orientation FROM
vertical =>
BEGIN
menu.br [X] ← tl [X] + twoLineWidth-1;
menu.br [Y] ← tl [Y] + menuLineWidth-1;
END;
horizontal =>
BEGIN
menu.br [X] ← tl [X] + menuLineWidth-1;
menu.br [Y] ← tl [Y] + twoLineWidth + menuHeight;
END;
ENDCASE;
IF title # NIL AND Rope.Length[title] > 0
THEN AddMenuItem [menu, title, NullMenuProc].inverted ← TRUE;
END;
NullMenuProc: MenuProc = BEGIN END;
ItemWidth: PROCEDURE [string:ROPE] RETURNS [INTEGER] = INLINE
BEGIN
RETURN [
PointDefs.ObjValToScrVal[GriffinFontDefs.StringWidth[string,menuFont, menuStyle.orientation]] + menuMargin - 1];
END;
AddMenuItem: PUBLIC PROCEDURE [menu: MenuHandle, string: ROPE, proc: MenuProc] RETURNS [MenuItemHandle] =
BEGIN
newitem: MenuItemHandle;
rover: MenuItemHandle;
first: BOOLEAN ← FALSE;
newitem ← CZone.NEW[MenuItem];
newitem^ ← [link: NIL, menu: menu, selected: FALSE, inverted: FALSE,
tl: , br: , string: NIL, proc: proc];
IF menu.head=NIL
THEN BEGIN first ← TRUE; menu.head ← newitem END
ELSE BEGIN
FOR rover ← NARROW[menu.head], rover.link UNTIL rover.link = NIL
DO ENDLOOP; --find end
rover.link ← newitem
END;
SELECT menu.orientation FROM
vertical =>
BEGIN
newitem.tl [X] ← menu.tl [X] + menuLineWidth;
newitem.tl [Y] ← menu.br [Y] + 1;
END;
horizontal =>
BEGIN
newitem.tl [X] ← menu.br [X] + 1;
newitem.tl [Y] ← menu.tl [Y] + menuLineWidth;
END;
ENDCASE;
newitem.string ← string;
SELECT menu.orientation FROM
vertical =>
BEGIN
width: INTEGER ← ItemWidth[string];
IF first OR menu.tl[X] + width + twoLineWidth > menu.br [X]
THEN ChangeMenuWidth[menu, width]
ELSE newitem.br [X] ← menu.br [X] - menuLineWidth;
newitem.br [Y] ← newitem.tl [Y] + menuHeight;
menu.br [Y] ← newitem.br [Y] + menuLineWidth;
END;
horizontal =>
BEGIN
newitem.br [X] ← newitem.tl [X] + ItemWidth[string];
newitem.br [Y] ← menu.br [Y] - menuLineWidth;
menu.br [X] ← newitem.br [X] + menuLineWidth
END;
ENDCASE;
IF menu.visible THEN RefreshDefs.EraseAndSave[menu];
RETURN [newitem];
END;
ChangeMenuWidth: PROCEDURE [menu: MenuHandle, width: INTEGER] =
BEGIN OPEN ObjectDefs;
WidenMenu: MenuProc =
BEGIN
item.br [X] ← item.tl [X] + width;
END;
IF menu.orientation # vertical THEN ERROR;
ForAllMenuItems [menu, WidenMenu];
menu.br [X] ← menu.tl [X] + width + twoLineWidth;
IF menu.visible THEN RefreshDefs.EraseAndSave[menu];
END;
ForAllMenus: PUBLIC PROCEDURE [proc: PROCEDURE [menu: MenuHandle]] =
BEGIN OPEN ObjectDefs;
IsMenu: ObjectProc =
BEGIN
WITH obj SELECT FROM
mref: REF Object[menu] => proc[mref];
ENDCASE;
END;
ForAllObjects[IsMenu];
END;
ForAllMenuItems: PUBLIC PROCEDURE [menu: MenuHandle, proc: MenuProc] =
BEGIN
rover: MenuItemHandle;
FOR rover ← NARROW[menu.head], rover.link UNTIL rover = NIL
DO proc [rover] ENDLOOP;
END;
PlotMenu: PUBLIC PROCEDURE [menu: MenuHandle, dc: Graphics.Context] =
BEGIN
tl, br: PointDefs.ScrPt;
showItem: MenuProc = {ShowItem[item,dc]};
ScreenDefs.EraseBox[menu.tl, menu.br, dc];
ScreenDefs.SetFunction[opaque];
ScreenDefs.SetFillParms[menuGrey];
menu.visible ← TRUE;
--top edge:
tl ← menu.tl;
br [X] ← menu.br[X];
br [Y] ← tl [Y] + menuLineWidth - 1;
ScreenDefs.BoxFill [tl, br, dc];
--left edge:
br [X] ← tl [X] + menuLineWidth - 1;
br [Y] ← menu.br [Y];
tl ← menu.tl;
ScreenDefs.BoxFill [tl, br, dc];
-- the right edge:
tl [X] ← menu.br [X] - menuLineWidth + 1;
tl [Y] ← menu.tl [Y];
br ← menu.br;
ScreenDefs.BoxFill [tl, br, dc];
-- the bottom edge:
tl [X] ← menu.tl [X];
tl [Y] ← menu.br [Y] - menuLineWidth + 1;
br ← menu.br;
ScreenDefs.BoxFill [tl, br, dc];
ForAllMenuItems [menu, showItem];
END;
ShowMenu: PUBLIC PROCEDURE [menu: MenuHandle] =
BEGIN
menu.visible ← TRUE;
RefreshDefs.PlotAndMark[menu];
END;
HideMenu: PUBLIC PROCEDURE [menu: MenuHandle] =
BEGIN
menu.visible ← FALSE;
RefreshDefs.EraseAndSave[menu];
END;
ShowItem: PROCEDURE [item: MenuItemHandle, dc: Graphics.Context] =
BEGIN
tl, br: PointDefs.ScrPt;
tl ← item.tl;
br ← IF item.menu.orientation = vertical
THEN [item.br[X], item.br[Y] + menuLineWidth]
ELSE [item.br[X] + menuLineWidth, item.br[Y]];
IF item.menu.orientation = vertical
THEN tl [Y] ← item.br [Y]+1 -- bottom edges
ELSE tl [X] ← item.br [X]+1; -- right edges
ScreenDefs.SetFunction[opaque];
ScreenDefs.SetFillParms[menuGrey];
ScreenDefs.BoxFill [tl, br, dc];
ScreenDefsExtras.ShowMenuString[MenuAnchorPoint[item], item.string, dc];
-- GriffinFontDefs.DisplayString [item.string,
-- PointDefs.ScrToObj[MenuAnchorPoint[item]],
-- StyleDefs.Anchor [center],
-- StyleDefs.Orientation [or0], menuFont, dc];
IF item.inverted THEN ScreenDefs.InvertBox[item.tl, item.br, dc];
END;
OverWhichItem: PUBLIC PROCEDURE [pt: PointDefs.ScrPt] RETURNS [lastitem: MenuItemHandle] =
BEGIN
lastover: MenuHandle ← NIL;
IsOverMenu: PROCEDURE[m: MenuHandle] =
BEGIN
IF m.visible
AND pt [X] IN [m.tl[X]..m.br[X]]
AND pt [Y] IN [m.tl[Y]..m.br[Y]]
THEN lastover ← m;
END;
LastItemOver: MenuProc =
BEGIN
IF pt [X] IN [item.tl [X] .. item.br [X]] AND
pt [Y] IN [item.tl [Y] .. item.br [Y]] THEN lastitem ← item
END;
lastitem ← NIL;
ForAllMenus[IsOverMenu];
IF lastover = NIL THEN RETURN [NIL];
-- which menu item?
ForAllMenuItems[lastover, LastItemOver];
END;
IsOverItem: PUBLIC PROCEDURE [pt: PointDefs.ScrPt,
item: MenuItemHandle] RETURNS [BOOLEAN] =
BEGIN
IF pt [X] IN [item.tl [X]..item.br [X]]
AND pt [Y] IN [item.tl [Y]..item.br [Y]]
THEN RETURN [TRUE]
ELSE RETURN [FALSE];
END;
BugItem: PUBLIC PROCEDURE [item: MenuItemHandle] =
BEGIN item.proc [item] END;
--questions about menus:
WhichMenu: PUBLIC PROCEDURE [item: MenuItemHandle]
RETURNS [menu: MenuHandle] =
BEGIN RETURN [item.menu] END;
IsSelected: PUBLIC PROCEDURE [item: MenuItemHandle] RETURNS [BOOLEAN] =
BEGIN RETURN [item.selected] END;
MenuString: PUBLIC PROCEDURE [item: MenuItemHandle] RETURNS [ROPE] =
BEGIN RETURN [item.string] END;
MenuAnchorPoint: PUBLIC PROCEDURE [item: MenuItemHandle]
RETURNS [pt: PointDefs.ScrPt] =
BEGIN
pt[X] ← (item.br[X]+item.tl[X])/2 + 1;
pt[Y] ← item.tl[Y] + menuTopMargin;
END;
--changing things:
SetMenuString: PUBLIC PROCEDURE [item: MenuItemHandle, string: ROPE] =
BEGIN
menu: MenuHandle = item.menu;
width: INTEGER ← 0;
FindWidest: MenuProc =
BEGIN
w: INTEGER ← ItemWidth[item.string];
IF w>width THEN width ← w;
END;
item.string ← string;
IF menu.visible THEN RefreshDefs.EraseAndSave[menu];
ForAllMenuItems [menu, FindWidest];
ChangeMenuWidth[menu, width];
IF menu.visible THEN RefreshDefs.EraseAndSave[menu];
END;
SelectOnly: PUBLIC MenuProc =
BEGIN
ForAllMenuItems[item.menu, Deselect];
Select[item];
END;
Select: PUBLIC MenuProc =
BEGIN
item.selected ← TRUE;
ClearMenuItem[item]
END;
Deselect: PUBLIC MenuProc =
BEGIN
IF item.selected THEN
BEGIN
item.selected ← FALSE;
ClearMenuItem[item];
END;
END;
HighlightMenuItem: PUBLIC MenuProc =
BEGIN
wasInverted: BOOLEAN = item.inverted;
item.inverted ← ~ item.selected;
IF item.menu.visible AND wasInverted # item.inverted
THEN ObjectDefs.ReplotBoxFromObject[item.tl, item.br, item.menu, NIL];
END;
ClearMenuItem: PUBLIC MenuProc =
BEGIN
wasInverted: BOOLEAN = item.inverted;
item.inverted ← item.selected;
IF item.menu.visible AND wasInverted # item.inverted
THEN ObjectDefs.ReplotBoxFromObject[item.tl, item.br, item.menu, NIL];
END;
--called early on, right after the Controller initialization
InitMenuStyle: PUBLIC PROCEDURE =
BEGIN OPEN GriffinFontDefs;
[] ← ControllerDefs.AppendFont[menuFont]; --adds the font and makes it current
menuStyle ← CZone.NEW[StyleDefs.Style];
menuStyle^ ← ControllerDefs.CurrentStyle[]^; --includes current font
menuStyle.color ← [0,0,128]; -- 50% grey
menuStyle.fillcolor ← [0,0,128];
menuStyle.backgndcolor ← [0,0,128];
menuStyle.anchor ← center;
menuStyle.orientation ← or0;
menuHeight ← PointDefs.ObjValToScrVal[GriffinFontDefs.MaxHeight[menuFont]] + menuTopMargin-1;
menuBaseLine ← GriffinFontDefs.MaxPosExtent[menuFont];
END;
END.