GriffinMenuImpl.mesa
Copyright © 1985 by Xerox Corporation. All rights reserved.
Created by: Maureen Stone November 26, 1980 5:50 PM
Edited by: Maureen Stone September 19, 1985 2:10:40 pm PDT
Last Edited by: Ken Pier, November 13, 1985 4:44:41 pm PST
DIRECTORY
GriffinColor USING [StringToColor],
GriffinData USING [DataRec],
GriffinDisplay USING [BkgndColor, BkgndColorRec, BoxFill, DrawCaption, InvertBox],
GriffinKernel USING [ClipBox, DataRec],
GriffinMenu USING [MenuHandle, MenuHandleProc, MenuItem, MenuItemHandle, MenuProc],
GriffinObject USING [ForAllObjects, MenuOrientation, Object, ObjectProc, ReplotBoxFromObject, StartObject],
GriffinPoint USING [ScrPt, ScrRealPt, X, Y],
GriffinRefresh USING [EraseAndSave, MarkObject],
GriffinStyle USING [Style, StyleHandle],
GriffinText USING [GetBoundingBox],
GriffinViewer USING [DoPaint, PaintProc],
Imager USING [ConstantColor, Context],
ImagerColor USING [ColorFromGray],
ImagerFont USING [Extents, Find, FontBoundingBox],
Real USING [RoundI],
Rope USING [Length, ROPE];
GriffinMenuImpl: CEDAR PROGRAM
IMPORTS GriffinColor, GriffinDisplay, GriffinObject, GriffinRefresh, GriffinText, GriffinViewer, ImagerColor, ImagerFont, Real, Rope
EXPORTS GriffinMenu, GriffinKernel = BEGIN
Data: TYPE = REF DataRec;
DataRec: PUBLIC TYPE = GriffinData.DataRec;
ROPE: TYPE = Rope.ROPE;
X: NAT = GriffinPoint.X;
Y: NAT = GriffinPoint.Y;
menuLineWidth: INTEGER = 4;
twoLineWidth: INTEGER = 2*menuLineWidth;
colorLineWidth: INTEGER = 2;
menuMargin: INTEGER = 4;
menuGrey: Imager.ConstantColor = ImagerColor.ColorFromGray[.5];
menuWhite: Imager.ConstantColor = ImagerColor.ColorFromGray[0];
menuGrey: GriffinDisplay.BkgndColor; -- initialized in InitMenuStyle
menuWhite: GriffinDisplay.BkgndColor;-- initialized in InitMenuStyle
menuStyle: GriffinStyle.StyleHandle ← NIL; -- initialized in InitMenuStyle
menuHeight, itemHeight: INTEGER ← 0; -- initialized in InitMenuStyle
CreateMenu: PUBLIC PROC [data: Data, orientation: GriffinObject.MenuOrientation, tl: GriffinPoint.ScrPt, title: ROPE] RETURNS [GriffinMenu.MenuHandle] = {
menu: GriffinMenu.MenuHandle ← NARROW[GriffinObject.StartObject[data, menu]];
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 => {
menu.br[X] ← tl[X] + twoLineWidth;
menu.br[Y] ← tl[Y] - menuLineWidth;
};
horizontal => {
menu.br[X] ← tl[X] + menuLineWidth;
menu.br[Y] ← tl[Y] - menuHeight;
};
ENDCASE;
IF title # NIL AND Rope.Length[title] > 0
THEN AddMenuItem[menu, title, NullMenuProc].inverted ← TRUE;
RETURN[menu]
};
NullMenuProc: GriffinMenu.MenuProc = { };
ItemWidth: PROC [string: ROPE] RETURNS [INTEGER] = {
tl, br: GriffinPoint.ScrPt;
[tl, br] ← GriffinText.GetBoundingBox[string, menuStyle, [0, 0]];
RETURN[br[X]-tl[X]+menuMargin];
};
AddMenuItem: PUBLIC PROC [menu: GriffinMenu.MenuHandle, string: ROPE, proc: GriffinMenu.MenuProc] RETURNS [GriffinMenu.MenuItemHandle] = {
data: Data ← menu.data;
first: BOOLEANFALSE;
rover: GriffinMenu.MenuItemHandle;
newitem: GriffinMenu.MenuItemHandle ← NEW[GriffinMenu.MenuItem];
newitem^ ← [link: NIL, menu: menu, selected: FALSE, inverted: FALSE,
tl: , br: , string: NIL, proc: proc];
IF menu.head=NIL THEN { first ← TRUE; menu.head ← newitem }
ELSE {
FOR rover ← NARROW[menu.head], rover.link UNTIL rover.link = NIL
DO ENDLOOP; --find end
rover.link ← newitem;
};
SELECT menu.orientation FROM
vertical => {
width: INTEGERIF menu=data.colorMenu OR menu=data.lineColorMenu THEN colorLineWidth ELSE menuLineWidth;
newitem.tl[X] ← menu.tl[X] + menuLineWidth;
newitem.tl[Y] ← menu.br[Y] - width;
};
horizontal => {
width: INTEGERIF menu=data.colorMenu OR menu=data.lineColorMenu THEN colorLineWidth ELSE menuLineWidth;
newitem.tl[X] ← menu.br[X] + menuLineWidth;
newitem.tl[Y] ← menu.tl[Y] - width;
};
ENDCASE;
newitem.string ← string;
SELECT menu.orientation FROM
vertical => {
lineWidth: INTEGERIF menu=data.colorMenu OR menu=data.lineColorMenu THEN colorLineWidth ELSE menuLineWidth;
oldWidth: INTEGER ← menu.br[X] - menu.tl[X] - twoLineWidth;
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]+oldWidth;
newitem.br[Y] ← newitem.tl[Y] - itemHeight;
menu.br[Y] ← newitem.br[Y] - lineWidth;
};
horizontal => {
lineWidth: INTEGERIF menu=data.colorMenu OR menu=data.lineColorMenu THEN colorLineWidth ELSE menuLineWidth;
newitem.br[X] ← newitem.tl[X] + ItemWidth[string];
menu.br[X] ← newitem.br[X] + lineWidth;
newitem.br[Y] ← newitem.tl[Y] - itemHeight;
};
ENDCASE;
IF menu.visible THEN GriffinRefresh.EraseAndSave[menu];
RETURN[newitem];
};
ChangeMenuWidth: PROC [menu: GriffinMenu.MenuHandle, width: INTEGER] = {
WidenMenu: GriffinMenu.MenuProc = {
item.br[X] ← item.tl[X] + width;
};
IF menu.orientation # vertical THEN ERROR;
ForAllMenuItems[menu, WidenMenu];
menu.br[X] ← menu.tl[X] + width + twoLineWidth;
IF menu.visible THEN GriffinRefresh.EraseAndSave[menu];
};
ForAllMenus: PUBLIC PROC [data: Data, proc: GriffinMenu.MenuHandleProc] = {
IsMenu: GriffinObject.ObjectProc = {
WITH object SELECT FROM
mref: REF GriffinObject.Object[menu] => proc[mref];
ENDCASE;
};
GriffinObject.ForAllObjects[data, IsMenu];
};
ForAllMenuItems: PUBLIC PROC [menu: GriffinMenu.MenuHandle, proc: GriffinMenu.MenuProc] = {
rover: GriffinMenu.MenuItemHandle;
FOR rover ← NARROW[menu.head], rover.link UNTIL rover = NIL
DO proc[rover] ENDLOOP;
};
PlotMenu: PUBLIC PROC [menu: GriffinMenu.MenuHandle, dc: Imager.Context] = {
Show: GriffinMenu.MenuProc = { ShowItem[item, dc] };
data: Data ← menu.data;
GriffinDisplay.BoxFill[menu.tl, menu.br, menuGrey, data.clipBox, dc];
ForAllMenuItems[menu, Show];
};
ShowMenu: PUBLIC PROC [menu: GriffinMenu.MenuHandle] = {
IF NOT menu.visible THEN {
menu.visible ← TRUE;
GriffinRefresh.MarkObject[menu];
};
};
HideMenu: PUBLIC PROC [menu: GriffinMenu.MenuHandle] = {
IF menu.visible THEN {
menu.visible ← FALSE;
GriffinRefresh.EraseAndSave[menu];
};
};
ShowItem: PROC [item: GriffinMenu.MenuItemHandle, dc: Imager.Context] = {
data: Data ← item.menu.data;
clipBox: GriffinKernel.ClipBox ← data.clipBox;
GriffinDisplay.BoxFill[item.tl, item.br, menuWhite, clipBox, dc];
GriffinDisplay.DrawCaption[MenuAnchorPoint[item], item.string, menuStyle, clipBox, dc];
IF item.inverted THEN GriffinDisplay.InvertBox[item.tl, item.br, clipBox, dc];
};
OverWhichItem: PUBLIC PROC [data: Data, pt: GriffinPoint.ScrPt] RETURNS [GriffinMenu.MenuItemHandle] = {
IsOverMenu: PROC [m: GriffinMenu.MenuHandle] = {
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;
};
LastItemOver: GriffinMenu.MenuProc = {
IF pt[X] IN [item.tl[X] .. item.br[X]] AND pt[Y] IN [item.br[Y] .. item.tl[Y]]
THEN lastitem ← item;
};
lastover: GriffinMenu.MenuHandle ← NIL;
lastitem: GriffinMenu.MenuItemHandle ← NIL;
ForAllMenus[data, IsOverMenu];
IF lastover = NIL THEN RETURN[NIL];
ForAllMenuItems[lastover, LastItemOver];
RETURN[lastitem]
};
IsOverItem: PUBLIC PROC [pt: GriffinPoint.ScrPt, item: GriffinMenu.MenuItemHandle] RETURNS [BOOLEAN] = {
RETURN[pt[X] IN [item.tl[X]..item.br[X]] AND pt[Y] IN [item.br[Y]..item.tl[Y]]];
};
BugItem: PUBLIC PROC [item: GriffinMenu.MenuItemHandle] = { item.proc[item] };
WhichMenu: PUBLIC PROC [item: GriffinMenu.MenuItemHandle]
RETURNS [GriffinMenu.MenuHandle] = { RETURN[item.menu] };
IsSelected: PUBLIC PROC [item: GriffinMenu.MenuItemHandle] RETURNS [BOOLEAN] = { RETURN[item.selected] };
MenuString: PUBLIC PROC [item: GriffinMenu.MenuItemHandle] RETURNS [ROPE] = { RETURN[item.string] };
MenuAnchorPoint: PROC [item: GriffinMenu.MenuItemHandle] RETURNS [pt: GriffinPoint.ScrRealPt] = {
pt[X] ← (item.br[X]+item.tl[X])/2;
pt[Y] ← item.tl[Y]-menuMargin/2;
};
SetMenuString: PUBLIC PROC [item: GriffinMenu.MenuItemHandle, string: ROPE] = {
menu: GriffinMenu.MenuHandle = item.menu;
width: INTEGER ← 0;
FindWidest: GriffinMenu.MenuProc = {
w: INTEGER ← ItemWidth[item.string];
IF w>width THEN width ← w;
};
item.string ← string;
IF menu.visible THEN GriffinRefresh.EraseAndSave[menu];
ForAllMenuItems[menu, FindWidest];
ChangeMenuWidth[menu, width];
IF menu.visible THEN GriffinRefresh.EraseAndSave[menu];
};
SelectOnly: PUBLIC GriffinMenu.MenuProc = {
ForAllMenuItems[item.menu, Deselect];
Select[item];
};
Select: PUBLIC GriffinMenu.MenuProc = {
item.selected ← TRUE;
ClearMenuItem[item]
};
Deselect: PUBLIC GriffinMenu.MenuProc = {
IF item.selected THEN {
item.selected ← FALSE;
ClearMenuItem[item];
};
};
HighlightMenuItem: PUBLIC GriffinMenu.MenuProc = {
data: Data ← item.menu.data;
wasInverted: BOOLEAN = item.inverted;
PProc: GriffinViewer.PaintProc = {
GriffinObject.ReplotBoxFromObject[item.tl, item.br, item.menu, dc];
};
item.inverted ← ~ item.selected;
IF item.menu.visible AND wasInverted # item.inverted THEN GriffinViewer.DoPaint[data.viewer, PProc];
};
ClearMenuItem: PUBLIC GriffinMenu.MenuProc = {
data: Data ← item.menu.data;
wasInverted: BOOLEAN = item.inverted;
PProc: GriffinViewer.PaintProc = {
GriffinObject.ReplotBoxFromObject[item.tl, item.br, item.menu, dc];
};
item.inverted ← item.selected;
IF item.menu.visible AND wasInverted # item.inverted
THEN GriffinViewer.DoPaint[data.viewer, PProc];
};
called only once when Griffin STARTS.
InitMenuStyle: PUBLIC PROC = {
extents: ImagerFont.Extents;
menuStyle ← NEW[GriffinStyle.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;
menuGrey ← NEW[GriffinDisplay.BkgndColorRec ← [] ];
menuGrey.constant ← ImagerColor.ColorFromGray[0.5];
menuWhite ← NEW[GriffinDisplay.BkgndColorRec ← [] ];
menuWhite.constant ← ImagerColor.ColorFromGray[0];
};
END.