Syntax10.Scn.Fnt StampElems Alloc 7 May 96 Syntax10b.Scn.Fnt Syntax10i.Scn.Fnt FoldElems MODULE PopupElems; (** MF 27.1.92 /MH/CM/MAH/HM, old Style by Ralf Degner IMPORT Modules, Oberon, Input, Display, Viewers, Files, Fonts, Printer, Texts, MenuViewers, TextFrames, TextPrinter, Bitmaps; CONST oldStyle = TRUE; (* use old ETH or new Linz style *) (*<y THEN RETURN x ELSE RETURN y END END Max; PROCEDURE CopyText (T: Texts.Text): Texts.Text; VAR t: Texts.Text; buf: Texts.Buffer; (*Save destroys the global buf*) BEGIN NEW(buf); Texts.OpenBuf(buf); Texts.Save(T, 0, T.len, buf); t := TextFrames.Text(""); Texts.Append(t, buf); RETURN t END CopyText; PROCEDURE SetDefaultMenu (E: Elem); BEGIN Texts.WriteString(Wr, "right interclick to edit menu"); Texts.WriteLn(Wr); Texts.WriteLn(Wr); Texts.Append(E.menu, Wr.buf) END SetDefaultMenu; PROCEDURE Set (VAR r: Texts.Reader; t: Texts.Text; pos: LONGINT; line: INTEGER); VAR i: INTEGER; ch: CHAR; BEGIN Texts.OpenReader(r, t, pos); FOR i := 0 TO line-1 DO REPEAT Texts.Read(r, ch) UNTIL ch = CR END Set; PROCEDURE Restore (e: Elem); 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; (* metrics *) PROCEDURE MeasureElem (E: Elem; fnt: Fonts.Font); VAR i, wid, dx, x, y, w, h: INTEGER; p: LONGINT; BEGIN IF E.small THEN E.H := LONG(TextFrames.menuH-1)*DUnit ELSE E.H := LONG(fnt.maxY-fnt.minY+2*evm)*DUnit END; IF oldStyle & E.small THEN wid:=0 ELSE wid := 2*ehm END; (* no offset for small oldStyle *) (*< 1 THEN IF oldStyle THEN Display.ReplConst(Display.white, X, Y, W, H, Display.replace); Display.ReplConst(Display.black, X+1, Y+1, W-2, H-2, Display.replace) ELSE Display.ReplConst(black, X, Y, W, H, Display.replace); Display.ReplConst(grey2, X+1, Y+1, W-2, H-2, Display.replace) END; bot := Y + mvm - E.dsc; X0 := X + mhm; X := X0; Y := Y + H - mvm - E.lsp - E.dsc; Texts.OpenReader(R, E.menu, 0); WHILE ~R.eot & (Y >= bot) DO DrawLine(R, F, X, Y); Y := Y - E.lsp; X := X0 END; E.end := Texts.Pos(R) END DrawMenu; (* actions *) PROCEDURE ExecCmd (E: Elem; F: Display.Frame; pos: LONGINT; keys: SET); VAR s: Texts.Scanner; par: Oberon.ParList; res, i, j: INTEGER; ch: CHAR; m: TextFrames.TrackMsg; BEGIN Texts.OpenScanner(s, E.menu, pos); Texts.Scan(s); 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); m.frame := NIL; m.keys := {MM}; s.elem.handle(s.elem, m) END ExecCmd; PROCEDURE SelectMenu (E: Elem; F: Display.Frame; X, Y, W, H, ex, ey, ew, eh: INTEGER; VAR cmd: INTEGER; VAR keysum: SET); VAR mx, my, top, bot, left, right, newCmd: INTEGER; keys: SET; B: Bitmaps.Bitmap; PROCEDURE TrackMouse (VAR x, y: INTEGER; VAR keys, keysum: SET); BEGIN Input.Mouse(keys, x, y); keysum := keysum+keys; Oberon.DrawCursor(Oberon.Mouse, Oberon.Arrow, x, y) END TrackMouse; PROCEDURE Flip (in: BOOLEAN; cmd: INTEGER); VAR R: Texts.Reader; x, y, w, h, X0, Y0: INTEGER; BEGIN IF (E.n > 1) & (cmd >= 0) THEN X0 := X+mhm; Y0 := Y+H-(E.lsp*(cmd+1))-E.dsc-mvm; x := left; y := Y0 + E.dsc - 1; w := right - left + 1; h := E.lsp + 2; Oberon.RemoveMarks(x, y, w, h); (*<= 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.end < E.menu.len) & (keys # {}) DO ScrollUp; TrackMouse(mx, my, keys, keysum) END; WHILE (my >= top) & (E.beg > 0) & (keys # {}) DO Oberon.RemoveMarks(X, Y, W, H); (*< bot) & (my <= top) THEN newCmd:=(top-my) DIV E.lsp; 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 END ELSIF (mx < ex) OR (mx >= ex+ew) OR (my < ey) OR (my >= ey+eh) OR (newCmd >= 0) THEN Flip(FALSE, cmd); cmd := -1 END UNTIL keys = {}; (*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; PROCEDURE Popup (E: Elem; col: SHORTINT; X, Y: INTEGER; fnt: Fonts.Font; F: Display.Frame); 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; draw.X0 := X; draw.Y0 := Y; W := SHORT(E.W DIV DUnit); H := SHORT(E.H DIV DUnit); menuW := E.wid + 2*mhm; menuH := E.n*E.lsp + 2*mvm; IF Y - menuH >= 0 THEN menuY := Y - menuH ELSIF Y + H + menuH <= Display.Height THEN menuY := Y + H ELSE menuY := 0 END; IF X + menuW <= Display.Width THEN menuX := X ELSE menuX := Max(X + W - menuW, 0) END; i := Display.Height - 2*mvm; IF menuH > i THEN menuH := i DIV E.lsp * E.lsp + 2*mvm END; cmd := Max(E.def, 0); fullPlot := ~oldStyle; (*< -1) 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) END Popup; (* element *) PROCEDURE Handle* (E: Texts.Elem; VAR msg: Texts.ElemMsg); VAR e: Elem; 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 IF msg.e = NIL THEN NEW(e); 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.menu:=TextFrames.Text(""); Texts.Save(E.menu, 0, E.menu.len, buf); Texts.Append(e.menu, buf) | msg:Texts.IdentifyMsg DO msg.mod:="PopupElems"; msg.proc:="Alloc" | 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:TextFrames.TrackMsg DO IF msg.keys = {MM} THEN Popup(E, msg.col, msg.X0, msg.Y0, msg.fnt, msg.frame); msg.keys := {} END | msg: ExecMsg DO ExecCmd(E, msg.frame, msg.pos, msg.keys) ELSE END END Handle; PROCEDURE Alloc*; VAR E: Elem; BEGIN NEW(E); E.handle:=Handle; Texts.new:=E END Alloc; PROCEDURE Insert0 (small: BOOLEAN); VAR E: Elem; S: Texts.Scanner; insert: TextFrames.InsertElemMsg; BEGIN NEW(E); 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(""); SetDefaultMenu(E); MeasureMenu(E); E.handle := Handle; insert.e := E; Viewers.Broadcast(insert) END Insert0; PROCEDURE Insert*; BEGIN Insert0(FALSE) END Insert; PROCEDURE InsertMenu*; BEGIN Insert0(TRUE) END InsertMenu; PROCEDURE Toggle*; 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 Toggle; PROCEDURE Update*; 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); 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 Update; BEGIN elemPressed := FALSE; fullPlot := TRUE; NEW(buf); Texts.OpenBuf(buf); Texts.OpenWriter(Wr) END PopupElems.