ð Syntax10.Scn.FntSyntax10i.Scn.Fntõÿÿÿ€‹ðIStampElemsAlloc22 Feb 99$7þÿÿÐûqBalloonElemsAlloc{Syntax10.Scn.FntuSyntax10i.Scn.Fnt  =BN"SelCol" Is the color for a selected Line. "DefaultCol" Is the color for a non selected line. "MoveLine" PROCEDURE MoveLine*; (* fromList toList Value *) Moves the Value from one list to another. To delete a line from a list, set toList to an empty string. To copy a line from one list to another, set fromList to an empty string. ÌSyntax10b.Scn.Fnt 0Ý     "^ÿÿÿÿ€8ÀÔFoldElemsNew`ÿÿÿÿ€8ÀÔ üÿÿÿÀÔ°­MarkElemsAlloc‰“rÿÿÿÿ€8ÀÔœÿÿÿÿ€8ÀÔ üÿÿÿÀÔ°­æÝ=ÿÿÿÿ€8ÀÔÿÿÿÿ€8ÀÔ üÿÿÿÀÔ°­ÝÛö=ÿÿÿÿ€8ÀÔÝÿÿÿÿ€8ÀÔ üÿÿÿÀÔ°­ñ(hBÿÿÿÿ€8ÀÔ<Íÿÿÿ€8ÀÔ#Syntax10.Scn.Fnt go to next line ,ÿÿÿÿ€8ÀÔ{ÿÿÿÿ€8ÀÔ üÿÿÿÀÔ°­ñ(h%´ÿÿÿ€8ÀÔ#Syntax10.Scn.Fnt** set current activated pos according to s yÿÿÿÿ€8ÀÔoüÿÿÿÀÔ°­²ºLGÿÿÿÿ€8ÀÔ0ÿÿÿÿ€8ÀÔ üÿÿÿÀÔ°­G'ÿÿÿÿ€8ÀÔWÿÿÿÿ€8ÀÔ üÿÿÿÀÔ°­ï‚&ÿÿÿÿ€8ÀÔÐÿÿÿÿ€8ÀÔ üÿÿÿÀÔ°­ Ó8 ÿÿÿÿ€8ÀÔ^ÿÿÿÿ€8ÀÔ üÿÿÿÀÔ°­oGÿÿÿÿ€8ÀÔ) `ÿÿÿÿ€8ÀÔ üÿÿÿÀÔ°­©®rÿÿÿÿ€8ÀÔÍÿÿÿÿ€8ÀÔ üÿÿÿÀÔ°­yÄ–6ÿÿÿÿ€8ÀÔpÿÿÿÿ€8ÀÔ üÿÿÿÀÔ°­Hõæ[ÿÿÿÿ€8ÀÔ Óÿÿÿ€8ÀÔ#Syntax10.Scn.Fnt scroll up åÿÿÿÿ€8ÀÔÑÿÿÿ€8ÀÔ#Syntax10.Scn.Fnt scroll down ¹ÿÿÿÿ€8ÀÔÌÿÿÿ€8ÀÔ#Syntax10.Scn.Fnt outside the list Oÿÿÿÿ€8ÀÔÍÿÿÿ€8ÀÔ#Syntax10.Scn.Fnt inside the list ÿÿÿÿ€8ÀÔÿÿÿÿ€8ÀÔ üÿÿÿÀÔ°­ª´4ÿÿÿÿ€8ÀÔRÿÿÿÿ€8ÀÔ üÿÿÿÀÔ°­²ëÀ0ÿÿÿÿ€8ÀÔäÿÿÿÿ€8ÀÔ üÿÿÿÀÔ°­Hõæ]ÿÿÿÿ€8ÀÔüÓÿÿÿ€8ÀÔ#Syntax10.Scn.Fnt scroll up ÿÿÿÿ€8ÀÔÑÿÿÿ€8ÀÔ#Syntax10.Scn.Fnt scroll down ëÿÿÿÿ€8ÀÔÏÿÿÿ€8ÀÔ#Syntax10.Scn.Fnt track outside ÿÿÿÿ€8ÀÔÐÿÿÿ€8ÀÔ#Syntax10.Scn.Fnt track inside êÿÿÿÿ€8ÀÔÿÿÿÿ€8ÀÔHÿÿÿÿ€8ÀÔþÿÿÿÿ€8ÀÔ#ÿÿÿÿ€8ÀÔyÿÿÿÿ€8ÀÔ üÿÿÿÀÔ°­ ©9ÿÿÿÿ€8ÀÔfÿÿÿÿ€8ÀÔ üÿÿÿÀÔ°­ýbA@ÿÿÿÿ€8ÀÔÿÿÿÿ€8ÀÔ üÿÿÿÀÔ°­d}÷1ÿÿÿÿ€8ÀÔ#Ìÿÿÿ€8ÀÔ#Syntax10.Scn.Fnt inside scrollbar )ÿÿÿÿ€8ÀÔ`ÿÿÿÿ€8ÀÔÿÿÿÿ€8ÀÔ»ÿÿÿÿ€8ÀÔfÿÿÿÿ€8ÀÔäÿÿÿÿ€8ÀÔ_ÿÿÿÿ€8ÀÔÿÿÿÿ€8ÀÔ+|ÿÿÿÿ€8ÀÔÿÿÿÿ€8ÀÔ+tÿÿÿÿ€8ÀÔµÏÿÿÿ€8ÀÔ#Syntax10.Scn.Fnt has selection  ÿÿÿÿ€8ÀÔ¯ÿÿÿÿ€8ÀÔ üÿÿÿÀÔ°­d}÷1ÿÿÿÿ€8ÀÔGÿÿÿÿ€8ÀÔ üÿÿÿÀÔ°­Àü ;ÿÿÿÿ€8ÀÔ®ÿÿÿÿ€8ÀÔ üÿÿÿÀÔ°­&Wÿÿÿÿ€8ÀÔqÿÿÿÿ€8ÀÔ üÿÿÿÀÔ°­³ÀÎMÿÿÿÿ€8ÀÔj#ÿÿÿÿÿ€8ÀÔ üÿÿÿÀÔ°­“r!1ÿÿÿÿ€8ÀÔ7ÿÿÿÿ€8ÀÔÿÿÿÿ€8ÀÔÿÿÿÿ€8ÀÔK//»!ÿÿÿÿ€8ÀÔ ÿÿÿÿ€8ÀÔÿÿÿÿ€8ÀÔ3ÿÿÿÿ€8ÀÔ üÿÿÿÀÔ°­HŠJÿÿÿÿ€8ÀÔåÿÿÿÿ€8ÀÔ üÿÿÿÀÔ°­KŠ+ÿÿÿÿ€8ÀÔ }Y ÿÿÿÿ€8ÀÔ üÿÿÿÀÔ°­Dd< ÿÿÿÿ€8ÀÔõÿÿÿÿ€8ÀÔ üÿÿÿÀÔ°­LŠÿÿÿÿ€8ÀÔ=ÿÿÿÿ€8ÀÔ üÿÿÿÀÔ°­MŠÿÿÿÿ€8ÀÔ™ÿÿÿÿ€8ÀÔ ÿÿÿÿ€8ÀÔêÿÿÿÿ€8ÀÔ üÿÿÿÀÔ°­ôŠk "°ÿÿÿ€8ÀÔ#Syntax10.Scn.Fnt.. del line from fromName, add string to toName aÿÿÿÿ€8ÀÔ üÿÿÿÀÔ°­@2 ÿÿÿÿ€8ÀÔðÿÿÿÿ€8ÀÔOˆkMODULE ListElems; (* CE , parc-handling RLI, 15. Oct 1998 *)  IMPORT Texts, TextFrames, TextPrinter, Oberon, Display, Viewers, Files, Fonts, Elems, GU := GUtils, MenuViewers, Input, Bitmaps, In, Out; CONST DUnit = TextFrames.Unit; ML = 2; MM = 1; MR = 0; SelCol* = 0; DefaultCol* = 15; delay = 70; (* types for opentextframe *) list = 1; popup = 2; combo = 3; bW = 15; (* width of popup-button *) arrW = 9; arrH = 5; (* dim of arrow *) TYPE Elem* = POINTER TO ElemDesc; Frame = POINTER TO FrameDesc; FrameDesc = RECORD(Display.FrameDesc) e : Elem; END; EditFrame = POINTER TO EditFrameDesc; EditFrameDesc = RECORD (TextFrames.FrameDesc) e : Elem END; ElemDesc* = RECORD (Elems.ElemDesc) comboTxt*, txt* : Texts.Text; scrbar*, popup*, combo*, multi* : BOOLEAN; popupH* : INTEGER; (** in pixels *) pos* : LONGINT; (** pos of current line *) org* : LONGINT; (** pos of first displayed line *) END; VAR W : Texts.Writer; arrow : Display.Pattern; curElem : Elem; ex, ey : INTEGER; (* coords of curElem *) PROCEDURE Delay(); VAR t: LONGINT; BEGIN t := Oberon.Time () + delay; WHILE t > Oberon.Time () DO END END Delay; PROCEDURE SetComboText (e : Elem); VAR buf: Texts.Buffer; r : Texts.Reader; ch : CHAR; BEGIN Texts.OpenReader(r, e.txt, e.pos); REPEAT Texts.Read(r, ch) UNTIL (ch = Elems.CR) OR r.eot; NEW(buf); Texts.OpenBuf(buf); Texts.Save(e.txt, e.pos, Texts.Pos(r) - 1, buf); Texts.Delete(e.comboTxt, 0, e.comboTxt.len); Texts.Append(e.comboTxt, buf); Texts.ChangeLooks(e.comboTxt, 0, e.comboTxt.len, {1}, Fonts.Default, DefaultCol, 0); END SetComboText; PROCEDURE LineOfPos(t : Texts.Text; pos : LONGINT; VAR line : LONGINT); VAR r : Texts.Reader; ch : CHAR; BEGIN IF (pos < 0) OR (pos > t.len) THEN line := 0; RETURN END; line := 1; Texts.OpenReader(r, t, 0); Texts.Read(r, ch); WHILE ~r.eot & (Texts.Pos(r) <= pos) DO IF ch = Elems.CR THEN INC(line) END; Texts.Read(r, ch); END; END LineOfPos; PROCEDURE PosOfLine(t : Texts.Text; line : LONGINT; VAR pos : LONGINT); VAR r : Texts.Reader; ch : CHAR; BEGIN Texts.OpenReader(r, t, 0); Texts.Read(r, ch); WHILE ~r.eot & (line > 0) DO IF ch = Elems.CR THEN DEC(line) END; Texts.Read(r, ch) END; pos := Texts.Pos(r) - 2 END PosOfLine; PROCEDURE Find (t : Texts.Text; s : ARRAY OF CHAR; VAR beg, end : LONGINT);  VAR r : Texts.Reader; i : INTEGER; ch : CHAR; BEGIN i := 0; Texts.OpenReader(r, t, 0); Texts.Read(r, ch); WHILE ~r.eot & (s[i] # 0X) DO IF ch = s[0] THEN i := 0; beg := Texts.Pos(r) - 1; WHILE ~r.eot & (s[i] # 0X) & (s[i] = ch) DO Texts.Read(r, ch); INC(i) END; IF (ch # Elems.CR) OR (s[i] # 0X) THEN (* not equal *) i := 0; WHILE ch # Elems.CR DO Texts.Read(r, ch) END END END; Texts.Read(r, ch) END; IF s[i] # 0X THEN beg := -1; end := -1 ELSE end := Texts.Pos(r) - 1 END END Find; PROCEDURE SetPos (e : Elem; s : ARRAY OF CHAR); VAR beg, end : LONGINT; BEGIN Find(e.txt, s, beg, end); IF beg = -1 THEN e.pos := 0 ELSE e.pos := beg END; END SetPos; PROCEDURE ^OpenTextFrame(e : Elem; x, y, w, h, type : INTEGER; pos : LONGINT) : TextFrames.Frame; PROCEDURE TextLineToString(t : Texts.Text; pos : LONGINT; VAR s : ARRAY OF CHAR); VAR i : INTEGER; r: Texts.Reader; ch : CHAR; len : LONGINT; BEGIN i := 0; len := LEN(s); Texts.OpenReader(r, t, pos); Texts.Read(r, ch); WHILE ~r.eot & (i < len - 1) & (ch # Elems.CR) DO IF ch # Texts.ElemChar THEN s[i] := ch; INC(i) END; Texts.Read(r, ch) END; s[i] := 0X END TextLineToString; PROCEDURE SelToText(t : Texts.Text) : Texts.Text; VAR r : Texts.Reader; ch : CHAR; res : Texts.Text; copy : Texts.CopyMsg; BEGIN res := TextFrames.Text(""); Texts.OpenReader(r, t, 0); Texts.Read(r, ch); WHILE ~r.eot DO IF r.col = SelCol THEN WHILE ~r.eot & (ch # Elems.CR) DO IF ch = Texts.ElemChar THEN copy.e := NIL; r.elem.handle(r.elem, copy); Texts.WriteElem(W, copy.e) ELSE Texts.Write(W, ch) END; Texts.Read(r, ch) END; Texts.WriteLn(W) ELSE WHILE ~r.eot & (ch # Elems.CR) DO Texts.Read(r, ch) END END; Texts.Read(r, ch) END; Texts.Append(res, W.buf); RETURN res END SelToText; PROCEDURE FirstSelPos(t : Texts.Text) : LONGINT; VAR r : Texts.Reader; ch : CHAR; BEGIN Texts.OpenReader(r, t, 0); Texts.Read(r, ch); WHILE ~r.eot DO IF r.col = SelCol THEN RETURN Texts.Pos(r) END; Texts.Read(r, ch); END; RETURN -1 END FirstSelPos; PROCEDURE RemoveSelection(t : Texts.Text); BEGIN Texts.ChangeLooks(t, 0, t.len, {1}, Fonts.Default, DefaultCol, 0) END RemoveSelection; PROCEDURE InvertSelection (f : TextFrames.Frame; pos : LONGINT; multi : BOOLEAN); VAR r : Texts.Reader; col : SHORTINT; ch : CHAR; BEGIN Texts.OpenReader(r, f.text, pos); Texts.Read(r, ch); IF r.col = SelCol THEN col := DefaultCol ELSE col := SelCol END; WHILE ~r.eot & (ch # Elems.CR) DO Texts.Read(r, ch) END; IF ~multi & (col = SelCol) THEN RemoveSelection(f.text) END; (* only one selection allowed *) Texts.ChangeLooks(f.text, pos, Texts.Pos(r), {1}, Fonts.Default, col, 0); END InvertSelection; PROCEDURE CopyOver (t : Texts.Text); VAR msg : Oberon.CopyOverMsg; selT : Texts.Text; BEGIN selT := SelToText(t); IF selT.len > 0 THEN msg.text := selT; msg.beg := 0; msg.end := msg.text.len; Viewers.Broadcast(msg) END END CopyOver; PROCEDURE SetFrameCoords (src : Frame; dest : TextFrames.Frame); BEGIN dest.X := src.X + 2; dest.Y := src.Y + 2; dest.H := src.H - 4; dest.W := src.W - 4; END SetFrameCoords; PROCEDURE TrackText (VAR keysum : SET; VAR x, y : INTEGER; f : TextFrames.Frame; VAR done : BOOLEAN); VAR keys : SET; ox, oy : INTEGER; R : Texts.Reader; oldloc, sloc, loc : TextFrames.Location; oend, end : LONGINT; ch : CHAR; N : Oberon.ControlMsg; wasin : BOOLEAN; BEGIN wasin := FALSE; N.id := Oberon.neutralize; Input.Mouse(keys, x, y); keysum := {}; TextFrames.LocateLine(f, y, loc); end := TextFrames.Pos(f, f.X + f.W, loc.y); IF ~curElem.popup THEN TextFrames.SetSelection(f, loc.org, end+1) END; oldloc := loc; oend := -1; ox := x; oy := y; WHILE (keys # {}) & ((y < f.Y) OR (y > f.Y + f.H)) DO Input.Mouse(keys, x, y); keysum := keysum + keys; Oberon.DrawCursor(Oberon.Mouse, Oberon.Arrow, x, y) END; WHILE keys # {} DO Input.Mouse(keys, x, y); keysum := keysum + keys; Oberon.DrawCursor(Oberon.Mouse, Oberon.Arrow, x, y); IF (ox # x) OR (oy # y) THEN WHILE wasin & (y > f.Y + f.H) & (f.org > 0) & (keys = {MM}) DO Delay(); TextFrames.Show(f, f.org - 1); Input.Mouse(keys, x, y); keysum := keysum + keys; Oberon.DrawCursor(Oberon.Mouse, Oberon.Arrow, x, y); END;  WHILE wasin & (y < f.Y) & (oend < f.text.len - 1) & (keys = {MM}) DO Delay(); Texts.OpenReader(R, f.text, f.org); Texts.Read(R, ch); WHILE ch # Elems.CR DO Texts.Read(R, ch) END; TextFrames.Show(f, Texts.Pos(R) + 1); TextFrames.LocateLine(f, f.Y, sloc); oend := TextFrames.Pos(f, f.X + f.W, sloc.y); Input.Mouse(keys, x, y); keysum := keysum + keys; Oberon.DrawCursor(Oberon.Mouse, Oberon.Arrow, x, y); END;  IF (x < f.X + f.left) OR (x > f.X + f.W) OR (y < f.Y) OR (y > f.Y + f.H) THEN f.handle(f, N); WHILE ((x < f.X + f.left) OR (x > f.X + f.W) OR (y < f.Y) OR (y > f.Y + f.H)) & (keys # {}) DO Input.Mouse(keys, x, y); keysum := keysum + keys; Oberon.DrawCursor(Oberon.Mouse, Oberon.Arrow, x, y) END; oend := -1; (* invalidate current line *) END; TextFrames.LocateLine(f, y, loc); end := TextFrames.Pos(f, f.X + f.W, loc.y); IF (oend # end) OR (loc.org # oldloc.org) THEN f.handle(f, N); oldloc := loc; oend := end; TextFrames.SetSelection(f, loc.org, end+1); wasin := TRUE; END; ox := x; oy := y; END; END; f.handle(f, N); Oberon.DrawCursor(Oberon.Mouse, Oberon.Arrow, x, y); IF ~(MR IN keysum) & (loc.org # f.text.len) & (x > f.X + f.left) & (x < f.X + f.W) & (y > f.Y) & (y < f.Y + f.H) THEN curElem.pos := loc.org; done := TRUE END END TrackText; PROCEDURE PrevSelPos(t : Texts.Text; pos : LONGINT) : LONGINT; VAR lastPos : LONGINT; r : Texts.Reader; ch : CHAR; BEGIN lastPos := -1; Texts.OpenReader(r, t, 0); Texts.Read(r, ch); WHILE ~r.eot & (Texts.Pos(r)-1 # pos) DO IF r.col = SelCol THEN lastPos := Texts.Pos(r) - 1 END; WHILE ~r.eot & (ch # Elems.CR) DO Texts.Read(r, ch) END; Texts.Read(r, ch) END; RETURN lastPos END PrevSelPos; PROCEDURE SelectArea(t : Texts.Text; from , to : LONGINT); VAR r : Texts.Reader; ch : CHAR; BEGIN Texts.OpenReader(r, t, to); Texts.Read(r, ch); WHILE ~r.eot & (ch # Elems.CR) DO Texts.Read(r, ch) END; Texts.ChangeLooks(t, from, Texts.Pos(r) - 1, {1}, NIL, SelCol, 0) END SelectArea; PROCEDURE TrackSelection (VAR keysum : SET; VAR x, y : INTEGER; multi : BOOLEAN; f : TextFrames.Frame); VAR keys : SET; ox, oy : INTEGER; R : Texts.Reader; oldloc, sloc, loc : TextFrames.Location; oend, end : LONGINT; ch : CHAR; BEGIN Input.Mouse(keys, x, y); keysum := {}; TextFrames.LocateLine(f, y, loc); end := TextFrames.Pos(f, f.X + f.W, loc.y); InvertSelection(f, loc.org, multi); oldloc := loc; oend := end; ox := x; oy := y; WHILE keys # {} DO Input.Mouse(keys, x, y); keysum := keysum + keys; Oberon.DrawCursor(Oberon.Mouse, Oberon.Arrow, x, y); IF (ox # x) OR (oy # y) THEN WHILE (y > f.Y + f.H) & (f.org > 0) & ((keys = {MR}) OR (keys = {ML})) DO Delay(); TextFrames.Show(f, f.org - 1); InvertSelection(f, f.org, multi); Input.Mouse(keys, x, y); keysum := keysum + keys; Oberon.DrawCursor(Oberon.Mouse, Oberon.Arrow, x, y); END; WHILE (y < f.Y) & (oend < f.text.len - 1) & ((keys = {MR}) OR (keys = {ML})) DO Delay(); Texts.OpenReader(R, f.text, f.org); Texts.Read(R, ch); WHILE ch # Elems.CR DO Texts.Read(R, ch) END; TextFrames.Show(f, Texts.Pos(R) + 1); TextFrames.LocateLine(f, f.Y, sloc); oend := TextFrames.Pos(f, f.X + f.W, sloc.y); InvertSelection(f, sloc.org, multi); Input.Mouse(keys, x, y); keysum := keysum + keys; Oberon.DrawCursor(Oberon.Mouse, Oberon.Arrow, x, y); END;  IF (x < f.X + f.left) OR (x > f.X + f.W) THEN WHILE ((x < f.X + f.left) OR (x > f.X + f.W)) & ((keys = {MR}) OR (keys = {ML})) DO Input.Mouse(keys, x, y); keysum := keysum + keys; Oberon.DrawCursor(Oberon.Mouse, Oberon.Arrow, x, y) END; oend := -1; (* invalidate current line *) END; TextFrames.LocateLine(f, y, loc); end := TextFrames.Pos(f, f.X + f.W, loc.y); IF ((oend # end) OR (loc.org # oldloc.org)) & (end < f.text.len) THEN oldloc := loc; oend := end; InvertSelection(f, loc.org, multi); END; ox := x; oy := y END END; IF keysum = {MR, ML} THEN end := PrevSelPos(f.text, loc.org); IF end # -1 THEN SelectArea(f.text, end, loc.org) END ELSIF keysum = {MR, MM} THEN CopyOver(f.text) END; Oberon.DrawCursor(Oberon.Mouse, Oberon.Arrow, x, y) END TrackSelection; PROCEDURE HandleEdit (f : Display.Frame; VAR msg : Display.FrameMsg);  VAR f1: EditFrame; BEGIN TextFrames.Handle(f, msg); WITH f : EditFrame DO IF msg IS Oberon.CopyMsg THEN NEW(f1); TextFrames.Open(f1, f.text, f.org); f1.handle := f.handle; f1.e := f.e; msg(Oberon.CopyMsg).F := f1 END END END HandleEdit;  PROCEDURE OpenEditor (e : Elem);  VAR v : Viewers.Viewer; f : EditFrame; x, y : INTEGER; BEGIN Oberon.AllocateUserViewer(Oberon.Mouse.X, x, y); NEW(f); f.e := e; TextFrames.Open(f, Elems.CopyText(e.txt), 0); f.handle := HandleEdit; v := MenuViewers.New(TextFrames.NewMenu("ListElems", "System.Close System.Copy System.Grow Edit.Parcs ListElems.Update "), f, TextFrames.menuH, x, y) END OpenEditor;  PROCEDURE MeasureLine (VAR r : Texts.Reader; VAR lw, lh : INTEGER); VAR ch : CHAR; x, y, w, h, dx, dsr : INTEGER; p : Display.Pattern; pH: LONGINT; BEGIN Texts.Read(r, ch); lw := 0; lh := 0; dsr := 0; y := 0; WHILE ~r.eot & (ch # Elems.CR) DO IF r.elem # NIL THEN h := SHORT(r.elem.H DIV DUnit); dx := SHORT(r.elem.W DIV DUnit); y := r.fnt.minY ELSE Display.GetChar(r.fnt.raster, ch, dx, x, y, w, h, p); INC(y, r.fnt.height * r.voff DIV 64); END ; IF y < dsr THEN dsr := y END ; IF y + h > lh THEN lh := y + h END ; lw := lw + dx; Texts.Read(r, ch) END; IF ~r.eot THEN dsr := -dsr; IF dsr < TextFrames.defParc.dsr DIV TextFrames.Unit THEN dsr := SHORT(TextFrames.defParc.dsr DIV TextFrames.Unit); END; ASSERT(dsr >= 0); lh := lh + dsr; IF lh < TextFrames.defParc.lsp DIV TextFrames.Unit THEN lh := SHORT(TextFrames.defParc.lsp DIV TextFrames.Unit); END; ELSE lh := 0; END; END MeasureLine; PROCEDURE MeasureList(t : Texts.Text; maxH : INTEGER; VAR w, h : INTEGER); VAR r : Texts.Reader; lw, lh : INTEGER; BEGIN IF t.len = 0 THEN w := -1; h := -1; RETURN END; w := 0; h := 0; Texts.OpenReader(r, t, 0); WHILE ~r.eot DO MeasureLine(r, lw, lh); IF lw > w THEN w := lw END ; IF h + lh + 6 <= maxH THEN h := h + lh END END; w := w + 8; h := h + 6; IF w > Display.Width THEN Out.String("toomuch$"); w := Display.Width END; END MeasureList; PROCEDURE TextListHandle* (f : Display.Frame; VAR msg : Display.FrameMsg); VAR keysum : SET; x, y, w, h, py, px : INTEGER; bmp : Bitmaps.Bitmap; lf : TextFrames.Frame; exec : Elems.ExecMsg; modify : MenuViewers.ModifyMsg; t : Texts.Text; done : BOOLEAN; BEGIN WITH f : TextFrames.Frame DO WITH msg : Oberon.InputMsg DO IF (msg.id = Oberon.track) THEN IF  (msg.X >= f.X) & (msg.X < f.X + f.barW)  THEN TextFrames.Handle(f, msg); curElem.org := f.org; ELSIF msg.keys = {MM} THEN IF curElem.popup THEN MeasureList(curElem.txt, curElem.popupH, w, h); IF h < (curElem.H DIV DUnit) THEN h := SHORT(curElem.H DIV DUnit) END; IF w < (curElem.W DIV DUnit) THEN w := SHORT(curElem.W DIV DUnit) END; IF ey - h < 0 THEN py := ey + SHORT(curElem.H DIV DUnit) ELSE py := ey - h END; IF ex + w > Display.Width THEN px := Display.Width - w ELSE px := ex END; bmp := Bitmaps.New(w, h); Bitmaps.CopyBlock(Bitmaps.Disp, bmp, px, py, w, h, 0, 0, 0); GU.Frame(NIL, 15, px, py, w, h, 1, Display.paint); lf := OpenTextFrame(curElem, px + 1, py + 1, w - 2, h - 2, list, 0); modify.id := 1; modify.Y := lf.Y; modify.H := lf.H; lf.handle(lf, modify); ELSE lf := f END; TrackText(keysum , x, y, lf, done); IF curElem.popup THEN Bitmaps.CopyBlock(bmp, Bitmaps.Disp, 0, 0, w, h, px, py, 0); IF done THEN IF curElem.combo THEN SetComboText(curElem) ELSE TextFrames.Show(f, curElem.pos) END END END; IF keysum = {MM, MR} THEN IF ~curElem.locked THEN OpenEditor(curElem) END ELSIF done & (keysum # {ML, MM, MR}) & (x >= lf.X + lf.left) & (x < lf.X + lf.W) & (y > lf.Y) & (y < lf.Y + lf.H) THEN exec.e := curElem; exec.x := f.X; exec.y := f.Y; exec.f := f; exec.unload := ML IN keysum; curElem.handle(curElem, exec) END ELSIF msg.keys = {MR} THEN IF curElem.popup & curElem.combo THEN (* edit combo text *) ELSIF ~curElem.popup THEN f.time := Oberon.Time(); TrackSelection(keysum, x, y, curElem.multi, f) END ELSIF msg.keys = {ML} THEN IF curElem.popup & curElem.combo THEN (* edit combo text *) ELSIF ~curElem.popup THEN f.time := Oberon.Time(); TrackSelection(keysum, x, y, FALSE, f) END ELSE TextFrames.Handle(f, msg); curElem.org := f.org; END END | msg : Oberon.SelectionMsg DO IF f.time > msg.time THEN t := SelToText(f.text); IF t.len > 0 THEN msg.text := t; msg.beg := 0; msg.end := msg.text.len; msg.time := f.time END END ELSE TextFrames.Handle(f, msg) END END END TextListHandle; PROCEDURE TextComboHandle* (f : Display.Frame; VAR msg : Display.FrameMsg); VAR exec : Elems.ExecMsg; BEGIN WITH f : TextFrames.Frame DO WITH msg : Oberon.InputMsg DO IF (msg.id = Oberon.track) THEN IF msg.keys = {MM} THEN TextListHandle(f, msg) ELSE TextFrames.Handle(f, msg) END ELSIF (msg.id = Oberon.consume) & f.hasCar THEN IF msg.ch = Elems.CR THEN exec.e := curElem; exec.x := f.X; exec.y := f.Y; exec.f := f; exec.unload := FALSE; curElem.handle(curElem, exec) ELSE TextFrames.Handle(f, msg) END ELSE TextFrames.Handle(f, msg) END ELSE TextFrames.Handle(f, msg) END; END; END TextComboHandle; PROCEDURE FrameHandle(f : Display.Frame; VAR msg : Display.FrameMsg); BEGIN WITH msg : MenuViewers.ModifyMsg DO SetFrameCoords(f(Frame), f.dsc(TextFrames.Frame)) | msg : Elems.GetFrameMsg DO IF msg.e = f(Frame).e THEN msg.f := f.dsc END | msg : Elems.GetContextMsg DO IF (msg.p = f(Frame).e) & ((msg.fx >= f.X) & (msg.fx <= f.X + f.W) & (msg.fy >= f.Y) & (msg.fy <= f.Y + f.H) OR (msg.fx < 0) & (msg.fy < 0)) THEN msg.context := f; msg.p := NIL END | msg : TextFrames.UpdateMsg DO IF msg.text = f(Frame).e.txt THEN f(Frame).e.pos := 0; f(Frame).e.org := 0 END; (* text has changed *) f.dsc.handle(f.dsc, msg) ELSE IF msg IS Oberon.InputMsg THEN curElem := f(Frame).e; ex := f.X; ey := f.Y; END; f.dsc.handle(f.dsc, msg); END END FrameHandle; PROCEDURE OpenTextFrame (e : Elem; x, y, w, h, type : INTEGER; pos : LONGINT) : TextFrames.Frame; VAR new : TextFrames.Frame; BEGIN IF type = combo THEN new := TextFrames.NewText(e.comboTxt, 0) ELSE new := TextFrames.NewText(e.txt, pos) END; new.X := x; new.Y := y; new.W := w; new.H := h; new.right := 2; new.top := 2; new.bot := 0; new.showsParcs := FALSE; new.left := 2; new.barW := 0; new.col := 12; IF type = list THEN new.handle := TextListHandle; IF ~e.popup & e.scrbar THEN new.barW := TextFrames.barW; new.left := new.barW + 2 END ELSIF type = combo THEN new.handle := TextComboHandle; new.col := 0 ELSIF type = popup THEN new.handle := TextListHandle END; RETURN new END OpenTextFrame; PROCEDURE OpenFrame(e : Elem; f : Display.Frame; x, y, w, h : INTEGER) : Display.Frame; VAR new : Frame; type : INTEGER; m : MenuViewers.ModifyMsg; BEGIN NEW(new); new.handle := FrameHandle; new.e := e; new.X := x; new.Y := y; new.W := w; new.H := h; IF ~e.popup THEN type := list ELSIF e.combo THEN type := combo ELSE type := popup END; IF type = list THEN new.dsc := OpenTextFrame(e, x + 2, y + 2, w - 4, h - 4, type, e.org) ELSE (* popup reduced to buttonwidth *) new.dsc := OpenTextFrame(e, x + 2, y + 2, w - 4 - bW, h - 4, type, e.pos) END; Elems.AdjustSubFrame(f, new); Elems.AdjustSubFrame(new, new.dsc); m.id := 1; m.Y := new.dsc.Y; m.H := new.dsc.H; new.dsc.handle(new.dsc, m); RETURN new; END OpenFrame; PROCEDURE HandleAttrMsg(e : Elem; VAR msg : Elems.AttrMsg); BEGIN Elems.Done := TRUE; IF msg.id = Elems.get THEN IF msg.name = "Value" THEN msg.class := Elems.String; IF e.popup & e.combo THEN TextLineToString(e.comboTxt, 0, msg.s) ELSE TextLineToString(e.txt, e.pos, msg.s) END ELSIF msg.name = "ValueT" THEN msg.class := Elems.Text; msg.t := e.txt ELSIF msg.name = "Line" THEN msg.class := Elems.Int; LineOfPos(e.txt, e.pos, msg.i) ELSIF msg.name = "ComboV" THEN msg.class := Elems.String; TextLineToString(e.comboTxt, 0, msg.s) ELSIF msg.name = "ComboVT" THEN msg.class := Elems.Text; msg.t := e.comboTxt ELSIF msg.name = "Sel" THEN msg.class := Elems.String; TextLineToString(SelToText(e.txt), 0, msg.s) ELSIF msg.name = "SelT" THEN msg.class := Elems.Text; msg.t := SelToText(e.txt) ELSIF msg.name = "SelLine" THEN msg.class := Elems.Int; LineOfPos(e.txt, FirstSelPos(e.txt), msg.i) ELSIF msg.name = "Scrollbar" THEN msg.class := Elems.Bool; msg.b := e.scrbar ELSIF msg.name = "Popup" THEN msg.class := Elems.Bool; msg.b := e.popup ELSIF msg.name = "Combo" THEN msg.class := Elems.Bool; msg.b := e.combo ELSIF msg.name = "Multi" THEN msg.class := Elems.Bool; msg.b := e.multi ELSIF msg.name = "PopupH" THEN msg.class := Elems.Int; msg.i := e.popupH ELSE Elems.Handle(e, msg) END ELSIF msg.id = Elems.set THEN IF msg.name = "Value" THEN IF msg.class = Elems.String THEN SetPos(e, msg.s) END ELSIF msg.name = "ValueT" THEN IF msg.class = Elems.Text THEN e.txt := msg.t END ELSIF msg.name = "Line" THEN IF msg.class = Elems.Int THEN PosOfLine(e.txt, msg.i, e.pos) END ELSIF msg.name = "ComboV" THEN IF msg.class = Elems.String THEN Texts.Delete(e.comboTxt, 0, e.comboTxt.len); Texts.WriteString(W, msg.s); Texts.Append(e.comboTxt, W.buf) END ELSIF msg.name = "ComboVT" THEN IF msg.class = Elems.Text THEN e.comboTxt := msg.t END ELSIF msg.name = "Sel" THEN (* suppress generation of dynamic attribute *) ELSIF msg.name = "SelT" THEN (* suppress generation of dynamic attribute *) ELSIF msg.name = "Scrollbar" THEN IF msg.class = Elems.Bool THEN e.scrbar := msg.b END ELSIF msg.name = "Popup" THEN IF msg.class = Elems.Bool THEN IF ~e.popup & msg.b THEN (* set default size for popup *) e.H := LONG(Fonts.Default.maxY - Fonts.Default.minY + 7) * DUnit END; e.popup := msg.b END ELSIF msg.name = "Combo" THEN IF msg.class = Elems.Bool THEN e.combo := msg.b END ELSIF msg.name = "Multi" THEN IF msg.class = Elems.Bool THEN e.multi := msg.b END ELSIF msg.name = "PopupH" THEN IF msg.class = Elems.Int THEN e.popupH := SHORT(msg.i) END ELSE Elems.Handle(e, msg) END ELSIF msg.id = Elems.enum THEN Elems.Handle(e, msg); msg.enum("Scrollbar", Elems.Bool); msg.enum("Popup", Elems.Bool); msg.enum("Combo", Elems.Bool); msg.enum("Multi", Elems.Bool); msg.enum("Value", Elems.String); msg.enum("ValueT", Elems.Text); msg.enum("PopupH", Elems.Int); ELSE Elems.Handle(e, msg) END END HandleAttrMsg; PROCEDURE Draw(e : Elem; x, y : INTEGER; f : Display.Frame; VAR ef : Display.Frame); VAR h, w, one, bw, arrw, arrh, dx : INTEGER; pos : LONGINT; t : Texts.Text; BEGIN h := GU.Unit(e.H, TRUE); w := GU.Unit(e.W, TRUE); one := GU.Unit(1, FALSE); bw := GU.Unit(bW, FALSE); arrw := GU.Unit(arrW, FALSE); arrh := GU.Unit(arrH, FALSE); IF GU.device = GU.display THEN ef := OpenFrame(e, f, x, y, w, h) END; GU.Area(f, 0, 0, x, y, w, h, 2*one, FALSE, TRUE); IF e.popup THEN GU.ReplConst(f, 12, x + 2*one, y + 2*one, w - 4*one - bw, one, Display.paint); GU.Area(f, 13, 0, x + w - bw - 2*one, y + 2*one, bw, h - 4*one, one, TRUE, FALSE); IF (h - 4*one > arrh) & (w - 4*one > arrw) THEN GU.CopyPattern(f, 15, arrow, x + w - arrw - 2*one - (bw - arrw) DIV 2 , y + 1 + (h - arrh) DIV 2, Display.paint) END END; IF GU.device = GU.printer THEN pos := 0; IF e.popup THEN IF e.combo THEN t := e.comboTxt; pos := e.pos ELSE t := e.txt END; TextPrinter.PlaceBody(x + GU.Unit(2, FALSE), y, w - GU.Unit(bW + 2, FALSE), h, e.txt, pos, 0, TRUE) ELSE dx := 0; IF e.scrbar THEN dx := GU.Unit(TextFrames.barW, FALSE); GU.ReplConst(f, 0, x + dx, y, GU.Unit(1, FALSE), GU.Unit(e.H, TRUE), Display.paint) END; TextPrinter.PlaceBody(x + dx + GU.Unit(2, FALSE), y, w, h, e.txt, pos, 0, TRUE) END END END Draw; PROCEDURE Handle* (e : Texts.Elem; VAR msg : Texts.ElemMsg); VAR copy: Elem; ch : CHAR; f : Display.Frame; BEGIN WITH e : Elem DO WITH msg: TextFrames.DisplayMsg DO IF ~msg.prepare THEN GU.SetDevice(GU.display); Draw(e, msg.X0, msg.Y0, msg.frame, msg.elemFrame) END | msg : TextPrinter.PrintMsg DO IF ~msg.prepare THEN GU.SetDevice(GU.printer); Draw(e, msg.X0, msg.Y0, NIL, f); GU.SetDevice(GU.display) END | msg : TextFrames.TrackMsg DO (* send to his frame *) Elems.Handle(e, msg); IF msg.keys = {MM} THEN Elems.ToFrame(e, msg) END | msg : Texts.CopyMsg DO NEW(copy); Elems.CopyElem(e, copy); copy.txt := Elems.CopyText(e.txt); copy.comboTxt := Elems.CopyText(e.comboTxt); copy.scrbar := e.scrbar; copy.popup := e.popup; copy.combo := e.combo; copy.multi := e.multi; copy.popupH := e.popupH; copy.pos := e.pos; msg.e := copy; | msg : Texts.IdentifyMsg DO msg.mod := "ListElems"; msg.proc := "New" | msg : Elems.AttrMsg DO HandleAttrMsg(e, msg) | msg : Texts.FileMsg DO Elems.Handle(e, msg); IF msg.id = Texts.load THEN Files.Read(msg.r, ch); (* version -> not used *) Texts.Load(msg.r, e.txt); Texts.Load(msg.r, e.comboTxt); Files.ReadBool(msg.r, e.scrbar); Files.ReadBool(msg.r, e.popup); Files.ReadBool(msg.r, e.combo); Files.ReadBool(msg.r, e.multi); Files.ReadInt(msg.r, e.popupH); Files.ReadLInt(msg.r, e.pos); ELSIF msg.id = Texts.store THEN Files.Write(msg.r, 0X); (* version *) Texts.Store(msg.r, e.txt); Texts.Store(msg.r, e.comboTxt); Files.WriteBool(msg.r, e.scrbar); Files.WriteBool(msg.r, e.popup); Files.WriteBool(msg.r, e.combo); Files.WriteBool(msg.r, e.multi); Files.WriteInt(msg.r, e.popupH); IF e.popup THEN Files.WriteLInt(msg.r, e.pos) ELSE Files.WriteLInt(msg.r, 0) END END ELSE Elems.Handle(e, msg) END END END Handle; PROCEDURE Init* (e : Elem); BEGIN Elems.Init(e); e.handle := Handle; e.txt := TextFrames.Text(""); e.comboTxt := TextFrames.Text(""); e.scrbar := TRUE; e.popup := FALSE; e.combo := FALSE; e.popupH := 90; e.pos := 0; e.H := 50 * DUnit; e.W := 90 * DUnit; END Init; PROCEDURE New*; VAR e : Elem; BEGIN NEW(e); Init(e); Texts.new := e END New; PROCEDURE Insert*;(** Name Cmd Par W H *)  VAR e : Elem; m : TextFrames.InsertElemMsg; s : Texts.Scanner; BEGIN NEW(e); Init(e); Elems.GetPar(e, s); m.e := e; Viewers.Broadcast(m) END Insert; 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.e; menuText := Oberon.Par.frame(TextFrames.Frame).text; E.txt := Elems.CopyText(F.text); E.pos := 0; RemoveSelection(E.txt); Elems.UpdateElem(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;  PROCEDURE MoveLine*; (* 'fromName' 'toName' 'string' *)  VAR e : Elems.Elem; fromName, toName, str : ARRAY 256 OF CHAR; beg, end : LONGINT; BEGIN In.Open; In.String(fromName); In.String(toName); In.String(str); IF ~In.Done THEN Out.String("-- ListElems.MoveLine fromName toName line$"); RETURN END; IF str = "" THEN RETURN END; IF fromName # "" THEN e := Elems.NamedElem(fromName, Elems.CmdContext); IF e = NIL THEN Out.String("-- elem not found: "); Out.String(fromName); Out.Ln ELSE WITH e : Elem DO Find(e.txt, str, beg, end); IF beg >= 0 THEN Texts.Delete(e.txt, beg, end) END END END END; IF toName # "" THEN e := Elems.NamedElem(toName, Elems.CmdContext); IF e = NIL THEN Out.String("-- elem not found: "); Out.String(toName); Out.Ln ELSE WITH e : Elem DO Texts.WriteString(W, str); Texts.WriteLn(W); Texts.Append(e.txt, W.buf) END END END END MoveLine; PROCEDURE InitMod(); VAR arr : ARRAY 10 OF SET; BEGIN arr[9] := {}; arr[8] := {}; arr[7] := {}; arr[6] := {}; arr[5] := {0..8}; arr[4] := {1..7}; arr[3] := {2..6}; arr[2] := {3..5}; arr[1] := {4}; arrow := Display.NewPattern(arr, 9, 5) END InitMod; BEGIN Texts.OpenWriter(W); InitMod() END ListElems. System.Free ListElems ~