MODULE WMVT100;
IMPORT WMWindowManager, WMComponents, WMStandardComponents, WMGraphics, WMPopups,
Strings, Texts, Inputs, Streams, Commands, IP, DNS, TCP, Telnet, KernelLog;
CONST
Border = 2; BoxW = 8; BoxH = 18;
Left = 0; Right = 2;
Underscore = 0; Blink = 1;
CursorKeyMode = 0; AppKeypadMode = 1; AutoWrapMode = 2; WindowSize = 31;
TYPE
Connection = OBJECT (Telnet.Connection)
VAR frame: Frame; mode: SET;
PROCEDURE Do(option: CHAR);
BEGIN
IF option = Telnet.OptTerminalType THEN
W.Char(Telnet.CmdIAC); W.Char(Telnet.CmdWILL); W.Char(Telnet.OptTerminalType)
ELSIF option = Telnet.OptWindowSize THEN
ASSERT((frame.cols < 255) & (frame.rows < 255));
INCL(mode, WindowSize);
W.Char(Telnet.CmdIAC); W.Char(Telnet.CmdSB);
W.Char(Telnet.OptWindowSize);
W.Char(CHR(frame.cols DIV 256));
W.Char(CHR(frame.cols MOD 256));
W.Char(CHR(frame.rows DIV 256));
W.Char(CHR(frame.rows MOD 256));
W.Char(Telnet.CmdIAC); W.Char(Telnet.CmdSE)
ELSE
Do^(option)
END
END Do;
PROCEDURE SB(option: CHAR);
VAR ch: CHAR;
BEGIN
IF (option = Telnet.OptTerminalType) & (R.Peek() = 01X) THEN
INCL(flags, Telnet.VT100);
R.Char(ch);
R.Char(ch); ASSERT(ch = Telnet.CmdIAC);
R.Char(ch); ASSERT(ch = Telnet.CmdSE);
W.Char(Telnet.CmdIAC); W.Char(Telnet.CmdSB);
W.Char(Telnet.OptTerminalType);
W.Char(0X);
W.String("VT100");
W.Char(Telnet.CmdIAC); W.Char(Telnet.CmdSE)
ELSE
SB^(option)
END
END SB;
PROCEDURE ESC(ch: CHAR);
VAR par: ARRAY 4 OF LONGINT; i, n: LONGINT;
done: BOOLEAN;
BEGIN
IF ~(Telnet.VT100 IN flags) THEN RETURN END;
R.Char(ch);
IF ch = "[" THEN
ch := R.Peek(); n := 0;
IF ch = "?" THEN
R.Char(ch); ch := R.Peek();
IF (ch >= "0") & (ch <= "9") THEN
REPEAT
R.Int(par[n], FALSE); INC(n); R.Char(ch)
UNTIL (n >= 4) OR (ch # " ")
END
ELSIF (ch >= "0") & (ch <= "9") THEN
REPEAT
R.Int(par[n], FALSE); INC(n); R.Char(ch)
UNTIL (n >= 4) OR (ch # ";")
ELSE
ASSERT(ch < 07FX);
R.Char(ch)
END;
done := FALSE;
CASE ch OF
"A": IF n = 1 THEN
frame.Goto(frame.GetCol(), frame.GetRow()-par[0], TRUE)
;done := TRUE
ELSE
frame.Goto(frame.GetCol(), frame.GetRow()-1, TRUE)
;done := n = 0
END
;done := n = 0
|"B": IF n = 1 THEN
frame.Goto(frame.GetCol(), frame.GetRow()+par[0], TRUE)
;done := TRUE
ELSE
frame.Goto(frame.GetCol(), frame.GetRow()+1, TRUE)
;done := n = 0
END
|"C": IF n = 1 THEN
frame.Goto(frame.GetCol()+par[0], frame.GetRow(), FALSE)
;done := TRUE
ELSE
frame.Goto(frame.GetCol()+1, frame.GetRow(), FALSE)
;done := n = 0
END
|"D": IF n = 1 THEN
frame.Goto(frame.GetCol()-par[0], frame.GetRow(), FALSE)
;done := TRUE
ELSE
frame.Goto(frame.GetCol()-1, frame.GetRow(), FALSE)
;done := n = 0
END
|"H": IF n = 2 THEN
frame.Goto(par[1]-1, par[0]-1, FALSE)
;done := TRUE
ELSE
frame.Goto(0, 0, FALSE)
;done := n = 0
END
|"J", "K": frame.Erase(ch, par, n)
;done := TRUE
|"h": IF n = 1 THEN
IF par[0] = 1 THEN
INCL(mode, CursorKeyMode)
;done := TRUE
ELSIF par[0] = 7 THEN
INCL(mode, AutoWrapMode)
;done := TRUE
END
END
|"l": IF n = 1 THEN
IF par[0] = 1 THEN
EXCL(mode, CursorKeyMode)
;done := TRUE
ELSIF par[0] = 7 THEN
EXCL(mode, AutoWrapMode)
;done := TRUE
END
END
|"m": frame.SetAttributes(par, n)
;done := TRUE
ELSE
END
; IF ~done THEN
KernelLog.String("ESC [ ");
i := 0;
WHILE i < n DO
KernelLog.Int(par[i], 0); INC(i);
IF i < n THEN KernelLog.String(" ; ") END
END;
KernelLog.String(" "); KernelLog.Char(ch);
KernelLog.String(" "); KernelLog.Ln()
END
ELSE
CASE ch OF
"=": INCL(mode, AppKeypadMode)
|">": EXCL(mode, AppKeypadMode)
|"D": frame.SetTop(frame.GetRow()+1)
|"M": frame.SetTop(frame.GetRow()-1)
ELSE
KernelLog.String("ESC "); KernelLog.Hex(ORD(ch), 0); KernelLog.Ln()
END
END
END ESC;
PROCEDURE Consume(ch: CHAR);
VAR buf: ARRAY 128 OF LONGINT; i, n: LONGINT;
BEGIN
CASE ch OF
0X:
|07X:
|08X: frame.Goto(frame.GetCol()-1, frame.GetRow(), FALSE)
|09X: frame.RightTab()
|0AX, 0BX, 0CX: frame.Goto(frame.GetCol(), frame.GetRow()+1, TRUE)
|0DX: IF R.Peek() = 0AX THEN
R.Char(ch); frame.Goto(0, frame.GetRow()+1, TRUE)
ELSE
frame.Goto(0, frame.GetRow(), FALSE)
END
|01BX: ESC(ch)
|07FX: frame.Delete()
ELSE
buf[0] := ORD(ch); i := 1; n := R.Available();
IF n > 0 THEN
IF n > 127 THEN n := 127 END; ch := R.Peek();
WHILE (n > 0) & (ch >= 020X) & (ch <= 07EX) DO
R.Char(ch); DEC(n);
buf[i] := ORD(ch); INC(i);
IF n > 0 THEN ch := R.Peek() END
END
END;
frame.WriteChars(buf, i)
END
END Consume;
PROCEDURE &Init*(C: Streams.Connection);
BEGIN
Init^(C); INCL(flags, Telnet.Telnet);
mode := {}; frame := NIL
END Init;
PROCEDURE SetFrame(frame: Frame);
BEGIN {EXCLUSIVE}
SELF.frame := frame
END SetFrame;
PROCEDURE Setup;
BEGIN {EXCLUSIVE}
AWAIT(frame # NIL);
IF Telnet.Telnet IN flags THEN
W.Char(Telnet.CmdIAC); W.Char(Telnet.CmdDO); W.Char(Telnet.OptSupGoAhead);
W.Char(Telnet.CmdIAC); W.Char(Telnet.CmdDO); W.Char(Telnet.OptEcho);
W.Char(Telnet.CmdIAC); W.Char(Telnet.CmdWILL); W.Char(Telnet.OptTerminalType);
W.Char(Telnet.CmdIAC); W.Char(Telnet.CmdWILL); W.Char(Telnet.OptWindowSize);
W.Update()
END
END Setup;
END Connection;
Attribute = POINTER TO RECORD
fnt: WMGraphics.Font;
bg, fg: LONGINT;
special: SET
END;
Char = RECORD
attr: Attribute;
char: LONGINT
END;
Data = POINTER TO ARRAY OF Char;
Line = POINTER TO RECORD
data: Data;
t, b: LONGINT;
next: Line
END;
Position = RECORD
line: Line; ofs: LONGINT
END;
Frame = OBJECT (WMComponents.VisualComponent)
VAR
C: Connection;
first, last, top: Line; bg: LONGINT;
rows, cols, boxW, boxH, dX, dY: LONGINT;
tabs: POINTER TO ARRAY OF BOOLEAN;
attr: Attribute; cursor: Position;
sel: RECORD beg, end: Position END;
popup: WMPopups.Popup;
PROCEDURE GetCol(): LONGINT;
BEGIN {EXCLUSIVE}
RETURN cursor.ofs
END GetCol;
PROCEDURE GetRow(): LONGINT;
VAR l: Line; row: LONGINT;
BEGIN {EXCLUSIVE}
l := top; row := 0;
WHILE l # cursor.line DO
l := l.next; INC(row)
END;
RETURN row
END GetRow;
PROCEDURE appendLine(): Line;
VAR line: Line; i: LONGINT; ch: Char;
BEGIN
NEW(line); line.next := NIL;
NEW(line.data, cols);
ch.attr := attr; ch.char := 0;
i := 0;
WHILE i < cols DO
line.data[i] := ch; INC(i)
END;
IF last # NIL THEN
last.next := line; line.t := last.b
ELSE
line.t := dY
END;
last := line; line.b := line.t + boxH;
RETURN line
END appendLine;
PROCEDURE AppendLine(): Line;
BEGIN {EXCLUSIVE}
RETURN appendLine()
END AppendLine;
PROCEDURE UpdateBox(line: Line; ofs: LONGINT);
VAR update: WMGraphics.Rectangle;
BEGIN
update.l := dX + ofs*boxW; update.r := update.l + boxW;
update.t := line.t; update.b := line.b;
InvalidateRect(update)
END UpdateBox;
PROCEDURE UpdateRect(al, bl: Line; aofs, bofs: LONGINT; cur: SET);
VAR tl: Line; tofs: LONGINT; update: WMGraphics.Rectangle; swapl, swapo: BOOLEAN;
BEGIN
swapl := FALSE; swapo := FALSE;
IF al # bl THEN
tl := al;
WHILE (tl # NIL) & (tl # bl) DO
tl := tl.next
END;
IF tl = NIL THEN swapl := TRUE; tl := al; al := bl; bl := tl END
END;
IF aofs > bofs THEN swapo := TRUE; tofs := aofs; aofs := bofs; bofs := tofs END;
update.l := dX + aofs*boxW; update.r := dX + bofs*boxW + boxW;
update.t := al.t; update.b := bl.b;
IF cur # {} THEN
IF 1 IN cur THEN
IF swapl THEN cursor.line := bl ELSE cursor.line := al END
ELSIF 2 IN cur THEN
IF swapl THEN cursor.line := al ELSE cursor.line := bl END
END;
IF 3 IN cur THEN
IF swapo THEN cursor.ofs := bofs ELSE cursor.ofs := aofs END
ELSIF 4 IN cur THEN
IF swapo THEN cursor.ofs := aofs ELSE cursor.ofs := bofs END
END
END;
InvalidateRect(update)
END UpdateRect;
PROCEDURE UpdateAll;
VAR update: WMGraphics.Rectangle;
BEGIN
update.l := 0; update.r := bounds.GetWidth();
update.t := 0; update.b := bounds.GetHeight();
InvalidateRect(update)
END UpdateAll;
PROCEDURE WriteChars(VAR buf: ARRAY OF LONGINT; n: LONGINT);
VAR l: Line; i, ofs: LONGINT; wrap: BOOLEAN;
BEGIN {EXCLUSIVE}
wrap := FALSE;
l := cursor.line; ofs := cursor.ofs; i := 0;
LOOP
WHILE (i < n) & (ofs < cols) DO
l.data[ofs].attr := attr; l.data[ofs].char := buf[i];
INC(ofs); INC(i)
END;
IF (i < n) & (AutoWrapMode IN C.mode) THEN
l := l.next; ofs := 0; wrap := TRUE;
IF l = NIL THEN l := appendLine() END
ELSE
EXIT
END
END;
IF wrap THEN
cursor.ofs := ofs;
UpdateRect(cursor.line, l, 0, cols-1, {2})
ELSE
UpdateRect(cursor.line, l, cursor.ofs, ofs, {4})
END
END WriteChars;
PROCEDURE Delete;
VAR l: Line; ofs: LONGINT;
BEGIN {EXCLUSIVE}
l := cursor.line; ofs := cursor.ofs;
IF ofs > 0 THEN
DEC(ofs); l.data[ofs].attr := attr; l.data[ofs].char := 0;
UpdateRect(l, l, ofs, cursor.ofs, {3})
END
END Delete;
PROCEDURE Goto(col, row: LONGINT; scroll: BOOLEAN);
VAR l: Line; y, b: LONGINT;
BEGIN {EXCLUSIVE}
ASSERT(row >= 0);
IF col < 0 THEN col := 0 ELSIF col >= cols THEN col := cols-1 END;
y := dY + boxH; b := dY + rows*boxH; l := top;
WHILE row > 0 DO
l := l.next; DEC(row); INC(y, boxH);
IF l = NIL THEN l := appendLine() END
END;
IF scroll & (y > b) & (top.next # NIL) THEN
top := top.next; cursor.line := l; cursor.ofs := col;
UpdateAll()
ELSE
UpdateRect(cursor.line, l, cursor.ofs, col, {2, 4})
END
END Goto;
PROCEDURE SetTop(row: LONGINT);
BEGIN {EXCLUSIVE}
KernelLog.String("SetTop "); KernelLog.Int(row, 0); KernelLog.Ln();
IF row < 0 THEN
ELSIF row > 0 THEN
END
END SetTop;
PROCEDURE RightTab;
VAR l: Line; ofs: LONGINT; char: Char;
BEGIN {EXCLUSIVE}
char.attr := attr; char.char := 020H;
l := cursor.line; ofs := cursor.ofs+1;
WHILE (ofs < cols) & ~tabs[ofs] DO
l.data[ofs] := char; INC(ofs)
END;
IF ofs = cursor.ofs THEN RETURN END;
UpdateRect(l, l, cursor.ofs, ofs, {4})
END RightTab;
PROCEDURE EraseLine(l: Line; from, to: LONGINT);
VAR i: LONGINT;
BEGIN
i := from;
WHILE i <= to DO
l.data[i].attr := attr; l.data[i].char := 0;
INC(i)
END
END EraseLine;
PROCEDURE Erase(mode: CHAR; par: ARRAY OF LONGINT; n: LONGINT);
BEGIN {EXCLUSIVE}
CASE mode OF
"J": sel.beg.line := NIL; cursor.line := last; cursor.ofs := 0;
top := last; EraseLine(top, 0, cols-1);
UpdateAll()
|"K": IF n = 0 THEN
EraseLine(cursor.line, cursor.ofs, cols-1);
UpdateRect(cursor.line, cursor.line, cursor.ofs, cols-1, {})
ELSIF (n = 1) & (par[0] = 1) THEN
EraseLine(cursor.line, 0, cursor.ofs);
UpdateRect(cursor.line, cursor.line, 0, cursor.ofs, {})
ELSIF (n = 1) & (par[0] = 2) THEN
EraseLine(cursor.line, 0, cols-1);
UpdateRect(cursor.line, cursor.line, 0, cols-1, {})
END
END
END Erase;
PROCEDURE NewAttr;
BEGIN
NEW(attr); attr.special := {};
attr.fnt := WMGraphics.GetFont("Courier", 10, {});
attr.bg := WMGraphics.RGBAToColor(255, 255, 255, 255);
attr.fg := WMGraphics.RGBAToColor(0, 0, 0, 255)
END NewAttr;
PROCEDURE Bright;
VAR style: SET;
BEGIN
style := attr.fnt.style;
IF ~(WMGraphics.FontBold IN style) THEN
INCL(style, WMGraphics.FontBold);
attr.fnt := WMGraphics.GetFont(attr.fnt.name, attr.fnt.size, style)
ELSE
KernelLog.String("Bright"); KernelLog.Ln()
END
END Bright;
PROCEDURE Dim;
VAR style: SET;
BEGIN
style := attr.fnt.style;
IF WMGraphics.FontBold IN style THEN
EXCL(style, WMGraphics.FontBold);
attr.fnt := WMGraphics.GetFont(attr.fnt.name, attr.fnt.size, style)
ELSE
KernelLog.String("Dim"); KernelLog.Ln()
END
END Dim;
PROCEDURE SetAttributes(attrs: ARRAY OF LONGINT; n: LONGINT);
VAR c, i: LONGINT;
BEGIN {EXCLUSIVE}
NewAttr();
i := 0;
WHILE i < n DO
CASE attrs[i] OF
0: NewAttr()
|1: Bright()
|2: Dim()
|4: INCL(attr.special, Underscore)
|5: INCL(attr.special, Blink )
|7: c := attr.bg; attr.bg := attr.fg; attr.fg := c
|8: attr.fg := attr.bg
ELSE
KernelLog.String("attr "); KernelLog.Int(attrs[i], 0); KernelLog.Ln()
END;
INC(i)
END
END SetAttributes;
PROCEDURE Draw(canvas: WMGraphics.Canvas);
VAR l: Line; i, j, dy, bottom: LONGINT; attr: Attribute; char: Char; box: WMGraphics.Rectangle;
BEGIN {EXCLUSIVE}
canvas.Fill(canvas.clipRect, bg, WMGraphics.ModeCopy);
l := first;
WHILE l # top DO
l.t := MIN(INTEGER); l.b := MIN(INTEGER); l := l.next
END;
attr := NIL; bottom := dY + rows*boxH;
box.t := dY; box.b := dY + boxH; j := 0;
WHILE (l # NIL) & (j < rows) & (box.b <= bottom) DO
l.t := box.t; l.b := box.b;
box.l := dX; box.r := dX + boxW; i := 0;
WHILE i < cols DO
char := l.data[i];
IF char.attr # attr THEN
attr := char.attr;
canvas.SetColor(attr.fg);
canvas.SetFont(attr.fnt);
dy := attr.fnt.GetDescent()
END;
IF attr.bg # bg THEN
canvas.Fill(box, attr.bg, WMGraphics.ModeCopy)
END;
IF char.char # 0 THEN
attr.fnt.RenderChar(canvas, box.l, box.b-dy, char.char)
END;
IF Underscore IN attr.special THEN
canvas.Line(box.l, box.b-dy+1, box.r-1, box.b-dy+1, attr.fg, WMGraphics.ModeCopy)
END;
INC(i); INC(box.l, boxW); INC(box.r, boxW)
END;
INC(j); l := l.next;
INC(box.t, boxH); INC(box.b, boxH)
END;
WHILE l # NIL DO
l.t := MAX(INTEGER); l.b := MAX(INTEGER); l := l.next
END;
IF hasFocus & (cursor.ofs >= 0) & (cursor.ofs < cols) THEN
l := cursor.line; box.t := l.t; box.b := l.b;
IF box.t < box.b THEN
box.l := dX + cursor.ofs*boxW; box.r := box.l + boxW;
canvas.Fill(box, WMGraphics.RGBAToColor(255, 0, 0, 192), WMGraphics.ModeSrcOverDst)
ELSE
FocusLost
END
END;
IF sel.beg.line # NIL THEN
IF sel.beg.line = sel.end.line THEN
box.l := dX + sel.beg.ofs * boxW; box.r := dX + sel.end.ofs * boxW + boxW;
box.t := sel.beg.line.t; box.b := sel.end.line.b;
canvas.Fill(box, WMGraphics.RGBAToColor(0, 0, 255, 32), WMGraphics.ModeSrcOverDst)
ELSE
box.l := dX + sel.beg.ofs * boxW; box.r := dX + cols * boxW;
box.t := sel.beg.line.t; box.b := sel.beg.line.b;
canvas.Fill(box, WMGraphics.RGBAToColor(0, 0, 255, 32), WMGraphics.ModeSrcOverDst);
l := sel.beg.line.next;
WHILE l # sel.end.line DO
box.l := dX; box.r := dX + cols * boxW;
box.t := l.t; box.b := l.b;
canvas.Fill(box, WMGraphics.RGBAToColor(0, 0, 255, 32), WMGraphics.ModeSrcOverDst);
l := l.next
END;
box.l := dX; box.r := dX + sel.end.ofs * boxW + boxW;
box.t := sel.end.line.t; box.b := sel.end.line.b;
canvas.Fill(box, WMGraphics.RGBAToColor(0, 0, 255, 32), WMGraphics.ModeSrcOverDst)
END
END
END Draw;
PROCEDURE FocusReceived;
BEGIN
FocusReceived^();
UpdateBox(cursor.line, cursor.ofs)
END FocusReceived;
PROCEDURE FocusLost;
BEGIN
FocusLost^();
UpdateBox(cursor.line, cursor.ofs)
END FocusLost;
PROCEDURE LocateBox(x, y: LONGINT; VAR pos: Position);
VAR l: Line; ofs, i: LONGINT;
BEGIN
IF x < dX THEN x := dX ELSIF x >= (dX + cols*boxW) THEN x := dX + cols*boxW-1 END;
IF y < dY THEN y := dY ELSIF y >= (dY + rows*boxH) THEN y := dY + rows*boxH-1 END;
pos.line := NIL; pos.ofs := -1;
l := top;
WHILE (l # NIL) & ~((l.t <= y) & (l.b > y)) DO
l := l.next
END;
IF l # NIL THEN
ofs := 0; i := dX;
WHILE (ofs < cols) & ~((i <= x) & ((i+boxW) > x)) DO
INC(ofs); INC(i, boxW)
END;
IF ofs < cols THEN
pos.line := l; pos.ofs := ofs
END
END
END LocateBox;
PROCEDURE Copy;
VAR
l: Line; apos, pos, ofs, end: LONGINT; buf: ARRAY 2 OF LONGINT;
attr: Attribute; tattr: Texts.Attributes;
BEGIN {EXCLUSIVE}
IF sel.beg.line = NIL THEN RETURN END;
Texts.clipboard.AcquireRead();
end := Texts.clipboard.GetLength();
Texts.clipboard.ReleaseRead();
Texts.clipboard.AcquireWrite();
Texts.clipboard.Delete(0, end);
pos := 0; buf[1] := 0; l := sel.beg.line;
attr := NIL; tattr := NIL; apos := -1;
LOOP
IF l = sel.beg.line THEN
ofs := sel.beg.ofs
ELSE
ofs := 0
END;
IF l = sel.end.line THEN
end := sel.end.ofs+1
ELSE
end := cols
END;
WHILE ofs < end DO
IF l.data[ofs].char # 0 THEN
buf[0] := l.data[ofs].char;
IF attr # l.data[ofs].attr THEN
IF tattr # NIL THEN
Texts.clipboard.SetAttributes(apos, pos-apos, tattr)
END;
apos := pos; attr := l.data[ofs].attr;
NEW(tattr); NEW(tattr.fontInfo);
tattr.color := attr.fg; tattr.bgcolor := attr.bg;
COPY(attr.fnt.name, tattr.fontInfo.name);
tattr.fontInfo.size := attr.fnt.size; tattr.fontInfo.style := attr.fnt.style
END;
Texts.clipboard.InsertUCS32(pos, buf); INC(pos)
END;
INC(ofs)
END;
IF l = sel.end.line THEN
EXIT
ELSE
l := l.next;
buf[0] := 0AH;
Texts.clipboard.InsertUCS32(pos, buf); INC(pos)
END
END;
IF tattr # NIL THEN
Texts.clipboard.SetAttributes(apos, pos-apos, tattr)
END;
Texts.clipboard.ReleaseWrite()
END Copy;
PROCEDURE Paste;
VAR R: Texts.TextReader; ch: LONGINT;
BEGIN {EXCLUSIVE}
Texts.clipboard.AcquireRead();
NEW(R, Texts.clipboard);
R.SetPosition(0);
R.SetDirection(1);
R.ReadCh(ch);
WHILE ~R.eot DO
IF (ch DIV 256) = 0 THEN C.W.Char(CHR(ch)) END;
R.ReadCh(ch)
END;
Texts.clipboard.ReleaseRead();
C.W.Update()
END Paste;
PROCEDURE ClickHandler(sender, par: ANY);
VAR b: WMStandardComponents.Button; str: Strings.String;
BEGIN
popup.Close();
b := sender(WMStandardComponents.Button);
str := b.caption.Get();
IF str^ = "Copy" THEN
Copy()
ELSIF str^ = "Paste" THEN
Paste()
END
END ClickHandler;
PROCEDURE PointerDown(x, y: LONGINT; keys: SET);
BEGIN
IF (Left IN keys) & hasFocus THEN
LocateBox(x, y, sel.beg); sel.end := sel.beg
ELSIF Right IN keys THEN
ToWMCoordinates(x, y, x, y);
popup.Popup(x, y)
ELSE
sel.beg.line := NIL; sel.beg.ofs := -1;
sel.end := sel.beg
END;
UpdateAll()
END PointerDown;
PROCEDURE PointerMove(x, y: LONGINT; keys: SET);
VAR pos: Position;
BEGIN
IF (Left IN keys) & (sel.beg.line # NIL) THEN
LocateBox(x, y, pos);
IF pos.line # NIL THEN
IF pos.line.t > sel.beg.line.t THEN
sel.end := pos
ELSIF (pos.line = sel.beg.line) & (pos.ofs >= sel.beg.ofs) THEN
sel.end := pos
END;
UpdateAll()
END
END
END PointerMove;
PROCEDURE WheelMove(dz: LONGINT);
VAR l: Line;
BEGIN
IF (dz > 0) & (top.next # NIL) THEN
top := top.next; UpdateAll()
ELSIF (dz < 0) & (top # first) THEN
l := first;
WHILE l.next # top DO
l := l.next
END;
top := l; UpdateAll()
END
END WheelMove;
PROCEDURE PointerUp(x, y: LONGINT; keys: SET);
END PointerUp;
PROCEDURE CursorKey(keySym: LONGINT);
BEGIN
C.W.Char(01BX);
IF CursorKeyMode IN C.mode THEN
C.W.Char("O")
ELSE
C.W.Char("[")
END;
CASE keySym OF
0FF51H: C.W.Char("D")
|0FF52H: C.W.Char("A")
|0FF53H: C.W.Char("C")
|0FF54H: C.W.Char("B")
END;
C.W.Update()
END CursorKey;
PROCEDURE KeyEvent(ucs: LONGINT; flags: SET; VAR keySym: LONGINT);
BEGIN
IF ~(Inputs.Release IN flags) & hasFocus THEN
IF (keySym DIV 256) = 0 THEN
C.W.Char(CHR(keySym)); C.W.Update()
ELSIF (keySym DIV 256) = 0FFH THEN
CASE keySym OF
0FF51H .. 0FF54H: CursorKey(keySym)
|0FF50H:
|0FF57H:
|0FFFFH:
|0FF08H: C.W.Char(07FX); C.W.Update()
|0FF0DH: C.W.Char(0DX); C.W.Char(0AX); C.W.Update()
|0FF1BH: C.W.Char(01BX); C.W.Update()
|0FF8DH: IF AppKeypadMode IN C.mode THEN
C.W.Char(01BX); C.W.Char("O"); C.W.Char("M")
ELSE
C.W.Char(0DX); C.W.Char(0AX)
END;
C.W.Update()
ELSE
END
END
END
END KeyEvent;
PROCEDURE resized;
VAR l: Line; W, H, b, t, c, r, i: LONGINT; d: Data; ch: Char;
BEGIN {EXCLUSIVE}
W := bounds.GetWidth() - 2*Border;
H := bounds.GetHeight() - 2*Border;
c := W DIV BoxW; r := H DIV BoxH;
boxW := W DIV c; boxH := H DIV r;
dX := Border + (W - c*boxW) DIV 2;
dY := Border + (H - r*boxH) DIV 2;
l := top; t := dY; b := dY + boxH;
WHILE l # NIL DO
l.t := t; l.b := b; l := l.next;
INC(t, boxH); INC(b, boxH)
END;
IF c # cols THEN
ch.attr := attr; ch.char := 0;
l := first;
WHILE l # NIL DO
NEW(d, c);
i := 0;
WHILE (i < c) & (i < cols) DO
d[i] := l.data[i]; INC(i)
END;
WHILE i < c DO
d[i] := ch; INC(i)
END;
l.data := d; l := l.next
END
END;
IF (c # cols) OR (r # rows) THEN
IF cursor.ofs >= c THEN cursor.ofs := c-1 END;
l := cursor.line;
IF l.b > (dY + r*boxH) THEN
i := (l.b - (dY + r*boxH)) DIV boxH;
l := top.next;
WHILE (l # NIL) & (i > 0) DO
top := l; l := l.next; DEC(i)
END
END;
sel.beg.line := NIL; cols := c; rows := r;
IF WindowSize IN C.mode THEN
C.Do(Telnet.OptWindowSize)
ELSE
C.W.Char(Telnet.CmdIAC); C.W.Char(Telnet.CmdWILL); C.W.Char(Telnet.OptWindowSize)
END
END
END resized;
PROCEDURE Resized;
BEGIN
Resized^();
resized()
END Resized;
PROCEDURE Initialize;
BEGIN
Initialize^();
takesFocus.Set(TRUE);
resized();
Invalidate()
END Initialize;
PROCEDURE &New*(C: Connection; cols, rows: LONGINT);
VAR i: LONGINT;
BEGIN
Init(); SELF.C := C;
SELF.rows := rows; SELF.cols := cols;
NewAttr(); bg := WMGraphics.RGBAToColor(255, 255, 255, 255);
last := NIL; first := AppendLine(); top := first;
cursor.line := top; cursor.ofs := 0;
boxW := 0; boxH := 0; dX := 0; dY := 0;
NEW(tabs, cols+1);
tabs[0] := FALSE; i := 1;
WHILE i <= cols DO
tabs[i] := (i MOD 8) = 0; INC(i)
END;
C.SetFrame(SELF);
NEW(popup);
popup.Add("Copy", ClickHandler);
popup.Add("Paste", ClickHandler)
END New;
END Frame;
Window = OBJECT (WMComponents.FormWindow)
VAR
panel: WMStandardComponents.Panel;
frame: Frame;
PROCEDURE &New*(C: Connection);
VAR
BEGIN
NEW(panel);
panel.bounds.SetWidth(2*Border + 80*BoxW); panel.bounds.SetHeight(2*Border + 24*BoxH);
NEW(frame, C, 80, 24); panel.AddContent(frame);
frame.alignment.Set(WMComponents.AlignClient);
Init(panel.bounds.GetWidth(), panel.bounds.GetHeight(), FALSE);
SetContent(panel);
manager := WMWindowManager.GetDefaultManager();
SetTitle(WMWindowManager.NewString("VT100 Terminal"));
manager.Add(100, 100, SELF, {WMWindowManager.FlagFrame})
END New;
PROCEDURE Close;
BEGIN
frame.C.Close();
Close^()
END Close;
END Window;
PROCEDURE Open*(context : Commands.Context);
VAR
inst: Window;
name: ARRAY 256 OF CHAR; port: LONGINT; adr: IP.Adr; res: LONGINT;
C: TCP.Connection; TC: Connection;
BEGIN
context.arg.SkipWhitespace; context.arg.String(name);
context.arg.SkipWhitespace; context.arg.Int(port, FALSE);
IF port = 0 THEN port := 23 END;
DNS.HostByName(name, adr, res);
IF res # DNS.Ok THEN
context.error.String(name); context.error.String(" invalid address");
context.error.Ln(); RETURN;
END;
NEW(C); C.Open(TCP.NilPort, adr, port, res);
IF res # TCP.Ok THEN
context.error.String(name); context.error.String(" open failed");
context.error.Ln(); RETURN;
END;
NEW(TC, C); NEW(inst, TC);
END Open;
END WMVT100.
Aos.Call WMVT100.Open lillian.inf.ethz.ch ~
Aos.Call WMVT100.Open "127.0.0.1" ~
System.Free WMVT100 ~ System.State WMVT100 ~
System.OpenKernelLog
ESC [ 1 ; 43 r
ESC 00000028
ESC 00000029
home, end, delete, insert, pageup, pagedown
emacs
pine
pico
lynx