home *** CD-ROM | disk | FTP | other *** search
/ Amiga MA Magazine 1998 #6 / amigamamagazinepolishissue1998.iso / coders / jËzyki_programowania / oberon / system / terminalframes.mod (.txt) < prev    next >
Oberon Text  |  1977-12-31  |  18KB  |  376 lines

  1. Syntax10.Scn.Fnt
  2. Syntax10b.Scn.Fnt
  3. MODULE TerminalFrames;    (*Copyright (c) Robert Griesemer and Wolfgang Weck, 1992-95 / gri, ww, mf 30.9.93*)
  4.     IMPORT
  5.         Terminals, Oberon, MenuViewers, Viewers, Texts, TextFrames, Display, Fonts, Input;
  6.     CONST
  7.         NoCursor*=0; FadedCursor*=1; FullCursor*=2;
  8.         Left=2; Middle=1; Right=0;    Gap=2; VSpace=2 * Gap; HSpace=3 * VSpace;
  9.     TYPE
  10.         Frame*=POINTER TO FrameDesc;
  11.         FrameDesc*=RECORD(Display.FrameDesc)
  12.             text*: Terminals.Terminal;
  13.             fnt*: Fonts.Font;
  14.             cursorState*, charW*, lineH*: INTEGER;
  15.             hasSel*: BOOLEAN;
  16.             selTime*: LONGINT;
  17.             selFrom*, selTo*: Terminals.Location;
  18.         END;
  19.         UpdateMsg*=RECORD(Display.FrameMsg)
  20.             text: Terminals.Terminal;
  21.             op, fromLine, fromCol, toLine, toCol: INTEGER;
  22.             oldCur: Terminals.Location
  23.         END;
  24.     VAR w: Texts.Writer;
  25.     PROCEDURE NotifyDisplay*
  26.         (t: Terminals.Terminal; op, fromLine, fromCol, toLine, toCol: INTEGER; oldCur: Terminals.Location);
  27.         VAR msg: UpdateMsg;
  28.     BEGIN msg.text:=t; msg.op:=op;
  29.         msg.fromLine:=fromLine; msg.fromCol:=fromCol; msg.toLine:=toLine; msg.toCol:=toCol; msg.oldCur:=oldCur;
  30.         Viewers.Broadcast(msg)
  31.     END NotifyDisplay;
  32.     PROCEDURE Open*(f: Frame; h: Display.Handler; t: Terminals.Terminal; fnt: Fonts.Font);
  33.     BEGIN f.handle:=h; f.text:=t; f.cursorState:=FadedCursor; f.hasSel:=FALSE;
  34.         f.fnt:=fnt; f.charW:=fnt.maxX-fnt.minX; f.lineH:=fnt.maxY-fnt.minY+Gap
  35.     END Open;
  36.     PROCEDURE Copy*(from, to: Frame);
  37.     BEGIN Open(to, from.handle, from.text, from.fnt)
  38.     END Copy;
  39.     PROCEDURE DrawCursor(f: Frame; line, col: INTEGER; mode: INTEGER);
  40.         VAR x, y, w, h: INTEGER;
  41.     BEGIN w:=f.charW; h:=f.lineH; x:=f.X+HSpace+w * col; y:=f.Y+f.H-VSpace-h * line;
  42.         IF (x < f.X+f.W-HSpace) & (y > f.Y+VSpace) THEN
  43.             IF mode=FullCursor THEN Display.ReplConst(Display.white, x-w, y, w, h-Gap, Display.invert)
  44.             ELSIF mode=FadedCursor THEN
  45.                 Display.ReplConst(Display.white, x-w, y+1, 1, h-Gap-2, Display.invert);
  46.                 Display.ReplConst(Display.white, x-1, y+1, 1, h-Gap-2, Display.invert);
  47.                 Display.ReplConst(Display.white, x-w, y+h-Gap-1, w, 1, Display.invert);
  48.                 Display.ReplConst(Display.white, x-w, y, w, 1, Display.invert)
  49.             END
  50.         END
  51.     END DrawCursor;
  52.     PROCEDURE SetCursor*(f: Frame; state: INTEGER);
  53.         VAR loc: Terminals.Location;
  54.     BEGIN loc:=f.text.cursor; DrawCursor(f, loc.line, loc.col, f.cursorState);
  55.         f.cursorState:=state; DrawCursor(f, loc.line, loc.col, state)
  56.     END SetCursor;
  57.     PROCEDURE DrawSelection(f: Frame; fromLine, fromCol, toLine, toCol: INTEGER);
  58.         VAR x, y, w, h, top, left, right, cw, tw: INTEGER;
  59.     BEGIN top:=f.Y+f.H-VSpace; left:=f.X+HSpace; right:=f.X+f.W-HSpace; h:=f.lineH; cw:=f.charW;
  60.         y:=top-fromLine * h; x:=left+(fromCol-1) * cw;
  61.         IF fromLine=toLine THEN w:=(toCol-fromCol+1) * cw;
  62.             IF x+w > right THEN w:=right-x END;
  63.             IF w > 0 THEN Display.ReplConst(Display.white, x, y, w, h, Display.invert) END
  64.         ELSE tw:=f.text.width; w:=(tw-fromCol+2) * cw;
  65.             IF x+w > right THEN w:=right-x END;
  66.             IF w > 0 THEN Display.ReplConst(Display.white, x, y, w, h, Display.invert) END;
  67.             x:=left; w:=(tw+1) * cw;
  68.             IF x+w > right THEN w:=right-x END;
  69.             INC(fromLine);
  70.             WHILE fromLine < toLine DO INC(fromLine); y:=y-h;
  71.                 Display.ReplConst(Display.white, x, y, w, h, Display.invert)
  72.             END;
  73.             y:=y-h; w:=(toCol) * cw;
  74.             IF x+w > right THEN w:=right-x END;
  75.             Display.ReplConst(Display.white, x, y, w, h, Display.invert)
  76.         END
  77.     END DrawSelection;
  78.     PROCEDURE RemoveSelection*(f: Frame);
  79.         VAR from, to: Terminals.Location;
  80.     BEGIN
  81.         IF f.hasSel THEN from:=f.selFrom; to:=f.selTo; DrawSelection(f, from.line, from.col, to.line, to.col);
  82.             f.hasSel:=FALSE
  83.         END
  84.     END RemoveSelection;
  85.     PROCEDURE SetSelection*(f: Frame; fromLine, fromCol, toLine, toCol: INTEGER);
  86.         VAR h: INTEGER; loc: Terminals.Location;
  87.     BEGIN RemoveSelection(f); h:=f.H-2 * VSpace;
  88.         IF h < toLine * f.lineH THEN toLine:=h DIV f.lineH; toCol:=f.text.width+1 END;
  89.         IF fromCol > f.text.line[fromLine].len THEN fromCol:=f.text.line[fromLine].len+1 END;
  90.         IF toCol > f.text.line[toLine].len THEN toCol:=f.text.width+1 END;
  91.         IF (fromLine < toLine) OR ((fromLine=toLine) & (fromCol * f.charW < f.W-2 * HSpace)) THEN
  92.             DrawSelection(f, fromLine, fromCol, toLine, toCol);
  93.             loc.line:=fromLine; loc.col:=fromCol; f.selFrom:=loc;
  94.             loc.line:=toLine; loc.col:=toCol; f.selTo:=loc;
  95.             f.hasSel:=TRUE; f.selTime:=Oberon.Time()
  96.         END
  97.     END SetSelection;
  98.     PROCEDURE TextOf(f: Frame): Texts.Text;
  99.         VAR i, j, len: INTEGER; line: Terminals.Line; text: Texts.Text;
  100.     BEGIN Texts.SetFont(w, f.fnt); i:=1;
  101.         REPEAT j:=1; line:=f.text.line[i]; len:=line.len;
  102.             WHILE j <= len DO Texts.Write(w, line.ch[j].ch); INC(j) END;
  103.             Texts.WriteLn(w); INC(i)
  104.         UNTIL i > Terminals.Height;
  105.         text:=TextFrames.Text(""); Texts.Append(text, w.buf); RETURN text
  106.     END TextOf;
  107.     PROCEDURE TextPos(f: Frame; line, col: INTEGER): INTEGER;
  108.         VAR i, l, len: INTEGER; text: Terminals.Terminal;
  109.     BEGIN i:=1; len:=0; text:=f.text;
  110.         WHILE i < line DO len:=len+text.line[i].len; INC(i) END;
  111.         IF i <= Terminals.Height THEN l:=text.line[i].len ELSE l:=0 END;
  112.         IF l >= col THEN RETURN len+col+i-2 ELSE RETURN len+l+i-1 END
  113.     END TextPos;
  114.     PROCEDURE GetSelection*(f: Frame; VAR text: Texts.Text; VAR beg, end, time: LONGINT);
  115.     BEGIN
  116.         IF f.hasSel THEN time:=f.selTime; text:=TextOf(f);
  117.             beg:=TextPos(f, f.selFrom.line, f.selFrom.col); end:=TextPos(f, f.selTo.line, f.selTo.col)+1
  118.         ELSE text:=TextFrames.Text(""); time:=0; beg:=0
  119.         END
  120.     END GetSelection;
  121.     PROCEDURE Neutralize*(f: Frame);
  122.     BEGIN Oberon.RemoveMarks(f.X, f.Y, f.W, f.H); SetCursor(f, FadedCursor); RemoveSelection(f)
  123.     END Neutralize;
  124.     PROCEDURE DrawChar(f: Frame; x, y: INTEGER; char: Terminals.Char);
  125.         VAR dx, cx, cy, cw, ch: INTEGER; p: Display.Pattern; fnt: Fonts.Font;
  126.     BEGIN fnt:=f.fnt; Display.GetChar(fnt.raster, char.ch, dx, cx, cy, cw, ch, p);
  127.         Display.CopyPattern(Display.white, p, x+cx-fnt.minX, y+cy-fnt.minY, Display.replace);
  128.         IF ODD(char.attr DIV Terminals.bold) THEN
  129.             Display.CopyPattern(Display.white, p, x+cx-fnt.minX+1, y+cy-fnt.minY, Display.replace)
  130.         END;
  131.         IF ODD(char.attr DIV Terminals.reverse) OR ODD(char.attr DIV Terminals.blinking) THEN
  132.             Display.ReplConst(Display.white, x, y, f.charW, f.lineH-Gap, Display.invert)
  133.         END;
  134.         IF ODD(char.attr DIV Terminals.underline) THEN
  135.             Display.ReplConst(Display.white, x, y, f.charW, 1, Display.invert)
  136.         END
  137.     END DrawChar;
  138.     PROCEDURE UpdateLine(f: Frame; line, fromCol, toCol: INTEGER);
  139.         VAR x, y, w, h, w2: INTEGER; l: Terminals.Line; text: Terminals.Terminal;
  140.     BEGIN h:=f.lineH; y:=f.Y+f.H-VSpace-line * h;
  141.         IF y > f.Y+VSpace THEN text:=f.text;
  142.             l:=text.line[line]; w:=f.charW; x:=w * fromCol;
  143.             IF x < f.W-2 * HSpace THEN w2:=w * (toCol-fromCol);
  144.                 IF w2 > f.W-2 * HSpace-x THEN w2:=f.W-2 * HSpace-x END;
  145.                 Display.ReplConst(Display.black, f.X+HSpace+x-w, y, w+w2, h, Display.replace);
  146.                 IF toCol > l.len THEN toCol:=l.len END;
  147.                 WHILE (fromCol <= toCol) & (x < f.W-2 * HSpace) DO DrawChar(f, f.X+HSpace+x-w, y, l.ch[fromCol]);
  148.                     INC(fromCol); x:=x+w
  149.                 END
  150.             END
  151.         END
  152.     END UpdateLine;
  153.     PROCEDURE UpdateScrolling(f: Frame; top, bot, dH: INTEGER);
  154.         VAR y, lh, h, diff, w: INTEGER;
  155.     BEGIN lh:=f.lineH; y:=f.Y+f.H-VSpace-bot * lh; diff:=(f.Y+VSpace-y+lh) DIV lh;
  156.         IF diff < 0 THEN diff:=0 END;
  157.         y:=y+diff * lh; h:=(bot-diff-top-ABS(dH)+1) * lh;
  158.         IF dH < 0 THEN dH:=-dH;
  159.             IF h > 0 THEN Display.CopyBlock(f.X, y, f.W, h, f.X, y+dH * lh, Display.replace) END;
  160.             top:=bot-diff-dH+1; w:=f.text.width;
  161.             IF top < 1 THEN top:=1 END;
  162.             WHILE top <= bot DO UpdateLine(f, top, 1, w); INC(top) END
  163.         ELSE
  164.             IF h > 0 THEN Display.CopyBlock(f.X, y+dH * lh, f.W, h, f.X, y, Display.replace) END;
  165.             y:=f.Y+f.H-VSpace-(top+dH-1) * lh; h:=dH * lh;
  166.             IF y < f.Y+VSpace THEN h:=h-f.Y-VSpace+y; y:=f.Y+VSpace END;
  167.             IF h > 0 THEN Display.ReplConst(Display.black, f.X, y, f.W, h, Display.replace) END
  168.         END
  169.     END UpdateScrolling;
  170.     PROCEDURE Update*(f: Frame; op, fromLine, fromCol, toLine, toCol: INTEGER; oldCur: Terminals.Location);
  171.         VAR cursor: Terminals.Location;
  172.     BEGIN Oberon.RemoveMarks(f.X, f.Y, f.W, f.H); RemoveSelection(f); cursor:=f.text.cursor;
  173.         IF op=Terminals.update THEN DrawCursor(f, oldCur.line, oldCur.col, f.cursorState);
  174.             IF fromLine=toLine THEN UpdateLine(f, fromLine, fromCol, toCol)
  175.             ELSE UpdateLine(f, fromLine, fromCol, Terminals.MaxWidth);
  176.                 INC(fromLine);
  177.                 WHILE fromLine < toLine DO UpdateLine(f, fromLine, 1, Terminals.MaxWidth); INC(fromLine) END;
  178.                 UpdateLine(f, toLine, 1, toCol)
  179.             END;
  180.             DrawCursor(f, cursor.line, cursor.col, f.cursorState)
  181.         ELSIF op=Terminals.moveCursor THEN
  182.             DrawCursor(f, oldCur.line, oldCur.col, f.cursorState); DrawCursor(f, cursor.line, cursor.col, f.cursorState)
  183.         ELSIF op=Terminals.scroll THEN DrawCursor(f, cursor.line, cursor.col, f.cursorState);
  184.             UpdateScrolling(f, fromLine, toLine, fromCol); DrawCursor(f, cursor.line, cursor.col, f.cursorState)
  185.         END
  186.     END Update;
  187.     PROCEDURE ConsumeKey(t: Terminals.Terminal; ch: CHAR);
  188.     BEGIN
  189.         IF ch=80X THEN Terminals.Send(t, 81X)
  190.         ELSIF ch=85X THEN Terminals.Send(t, 8FX)
  191.         ELSIF ch=82X THEN Terminals.Send(t, 95X)
  192.         ELSIF ch=83X THEN Terminals.Send(t, 01X)
  193.         ELSIF ch=84X THEN Terminals.Send(t, 0FX)
  194.         ELSIF ch=85X THEN Terminals.Send(t, 15X)
  195.         ELSE Terminals.Send(t, ch)
  196.         END
  197.     END ConsumeKey;
  198.     PROCEDURE TrackSelection*(f: Frame; VAR keySum: SET; x, y: INTEGER);
  199.         VAR keys: SET; top, bot, h, left, w, len, tw: INTEGER; from, to, oldTo: Terminals.Location;
  200.     BEGIN top:=f.Y+f.H-VSpace; h:=f.lineH; tw:=f.text.width;
  201.         IF Terminals.Height * h > top-f.Y-VSpace THEN bot:=top-((top-f.Y-VSpace) DIV h) * h
  202.         ELSE bot:=top-Terminals.Height * h
  203.         END;
  204.         left:=f.X+HSpace; w:=f.charW;
  205.         IF x < left THEN x:=left END;
  206.         IF (bot < y) & (y < top) THEN from.line:=(top-y) DIV h+1; from.col:=(x-left) DIV w+1;
  207.             len:=f.text.line[from.line].len;
  208.             IF from.col < 1 THEN from.col:=1 ELSIF from.col > len THEN from.col:=len+1 END;
  209.             oldTo:=from;
  210.             IF oldTo.col > len THEN oldTo.col :=tw+1 END;
  211.             IF f.hasSel THEN
  212.                 IF (f.selFrom.line=f.selTo.line)
  213.                     & ((f.selFrom.col=f.selTo.col) OR (f.selFrom.col=f.text.line[f.selFrom.line].len+1))
  214.                     & (f.selFrom.line=from.line) & (f.selFrom.col=from.col)
  215.                 THEN from.col:=1
  216.                 END;
  217.                 RemoveSelection(f)
  218.             END;
  219.             DrawSelection(f, from.line, from.col, oldTo.line, oldTo.col);
  220.             REPEAT Input.Mouse(keys, x, y); keySum:=keySum+keys;
  221.                 Oberon.DrawCursor(Oberon.Mouse, Oberon.Arrow, x, y);
  222.                 IF x < left THEN x:=left END;
  223.                 IF y <= bot THEN y:=bot+1 ELSIF y > top THEN y:=top END;
  224.                 to.line:=(top-y) DIV h+1; to.col:=(x-left) DIV w+1;
  225.                 IF (to.line < from.line) OR ((to.line=from.line) & (to.col < from.col)) THEN to:=from;
  226.                 END;
  227.                 IF to.col > f.text.line[to.line].len THEN to.col:=tw+1 END;
  228.                 IF (to.line > oldTo.line) OR ((to.line=oldTo.line) & (to.col > oldTo.col)) THEN
  229.                     DrawSelection(f, oldTo.line, oldTo.col, oldTo.line, oldTo.col);
  230.                     DrawSelection(f, oldTo.line, oldTo.col, to.line, to.col)
  231.                 ELSIF (to.line < oldTo.line) OR ((to.line=oldTo.line) & (to.col < oldTo.col)) THEN
  232.                     DrawSelection(f, to.line, to.col, oldTo.line, oldTo.col);
  233.                     DrawSelection(f, to.line, to.col, to.line, to.col)
  234.                 END;
  235.                 oldTo:=to
  236.             UNTIL keys={};
  237.             f.selFrom:=from; f.selTo:=to; f.hasSel:=TRUE; f.selTime:=Oberon.Time()
  238.         ELSE Oberon.DrawCursor(Oberon.Mouse, Oberon.Arrow, x, y)
  239.         END
  240.     END TrackSelection;
  241.     PROCEDURE Call*(f: Frame; cmdLine, cmdCol: INTEGER; new: BOOLEAN);
  242.         VAR i, len: INTEGER; t: Texts.Text; line: Terminals.Line; ch: CHAR;
  243.             name: ARRAY Terminals.MaxWidth OF CHAR;
  244.     BEGIN
  245.         IF cmdCol > 0 THEN i:=0; line:=f.text.line[cmdLine]; len:=line.len; ch:=line.ch[cmdCol].ch;
  246.             WHILE (cmdCol < len) & (ch > " ") DO name[i]:=ch; INC(i); INC(cmdCol); ch:=line.ch[cmdCol].ch END;
  247.             IF ch > " " THEN name[i]:=ch; INC(i); cmdCol:=0; INC(cmdLine) END;
  248.             name[i]:=0X;
  249.             Oberon.Par.text:=TextOf(f); Oberon.Par.pos:=TextPos(f, cmdLine, cmdCol);
  250.             Oberon.Par.vwr:=MenuViewers.Ancestor; Oberon.Par.frame:=f;
  251.             Oberon.Call(name, Oberon.Par, new, i)
  252.         END
  253.     END Call;
  254.     PROCEDURE DrawLine(f: Frame; from: Terminals.Location);
  255.         VAR line: Terminals.Line; x1, x2, y, tocol, len: INTEGER;
  256.     BEGIN
  257.         IF from.col > 0 THEN line:=f.text.line[from.line]; len:=line.len; tocol:=from.col;
  258.             WHILE (tocol < len) & (line.ch[tocol+1].ch > " ") DO INC(tocol) END;
  259.             y:=f.Y+f.H-VSpace-from.line * f.lineH-1;
  260.             x1:=f.X+HSpace+(from.col-1) * f.charW; x2:=f.X+HSpace+tocol * f.charW;
  261.             IF x2 > f.X+f.W-HSpace THEN x2:=f.X+f.W-HSpace END;
  262.             Display.ReplConst(Display.white, x1, y, x2-x1, 2, Display.invert)
  263.         END
  264.     END DrawLine;
  265.     PROCEDURE TrackWord*(f: Frame; x, y: INTEGER; VAR cmdLine, cmdCol: INTEGER; VAR keySum: SET);
  266.         VAR keys: SET; top, bot, h, left, w, len: INTEGER; pos, oldPos: Terminals.Location; line: Terminals.Line;
  267.     BEGIN top:=f.Y+f.H-VSpace; h:=f.lineH;
  268.         IF Terminals.Height * h > top-f.Y-VSpace THEN bot:=top-((top-f.Y-VSpace) DIV h) * h
  269.         ELSE bot:=top-Terminals.Height * h
  270.         END;
  271.         left:=f.X+HSpace; w:=f.charW; oldPos.line:=0; oldPos.col:=0;
  272.         REPEAT Input.Mouse(keys, x, y); keySum:=keySum+keys;
  273.             Oberon.DrawCursor(Oberon.Mouse, Oberon.Arrow, x, y);
  274.             IF x < left THEN x:=left END;
  275.             IF (y <= bot) OR (y > top) THEN pos.line:=0; pos.col:=0
  276.             ELSE pos.line:=(top-y) DIV h+1; line:=f.text.line[pos.line];
  277.                 pos.col:=(x-left) DIV w+1; len:=line.len;
  278.                 IF pos.col > len THEN pos.col:=len END;
  279.                 WHILE (pos.col > 0) & (line.ch[pos.col].ch <= " ") DO DEC(pos.col) END;
  280.                 WHILE (pos.col > 1) & (line.ch[pos.col-1].ch > " ") DO DEC(pos.col) END;
  281.                 IF pos.col=0 THEN pos.line:=0 END
  282.             END;
  283.             IF (pos.line # oldPos.line) OR (pos.col # oldPos.col) THEN
  284.                 DrawLine(f, oldPos); DrawLine(f, pos); oldPos:=pos
  285.             END
  286.         UNTIL keys={};
  287.         DrawLine(f, pos);
  288.         cmdLine:=pos.line; cmdCol:=pos.col
  289.     END TrackWord;
  290.     PROCEDURE Edit*(f: Frame; keys: SET; x, y: INTEGER);
  291.         VAR keySum: SET; text: Texts.Text; beg, end, time: LONGINT; cmdLine, cmdCol: INTEGER;
  292.             msg: Oberon.CopyOverMsg;
  293.     BEGIN
  294.         IF Left IN keys THEN keySum:=keys;
  295.             Oberon.PassFocus(MenuViewers.Ancestor); SetCursor(f, FullCursor);
  296.             REPEAT Oberon.DrawCursor(Oberon.Mouse, Oberon.Arrow, x, y);
  297.                 Input.Mouse(keys, x, y); keySum:=keySum+keys
  298.             UNTIL keys={};
  299.             IF keySum={Left, Middle} THEN Oberon.GetSelection(text, beg, end, time);
  300.                 IF time > 0 THEN Terminals.SendText(f.text, text, beg, end) END
  301.             END
  302.         ELSIF Middle IN keys THEN TrackWord(f, x, y, cmdLine, cmdCol, keys);
  303.             IF ~(Right IN keys) THEN Call(f, cmdLine, cmdCol, Left IN keys) END
  304.         ELSIF Right IN keys THEN TrackSelection(f, keys, x, y);
  305.             IF keys={Middle, Right} THEN GetSelection(f, msg.text, msg.beg, msg.end, time);
  306.                 Oberon.FocusViewer.handle(Oberon.FocusViewer, msg)
  307.             END
  308.         ELSE Oberon.DrawCursor(Oberon.Mouse, Oberon.Arrow, x, y)
  309.         END
  310.     END Edit;
  311.     PROCEDURE Modify*(f: Frame; id, Y, H, dY: INTEGER);
  312.         VAR y, h, l1, l2, w: INTEGER; cursor: Terminals.Location;
  313.     BEGIN Neutralize(f); cursor:=f.text.cursor; DrawCursor(f, cursor.line, cursor.col, f.cursorState);
  314.         IF H < 2 * VSpace THEN f.Y:=Y; f.H:=H; Display.ReplConst(Display.black, f.X, Y, f.W, H, Display.replace)
  315.         ELSIF id=MenuViewers.reduce THEN h:=((H-2 * VSpace-1) DIV f.lineH) * f.lineH;
  316.             IF h < 0 THEN h:=0 END;
  317.             y:=f.Y+f.H-VSpace-h;
  318.             IF dY # 0 THEN Display.CopyBlock(f.X, y, f.W, h+VSpace, f.X, y-dY, Display.replace) END;
  319.             IF H-h-VSpace > 0 THEN Display.ReplConst(Display.black, f.X, Y, f.W, H-h-VSpace, Display.replace) END;
  320.             f.Y:=Y; f.H:=H
  321.         ELSE l1:=(f.H-2 * VSpace-1) DIV f.lineH;
  322.             IF l1 < 0 THEN l1:=0 END;
  323.             h:=l1 * f.lineH; y:=f.Y+f.H-VSpace-h;
  324.             IF (dY # 0) & (h > 0) THEN Display.CopyBlock(f.X, y, f.W, h+VSpace, f.X, y+dY, Display.replace) END;
  325.             Display.ReplConst(Display.black, f.X, Y+H-VSpace, f.W, VSpace, Display.replace);
  326.             IF H-h-VSpace > 0 THEN Display.ReplConst(Display.black, f.X, Y, f.W, H-h-VSpace, Display.replace) END;
  327.             w:=f.text.width; l2:=(H-2 * VSpace-1) DIV f.lineH;
  328.             f.Y:=Y; f.H:=H;
  329.             IF l2 > Terminals.Height THEN l2:=Terminals.Height END;
  330.             WHILE l1 < l2 DO INC(l1); UpdateLine(f, l1, 1, w) END
  331.         END;
  332.         DrawCursor(f, cursor.line, cursor.col, f.cursorState)
  333.     END Modify;
  334.     PROCEDURE Handle*(f: Display.Frame; VAR m: Display.FrameMsg);
  335.         VAR nF: Frame;
  336.     BEGIN
  337.         WITH f: Frame DO
  338.             IF m IS UpdateMsg THEN
  339.                 WITH m: UpdateMsg DO
  340.                     IF m.text=f.text THEN Update(f, m.op, m.fromLine, m.fromCol, m.toLine, m.toCol, m.oldCur) END
  341.                 END
  342.             ELSIF m IS Oberon.CopyMsg THEN
  343.                 WITH m: Oberon.CopyMsg DO
  344.                     IF (m.F # NIL) & (m.F IS Frame) THEN nF:=m.F(Frame) ELSE NEW(nF); m.F:=nF END;
  345.                     Copy(f, nF)
  346.                 END
  347.             ELSIF m IS MenuViewers.ModifyMsg THEN
  348.                 WITH m: MenuViewers.ModifyMsg DO Modify(f, m.id, m.Y, m.H, m.dY) END
  349.             ELSIF m IS Oberon.InputMsg THEN
  350.                 WITH  m: Oberon.InputMsg DO
  351.                     IF m.id=Oberon.track THEN Edit(f, m.keys, m.X, m.Y)
  352.                     ELSIF (m.id=Oberon.consume) & (f.cursorState=FullCursor) THEN ConsumeKey(f.text, m.ch)
  353.                     END
  354.                 END
  355.             ELSIF m IS Oberon.ControlMsg THEN
  356.                 WITH m: Oberon.ControlMsg DO
  357.                     IF m.id=Oberon.neutralize THEN Neutralize(f)
  358.                     ELSIF m.id=Oberon.defocus THEN SetCursor(f, FadedCursor)
  359.                     END
  360.                 END
  361.             ELSIF (m IS Oberon.CopyOverMsg) & (f.cursorState=FullCursor) THEN
  362.                 WITH m: Oberon.CopyOverMsg DO Terminals.SendText(f.text, m.text, m.beg, m.end) END
  363.             ELSIF m IS Oberon.SelectionMsg THEN
  364.                 WITH m: Oberon.SelectionMsg DO
  365.                     IF f.hasSel & (m.time < f.selTime) THEN GetSelection(f, m.text, m.beg, m.end, m.time) END
  366.                 END
  367.             END
  368.         END
  369.     END Handle;
  370.     PROCEDURE New*(t: Terminals.Terminal): Frame;
  371.         VAR f: Frame;
  372.     BEGIN NEW(f); Open(f, Handle, t, Fonts.This("Courier10.Scn.Fnt")); RETURN f
  373.     END New;
  374. BEGIN Texts.OpenWriter(w)
  375. END TerminalFrames.
  376.