CDPopUpMenusImpl.mesa  (a ChipNDale module)
Copyright © 1986, 1987 by Xerox Corporation. All rights reserved.
Created by: Christian Jacobi, September 18, 1984 3:24:53 pm PDT
Last edited by: Christian Jacobi, February 26, 1987 5:48:32 pm PST
DIRECTORY
Ascii,
Atom,
CD,
CDEnvironment,
CDMenuSpecials,
CDPopUpMenus,
CDSequencer,
Commander,
FS,
IO,
PopUpMenus,
RefTab,
Rope,
SymTab,
TEditProfile USING [DoList],
TerminalIO;
CDPopUpMenusImpl: CEDAR PROGRAM
IMPORTS Atom, CDEnvironment, CDSequencer, FS, IO, PopUpMenus, RefTab, Rope, SymTab, TEditProfile, TerminalIO
EXPORTS CDPopUpMenus, CDMenuSpecials
SHARES PopUpMenus =
BEGIN
UnknownMenu: PUBLIC SIGNAL = CODE;
menuTab: RefTab.Ref ~ RefTab.Create[];
garbageMenu: PopUpMenus.Menu ~ MakeMenu[$GarbageMenu, "garbage menu", "used if command is registered with unknown menu"];
GetMenu: PUBLIC PROC [key: REF, check: BOOLFALSE] RETURNS [PopUpMenus.Menu] = {
WITH key SELECT FROM
pm: PopUpMenus.Menu => RETURN [pm];
ENDCASE => NULL;
WITH RefTab.Fetch[menuTab, key].val SELECT FROM
pm: PopUpMenus.Menu => RETURN [pm];
ENDCASE => NULL;
IF check THEN SIGNAL UnknownMenu;
RETURN [garbageMenu];
};
MakeMenu: PUBLIC PROC [key: ATOM, header, doc: Rope.ROPE, tech: CD.Technology←NIL] RETURNS [menu: PopUpMenus.Menu] = {
IF key=NIL THEN RETURN [garbageMenu];
WITH RefTab.Fetch[menuTab, key].val SELECT FROM
pm: PopUpMenus.Menu => [] ← PopUpMenus.ReLabel[pm, header, doc];
ENDCASE => {
menu ← PopUpMenus.Create[header, doc];
[] ← RefTab.Store[menuTab, key, menu];
};
CDSequencer.ImplementCommand[key, CallMenuComm, tech, dontQueue];
};
CallMenuComm: PROC [comm: CDSequencer.Command] = {
menu: PopUpMenus.Menu ← GetMenu[comm.key];
WITH PopUpMenus.Call[menu, comm] SELECT FROM
a: ATOM => CDSequencer.ExecuteCommand[comm: comm, key: a];
ENDCASE => NULL;
};
--====================================
InitMenus: PROC [] = {
[] ← MakeMenu[$GlobalMenu, "Global menu", "all entries are menus again"];
[] ← MakeMenu[$RectGlobalMenu, "Global on rects", "all entries are menus again"];
[] ← MakeMenu[$ProgramMenu, "Additional Programs", "additional programs"];
[] ← MakeMenu[$RectProgramMenu, "Programs on Rects", "additional programs using coordinates"];
[] ← MakeMenu[$OtherProgramMenu, "Other Programs", "additional programs"];
[] ← MakeMenu[$CellMenu, "Cell (s)", ""];
[] ← MakeMenu[$IOMenu, "Input / Output", ""];
[] ← MakeMenu[$DirectoryMenu, "Directory options", ""];
[] ← MakeMenu[$ViewerMenu, "Viewer options", ""];
[] ← MakeMenu[$DrawModeMenu, "Draw Modes", "set drawing modes for the viewer"];
[] ← MakeMenu[$SpecialMenu, "Special commands", ""];
[] ← MakeMenu[$RectSpecialMenu, "Special on rects", ""];
[] ← MakeMenu[$ImportMenu, "Import and remote", ""];
[] ← MakeMenu[$GeneratorMenu, "Generator options", ""];
[] ← MakeMenu[$TextPropertyMenu, "Text & Properties", ""];
[] ← MakeMenu[$PolygonMenu, "Polygons & Splines", ""];
[] ← MakeMenu[$SelectionMenu, "Selections", ""];
[] ← MakeMenu[$RectSelectionMenu, "Selections on rects", ""];
[] ← MakeMenu[$RectDrawMenu, "Draw", "draw certain types of objects"];
[] ← MakeMenu[$CommentLayerMenu, "set current layer comment", "select color or discard"];
};
SkipLeading: PROC [line: Rope.ROPE, start: INT𡤀] RETURNS [Rope.ROPE] = {
removes leading spaces spaces and tabs
ignores one leading !
leng: INT ← Rope.Length[line];
WHILE start<leng DO
SELECT Rope.Fetch[line, start] FROM
Ascii.SP, Ascii.TAB => start ← start+1;
'! => {start ← start+1; EXIT};
ENDCASE => EXIT;
ENDLOOP;
RETURN [ Rope.Substr[line, start] ];
};
SkipTrailing: PROC [line: Rope.ROPE, last: INT←-1] RETURNS [Rope.ROPE] = {
removes trailing spaces spaces and tabs
ignores one trailing /
IF last<0 THEN last ← Rope.Length[line]-1;
WHILE last>0 DO
SELECT Rope.Fetch[line, last] FROM
Ascii.SP, Ascii.TAB => last ← last-1;
'/ => {last ← last-1; EXIT};
ENDCASE => EXIT;
ENDLOOP;
RETURN [ Rope.Substr[line, 0, last+1] ];
};
SplitText: PROC [line: Rope.ROPE] RETURNS [first, rest: Rope.ROPENIL] = {
Split line according to the following syntax
first | rest
represent | as ||
removes spaces and tabs adjacent to the |
ignores one ! adjacent the |
nextPos: INT ← 0;
leng: INT ← Rope.Length[line];
WHILE nextPos<leng DO
IF Rope.Fetch[line, nextPos]='| THEN {
IF nextPos+1>leng OR Rope.Fetch[line, nextPos+1]='| THEN {
line ← Rope.Replace[line, nextPos, 1, NIL]; leng ← leng-1;
}
ELSE {
first ← SkipTrailing[line, nextPos-1];
rest ← SkipLeading[line, nextPos+1];
RETURN;
};
};
nextPos ← nextPos+1;
ENDLOOP;
first ← line
};
HandleMenuFile: PUBLIC PROC [fileName: Rope.ROPE, doneFiles: SymTab.Ref←NIL] = {
--doneFiles: SymTab of files already handled; stops infinite recursion!
MakeMenuLine: PROC [line: Rope.ROPE] = {
Syntax of menu lines
menuKey | entryKey | entryText | doc
lines starting with "-" are comment lines and ignored
"!" adjacent to a | are ignored
entryKey = "NIL": removes the entry
menuR, keyR, textR, restR, docR: Rope.ROPENIL; key: ATOM NIL;
line ← SkipLeading[line];
IF Rope.IsEmpty[line] THEN RETURN;
[menuR, restR] ← SplitText[line];
IF Rope.IsEmpty[menuR] OR Rope.Fetch[menuR, 0]='- THEN RETURN;
[keyR, textR] ← SplitText[restR];
IF Rope.IsEmpty[keyR] THEN RETURN;
IF ~Rope.IsEmpty[textR] THEN [textR, docR] ← SplitText[textR];
IF Rope.Equal[menuR, "DefineMenu", FALSE] THEN {
--Make a menu
IF ~Rope.Equal[keyR, "NIL"] THEN key ← Atom.MakeAtom[keyR];
[] ← MakeMenu[key, textR, docR, NIL]
}
ELSE IF Rope.Equal[menuR, "IncludeFile", FALSE] THEN {
--Include a file
HandleMenuFile[keyR]
}
ELSE {
--Regular menu entry
IF ~Rope.Equal[keyR, "NIL"] THEN key ← Atom.MakeAtom[keyR];
[] ← PopUpMenus.Entry[
menu: GetMenu[Atom.MakeAtom[menuR]],
entry: textR, entryData: key, doc: docR
];
}
};
InstallFile: PROC [fileName: Rope.ROPE] = {
file: IO.STREAM; line: Rope.ROPE;
file ← FS.StreamOpen[fileName
! FS.Error => {
TerminalIO.PutRopes["** menu table file """, fileName, """ not opened\n"];
GOTO finish
}
];
DO
line ← IO.GetLineRope[file ! IO.EndOfStream => GOTO finish];
IF ~Rope.IsEmpty[line] THEN MakeMenuLine[line];
ENDLOOP;
EXITS finish => NULL;
};
IF doneFiles=NIL THEN doneFiles ← SymTab.Create[case: FALSE];
fileName ← CDEnvironment.MakeName[fileName, "MenuTable", CDEnvironment.GetWorkingDirectory[NIL]];
IF SymTab.Insert[doneFiles, fileName, $x] THEN InstallFile[fileName];
};
ReInstallMenus: PROC = {
--Menu entries are installed in opposite order as found in user profile
--to allow client installations overwrite standard installation.
--Menu entries are not removed if not explicitely requested to allow permanent
--installation of menu entries by programs.
doneFiles: SymTab.Ref ← SymTab.Create[case: FALSE];
mustFiles: SymTab.Ref ← SymTab.Create[];
EachProfileEntry: PROC [r: Rope.ROPE] = {
IF Rope.Equal[r, "Default"] THEN r ← CDEnvironment.MakeName["ChipNDale", "MenuTable", CDEnvironment.GetWorkingDirectory[NIL]];
[] ← SymTab.Insert[mustFiles, r, $x]
};
EachSymTabEntry: SymTab.EachPairAction = {quit←FALSE;
HandleMenuFile[key, doneFiles];
};
TEditProfile.DoList[Rope.Concat[CDEnvironment.profilePrefix, "MenuTable"], EachProfileEntry, "Default"];
[] ← SymTab.Pairs[mustFiles, EachSymTabEntry]
};
ReInstallMenusCommand: Commander.CommandProc = {
ReInstallMenus[];
};
--CDMenuSpecials
SelectOneOf: PUBLIC PROC [ref: REF, label: Rope.ROPE, allowTypeIn: BOOLFALSE] RETURNS [r: Rope.ROPENIL] = {
cnt: INT ← 0; cntPerMenu: INT = 12;
menu, firstMenu: PopUpMenus.Menu; x: REFNIL;
alreadyUsed: SymTab.Ref ← SymTab.Create[];
NewMenu: PROC [] RETURNS [m: PopUpMenus.Menu] = {
m ← PopUpMenus.Create[header: label];
IF allowTypeIn THEN
[] ← PopUpMenus.Entry[menu: m, entry: "<type in>", entryData: $type, doc: "type in rope to terminal"];
};
AddEntry: PROC [entry: Rope.ROPE] = {
IF SymTab.Insert[alreadyUsed, entry, entry] THEN {
IF (cnt MOD cntPerMenu)=(cntPerMenu-1) THEN {
newMenu: PopUpMenus.Menu ← NewMenu[];
[] ← PopUpMenus.Entry[menu: menu, entry: "<show more>", entryData: newMenu, doc: "show more entries for this menu"];
menu ← newMenu;
};
cnt ← cnt+1;
[] ← PopUpMenus.Entry[menu: menu, entry: entry, entryData: entry];
};
};
EachSymTabEntry: SymTab.EachPairAction = { quit ← FALSE;
AddEntry[key]
};
menu ← firstMenu ← NewMenu[];
WITH ref SELECT FROM
st: SymTab.Ref => [] ← SymTab.Pairs[st, EachSymTabEntry];
rl: LIST OF Rope.ROPE =>
FOR l: LIST OF Rope.ROPE ← rl, l.rest WHILE l#NIL DO
AddEntry[l.first];
ENDLOOP;
ENDCASE => NULL;
IF menu#firstMenu THEN
[] ← PopUpMenus.Entry[menu: menu, entry: "<show again>", entryData: firstMenu, doc: "show beginning entries again"];
IF cnt>0 THEN x ← PopUpMenus.Call[firstMenu] ELSE IF allowTypeIn THEN x ← $type;
WHILE x#NIL AND ISTYPE[x, PopUpMenus.Menu] DO
x ← PopUpMenus.Call[NARROW[x]];
ENDLOOP;
IF x=$type THEN
r ← TerminalIO.RequestRope[Rope.Concat[label, " >"] ! TerminalIO.UserAbort => CONTINUE]
ELSE r ← NARROW[x];
};
InitMenus[];
CDEnvironment.RegisterCommander["CDReInstallMenus", ReInstallMenusCommand, "re-read the ChipNDale menus"];
ReInstallMenus[];
END.