<> <> <> <> <> <<>> 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: 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: BOOLEAN _ FALSE; 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: INTEGER _ IF 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: INTEGER _ IF 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: INTEGER _ IF 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: INTEGER _ IF 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]; }; <> 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.