Syntax10.Scn.Fnt6`=IStampElemsAlloc16 Mar 988FoldElemsNewSyntax10.Scn.FntSyntax10i.Scn.Fnt/,Syntax10b.Scn.Fnt    ehm = 4; evm = 3; (*element: horizontal margin, vertical margin*) mhm = 5; mvm = 2; (*menu: horizontal margin, vertical margin*) CR = 0DX; DUnit = TextFrames.Unit; PUnit = TextPrinter.Unit; MR = 0; MM = 1; ML = 2; cancel = {ML, MM, MR}; white = 0; yellow = 5; grey1 = 12; grey2 = 13; grey3 = 14; black = 15; IDSelect* = 0; IDExecute* = 1; IDCancel* = 2; (* Command-Id for SelectMsg *) 88Syntax10.Scn.FntSyntax10m.Scn.Fnt8FoldElemsNewSyntax10.Scn.FntSyntax10m.Scn.FntSyntax10i.Scn.Fnt0 !". ElemDesc* = RECORD(Texts.ElemDesc) name*: ARRAY 32 OF CHAR; menu*: Texts.Text; small*, elemPressed: BOOLEAN; (** small: TRUE if elem displays itself small *) def*: INTEGER; (**default item; first item = 0*) begLine, endLine: INTEGER; (*displayed text stretch in menu*) n: INTEGER; (* number of items*) wid, lsp, dsc: INTEGER (*width, line space, descender of item lines*) END;8Syntax10b.Scn.FntP8cSyntax10.Scn.FntSyntax10i.Scn.Fnt%Syntax10b.Scn.Fnt N (* Elem which contains the command *) CmdElemDesc* = RECORD (ElemDesc) END;8(8#Syntax10.Scn.FntBB EditFrameDesc = RECORD (TextFrames.FrameDesc) elem: Elem END;8d8_Syntax10.Scn.FntSyntax10m.Scn.Fnt > frame*: Display.Frame; pos*: LONGINT; keys*: SET; END;8 !8Syntax10.Scn.FntSyntax10m.Scn.Fnt8FoldElemsNewSyntax10.Scn.FntSyntax10m.Scn.Fnt  x (* frame*: Display.Frame; pos*: LONGINT; keys*: SET; X0*, Y0*: INTEGER; fnt*: Fonts.Font; col*: SHORTINT; *)8 Syntax10i.Scn.Fnt$ 3 elem*: Elem;  id*: INTEGER; (* IDSelect, IDExecute, IDCancel *) execElem*: Elem; (* Elem which contains the command for execution *) END;8L8QSyntax10.Scn.FntSyntax10i.Scn.Fnt!D prev: LineIndices; (* Pointer to father-PopupElem *) idxArr: IdxArray; (* Positions of the first character of new lines in the menu-text *) END;8 Elem* = POINTER TO ElemDesc;  CmdElem* = POINTER TO CmdElemDesc;  EditFrame = POINTER TO EditFrameDesc;  ExecMsg* = RECORD (Texts.ElemMsg)  SelectMsg* = RECORD (TextFrames.TrackMsg)  IdxArray = POINTER TO ARRAY OF LONGINT; LineIndices = POINTER TO RECORD  8P8mSyntax10.Scn.FntSyntax10i.Scn.Fnt+44,,D cmdElem: CmdElem; (* Current open CmdElem (Help / Command) *) showHelp: BOOLEAN; (* PopupElems shows help to the commands, if TRUE *) showCommands: BOOLEAN; (* PopupElems shows help to the commands, if TRUE *) Wr: Texts.Writer; parc: TextFrames.Parc; (* Last parc or default parc in menu-text *) indices: LineIndices;8Syntax10i.Scn.Fnt 8zSyntax10.Scn.Fnt)8FoldElemsNew#Syntax10.Scn.Fnt88 BEGIN IF xy THEN RETURN x ELSE RETURN y END END Max; 8ET8#Syntax10.Scn.Fnt VAR t: Texts.Text; buf: Texts.Buffer; len: LONGINT; r: Texts.Reader; ch: CHAR; BEGIN NEW(buf); Texts.OpenBuf(buf); IF firstLine THEN Texts.OpenReader (r, T, 0); Texts.Read (r, ch); WHILE ~r.eot & (ch # CR) DO Texts.Read (r, ch) END; len := Texts.Pos (r) - 1 ELSE len := T.len END; Texts.Save(T, 0, len, buf); t := TextFrames.Text(""); Texts.Append(t, buf); RETURN t END CopyText; 8%E8#Syntax10.Scn.Fnt BEGIN Texts.WriteString(Wr, "right interclick to edit menu"); Texts.WriteLn(Wr); Texts.WriteLn(Wr); Texts.Append(E.menu, Wr.buf) END SetDefaultMenu; 8D8#Syntax10.Scn.Fnt BEGIN IF indices.idxArr = NIL THEN Texts.OpenReader (r, t, 0) ELSIF line >= LEN (indices.idxArr^) THEN Texts.OpenReader (r, t, t.len) ELSE Texts.OpenReader (r, t, indices.idxArr [line]) END END Set; Syntax10i.Scn.Fnt"8M8#Syntax10.Scn.Fnt VAR t: Texts.Text; pos: LONGINT; BEGIN t := Texts.ElemBase(e); pos := Texts.ElemPos(e); t.notify(t, Texts.replace, pos, pos+1) END Restore; 8y PROCEDURE Min (x, y: INTEGER): INTEGER;  PROCEDURE MinL (x, y: LONGINT): LONGINT;  PROCEDURE Max (x, y: INTEGER): INTEGER;  PROCEDURE CopyText (T: Texts.Text; firstLine: BOOLEAN): Texts.Text;  PROCEDURE SetDefaultMenu (E: Elem);  PROCEDURE Set (VAR r: Texts.Reader; t: Texts.Text; line: INTEGER);  Positions to the start of a line  PROCEDURE Restore (e: Elem);  88Syntax10.Scn.Fnt3,8FoldElemsNew#Syntax10.Scn.Fnt VAR i, wid, dx, x, y, w, h: INTEGER; p: LONGINT; hStr: ARRAY 32 OF CHAR; BEGIN IF E.small OR (E IS CmdElem) THEN E.H := LONG(TextFrames.menuH-1)*DUnit ELSE E.H := LONG(fnt.maxY-fnt.minY+2*evm)*DUnit END; wid := 2*ehm; i := 0; WHILE E.name [i] # 0X DO Display.GetChar (fnt.raster, E.name [i], dx, x, y, w, h, p); INC (wid, dx); INC (i) END; IF E IS CmdElem THEN E.small := TRUE END; E.W := LONG (wid) * DUnit END MeasureElem; Syntax10i.Scn.Fnt&8 Syntax10m.Scn.Fnt  8#Syntax10.Scn.Fnt!! BEGIN RETURN; END MeasureMenu; !8 PROCEDURE MeasureElem (E: Elem; fnt: Fonts.Font);  Calculates the size of the PopupElem  PROCEDURE MeasureMenu* (E: Elem);  Only for downward compatibility  8"8Syntax10.Scn.FntC8FoldElemsNew#Syntax10.Scn.Fnt VAR F1: EditFrame; BEGIN TextFrames.Handle (F, M); WITH F: EditFrame DO IF M IS Oberon.CopyMsg THEN NEW (F1); TextFrames.Open (F1, F.text, F.org); F1.handle := F.handle; F1.elem := F.elem; M(Oberon.CopyMsg).F := F1 END END END HandleEdit; 8 Syntax10b.Scn.Fnt  8#Syntax10.Scn.Fnt VAR V: Viewers.Viewer; F: EditFrame; x, y, i, j: INTEGER; name: ARRAY 70 OF CHAR; fm: TextFrames.Frame; BEGIN name [0] := 22X; i := 0; (* 22X = " *) WHILE E.name[i] # 0X DO name [i+1] := E.name [i]; INC (i) END; name [i+1] := 22X; name [i+2] := 0X; Oberon.AllocateUserViewer (Oberon.Mouse.X, x, y); NEW (F); F.elem := E; TextFrames.Open (F, CopyText (E.menu, FALSE), 0); F.handle := HandleEdit; IF Files.Old ("PopupElems.Menu.Text") # NIL THEN fm := TextFrames.NewMenu(name,"^PopupElems.Menu.Text") ELSE fm := TextFrames.NewMenu(name, "System.Close System.Copy System.Grow PopupElems.Toggle PopupElems.Update ") END; V := MenuViewers.New (fm, F, TextFrames.menuH, x, y) END OpenEditor; 8j PROCEDURE HandleEdit (F: Display.Frame; VAR M: Display.FrameMsg);  PROCEDURE OpenEditor* (E: Elem);  88Syntax10.Scn.Fnt/8FoldElemsNew#Syntax10.Scn.Fnt(( CONST VersionTag = 01X; menuElem = 0; VAR ch: CHAR; val: LONGINT; options: SET; name: ARRAY 70 OF CHAR; BEGIN Files.Read (R, ch); IF ch = VersionTag THEN Files.ReadString (R, E.name); Files.ReadNum (R, val); Files.ReadSet (R, options); IF menuElem IN options THEN E.small := TRUE ELSE E.small := FALSE END; ELSE Files.Set (R, Files.Base (R), Files.Pos (R) - 1); Files.ReadString (R, name); Strings.Extract (name, 0, 31, E.name); Files.ReadBool (R, E.small) END; E.menu := TextFrames.Text (""); Texts.Load (R, E.menu) END Load; 808#Syntax10.Scn.Fnt VAR name: ARRAY 70 OF CHAR; BEGIN COPY (E.name, name); IF E IS CmdElem THEN Files.WriteString (R, "") ELSE Files.WriteString (R, E.name) END; Files.WriteBool (R, E.small); Texts.Store (R, E.menu) END Store; 8d PROCEDURE Load (VAR R: Files.Rider; E: Elem);  PROCEDURE Store (VAR R: Files.Rider; E: Elem);  88"Syntax10.Scn.Fnt@8FoldElemsNew#Syntax10.Scn.Fnt VAR W, H: INTEGER; BEGIN W:=SHORT((E.W-1) DIV PUnit); H:=SHORT(E.H DIV PUnit); IF E.small THEN Printer.String(X, Y, E.name, fnt.name); Printer.ReplPattern(X, Y-2, W, 1, 2) ELSE INC (W, 2 * ehm * DUnit DIV PUnit); Printer.ReplConst(X, Y, W, 2); Printer.ReplConst(X, Y+H-2, W, 2); Printer.ReplConst(X, Y+2, 2, H-4); Printer.ReplConst(X+W-2, Y+2, 2, H-4); Printer.String(X + ehm * DUnit DIV PUnit, Y + SHORT(LONG(evm-fnt.minY)*DUnit DIV PUnit), E.name, fnt.name) END END PrintElem; 8@o8#Syntax10.Scn.Fntoo BEGIN IF pressed THEN Display.ReplConst(grey1, X, Y, W, H, Display.replace); Display.ReplConst(grey3, X, Y+2, W-2, H-2, Display.replace); Display.ReplConst(grey2, X+2, Y+2, W-4, H-4, Display.replace); Display.Dot(grey3, X, Y+1, Display.replace); Display.Dot(grey3, X+W-2, Y+H-1, Display.replace); ELSE Display.ReplConst(grey3, X, Y, W, H, Display.replace); Display.ReplConst(grey1, X, Y+2, W-2, H-2, Display.replace); Display.ReplConst(grey2, X+2, Y+2, W-4, H-4, Display.replace); Display.Dot(grey1, X, Y+1, Display.replace); Display.Dot(grey1, X+W-2, Y+H-1, Display.replace); END END DrawBigElem; 8M8#Syntax10.Scn.Fnt BEGIN IF isCmdElem THEN Display.ReplConst (black, X, Y, W, H, Display.replace); IF pressed THEN Display.ReplConst (grey2, X + 1, Y + 1, W - 2, H - 2, Display.replace) ELSE Display.ReplConst (white, X + 1, Y + 1, W - 2, H - 2, Display.replace) END ELSIF pressed THEN Display.ReplConst(white, X, Y, W, H, Display.replace); Display.ReplConst(grey3, X, Y+1, W-1, H-1, Display.replace); Display.ReplConst(grey2, X+1, Y+1, W-2, H-2, Display.replace) ELSE Display.ReplConst(black, X, Y, W, H, Display.replace); Display.ReplConst(grey3, X, Y+1, W-1, H-1, Display.replace); Display.ReplConst(grey2, X, Y+2, W-2, H-2, Display.replace); Display.ReplConst(white, X, Y+1, 1, H-1, Display.replace); Display.ReplConst(white, X, Y+H-1, W-1, 1, Display.replace) END END DrawSmallElem; 8N8#Syntax10.Scn.Fnt VAR W, H: INTEGER; i, x, y, w, h, dx: INTEGER; pat: Display.Pattern; BEGIN W := SHORT (E.W DIV DUnit); H := SHORT (E.H DIV DUnit); IF E.small OR (E IS CmdElem) THEN DrawSmallElem (E.elemPressed, E IS CmdElem, X, Y, W, H); INC (Y, 3) ELSE DrawBigElem (E.elemPressed, X, Y, W, H); INC (Y, evm-fnt.minY) END; INC (X, ehm); i := 0; WHILE E.name [i] # 0X DO Display.GetChar (fnt.raster, E.name [i], dx, x, y, w, h, pat); Display.CopyPattern (col, pat, X+x, Y+y, Display.paint); INC (X, dx); INC (i) END END DrawElem; 8Syntax10i.Scn.FntD8 Syntax10.Scn.Fnt08FoldElemsNew#Syntax10.Scn.Fnte: Texts.Elem; ch, ch2: CHAR; dx, x, y, w, h: INTEGER; pat: Display.Pattern; m: TextFrames.DisplayMsg; lines, X0: INTEGER; first, lFirst: BOOLEAN; r2, rr, rh: Texts.Reader;8>O8#Syntax10.Scn.FntIF Texts.Pos (r) = 0 THEN first := TRUE ELSE Texts.OpenReader (r2, E.menu, Texts.Pos (r) - 1); Texts.Read (r2, ch); first := ch = CR END;Syntax10i.Scn.Fnt:88#Syntax10.Scn.Fnt;; parc := rr.elem(TextFrames.Parc); Texts.Read (rr, ch) 8I8Syntax10.Scn.Fnt'8FoldElemsNew#Syntax10.Scn.Fnt!! IF measure THEN MeasureElem (rr.elem(Elem), rr.fnt) ELSE Texts.OpenReader (r2, E.menu, Texts.Pos (rr)); Texts.Read (r2, ch); IF r2.eot OR (ch = CR) OR ((r2.elem # NIL) & (r2.elem IS CmdElem)) THEN rr.elem.W := DUnit * LONG (E.wid) END END Syntax10i.Scn.Fnt#8B IF (rr.elem IS Elem) & first THEN  Set PopupElem-width to menu-width  END; IF ~(rr.elem IS CmdElem) & ~(rr.elem IS TextFrames.Parc) THEN e := rr.elem; y := rr.fnt.minY; m.fnt := rr.fnt; m.col := rr.col; m.pos := Texts.Pos (rr) - 1; m.frame := f; m.X0 := X; m.Y0 := Y + 1 + E.dsc; m.elemFrame := NIL; dx := SHORT(e.W DIV DUnit); IF measure THEN m.prepare := TRUE; e.handle (e, m) END; E.lsp := Max (E.lsp, SHORT (e.H DIV DUnit) + 2); E.wid := Max (E.wid, X - X0); IF ((X + dx) > (X0 + parc.width DIV DUnit)) & (~lFirst) THEN IF idx < 0 THEN EXIT END; IF ~measure THEN indices.idxArr [idx + lines] := Texts.Pos (rr) - 1 END; Y := Y - E.lsp; X := X0; INC (lines); DEC (maxLines); lFirst := TRUE END; IF (maxLines > 0) & (~measure) THEN m.prepare := FALSE; e.handle (e, m) END ELSE cmdElem := rr.elem(CmdElem); EXIT END 8 8#Syntax10.Scn.Fnt.. E.lsp := Max (E.lsp, rr.fnt.height); E.dsc := Min (E.dsc, rr.fnt.minY); E.wid := Max (E.wid, X - X0); Display.GetChar (rr.fnt.raster, ch, dx, x, y, w, h, pat); IF ((X + dx) > (X0 + parc.width DIV TextFrames.Unit)) & (~lFirst) THEN IF idx < 0 THEN EXIT END; IF ~measure THEN indices.idxArr [idx + lines] := Texts.Pos (rr) - 1 END; Y := Y - E.lsp; X := X0; INC (lines); DEC (maxLines); lFirst := TRUE END; IF (maxLines > 0) & (~measure) THEN Display.CopyPattern (rr.col, pat, X+x, Y+y, Display.paint) END8<8#Syntax10.Scn.Fnt IF ~measure THEN indices.idxArr [idx + lines] := Texts.Pos (rr) - 1 END; Y := Y - E.lsp; INC (lines); DEC (maxLines); X := X0; lFirst := TRUE 8I8#Syntax10.Scn.Fnt88 WHILE ~rr.eot & (ch # CR) DO Texts.Read (rr, ch) END 8% VAR  BEGIN cmdElem := NIL; lines := 0; X0 := X; lFirst := TRUE;  if at this position a new line starts then first := TRUE  Texts.OpenReader (r2, E.menu, Texts.Pos (r)); Texts.Read (r2, ch); WHILE ~r2.eot & (ch # CR) & ~((r2.elem # NIL) & (r2.elem IS CmdElem)) DO Texts.Read (r2, ch) END; IF ~showCommands & (r2.elem # NIL) & (r2.elem IS CmdElem) THEN Texts.OpenReader (rr, r2.elem(CmdElem).menu, 0); cmdElem := r2.elem(CmdElem); rh := rr; Texts.Read (rr, ch2); IF rr.eot OR (ch2 = CR) THEN Texts.OpenReader (rr, E.menu, Texts.Pos (r)) ELSE rr := rh END ELSE cmdElem := NIL; Texts.OpenReader (rr, E.menu, Texts.Pos (r)) END; WHILE ~r2.eot & (ch # CR) DO Texts.Read (r2, ch) END; r := r2; LOOP Texts.Read (rr, ch); IF (~rr.eot) & (lines = 0) THEN lines := 1 END; WHILE (rr.elem # NIL) & ~rr.eot & (rr.elem IS TextFrames.Parc) DO  Set current parc  END; IF rr.eot OR (ch = CR) THEN EXIT ELSE IF rr.elem # NIL THEN  Print elem  ELSE  Print Character  END; INC (X, dx); IF measure THEN E.wid := Max (E.wid, X - X0) END; IF (X > (X0 + parc.width DIV DUnit)) & (~lFirst) THEN  Start a new line  END; END; first := FALSE; lFirst := FALSE END; (*IF idx >= 0 THEN  Read to the end of the line  END; *) RETURN lines END DrawLine; 8SX8Syntax10.Scn.Fntr8FoldElemsNew#Syntax10.Scn.FntllR: Texts.Reader; X0, bot: INTEGER; lines, i, maxLines: INTEGER; oldIndices: LineIndices; idxArr: IdxArray;86N8#Syntax10.Scn.Fnt oldIndices := indices; NEW (indices); indices.prev := oldIndices; IF E.n = 0 THEN RETURN END; NEW (idxArr, E.n); indices.idxArr := idxArrSyntax10i.Scn.FntG8u 8#Syntax10.Scn.Fnt Display.ReplConst(black, X, Y, W, H, Display.replace); Display.ReplConst(grey2, X+1, Y+1, W-2, H-2, Display.replace); bot := Y + mvm - E.dsc; X0 := X + mhm; X := X0; Y := Y + H - mvm - E.lsp - E.dsc '8s8#Syntax10.Scn.Fntkk idxArr [i] := Texts.Pos (R); maxLines := (Y - bot) DIV E.lsp + 1; E.endLine := i + maxLines '8 VAR  BEGIN parc := TextFrames.defParc; IF ~measure THEN  if drawing -> create a new index-array for the positions of the lines  ELSE idxArr := NIL; E.wid := 0; E.lsp := 0 END; E.begLine := 0; IF (E.n > 1) OR measure THEN IF ~measure THEN  Draw the background for the menu-area  END; Texts.OpenReader(R, E.menu, 0); i := 0; lines := 1; WHILE ~R.eot & (measure OR (i < LEN (idxArr^))) DO IF ~measure THEN  Calculate the number of visible lines  END; lines := DrawLine (R, E, F, X, Y, i, maxLines, measure); Y := Y - E.lsp * lines; X := X0; INC (i, lines) END; E.n := i END; IF E.n <= E.def THEN E.def := 0 END END DrawMenu; 8 PROCEDURE PrintElem (E: Elem; X, Y: INTEGER; fnt: Fonts.Font);  PROCEDURE DrawBigElem (pressed: BOOLEAN; X, Y, W, H: INTEGER);  PROCEDURE DrawSmallElem (pressed, isCmdElem: BOOLEAN; X, Y, W, H: INTEGER);  PROCEDURE DrawElem (E: Elem; col: SHORTINT; X, Y: INTEGER; fnt: Fonts.Font);  (* Draws a line beginning from the current position of the reader *) PROCEDURE DrawLine (VAR r: Texts.Reader; VAR E: Elem; f: Display.Frame; X, Y, idx, maxLines: INTEGER; measure: BOOLEAN): INTEGER;  (* Draws the menu-text into the menu-area and measures the size of the menu-area *) PROCEDURE DrawMenu (E: Elem; F: Display.Frame; X, Y, W, H: INTEGER; measure: BOOLEAN);  88*Syntax10.Scn.FntI8FoldElemsNew_Syntax10.Scn.FntSyntax10i.Scn.Fnt)!V VAR s: Texts.Scanner; par: Oberon.ParList; res, i, j: INTEGER; ch: CHAR; m: TextFrames.TrackMsg; BEGIN Texts.OpenReader (s, E.menu, pos); Texts.Read (s, ch); WHILE ~s.eot & (ch # CR) & ((s.elem = NIL) OR ~(s.elem IS CmdElem)) DO Texts.Read (s, ch) END; IF ~s.eot & (s.elem # NIL) & (s.elem IS CmdElem) THEN IF s.elem(CmdElem).name = "" THEN Texts.OpenScanner(s, E.menu, pos); Texts.Scan(s) (* CmdElem has no command *) ELSE (* Command in CmdElem will be executed *) COPY (s.elem(CmdElem).name, s.s); s.class := Texts.Name; s.line := 0; i := 0; WHILE s.s [i] # 0X DO INC (i) END; s.len := SHORT (i - 1); Texts.Read (s, ch) END ELSE Texts.OpenScanner(s, E.menu, pos); Texts.Scan(s) END; IF (s.class = Texts.Name) & (s.line = 0) THEN i := 0; WHILE (i < s.len) & (s.s[i] # ".") DO INC(i) END; j := i + 1; WHILE (j < s.len) & (s.s[j] # ".") DO INC(j) END; IF (j >= s.len) & (s.s[i] = ".") THEN NEW(par); par.frame := F; par.vwr := Viewers.This(F.X, F.Y); par.text := E.menu; par.pos := Texts.Pos(s)-1; Oberon.Call(s.s, par, ML IN keys, res); (* left interclick -> unload module *) IF res > 0 THEN Texts.WriteString(Wr, "Call error: "); Texts.WriteString(Wr, Modules.importing); IF (res = 1) OR (res = 5) THEN Texts.WriteString(Wr, " not found") ELSIF res = 2 THEN Texts.WriteString(Wr, " not an obj-file") ELSIF res = 3 THEN Texts.WriteString(Wr, " imports "); Texts.WriteString(Wr, Modules.imported); Texts.WriteString(Wr, " with bad key") ELSIF res = 4 THEN Texts.WriteString(Wr, " not enough memory") ELSIF res = 5 THEN Texts.WriteString(Wr, " module not found") ELSIF res = 6 THEN Texts.WriteString(Wr, " command not found") ELSE Texts.WriteString(Wr, " res = "); Texts.WriteInt(Wr, res, 0) END ELSIF res < 0 THEN INC(i); WHILE i < s.len DO Texts.Write(Wr, s.s[i]); INC(i) END; Texts.WriteString(Wr, " not found") END; IF res # 0 THEN Texts.WriteLn(Wr); Texts.Append(Oberon.Log, Wr.buf) END END ELSIF (s.class = Texts.Char) & (s.c = Texts.ElemChar) & (s.line = 0) THEN Texts.OpenReader(s, E.menu, pos); Texts.Read(s, ch); IF ~(s.elem IS Elem) THEN (* If elem is not a popup-elem *) m.frame := NIL; m.keys := {MM}; s.elem.handle(s.elem, m); END END END ExecCmd; 88Syntax10.Scn.Fnt[8FoldElemsNew#Syntax10.Scn.Fntmx, my, top, bot, left, right, newCmd: INTEGER; keys, keyssave: SET; B: Bitmaps.Bitmap; isPopup: BOOLEAN; MW: MsgWindows.InfoWin;8F\8#Syntax10.Scn.Fnt BEGIN Input.Mouse(keys, x, y); keysum := keysum+keys; Oberon.DrawCursor(Oberon.Mouse, Oberon.Arrow, x, y) END TrackMouse; 8/8Syntax10.Scn.Fnt8FoldElemsNew#Syntax10.Scn.FntOO NEW (MW); IF MW.OpenInfo (yellow, cmdElem.menu, MsgWindows.NoTime) THEN IF x + w + MW.w > Display.Width THEN DEC (x, MW.w) ELSE INC (x, w) END; IF y + h + MW.h > Display.Height THEN DEC (y, y + MW.h - Display.Height) ELSE INC (y, h) END; MW.SetPos (x, y); MW.Draw (); MW.DrawContent () END Syntax10i.Scn.Fnt 88#Syntax10.Scn.Fnt\\ IF (R.elem IS Elem) & ~(R.elem IS CmdElem) THEN IF MW # NIL THEN MW.Close (); MW := NIL END; sel.frame := F; sel.elem := E; sel.id := IDSelect; sel.keys := keysum; sel.col := 0; sel.X0 := X0; sel.Y0 := Y0 + E.dsc; sel.fnt := Fonts.Default; R.elem.handle (R.elem, sel); isPopup := TRUE ELSE isPopup := FALSE END8f VAR R: Texts.Reader; x, y, w, h, X0, Y0, lines: INTEGER; ch: CHAR; beg: LONGINT; BEGIN IF (E.n > 1) & (cmd >= 0) THEN X0 := X+mhm; Y0 := Y+H-(E.lsp*(cmd - E.begLine+1))-E.dsc-mvm; x := left; y := Y0 + E.dsc - 1; w := right - left + 1; h := E.lsp + 2; IF (cmdElem # NIL) & (MW # NIL) THEN MW.Close (); MW := NIL END; IF in THEN Display.ReplConst(black, x, y, w, 1, Display.replace); Display.ReplConst(black, x+w-1, y, 1, h-1, Display.replace); Display.ReplConst(white, x, y+1, 1, h-1, Display.replace); Display.ReplConst(white, x, y+h-1, w, 1, Display.replace); Display.ReplConst(grey1, x+1, y+1, w-2, h-2, Display.replace) ELSE Display.ReplConst(grey2, x, y, w, h, Display.replace); END; Set (R, E.menu, cmd); TextFrames.ParcBefore (E.menu, Texts.Pos (R), parc, beg); lines := DrawLine (R, E, F, X0, Y0, -1, 1, FALSE); IF showHelp & (cmdElem # NIL) & in THEN  Show help  END; Set (R, E.menu, cmd); sel.pos := Texts.Pos (R); Texts.Read (R, ch); IF in & (ch # CR) & (R.elem # NIL) & (keys = {ML, MM}) THEN  Open Sub - PopupElem  ELSE isPopup := FALSE END; IF ~in THEN keysum := {MM}; keyssave := {} END END END Flip; 88#Syntax10.Scn.Fnt BEGIN Flip(FALSE, cmd); cmd := E.endLine; Display.CopyBlock(left, bot, W-2, H-2*mvm-E.lsp, left, bot+E.lsp, Display.replace); INC (E.begLine); INC (E.endLine); Flip(TRUE, cmd) END ScrollUp; 88#Syntax10.Scn.Fnt BEGIN Flip(FALSE, cmd); Display.CopyBlock(left, bot+E.lsp, W-2, H-2*mvm-E.lsp, left, bot, Display.replace); DEC (E.begLine); DEC (E.endLine); cmd := E.begLine; Flip(TRUE, cmd) END ScrollDown; 8=8#Syntax10.Scn.Fnt VAR endTime: LONGINT; hx, hy: INTEGER; hKeys: SET; BEGIN endTime := Oberon.Time () + 3; hx := x; hy := y; hKeys := keys; REPEAT TrackMouse (x, y, keys, keysum) UNTIL (keys # hKeys) OR (x # hx) OR (y # hy) OR (Oberon.Time () >= endTime) END Wait; 8c8#Syntax10.Scn.Fnt{{((mx < ex) OR (mx >= ex + ew) OR (my < ey) OR (my >= ey + eh)) & ((mx < X) OR (mx >= X + W) OR (my < Y) OR (my >= Y + H))Syntax10i.Scn.Fnt$8? VAR  PROCEDURE TrackMouse (VAR x, y: INTEGER; VAR keys, keysum: SET);  PROCEDURE Flip (in: BOOLEAN; cmd: INTEGER);  PROCEDURE ScrollUp;  PROCEDURE ScrollDown;  PROCEDURE Wait (VAR x, y: INTEGER; VAR keys, keysum: SET);  BEGIN keyssave := {}; left := X + 1; right := X + W - 2; bot := Y + mvm; top := Y + H - mvm; Oberon.RemoveMarks (X, Y, W, H); Oberon.FadeCursor (Oberon.Mouse); B := Bitmaps.New (W, H); Bitmaps.CopyBlock (Bitmaps.Disp, B, X, Y, W, H, 0, 0, 0); DrawMenu (E, F, X, Y, W, H, FALSE); Flip (TRUE, cmd); keysum := {}; newCmd := -1; REPEAT TrackMouse (mx, my, keys, keysum); IF keysum = cancel THEN cmd := -1; sel.id := IDCancel ELSIF (keys = {ML, MM}) & (keyssave # keysum) THEN keyssave := keysum; Flip (TRUE, cmd); IF (sel.id # IDExecute) & isPopup THEN WHILE keys = {ML, MM} DO TrackMouse (mx, my, keys, keysum) END END; IF isPopup THEN keysum := {MM}; keyssave := {} END ELSIF E.n = 1 THEN (*did not pop up*) IF (mx >= ex) & (mx <= ex+ew) & (my >= ey) & (my <= ey+eh) THEN cmd := 0 ELSE cmd := -1 END ELSIF (mx >= left) & (mx <= right) THEN WHILE (my <= bot) & (E.endLine < E.n) & (keys # {}) DO Wait (mx, my, keys, keysum); ScrollUp END; WHILE (my >= top) & (E.begLine > 0) & (keys # {}) DO Wait (mx, my, keys, keysum); ScrollDown END; IF (my > bot) & (my <= top) THEN newCmd := (top - my) DIV E.lsp + E.begLine; IF newCmd # cmd THEN Flip(FALSE, cmd); Flip(TRUE, newCmd); cmd:=newCmd END ELSIF (mx < ex) OR (mx >= ex+ew) OR (my < ey) OR (my >= ey+eh) OR (newCmd >= 0) THEN Flip(FALSE, cmd); cmd := -1; sel.id := IDSelect END ELSIF (mx < ex) OR (mx >= ex+ew) OR (my < ey) OR (my >= ey+eh) OR (newCmd >= 0) THEN Flip(FALSE, cmd); cmd := -1; sel.id := IDSelect END; UNTIL (keys = {}) OR ((keys = {ML, MM}) & (father # NIL) & (sel.id # IDCancel)) OR (sel.id = IDExecute); IF  mouse not in Elem and not in Popup  THEN sel.id := IDCancel END; IF MW # NIL THEN MW.Close (); MW := NIL END; IF ML IN keys THEN INCL (keysum, ML) END; (*Out.F("keysum = #$", SYSTEM.VAL(LONGINT, keysum)); IF keysum = cancel THEN HALT(99) END;*) Oberon.FadeCursor(Oberon.Mouse); Bitmaps.CopyBlock(B, Bitmaps.Disp, 0, 0, W, H, X, Y, 0) END SelectMenu; 8y/8Syntax10.Scn.Fnt8FoldElemsNew#Syntax10.Scn.Fnt IF (X + menuW) <= (Display.Width - 2) THEN menuX := X ELSE menuX := Max (X + W - menuW, 2) END; IF Y - menuH >= 2 THEN menuY := Y - menuH ELSIF (Y + H + menuH) <= (Display.Height - 2) THEN menuY := Y + H ELSE menuY := 2 ENDSyntax10i.Scn.Fnt#88#Syntax10.Scn.FntDD IF (X + father.wid + menuW - 10) <= (Display.Width - 2) THEN menuX := X + father.wid - 10 ELSIF (X - menuW) >= 2 THEN menuX := X - menuW ELSE menuX := Display.Width - 2 - menuW END; IF Y + H - menuH >= 2 THEN menuY := Y + H - menuH ELSIF Y + menuH <= (Display.Height - 2) THEN menuY := Y ELSE menuY := 2 END8 VAR W, H, menuX, menuY, menuW, menuH, cmd, i: INTEGER; r: Texts.Reader; keys: SET; draw: TextFrames.DisplayMsg; exec: ExecMsg; BEGIN draw.prepare := FALSE; draw.fnt := fnt; draw.col := col; draw.frame := F; DrawMenu (E, F, 0, 0, 0, 0, TRUE); draw.X0 := X; draw.Y0 := Y; W := SHORT(E.W DIV DUnit); H := SHORT(E.H DIV DUnit) - 2; menuW := E.wid + 2*mhm; menuH := E.n*E.lsp + 2*mvm; IF father = NIL THEN  PopupElem has no father-PopupElem  ELSE  PopupElem is a Sub-PopupElem  END; i := Display.Height - 2*mvm - 2; IF menuH > i THEN menuH := i DIV E.lsp * E.lsp + 2*mvm END; cmd := Max(E.def, 0); IF father = NIL THEN E.elemPressed := TRUE; E.handle(E, draw) END; SelectMenu (E, father, sel, F, menuX, menuY, menuW, menuH, X, Y, W, H, cmd, keys); IF father = NIL THEN E.elemPressed := FALSE; E.handle(E, draw) END; IF (keys = {MM, MR}) & (father = NIL) THEN OpenEditor(E) ELSIF (father # NIL) & (sel.id # IDCancel) THEN IF (keys = {MM}) & (sel.execElem = NIL) THEN ASSERT (sel.id # IDExecute); sel.id := IDExecute; sel.execElem := E; E.def := cmd END ELSIF (keys # cancel) & (sel.id # IDCancel) & (cmd > -1) THEN IF sel.execElem = NIL THEN E.def := cmd; Set (r, E.menu, (* E.beg,*) cmd); exec.frame := F; exec.pos := Texts.Pos(r); exec.keys := keys; E.handle(E, exec); ELSE exec.frame := F; exec.pos := sel.pos; exec.keys := {MM}; sel.execElem.handle (sel.execElem, exec) END; ELSE sel.id := IDCancel END END Popup; 8` PROCEDURE ExecCmd (E: Elem; F: Display.Frame; pos: LONGINT; keys: SET);  PROCEDURE SelectMenu (E, father: Elem; VAR sel: SelectMsg; F: Display.Frame; X, Y, W, H, ex, ey, ew, eh: INTEGER; VAR cmd: INTEGER; VAR keysum: SET);  PROCEDURE Popup (E, father: Elem; VAR sel: SelectMsg; col: SHORTINT; X, Y: INTEGER; fnt: Fonts.Font; F: Display.Frame);  8D8eSyntax10.Scn.Fnt Syntax10m.Scn.Fnt+8FoldElemsNewSyntax10.Scn.Fnt| 8FoldElemsNew#Syntax10.Scn.Fnt IF msg.e = NIL THEN IF E IS CmdElem THEN NEW(cmdE); e := cmdE ELSE NEW (e) END; msg.e := e ELSE e := msg.e(Elem) END; Texts.CopyElem(E, e); e.name:=E.name; e.n := E.n; e.wid:=E.wid; e.lsp:=E.lsp; e.dsc:=E.dsc; e.small := E.small; e.def := E.def; e.elemPressed := FALSE; e.menu:=TextFrames.Text(""); NEW (localBuf); Texts.OpenBuf (localBuf); Texts.Save(E.menu, 0, E.menu.len, localBuf); Texts.Append(e.menu, localBuf)Syntax10i.Scn.Fnt8+8#Syntax10.Scn.Fnt(( IF msg.id = IDSelect THEN WHILE msg.keys = {ML, MM} DO Input.Mouse (msg.keys, x, y); Oberon.DrawCursor(Oberon.Mouse, Oberon.Arrow, x, y) END; Popup (E, msg.elem, msg, msg.col, msg.X0, msg.Y0, msg.fnt, msg.frame); indices := indices.prev; ASSERT (indices # NIL) END8 8#Syntax10.Scn.Fnt IF msg.keys = {MM} THEN indices := NIL; Popup (E, NIL, sel, msg.col, msg.X0, msg.Y0, msg.fnt, msg.frame); msg.keys := {}; indices := indices.prev; ASSERT (indices = NIL) END8{ VAR e: Elem; x, y: INTEGER; localBuf: Texts.Buffer; sel: SelectMsg; cmdE: CmdElem; BEGIN WITH E: Elem DO WITH msg: TextFrames.DisplayMsg DO IF msg.prepare THEN MeasureElem(E, msg.fnt) ELSE DrawElem(E, msg.col, msg.X0, msg.Y0, msg.fnt) END | msg:TextPrinter.PrintMsg DO IF ~msg.prepare THEN PrintElem(E, msg.X0, msg.Y0, msg.fnt) END | msg:Texts.CopyMsg DO  Copy elem recursively  | msg:Texts.IdentifyMsg DO msg.mod:="PopupElems"; IF E IS CmdElem THEN msg.proc := "AllocCmd" ELSE msg.proc:="Alloc" END | msg:Texts.FileMsg DO IF msg.id=Texts.load THEN Load(msg.r, E); (* MeasureMenu(E) *) ELSIF msg.id=Texts.store THEN Store(msg.r, E) END | msg: SelectMsg DO  Open sub-PopupElem  | msg:TextFrames.TrackMsg DO  Open PopupElem  | msg: ExecMsg DO IF ~(E IS CmdElem) THEN ExecCmd(E, msg.frame, msg.pos, msg.keys) END ELSE END END END Handle; 8 8#Syntax10.Scn.FntGG VAR E: Elem; BEGIN NEW(E); E.handle:=Handle; Texts.new:=E END Alloc; 8 8#Syntax10.Scn.FntMM VAR E: CmdElem; BEGIN NEW(E); E.handle:=Handle; Texts.new:=E END AllocCmd; 8. 8#Syntax10.Scn.Fnt VAR S: Texts.Scanner; insert: TextFrames.InsertElemMsg; BEGIN Texts.OpenScanner(S, Oberon.Par.text, Oberon.Par.pos); Texts.Scan(S); IF ~(S.class IN {Texts.Name, Texts.String}) THEN S.s := "Popup" END; COPY (S.s, E.name); E.small := small; E.menu := TextFrames.Text(""); IF ~(E IS CmdElem) THEN SetDefaultMenu(E) END; (* MeasureMenu(E); *) E.handle := Handle; E.elemPressed := FALSE; insert.e := E; Viewers.Broadcast(insert) END Insert0; 8 8#Syntax10.Scn.Fnt== VAR E: Elem; BEGIN NEW (E); Insert0(E, FALSE) END Insert; 8  8#Syntax10.Scn.FntAA VAR E: Elem; BEGIN NEW (E); Insert0(E, TRUE) END InsertMenu; 8  8#Syntax10.Scn.FntTT VAR E: CmdElem; BEGIN NEW (E); Insert0(E, TRUE); E.name [0] := 0X END InsertCmd; 8 98#Syntax10.Scn.Fnt VAR E: Elem; BEGIN IF Oberon.Par.frame = Oberon.Par.vwr.dsc THEN E := Oberon.Par.frame.next(EditFrame).elem; E.small := ~E.small; Restore(E) END END Toggle; 8 Q8#Syntax10.Scn.Fnt VAR F: EditFrame; S: Texts.Scanner; menuText: Texts.Text; E: Elem; BEGIN IF Oberon.Par.frame = Oberon.Par.vwr.dsc THEN F := Oberon.Par.frame.next(EditFrame); E := F.elem; menuText := Oberon.Par.frame(TextFrames.Frame).text; Texts.OpenScanner(S, menuText, 0); Texts.Scan(S); IF ~(S.class IN {Texts.Name, Texts.String}) THEN S.s := "Popup" END; COPY(S.s, E.name); E.menu := CopyText(F.text, FALSE); IF E IS CmdElem THEN E.name [0] := 0X END; (* MeasureMenu(E);*) Restore(E); Texts.OpenReader(S, menuText, menuText.len-1); Texts.Read(S, S.c); IF S.c = "!" THEN Texts.Delete(menuText, menuText.len-1, menuText.len) END END END Update; 8  8#Syntax10.Scn.Fnt VAR S: Texts.Scanner; BEGIN Texts.OpenScanner(S, Oberon.Par.text, Oberon.Par.pos); Texts.Scan(S); IF S.class IN {Texts.Name, Texts.String} THEN IF S.s = "Off" THEN showHelp := FALSE ELSIF S.s = "On" THEN showHelp := TRUE END END END HelpText; 8  8#Syntax10.Scn.Fnt   VAR S: Texts.Scanner; BEGIN Texts.OpenScanner(S, Oberon.Par.text, Oberon.Par.pos); Texts.Scan(S); IF S.class IN {Texts.Name, Texts.String} THEN IF S.s = "Off" THEN showCommands := FALSE ELSIF S.s = "On" THEN showCommands := TRUE END END END ShowCommands; 8^8CSyntax10.Scn.FntySyntax10i.Scn.Fnt"` VAR e: Elem; fnt: Fonts.Font; BEGIN Texts.OpenWriter(Wr); showHelp := TRUE; showCommands := FALSE; indices := NIL; (* Initialization of MsgWindows *) fnt := MsgWindows.butFnt; NEW (e); e.name := "No"; e.small := FALSE; e.menu := TextFrames.Text (""); e.handle := Handle; MeasureElem (e, fnt); MsgWindows.defElems [MsgWindows.BNo] := e; NEW (e); e.name := "Yes"; e.small := FALSE; e.menu := TextFrames.Text (""); e.handle := Handle; MeasureElem (e, fnt); MsgWindows.defElems [MsgWindows.BYes] := e; NEW (e); e.name := "Cancel"; e.small := FALSE; e.menu := TextFrames.Text (""); e.handle := Handle; MeasureElem (e, fnt); MsgWindows.defElems [MsgWindows.BCancel] := e; NEW (e); e.name := "Add to Log"; e.small := FALSE; e.menu := TextFrames.Text (""); e.handle := Handle; MeasureElem (e, fnt); MsgWindows.defElems [MsgWindows.BAddToLog] := e END Init; 8X PROCEDURE Handle* (E: Texts.Elem; VAR msg: Texts.ElemMsg);  PROCEDURE Alloc*;  PROCEDURE AllocCmd*;  PROCEDURE Insert0 (E: Elem; small: BOOLEAN);  PROCEDURE Insert*;  PROCEDURE InsertMenu*;  PROCEDURE InsertCmd*;  PROCEDURE Toggle*;  PROCEDURE Update*;  PROCEDURE HelpText*;  PROCEDURE ShowCommands*;  PROCEDURE Init;  8a8#Syntax10.Scn.Fnt""Folds.Compile^ PopupElems.Mod/s OpenElems.Mod/s DirElems.Mod/s HandlerElems.Mod/s AutoMenuElems.Mod/s FontElems.Mod/s LinkElems.Mod/s CommandElems.Mod/s ViewerBar.Mod/s VersionElems.Mod/s Inspector.Mod/s BalloonElems.Mod/s InfoElems.Mod/s ~ HeapInspector.Mod/s HeapInspViewers.Mod/s 8<9MODULE PopupElems; (** MF 27.1.92 /MH/CM/MAH/HM/MR/NP  *) IMPORT Modules, Oberon, Input, Display, Viewers, Files, Fonts, Printer, Texts, MenuViewers, TextFrames, TextPrinter, Bitmaps, MsgWindows, Strings; CONST  TYPE  VAR  (* auxiliary *)  (* metrics *)  (* interactive editing of popup menus *)  (* file input/output *)  (* graphics *)  (* actions *)  (* element *)  BEGIN Init END PopupElems. Edit.Store * ~ Folds.Compile * ~ System.Quit ~ System.Directory * ~  Compile Elems  PopupElems.ShowCommands On ~ PopupElems.ShowCommands Off ~