mirror of
https://gitlab.com/freepascal.org/fpc/source.git
synced 2025-04-10 04:08:37 +02:00
1091 lines
27 KiB
ObjectPascal
1091 lines
27 KiB
ObjectPascal
{
|
|
This file is part of the Free Pascal Integrated Development Environment
|
|
Copyright (c) 1996-2000 by Berczi Gabor
|
|
|
|
ANSI support
|
|
|
|
See the file COPYING.FPC, included in this distribution,
|
|
for details about the copyright.
|
|
|
|
This program is distributed in the hope that it will be useful,
|
|
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
|
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
|
|
|
|
**********************************************************************}
|
|
{.$DEFINE DEBUG}
|
|
unit WANSI;
|
|
|
|
interface
|
|
|
|
uses Objects,Drivers,
|
|
{$ifdef WITH_CRT}
|
|
Crt,
|
|
{$endif WITH_CRT}
|
|
Dos,Views,App;
|
|
|
|
const
|
|
{$ifndef WITH_CRT}
|
|
{ Foreground and background color constants }
|
|
Black = 0;
|
|
Blue = 1;
|
|
Green = 2;
|
|
Cyan = 3;
|
|
Red = 4;
|
|
Magenta = 5;
|
|
Brown = 6;
|
|
LightGray = 7;
|
|
|
|
{ Foreground color constants }
|
|
DarkGray = 8;
|
|
LightBlue = 9;
|
|
LightGreen = 10;
|
|
LightCyan = 11;
|
|
LightRed = 12;
|
|
LightMagenta = 13;
|
|
Yellow = 14;
|
|
White = 15;
|
|
|
|
{ Add-in for blinking }
|
|
Blink = 128;
|
|
{$endif not WITH_CRT}
|
|
|
|
ANSIMaxParamLen = 30; { max ANSI escape sequence length }
|
|
ANSICurPosStackSize = 20; { max number of cursor positions stored at the same time }
|
|
|
|
Esc = #27;
|
|
|
|
{ BoundCheck constants }
|
|
bc_MinX = 1;
|
|
bc_MinY = 2;
|
|
bc_MaxX = 4;
|
|
bc_MaxY = 8;
|
|
bc_X = bc_MinX or bc_MaxX;
|
|
bc_Y = bc_MinY or bc_MaxY;
|
|
bc_Min = bc_MinX or bc_MinY;
|
|
bc_Max = bc_MaxX or bc_MaxY;
|
|
bc_All = bc_X or bc_Y;
|
|
|
|
type
|
|
TANSIParam = string[ANSIMaxParamLen];
|
|
|
|
PHookProc = ^THookProc;
|
|
THookProc = procedure (S: string);
|
|
|
|
PConsoleObject = ^TConsoleObject;
|
|
TConsoleObject = object(TObject)
|
|
CurPos : TPoint;
|
|
Size : TPoint;
|
|
TextAttr : byte;
|
|
BoldOn : boolean;
|
|
BlinkOn : boolean;
|
|
BoundChecks: byte;
|
|
LineWrapping: boolean;
|
|
ReplyHook : PHookProc;
|
|
KeyHook : PHookProc;
|
|
WriteHook : PHookProc;
|
|
constructor Init(AReplyHook, AKeyHook, AWriteHook: PHookProc);
|
|
procedure Home; virtual;
|
|
procedure ClrScr; virtual;
|
|
procedure FillScreen(B: byte); virtual;
|
|
procedure ClrEol; virtual;
|
|
procedure GotoXY(X,Y: integer); virtual;
|
|
procedure Write(Const S: string); virtual;
|
|
procedure WriteLn(Const S: string); virtual;
|
|
procedure WriteChar(C: char); virtual;
|
|
procedure WriteCharRaw(C: char); virtual;
|
|
procedure DelLine(LineCount: integer); virtual;
|
|
procedure InsLine(LineCount: integer); virtual;
|
|
procedure HighVideo; virtual;
|
|
procedure BlinkVideo; virtual;
|
|
procedure NoBlinkVideo; virtual;
|
|
procedure NormVideo; virtual;
|
|
procedure LowVideo; virtual;
|
|
procedure TextBackground(Color: byte); virtual;
|
|
procedure TextColor(Color: byte); virtual;
|
|
function WhereX: integer; virtual;
|
|
function WhereY: integer; virtual;
|
|
procedure CursorOn; virtual;
|
|
procedure CursorOff; virtual;
|
|
procedure UpdateCursor; virtual;
|
|
{ --- Hook procedures --- }
|
|
procedure Reply(S: string); virtual;
|
|
procedure PutKey(S: string); virtual;
|
|
destructor Done; virtual;
|
|
private
|
|
procedure ProcessChar(C: char); virtual;
|
|
end;
|
|
|
|
PANSIConsole = ^TANSIConsole;
|
|
TANSIConsole = object(TConsoleObject)
|
|
ANSIParam : TANSIParam;
|
|
ANSILevel : byte;
|
|
ANSICurPosStack : array[1..ANSICurPosStackSize] of TPoint;
|
|
ANSICurPosStackPtr : byte;
|
|
constructor Init(AReplyHook, AKeyHook, AWriteHook: PHookProc);
|
|
procedure ProcessChar(C: char); virtual;
|
|
function GetANSIParam: integer; virtual;
|
|
{ --- ANSI functions --- }
|
|
procedure PushCurPos; virtual;
|
|
procedure PopCurPos; virtual;
|
|
procedure CursorUp(LineCount: integer); virtual;
|
|
procedure CursorDown(LineCount: integer); virtual;
|
|
procedure CursorForward(CharCount: integer); virtual;
|
|
procedure CursorBack(CharCount: integer); virtual;
|
|
procedure SetAttr(Color: integer); virtual;
|
|
end;
|
|
|
|
{$ifdef WITH_CRT}
|
|
PCrtConsole = ^TCrtConsole;
|
|
TCrtConsole = object(TANSIConsole)
|
|
constructor Init(AReplyHook, AKeyHook, AWriteHook: PHookProc);
|
|
procedure CursorOn; virtual;
|
|
procedure CursorOff; virtual;
|
|
procedure ClrScr; virtual;
|
|
procedure ClrEol; virtual;
|
|
procedure WriteChar(C: char); virtual;
|
|
procedure DelLine(LineCount: integer); virtual;
|
|
procedure InsLine(LineCount: integer); virtual;
|
|
procedure UpdateCursor; virtual;
|
|
procedure TextBackground(Color: byte); virtual;
|
|
procedure TextColor(Color: byte); virtual;
|
|
end;
|
|
{$endif WITH_CRT}
|
|
|
|
const
|
|
MaxVideoLine = 65520 div (2*MaxViewWidth); { maximum number of lines that fit in 64K }
|
|
|
|
type
|
|
TAnsiBuffer = array[0..MaxViewWidth*MaxVideoLine] of word;
|
|
PAnsiBuffer = ^TAnsiBuffer;
|
|
|
|
PANSIView = ^TANSIView;
|
|
|
|
PANSIViewConsole = ^TANSIViewConsole;
|
|
TANSIViewConsole = object(TANSIConsole)
|
|
Owner : PANSIView;
|
|
constructor Init(AOwner: PANSIView);
|
|
procedure CursorOn; virtual;
|
|
procedure CursorOff; virtual;
|
|
procedure ClrScr; virtual;
|
|
procedure ClrEol; virtual;
|
|
procedure WriteChar(C: char); virtual;
|
|
procedure WriteCharRaw(C: char); virtual;
|
|
procedure DelLine(LineCount: integer); virtual;
|
|
procedure InsLine(LineCount: integer); virtual;
|
|
procedure UpdateCursor; virtual;
|
|
procedure GotoXY(X,Y: integer); virtual;
|
|
end;
|
|
|
|
TANSIView = object(TScroller)
|
|
Console : PANSIViewConsole;
|
|
Buffer : PAnsiBuffer;
|
|
LockCount : word;
|
|
constructor Init(var Bounds: TRect; AHScrollBar, AVScrollBar:PScrollBar);
|
|
function LoadFile(const FileName: string): boolean;
|
|
procedure Draw; virtual;
|
|
destructor Done; virtual;
|
|
procedure Write(Const S: string); virtual;
|
|
procedure WriteLn(Const S: string); virtual;
|
|
procedure Lock; virtual;
|
|
procedure UnLock; virtual;
|
|
procedure ChangeBounds(var Bounds: TRect); virtual;
|
|
procedure HandleEvent(var Event: TEvent); virtual;
|
|
private
|
|
end;
|
|
|
|
PANSIBackground = ^TANSIBackground;
|
|
|
|
PANSIBackgroundConsole = ^TANSIBackgroundConsole;
|
|
TANSIBackgroundConsole = object(TANSIConsole)
|
|
Owner : PANSIBackground;
|
|
constructor Init(AOwner: PANSIBackground);
|
|
procedure CursorOn; virtual;
|
|
procedure CursorOff; virtual;
|
|
procedure ClrScr; virtual;
|
|
procedure ClrEol; virtual;
|
|
procedure WriteChar(C: char); virtual;
|
|
procedure DelLine(LineCount: integer); virtual;
|
|
procedure InsLine(LineCount: integer); virtual;
|
|
procedure UpdateCursor; virtual;
|
|
procedure GotoXY(X,Y: integer); virtual;
|
|
end;
|
|
|
|
TANSIBackground = object(TBackground)
|
|
Console : PANSIBackgroundConsole;
|
|
Buffer : TAnsiBuffer;
|
|
LockCount : word;
|
|
constructor Init(var Bounds: TRect);
|
|
function LoadFile(const FileName: string): boolean;
|
|
procedure Draw; virtual;
|
|
destructor Done; virtual;
|
|
procedure Write(Const S: string); virtual;
|
|
procedure WriteLn(Const S: string); virtual;
|
|
procedure Lock; virtual;
|
|
procedure UnLock; virtual;
|
|
procedure ChangeBounds(var Bounds: TRect); virtual;
|
|
procedure HandleEvent(var Event: TEvent); virtual;
|
|
private
|
|
end;
|
|
|
|
implementation
|
|
|
|
uses WUtils;
|
|
|
|
constructor TConsoleObject.Init(AReplyHook, AKeyHook, AWriteHook: PHookProc);
|
|
begin
|
|
inherited Init;
|
|
ReplyHook:=AReplyHook; KeyHook:=AKeyHook; WriteHook:=AWriteHook;
|
|
BoundChecks:=bc_All; LineWrapping:=true;
|
|
TextColor(LightGray); TextBackground(Black);
|
|
NormVideo;
|
|
ClrScr;
|
|
end;
|
|
|
|
procedure TConsoleObject.Home;
|
|
begin
|
|
GotoXY(1,1);
|
|
end;
|
|
|
|
procedure TConsoleObject.ClrScr;
|
|
begin
|
|
Abstract;
|
|
end;
|
|
|
|
procedure TConsoleObject.FillScreen(B: byte);
|
|
var X,Y: integer;
|
|
S : string;
|
|
begin
|
|
GotoXY(1,1);
|
|
for Y:=1 to Size.Y do
|
|
begin
|
|
S:='';
|
|
for X:=1 to Size.X do S:=S+chr(B);
|
|
WriteLn(S);
|
|
end;
|
|
end;
|
|
|
|
procedure TConsoleObject.ClrEol;
|
|
begin
|
|
Abstract;
|
|
end;
|
|
|
|
procedure TConsoleObject.GotoXY(X,Y: integer);
|
|
begin
|
|
if (BoundChecks and bc_MinX)<>0 then X:=Max(X,1);
|
|
if (BoundChecks and bc_MaxX)<>0 then
|
|
if LineWrapping then while (X>Size.X) and (Size.X<>0)
|
|
do begin
|
|
Inc(Y);
|
|
X:=X-Size.X;
|
|
end
|
|
else X:=Min(X,Size.X);
|
|
if (BoundChecks and bc_MinY)<>0 then Y:=Max(Y,1);
|
|
if (BoundChecks and bc_MaxY)<>0 then Y:=Min(Y,Size.Y);
|
|
CurPos.X:=X; CurPos.Y:=Y;
|
|
UpdateCursor;
|
|
end;
|
|
|
|
procedure TConsoleObject.ProcessChar(C: char);
|
|
begin
|
|
WriteChar(C);
|
|
end;
|
|
|
|
procedure TConsoleObject.WriteChar(C: char);
|
|
begin
|
|
Abstract;
|
|
end;
|
|
|
|
procedure TConsoleObject.WriteCharRaw(C: char);
|
|
begin
|
|
Abstract;
|
|
end;
|
|
|
|
procedure TConsoleObject.Write(Const S: string); {assembler;
|
|
asm
|
|
push ds
|
|
lds si, S
|
|
lodsb
|
|
xor ah, ah
|
|
mov cx, ax
|
|
@loop:
|
|
or cx, cx
|
|
je @exitloop
|
|
lodsb
|
|
pop ds
|
|
push ax
|
|
call ProcessChar
|
|
push ds
|
|
dec cx
|
|
jmp @loop
|
|
@exitloop:
|
|
pop ds
|
|
end;}
|
|
var Len: byte;
|
|
I : byte;
|
|
begin
|
|
Len:=length(S);
|
|
for I:=1 to Len do ProcessChar(S[I]);
|
|
end;
|
|
|
|
procedure TConsoleObject.WriteLn(Const S: string);
|
|
begin
|
|
Write(S);Write(#10);
|
|
end;
|
|
|
|
procedure TConsoleObject.DelLine(LineCount: integer);
|
|
begin
|
|
Abstract;
|
|
end;
|
|
|
|
procedure TConsoleObject.InsLine(LineCount: integer);
|
|
begin
|
|
Abstract;
|
|
end;
|
|
|
|
procedure TConsoleObject.NormVideo;
|
|
begin
|
|
BoldOn:=false; BlinkOn:=false;
|
|
TextColor(LightGray);
|
|
TextBackground(Black);
|
|
end;
|
|
|
|
procedure TConsoleObject.BlinkVideo;
|
|
begin
|
|
BlinkOn:=true;
|
|
TextBackground(TextAttr shr 4);
|
|
end;
|
|
|
|
procedure TConsoleObject.NoBlinkVideo;
|
|
begin
|
|
BlinkOn:=false;
|
|
TextAttr:=TextAttr and $7f;
|
|
TextBackground(TextAttr shr 4);
|
|
end;
|
|
|
|
procedure TConsoleObject.HighVideo;
|
|
begin
|
|
BoldOn:=true;
|
|
TextColor(TextAttr);
|
|
end;
|
|
|
|
procedure TConsoleObject.LowVideo;
|
|
begin
|
|
BoldOn:=false;
|
|
TextAttr:=TextAttr and not $08;
|
|
TextColor(TextAttr);
|
|
end;
|
|
|
|
procedure TConsoleObject.TextBackground(Color: byte);
|
|
begin
|
|
TextAttr:=(TextAttr and $0f) or (Color shl 4) or byte(BlinkOn)*$80;
|
|
end;
|
|
|
|
procedure TConsoleObject.TextColor(Color: byte);
|
|
begin
|
|
TextAttr:=((TextAttr and $f0) or (Color and $0f) or byte(BoldOn)*$08);
|
|
end;
|
|
|
|
function TConsoleObject.WhereX: integer;
|
|
begin
|
|
WhereX:=CurPos.X;
|
|
end;
|
|
|
|
function TConsoleObject.WhereY: integer;
|
|
begin
|
|
WhereY:=CurPos.Y;
|
|
end;
|
|
|
|
procedure TConsoleObject.CursorOn;
|
|
begin
|
|
Abstract;
|
|
end;
|
|
|
|
procedure TConsoleObject.CursorOff;
|
|
begin
|
|
Abstract;
|
|
end;
|
|
|
|
procedure TConsoleObject.UpdateCursor;
|
|
begin
|
|
Abstract;
|
|
end;
|
|
|
|
procedure TConsoleObject.Reply(S: string);
|
|
begin
|
|
if ReplyHook<>nil then ReplyHook^(S);
|
|
end;
|
|
|
|
procedure TConsoleObject.PutKey(S: string);
|
|
begin
|
|
if KeyHook<>nil then KeyHook^(S);
|
|
end;
|
|
|
|
destructor TConsoleObject.Done;
|
|
begin
|
|
inherited Done;
|
|
end;
|
|
|
|
{$ifdef WITH_CRT}
|
|
constructor TCrtConsole.Init(AReplyHook, AKeyHook, AWriteHook: PHookProc);
|
|
begin
|
|
inherited Init(AReplyHook, AKeyHook, AWriteHook);
|
|
Size.X:=Lo(Crt.WindMax); Size.Y:=Hi(Crt.WindMax);
|
|
end;
|
|
|
|
procedure TCrtConsole.CursorOn;
|
|
begin
|
|
end;
|
|
|
|
procedure TCrtConsole.CursorOff;
|
|
begin
|
|
end;
|
|
|
|
procedure TCrtConsole.ClrScr;
|
|
begin
|
|
Crt.ClrScr;
|
|
GotoXY(Crt.WhereX,Crt.WhereY);
|
|
end;
|
|
|
|
procedure TCrtConsole.ClrEol;
|
|
begin
|
|
Crt.ClrEol;
|
|
GotoXY(Crt.WhereX,Crt.WhereY);
|
|
end;
|
|
|
|
procedure TCrtConsole.WriteChar(C: char);
|
|
{var OK: boolean;}
|
|
begin
|
|
{ OK:=((C>=#32) and (WhereX<Size.X)) or (C<#32);
|
|
if OK then
|
|
begin}
|
|
System.Write(C);
|
|
GotoXY(Crt.WhereX,Crt.WhereY);
|
|
{ end
|
|
else Inc(CurPos.X);}
|
|
end;
|
|
|
|
procedure TCrtConsole.DelLine(LineCount: integer);
|
|
var I: integer;
|
|
begin
|
|
for I:=1 to LineCount do Crt.DelLine;
|
|
end;
|
|
|
|
procedure TCrtConsole.InsLine(LineCount: integer);
|
|
var I: integer;
|
|
begin
|
|
for I:=1 to LineCount do Crt.InsLine;
|
|
end;
|
|
|
|
procedure TCrtConsole.UpdateCursor;
|
|
begin
|
|
Crt.GotoXY(CurPos.X,CurPos.Y);
|
|
end;
|
|
|
|
procedure TCrtConsole.TextBackground(Color: byte);
|
|
begin
|
|
inherited TextBackground(Color);
|
|
Crt.TextAttr:=TextAttr;
|
|
end;
|
|
|
|
procedure TCrtConsole.TextColor(Color: byte);
|
|
begin
|
|
inherited TextColor(Color);
|
|
Crt.TextAttr:=TextAttr;
|
|
end;
|
|
{$endif WITH_CRT}
|
|
|
|
constructor TANSIConsole.Init(AReplyHook, AKeyHook, AWriteHook: PHookProc);
|
|
begin
|
|
inherited Init(AReplyHook, AKeyHook, AWriteHook);
|
|
BoundChecks:=bc_MaxX;
|
|
ANSIParam:=''; ANSILevel:=0; ANSICurPosStackPtr:=0;
|
|
end;
|
|
|
|
procedure TANSIConsole.ProcessChar(C: char);
|
|
var SkipThis : boolean;
|
|
ANSIDone : boolean;
|
|
X,Y,Z : integer;
|
|
begin
|
|
SkipThis:=false;
|
|
if C=Esc then
|
|
begin
|
|
{ Treat EscEsc as a request to print a single Escape #27 char PM }
|
|
if AnsiLevel=0 then
|
|
begin
|
|
ANSILevel:=1;
|
|
SkipThis:=true;
|
|
end
|
|
else
|
|
begin
|
|
AnsiLevel:=0;
|
|
WriteCharRaw(c);
|
|
SkipThis:=true;
|
|
end;
|
|
end
|
|
else if (ANSILevel=1) then
|
|
begin
|
|
ANSILevel:=0;
|
|
case C of
|
|
'[' : begin
|
|
ANSILevel:=2;
|
|
SkipThis:=true;
|
|
end;
|
|
else
|
|
{ Treat Esc+ AnyChar as a request to print that single char raw PM }
|
|
begin
|
|
WriteCharRaw(c);
|
|
SkipThis:=true;
|
|
end;
|
|
end;
|
|
end;
|
|
|
|
if SkipThis=false then
|
|
if (ANSILevel=2)
|
|
then begin
|
|
ANSIDone:=true;
|
|
case C of
|
|
'H','f' : if ANSIParam='' then GotoXY(1,1) else
|
|
begin
|
|
X:=WhereX; Y:=WhereY;
|
|
Z:=Pos(';',ANSIParam);
|
|
if Z=0
|
|
then Y:=GetANSIParam
|
|
else if Z=1 then X:=GetANSIParam
|
|
else begin Y:=GetANSIParam; X:=GetANSIParam; end;
|
|
GotoXY(X,Y);
|
|
end;
|
|
'A' : if ANSIParam='' then CursorUp(1)
|
|
else CursorUp(GetANSIParam);
|
|
'B' : if ANSIParam='' then CursorDown(1)
|
|
else CursorDown(GetANSIParam);
|
|
'C' : if ANSIParam='' then CursorForward(1)
|
|
else CursorForward(GetANSIParam);
|
|
'D' : if ANSIParam='' then CursorBack(1)
|
|
else CursorBack(GetANSIParam);
|
|
's' : if ANSIParam='' then PushCurPos;
|
|
'u' : if ANSIParam='' then PopCurPos;
|
|
'J' : if ANSIParam='2' then begin ANSIParam:=''; ClrScr; end
|
|
else FillScreen(GetANSIParam);
|
|
'K' : if ANSIParam='' then ClrEol;
|
|
'L' : if ANSIParam='' then InsLine(1)
|
|
else InsLine(GetANSIParam);
|
|
'M' : if ANSIParam='' then DelLine(1)
|
|
else DelLine(GetANSIParam);
|
|
'm' : while ANSIParam<>'' do SetAttr(GetANSIParam);
|
|
else
|
|
begin
|
|
{ANSIParam:=ANSIParam+C;}
|
|
System.Insert(C,AnsiParam,Length(AnsiParam)+1);
|
|
ANSIDone:=false;
|
|
end;
|
|
end;
|
|
if ANSIDone then
|
|
begin
|
|
{$IFDEF DEBUG}
|
|
if ANSIParam<>'' then RunError(240);
|
|
{$ENDIF}
|
|
ANSIParam:=''; ANSILevel:=0;
|
|
end;
|
|
end
|
|
else begin
|
|
WriteChar(C);
|
|
if C=#10 then WriteChar(#13);
|
|
end;
|
|
end;
|
|
|
|
function TANSIConsole.GetANSIParam: integer;
|
|
var P: byte;
|
|
I,C: integer;
|
|
begin
|
|
P:=Pos(';',ANSIParam);
|
|
if P=0 then P:=length(ANSIParam)+1;
|
|
Val(copy(ANSIParam,1,P-1),I,C);
|
|
if C<>0 then I:=0;
|
|
Delete(ANSIParam,1,P);
|
|
GetANSIParam:=I;
|
|
end;
|
|
procedure TANSIConsole.CursorUp(LineCount: integer);
|
|
begin
|
|
GotoXY(WhereX,WhereY-LineCount);
|
|
end;
|
|
|
|
procedure TANSIConsole.CursorDown(LineCount: integer);
|
|
begin
|
|
GotoXY(WhereX,WhereY+LineCount);
|
|
end;
|
|
|
|
procedure TANSIConsole.CursorForward(CharCount: integer);
|
|
var X, Y: integer;
|
|
begin
|
|
X:=WhereX; Y:=WhereY;
|
|
X:=X+CharCount;
|
|
while (X>Size.X) do
|
|
begin Inc(Y); Dec(X,Size.X); end;
|
|
GotoXY(X,Y);
|
|
end;
|
|
|
|
procedure TANSIConsole.CursorBack(CharCount: integer);
|
|
var X, Y: integer;
|
|
begin
|
|
X:=WhereX; Y:=WhereY;
|
|
X:=X-CharCount;
|
|
while (X<1) do begin Dec(Y); Inc(X,Size.X); end;
|
|
GotoXY(X,Y);
|
|
end;
|
|
|
|
procedure TANSIConsole.PushCurPos;
|
|
begin
|
|
if ANSICurPosStackPtr=ANSICurPosStackSize then Exit;
|
|
Inc(ANSICurPosStackPtr);
|
|
ANSICurPosStack[ANSICurPosStackPtr].X:=WhereX;
|
|
ANSICurPosStack[ANSICurPosStackPtr].Y:=WhereY;
|
|
end;
|
|
|
|
procedure TANSIConsole.PopCurPos;
|
|
begin
|
|
if ANSICurPosStackPtr=0 then Exit;
|
|
GotoXY(ANSICurPosStack[ANSICurPosStackPtr].X,ANSICurPosStack[ANSICurPosStackPtr].Y);
|
|
Dec(ANSICurPosStackPtr);
|
|
end;
|
|
|
|
procedure TANSIConsole.SetAttr(Color: integer);
|
|
const ColorTab : array[0..7] of byte =
|
|
(Black,Red,Green,Brown,Blue,Magenta,Cyan,LightGray);
|
|
begin
|
|
case Color of
|
|
0 : NormVideo;
|
|
1 : HighVideo;
|
|
5 : BlinkVideo;
|
|
7,27 : TextAttr:=(TextAttr shl 4) or (TextAttr shr 4);
|
|
8 : TextColor(TextAttr shr 4);
|
|
21,22 : LowVideo;
|
|
25 : NoBlinkVideo;
|
|
30..37 : TextColor(ColorTab[Color-30]);
|
|
40..47 : TextBackground(ColorTab[Color-40]);
|
|
(* else {$IFDEF DEBUG}begin system.writeln('Unknown attr : ',Color); Halt; end{$ENDIF};*)
|
|
end;
|
|
end;
|
|
|
|
constructor TANSIViewConsole.Init(AOwner: PANSIView);
|
|
begin
|
|
if AOwner=nil then Fail;
|
|
inherited Init(nil,nil,nil);
|
|
Owner:=AOwner;
|
|
Size:=Owner^.Size;
|
|
end;
|
|
|
|
procedure TANSIViewConsole.CursorOn;
|
|
begin
|
|
Owner^.ShowCursor;
|
|
end;
|
|
|
|
procedure TANSIViewConsole.CursorOff;
|
|
begin
|
|
Owner^.HideCursor;
|
|
end;
|
|
|
|
procedure TANSIViewConsole.ClrScr;
|
|
var X,Y: word;
|
|
Pos: longint;
|
|
begin
|
|
GotoXY(1,1);
|
|
if Owner<>nil then
|
|
for X:=0 to MaxViewWidth-1 do for Y:=0 to Size.Y-1 do
|
|
begin
|
|
Pos:=(Owner^.Delta.Y+Y)*MaxViewWidth+X;
|
|
Owner^.Buffer^[Pos]:=32+256*word(TextAttr);
|
|
end;
|
|
end;
|
|
|
|
procedure TANSIViewConsole.ClrEol;
|
|
var X,Y: word;
|
|
Pos: longint;
|
|
begin
|
|
if Owner<>nil then
|
|
begin
|
|
Y:=CurPos.Y;
|
|
for X:=CurPos.X to MaxViewWidth-1 do
|
|
begin
|
|
Pos:=(Owner^.Delta.Y*MaxViewWidth)+X+Y*MaxViewWidth;
|
|
Owner^.Buffer^[Pos]:=32+256*word(TextAttr);
|
|
end;
|
|
end;
|
|
end;
|
|
|
|
procedure TANSIViewConsole.WriteChar(C: char);
|
|
var Pos: longint;
|
|
begin
|
|
case C of
|
|
#8 : begin
|
|
CursorBack(1);
|
|
Pos:=(CurPos.Y-1)*MaxViewWidth+(WhereX-1);
|
|
Owner^.Buffer^[Pos]:=ord(' ')+256*word(TextAttr);
|
|
end;
|
|
#0..#7,#9,
|
|
#11..#12,
|
|
#14..#31,
|
|
#32..#255
|
|
: begin
|
|
Pos:=(CurPos.Y-1)*MaxViewWidth+(WhereX-1);
|
|
Owner^.Buffer^[Pos]:=ord(C)+256*word(TextAttr);
|
|
GotoXY(WhereX+1,WhereY);
|
|
end;
|
|
#10 :
|
|
GotoXY(WhereX,WhereY+1);
|
|
#13 :
|
|
GotoXY(1,WhereY);
|
|
else {$IFDEF DEBUG}RunError(241){$ENDIF};
|
|
end;
|
|
end;
|
|
|
|
procedure TANSIViewConsole.WriteCharRaw(C: char);
|
|
var Pos: longint;
|
|
begin
|
|
Pos:=(CurPos.Y-1)*MaxViewWidth+(WhereX-1);
|
|
Owner^.Buffer^[Pos]:=ord(C)+256*word(TextAttr);
|
|
GotoXY(WhereX+1,WhereY);
|
|
end;
|
|
|
|
procedure TANSIViewConsole.DelLine(LineCount: integer);
|
|
begin
|
|
Abstract;
|
|
end;
|
|
|
|
procedure TANSIViewConsole.InsLine(LineCount: integer);
|
|
begin
|
|
Abstract;
|
|
end;
|
|
|
|
procedure TANSIViewConsole.UpdateCursor;
|
|
begin
|
|
if Owner<>nil then
|
|
if Owner^.LockCount=0 then Owner^.SetCursor(WhereX-1,WhereY-1);
|
|
end;
|
|
|
|
procedure TANSIViewConsole.GotoXY(X,Y: integer);
|
|
var W: word;
|
|
begin
|
|
if Owner<>nil then
|
|
while Y>MaxVideoLine do
|
|
begin
|
|
Move(Owner^.Buffer^[MaxViewWidth],Owner^.Buffer,SizeOf(Owner^.Buffer^)-(MaxViewWidth*2));
|
|
W:=(MaxViewWidth*MaxVideoLine)-1-(MaxViewWidth);
|
|
FillChar(Owner^.Buffer^[W],MaxViewWidth*2,0);
|
|
Dec(Y);
|
|
end;
|
|
inherited GotoXY(X,Y);
|
|
end;
|
|
|
|
constructor TANSIView.Init(var Bounds: TRect; AHScrollBar, AVScrollBar:
|
|
PScrollBar);
|
|
begin
|
|
inherited Init(Bounds,AHScrollBar,AVScrollBar);
|
|
LockCount:=0; Options:=Options or ofTopSelect;
|
|
GrowMode:=gfGrowHiX or gfGrowHiY;
|
|
New(Buffer);
|
|
SetLimit({MaxViewWidth}80,MaxVideoLine);
|
|
New(Console, Init(@Self));
|
|
Console^.Size.X:=80; Console^.Size.Y:=25;
|
|
Console^.ClrScr;
|
|
Console^.CursorOn;
|
|
end;
|
|
|
|
function TANSIView.LoadFile(const FileName: string): boolean;
|
|
var S: PBufStream;
|
|
OK: boolean;
|
|
B: array[0..1023] of char;
|
|
I,FragSize: integer;
|
|
begin
|
|
{$I-}
|
|
New(S, Init(FileName, stOpenRead, 4096));
|
|
OK:=Assigned(S);
|
|
Lock;
|
|
while OK and (S^.Status=stOK) do
|
|
begin
|
|
FragSize:=Min(Sizeof(B),S^.GetSize-S^.GetPos);
|
|
if FragSize=0 then Break;
|
|
S^.Read(B,FragSize);
|
|
OK:=(S^.Status=stOK);
|
|
if OK then
|
|
for I:=0 to FragSize-1 do
|
|
self.Write(B[I]);
|
|
end;
|
|
Unlock;
|
|
if Assigned(S) then Dispose(S, Done); S:=nil;
|
|
{$I+}
|
|
LoadFile:=OK;
|
|
end;
|
|
|
|
procedure TANSIView.Draw;
|
|
var I: integer;
|
|
Pos: longint;
|
|
X,Y: integer;
|
|
begin
|
|
if LockCount<>0 then Exit;
|
|
for I:=0 to Size.Y-1 do
|
|
begin
|
|
Pos:=Delta.X+(Delta.Y+I)*MaxViewWidth;
|
|
WriteLine(0,I,Size.X,1,Buffer^[Pos]);
|
|
end;
|
|
if Console=nil then Exit;
|
|
X:=Console^.WhereX-Delta.X; Y:=Console^.WhereY-Delta.Y;
|
|
if (X<0) or (Y<0) or (X>Size.X-1) or (Y>Size.X-1)
|
|
then HideCursor
|
|
else begin
|
|
ShowCursor;
|
|
SetCursor(X-1,Y-1);
|
|
end;
|
|
end;
|
|
|
|
procedure TANSIView.Write(Const S: string);
|
|
begin
|
|
Console^.Write(S);
|
|
DrawView;
|
|
end;
|
|
|
|
procedure TANSIView.WriteLn(Const S: string);
|
|
begin
|
|
Console^.WriteLn(S);
|
|
DrawView;
|
|
end;
|
|
|
|
procedure TANSIView.Lock;
|
|
begin
|
|
Inc(LockCount);
|
|
end;
|
|
|
|
procedure TANSIView.UnLock;
|
|
begin
|
|
Dec(LockCount);
|
|
if LockCount=0 then DrawView;
|
|
end;
|
|
|
|
procedure TANSIView.ChangeBounds(var Bounds: TRect);
|
|
begin
|
|
inherited ChangeBounds(Bounds);
|
|
{ Console^.Size.X:=Size.X; Console^.Size.Y:=Size.Y;}
|
|
end;
|
|
|
|
procedure TANSIView.HandleEvent(var Event: TEvent);
|
|
begin
|
|
inherited HandleEvent(Event);
|
|
{ if Event.What=evKeyDown then
|
|
begin
|
|
if VScrollBar<>nil then VScrollBar^.HandleEvent(Event);
|
|
if HScrollBar<>nil then HScrollBar^.HandleEvent(Event);
|
|
end;}
|
|
end;
|
|
|
|
destructor TANSIView.Done;
|
|
begin
|
|
Dispose(Console, Done);
|
|
Dispose(Buffer);
|
|
inherited Done;
|
|
end;
|
|
|
|
constructor TANSIBackgroundConsole.Init(AOwner: PANSIBackground);
|
|
begin
|
|
if AOwner=nil then Fail;
|
|
inherited Init(nil,nil,nil);
|
|
Owner:=AOwner;
|
|
Size:=Owner^.Size;
|
|
end;
|
|
|
|
procedure TANSIBackgroundConsole.CursorOn;
|
|
begin
|
|
Owner^.ShowCursor;
|
|
end;
|
|
|
|
procedure TANSIBackgroundConsole.CursorOff;
|
|
begin
|
|
Owner^.HideCursor;
|
|
end;
|
|
|
|
procedure TANSIBackgroundConsole.ClrScr;
|
|
var X,Y: word;
|
|
Pos: longint;
|
|
begin
|
|
GotoXY(1,1);
|
|
if Owner<>nil then
|
|
for X:=0 to MaxViewWidth-1 do
|
|
for Y:=0 to Size.Y-1 do
|
|
begin
|
|
Pos:=X+Y*MaxViewWidth;
|
|
Owner^.Buffer[Pos]:=32+256*word(TextAttr);
|
|
end;
|
|
end;
|
|
|
|
procedure TANSIBackgroundConsole.ClrEol;
|
|
var X,Y: word;
|
|
Pos: longint;
|
|
begin
|
|
if Owner<>nil then
|
|
begin
|
|
Y:=CurPos.Y;
|
|
for X:=CurPos.X to MaxViewWidth-1 do
|
|
begin
|
|
Pos:=X+Y*MaxViewWidth;
|
|
Owner^.Buffer[Pos]:=32+256*word(TextAttr);
|
|
end;
|
|
end;
|
|
end;
|
|
|
|
procedure TANSIBackgroundConsole.WriteChar(C: char);
|
|
var Pos: longint;
|
|
begin
|
|
case C of
|
|
#8 : begin
|
|
CursorBack(1);
|
|
Pos:=(CurPos.Y-1)*MaxViewWidth+(WhereX-1);
|
|
Owner^.Buffer[Pos]:=ord(' ')+256*word(TextAttr);
|
|
end;
|
|
#0..#7,#9,
|
|
#11..#12,
|
|
#14..#31,
|
|
#32..#255
|
|
: begin
|
|
Pos:=(CurPos.Y-1)*MaxViewWidth+(WhereX-1);
|
|
Owner^.Buffer[Pos]:=ord(C)+256*word(TextAttr);
|
|
GotoXY(WhereX+1,WhereY);
|
|
end;
|
|
#10 :
|
|
GotoXY(WhereX,WhereY+1);
|
|
#13 :
|
|
GotoXY(1,WhereY);
|
|
else {$IFDEF DEBUG}RunError(241){$ENDIF};
|
|
end;
|
|
end;
|
|
|
|
procedure TANSIBackgroundConsole.DelLine(LineCount: integer);
|
|
begin
|
|
Abstract;
|
|
end;
|
|
|
|
procedure TANSIBackgroundConsole.InsLine(LineCount: integer);
|
|
begin
|
|
Abstract;
|
|
end;
|
|
|
|
procedure TANSIBackgroundConsole.UpdateCursor;
|
|
begin
|
|
if Owner<>nil then
|
|
if Owner^.LockCount=0 then Owner^.SetCursor(WhereX-1,WhereY-1);
|
|
end;
|
|
|
|
procedure TANSIBackgroundConsole.GotoXY(X,Y: integer);
|
|
var W: word;
|
|
begin
|
|
if Owner<>nil then
|
|
while Y>MaxVideoLine do
|
|
begin
|
|
Move(Owner^.Buffer[MaxViewWidth],Owner^.Buffer,SizeOf(Owner^.Buffer)-(MaxViewWidth*2));
|
|
W:=(MaxViewWidth*MaxVideoLine)-1-(MaxViewWidth);
|
|
FillChar(Owner^.Buffer[W],MaxViewWidth*2,0);
|
|
Dec(Y);
|
|
end;
|
|
inherited GotoXY(X,Y);
|
|
end;
|
|
|
|
constructor TANSIBackground.Init(var Bounds: TRect);
|
|
begin
|
|
inherited Init(Bounds,' ');
|
|
LockCount:=0;
|
|
GrowMode:=gfGrowHiX or gfGrowHiY;
|
|
New(Console, Init(@Self));
|
|
Console^.Size.X:=Bounds.B.X+1; Console^.Size.Y:=Bounds.B.Y+1;
|
|
Console^.ClrScr;
|
|
Console^.CursorOn;
|
|
end;
|
|
|
|
function TANSIBackground.LoadFile(const FileName: string): boolean;
|
|
var S: PBufStream;
|
|
OK: boolean;
|
|
B: array[0..1023] of char;
|
|
I,FragSize: integer;
|
|
begin
|
|
{$I-}
|
|
New(S, Init(FileName, stOpenRead, 4096));
|
|
OK:=Assigned(S);
|
|
while OK and (S^.Status=stOK) do
|
|
begin
|
|
FragSize:=Min(Sizeof(B),S^.GetSize-S^.GetPos);
|
|
if FragSize=0 then Break;
|
|
S^.Read(B,FragSize);
|
|
OK:=(S^.Status=stOK);
|
|
if OK then
|
|
for I:=0 to FragSize-1 do
|
|
self.Write(B[I]);
|
|
end;
|
|
if Assigned(S) then Dispose(S, Done); S:=nil;
|
|
{$I+}
|
|
LoadFile:=OK;
|
|
end;
|
|
|
|
procedure TANSIBackground.Draw;
|
|
var I: integer;
|
|
Pos: longint;
|
|
X,Y: integer;
|
|
begin
|
|
if LockCount<>0 then Exit;
|
|
for I:=0 to Size.Y-1 do
|
|
begin
|
|
Pos:=I*MaxViewWidth;
|
|
WriteLine(0,I,Size.X,1,Buffer[Pos]);
|
|
end;
|
|
if Console=nil then Exit;
|
|
X:=Console^.WhereX; Y:=Console^.WhereY;
|
|
if (X<0) or (Y<0) or (X>Size.X-1) or (Y>Size.X-1)
|
|
then HideCursor
|
|
else begin
|
|
ShowCursor;
|
|
SetCursor(X-1,Y-1);
|
|
end;
|
|
end;
|
|
|
|
procedure TANSIBackground.Write(Const S: string);
|
|
begin
|
|
Console^.Write(S);
|
|
DrawView;
|
|
end;
|
|
|
|
procedure TANSIBackground.WriteLn(Const S: string);
|
|
begin
|
|
Console^.WriteLn(S);
|
|
DrawView;
|
|
end;
|
|
|
|
procedure TANSIBackground.Lock;
|
|
begin
|
|
Inc(LockCount);
|
|
end;
|
|
|
|
procedure TANSIBackground.UnLock;
|
|
begin
|
|
Dec(LockCount);
|
|
if LockCount=0 then DrawView;
|
|
end;
|
|
|
|
procedure TANSIBackground.ChangeBounds(var Bounds: TRect);
|
|
begin
|
|
inherited ChangeBounds(Bounds);
|
|
{ Console^.Size.X:=Size.X; Console^.Size.Y:=Size.Y;}
|
|
end;
|
|
|
|
procedure TANSIBackground.HandleEvent(var Event: TEvent);
|
|
begin
|
|
inherited HandleEvent(Event);
|
|
{ if Event.What=evKeyDown then
|
|
begin
|
|
if VScrollBar<>nil then VScrollBar^.HandleEvent(Event);
|
|
if HScrollBar<>nil then HScrollBar^.HandleEvent(Event);
|
|
end;}
|
|
end;
|
|
|
|
destructor TANSIBackground.Done;
|
|
begin
|
|
Dispose(Console, Done);
|
|
inherited Done;
|
|
end;
|
|
|
|
END.
|