GriffinMenu.mesa
MStone November 26, 1980 5:50 PM
Tiberi January 25, 1980 1:37 PM
Maureen Stone September 19, 1985 2:10:40 pm PDT
DIRECTORY
MenuDefs: FROM "MenuDefs",
Imager USING [Context, ConstantColor],
ImagerFont USING [Extents, Find, FontBoundingBox],
Rope USING [Length,ROPE],
GriffinColor USING [StringToColor],
GriffinDisplay USING [BoxFill, InvertBox,DrawCaption],
GriffinViewer USING [PaintProc, DoPaint],
StyleDefs: FROM "StyleDefs",
Real USING [RoundI],
RefreshDefs: FROM "RefreshDefs",
PointDefs: FROM "PointDefs",
ImagerColor USING [ColorFromGray],
GriffinText USING [GetBoundingBox],
ObjectDefs: FROM "ObjectDefs"
USING [MenuOrientation, StartObject, ObjectProc,
ForAllObjects, ReplotBoxFromObject, Object],
GriffinMemoryDefs USING [CZone];
GriffinMenu: CEDAR PROGRAM
IMPORTS Rope, ObjectDefs, ImagerFont,
GriffinMemoryDefs, GriffinDisplay, GriffinText, GriffinViewer, GriffinColor,
RefreshDefs, ImagerColor, Real
EXPORTS MenuDefs =
BEGIN OPEN MenuDefs, ObjectDefs, GriffinMemoryDefs;
X: INTEGER = PointDefs.X;
Y: INTEGER = PointDefs.Y;
ROPE: TYPE = Rope.ROPE;
menuLineWidth: INTEGER = 4;
menuMargin: INTEGER = 4;
menuTopMargin: INTEGER = 1;
menuStyle: StyleDefs.StyleHandle ← NIL; --initialized below
menuHeight, itemHeight: INTEGER ← 0;
menuGrey: Imager.ConstantColor ← ImagerColor.ColorFromGray[.5];
menuWhite: Imager.ConstantColor ← ImagerColor.ColorFromGray[0];
extents: ImagerFont.Extents;
twoLineWidth: INTEGER = 2*menuLineWidth;
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;
menu.br [Y] ← tl [Y] - menuLineWidth;
END;
horizontal =>
BEGIN
menu.br [X] ← tl [X] + menuLineWidth;
menu.br [Y] ← tl [Y] - 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
tl, br: PointDefs.ScrPt;
[tl, br] ← GriffinText.GetBoundingBox[string, menuStyle, [0,0]];
RETURN [br[X]-tl[X]+ menuMargin];
END;
AddMenuItem: PUBLIC PROCEDURE [menu: MenuHandle, string: ROPE, proc: MenuProc] RETURNS [MenuItemHandle] =
BEGIN
newitem: MenuItemHandle;
rover: MenuItemHandle;
first: BOOLEANFALSE;
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
ELSEBEGIN
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] - menuLineWidth;
END;
horizontal =>
BEGIN
newitem.tl [X] ← menu.br [X] + menuLineWidth;
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] ← newitem.tl[X]+width;
newitem.br [Y] ← newitem.tl [Y] - itemHeight;
menu.br [Y] ← newitem.br [Y] - menuLineWidth;
END;
horizontal =>
BEGIN
newitem.br [X] ← newitem.tl [X] + ItemWidth[string];
menu.br [X] ← newitem.br [X] + menuLineWidth;
newitem.br [Y] ← newitem.tl [Y] - itemHeight;
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: Imager.Context] =
BEGIN
showItem: MenuProc = {ShowItem[item,dc]};
GriffinDisplay.BoxFill [menu.tl, menu.br, menuGrey, dc];
ForAllMenuItems [menu, showItem];
END;
ShowMenu: PUBLIC PROCEDURE [menu: MenuHandle] =
BEGIN
IF NOT menu.visible THEN {
menu.visible ← TRUE;
RefreshDefs.MarkObject[menu];
};
END;
HideMenu: PUBLIC PROCEDURE [menu: MenuHandle] =
BEGIN
IF menu.visible THEN {
menu.visible ← FALSE;
RefreshDefs.EraseAndSave[menu];
};
END;
ShowItem: PROCEDURE [item: MenuItemHandle, dc: Imager.Context] =
BEGIN
GriffinDisplay.BoxFill [item.tl, item.br, menuWhite, dc];
GriffinDisplay.DrawCaption[MenuAnchorPoint[item], item.string, menuStyle, dc];
IF item.inverted THEN GriffinDisplay.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.br[Y]..m.tl[Y]]
THEN lastover ← m;
END;
LastItemOver: MenuProc =
BEGIN
IF pt [X] IN [item.tl [X] .. item.br [X]] AND
pt [Y] IN [item.br [Y] .. item.tl [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.br[Y]..item.tl[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: PROCEDURE [item: MenuItemHandle]
RETURNS [pt: PointDefs.ScrRealPt] =
BEGIN
pt[X] ← (item.br[X]+item.tl[X])/2;
pt[Y] ← item.tl[Y]-menuMargin/2;
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;
proc: GriffinViewer.PaintProc = {
ObjectDefs.ReplotBoxFromObject[item.tl, item.br, item.menu, dc];
};
item.inverted ← ~ item.selected;
IF item.menu.visible AND wasInverted # item.inverted THEN GriffinViewer.DoPaint[proc];
END;
ClearMenuItem: PUBLIC MenuProc =
BEGIN
wasInverted: BOOLEAN = item.inverted;
proc: GriffinViewer.PaintProc = {
ObjectDefs.ReplotBoxFromObject[item.tl, item.br, item.menu, dc];
};
item.inverted ← item.selected;
IF item.menu.visible AND wasInverted # item.inverted THEN GriffinViewer.DoPaint[proc];
END;
called early on, right after the Controller initialization
InitMenuStyle: PUBLIC PROCEDURE =
BEGIN
menuStyle ← CZone.NEW[StyleDefs.Style];
menuStyle.color ← GriffinColor.StringToColor["black"];
menuStyle.fillcolor ← GriffinColor.StringToColor["grey"];
menuStyle.backgndcolor ← GriffinColor.StringToColor["white"];
menuStyle.anchor ← center;
menuStyle.stringRotation ← or0;
menuStyle.font ← ImagerFont.Find["Xerox/TiogaFonts/Cream10"];
extents ← ImagerFont.FontBoundingBox[menuStyle.font];
itemHeight ← Real.RoundI[extents.descent+extents.ascent] + menuMargin;
menuHeight ← itemHeight+twoLineWidth;
END;
END.