📄 helpfile.pas
字号:
{************************************************}
{ }
{ Turbo Vision Demo }
{ Copyright (c) 1992 by Borland International }
{ }
{************************************************}
unit HelpFile;
{$F+,O+,X+,S-,R-}
interface
uses Objects, Drivers, Views;
const
CHelpColor = #$37#$3F#$3A#$13#$13#$30#$3E#$1E;
CHelpBlackWhite = #$07#$0F#$07#$70#$70#$07#$0F#$70;
CHelpMonochrome = #$07#$0F#$07#$70#$70#$07#$0F#$70;
CHelpViewer = #6#7#8;
CHelpWindow = #128#129#130#131#132#133#134#135;
type
{ TParagraph }
PParagraph = ^TParagraph;
TParagraph = record
Next: PParagraph;
Wrap: Boolean;
Size: Word;
Text: record end;
end;
{ THelpTopic }
TCrossRef = record
Ref: Word;
Offset: Integer;
Length: Byte;
end;
PCrossRefs = ^TCrossRefs;
TCrossRefs = array[1..10000] of TCrossRef;
TCrossRefHandler = procedure (var S: TStream; XRefValue: Integer);
PHelpTopic = ^THelpTopic;
THelpTopic = object(TObject)
constructor Init;
constructor Load(var S: TStream);
destructor Done; virtual;
procedure AddCrossRef(Ref: TCrossRef);
procedure AddParagraph(P: PParagraph);
procedure GetCrossRef(I: Integer; var Loc: TPoint; var Length: Byte;
var Ref: Word);
function GetLine(Line: Integer): String;
function GetNumCrossRefs: Integer;
function NumLines: Integer;
procedure SetCrossRef(I: Integer; var Ref: TCrossRef);
procedure SetNumCrossRefs(I: Integer);
procedure SetWidth(AWidth: Integer);
procedure Store(var S: TStream);
private
Paragraphs: PParagraph;
NumRefs: Integer;
CrossRefs: PCrossRefs;
Width: Integer;
LastOffset: Integer;
LastLine: Integer;
LastParagraph: PParagraph;
function WrapText(var Text; Size: Integer; var Offset: Integer;
Wrap: Boolean): String;
end;
{ THelpIndex }
PIndexArray = ^TIndexArray;
TIndexArray = array[0..16380] of LongInt;
PContextArray = ^TContextArray;
TContextArray = array[0..16380] of Word;
PHelpIndex = ^THelpIndex;
THelpIndex = object(TObject)
constructor Init;
constructor Load(var S: TStream);
destructor Done; virtual;
function Position(I: Word): Longint;
procedure Add(I: Word; Val: Longint);
procedure Store(var S: TStream);
private
Size: Word;
Used: Word;
Contexts: PContextArray;
Index: PIndexArray;
function Find(I: Word): Word;
end;
{ THelpFile }
PHelpFile = ^THelpFile;
THelpFile = object(TObject)
Stream: PStream;
Modified: Boolean;
constructor Init(S: PStream);
destructor Done; virtual;
function GetTopic(I: Word): PHelpTopic;
function InvalidTopic: PHelpTopic;
procedure RecordPositionInIndex(I: Integer);
procedure PutTopic(Topic: PHelpTopic);
private
Index: PHelpIndex;
IndexPos: LongInt;
end;
{ THelpViewer }
PHelpViewer = ^THelpViewer;
THelpViewer = object(TScroller)
HFile: PHelpFile;
Topic: PHelpTopic;
Selected: Integer;
constructor Init(var Bounds: TRect; AHScrollBar,
AVScrollBar: PScrollBar; AHelpFile: PHelpFile; Context: Word);
destructor Done; virtual;
procedure ChangeBounds(var Bounds: TRect); virtual;
procedure Draw; virtual;
function GetPalette: PPalette; virtual;
procedure HandleEvent(var Event: TEvent); virtual;
end;
{ THelpWindow }
PHelpWindow = ^THelpWindow;
THelpWindow = object(TWindow)
constructor Init(HFile: PHelpFile; Context: Word);
function GetPalette: PPalette; virtual;
end;
const
RHelpTopic: TStreamRec = (
ObjType: 10000;
VmtLink: Ofs(TypeOf(THelpTopic)^);
Load: @THelpTopic.Load;
Store: @THelpTopic.Store
);
const
RHelpIndex: TStreamRec = (
ObjType: 10001;
VmtLink: Ofs(TypeOf(THelpIndex)^);
Load: @THelpIndex.Load;
Store: @THelpIndex.Store
);
procedure RegisterHelpFile;
procedure NotAssigned(var S: TStream; Value: Integer);
const
CrossRefHandler: TCrossRefHandler = NotAssigned;
implementation
{ THelpTopic }
constructor THelpTopic.Init;
begin
inherited Init;
LastLine := MaxInt;
end;
constructor THelpTopic.Load(var S: TStream);
procedure ReadParagraphs;
var
I, Size: Integer;
PP: ^PParagraph;
begin
S.Read(I, SizeOf(I));
PP := @Paragraphs;
while I > 0 do
begin
S.Read(Size, SizeOf(Size));
GetMem(PP^, SizeOf(PP^^) + Size);
PP^^.Size := Size;
S.Read(PP^^.Wrap, SizeOf(Boolean));
S.Read(PP^^.Text, Size);
PP := @PP^^.Next;
Dec(I);
end;
PP^ := nil;
end;
procedure ReadCrossRefs;
begin
S.Read(NumRefs, SizeOf(Integer));
GetMem(CrossRefs, SizeOf(TCrossRef) * NumRefs);
if CrossRefs <> nil then
S.Read(CrossRefs^, SizeOf(TCrossRef) * NumRefs);
end;
begin
ReadParagraphs;
ReadCrossRefs;
Width := 0;
LastLine := MaxInt;
end;
destructor THelpTopic.Done;
procedure DisposeParagraphs;
var
P, T: PParagraph;
begin
P := Paragraphs;
while P <> nil do
begin
T := P;
P := P^.Next;
FreeMem(T, SizeOf(T^) + T^.Size);
end;
end;
begin
DisposeParagraphs;
FreeMem(CrossRefs, SizeOf(TCrossRef) * NumRefs);
inherited Done
end;
procedure THelpTopic.AddCrossRef(Ref: TCrossRef);
var
P: PCrossRefs;
begin
GetMem(P, (NumRefs+1) * SizeOf(TCrossRef));
if NumRefs > 0 then
begin
Move(CrossRefs^, P^, NumRefs * SizeOf(TCrossRef));
FreeMem(CrossRefs, NumRefs * SizeOf(TCrossRef));
end;
CrossRefs := P;
CrossRefs^[NumRefs] := Ref;
Inc(NumRefs);
end;
procedure THelpTopic.AddParagraph(P: PParagraph);
var
PP: ^PParagraph;
begin
PP := @Paragraphs;
while PP^ <> nil do
PP := @PP^^.Next;
PP^ := P;
P^.Next := nil;
end;
procedure THelpTopic.GetCrossRef(I: Integer; var Loc: TPoint;
var Length: Byte; var Ref: Word);
var
OldOffset, CurOffset, Offset, ParaOffset: Integer;
P: PParagraph;
Line: Integer;
begin
ParaOffset := 0;
CurOffset := 0;
OldOffset := 0;
Line := 0;
Offset := CrossRefs^[I].Offset;
P := Paragraphs;
while ParaOffset+CurOffset < Offset do
begin
OldOffset := ParaOffset + CurOffset;
WrapText(P^.Text, P^.Size, CurOffset, P^.Wrap);
Inc(Line);
if CurOffset >= P^.Size then
begin
Inc(ParaOffset, P^.Size);
P := P^.Next;
CurOffset := 0;
end;
end;
Loc.X := Offset - OldOffset - 1;
Loc.Y := Line;
Length := CrossRefs^[I].Length;
Ref := CrossRefs^[I].Ref;
end;
function THelpTopic.GetLine(Line: Integer): String;
var
Offset, I: Integer;
P: PParagraph;
begin
if LastLine < Line then
begin
I := Line;
Dec(Line, LastLine);
LastLine := I;
Offset := LastOffset;
P := LastParagraph;
end
else
begin
P := Paragraphs;
Offset := 0;
LastLine := Line;
end;
GetLine := '';
while (P <> nil) do
begin
while Offset < P^.Size do
begin
Dec(Line);
GetLine := WrapText(P^.Text, P^.Size, Offset, P^.Wrap);
if Line = 0 then
begin
LastOffset := Offset;
LastParagraph := P;
Exit;
end;
end;
P := P^.Next;
Offset := 0;
end;
GetLine := '';
end;
function THelpTopic.GetNumCrossRefs: Integer;
begin
GetNumCrossRefs := NumRefs;
end;
function THelpTopic.NumLines: Integer;
var
Offset, Lines: Integer;
P: PParagraph;
begin
Offset := 0;
Lines := 0;
P := Paragraphs;
while P <> nil do
begin
Offset := 0;
while Offset < P^.Size do
begin
Inc(Lines);
WrapText(P^.Text, P^.Size, Offset, P^.Wrap);
end;
P := P^.Next;
end;
NumLines := Lines;
end;
procedure THelpTopic.SetCrossRef(I: Integer; var Ref: TCrossRef);
begin
if I <= NumRefs then CrossRefs^[I] := Ref;
end;
procedure THelpTopic.SetNumCrossRefs(I: Integer);
var
P: PCrossRefs;
begin
if NumRefs = I then Exit;
GetMem(P, I * SizeOf(TCrossRef));
if NumRefs > 0 then
begin
if I > NumRefs then Move(CrossRefs^, P^, NumRefs * SizeOf(TCrossRef))
else Move(CrossRefs^, P^, I * SizeOf(TCrossRef));
FreeMem(CrossRefs, NumRefs * SizeOf(TCrossRef));
end;
CrossRefs := P;
NumRefs := I;
end;
procedure THelpTopic.SetWidth(AWidth: Integer);
begin
Width := AWidth;
end;
procedure THelpTopic.Store(var S: TStream);
procedure WriteParagraphs;
var
I: Integer;
P: PParagraph;
begin
P := Paragraphs;
I := 0;
while P <> nil do
begin
Inc(I);
P := P^.Next;
end;
S.Write(I, SizeOf(I));
P := Paragraphs;
while P <> nil do
begin
S.Write(P^.Size, SizeOf(Integer));
S.Write(P^.Wrap, SizeOf(Boolean));
S.Write(P^.Text, P^.Size);
P := P^.Next;
end;
end;
procedure WriteCrossRefs;
var
I: Integer;
begin
S.Write(NumRefs, SizeOf(Integer));
if @CrossRefHandler = @NotAssigned then
S.Write(CrossRefs^, SizeOf(TCrossRef) * NumRefs)
else
for I := 1 to NumRefs do
begin
CrossRefHandler(S, CrossRefs^[I].Ref);
S.Write(CrossRefs^[I].Offset, SizeOf(Integer) + SizeOf(Byte));
end;
end;
begin
WriteParagraphs;
WriteCrossRefs;
end;
function THelpTopic.WrapText(var Text; Size: Integer;
var Offset: Integer; Wrap: Boolean): String;
type
PCArray = ^CArray;
CArray = array[0..32767] of Char;
var
Line: String;
I, P: Integer;
function IsBlank(Ch: Char): Boolean;
begin
IsBlank := (Ch = ' ') or (Ch = #13) or (Ch = #10);
end;
function Scan(var P; Offset, Size: Integer; C: Char): Integer; assembler;
asm
CLD
LES DI,P
ADD DI,&Offset
MOV DX,Size
SUB DX,&Offset
OR DH,DH
JZ @@1
MOV DX,256
@@1: MOV CX,DX
MOV AL, C
REPNE SCASB
SUB CX,DX
NEG CX
XCHG AX,CX
end;
procedure TextToLine(var Text; Offset, Length: Integer; var Line: String);
assembler;
asm
CLD
PUSH DS
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -