{ 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; {$H-} 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: AnsiChar); virtual; procedure WriteCharRaw(C: AnsiChar); 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: AnsiChar); 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: AnsiChar); 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: AnsiChar); 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: AnsiChar); virtual; procedure WriteCharRaw(C: AnsiChar); 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: AnsiChar); 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: AnsiChar); begin WriteChar(C); end; procedure TConsoleObject.WriteChar(C: AnsiChar); begin Abstract; end; procedure TConsoleObject.WriteCharRaw(C: AnsiChar); 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: AnsiChar); {var OK: boolean;} begin { OK:=((C>=#32) and (WhereX'' 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: AnsiChar); 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: AnsiChar); 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 AnsiChar; 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: AnsiChar); 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 AnsiChar; 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.