<> <> <> <> DIRECTORY Ascii, Atom, CD, CDEnvironment, CDMenuSpecials, CDPopUpMenus, CDSequencer, CDSequencerExtras, Commander, FS, IO, PopUpMenus, RefTab, Rope, SymTab, TEditProfile USING [DoList], TerminalIO; CDPopUpMenusImpl: CEDAR PROGRAM IMPORTS Atom, CDEnvironment, CDSequencer, CDSequencerExtras, 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: BOOL_FALSE] 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]; }; CDSequencerExtras.RegisterCommand[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_0] RETURNS [Rope.ROPE] = { <> <> leng: INT _ Rope.Length[line]; WHILE start 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] = { <> <> 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.ROPE_NIL] = { <> <> <> <> <> nextPos: INT _ 0; leng: INT _ Rope.Length[line]; WHILE nextPos> MakeMenuLine: PROC [line: Rope.ROPE] = { <> <> <> <<"!" adjacent to a | are ignored>> <> menuR, keyR, textR, restR, docR: Rope.ROPE _ NIL; 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: BOOL_FALSE] RETURNS [r: Rope.ROPE_NIL] = { cnt: INT _ 0; cntPerMenu: INT = 12; menu, firstMenu: PopUpMenus.Menu; x: REF_NIL; alreadyUsed: SymTab.Ref _ SymTab.Create[]; NewMenu: PROC [] RETURNS [m: PopUpMenus.Menu] = { m _ PopUpMenus.Create[header: label]; IF allowTypeIn THEN [] _ PopUpMenus.Entry[menu: m, entry: "", 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: "", 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: "", 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.