Oberon/A2/Oberon.TextFrames.Mod

(* ETH Oberon, Copyright 2001 ETH Zuerich Institut fuer Computersysteme, ETH Zentrum, CH-8092 Zuerich. Refer to the "General ETH Oberon System Source License" contract available at&#58; http&#58;//www.oberon.ethz.ch/ *) MODULE TextFrames IN Oberon;	(** portable *) (* JG / pjm *) &#32;&#32;IMPORT Input, Modules, Objects, Display, Viewers, Fonts, Texts, Oberon, MenuViewers; &#32;&#32;CONST CR &#61; 0DX; &#32;&#32;&#32;&#32;replace &#61; Display.replace; paint &#61; Display.paint; invert &#61; Display.invert; &#32;&#32;&#32;&#32;extend &#61; Display.extend; reduce &#61; Display.reduce; &#9;StandardMenu &#61; "System.Close System.Copy System.Grow Edit.Search Edit.Store"; &#9;LogMenu &#61; "System.Clear Edit.Locate Edit.Search Edit.Store"; &#9;OpenCmd &#61; "ET.Open"; &#9;Modern &#61; FALSE;	(* enable "modern" look *) &#9;SmallDisplay &#61; TRUE;	(* enable PDR&#39;s support for narrow displays *) &#9;MoveArea &#61; TRUE;	(* show "move" icon at top left, and use clipping for caret *) &#32;&#32;TYPE &#32;&#32;&#9;Line &#61; POINTER TO LineDesc; &#32;&#32;&#9;LineDesc &#61; RECORD &#32;&#32;&#32;&#32;&#9;len&#58; SIGNED32; &#32;&#32;&#32;&#32;&#32;&#32;&#32;&#32;wid&#58; SIGNED16; &#32;&#32;&#32;&#32;&#32;&#32;&#32;&#32;eot&#58; BOOLEAN; &#32;&#32;&#32;&#32;&#32;&#32;&#32;&#32;next&#58; Line &#32;&#32;&#9;END; &#32;&#32;&#9;Location* &#61; RECORD &#32;&#32;&#32;&#32;&#32;&#32;&#32;&#32;org*, pos*&#58; SIGNED32; &#32;&#32;&#32;&#32;&#32;&#32;&#32;&#32;dx*, x*, y*&#58; SIGNED16; &#32;&#32;&#32;&#32;&#32;&#32;&#32;&#32;lin&#58; Line &#32;&#32;&#9;END; &#32;&#32;&#9;Frame* &#61; POINTER TO FrameDesc; &#32;&#32;&#9;FrameDesc* &#61; RECORD &#32;&#32;&#32;&#32;&#32;&#32;&#32;&#32;(Display.FrameDesc) &#32;&#32;&#32;&#32;&#32;&#32;&#32;&#32;text*&#58; Texts.Text; &#32;&#32;&#32;&#32;&#32;&#32;&#32;&#32;org*&#58; SIGNED32; &#32;&#32;&#32;&#32;&#32;&#32;&#32;&#32;col*&#58; SIGNED16; &#32;&#32;&#32;&#32;&#32;&#32;&#32;&#32;lsp*&#58; SIGNED16; &#32;&#32;&#32;&#32;&#32;&#32;&#32;&#32;left*, right*, top*, bot*&#58; SIGNED16; &#32;&#32;&#32;&#32;&#32;&#32;&#32;&#32;markH*&#58; SIGNED16; &#32;&#32;&#32;&#32;&#32;&#32;&#32;&#32;time*&#58; SIGNED32; &#32;&#32;&#32;&#32;&#32;&#32;&#32;&#32;mark*, car*, sel*&#58; SIGNED16; &#32;&#32;&#32;&#32;&#32;&#32;&#32;&#32;carloc*&#58; Location; &#32;&#32;&#32;&#32;&#32;&#32;&#32;&#32;selbeg*, selend*&#58; Location; &#32;&#32;&#32;&#32;&#32;&#32;&#32;&#32;trailer&#58; Line &#32;&#32;&#9;END; &#32;&#32;&#9;(*mark &#60; 0&#58; arrow mark &#32;&#32;&#32;&#32;&#32;&#32;&#32;&#32;mark &#61; 0&#58; no mark &#32;&#32;&#32;&#32;&#32;&#32;&#32;&#32;mark &#62; 0&#58; position mark*) &#32;&#32;VAR &#32;&#32;&#32;&#32;menuH*, barW*, left*, right*, top*, bot*, lsp*&#58; SIGNED16; (*standard sizes*) &#32;&#32;&#32;&#32;MarkColor, BarColor, MenuBG, TextBG, FullColor, mode&#58; SIGNED16; &#32;&#32;&#32;&#32;asr, dsr, selH, markW, eolW&#58; SIGNED16; &#32;&#32;&#32;&#32;ch&#58; CHAR; &#32;&#32;&#32;&#32;W, KW&#58; Texts.Writer; (*keyboard writer*) &#32;&#32;&#32;&#32;box&#58; Fonts.Char; &#32;&#32;&#32;&#32;BoxPat&#58; ARRAY 12 OF SET; &#32;&#32;&#32;&#32;hintPos&#58; SIGNED32; &#32;&#32;&#32;&#32;saved&#58; Oberon.CaretMsg; &#32;&#32;PROCEDURE Min (i, j&#58; SIGNED16)&#58; SIGNED16; &#32;&#32;BEGIN IF i &#62;&#61; j THEN RETURN j ELSE RETURN i END &#32;&#32;END Min; &#32;&#32;PROCEDURE Max (i, j&#58; SIGNED32)&#58; SIGNED32; &#32;&#32;BEGIN IF i &#62;&#61; j THEN RETURN i ELSE RETURN j END &#32;&#32;END Max; &#32;&#32;(*--display support*) &#32;&#32;PROCEDURE ReplConst (col&#58; SIGNED16; F&#58; Frame; X, Y, W, H&#58; SIGNED16; mode&#58; SIGNED16); &#32;&#32;BEGIN &#32;&#32;&#32;&#32;IF X + W &#60;&#61; F.X + F.W THEN Display.ReplConst(col, X, Y, W, H, mode) &#32;&#32;&#32;&#32;&#32;&#32;ELSIF X &#60; F.X + F.W THEN Display.ReplConst(col, X, Y, F.X + F.W - X, H, mode) &#32;&#32;&#32;&#32;END &#32;&#32;END ReplConst; &#32;&#32;PROCEDURE UpdateMark (F&#58; Frame); &#32;&#32;&#32;&#32;VAR oldH&#58; SIGNED16; &#32;&#32;BEGIN &#32;&#32;&#32;&#32;oldH &#58;&#61; F.markH; F.markH &#58;&#61; SHORT(F.org * F.H DIV (F.text.len + 1)); &#32;&#32;&#32;&#32;IF (F.mark &#62; 0) &#38; (F.left &#62;&#61; barW) &#38; (F.markH # oldH) THEN &#32;&#32;&#32;&#32;&#32;&#32;Display.ReplConst(F.col, F.X, F.Y + F.H - 1 - oldH, markW, 1, replace); &#32;&#32;&#32;&#32;&#32;&#32;Display.ReplConst(MarkColor, F.X, F.Y + F.H - 1 - F.markH, markW, 1, replace) &#32;&#32;&#32;&#32;END &#32;&#32;END UpdateMark; &#32;&#32;PROCEDURE Width (VAR R&#58; Texts.Reader; len&#58; SIGNED32)&#58; SIGNED16; &#32;&#32;&#32;&#32;VAR pos&#58; SIGNED32; ox&#58; SIGNED16; obj&#58; Objects.Object; &#32;&#32;BEGIN pos &#58;&#61; 0; ox &#58;&#61; 0; &#32;&#32;&#32;&#32;WHILE pos # len DO &#32;&#32;&#32;&#32;&#32;&#32;R.lib.GetObj(R.lib, ORD(ch), obj); &#32;&#32;&#32;&#32;&#32;&#32;IF &#126;(obj IS Fonts.Char) THEN obj &#58;&#61; box END; &#32;&#32;&#32;&#32;&#32;&#32;ox &#58;&#61; ox + obj(Fonts.Char).dx; INC(pos); Texts.Read(R, ch) &#32;&#32;&#32;&#32;END; &#32;&#32;&#32;&#32;RETURN ox &#32;&#32;END Width; &#32;&#32;PROCEDURE DisplayLine (F&#58; Frame; L&#58; Line; &#32;&#32;&#32;&#32;VAR R&#58; Texts.Reader; X, Y&#58; SIGNED16; len&#58; SIGNED32); &#32;&#32;&#32;&#32;VAR NX&#58; SIGNED16; obj&#58; Objects.Object; &#32;&#32;BEGIN NX &#58;&#61; F.X + F.W; &#32;&#32;&#32;&#32;WHILE (ch # CR) &#38; (R.lib # NIL) DO &#32;&#32;&#32;&#32;&#32;&#32;IF R.lib IS Fonts.Font THEN R.lib.GetObj(R.lib, ORD(ch), obj) &#32;&#32;&#32;&#32;&#32;&#32;&#32;&#32;ELSE obj &#58;&#61; box &#32;&#32;&#32;&#32;&#32;&#32;END; &#32;&#32;&#32;&#32;&#32;&#32;WITH obj&#58; Fonts.Char DO &#32;&#32;&#32;&#32;&#32;&#32;&#32;&#32;IF X + obj.x + obj.w &#60;&#61; NX THEN &#32;&#32;&#32;&#32;&#32;&#32;&#32;&#32;&#32;&#32;Display.CopyPattern(R.col, obj.pat, X + obj.x, Y + obj.y, mode); &#32;&#32;&#32;&#32;&#32;&#32;&#32;&#32;&#32;&#32;X &#58;&#61; X + obj.dx &#32;&#32;&#32;&#32;&#32;&#32;&#32;&#32;ELSE &#32;&#32;&#32;&#32;&#32;&#32;&#32;&#32;&#32;&#32;X &#58;&#61; NX &#32;&#32;&#32;&#32;&#32;&#32;&#32;&#32;END; &#32;&#32;&#32;&#32;&#32;&#32;END; &#32;&#32;&#32;&#32;&#32;&#32;INC(len); Texts.Read(R, ch) &#32;&#32;&#32;&#32;END; &#32;&#32;&#32;&#32;L.len &#58;&#61; len + 1; L.wid &#58;&#61; X + eolW - (F.X + F.left); &#32;&#32;&#32;&#32;L.eot &#58;&#61; R.eot; Texts.Read(R, ch) &#32;&#32;END DisplayLine; &#32;&#32;PROCEDURE Validate (T&#58; Texts.Text; VAR org&#58; SIGNED32); &#32;&#32;&#32;&#32;VAR R&#58; Texts.Reader; pos&#58; SIGNED32; &#32;&#32;BEGIN &#32;&#32;&#32;&#32;IF org &#62; T.len THEN org &#58;&#61; T.len &#32;&#32;&#32;&#32;ELSIF org &#62; 0 THEN Texts.OpenReader(R, T, org - 1); Texts.Read(R, ch); &#32;&#32;&#32;&#32;&#32;&#32;IF ch # CR THEN &#32;&#32;&#32;&#32;&#32;&#32;&#32;&#32;pos &#58;&#61; Max(org - 100, 0); Texts.OpenReader(R, T, pos); &#32;&#32;&#32;&#32;&#32;&#32;&#32;&#32;REPEAT Texts.Read(R, ch); INC(pos) UNTIL (pos &#61; org) OR (ch &#61; CR); &#32;&#32;&#32;&#32;&#32;&#32;&#32;&#32;org &#58;&#61; pos &#32;&#32;&#32;&#32;&#32;&#32;END &#32;&#32;&#32;&#32;ELSE org &#58;&#61; 0 &#32;&#32;&#32;&#32;END &#32;&#32;END Validate; &#32;&#32;PROCEDURE Mark* (F&#58; Frame; mark&#58; SIGNED16); &#32;&#32;BEGIN &#32;&#32;&#32;&#32;IF (mark &#62;&#61; 0) &#38; (F.mark &#60; 0) &#38; (F.H &#62;&#61; 16) THEN &#32;&#32;&#32;&#32;&#32;&#32;Display.CopyPattern(F.col, Display.downArrow, F.X, F.Y, paint) &#32;&#32;&#32;&#32;ELSIF (mark &#60;&#61; 0) &#38; (F.mark &#62; 0) &#38; (F.H &#62; 0) &#38; (F.left &#62;&#61; barW) THEN &#32;&#32;&#32;&#32;&#32;&#32;Display.ReplConst(F.col, F.X, F.Y + F.H - 1 - F.markH, markW, 1, replace) &#32;&#32;&#32;&#32;END; &#32;&#32;&#32;&#32;IF (mark &#62; 0) &#38; (F.H &#62; 0) &#38; (F.left &#62;&#61; barW) &#38; (F.mark &#60;&#61; 0) THEN &#32;&#32;&#32;&#32;&#32;&#32;Display.ReplConst(MarkColor, F.X, F.Y + F.H - 1 - F.markH, markW, 1, replace) &#32;&#32;&#32;&#32;ELSIF (mark &#60; 0) &#38; (F.H &#62;&#61; 16) &#38; (F.mark &#62;&#61; 0) THEN &#32;&#32;&#32;&#32;&#32;&#32;Display.CopyPattern(MarkColor, Display.downArrow, F.X, F.Y, paint) &#32;&#32;&#32;&#32;END; &#32;&#32;&#32;&#32;F.mark &#58;&#61; mark &#32;&#32;END Mark; &#32;&#32;PROCEDURE DrawIcon(F&#58; Frame); &#32;&#32;BEGIN &#32;&#32;&#32;&#32;Display.ReplConst(MarkColor, F.X+3, F.Y+F.H-9, 6, 6, replace); &#32;&#32;&#32;&#32;IF Oberon.New THEN &#32;&#32;&#32;&#32;&#32;&#32;Display.ReplConst(F.col, F.X+5, F.Y+F.H-7, 2, 2, replace) &#32;&#32;&#32;&#32;END &#32;&#32;END DrawIcon; &#32;&#32;PROCEDURE Restore* (F&#58; Frame); &#32;&#32;&#32;&#32;VAR R&#58; Texts.Reader; L&#58; Line; curY, botY&#58; SIGNED16; &#32;&#32;BEGIN (*F.mark &#61; 0*) &#32;&#32;&#32;&#32;Display.ReplConst(F.col, F.X, F.Y, F.W, F.H, replace); &#32;&#32;&#32;&#32;IF F.left &#62;&#61; barW THEN &#32;&#32;&#32;&#32;&#32;&#32;Display.ReplConst(BarColor, F.X + barW - 1, F.Y, 1, F.H, replace) &#32;&#32;&#32;&#32;ELSIF MoveArea THEN &#32;&#32;&#32;&#32;&#32;&#32;DrawIcon(F) &#32;&#32;&#32;&#32;END; &#32;&#32;&#32;&#32;Validate(F.text, F.org); &#32;&#32;&#32;&#32;botY &#58;&#61; F.Y + F.bot + dsr; &#32;&#32;&#32;&#32;Texts.OpenReader(R, F.text, F.org); Texts.Read(R, ch); &#32;&#32;&#32;&#32;L &#58;&#61; F.trailer; curY &#58;&#61; F.Y + F.H - F.top - asr; &#32;&#32;&#32;&#32;WHILE &#126;L.eot &#38; (curY &#62;&#61; botY) DO &#32;&#32;&#32;&#32;&#32;&#32;NEW(L.next); L &#58;&#61; L.next; &#32;&#32;&#32;&#32;&#32;&#32;DisplayLine(F, L, R, F.X + F.left, curY, 0); &#32;&#32;&#32;&#32;&#32;&#32;curY &#58;&#61; curY - lsp &#32;&#32;&#32;&#32;END; &#32;&#32;&#32;&#32;L.next &#58;&#61; F.trailer; &#32;&#32;&#32;&#32;F.markH &#58;&#61; SHORT(F.org * F.H DIV (F.text.len + 1)) &#32;&#32;END Restore; &#32;&#32;PROCEDURE Suspend* (F&#58; Frame); &#32;&#32;BEGIN (*F.mark &#61; 0*) &#32;&#32;&#32;&#32;F.trailer.next &#58;&#61; F.trailer &#32;&#32;END Suspend; &#32;&#32;PROCEDURE Extend* (F&#58; Frame; newY&#58; SIGNED16); &#32;&#32;&#32;&#32;VAR R&#58; Texts.Reader; L&#58; Line; &#32;&#32;&#32;&#32;org&#58; SIGNED32; curY, botY&#58; SIGNED16; &#32;&#32;BEGIN (*F.mark &#61; 0*) &#32;&#32;&#32;&#32;Display.ReplConst(F.col, F.X, newY, F.W, F.Y - newY, replace); &#32;&#32;&#32;&#32;IF F.left &#62;&#61; barW THEN &#32;&#32;&#32;&#32;&#32;&#32;Display.ReplConst(BarColor, F.X + barW - 1, newY, 1, F.Y - newY, replace) &#32;&#32;&#32;&#32;ELSIF MoveArea THEN &#32;&#32;&#32;&#32;&#32;&#32;DrawIcon(F) &#32;&#32;&#32;&#32;END; &#32;&#32;&#32;&#32;F.H &#58;&#61; F.H + F.Y - newY; F.Y &#58;&#61; newY; &#32;&#32;&#32;&#32;IF F.trailer.next &#61; F.trailer THEN Validate(F.text, F.org) END; &#32;&#32;&#32;&#32;L &#58;&#61; F.trailer; org &#58;&#61; F.org; curY &#58;&#61; F.Y + F.H - F.top - asr; &#32;&#32;&#32;&#32;WHILE L.next # F.trailer DO &#32;&#32;&#32;&#32;&#32;&#32;L &#58;&#61; L.next; org &#58;&#61; org + L.len; curY &#58;&#61; curY - lsp &#32;&#32;&#32;&#32;END; &#32;&#32;&#32;&#32;botY &#58;&#61; F.Y + F.bot + dsr; &#32;&#32;&#32;&#32;Texts.OpenReader(R, F.text, org); Texts.Read(R, ch); &#32;&#32;&#32;&#32;WHILE &#126;L.eot &#38; (curY &#62;&#61; botY) DO &#32;&#32;&#32;&#32;&#32;&#32;NEW(L.next); L &#58;&#61; L.next; &#32;&#32;&#32;&#32;&#32;&#32;DisplayLine(F, L, R, F.X + F.left, curY, 0); &#32;&#32;&#32;&#32;&#32;&#32;curY &#58;&#61; curY - lsp &#32;&#32;&#32;&#32;END; &#32;&#32;&#32;&#32;L.next &#58;&#61; F.trailer; &#32;&#32;&#32;&#32;F.markH &#58;&#61; SHORT(F.org * F.H DIV (F.text.len + 1)) &#32;&#32;END Extend; &#32;&#32;PROCEDURE Reduce* (F&#58; Frame; newY&#58; SIGNED16); &#32;&#32;&#32;&#32;VAR L&#58; Line; curY, botY&#58; SIGNED16; &#32;&#32;BEGIN (*F.mark &#61; 0*) &#32;&#32;&#32;&#32;F.H &#58;&#61; F.H + F.Y - newY; F.Y &#58;&#61; newY; &#32;&#32;&#32;&#32;botY &#58;&#61; F.Y + F.bot + dsr; &#32;&#32;&#32;&#32;L &#58;&#61; F.trailer; curY &#58;&#61; F.Y + F.H - F.top - asr; &#32;&#32;&#32;&#32;WHILE (L.next # F.trailer) &#38; (curY &#62;&#61; botY) DO &#32;&#32;&#32;&#32;&#32;&#32;L &#58;&#61; L.next; curY &#58;&#61; curY - lsp &#32;&#32;&#32;&#32;END; &#32;&#32;&#32;&#32;L.next &#58;&#61; F.trailer; &#32;&#32;&#32;&#32;IF curY + asr &#62; F.Y THEN &#32;&#32;&#32;&#32;&#32;&#32;Display.ReplConst(F.col, F.X + F.left, F.Y, F.W - F.left, curY + asr - F.Y, replace) &#32;&#32;&#32;&#32;END; &#32;&#32;&#32;&#32;F.markH &#58;&#61; SHORT(F.org * F.H DIV (F.text.len + 1)); &#32;&#32;&#32;&#32;Mark(F, 1) &#32;&#32;END Reduce; &#32;&#32;PROCEDURE Show* (F&#58; Frame; pos&#58; SIGNED32); &#32;&#32;&#32;&#32;VAR R&#58; Texts.Reader; L&#58; Line; &#32;&#32;&#32;&#32;&#32;&#32;org&#58; SIGNED32; curY, botY, Y0&#58; SIGNED16; &#32;&#32;BEGIN &#32;&#32;&#32;&#32;IF F.trailer.next # F.trailer THEN Validate(F.text, pos); &#32;&#32;&#32;&#32;&#32;&#32;IF pos &#60; F.org THEN Mark(F, 0); &#32;&#32;&#32;&#32;&#32;&#32;&#32;&#32;Display.ReplConst(F.col, F.X + F.left, F.Y, F.W - F.left, F.H, replace); &#32;&#32;&#32;&#32;&#32;&#32;&#32;&#32;botY &#58;&#61; F.Y; F.Y &#58;&#61; F.Y + F.H; F.H &#58;&#61; 0; &#32;&#32;&#32;&#32;&#32;&#32;&#32;&#32;F.org &#58;&#61; pos; F.trailer.next &#58;&#61; F.trailer; Extend(F, botY); &#32;&#32;&#32;&#32;&#32;&#32;&#32;&#32;Mark(F, 1) &#32;&#32;&#32;&#32;&#32;&#32;ELSIF pos &#62; F.org THEN &#32;&#32;&#32;&#32;&#32;&#32;&#32;&#32;org &#58;&#61; F.org; L &#58;&#61; F.trailer.next; curY &#58;&#61; F.Y + F.H - F.top - asr; &#32;&#32;&#32;&#32;&#32;&#32;&#32;&#32;WHILE (L.next # F.trailer) &#38; (org # pos) DO &#32;&#32;&#32;&#32;&#32;&#32;&#32;&#32;&#32;&#32;org &#58;&#61; org + L.len; L &#58;&#61; L.next; curY &#58;&#61; curY - lsp; &#32;&#32;&#32;&#32;&#32;&#32;&#32;&#32;END; &#32;&#32;&#32;&#32;&#32;&#32;&#32;&#32;IF org &#61; pos THEN &#32;&#32;&#32;&#32;&#32;&#32;&#32;&#32;&#32;&#32;F.org &#58;&#61; org; F.trailer.next &#58;&#61; L; Y0 &#58;&#61; curY; &#32;&#32;&#32;&#32;&#32;&#32;&#32;&#32;&#32;&#32;WHILE L.next # F.trailer DO &#32;&#32;&#32;&#32;&#32;&#32;&#32;&#32;&#32;&#32;&#32;&#32;org &#58;&#61; org + L.len; L &#58;&#61; L.next; curY &#58;&#61; curY - lsp &#32;&#32;&#32;&#32;&#32;&#32;&#32;&#32;&#32;&#32;END; &#32;&#32;&#32;&#32;&#32;&#32;&#32;&#32;&#32;&#32;Display.CopyBlock &#32;&#32;&#32;&#32;&#32;&#32;&#32;&#32;&#32;&#32;&#32;&#32;(F.X + F.left, curY - dsr, F.W - F.left, Y0 + asr - (curY - dsr), &#32;&#32;&#32;&#32;&#32;&#32;&#32;&#32;&#32;&#32;&#32;&#32;F.X + F.left, curY - dsr + F.Y + F.H - F.top - asr - Y0, replace); &#32;&#32;&#32;&#32;&#32;&#32;&#32;&#32;&#32;&#32;curY &#58;&#61; curY + F.Y + F.H - F.top - asr - Y0; &#32;&#32;&#32;&#32;&#32;&#32;&#32;&#32;&#32;&#32;Display.ReplConst(F.col, F.X + F.left, F.Y, F.W - F.left, curY - dsr - F.Y, replace); &#32;&#32;&#32;&#32;&#32;&#32;&#32;&#32;&#32;&#32;botY &#58;&#61; F.Y + F.bot + dsr; &#32;&#32;&#32;&#32;&#32;&#32;&#32;&#32;&#32;&#32;org &#58;&#61; org + L.len; curY &#58;&#61; curY - lsp; &#32;&#32;&#32;&#32;&#32;&#32;&#32;&#32;&#32;&#32;Texts.OpenReader(R, F.text, org); Texts.Read(R, ch); &#32;&#32;&#32;&#32;&#32;&#32;&#32;&#32;&#32;&#32;WHILE &#126;L.eot &#38; (curY &#62;&#61; botY) DO &#32;&#32;&#32;&#32;&#32;&#32;&#32;&#32;&#32;&#32;&#32;&#32;NEW(L.next); L &#58;&#61; L.next; &#32;&#32;&#32;&#32;&#32;&#32;&#32;&#32;&#32;&#32;&#32;&#32;DisplayLine(F, L, R, F.X + F.left, curY, 0); &#32;&#32;&#32;&#32;&#32;&#32;&#32;&#32;&#32;&#32;&#32;&#32;curY &#58;&#61; curY - lsp &#32;&#32;&#32;&#32;&#32;&#32;&#32;&#32;&#32;&#32;END; &#32;&#32;&#32;&#32;&#32;&#32;&#32;&#32;&#32;&#32;L.next &#58;&#61; F.trailer; &#32;&#32;&#32;&#32;&#32;&#32;&#32;&#32;&#32;&#32;UpdateMark(F) &#32;&#32;&#32;&#32;&#32;&#32;&#32;&#32;ELSE Mark(F, 0); &#32;&#32;&#32;&#32;&#32;&#32;&#32;&#32;&#32;&#32;Display.ReplConst(F.col, F.X + F.left, F.Y, F.W - F.left, F.H, replace); &#32;&#32;&#32;&#32;&#32;&#32;&#32;&#32;&#32;&#32;botY &#58;&#61; F.Y; F.Y &#58;&#61; F.Y + F.H; F.H &#58;&#61; 0; &#32;&#32;&#32;&#32;&#32;&#32;&#32;&#32;&#32;&#32;F.org &#58;&#61; pos; F.trailer.next &#58;&#61; F.trailer; Extend(F, botY); &#32;&#32;&#32;&#32;&#32;&#32;&#32;&#32;&#32;&#32;Mark(F, 1) &#32;&#32;&#32;&#32;&#32;&#32;&#32;&#32;END &#32;&#32;&#32;&#32;&#32;&#32;END &#32;&#32;&#32;&#32;END &#32;&#32;END Show; &#32;&#32;PROCEDURE LocateLine (F&#58; Frame; y&#58; SIGNED16; VAR loc&#58; Location); &#32;&#32;&#32;&#32;VAR L&#58; Line; org&#58; SIGNED32; cury&#58; SIGNED16; &#32;&#32;BEGIN &#32;&#32;&#32;&#32;org &#58;&#61; F.org; L &#58;&#61; F.trailer.next; cury &#58;&#61; F.H - F.top - asr; &#32;&#32;&#32;&#32;WHILE (L.next # F.trailer) &#38; (cury &#62; y + dsr) DO &#32;&#32;&#32;&#32;&#32;&#32;org &#58;&#61; org + L.len; L &#58;&#61; L.next; cury &#58;&#61; cury - lsp &#32;&#32;&#32;&#32;END; &#32;&#32;&#32;&#32;loc.org &#58;&#61; org; loc.lin &#58;&#61; L; loc.y &#58;&#61; cury &#32;&#32;END LocateLine; &#32;&#32;PROCEDURE LocateString (F&#58; Frame; x, y&#58; SIGNED16; VAR loc&#58; Location); &#32;&#32;&#32;&#32;VAR R&#58; Texts.Reader; &#32;&#32;&#32;&#32;&#32;&#32;bpos, pos, lim&#58; SIGNED32; &#32;&#32;&#32;&#32;&#32;&#32;bx, ex, ox&#58; SIGNED16; &#32;&#32;&#32;&#32;&#32;&#32;obj&#58; Objects.Object; &#32;&#32;&#32;&#32;&#32;&#32;continue (* outer loop *)&#58; BOOLEAN; &#32;&#32;BEGIN &#32;&#32;&#32;&#32;LocateLine(F, y, loc); &#32;&#32;&#32;&#32;lim &#58;&#61; loc.org + loc.lin.len - 1; &#32;&#32;&#32;&#32;bpos &#58;&#61; loc.org; bx &#58;&#61; F.left; &#32;&#32;&#32;&#32;pos &#58;&#61; loc.org; ox &#58;&#61; F.left; &#32;&#32;&#32;&#32;Texts.OpenReader(R, F.text, loc.org); Texts.Read(R, ch); &#32;&#32;&#32;&#32;continue &#58;&#61; TRUE; &#32;&#32;&#32;&#32;(* LOOP *) WHILE continue DO &#32;&#32;&#32;&#32;&#32;&#32;(* LOOP *) (*scan string*) &#32;&#32;&#32;&#32;&#32;&#32;WHILE (pos # lim) &#38; (" " &#60; ch) DO &#32;&#32;&#32;&#32;&#32;&#32;&#32;&#32;R.lib.GetObj(R.lib, ORD(ch), obj); &#32;&#32;&#32;&#32;&#32;&#32;&#32;&#32;IF &#126;(obj IS Fonts.Char) THEN obj &#58;&#61; box END; &#32;&#32;&#32;&#32;&#32;&#32;&#32;&#32;INC(pos); ox &#58;&#61; ox + obj(Fonts.Char).dx; Texts.Read(R, ch) &#32;&#32;&#32;&#32;&#32;&#32;END; &#32;&#32;&#32;&#32;&#32;&#32;ex &#58;&#61; ox; &#32;&#32;&#32;&#32;&#32;&#32;(* LOOP *) (*scan gap*) &#32;&#32;&#32;&#32;&#32;&#32;WHILE (pos # lim) &#38; (ch &#60;&#61; " ") DO &#32;&#32;&#32;&#32;&#32;&#32;&#32;&#32;R.lib.GetObj(R.lib, ORD(ch), obj); &#32;&#32;&#32;&#32;&#32;&#32;&#32;&#32;IF &#126;(obj IS Fonts.Char) THEN obj &#58;&#61; box END; &#32;&#32;&#32;&#32;&#32;&#32;&#32;&#32;INC(pos); ox &#58;&#61; ox + obj(Fonts.Char).dx; Texts.Read(R, ch) &#32;&#32;&#32;&#32;&#32;&#32;END; &#32;&#32;&#32;&#32;&#32;&#32;IF (pos &#61; lim) OR (ox &#62; x) THEN &#32;&#32;&#32;&#32;&#32;&#32;&#32;&#32;(* EXIT *) continue &#58;&#61; FALSE &#32;&#32;&#32;&#32;&#32;&#32;ELSE &#32;&#32;&#32;&#32;&#32;&#32;&#32;&#32;R.lib.GetObj(R.lib, ORD(ch), obj); &#32;&#32;&#32;&#32;&#32;&#32;&#32;&#32;IF &#126;(obj IS Fonts.Char) THEN obj &#58;&#61; box END; &#32;&#32;&#32;&#32;&#32;&#32;&#32;&#32;bpos &#58;&#61; pos; bx &#58;&#61; ox; &#32;&#32;&#32;&#32;&#32;&#32;&#32;&#32;INC(pos); ox &#58;&#61; ox + obj(Fonts.Char).dx; Texts.Read(R, ch) &#32;&#32;&#32;&#32;&#32;&#32;END &#32;&#32;&#32;&#32;END; &#32;&#32;&#32;&#32;loc.pos &#58;&#61; bpos; loc.dx &#58;&#61; ex - bx; loc.x &#58;&#61; bx &#32;&#32;END LocateString; &#32;&#32;PROCEDURE LocateChar (F&#58; Frame; x, y&#58; SIGNED16; VAR loc&#58; Location); &#32;&#32;&#32;&#32;VAR R&#58; Texts.Reader; &#32;&#32;&#32;&#32;&#32;&#32;pos, lim&#58; SIGNED32; &#32;&#32;&#32;&#32;&#32;&#32;ox, dx&#58; SIGNED16; &#32;&#32;&#32;&#32;&#32;&#32;obj&#58; Objects.Object; &#32;&#32;&#32;&#32;&#32;&#32;continue (* one loop *)&#58; BOOLEAN; &#32;&#32;BEGIN &#32;&#32;&#32;&#32;LocateLine(F, y, loc); &#32;&#32;&#32;&#32;lim &#58;&#61; loc.org + loc.lin.len - 1; &#32;&#32;&#32;&#32;pos &#58;&#61; loc.org; ox &#58;&#61; F.left; &#32;&#32;&#32;&#32;Texts.OpenReader(R, F.text, loc.org); Texts.Read(R, ch); &#32;&#32;&#32;&#32;continue &#58;&#61; TRUE; &#32;&#32;&#32;&#32;(* LOOP *) WHILE continue DO &#32;&#32;&#32;&#32;&#32;&#32;IF pos &#61; lim THEN &#32;&#32;&#32;&#32;&#32;&#32;&#32;&#32;dx &#58;&#61; eolW; (* EXIT *) continue &#58;&#61; FALSE &#32;&#32;&#32;&#32;&#32;&#32;ELSE &#32;&#32;&#32;&#32;&#32;&#32;&#32;&#32;R.lib.GetObj(R.lib, ORD(ch), obj); &#32;&#32;&#32;&#32;&#32;&#32;&#32;&#32;IF &#126;(obj IS Fonts.Char) THEN obj &#58;&#61; box END; &#32;&#32;&#32;&#32;&#32;&#32;&#32;&#32;dx &#58;&#61; obj(Fonts.Char).dx; &#32;&#32;&#32;&#32;&#32;&#32;&#32;&#32;IF ox + dx &#62; x THEN &#32;&#32;&#32;&#32;&#32;&#32;&#32;&#32;&#32;&#32;(* EXIT *) continue &#58;&#61; FALSE &#32;&#32;&#32;&#32;&#32;&#32;&#32;&#32;ELSE &#32;&#32;&#32;&#32;&#32;&#32;&#32;&#32;&#32;&#32;INC(pos); ox &#58;&#61; ox + dx; Texts.Read(R, ch) &#32;&#32;&#32;&#32;&#32;&#32;&#32;&#32;END &#32;&#32;&#32;&#32;&#32;&#32;END &#32;&#32;&#32;&#32;END (* LOOP *); &#32;&#32;&#32;&#32;loc.pos &#58;&#61; pos; loc.dx &#58;&#61; dx; loc.x &#58;&#61; ox &#32;&#32;END LocateChar; &#32;&#32;PROCEDURE LocatePos (F&#58; Frame; pos&#58; SIGNED32; VAR loc&#58; Location); &#32;&#32;&#32;&#32;VAR R&#58; Texts.Reader; L&#58; Line; org&#58; SIGNED32; cury&#58; SIGNED16; &#32;&#32;BEGIN &#32;&#32;&#32;&#32;org &#58;&#61; F.org; L &#58;&#61; F.trailer.next; cury &#58;&#61; F.H - F.top - asr; &#32;&#32;&#32;&#32;WHILE (L.next # F.trailer) &#38; (pos &#62;&#61; org + L.len) DO &#32;&#32;&#32;&#32;&#32;&#32;org &#58;&#61; org + L.len; L &#58;&#61; L.next; cury &#58;&#61; cury - lsp &#32;&#32;&#32;&#32;END; &#32;&#32;&#32;&#32;IF pos &#60; org THEN pos &#58;&#61; org &#32;&#32;&#32;&#32;&#32;&#32;ELSIF pos &#62;&#61; org + L.len THEN pos &#58;&#61; org + L.len - 1 &#32;&#32;&#32;&#32;END; &#32;&#32;&#32;&#32;Texts.OpenReader(R, F.text, org); Texts.Read(R, ch); &#32;&#32;&#32;&#32;loc.org &#58;&#61; org; loc.pos &#58;&#61; pos; loc.lin &#58;&#61; L; &#32;&#32;&#32;&#32;loc.x &#58;&#61; F.left + Width(R, pos - org); loc.y &#58;&#61; cury &#32;&#32;END LocatePos; &#32;&#32;PROCEDURE Pos* (F&#58; Frame; X, Y&#58; SIGNED16)&#58; SIGNED32; &#32;&#32;&#32;&#32;VAR loc&#58; Location; &#32;&#32;BEGIN LocateChar(F, X - F.X, Y - F.Y, loc); &#32;&#32;&#32;&#32;RETURN loc.pos &#32;&#32;END Pos; &#32;&#32;PROCEDURE FlipCaret (F&#58; Frame); &#32;&#32;VAR ox, oy, ow, oh&#58; SIGNED16; &#32;&#32;BEGIN &#32;&#32;&#32;&#32;IF MoveArea THEN &#32;&#32;&#32;&#32;&#32;&#32;Display.GetClip(ox, oy, ow, oh); &#32;&#32;&#32;&#32;&#32;&#32;Display.SetClip(F.X, F.Y, F.W, F.H); &#32;&#32;&#32;&#32;&#32;&#32;Display.CopyPattern(FullColor, Display.hook, F.X + F.carloc.x, F.Y + F.carloc.y - 10, invert); &#32;&#32;&#32;&#32;&#32;&#32;Display.SetClip(ox, oy, ow, oh) &#32;&#32;&#32;&#32;ELSE &#32;&#32;&#32;&#32;&#32;&#32;IF (F.carloc.y &#62;&#61; 10) &#38; (F.carloc.x + 12 &#60; F.W) THEN &#32;&#32;&#32;&#32;&#32;&#32;&#32;&#32;Display.CopyPattern(FullColor, Display.hook, F.X + F.carloc.x, F.Y + F.carloc.y - 10, invert) &#32;&#32;&#32;&#32;&#32;&#32;END &#32;&#32;&#32;&#32;END &#32;&#32;END FlipCaret; &#32;&#32;PROCEDURE SetCaret* (F&#58; Frame; pos&#58; SIGNED32); &#32;&#32;BEGIN &#32;&#32;&#32;&#32;IF F.car # 0 THEN FlipCaret(F); F.car &#58;&#61; 0 END; &#32;&#32;&#32;&#32;LocatePos(F, pos, F.carloc); &#32;&#32;&#32;&#32;IF F.carloc.pos &#61; pos THEN FlipCaret(F); F.car &#58;&#61; 1 &#32;&#32;&#32;&#32;ELSE &#32;&#32;&#32;&#32;&#32;&#32;RemoveMarks(F); Oberon.RemoveMarks(F.X, F.Y, F.W, F.H); &#32;&#32;&#32;&#32;&#32;&#32;Show(F, pos - 100); LocatePos(F, pos, F.carloc); &#32;&#32;&#32;&#32;&#32;&#32;IF F.carloc.pos &#61; pos THEN FlipCaret(F); F.car &#58;&#61; 1 END &#32;&#32;&#32;&#32;END &#32;&#32;END SetCaret; &#32;&#32;PROCEDURE TrackCaret* (F&#58; Frame; X, Y&#58; SIGNED16; VAR keysum&#58; SET); &#32;&#32;&#32;&#32;VAR loc&#58; Location; keys&#58; SET; &#32;&#32;BEGIN &#32;&#32;&#32;&#32;IF F.trailer.next # F.trailer THEN &#32;&#32;&#32;&#32;&#32;&#32;LocateChar(F, X - F.X, Y - F.Y, F.carloc); &#32;&#32;&#32;&#32;&#32;&#32;FlipCaret(F); &#32;&#32;&#32;&#32;&#32;&#32;keysum &#58;&#61; &#123;&#125;; &#32;&#32;&#32;&#32;&#32;&#32;REPEAT &#32;&#32;&#32;&#32;&#32;&#32;&#32;&#32;Input.Mouse(keys, X, Y); &#32;&#32;&#32;&#32;&#32;&#32;&#32;&#32;keysum &#58;&#61; keysum + keys; &#32;&#32;&#32;&#32;&#32;&#32;&#32;&#32;Oberon.DrawCursor(Oberon.Mouse, Oberon.Mouse.marker, X, Y); &#32;&#32;&#32;&#32;&#32;&#32;&#32;&#32;LocateChar(F, X - F.X, Y - F.Y, loc); &#32;&#32;&#32;&#32;&#32;&#32;&#32;&#32;IF loc.pos # F.carloc.pos THEN FlipCaret(F); F.carloc &#58;&#61; loc; FlipCaret(F) END &#32;&#32;&#32;&#32;&#32;&#32;UNTIL keys &#61; &#123;&#125;; &#32;&#32;&#32;&#32;&#32;&#32;F.car &#58;&#61; 1 &#32;&#32;&#32;&#32;END &#32;&#32;END TrackCaret; &#32;&#32;PROCEDURE RemoveCaret* (F&#58; Frame); &#32;&#32;BEGIN IF F.car # 0 THEN FlipCaret(F); F.car &#58;&#61; 0 END &#32;&#32;END RemoveCaret; &#32;&#32;PROCEDURE FlipSelection (F&#58; Frame; VAR beg, end&#58; Location); &#32;&#32;&#32;&#32;VAR L&#58; Line; Y&#58; SIGNED16; &#32;&#32;&#32;&#32;continue (* one loop *)&#58; BOOLEAN; &#32;&#32;BEGIN &#32;&#32;&#32;&#32;L &#58;&#61; beg.lin; Y &#58;&#61; F.Y + beg.y - 2; &#32;&#32;&#32;&#32;IF L &#61; end.lin THEN &#32;&#32;&#32;&#32;&#32;&#32;ReplConst(FullColor, F, F.X + beg.x, Y, end.x - beg.x, selH, invert) &#32;&#32;&#32;&#32;ELSE &#32;&#32;&#32;&#32;&#32;&#32;ReplConst(FullColor, F, F.X + beg.x, Y, F.left + L.wid - beg.x, selH, invert); &#32;&#32;&#32;&#32;&#32;&#32;continue &#58;&#61; TRUE; &#32;&#32;&#32;&#32;&#32;&#32;(* LOOP *) WHILE continue DO &#32;&#32;&#32;&#32;&#32;&#32;&#32;&#32;L &#58;&#61; L.next; Y &#58;&#61; Y - lsp; &#32;&#32;&#32;&#32;&#32;&#32;&#32;&#32;IF L &#61; end.lin THEN &#32;&#32;&#32;&#32;&#32;&#32;&#32;&#32;&#32;&#32;(* EXIT *) continue &#58;&#61; FALSE &#32;&#32;&#32;&#32;&#32;&#32;&#32;&#32;ELSE &#32;&#32;&#32;&#32;&#32;&#32;&#32;&#32;&#32;&#32;ReplConst(FullColor, F, F.X + F.left, Y, L.wid, selH, invert) &#32;&#32;&#32;&#32;&#32;&#32;&#32;&#32;END &#32;&#32;&#32;&#32;&#32;&#32;END; &#32;&#32;&#32;&#32;&#32;&#32;ReplConst(FullColor, F, F.X + F.left, Y, end.x - F.left, selH, invert) &#32;&#32;&#32;&#32;END &#32;&#32;END FlipSelection; &#32;&#32;PROCEDURE SetSelection* (F&#58; Frame; beg, end&#58; SIGNED32); &#32;&#32;BEGIN &#32;&#32;&#32;&#32;IF end &#60;&#61; beg THEN end &#58;&#61; beg + 1 END; &#32;&#32;&#32;&#32;IF F.sel # 0 THEN FlipSelection(F, F.selbeg, F.selend) END; &#32;&#32;&#32;&#32;LocatePos(F, beg, F.selbeg); &#32;&#32;&#32;&#32;IF F.selbeg.pos # beg THEN Show(F, beg); LocatePos(F, beg, F.selbeg) END; &#32;&#32;&#32;&#32;LocatePos(F, end, F.selend); &#32;&#32;&#32;&#32;FlipSelection(F, F.selbeg, F.selend); F.time &#58;&#61; Input.Time; F.sel &#58;&#61; 1 &#32;&#32;END SetSelection; &#32;&#32;PROCEDURE TrackSelection* (F&#58; Frame; X, Y&#58; SIGNED16; VAR keysum&#58; SET); &#32;&#32;&#32;&#32;VAR loc&#58; Location; modKeys, keys&#58; SET; M&#58; Oberon.SelectMsg; &#32;&#32;BEGIN &#32;&#32;&#32;&#32;&#32;&#32;IF F.trailer.next # F.trailer THEN &#32;&#32;&#32;&#32;&#9;IF F.sel # 0 THEN FlipSelection(F, F.selbeg, F.selend) END; &#32;&#32;&#32;&#32;&#9;LocateChar(F, X - F.X, Y - F.Y, loc); &#32;&#32;&#32;&#32;&#9;IF (F.sel # 0) &#38; (loc.pos &#61; F.selbeg.pos) &#38; (F.selend.pos &#61; F.selbeg.pos + 1) THEN &#32;&#32;&#32;&#32;&#32;&#32;&#9;LocateChar(F, F.left, Y - F.Y, F.selbeg) &#32;&#32;&#32;&#32;&#9;ELSE F.selbeg &#58;&#61; loc &#32;&#32;&#32;&#32;&#9;END; &#32;&#32;&#32;&#32;&#9;F.sel &#58;&#61; 0; &#32;&#32;&#32;&#32;&#9;INC(loc.pos); loc.x &#58;&#61; loc.x + loc.dx; F.selend &#58;&#61; loc; &#32;&#32;&#32;&#32;&#9;FlipSelection(F, F.selbeg, F.selend); &#32;&#32;&#32;&#32;&#32;&#32;&#32;&#32;keysum &#58;&#61; &#123;&#125;; &#32;&#32;&#32;&#32;&#9;REPEAT &#32;&#32;&#32;&#32;&#32;&#32;&#32;&#32;&#32;&#32;Input.Mouse(keys, X, Y); &#32;&#32;&#32;&#32;&#32;&#32;&#9;keysum &#58;&#61; keysum + keys; &#32;&#32;&#32;&#32;&#32;&#32;&#9;Oberon.DrawCursor(Oberon.Mouse, Oberon.Mouse.marker, X, Y); &#32;&#32;&#32;&#32;&#9;&#32;&#32;LocateChar(F, X - F.X, Y - F.Y, loc); &#32;&#32;&#32;&#32;&#32;&#32;&#9;IF loc.pos &#60; F.selbeg.pos THEN loc &#58;&#61; F.selbeg END; &#32;&#32;&#32;&#32;&#32;&#32;&#9;INC(loc.pos); loc.x &#58;&#61; loc.x + loc.dx; &#32;&#32;&#32;&#32;&#32;&#32;&#9;IF loc.pos &#60; F.selend.pos THEN FlipSelection(F, loc, F.selend); F.selend &#58;&#61; loc &#32;&#32;&#32;&#32;&#32;&#32;&#32;&#32;&#9;ELSIF loc.pos &#62; F.selend.pos THEN FlipSelection(F, F.selend, loc); F.selend &#58;&#61; loc &#32;&#32;&#32;&#32;&#32;&#32;&#9;END &#32;&#32;&#9;&#32;&#32;UNTIL keys &#61; &#123;&#125;; &#32;&#32;&#32;&#32;&#32;&#32;&#32;(* ps - 3.4.98 *) &#32;&#32;&#32;&#32;&#32;&#32;&#32;&#32;Input.KeyState(modKeys); &#32;&#32;&#32;&#32;&#32;&#32;&#32;&#32;IF Input.SHIFT IN modKeys THEN &#32;&#32;&#32;&#32;&#32;&#32;&#32;&#32;&#32;&#32;M.id &#58;&#61; Oberon.get; M.F &#58;&#61; NIL; M.sel &#58;&#61; NIL; M.text &#58;&#61; NIL; M.time &#58;&#61; -1; Display.Broadcast(M); &#32;&#32;&#32;&#32;&#32;&#32;&#32;&#32;&#32;&#32;IF (M.time # -1) &#38; (M.text &#61; F.text) &#38; (M.sel IS Frame) THEN &#32;&#32;&#32;&#32;&#32;&#32;&#32;&#32;&#32;&#32;&#32;&#32;IF M.beg &#62; F.selbeg.pos THEN M.beg &#58;&#61; F.selbeg.pos END; &#32;&#32;&#32;&#32;&#32;&#32;&#32;&#32;&#32;&#32;&#32;&#32;IF M.end &#60; F.selend.pos THEN M.end &#58;&#61; F.selend.pos END; &#32;&#32;&#32;&#32;&#32;&#32;&#32;&#32;&#32;&#32;&#32;&#32;FlipSelection(F, F.selbeg, F.selend); &#32;&#32;&#32;&#32;&#32;&#32;&#32;&#32;&#32;&#32;&#32;&#32;LocatePos(F, M.beg, F.selbeg); LocatePos(F, M.end, F.selend); &#32;&#32;&#32;&#32;&#32;&#32;&#32;&#32;&#32;&#32;&#32;&#32;FlipSelection(F, F.selbeg, F.selend); &#32;&#32;&#32;&#32;&#32;&#32;&#32;&#32;&#32;&#32;&#32;&#32;M.F &#58;&#61; M.sel; M.id &#58;&#61; Oberon.set; Display.Broadcast(M) &#32;&#32;&#32;&#32;&#32;&#32;&#32;&#32;&#32;&#32;END &#32;&#32;&#32;&#32;&#32;&#32;&#32;&#32;END; &#32;&#32;&#32;&#32;&#32;&#32;&#32;&#32;F.time &#58;&#61; Input.Time; F.sel &#58;&#61; 1 &#32;&#32;&#32;&#32;&#32;&#32;END &#32;&#32;END TrackSelection; &#32;&#32;PROCEDURE RemoveSelection* (F&#58; Frame); &#32;&#32;BEGIN IF F.sel # 0 THEN FlipSelection(F, F.selbeg, F.selend); F.sel &#58;&#61; 0 END &#32;&#32;END RemoveSelection; &#32;&#32;PROCEDURE TrackLine* (F&#58; Frame; X, Y&#58; SIGNED16; VAR org&#58; SIGNED32; VAR keysum&#58; SET); &#32;&#32;&#32;&#32;VAR old, new&#58; Location; keys&#58; SET; &#32;&#32;BEGIN &#32;&#32;&#32;&#32;&#32;&#32;&#32;&#32;IF F.trailer.next # F.trailer THEN &#32;&#32;&#32;&#32;&#9;&#32;&#32;LocateLine(F, Y - F.Y, old); &#32;&#32;&#32;&#32;&#9;&#32;&#32;ReplConst(FullColor, F, F.X + F.left, F.Y + old.y - dsr, old.lin.wid, 2, invert); &#32;&#32;&#32;&#32;&#32;&#32;&#32;&#32;&#32;&#32;keysum &#58;&#61; &#123;&#125;; &#32;&#32;&#32;&#32;&#32;&#32;&#9;REPEAT &#32;&#32;&#32;&#32;&#32;&#32;&#9;&#32;&#32;Input.Mouse(keys, X, Y); &#32;&#32;&#32;&#32;&#32;&#32;&#9;&#32;&#32;keysum &#58;&#61; keysum + keys; &#32;&#32;&#32;&#32;&#32;&#32;&#32;&#32;&#32;&#32;&#32;&#32;Oberon.DrawCursor(Oberon.Mouse, Oberon.Mouse.marker, X, Y); &#32;&#32;&#32;&#32;&#32;&#32;&#32;&#32;&#9;LocateLine(F, Y - F.Y, new); &#32;&#32;&#32;&#32;&#32;&#32;&#32;&#32;&#9;IF new.org # old.org THEN &#32;&#32;&#32;&#32;&#32;&#32;&#32;&#32;&#9;&#32;&#32;ReplConst(FullColor, F, F.X + F.left, F.Y + old.y - dsr, old.lin.wid, 2, invert); &#32;&#32;&#32;&#32;&#32;&#32;&#32;&#9;&#32;&#32;&#32;ReplConst(FullColor, F, F.X + F.left, F.Y + new.y - dsr, new.lin.wid, 2, invert); &#32;&#32;&#32;&#32;&#32;&#32;&#32;&#32;&#9;&#32;&#32;old &#58;&#61; new &#32;&#32;&#32;&#32;&#32;&#32;&#9;&#32;&#32;END &#32;&#32;&#32;&#32;&#9;&#32;&#32;UNTIL keys &#61; &#123;&#125;; &#32;&#32;&#32;&#32;&#9;&#32;&#32;ReplConst(FullColor, F, F.X + F.left, F.Y + new.y - dsr, new.lin.wid, 2, invert); &#32;&#32;&#32;&#32;&#9;&#32;&#32;org &#58;&#61; new.org &#32;&#32;&#32;&#32;&#32;&#32;&#32;&#32;ELSE org &#58;&#61; -1 &#32;&#32;&#32;&#32;&#32;&#32;&#32;&#32;END &#32;&#32;END TrackLine; &#32;&#32;PROCEDURE TrackWord* (F&#58; Frame; X, Y&#58; SIGNED16; VAR pos&#58; SIGNED32; VAR keysum&#58; SET); &#32;&#32;&#32;&#32;VAR old, new&#58; Location; keys&#58; SET; &#32;&#32;BEGIN &#32;&#32;&#32;&#32;IF F.trailer.next # F.trailer THEN &#9;&#32;&#32;LocateString(F, X - F.X, Y - F.Y, old); &#32;&#32;&#9;ReplConst(FullColor, F, F.X + old.x, F.Y + old.y - dsr, old.dx, 2, invert); &#32;&#32;&#32;&#32;&#32;&#32;keysum &#58;&#61; &#123;&#125;; &#32;&#32;&#32;&#32;&#32;&#32;REPEAT &#32;&#32;&#32;&#32;&#9;Input.Mouse(keys, X, Y); &#9;&#9;keysum &#58;&#61; keysum + keys; &#32;&#32;&#32;&#32;&#9;Oberon.DrawCursor(Oberon.Mouse, Oberon.Mouse.marker, X, Y); &#32;&#32;&#32;&#32;&#9;LocateString(F, X - F.X, Y - F.Y, new); &#32;&#32;&#32;&#32;&#9;IF new.pos # old.pos THEN &#32;&#32;&#32;&#32;&#32;&#32;&#9;ReplConst(FullColor, F, F.X + old.x, F.Y + old.y - dsr, old.dx, 2, invert); &#32;&#32;&#32;&#32;&#32;&#32;&#9;ReplConst(FullColor, F, F.X + new.x, F.Y + new.y - dsr, new.dx, 2, invert); &#32;&#32;&#32;&#32;&#32;&#32;&#9;old &#58;&#61; new &#32;&#32;&#32;&#32;&#9;END &#32;&#32;&#9;UNTIL keys &#61; &#123;&#125;; &#32;&#32;&#9;ReplConst(FullColor, F, F.X + new.x, F.Y + new.y - dsr, new.dx, 2, invert); &#32;&#32;&#9;pos &#58;&#61; new.pos; hintPos &#58;&#61; new.org &#32;&#32;&#32;&#32;ELSE pos &#58;&#61; -1 &#32;&#32;&#32;&#32;END &#32;&#32;END TrackWord; &#32;&#32;(*--message handling*) &#32;&#32;PROCEDURE RemoveMarks (F&#58; Frame); &#32;&#32;BEGIN RemoveCaret(F); RemoveSelection(F) &#32;&#32;END RemoveMarks; &#32;&#32;PROCEDURE GetAttr* (F&#58; Frame; VAR s&#58; ARRAY OF CHAR); &#32;&#32;&#32;&#32;VAR S&#58; Texts.Scanner; &#32;&#32;BEGIN Texts.OpenScanner(S, F.text, 0); Texts.Scan(S); COPY(S.s, s) &#32;&#32;END GetAttr; &#32;&#32;PROCEDURE CallCmd (cmd&#58; ARRAY OF CHAR; F&#58; Frame; pos&#58; SIGNED32; new&#58; BOOLEAN); &#32;&#32;&#32;&#32;VAR res&#58; SIGNED16; par&#58; Oberon.ParList; &#32;&#32;BEGIN &#32;&#32;&#32;&#32;NEW(par); par.vwr &#58;&#61; Viewers.This(F.X, F.Y); &#32;&#32;&#32;&#32;par.frame &#58;&#61; F; par.text &#58;&#61; F.text; par.pos &#58;&#61; pos; &#32;&#32;&#32;&#32;Oberon.Call(cmd, par, new, res); &#32;&#32;&#32;&#32;IF res &#62; 0 THEN &#32;&#32;&#32;&#32;&#32;&#32;Texts.WriteString(W, "Call error&#58; "); &#32;&#32;&#32;&#32;&#32;&#32;Texts.WriteString(W, Modules.resMsg); &#32;&#32;&#32;&#32;&#32;&#32;Texts.WriteLn(W); Texts.Append(Oberon.Log, W.buf) &#32;&#32;&#32;&#32;END &#32;&#32;END CallCmd; &#32;&#32;PROCEDURE Call* (F&#58; Frame; pos&#58; SIGNED32; new&#58; BOOLEAN); &#32;&#32;&#32;&#32;VAR S&#58; Texts.Scanner; i, h&#58; SIGNED16; hint&#58; ARRAY 32 OF CHAR; &#32;&#32;BEGIN &#32;&#32;&#32;&#32;IF SmallDisplay THEN &#32;&#32;&#32;&#32;&#32;&#32;Texts.OpenScanner(S, F.text, pos); Texts.Scan(S); h &#58;&#61; 0; &#32;&#32;&#32;&#32;&#32;&#32;IF ((S.class &#61; Texts.Char) &#38; (S.c &#61; ".") OR (S.class &#61; Texts.Name) &#38; (S.s&#91;0&#93; &#61; ".")) THEN &#32;&#32;&#32;&#32;&#32;&#32;&#32;&#32;(*find hint*) &#32;&#32;&#32;&#32;&#32;&#32;&#32;&#32;Texts.OpenScanner(S, F.text, hintPos); &#32;&#32;&#32;&#32;&#32;&#32;&#32;&#32;REPEAT &#32;&#32;&#32;&#32;&#32;&#32;&#32;&#32;&#32;&#32;Texts.Scan(S); &#32;&#32;&#32;&#32;&#32;&#32;&#32;&#32;&#32;&#32;IF S.class &#61; Texts.Name THEN &#32;&#32;&#32;&#32;&#32;&#32;&#32;&#32;&#32;&#32;&#32;&#32;i &#58;&#61; 0; WHILE (i &#60; S.len) &#38; (S.s&#91;i&#93; # ".") DO INC(i) END; &#32;&#32;&#32;&#32;&#32;&#32;&#32;&#32;&#32;&#32;&#32;&#32;IF (0 &#60; i) &#38; (i &#60; S.len) THEN &#32;&#32;&#32;&#32;&#32;&#32;&#32;&#32;&#32;&#32;&#32;&#32;&#32;&#32;h &#58;&#61; 0; REPEAT hint&#91;h&#93; &#58;&#61; S.s&#91;h&#93;; INC(h) UNTIL h &#62; i &#32;&#32;&#32;&#32;&#32;&#32;&#32;&#32;&#32;&#32;&#32;&#32;END &#32;&#32;&#32;&#32;&#32;&#32;&#32;&#32;&#32;&#32;END &#32;&#32;&#32;&#32;&#32;&#32;&#32;&#32;UNTIL Texts.Pos(S) &#62; pos; &#32;&#32;&#32;&#32;&#32;&#32;&#32;&#32;IF (S.class &#61; Texts.Char) &#38; (S.c &#61; ".") THEN Texts.Scan(S) END &#32;&#32;&#32;&#32;&#32;&#32;END; &#32;&#32;&#32;&#32;&#32;&#32;IF S.class &#61; Texts.Name THEN &#32;&#32;&#32;&#32;&#32;&#32;&#32;&#32;IF h &#62; 1 THEN (*use hint*) &#32;&#32;&#32;&#32;&#32;&#32;&#32;&#32;&#32;&#32;i &#58;&#61; S.len; IF S.s&#91;0&#93; &#61; "." THEN DEC(h) END; &#32;&#32;&#32;&#32;&#32;&#32;&#32;&#32;&#32;&#32;REPEAT S.s&#91;i+h&#93; &#58;&#61; S.s&#91;i&#93;; DEC(i) UNTIL (i &#61; -1) OR (S.s&#91;i+1&#93; &#61; "."); &#32;&#32;&#32;&#32;&#32;&#32;&#32;&#32;&#32;&#32;REPEAT DEC(h); S.s&#91;h&#93; &#58;&#61; hint&#91;h&#93; UNTIL h &#61; 0 &#32;&#32;&#32;&#32;&#32;&#32;&#32;&#32;END; &#32;&#32;&#32;&#32;&#32;&#32;&#32;&#32;CallCmd(S.s, F, pos + S.len, new) &#32;&#32;&#32;&#32;&#32;&#32;END &#32;&#32;&#32;&#32;ELSE &#32;&#32;&#32;&#32;&#32;&#32;Texts.OpenScanner(S, F.text, pos); Texts.Scan(S); &#32;&#32;&#32;&#32;&#32;&#32;IF (S.line &#61; 0) &#38; (S.class &#61; Texts.Name) THEN CallCmd(S.s, F, pos + S.len, new) END &#32;&#32;&#32;&#32;END &#32;&#32;END Call; &#32;&#32;PROCEDURE Write* (F&#58; Frame; ch&#58; CHAR; lib&#58; Objects.Library; col, voff&#58; SIGNED8); &#32;&#32;BEGIN (*F.car # 0*) &#32;&#32;&#32;&#32;IF ch &#61; 7FX THEN &#32;&#32;&#32;&#32;&#32;&#32;IF F.carloc.pos &#62; F.org THEN &#32;&#32;&#32;&#32;&#32;&#32;&#32;&#32;Texts.Delete(F.text, F.carloc.pos - 1, F.carloc.pos); &#32;&#32;&#32;&#32;&#32;&#32;&#32;&#32;SetCaret(F, F.carloc.pos - 1) &#32;&#32;&#32;&#32;&#32;&#32;END &#32;&#32;&#32;&#32;ELSIF ch &#61; 0C3X THEN (* right *) &#32;&#32;&#32;&#32;&#32;&#32;IF F.carloc.pos &#60; F.text.len THEN &#32;&#32;&#32;&#32;&#32;&#32;&#32;&#32;RemoveCaret(F); SetCaret(F, F.carloc.pos + 1) &#32;&#32;&#32;&#32;&#32;&#32;END &#32;&#32;&#32;&#32;ELSIF ch &#61; 0C4X THEN (* left *) &#32;&#32;&#32;&#32;&#32;&#32;IF F.carloc.pos &#62; 0 THEN &#32;&#32;&#32;&#32;&#32;&#32;&#32;&#32;RemoveCaret(F); SetCaret(F, F.carloc.pos - 1) &#32;&#32;&#32;&#32;&#32;&#32;END &#32;&#32;&#32;&#32;ELSIF (ch &#62;&#61; 0C1X) &#38; (ch &#60;&#61; 0C4X) THEN &#32;&#32;&#32;&#32;ELSIF (ch &#62;&#61; 0A0X) &#38; (ch &#60;&#61; 0A9X) THEN &#32;&#32;&#32;&#32;ELSIF (ch &#62;&#61; 0F0X) &#38; (ch &#60;&#61; 0FFX) THEN &#32;&#32;&#32;&#32;ELSE &#32;&#32;&#32;&#32;&#32;&#32;KW.lib &#58;&#61; lib; KW.col &#58;&#61; col; KW.voff &#58;&#61; voff; Texts.Write(KW, ch); &#32;&#32;&#32;&#32;&#32;&#32;Texts.Insert(F.text, F.carloc.pos, KW.buf); &#32;&#32;&#32;&#32;&#32;&#32;SetCaret(F, F.carloc.pos + 1) &#32;&#32;&#32;&#32;END &#32;&#32;END Write; &#32;&#32;PROCEDURE Defocus* (F&#58; Frame); &#32;&#32;BEGIN RemoveCaret(F) &#32;&#32;END Defocus; &#32;&#32;PROCEDURE Neutralize* (F&#58; Frame); &#32;&#32;BEGIN RemoveMarks(F) &#32;&#32;END Neutralize; &#32;&#32;PROCEDURE Modify* (F&#58; Frame; id, dY, Y, H&#58; SIGNED16); &#32;&#32;BEGIN &#32;&#32;&#32;&#32;Mark(F, 0); RemoveMarks(F); &#32;&#32;&#32;&#32;IF id &#61; extend THEN &#32;&#32;&#32;&#32;&#32;&#32;IF dY &#62; 0 THEN &#32;&#32;&#32;&#32;&#32;&#32;&#32;&#32;Display.CopyBlock(F.X, F.Y, F.W, F.H, F.X, F.Y + dY, replace); F.Y &#58;&#61; F.Y + dY &#32;&#32;&#32;&#32;&#32;&#32;END; &#32;&#32;&#32;&#32;&#32;&#32;Extend(F, Y) &#32;&#32;&#32;&#32;ELSIF id &#61; reduce THEN &#32;&#32;&#32;&#32;&#32;&#32;Reduce(F, Y + dY); &#32;&#32;&#32;&#32;&#32;&#32;IF dY &#62; 0 THEN Display.CopyBlock(F.X, F.Y, F.W, F.H, F.X, Y, replace); F.Y &#58;&#61; Y END; &#32;&#32;&#32;&#32;END; &#32;&#32;&#32;&#32;IF F.H &#62; 0 THEN Mark(F, 1) END &#32;&#32;END Modify; &#32;&#32;PROCEDURE Open* ( &#32;&#32;&#32;&#32;&#32;&#32;&#32;&#32;F&#58; Frame; H&#58; Objects.Handler; T&#58; Texts.Text; org&#58; SIGNED32; &#32;&#32;&#32;&#32;&#32;&#32;&#32;&#32;col, left, right, top, bot, lsp&#58; SIGNED16); &#32;&#32;&#32;&#32;VAR L&#58; Line; &#32;&#32;BEGIN NEW(L); &#32;&#32;&#32;&#32;L.len &#58;&#61; 0; L.wid &#58;&#61; 0; L.eot &#58;&#61; FALSE; L.next &#58;&#61; L; &#32;&#32;&#32;&#32;F.handle &#58;&#61; H; F.text &#58;&#61; T; F.org &#58;&#61; org; F.trailer &#58;&#61; L; &#32;&#32;&#32;&#32;F.left &#58;&#61; left; F.right &#58;&#61; right; F.top &#58;&#61; top; F.bot &#58;&#61; bot; &#32;&#32;&#32;&#32;F.lsp &#58;&#61; lsp; F.col &#58;&#61; col; F.mark &#58;&#61; 0; F.car &#58;&#61; 0; F.sel &#58;&#61; 0 &#32;&#32;END Open; &#32;&#32;PROCEDURE Copy* (F&#58; Frame; VAR F1&#58; Frame); &#32;&#32;BEGIN NEW(F1); &#32;&#32;&#32;&#32;Open(F1, F.handle, F.text, F.org, F.col, F.left, F.right, F.top, F.bot, F.lsp) &#32;&#32;END Copy; &#32;&#32;PROCEDURE CopyOver* (F&#58; Frame; text&#58; Texts.Text; beg, end&#58; SIGNED32); &#32;&#32;&#32;&#32;VAR buf&#58; Texts.Buffer; &#32;&#32;BEGIN &#32;&#32;&#32;&#32;IF F.car &#62; 0 THEN &#32;&#32;&#32;&#32;&#32;&#32;NEW(buf); Texts.OpenBuf(buf); &#32;&#32;&#32;&#32;&#32;&#32;Texts.Save(text, beg, end, buf); &#32;&#32;&#32;&#32;&#32;&#32;Texts.Insert(F.text, F.carloc.pos, buf); &#32;&#32;&#32;&#32;&#32;&#32;SetCaret(F, F.carloc.pos + (end - beg)) &#32;&#32;&#32;&#32;END &#32;&#32;END CopyOver; &#32;&#32;PROCEDURE GetSelection* (F&#58; Frame; VAR M&#58; Oberon.SelectMsg); &#32;&#32;BEGIN &#32;&#32;&#32;&#32;IF F.sel &#62; 0 THEN &#32;&#32;&#32;&#32;&#32;&#32;IF (F.time - M.time &#62; 0) OR (M.time &#61; -1) THEN M.sel &#58;&#61; F; M.time &#58;&#61; F.time; &#32;&#32;&#32;&#32;&#32;&#32;&#32;&#32;M.text &#58;&#61; F.text; M.beg &#58;&#61; F.selbeg.pos; M.end &#58;&#61; F.selend.pos; &#32;&#32;&#32;&#32;&#32;&#32;&#32;&#32;IF M.end &#62; M.text.len THEN M.end &#58;&#61; M.text.len END (* &#32;&#32;&#32;&#32;&#32;&#32;&#32;ELSIF (F.text &#61; M.text) &#38; (F.selbeg.pos &#60; M.beg) &#38; (M.sel IS Frame) THEN &#32;&#32;&#32;&#32;&#32;&#32;&#32;&#32;IF (M.beg &#60;&#61; M.sel(Frame).org) &#38; (F.selend.pos &#62;&#61; Pos(F, F.X+F.W, F.Y)) THEN &#32;&#32;&#32;&#32;&#32;&#32;&#32;&#32;&#9;M.beg &#58;&#61; F.selbeg.pos &#32;&#32;&#32;&#32;&#32;&#32;&#32;&#32;END &#42;) &#32;&#32;&#32;&#32;&#32;ELSIF F.text &#61; M.text THEN	(* extend selection over frame boundaries *) &#32;&#32;&#32;&#32;&#32;&#32;&#32;&#32;(* 7.4.98 - ps *) &#32;&#32;&#32;&#32;&#32;&#32;&#32;&#32;IF (F.selbeg.pos &#60; M.beg) &#38; (F.selend.pos &#62;&#61; Pos(F, F.X+F.W, F.Y)) THEN M.beg &#58;&#61; F.selbeg.pos END; &#32;&#32;&#32;&#32;&#32;&#32;&#32;&#32;IF (F.selend.pos &#62; M.end) &#38; (F.selbeg.pos &#61; F.org) THEN M.end &#58;&#61; F.selend.pos END; &#32;&#32;&#32;&#32;&#32;&#32;&#32;&#32;IF M.end &#62; F.text.len THEN M.end &#58;&#61; F.text.len END &#32;&#32;&#32;&#32;&#32;&#32;END &#32;&#32;&#32;&#32;END &#32;&#32;END GetSelection; &#32;&#32;PROCEDURE GetCaret* (F&#58; Frame; VAR M&#58; Oberon.CaretMsg); &#32;&#32;BEGIN IF F.car &#62; 0 THEN M.text &#58;&#61; F.text; M.pos &#58;&#61; F.carloc.pos; M.car &#58;&#61; F; M.res &#58;&#61; 0 END &#32;&#32;END GetCaret; &#32;&#32;PROCEDURE LineLen (VAR R&#58; Texts.Reader)&#58; SIGNED32; &#32;&#32;&#32;&#32;VAR len&#58; SIGNED32; &#32;&#32;BEGIN len &#58;&#61; 0; &#32;&#32;&#32;&#32;WHILE (ch # CR) &#38; (R.lib # NIL) DO INC(len); Texts.Read(R, ch) END; &#32;&#32;&#32;&#32;Texts.Read(R, ch); &#32;&#32;&#32;&#32;RETURN len + 1 &#32;&#32;END LineLen; &#32;&#32;PROCEDURE Update* (F&#58; Frame; beg, end, len&#58; SIGNED32); &#32;&#32;&#32;&#32;VAR R&#58; Texts.Reader; L, LB, LR, LS&#58; Line; done&#58; BOOLEAN; &#32;&#32;&#32;&#32;&#32;&#32;org, orgB, orgS, off, Llen&#58; SIGNED32; &#32;&#32;&#32;&#32;&#32;&#32;botY, Y, YB, YL, YR, YS, wid, H&#58; SIGNED16; &#32;&#32;BEGIN &#32;&#32;&#32;&#32;IF end &#60; F.org THEN F.org &#58;&#61; F.org - (end - beg) + len; &#32;&#32;&#32;&#32;ELSE &#32;&#32;&#32;&#32;&#32;&#32;IF beg &#60; F.org THEN &#32;&#32;&#32;&#32;&#32;&#32;&#32;&#32;F.trailer.next.len &#58;&#61; F.trailer.next.len + (F.org - beg); &#32;&#32;&#32;&#32;&#32;&#32;&#32;&#32;F.org &#58;&#61; beg &#32;&#32;&#32;&#32;&#32;&#32;END; &#32;&#32;&#32;&#32;&#32;&#32;botY &#58;&#61; F.Y + F.bot + dsr; &#32;&#32;&#32;&#32;&#32;&#32;org &#58;&#61; F.org; Y &#58;&#61; F.Y + F.H - F.top - asr; L &#58;&#61; F.trailer.next; &#32;&#32;&#32;&#32;&#32;&#32;WHILE (L # F.trailer) &#38; (org + L.len &#60;&#61; beg) DO &#32;&#32;&#32;&#32;&#32;&#32;&#32;&#32;org &#58;&#61; org + L.len; Y &#58;&#61; Y - lsp; L &#58;&#61; L.next &#32;&#32;&#32;&#32;&#32;&#32;END; &#32;&#32;&#32;&#32;&#32;&#32;IF L # F.trailer THEN done &#58;&#61; FALSE; &#32;&#32;&#32;&#32;&#32;&#32;&#32;&#32;RemoveMarks(F); Oberon.RemoveMarks(F.X, F.Y, F.W, F.H); &#32;&#32;&#32;&#32;&#32;&#32;&#32;&#32;orgB &#58;&#61; org; YB &#58;&#61; Y; LB &#58;&#61; L; &#32;&#32;&#32;&#32;&#32;&#32;&#32;&#32;WHILE (L # F.trailer) &#38; (org + L.len &#60;&#61; end) DO &#32;&#32;&#32;&#32;&#32;&#32;&#32;&#32;&#32;&#32;org &#58;&#61; org + L.len; Y &#58;&#61; Y - lsp; L &#58;&#61; L.next &#32;&#32;&#32;&#32;&#32;&#32;&#32;&#32;END; &#32;&#32;&#32;&#32;&#32;&#32;&#32;&#32;IF L # F.trailer THEN &#32;&#32;&#32;&#32;&#32;&#32;&#32;&#32;&#32;&#32;org &#58;&#61; org + L.len; Y &#58;&#61; Y - lsp; L &#58;&#61; L.next; &#32;&#32;&#32;&#32;&#32;&#32;&#32;&#32;&#32;&#32;IF L # F.trailer THEN &#32;&#32;&#32;&#32;&#32;&#32;&#32;&#32;&#32;&#32;&#32;&#32;YR &#58;&#61; Y; LR &#58;&#61; L; org &#58;&#61; orgB; Y &#58;&#61; YB; &#32;&#32;&#32;&#32;&#32;&#32;&#32;&#32;&#32;&#32;&#32;&#32;Texts.OpenReader(R, F.text, org); Texts.Read(R, ch); &#32;&#32;&#32;&#32;&#32;&#32;&#32;&#32;&#32;&#32;&#32;&#32;Llen &#58;&#61; LineLen(R); &#32;&#32;&#32;&#32;&#32;&#32;&#32;&#32;&#32;&#32;&#32;&#32;WHILE (org + Llen &#60;&#61; beg + len) &#38; (botY + lsp &#60;&#61; Y) DO &#32;&#32;&#32;&#32;&#32;&#32;&#32;&#32;&#32;&#32;&#32;&#32;&#32;&#32;org &#58;&#61; org + Llen; Y &#58;&#61; Y - lsp; Llen &#58;&#61; LineLen(R) &#32;&#32;&#32;&#32;&#32;&#32;&#32;&#32;&#32;&#32;&#32;&#32;END; &#32;&#32;&#32;&#32;&#32;&#32;&#32;&#32;&#32;&#32;&#32;&#32;org &#58;&#61; org + Llen; Y &#58;&#61; Y - lsp; &#32;&#32;&#32;&#32;&#32;&#32;&#32;&#32;&#32;&#32;&#32;&#32;IF botY &#60;&#61; Y THEN (* update with reusing lines *) &#32;&#32;&#32;&#32;&#32;&#32;&#32;&#32;&#32;&#32;&#32;&#32;&#32;&#32;YL &#58;&#61; Y; L &#58;&#61; LR; &#32;&#32;&#32;&#32;&#32;&#32;&#32;&#32;&#32;&#32;&#32;&#32;&#32;&#32;WHILE (L.next # F.trailer) &#38; (botY + lsp &#60;&#61; Y) DO &#32;&#32;&#32;&#32;&#32;&#32;&#32;&#32;&#32;&#32;&#32;&#32;&#32;&#32;&#32;&#32;org &#58;&#61; org + L.len; Y &#58;&#61; Y - lsp; L &#58;&#61; L.next &#32;&#32;&#32;&#32;&#32;&#32;&#32;&#32;&#32;&#32;&#32;&#32;&#32;&#32;END; &#32;&#32;&#32;&#32;&#32;&#32;&#32;&#32;&#32;&#32;&#32;&#32;&#32;&#32;orgS &#58;&#61; org; YS &#58;&#61; Y; LS &#58;&#61; L; &#32;&#32;&#32;&#32;&#32;&#32;&#32;&#32;&#32;&#32;&#32;&#32;&#32;&#32;Display.CopyBlock ( &#32;&#32;&#32;&#32;&#32;&#32;&#32;&#32;&#32;&#32;&#32;&#32;&#32;&#32;&#32;&#32;F.X + F.left, YS - dsr + (YR - YL), F.W - F.left, YL + lsp - YS, F.X + F.left, YS - dsr, replace); &#32;&#32;&#32;&#32;&#32;&#32;&#32;&#32;&#32;&#32;&#32;&#32;&#32;&#32;org &#58;&#61; orgB; Y &#58;&#61; YB; L &#58;&#61; LB; &#32;&#32;&#32;&#32;&#32;&#32;&#32;&#32;&#32;&#32;&#32;&#32;&#32;&#32;Texts.OpenReader(R, F.text, org); Texts.Read(R, ch); &#32;&#32;&#32;&#32;&#32;&#32;&#32;&#32;&#32;&#32;&#32;&#32;&#32;&#32;off &#58;&#61; beg - org; wid &#58;&#61; Width(R, off); &#32;&#32;&#32;&#32;&#32;&#32;&#32;&#32;&#32;&#32;&#32;&#32;&#32;&#32;ReplConst (F.col, F, F.X + F.left + wid, Y - dsr, L.wid - wid, lsp, 0); &#32;&#32;&#32;&#32;&#32;&#32;&#32;&#32;&#32;&#32;&#32;&#32;&#32;&#32;DisplayLine(F, L, R, F.X + F.left + wid, Y, off); &#32;&#32;&#32;&#32;&#32;&#32;&#32;&#32;&#32;&#32;&#32;&#32;&#32;&#32;WHILE org + L.len &#60;&#61; beg + len DO &#32;&#32;&#32;&#32;&#32;&#32;&#32;&#32;&#32;&#32;&#32;&#32;&#32;&#32;&#32;&#32;org &#58;&#61; org + L.len; Y &#58;&#61; Y - lsp; NEW(L.next); L &#58;&#61; L.next; &#32;&#32;&#32;&#32;&#32;&#32;&#32;&#32;&#32;&#32;&#32;&#32;&#32;&#32;&#32;&#32;Display.ReplConst(F.col, F.X + F.left, Y - dsr, F.W - F.left, lsp, replace); &#32;&#32;&#32;&#32;&#32;&#32;&#32;&#32;&#32;&#32;&#32;&#32;&#32;&#32;&#32;&#32;DisplayLine(F, L, R, F.X + F.left, Y, 0) &#32;&#32;&#32;&#32;&#32;&#32;&#32;&#32;&#32;&#32;&#32;&#32;&#32;&#32;END; &#32;&#32;&#32;&#32;&#32;&#32;&#32;&#32;&#32;&#32;&#32;&#32;&#32;&#32;L.next &#58;&#61; LR; &#32;&#32;&#32;&#32;&#32;&#32;&#32;&#32;&#32;&#32;&#32;&#32;&#32;&#32;org &#58;&#61; orgS; Y &#58;&#61; YS; L &#58;&#61; LS; org &#58;&#61; org + L.len; Y &#58;&#61; Y - lsp; &#32;&#32;&#32;&#32;&#32;&#32;&#32;&#32;&#32;&#32;&#32;&#32;&#32;&#32;Texts.OpenReader(R, F.text, org); Texts.Read(R, ch); &#32;&#32;&#32;&#32;&#32;&#32;&#32;&#32;&#32;&#32;&#32;&#32;&#32;&#32;WHILE &#126;L.eot &#38; (botY &#60;&#61; Y) DO &#32;&#32;&#32;&#32;&#32;&#32;&#32;&#32;&#32;&#32;&#32;&#32;&#32;&#32;&#32;&#32;NEW(L.next); L &#58;&#61; L.next; &#32;&#32;&#32;&#32;&#32;&#32;&#32;&#32;&#32;&#32;&#32;&#32;&#32;&#32;&#32;&#32;Display.ReplConst(F.col, F.X + F.left, Y - dsr, F.W - F.left, lsp, replace); &#32;&#32;&#32;&#32;&#32;&#32;&#32;&#32;&#32;&#32;&#32;&#32;&#32;&#32;&#32;&#32;DisplayLine(F, L, R, F.X + F.left, Y, 0); &#32;&#32;&#32;&#32;&#32;&#32;&#32;&#32;&#32;&#32;&#32;&#32;&#32;&#32;&#32;&#32;org &#58;&#61; org + L.len; Y &#58;&#61; Y - lsp &#32;&#32;&#32;&#32;&#32;&#32;&#32;&#32;&#32;&#32;&#32;&#32;&#32;&#32;END; &#32;&#32;&#32;&#32;&#32;&#32;&#32;&#32;&#32;&#32;&#32;&#32;&#32;&#32;L.next &#58;&#61; F.trailer; &#32;&#32;&#32;&#32;&#32;&#32;&#32;&#32;&#32;&#32;&#32;&#32;&#32;&#32;IF YR &#60; YL THEN H &#58;&#61; Min(YL- YR, Y + lsp - dsr - F.Y); &#32;&#32;&#32;&#32;&#32;&#32;&#32;&#32;&#32;&#32;&#32;&#32;&#32;&#32;&#32;&#32;Display.ReplConst(F.col, F.X + F.left, Y + lsp - dsr - H, F.W - F.left, H, replace) &#32;&#32;&#32;&#32;&#32;&#32;&#32;&#32;&#32;&#32;&#32;&#32;&#32;&#32;END; &#32;&#32;&#32;&#32;&#32;&#32;&#32;&#32;&#32;&#32;&#32;&#32;&#32;&#32;done &#58;&#61; TRUE &#32;&#32;&#32;&#32;&#32;&#32;&#32;&#32;&#32;&#32;&#32;&#32;END &#32;&#32;&#32;&#32;&#32;&#32;&#32;&#32;&#32;&#32;END &#32;&#32;&#32;&#32;&#32;&#32;&#32;&#32;END; &#32;&#32;&#32;&#32;&#32;&#32;&#32;&#32;IF &#126;done THEN (* update without reusing lines *) &#32;&#32;&#32;&#32;&#32;&#32;&#32;&#32;&#32;&#32;YR &#58;&#61; Y; org &#58;&#61; orgB; Y &#58;&#61; YB; L &#58;&#61; LB; &#32;&#32;&#32;&#32;&#32;&#32;&#32;&#32;&#32;&#32;Texts.OpenReader(R, F.text, org); Texts.Read(R, ch); &#32;&#32;&#32;&#32;&#32;&#32;&#32;&#32;&#32;&#32;off &#58;&#61; beg - org; wid &#58;&#61; Width(R, off); &#32;&#32;&#32;&#32;&#32;&#32;&#32;&#32;&#32;&#32;ReplConst (F.col, F, F.X + F.left + wid, Y - dsr, L.wid - wid, lsp, 0); &#32;&#32;&#32;&#32;&#32;&#32;&#32;&#32;&#32;&#32;DisplayLine(F, L, R, F.X + F.left + wid, Y, off); &#32;&#32;&#32;&#32;&#32;&#32;&#32;&#32;&#32;&#32;WHILE &#126;L.eot &#38; (botY + lsp &#60;&#61; Y) DO &#32;&#32;&#32;&#32;&#32;&#32;&#32;&#32;&#32;&#32;&#32;&#32;org &#58;&#61; org + L.len; Y &#58;&#61; Y - lsp; NEW(L.next); L &#58;&#61; L.next; &#32;&#32;&#32;&#32;&#32;&#32;&#32;&#32;&#32;&#32;&#32;&#32;Display.ReplConst(F.col, F.X + F.left, Y - dsr, F.W - F.left, lsp, replace); &#32;&#32;&#32;&#32;&#32;&#32;&#32;&#32;&#32;&#32;&#32;&#32;DisplayLine(F, L, R, F.X + F.left, Y, 0) &#32;&#32;&#32;&#32;&#32;&#32;&#32;&#32;&#32;&#32;END; &#32;&#32;&#32;&#32;&#32;&#32;&#32;&#32;&#32;&#32;org &#58;&#61; org + L.len; Y &#58;&#61; Y - lsp; &#32;&#32;&#32;&#32;&#32;&#32;&#32;&#32;&#32;&#32;IF (Y &#60; botY) &#38; (org &#60;&#61; beg + len) &#38; (beg + len &#60; org + 500) THEN (*autoscroll*) &#32;&#32;&#32;&#32;&#32;&#32;&#32;&#32;&#32;&#32;&#32;&#32;REPEAT &#32;&#32;&#32;&#32;&#32;&#32;&#32;&#32;&#32;&#32;&#32;&#32;&#32;&#32;Display.CopyBlock &#32;&#32;&#32;&#32;&#32;&#32;&#32;&#32;&#32;&#32;&#32;&#32;&#32;&#32;(F.X + F.left, Y + lsp - dsr, F.W - F.left, F.Y + F.H - F.top - asr - Y - lsp, &#32;&#32;&#32;&#32;&#32;&#32;&#32;&#32;&#32;&#32;&#32;&#32;&#32;&#32;&#32;&#32;&#32;&#32;F.X + F.left, Y + lsp - dsr + lsp, &#32;&#32;&#32;&#32;&#32;&#32;&#32;&#32;&#32;&#32;&#32;&#32;&#32;&#32;replace); &#32;&#32;&#32;&#32;&#32;&#32;&#32;&#32;&#32;&#32;&#32;&#32;&#32;&#32;F.org &#58;&#61; F.org + F.trailer.next.len; &#32;&#32;&#32;&#32;&#32;&#32;&#32;&#32;&#32;&#32;&#32;&#32;&#32;&#32;L.next &#58;&#61; F.trailer.next; F.trailer.next &#58;&#61; F.trailer.next.next; &#32;&#32;&#32;&#32;&#32;&#32;&#32;&#32;&#32;&#32;&#32;&#32;&#32;&#32;L &#58;&#61; L.next; &#32;&#32;&#32;&#32;&#32;&#32;&#32;&#32;&#32;&#32;&#32;&#32;&#32;&#32;Display.ReplConst(F.col, F.X + F.left, Y + lsp - dsr, F.W - F.left, lsp, replace); &#32;&#32;&#32;&#32;&#32;&#32;&#32;&#32;&#32;&#32;&#32;&#32;&#32;&#32;DisplayLine(F, L, R, F.X + F.left, Y + lsp, 0); &#32;&#32;&#32;&#32;&#32;&#32;&#32;&#32;&#32;&#32;&#32;&#32;&#32;&#32;org &#58;&#61; org + L.len &#32;&#32;&#32;&#32;&#32;&#32;&#32;&#32;&#32;&#32;&#32;&#32;UNTIL org &#62; beg + len &#32;&#32;&#32;&#32;&#32;&#32;&#32;&#32;&#32;&#32;END; &#32;&#32;&#32;&#32;&#32;&#32;&#32;&#32;&#32;&#32;L.next &#58;&#61; F.trailer; &#32;&#32;&#32;&#32;&#32;&#32;&#32;&#32;&#32;&#32;IF YR &#60; Y THEN &#32;&#32;&#32;&#32;&#32;&#32;&#32;&#32;&#32;&#32;&#32;&#32;Display.ReplConst (F.col, F.X + F.left, YR + lsp - dsr, F.W - F.left, Y - YR, replace) &#32;&#32;&#32;&#32;&#32;&#32;&#32;&#32;&#32;&#32;END &#32;&#32;&#32;&#32;&#32;&#32;&#32;&#32;END &#32;&#32;&#32;&#32;&#32;&#32;END &#32;&#32;&#32;&#32;END; &#32;&#32;&#32;&#32;UpdateMark(F) &#32;&#32;END Update; &#32;&#32;PROCEDURE Recall (F&#58; Frame); &#32;&#32;&#32;&#32;VAR buf&#58; Texts.Buffer; pos&#58; SIGNED32; &#32;&#32;BEGIN &#32;&#32;&#32;&#32;IF F.car &#62; 0 THEN &#9;&#32;&#32;NEW(buf); Texts.OpenBuf(buf); &#32;&#32;&#32;&#32;&#32;&#32;Texts.Recall(buf); pos &#58;&#61; F.carloc.pos + buf.len; &#9;&#32;&#32;Texts.Insert(F.text, F.carloc.pos, buf); &#32;&#32;&#32;&#32;&#32;&#32;SetCaret(F, pos) &#32;&#32;&#32;&#32;END &#32;&#32;END Recall; &#32;&#32;PROCEDURE SaveCaret; &#32;&#32;BEGIN &#32;&#32;&#32;&#32;saved.car &#58;&#61; NIL; saved.text &#58;&#61; NIL; &#32;&#32;&#32;&#32;saved.id &#58;&#61; Oberon.get; Display.Broadcast(saved) &#32;&#32;END SaveCaret; &#32;&#32;PROCEDURE RestoreCaret; &#32;&#32;BEGIN &#32;&#32;&#32;&#32;IF (saved.car # NIL) &#38; (saved.text # NIL) THEN &#32;&#32;&#32;&#32;&#32;&#32;saved.id &#58;&#61; Oberon.set; Display.Broadcast(saved) &#32;&#32;&#32;&#32;END &#32;&#32;END RestoreCaret; &#32;&#32;PROCEDURE Edit* (F&#58; Frame; X, Y&#58; SIGNED16; Keys&#58; SET); &#32;&#32;&#32;&#32;VAR &#32;&#32;&#32;&#32;&#32;&#32;M&#58; Oberon.ConsumeMsg; &#32;&#32;&#32;&#32;&#32;&#32;R&#58; Texts.Reader; &#32;&#32;&#32;&#32;&#32;&#32;text&#58; Texts.Text; buf&#58; Texts.Buffer; &#32;&#32;&#32;&#32;&#32;&#32;time, pos, beg, end&#58; SIGNED32; &#32;&#32;&#32;&#32;&#32;&#32;keysum&#58; SET; &#32;&#32;&#32;&#32;&#32;&#32;ch&#58; CHAR; &#32;&#32;BEGIN &#32;&#32;&#32;&#32;Oberon.DrawCursor(Oberon.Mouse, Oberon.Arrow, X, Y); &#32;&#32;&#32;&#32;IF X &#60; F.X + Min(F.left, barW) THEN &#32;&#32;&#32;&#32;&#32;&#32;IF (0 IN Keys) OR (1 IN Keys) THEN keysum &#58;&#61; Keys; &#32;&#32;&#32;&#32;&#32;&#32;&#32;&#32;REPEAT &#32;&#32;&#32;&#32;&#32;&#32;&#32;&#32;&#32;&#32;Input.Mouse(Keys, X, Y); &#32;&#32;&#32;&#32;&#32;&#32;&#32;&#32;&#32;&#32;keysum &#58;&#61; keysum + Keys; &#32;&#32;&#32;&#32;&#32;&#32;&#32;&#32;&#32;&#32;Oberon.DrawCursor(Oberon.Mouse, Oberon.Arrow, X, Y) &#32;&#32;&#32;&#32;&#32;&#32;&#32;&#32;UNTIL Keys &#61; &#123;&#125;; &#32;&#32;&#32;&#32;&#32;&#32;&#32;&#32;IF &#126;(2 IN keysum) THEN &#32;&#32;&#32;&#32;&#32;&#32;&#32;&#32;&#32;&#32;RemoveMarks(F); Oberon.RemoveMarks(F.X, F.Y, F.W, F.H); &#32;&#32;&#32;&#32;&#32;&#32;&#32;&#32;&#32;&#32;IF (0 IN keysum) OR (F.Y + F.H &#60; Y) THEN &#32;&#32;&#32;&#32;&#32;&#32;&#32;&#32;&#32;&#32;&#32;&#32;IF 1 IN keysum THEN pos &#58;&#61; 0 &#32;&#32;&#32;&#32;&#32;&#32;&#32;&#32;&#32;&#32;&#32;&#32;ELSE pos &#58;&#61; Max(F.org - LONG(F.H * 25) DIV lsp, 0) &#32;&#32;&#32;&#32;&#32;&#32;&#32;&#32;&#32;&#32;&#32;&#32;END &#32;&#32;&#32;&#32;&#32;&#32;&#32;&#32;&#32;&#32;ELSE &#32;&#32;&#32;&#32;&#32;&#32;&#32;&#32;&#32;&#32;&#32;&#32;pos &#58;&#61; (F.Y + F.H - Y) * (F.text.len) DIV F.H &#32;&#32;&#32;&#32;&#32;&#32;&#32;&#32;&#32;&#32;END; &#32;&#32;&#32;&#32;&#32;&#32;&#32;&#32;&#32;&#32;RemoveMarks(F); Oberon.RemoveMarks(F.X, F.Y, F.W, F.H); &#32;&#32;&#32;&#32;&#32;&#32;&#32;&#32;&#32;&#32;Show(F, pos) &#32;&#32;&#32;&#32;&#32;&#32;&#32;&#32;ELSIF &#126;(0 IN keysum) THEN &#32;&#32;&#32;&#32;&#32;&#32;&#32;&#32;&#32;&#32;RemoveMarks(F); Oberon.RemoveMarks(F.X, F.Y, F.W, F.H); &#32;&#32;&#32;&#32;&#32;&#32;&#32;&#32;&#32;&#32;Show(F, F.text.len) &#32;&#32;&#32;&#32;&#32;&#32;&#32;&#32;END &#32;&#32;&#32;&#32;&#32;&#32;ELSIF 2 IN Keys THEN &#32;&#32;&#32;&#32;&#32;&#32;&#32;&#32;TrackLine(F, X, Y, pos, keysum); &#32;&#32;&#32;&#32;&#32;&#32;&#32;&#32;IF (pos &#62;&#61; 0) &#38; &#126;(0 IN keysum) THEN &#32;&#32;&#32;&#32;&#32;&#32;&#32;&#32;&#32;&#32;RemoveMarks(F); Oberon.RemoveMarks(F.X, F.Y, F.W, F.H); &#32;&#32;&#32;&#32;&#32;&#32;&#32;&#32;&#32;&#32;Show(F, pos) &#32;&#32;&#32;&#32;&#32;&#32;&#32;&#32;END &#32;&#32;&#32;&#32;&#32;&#32;END &#32;&#32;&#32;&#32;ELSE &#32;&#32;&#32;&#32;&#32;&#32;IF 0 IN Keys THEN &#32;&#32;&#32;&#32;&#32;&#32;&#32;&#32;TrackSelection(F, X, Y, keysum); &#32;&#32;&#32;&#32;&#32;&#32;&#32;&#32;IF F.sel # 0 THEN &#32;&#32;&#32;&#32;&#32;&#32;&#32;&#32;&#32;&#32;IF (2 IN keysum) &#38; &#126;(1 IN keysum) THEN (*delete text*) &#32;&#32;&#32;&#32;&#32;&#32;&#32;&#32;&#32;&#32;&#32;&#32;Oberon.GetSelection(text, beg, end, time); &#32;&#32;&#32;&#32;&#32;&#32;&#32;&#32;&#32;&#32;&#32;&#32;Texts.Delete(text, beg, end); &#32;&#32;&#32;&#32;&#32;&#32;&#32;&#32;&#32;&#32;&#32;&#32;Oberon.Defocus; SetCaret(F, beg) &#32;&#32;&#32;&#32;&#32;&#32;&#32;&#32;&#32;&#32;ELSIF (1 IN keysum) &#38; &#126;(2 IN keysum) THEN (*copy to focus*) &#32;&#32;&#32;&#32;&#32;&#32;&#32;&#32;&#32;&#32;&#32;&#32;Oberon.GetSelection(text, beg, end, time); &#32;&#32;&#32;&#32;&#32;&#32;&#32;&#32;&#32;&#32;&#32;&#32;M.F &#58;&#61; NIL; M.text &#58;&#61; text; M.beg &#58;&#61; beg; M.end &#58;&#61; end; &#32;&#32;&#32;&#32;&#32;&#32;&#32;&#32;&#32;&#32;&#32;&#32;Display.Broadcast(M) &#32;&#32;&#32;&#32;&#9;&#32;&#32;END &#32;&#32;&#32;&#32;&#32;&#32;&#32;&#32;END &#32;&#32;&#32;&#32;&#32;&#32;ELSIF 1 IN Keys THEN &#32;&#32;&#32;&#32;&#32;&#32;&#32;&#32;TrackWord(F, X, Y, pos, keysum); &#32;&#32;&#32;&#32;&#32;&#32;&#32;&#32;IF 0 IN keysum THEN &#32;&#32;&#32;&#32;&#32;&#32;&#32;&#32;&#32;&#32;IF (pos &#62;&#61; 0) &#38; &#126;(2 IN keysum) THEN CallCmd(OpenCmd, F, pos, FALSE) END &#32;&#32;&#32;&#32;&#32;&#32;&#32;&#32;ELSE &#32;&#32;&#32;&#32;&#32;&#32;&#32;&#32;&#32;&#32;IF pos &#62;&#61; 0 THEN Call(F, pos, 2 IN keysum) END &#32;&#32;&#32;&#32;&#32;&#32;&#32;&#32;END &#32;&#32;&#32;&#32;&#32;&#32;ELSIF 2 IN Keys THEN &#32;&#32;&#32;&#32;&#32;&#32;&#32;&#32;IF Oberon.New &#38; (F.car # 0) &#38; (Pos(F, X, Y) &#61; F.carloc.pos) THEN (*click on caret*) &#32;&#32;&#32;&#32;&#32;&#32;&#32;&#32;&#32;&#32;Oberon.Defocus; RestoreCaret; TrackWord(F, X, Y, pos, keysum); &#32;&#32;&#32;&#32;&#32;&#32;&#32;&#32;&#32;&#32;IF 0 IN keysum THEN &#32;&#32;&#32;&#32;&#32;&#32;&#32;&#32;&#32;&#32;&#32;&#32;IF (pos &#62;&#61; 0) &#38; &#126;(1 IN keysum) THEN CallCmd(OpenCmd, F, pos, FALSE) END &#32;&#32;&#32;&#32;&#32;&#32;&#32;&#32;&#32;&#32;ELSE &#32;&#32;&#32;&#32;&#32;&#32;&#32;&#32;&#32;&#32;&#32;&#32;IF pos &#62;&#61; 0 THEN Call(F, pos, FALSE) END &#32;&#32;&#32;&#32;&#32;&#32;&#32;&#32;&#32;&#32;END &#32;&#32;&#32;&#32;&#32;&#32;&#32;&#32;ELSE &#32;&#32;&#32;&#32;&#32;&#32;&#32;&#32;&#32;&#32;IF Oberon.New THEN SaveCaret END; &#32;&#32;&#32;&#32;&#32;&#32;&#32;&#32;&#32;&#32;Oberon.Defocus; TrackCaret(F, X, Y, keysum); &#32;&#32;&#32;&#32;&#32;&#32;&#32;&#32;&#32;&#32;IF F.car # 0 THEN &#32;&#32;&#32;&#32;&#32;&#32;&#32;&#32;&#32;&#32;&#32;&#32;IF (1 IN keysum) &#38; &#126;(0 IN keysum) THEN (*copy from selection*) &#32;&#32;&#32;&#32;&#32;&#32;&#32;&#32;&#32;&#32;&#32;&#32;&#32;&#32;Oberon.GetSelection(text, beg, end, time); &#32;&#32;&#32;&#32;&#32;&#32;&#32;&#32;&#32;&#32;&#32;&#32;&#32;&#32;IF time # -1 THEN &#32;&#32;&#32;&#32;&#32;&#32;&#32;&#32;&#32;&#32;&#32;&#32;&#32;&#32;&#32;&#32;&#32;NEW(buf); Texts.OpenBuf(buf); &#32;&#32;&#32;&#32;&#32;&#32;&#32;&#32;&#32;&#32;&#32;&#32;&#32;&#32;&#32;&#32;&#32;Texts.Save(text, beg, end, buf); &#32;&#32;&#32;&#32;&#32;&#32;&#32;&#32;&#32;&#32;&#32;&#32;&#32;&#32;&#32;&#32;&#32;Texts.Insert(F.text, F.carloc.pos, buf); &#32;&#32;&#32;&#32;&#32;&#32;&#32;&#32;&#32;&#32;&#32;&#32;&#32;&#32;&#32;&#32;&#32;SetCaret(F, F.carloc.pos + (end - beg)) &#32;&#32;&#32;&#32;&#32;&#32;&#32;&#32;&#32;&#32;&#32;&#32;&#32;&#32;&#32;ELSE (*copy from delete buffer*) &#32;&#32;&#32;&#32;&#32;&#32;&#32;&#32;&#32;&#32;&#32;&#32;&#32;&#32;&#32;&#32;&#32;NEW(buf); Texts.OpenBuf(buf); &#32;&#32;&#32;&#32;&#32;&#32;&#32;&#32;&#32;&#32;&#32;&#32;&#32;&#32;&#32;&#32;&#32;Texts.Recall(buf); &#32;&#32;&#32;&#32;&#32;&#32;&#32;&#32;&#32;&#32;&#32;&#32;&#32;&#32;&#32;&#32;&#32;end &#58;&#61; F.carloc.pos + buf.len; &#32;&#32;&#32;&#32;&#32;&#32;&#32;&#32;&#32;&#32;&#32;&#32;&#32;&#32;&#32;&#32;&#32;Texts.Insert(F.text, F.carloc.pos, buf); &#32;&#32;&#32;&#32;&#32;&#32;&#32;&#32;&#32;&#32;&#32;&#32;&#32;&#32;&#32;&#32;&#32;SetCaret(F, end) &#32;&#32;&#32;&#32;&#32;&#32;&#32;&#32;&#32;&#32;&#32;&#32;&#32;&#32;&#32;END &#32;&#32;&#32;&#32;&#32;&#32;&#32;&#32;&#32;&#32;&#32;&#32;ELSIF (0 IN keysum) &#38; &#126;(1 IN keysum) THEN (*copy font*) &#32;&#32;&#32;&#32;&#32;&#32;&#32;&#32;&#32;&#32;&#32;&#32;&#32;&#32;Oberon.GetSelection(text, beg, end, time); &#32;&#32;&#32;&#32;&#32;&#32;&#32;&#32;&#32;&#32;&#32;&#32;&#32;&#32;IF time # -1 THEN &#32;&#32;&#32;&#32;&#32;&#32;&#32;&#32;&#32;&#32;&#32;&#32;&#32;&#32;&#32;&#32;Texts.OpenReader(R, F.text, F.carloc.pos); Texts.Read(R, ch); &#32;&#32;&#32;&#32;&#32;&#32;&#32;&#32;&#32;&#32;&#32;&#32;&#32;&#32;&#32;&#32;IF (R.lib # NIL) &#38; (R.lib IS Fonts.Font) THEN &#32;&#32;&#32;&#32;&#32;&#32;&#32;&#32;&#32;&#32;&#32;&#32;&#32;&#32;&#32;&#32;&#32;&#32;Texts.ChangeLooks(text, beg, end, &#123;0, 1, 2&#125;, R.lib, R.col, R.voff) &#32;&#32;&#32;&#32;&#32;&#32;&#32;&#32;&#32;&#32;&#32;&#32;&#32;&#32;&#32;&#32;END &#32;&#32;&#32;&#32;&#32;&#32;&#32;&#32;&#32;&#32;&#32;&#32;&#32;&#32;END &#32;&#32;&#32;&#32;&#32;&#32;&#32;&#32;&#32;&#32;&#32;&#32;END &#32;&#32;&#32;&#32;&#32;&#32;&#32;&#32;&#32;&#32;END &#32;&#32;&#32;&#32;&#32;&#32;&#32;&#32;END &#32;&#32;&#32;&#32;&#32;&#32;END &#32;&#32;&#32;&#32;END &#32;&#32;END Edit; &#32;&#32;PROCEDURE Handle* (F&#58; Objects.Object; VAR M&#58; Objects.ObjMsg); &#32;&#32;&#9;VAR F1&#58; Frame; &#32;&#32;BEGIN &#32;&#32;&#32;&#32;WITH F&#58; Frame DO &#32;&#32;&#9;IF M IS Texts.UpdateMsg THEN &#32;&#32;&#9;&#32;&#32;WITH M&#58; Texts.UpdateMsg DO &#32;&#32;&#32;&#32;&#32;&#32;&#32;&#32;&#32;&#32;IF F.text &#61; M.text THEN Update(F, M.beg, M.end, M.len) END &#32;&#32;&#9;&#32;&#32;END &#32;&#32;&#32;&#32;&#32;&#32;ELSIF M IS Oberon.InputMsg THEN &#32;&#32;&#32;&#32;&#32;&#32;&#32;&#32;&#32;WITH M&#58; Oberon.InputMsg DO &#32;&#32;&#32;&#32;&#32;&#32;&#32;&#32;&#32;&#32;IF M.id &#61; Oberon.track THEN Edit(F, M.X, M.Y, M.keys) &#32;&#32;&#32;&#32;&#32;&#32;&#32;&#32;&#32;&#32;ELSIF M.id &#61; Oberon.consume THEN &#32;&#32;&#9;&#32;&#32;&#32;&#32;&#32;&#32;IF F.car # 0 THEN Write(F, M.ch, M.fnt, M.col, M.voff) END &#32;&#32;&#32;&#32;&#32;&#32;&#32;&#32;&#32;&#32;END &#32;&#32;&#32;&#32;&#32;&#32;&#32;&#32;&#32;END &#32;&#32;&#32;&#32;&#32;&#32;ELSIF M IS Oberon.ControlMsg THEN &#32;&#32;&#32;&#32;&#32;&#32;&#32;&#32;WITH M&#58; Oberon.ControlMsg DO &#32;&#32;&#9;&#32;&#32;&#32;&#32;IF M.id &#61; Oberon.defocus THEN Defocus(F) &#32;&#32;&#9;&#32;&#32;&#32;&#32;ELSIF M.id &#61; Oberon.neutralize THEN Neutralize(F) &#32;&#32;&#32;&#32;&#32;&#32;&#32;&#32;&#32;&#32;END &#32;&#32;&#32;&#32;&#32;&#32;&#32;&#32;END &#32;&#32;&#32;&#32;&#32;&#32;ELSIF M IS Oberon.CaretMsg THEN &#32;&#32;&#32;&#32;&#32;&#32;&#32;&#32;WITH M&#58; Oberon.CaretMsg DO &#32;&#32;&#32;&#32;&#32;&#32;&#32;&#32;&#32;&#32;IF M.id &#61; Oberon.get THEN GetCaret(F, M) &#32;&#32;&#32;&#32;&#32;&#32;&#32;&#32;&#32;&#32;ELSIF (M.car &#61; F) &#38; (M.text &#61; F.text) THEN &#32;&#32;&#32;&#32;&#32;&#32;&#32;&#32;&#32;&#32;&#32;&#32;IF M.id &#61; Oberon.set THEN SetCaret(F, M.pos) &#32;&#32;&#32;&#32;&#32;&#32;&#32;&#32;&#32;&#32;&#32;&#32;&#32;&#32;ELSIF M.id &#61; Oberon.reset THEN RemoveCaret(F) &#32;&#32;&#32;&#32;&#32;&#32;&#32;&#32;&#32;&#32;&#32;&#32;END &#32;&#32;&#32;&#32;&#32;&#32;&#32;&#32;&#32;&#32;END &#32;&#32;&#32;&#32;&#32;&#32;&#32;&#32;END &#32;&#32;&#32;&#32;&#32;&#32;ELSIF M IS Oberon.SelectMsg THEN &#32;&#32;&#32;&#32;&#32;&#32;&#32;&#32;WITH M&#58; Oberon.SelectMsg DO &#32;&#32;&#32;&#32;&#32;&#32;&#32;&#32;&#32;&#32;IF M.id &#61; Oberon.get THEN GetSelection(F, M) &#32;&#32;&#32;&#32;&#32;&#32;&#32;&#32;&#32;&#32;ELSIF (M.sel &#61; F) &#38; (M.text &#61; F.text) THEN &#32;&#32;&#32;&#32;&#32;&#32;&#32;&#32;&#32;&#32;&#32;&#32;IF M.id &#61; Oberon.set THEN SetSelection(F, M.beg, M.end) &#32;&#32;&#32;&#32;&#32;&#32;&#32;&#32;&#32;&#32;&#32;&#32;&#32;&#32;ELSIF M.id &#61; Oberon.reset THEN RemoveSelection(F) &#32;&#32;&#32;&#32;&#32;&#32;&#32;&#32;&#32;&#32;&#32;&#32;END &#32;&#32;&#32;&#32;&#32;&#32;&#32;&#32;&#32;&#32;END &#32;&#32;&#32;&#32;&#32;&#32;&#32;&#32;END &#32;&#32;&#32;&#32;&#32;&#32;ELSIF M IS Oberon.ConsumeMsg THEN &#32;&#32;&#32;&#32;&#32;&#32;&#32;&#32;WITH M&#58; Oberon.ConsumeMsg DO &#32;&#32;&#32;&#32;&#32;&#32;&#32;&#32;&#32;&#32;CopyOver(F, M.text, M.beg, M.end) &#32;&#32;&#32;&#32;&#32;&#32;&#32;&#32;END &#32;&#32;&#32;&#32;&#32;&#32;ELSIF M IS Oberon.RecallMsg THEN &#32;&#32;&#32;&#32;&#32;&#32;&#32;&#32;WITH M&#58; Oberon.RecallMsg DO Recall(F) END &#32;&#32;&#32;&#32;&#32;&#32;ELSIF M IS Display.ModifyMsg THEN &#32;&#32;&#32;&#32;&#32;&#32;&#32;&#32;WITH M&#58; Display.ModifyMsg DO &#32;&#32;&#32;&#32;&#32;&#32;&#32;&#32;&#32;&#32;IF M.F &#61; F THEN Modify(F, M.id, M.dY, M.Y, M.H) END &#32;&#32;&#32;&#32;&#32;&#32;&#32;&#32;END &#32;&#32;&#32;&#32;&#32;&#32;ELSIF M IS Display.LocateMsg THEN &#32;&#32;&#32;&#32;&#32;&#32;&#32;&#32;WITH M&#58; Display.LocateMsg DO &#32;&#32;&#32;&#32;&#32;&#32;&#32;&#32;&#32;&#32;IF (F.X &#60;&#61; M.X) &#38; (M.X &#60; F.X + F.W) &#38; (F.Y &#60;&#61; M.Y) &#38; (M.Y &#60; F.Y + F.H) THEN &#32;&#32;&#32;&#32;&#32;&#32;&#32;&#32;&#32;&#32;&#32;&#32;M.loc &#58;&#61; F; M.res &#58;&#61; 0 &#32;&#32;&#32;&#32;&#32;&#32;&#32;&#32;&#32;&#32;END &#32;&#32;&#32;&#32;&#32;&#32;&#32;&#32;END &#32;&#32;&#32;&#32;&#32;&#32;ELSIF M IS Objects.AttrMsg THEN &#32;&#32;&#32;&#32;&#32;&#32;&#32;&#32;WITH M&#58; Objects.AttrMsg DO GetAttr(F, M.s); M.class &#58;&#61; Objects.String; M.res &#58;&#61; 0 END &#32;&#32;&#32;&#32;&#32;&#32;ELSIF M IS Objects.CopyMsg THEN &#32;&#32;&#32;&#32;&#32;&#32;&#32;&#32;WITH M&#58; Objects.CopyMsg DO Copy(F, F1); M.obj &#58;&#61; F1 END &#32;&#32;&#32;&#32;&#32;&#32;ELSIF M IS Objects.LinkMsg THEN &#32;&#32;&#32;&#32;&#32;&#32;&#32;&#32;WITH M&#58; Objects.LinkMsg DO M.obj &#58;&#61; F.text; M.res &#58;&#61; 0 END &#32;&#32;&#9;END &#32;&#32;&#32;&#32;END &#32;&#32;END Handle; &#32;&#32;(*creation*) &#32;&#32;PROCEDURE Menu (name, commands&#58; ARRAY OF CHAR)&#58; Texts.Text; &#32;&#32;&#32;&#32;VAR T&#58; Texts.Text; mb, me, m, s, d, i&#58; SIGNED16; ch&#58; CHAR; &#32;&#32;&#32;&#32;continueOuter, continueInner&#58; BOOLEAN; &#32;&#32;BEGIN &#32;&#32;&#32;&#32;IF SmallDisplay &#38; (Display.Width &#60; 1024) THEN (*adjust commands*) &#32;&#32;&#32;&#32;&#32;&#32;mb &#58;&#61; 0; me &#58;&#61; 0; s &#58;&#61; 0; d &#58;&#61; 0; &#32;&#32;&#32;&#32;&#32;&#32;continueOuter &#58;&#61; TRUE; &#32;&#32;&#32;&#32;&#32;&#32;(* outer LOOP *) WHILE continueOuter DO &#32;&#32;&#32;&#32;&#32;&#32;&#32;&#32;(*position to beginning of word*) &#32;&#32;&#32;&#32;&#32;&#32;&#32;&#32;continueInner &#58;&#61; TRUE; &#32;&#32;&#32;&#32;&#32;&#32;&#32;&#32;(* LOOP 0 *) WHILE continueInner DO &#32;&#32;&#32;&#32;&#32;&#32;&#32;&#32;&#32;&#32;IF s &#62;&#61; LEN(commands) THEN &#32;&#32;&#32;&#32;&#32;&#32;&#32;&#32;&#32;&#32;&#32;&#32;(* EXIT *) continueInner &#58;&#61; FALSE &#32;&#32;&#32;&#32;&#32;&#32;&#32;&#32;&#32;&#32;ELSE &#32;&#32;&#32;&#32;&#32;&#32;&#32;&#32;&#32;&#32;&#32;&#32;ch &#58;&#61; commands&#91;s&#93;; INC(s); &#32;&#32;&#32;&#32;&#32;&#32;&#32;&#32;&#32;&#32;&#32;&#32;IF ch &#61; 0X THEN &#32;&#32;&#32;&#32;&#32;&#32;&#32;&#32;&#32;&#32;&#32;&#32;&#32;&#32;(* EXIT *) continueInner &#58;&#61; FALSE &#32;&#32;&#32;&#32;&#32;&#32;&#32;&#32;&#32;&#32;&#32;&#32;ELSE &#32;&#32;&#32;&#32;&#32;&#32;&#32;&#32;&#32;&#32;&#32;&#32;&#32;&#32;commands&#91;d&#93; &#58;&#61; ch; INC(d); &#32;&#32;&#32;&#32;&#32;&#32;&#32;&#32;&#32;&#32;&#32;&#32;&#32;&#32;IF ("A" &#60;&#61; CAP(ch)) &#38; (CAP(ch) &#60;&#61; "Z") THEN (* EXIT *) continueInner &#58;&#61; FALSE END &#32;&#32;&#32;&#32;&#32;&#32;&#32;&#32;&#32;&#32;&#32;&#32;END &#32;&#32;&#32;&#32;&#32;&#32;&#32;&#32;&#32;&#32;END &#32;&#32;&#32;&#32;&#32;&#32;&#32;&#32;END (* LOOP 0 *); &#32;&#32;&#32;&#32;&#32;&#32;&#32;&#32;IF (s &#62;&#61; LEN(commands)) OR (ch &#61; 0X) THEN &#32;&#32;&#32;&#32;&#32;&#32;&#32;&#32;&#32;&#32;(* EXIT *) continueInner &#58;&#61; FALSE &#32;&#32;&#32;&#32;&#32;&#32;&#32;&#32;ELSE &#32;&#32;&#32;&#32;&#32;&#32;&#32;&#32;&#32;&#32;(*scan first part of word, checking against last module name*) &#32;&#32;&#32;&#32;&#32;&#32;&#32;&#32;&#32;&#32;m &#58;&#61; mb; i &#58;&#61; 0; &#32;&#32;&#32;&#32;&#32;&#32;&#32;&#32;&#32;&#32;continueInner &#58;&#61; TRUE; &#32;&#32;&#32;&#32;&#32;&#32;&#32;&#32;&#32;&#32;(* LOOP 1 *) WHILE continueInner DO &#32;&#32;&#32;&#32;&#32;&#32;&#32;&#32;&#32;&#32;&#32;&#32;INC(i); IF (m &#60; me) &#38; (commands&#91;m&#93; &#61; ch) THEN INC(m) END; &#32;&#32;&#32;&#32;&#32;&#32;&#32;&#32;&#32;&#32;&#32;&#32;IF s &#62;&#61; LEN(commands) THEN &#32;&#32;&#32;&#32;&#32;&#32;&#32;&#32;&#32;&#32;&#32;&#32;&#32;&#32;(* EXIT *) continueInner &#58;&#61; FALSE &#32;&#32;&#32;&#32;&#32;&#32;&#32;&#32;&#32;&#32;&#32;&#32;ELSE &#32;&#32;&#32;&#32;&#32;&#32;&#32;&#32;&#32;&#32;&#32;&#32;&#32;&#32;ch &#58;&#61; commands&#91;s&#93;; INC(s); &#32;&#32;&#32;&#32;&#32;&#32;&#32;&#32;&#32;&#32;&#32;&#32;&#32;&#32;IF ch &#61; 0X THEN &#32;&#32;&#32;&#32;&#32;&#32;&#32;&#32;&#32;&#32;&#32;&#32;&#32;&#32;&#32;&#32;(* EXIT *) continueInner &#58;&#61; FALSE &#32;&#32;&#32;&#32;&#32;&#32;&#32;&#32;&#32;&#32;&#32;&#32;&#32;&#32;ELSE &#32;&#32;&#32;&#32;&#32;&#32;&#32;&#32;&#32;&#32;&#32;&#32;&#32;&#32;&#32;&#32;commands&#91;d&#93; &#58;&#61; ch; INC(d); &#32;&#32;&#32;&#32;&#32;&#32;&#32;&#32;&#32;&#32;&#32;&#32;&#32;&#32;&#32;&#32;IF (ch &#60; "0") OR ("9" &#60; ch) &#38; (CAP(ch) &#60; "A") OR (CAP(ch) &#62; "Z") THEN &#32;&#32;&#32;&#32;&#32;&#32;&#32;&#32;&#32;&#32;&#32;&#32;&#32;&#32;&#32;&#32;&#32;&#32;(* EXIT *) continueInner &#58;&#61; FALSE &#32;&#32;&#32;&#32;&#32;&#32;&#32;&#32;&#32;&#32;&#32;&#32;&#32;&#32;&#32;&#32;END &#32;&#32;&#32;&#32;&#32;&#32;&#32;&#32;&#32;&#32;&#32;&#32;&#32;&#32;END &#32;&#32;&#32;&#32;&#32;&#32;&#32;&#32;&#32;&#32;&#32;&#32;END &#32;&#32;&#32;&#32;&#32;&#32;&#32;&#32;&#32;&#32;END (* LOOP 1 *); &#32;&#32; &#32;&#32;&#32;&#32;&#32;&#32;&#32;&#32;&#32;&#32;(*check for match*) &#32;&#32;&#32;&#32;&#32;&#32;&#32;&#32;&#32;&#32;IF (s &#60; LEN(commands)) &#38; (ch &#61; ".") THEN &#32;&#32;&#32;&#32;&#32;&#32;&#32;&#32;&#32;&#32;&#32;&#32;IF m &#61; mb + i THEN (*matches previous module name - compress*) &#32;&#32;&#32;&#32;&#32;&#32;&#32;&#32;&#32;&#32;&#32;&#32;&#32;&#32;DEC(d, i); commands&#91;d-1&#93; &#58;&#61; "." &#32;&#32;&#32;&#32;&#32;&#32;&#32;&#32;&#32;&#32;&#32;&#32;ELSE (*set new module name*) &#32;&#32;&#32;&#32;&#32;&#32;&#32;&#32;&#32;&#32;&#32;&#32;&#32;&#32;mb &#58;&#61; d - (i+1); me &#58;&#61; d-1 &#32;&#32;&#32;&#32;&#32;&#32;&#32;&#32;&#32;&#32;&#32;&#32;END; &#32;&#32;&#32;&#32;&#32;&#32;&#32;&#32;&#32;&#32;&#32;&#32; &#32;&#32;&#32;&#32;&#32;&#32;&#32;&#32;&#32;&#32;&#32;&#32;(*and do last part of word*) &#32;&#32;&#32;&#32;&#32;&#32;&#32;&#32;&#32;&#32;&#32;&#32;continueInner &#58;&#61; TRUE; &#32;&#32;&#32;&#32;&#32;&#32;&#32;&#32;&#32;&#32;&#32;&#32;(* LOOP 2 *) WHILE continueInner DO &#32;&#32;&#32;&#32;&#32;&#32;&#32;&#32;&#32;&#32;&#32;&#32;&#32;&#32;IF s &#62;&#61; LEN(commands) THEN &#32;&#32;&#32;&#32;&#32;&#32;&#32;&#32;&#32;&#32;&#32;&#32;&#32;&#32;&#32;&#32;(* EXIT *) continueInner &#58;&#61; FALSE &#32;&#32;&#32;&#32;&#32;&#32;&#32;&#32;&#32;&#32;&#32;&#32;&#32;&#32;ELSE &#32;&#32;&#32;&#32;&#32;&#32;&#32;&#32;&#32;&#32;&#32;&#32;&#32;&#32;&#32;&#32;ch &#58;&#61; commands&#91;s&#93;; INC(s); &#32;&#32;&#32;&#32;&#32;&#32;&#32;&#32;&#32;&#32;&#32;&#32;&#32;&#32;&#32;&#32;IF ch &#61; 0X THEN &#32;&#32;&#32;&#32;&#32;&#32;&#32;&#32;&#32;&#32;&#32;&#32;&#32;&#32;&#32;&#32;&#32;&#32;(* EXIT *) continueInner &#58;&#61; FALSE &#32;&#32;&#32;&#32;&#32;&#32;&#32;&#32;&#32;&#32;&#32;&#32;&#32;&#32;&#32;&#32;ELSE &#32;&#32;&#32;&#32;&#32;&#32;&#32;&#32;&#32;&#32;&#32;&#32;&#32;&#32;&#32;&#32;&#32;&#32;commands&#91;d&#93; &#58;&#61; ch; INC(d); &#32;&#32;&#32;&#32;&#32;&#32;&#32;&#32;&#32;&#32;&#32;&#32;&#32;&#32;&#32;&#32;&#32;&#32;IF (ch &#60; "0") OR ("9" &#60; ch) &#38; (CAP(ch) &#60; "A") OR (CAP(ch) &#62; "Z") THEN &#32;&#32;&#32;&#32;&#32;&#32;&#32;&#32;&#32;&#32;&#32;&#32;&#32;&#32;&#32;&#32;&#32;&#32;&#32;&#32;(* EXIT *) continueInner &#58;&#61; FALSE &#32;&#32;&#32;&#32;&#32;&#32;&#32;&#32;&#32;&#32;&#32;&#32;&#32;&#32;&#32;&#32;&#32;&#32;END &#32;&#32;&#32;&#32;&#32;&#32;&#32;&#32;&#32;&#32;&#32;&#32;&#32;&#32;&#32;&#32;END &#32;&#32;&#32;&#32;&#32;&#32;&#32;&#32;&#32;&#32;&#32;&#32;&#32;&#32;END &#32;&#32;&#32;&#32;&#32;&#32;&#32;&#32;&#32;&#32;&#32;&#32;END (* LOOP 2 *) &#32;&#32;&#32;&#32;&#32;&#32;&#32;&#32;&#32;&#32;&#32;&#32; &#32;&#32;&#32;&#32;&#32;&#32;&#32;&#32;&#32;&#32;END; &#32;&#32;&#32;&#32;&#32;&#32;&#32;&#32;&#32;&#32;IF (s &#62;&#61; LEN(commands)) OR (ch &#61; 0X) THEN (* EXIT *) continueOuter &#58;&#61; FALSE END &#32;&#32;&#32;&#32;&#32;&#32;&#32;&#32;END &#32;&#32;&#32;&#32;&#32;&#32;END (* outer LOOP *); &#32;&#32;&#32;&#32;&#32;&#32;IF d &#60; LEN(commands) THEN commands&#91;d&#93; &#58;&#61; 0X END &#32;&#32;&#32;&#32;END; &#32;&#32;&#32;&#32;NEW(T); Texts.Open(T, ""); &#32;&#32;&#32;&#32;Texts.WriteString(W, name); Texts.WriteString(W, " &#124; "); Texts.WriteString(W, commands); &#32;&#32;&#32;&#32;Texts.Append(T, W.buf); &#32;&#32;&#32;&#32;RETURN T &#32;END Menu; &#32;&#32;PROCEDURE Text* (name&#58; ARRAY OF CHAR)&#58; Texts.Text; &#32;&#32;&#32;&#32;VAR T&#58; Texts.Text; &#32;&#32;BEGIN NEW(T); Texts.Open(T, name); RETURN T &#32;&#32;END Text; &#32;&#32;PROCEDURE NewMenu* (name, commands&#58; ARRAY OF CHAR)&#58; Frame; &#32;&#32;&#32;&#32;VAR F&#58; Frame; l&#58; SIGNED16; &#32;&#32;BEGIN NEW(F); &#32;&#32;&#32;&#32;IF MoveArea THEN l &#58;&#61; barW-1 ELSE l &#58;&#61; left DIV 4 END; &#32;&#32;&#32;&#32;IF Modern THEN Open(F, Handle, Menu(name, commands), 0, MenuBG, l, 0, 3, 1, lsp) &#32;&#32;&#32;&#32;ELSE Open(F, Handle, Menu(name, commands), 0, MenuBG, l, 0, 1, 0, lsp) &#32;&#32;&#32;&#32;END; &#32;&#32;&#32;&#32;RETURN F &#32;&#32;END NewMenu; &#32;&#32;PROCEDURE NewText* (text&#58; Texts.Text; pos&#58; SIGNED32)&#58; Frame; &#32;&#32;&#32;&#32;VAR F&#58; Frame; &#32;&#32;BEGIN NEW(F); &#32;&#32;&#32;&#32;Open(F, Handle, text, pos, TextBG, left, right, top, bot, lsp); &#32;&#32;&#32;&#32;RETURN F &#32;&#32;END NewText; PROCEDURE ShowText(title&#58; ARRAY OF CHAR; T&#58; Texts.Text; W, H&#58; SIGNED16); &#9;VAR X, Y&#58; SIGNED16; V&#58; Viewers.Viewer; menu&#58; ARRAY 100 OF CHAR; BEGIN &#9;X &#58;&#61; 0; WHILE (title&#91;X&#93; # 0X) &#38; (title&#91;X&#93; # "&#124;") DO INC(X) END; &#9;IF title&#91;X&#93; &#61; "&#124;" THEN &#9;&#9;title&#91;X&#93; &#58;&#61; 0X; INC(X);  Y &#58;&#61; 0; &#9;&#9;WHILE title&#91;X&#93; # 0X DO menu&#91;Y&#93; &#58;&#61; title&#91;X&#93;; INC(X);  INC(Y) END; &#9;&#9;menu&#91;Y&#93; &#58;&#61; 0X &#9;ELSE &#9;&#9;menu &#58;&#61; "" &#9;END; &#9;IF T &#61; Oberon.Log THEN &#9;&#9;Oberon.AllocateSystemViewer(0, X, Y); &#9;&#9;IF menu &#61; "" THEN menu &#58;&#61; LogMenu END; &#9;&#9;V &#58;&#61; MenuViewers.New(NewMenu(title, menu), NewText(T, Max(T.len-200, 0)), menuH, X, Y) &#9;ELSE &#9;&#9;IF W &#62; LONG(Display.Width * 3) DIV 8 THEN Oberon.AllocateUserViewer(0, X, Y) &#9;&#9;ELSE Oberon.AllocateSystemViewer(0, X, Y) &#9;&#9;END; &#9;&#9;IF menu &#61; "" THEN menu &#58;&#61; StandardMenu END; &#9;&#9;V &#58;&#61; MenuViewers.New(NewMenu(title, menu), NewText(T, 0), menuH, X, Y) &#9;END END ShowText; (** Replace the default system editor with a textframe. *) PROCEDURE ReplaceSystemEditor*; BEGIN &#9;Oberon.OpenText &#58;&#61; ShowText END ReplaceSystemEditor; BEGIN &#32;&#32;IF Oberon.OpenText &#61; NIL THEN &#32;&#32;&#32;&#32;Oberon.OpenText &#58;&#61; ShowText &#32;&#32;END; &#32;&#32;IF Display.Depth(0) # 1 THEN &#32;&#32;&#32;&#32;MarkColor &#58;&#61; 12; MenuBG &#58;&#61; 13; TextBG &#58;&#61; 14; &#32;&#32;&#32;&#32;IF Modern THEN BarColor &#58;&#61; 12; FullColor &#58;&#61; Display.FG - TextBG &#32;&#32;&#32;&#32;ELSE BarColor &#58;&#61; 13; FullColor &#58;&#61; Display.FG &#32;&#32;&#32;&#32;END; &#32;&#32;&#32;&#32;mode &#58;&#61; paint &#32;&#32;ELSE &#32;&#32;&#32;&#32;MarkColor &#58;&#61; Display.FG; BarColor &#58;&#61; Display.FG; MenuBG &#58;&#61; Display.FG; TextBG&#58;&#61; Display.BG; &#32;&#32;&#32;&#32;FullColor &#58;&#61; Display.FG; mode &#58;&#61; invert &#32;&#32;END; &#32;&#32;IF Modern THEN menuH &#58;&#61; Fonts.Default.height + 8 &#32;&#32;ELSE menuH &#58;&#61; Fonts.Default.height + 2 &#32;&#32;END; &#32;&#32;barW &#58;&#61; Fonts.Default.height + 2; &#32;&#32;left &#58;&#61; barW + Fonts.Default.height DIV 2; &#32;&#32;right &#58;&#61; Fonts.Default.height DIV 2; &#32;&#32;IF Modern THEN top &#58;&#61; Fonts.Default.height DIV 2 * 2 DIV 3 &#32;&#32;ELSE top &#58;&#61; Fonts.Default.height DIV 2 &#32;&#32;END; &#32;&#32;bot &#58;&#61; Fonts.Default.height DIV 2; &#32;&#32;asr &#58;&#61; Fonts.Default.maxY; &#32;&#32;dsr &#58;&#61; -Fonts.Default.minY; &#32;&#32;lsp &#58;&#61; Fonts.Default.height; &#32;&#32;selH &#58;&#61; Fonts.Default.height; &#32;&#32;markW &#58;&#61; Fonts.Default.height DIV 3 * 2; &#32;&#32;eolW &#58;&#61; Fonts.Default.height DIV 2; &#32;&#32;Texts.OpenWriter(W); Texts.OpenWriter(KW); &#32;&#32;BoxPat&#91;0&#93; &#58;&#61; &#123;0..11&#125;; &#32;&#32;BoxPat&#91;1&#93; &#58;&#61; &#123;0, 11&#125;; BoxPat&#91;2&#93; &#58;&#61; &#123;0, 11&#125;; BoxPat&#91;3&#93; &#58;&#61; &#123;0, 11&#125;; BoxPat&#91;4&#93; &#58;&#61; &#123;0, 11&#125;; &#32;&#32;BoxPat&#91;5&#93; &#58;&#61; &#123;0, 11&#125;; BoxPat&#91;6&#93; &#58;&#61; &#123;0, 11&#125;; BoxPat&#91;7&#93; &#58;&#61; &#123;0, 11&#125;; BoxPat&#91;8&#93; &#58;&#61; &#123;0, 11&#125;; &#32;&#32;BoxPat&#91;9&#93; &#58;&#61; &#123;0, 11&#125;; BoxPat&#91;10&#93; &#58;&#61; &#123;0, 11&#125;; BoxPat&#91;11&#93; &#58;&#61; &#123;0.. 11&#125;; &#32;&#32;NEW(box); &#32;&#32;box.dx &#58;&#61; 12; box.x &#58;&#61; 0; box.y &#58;&#61; -3; box.w &#58;&#61; 12; box.h &#58;&#61; 12; &#32;&#32;box.pat &#58;&#61; Display.NewPattern(12, 12, BoxPat) END TextFrames.