📄 tvdebug.pas
字号:
{************************************************}
{ }
{ Turbo Vision Debuging Unit }
{ Copyright (c) 1992 by Borland International }
{ }
{************************************************}
unit TVDebug;
interface
uses Objects, Drivers, Views, App, TextView;
const
cmTextWinAppendLine = 30000;
{ Custom options flag so TextInterior will know whether to scroll
its text as new lines are added or not. Uses an unused bit of the
TView options field. Default is not to scroll on append. }
ofScrollonAppend = $0400;
type
{ TApplication }
{ A debugging version of APP's TApplication that will create a
Event window and a Log window on the bottom of the desktop. }
TApplication = object(App.TApplication)
constructor Init;
procedure GetEvent(var E: TEvent); virtual;
end;
PApplication = ^TApplication;
{ TTextCollection }
{ Used internally by TTextInterior to hold the text to display }
PTextCollection = ^TTextCollection;
TTextCollection = object(TCollection)
procedure FreeItem(Item: Pointer); virtual;
end;
{ TTextInterior }
{ A scrolling view of the text stored in Lines. If the view recieves
a cmTextWinAppendLine as an evBroadcast the InfoPtr field is assumed
to contain a PString containing a new line to add to Lines. }
PTextInterior = ^TTextInterior;
TTextInterior = object(TScroller)
Lines: TTextCollection;
constructor Init( R: TRect; MaxLines: Integer;
AHScrollbar, AVScrollbar: PScrollbar);
destructor Done; virtual;
procedure Draw; virtual;
procedure HandleEvent(var E: TEvent); virtual;
end;
{ TTextWindow }
{ A window designed to contain a TTextInterior }
PTextWindow = ^TTextWindow;
TTextWindow = object(TWindow)
constructor Init(R: TRect; NewTitle: String; Num, MaxLines: Integer);
procedure MakeInterior( MaxLines: integer); virtual;
end;
{ TEventWindow }
{ A text window that will a list of the last MaxLines events
sent to it by DisplayEvent. TApplication above calls this
method upon receiving an event in GetEvent. If this unit
is included after Views in a unit, all Message calls in that
unit are also displayed. NOTE: only one of these windows is
allowed. If more than one is created the second will return
False from Valid causing InsertWindow to refuse to insert the
window in the desktop. }
PEventWindow = ^TEventWindow;
TEventWindow = object(TTextWindow)
Filters: Word;
constructor Init(var R: TRect; ATitle: String; Num, MaxLines: Integer);
destructor Done; virtual;
procedure DisplayEvent(var E: TEvent); virtual;
procedure FiltersDialog;
function GetPalette: PPalette; virtual;
procedure HandleEvent(var Event: TEvent); virtual;
procedure MakeInterior(Maxlines: Integer); virtual;
function Valid(Command: Word): Boolean; virtual;
end;
{ TLogWindow }
{ Creating a TLogWindow will redirect all Write and Writeln's to
the window. Only one of these windows should be created, if more
than one is create Valid will return False and InsertWindow will
refuse to insert the window into the desktop. }
PLogWindow = ^TLogWindow;
TLogWindow = object(TWindow)
Interior: PTerminal;
constructor Init(var Bounds: TRect; BufSize: Word);
destructor Done; virtual;
function Valid(Command: Word): Boolean; virtual;
end;
{ An alternate Message from View's that will log the message to the
event window before sending it. }
function Message(Receiver: PView; What, Command: Word;
InfoPtr: Pointer): Pointer;
implementation
uses Dos, Menus, Dialogs, KeyNamer, CmdNamer;
{ If you get a FILE NOT FOUND error when compiling this program
from a DOS IDE, change to the \BP\EXAMPLES\DOS\TVDEBUG directory
(use File|Change dir).
This will enable the compiler to find all of the units used by
this program.
}
var
EventWindow: PEventWindow;
{ TApplication }
constructor TApplication.Init;
var
R: TRect;
begin
inherited Init;
BuiltInCommandNames;
Desktop^.GetExtent(R);
R.Assign(R.A.X, R.B.Y-10, R.B.X div 2, R.B.Y);
InsertWindow(New(PEventWindow, Init(R, 'Event Window', wnNoNumber, 100)));
Desktop^.GetExtent(R);
R.Assign(R.B.X div 2, R.B.Y-10, R.B.X, R.B.Y);
InsertWindow(New(PLogWindow, Init(R, 1024)));
end;
procedure TApplication.GetEvent(var E: TEvent);
begin
inherited GetEvent(E);
if EventWindow <> nil then
EventWindow^.DisplayEvent(E);
end;
const
CEWMenu = #9#10#11#12#13#14;
{ TEWMenubox }
type
PEWMenubox = ^TEWMenubox;
TEWMenubox = object(TMenubox)
function GetPalette: PPalette; virtual;
end;
function TEWMenubox.GetPalette: PPalette;
const
P: String[length(CEWMenu)] = CEWMenu;
begin
GetPalette:= @P;
end;
{ TEWMenubar }
type
PEWMenubar = ^TEWMenubar;
TEWMenubar = object(TMenubar)
function GetPalette: PPalette; virtual;
function NewSubView(var Bounds: TRect; AMenu: PMenu;
AParentMenu: PMenuView): PMenuView; virtual;
end;
function TEWMenubar.GetPalette: PPalette;
const
P: string[length(CEWMenu)] = CEWMenu;
begin
GetPalette:= @P;
end;
function TEWMenubar.NewSubView(var Bounds: TRect; AMenu: PMenu;
AParentMenu: PMenuView): PMenuView;
begin
NewSubView := New(PEWMenuBox, Init(Bounds, AMenu, AParentMenu));
end;
{ TTextCollection }
procedure TTextCollection.FreeItem(Item: Pointer);
begin
DisposeStr(Item);
end;
{ TTextInterior }
constructor TTextInterior.Init( R: TRect; MaxLines: Integer;
AHScrollbar, AVScrollbar: PScrollbar);
begin
inherited Init(R, AHScrollbar, AVScrollbar);
if MaxLines = 0 then
Lines.Init(Size.X, 1) { let it grow unchecked: 16K items max}
else
Lines.Init(Maxlines, 0); { fix size and rollover when full }
SetLimit(128,Size.X);
GrowMode:= gfGrowHiX + gfGrowHiY;
end;
destructor TTextInterior.Done;
begin
Lines.Done;
inherited Done;
end;
procedure TTextInterior.Draw;
var
color: byte;
Y, I: Integer;
B: TDrawBuffer;
begin { draw only what's visible }
Color:= GetColor(1);
for y:= 0 to Size.Y-1 do
begin
MoveChar(B,' ',Color,Size.X);
I:= Delta.Y+Y;
if (I < Lines.Count) and (Lines.At(I) <> nil) then
MoveStr(B, Copy(PString(Lines.At(I))^,Delta.X+1, Size.X), Color);
WriteLine(0,Y,Size.X,1,B);
end;
end;
procedure TTextInterior.HandleEvent(var E: TEvent);
begin
inherited HandleEvent(E);
case E.What of
evBroadcast:
case E.Command of
cmTextWinAppendLine:
begin
if Lines.Count < Lines.Limit then { let it grow }
begin
Lines.Insert(E.Infoptr);
if Lines.Count > Size.Y then
begin
SetLimit(128,Lines.Count);
if (Owner <> nil) and
((Owner^.Options and ofScrollonAppend) <> 0) then
VScrollbar^.SetValue(Lines.Count);
end;
end
else
begin
Lines.AtFree(0); { zap the first item }
Lines.Insert(E.InfoPtr); { before adding new one }
end;
DrawView;
end { show the changes }
else
Exit;
end;
else
Exit;
end;
ClearEvent(E);
end;
{ TTextWindow }
constructor TTextWindow.Init( R: TRect; NewTitle: String;
Num, MaxLines: Integer);
begin
inherited Init(R,NewTitle, Num);
MakeInterior(MaxLines);
end;
procedure TTextWindow.MakeInterior( MaxLines: Integer);
var
R: TRect;
begin
GetExtent(R);
R.Grow(-1, -1);
Insert(New(PTextInterior, Init(R, MaxLines,
StandardScrollBar(sbHorizontal),
StandardScrollBar(sbVertical))));
end;
{ TEventWindow }
const
cmEventFilters = 503;
constructor TEventWindow.Init(var R: TRect; ATitle: String; Num,
Maxlines: Integer);
begin
inherited Init(R, ATitle, Num, MaxLines);
{ custom option flag for TextWindow's interior}
Options:= Options or (ofScrollOnAppend + ofFirstClick);
Filters := evMouse or evKeyBoard or evMessage;
EventWindow := @Self;
end;
destructor TEventWindow.Done;
begin
inherited Done;
EventWindow := nil;
end;
procedure TEventWindow.DisplayEvent(var E: TEvent);
var
st,xs,ys: String;
Event: Word;
begin
st:='';
if State and sfSelected = 0 then
begin
Event := E.What and Filters;
case Event of
evNothing: Exit;
evMouseDown,
evMouseUp,
evMouseMove,
evMouseAuto:
begin
st := 'Mouse ';
case E.What of
evMouseDown: st := st + 'Down, ';
evMouseUp: st := st + 'Up, ';
evMouseMove: st := st + 'Move, ';
evMouseAuto: st := st + 'Auto, ';
end;
case E.Buttons of
mbLeftButton: st := st + 'Left Button, ';
mbRightButton: st := st + 'Right Button, ';
$04: st := st + 'Center Button, ';
end;
if (E.Buttons <> 0) and E.Double then
st := st +'Double Click ';
Str(E.Where.X:0, xs);
Str(E.Where.Y:0, ys);
st := st + 'X:' + xs + ' Y:' + ys;
end;
evKeyDown:
begin
st := KeyName(E.KeyCode);
if st = '' then
st := KeyName(Word(E.CharCode));
st := 'Keyboard ' + st;
end;
evCommand,
evBroadcast:
begin
if E.What = evCommand then
st := 'Command '
else
st := 'Broadcast ';
St := Concat(St, CommandName(E.Command));
end;
else
Str(E.What:0, xs);
st := 'Unknown Event.What: ' + xs;
end; {case}
Views.Message(@Self, evBroadcast, cmTextWinAppendLine, NewStr(st));
end; { if }
end;
procedure TEventWindow.FiltersDialog;
var
D: PDialog;
R: TRect;
DataRec: Word;
begin
R.Assign(10,6,40,20);
D := New(PDialog, Init(R, 'Message Filters'));
with D^ do
begin
R.Assign(7,2,22,10);
Insert(New(PCheckBoxes, Init(R,
NewSItem('Mouse ~D~own',
NewSItem('Mouse ~U~p',
NewSItem('Mouse ~M~ove',
NewSItem('Mouse ~A~uto',
NewSItem('~K~eyboard',
NewSItem('~C~ommand',
NewSItem('~B~roadcast',
NewSItem('~O~ther', nil)))))))))));
R.Assign(5,11,13,13);
Insert(New(PButton, Init(R, 'Ok', cmOk, bfDefault)));
R.Assign(14,11,24,13);
Insert(New(PButton, Init(R, 'Cancel', cmCancel, bfNormal)));
SelectNext(False);
end;
{ transfer data from filters to a more linear datarec }
DataRec := 0;
DataRec := Filters and (evMouse or evKeyDown);
DataRec := DataRec or ((Filters - DataRec) shr 3);
if Application^.ExecuteDialog(D, @DataRec) <> cmCancel then
begin
Filters := 0;
Filters := DataRec and (evMouse or evKeyDown);
Filters := Filters or ((DataRec - Filters) shl 3);
end;
end;
function TEventWindow.GetPalette: PPalette;
const
P: String[length(CBlueWindow)+ length(CMenuView)] = CBlueWindow + CMenuView;
begin
GetPalette := @P;
end;
procedure TEventWindow.HandleEvent(var Event: TEvent);
begin
inherited HandleEvent(Event);
if (Event.What = evCommand) and (Event.Command = cmEventFilters) then
begin
FiltersDialog;
ClearEvent(Event);
end;
end;
procedure TEventWindow.MakeInterior(Maxlines: Integer);
var
R: TRect;
M: PMenubar;
begin
GetExtent(R);
R.Grow(-1,-1);
R.B.Y:= R.A.Y+1;
Insert(New(PEWMenubar, Init(R, NewMenu(
NewSubMenu('~O~ptions', hcNoContext, NewMenu(
NewItem('~F~ilters', '', 0, cmEventFilters, hcNoContext, nil)),
nil)))));
GetExtent(R);
R.Grow(-1, -1);
Inc(R.A.Y);
Insert(New(PTextInterior, Init(R, MaxLines,
StandardScrollBar(sbHorizontal+sbHandleKeyboard),
StandardScrollBar(sbVertical+sbHandleKeyboard))));
end;
function TEventWindow.Valid(Command: Word): Boolean;
begin
if inherited Valid(Command) then
Valid := EventWindow = @Self
else
Valid := False;
end;
{ TLogWindow }
function AssignedTo(var T: Text; View: PTextDevice): Boolean;
begin
AssignedTo := Pointer((@TextRec(T).UserData)^) = View;
end;
constructor TLogWindow.Init(var Bounds: TRect; BufSize: Word);
var
R: TRect;
vSB, hSB: PScrollBar;
begin
inherited Init(Bounds, 'Messages Log', wnNoNumber);
vSB := StandardScrollBar(sbVertical + sbHandleKeyboard);
Insert(vSB);
hsb := StandardScrollBar(sbHorizontal + sbHandleKeyboard);
Insert(hSB);
GetExtent(R);
R.Grow(-1, -1);
Interior := New(PTerminal, Init(R, hSB, vSB, BufSize));
Insert(Interior);
AssignDevice(Output, Interior);
Rewrite(Output);
end;
destructor TLogWindow.Done;
begin
if AssignedTo(Output, Interior) then
begin
Assign(Output, '');
Rewrite(Output);
end;
inherited Done;
end;
function TLogWindow.Valid(Command: Word): Boolean;
begin
Valid := AssignedTo(Output, Interior);
end;
{ Message }
function Message(Receiver: PView; What, Command: Word;
InfoPtr: Pointer): Pointer;
var
E: TEvent;
begin
E.What := What;
E.Command := Command;
E.Infoptr := Infoptr;
{ no point in displaying our own message to display an event...}
if (EventWindow <> nil) and (Command <> cmTextWinAppendLine) then
EventWindow^.DisplayEvent(E);
{ pass the intercepted data on to the Message function it was intended for }
Message:= Views.Message(Receiver, What, Command, InfoPtr);
end;
end.
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -