fpc/packages/ide/whlpview.pas
2024-10-09 18:40:28 +00:00

1442 lines
39 KiB
ObjectPascal

{
This file is part of the Free Pascal Integrated Development Environment
Copyright (c) 1998 by Berczi Gabor
Help display objects
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.
**********************************************************************}
unit WHlpView;
{$H-}
interface
uses
Objects,Drivers,Views,
FVConsts,
WEditor,WCEdit,
WUtils,WHelp;
type
TEditor = TCodeEditor;
PEditor = PCodeEditor;
const
cmPrevTopic = 90;
HistorySize = 30;
CHelpViewer = #33#34#35#36;
CHelpFrame = #37#37#38#38#39;
cmHelpFilesChanged = 57340;
type
PHelpLink = ^THelpLink;
THelpLink = record
Bounds : TRect;
FileID : longint;
Context : THelpCtx;
end;
PHelpColorArea = ^THelpColorArea;
THelpColorArea = record
Color : byte;
Bounds : TRect;
AttrMask : byte;
end;
PHelpKeyword = ^THelpKeyword;
THelpKeyword = record
KWord : PString;
Index : sw_integer;
end;
PLinkCollection = ^TLinkCollection;
TLinkCollection = object(TCollection)
procedure FreeItem(Item: Pointer); virtual;
end;
PColorAreaCollection = ^TColorAreaCollection;
TColorAreaCollection = object(TCollection)
procedure FreeItem(Item: Pointer); virtual;
end;
PKeywordCollection = ^TKeywordCollection;
TKeywordCollection = object({TSorted}TCollection)
function At(Index: sw_Integer): PHelpKeyword;
procedure FreeItem(Item: Pointer); virtual;
function Compare(Key1, Key2: Pointer): sw_Integer; virtual;
end;
{ TSearchRelation = (srEqual,srGreater,srLess,srGreatEqu,srLessEqu);
PAdvancedStringCollection = ^TAdvancedStringCollection;
TAdvancedStringCollection = object(TStringCollection)
function SearchItem(Key: pointer; Rel: TSearchRelation; var Index: integer): boolean; virtual;
end;}
PNamedMark = ^TNamedMark;
TNamedMark = object(TObject)
constructor Init(const AName: string; AX, AY: integer);
function GetName: string;
destructor Done; virtual;
private
Name: PString;
Pos: TPoint;
end;
PNamedMarkCollection = ^TNamedMarkCollection;
TNamedMarkCollection = object(TSortedCollection)
function At(Index: sw_Integer): PNamedMark;
function Compare(Key1, Key2: Pointer): sw_Integer; virtual;
function SearchMark(const Name: string): PNamedMark;
function GetMarkPos(const Name: string; var P: TPoint): boolean;
procedure Add(const Name: string; P: TPoint);
end;
PLinePosCollection = ^TLinePosCollection;
TLinePosCollection = object(TNoDisposeCollection)
function At(Index: sw_Integer): sw_integer;
procedure Insert (Item: pointer);virtual;
end;
PHelpTopic = ^THelpTopic;
THelpTopic = object(TObject)
Topic: PTopic;
Lines: PUnsortedStringCollection;
LinesPos: PLinePosCollection;
Links: PLinkCollection;
NamedMarks: PNamedMarkCollection;
ColorAreas: PColorAreaCollection;
public
constructor Init(ATopic: PTopic);
procedure SetParams(AMargin, AWidth: sw_integer); virtual;
function GetLineCount: sw_integer; virtual;
function GetLineText(Line: sw_integer): string; virtual;
function GetLinkCount: sw_integer; virtual;
procedure GetLinkBounds(Index: sw_integer; var R: TRect); virtual;
function GetLinkFileID(Index: sw_integer): word; virtual;
function GetLinkContext(Index: sw_integer): THelpCtx; virtual;
function GetColorAreaCount: sw_integer; virtual;
procedure GetColorAreaBounds(Index: sw_integer; var R: TRect); virtual;
function GetColorAreaColor(Index: sw_integer): word; virtual;
function GetColorAreaMask(Index: sw_integer): word; virtual;
destructor Done; virtual;
private
Width,Margin: sw_integer;
{ StockItem: boolean;}
procedure ReBuild;
end;
THelpHistoryEntry = record
Context_ : THelpCtx;
Delta_ : TPoint;
CurPos_ : TPoint;
CurLink_ : sw_integer;
FileID_ : word;
end;
PHelpViewer = ^THelpViewer;
THelpViewer = object(TEditor)
Margin: sw_integer;
HelpTopic: PHelpTopic;
CurLink: sw_integer;
constructor Init(var Bounds: TRect; AHScrollBar, AVScrollBar: PScrollBar);
procedure ChangeBounds(var Bounds: TRect); virtual;
procedure Draw; virtual;
procedure HandleEvent(var Event: TEvent); virtual;
procedure SetCurPtr(X,Y: sw_integer); virtual;
function GetLineCount: sw_integer; virtual;
function GetLine(LineNo: sw_integer): PCustomLine; virtual;
function GetLineText(Line: sw_integer): sw_astring; virtual;
function GetDisplayText(I: sw_integer): sw_astring; virtual;
function GetLinkCount: sw_integer; virtual;
procedure GetLinkBounds(Index: sw_integer; var R: TRect); virtual;
function GetLinkFileID(Index: sw_integer): word; virtual;
function GetLinkContext(Index: sw_integer): THelpCtx; virtual;
function GetLinkTarget(Index: sw_integer): string; virtual;
function GetLinkText(Index: sw_integer): string; virtual;
function GetColorAreaCount: sw_integer; virtual;
procedure GetColorAreaBounds(Index: sw_integer; var R: TRect); virtual;
function GetColorAreaColor(Index: sw_integer): word; virtual;
function GetColorAreaMask(Index: sw_integer): word; virtual;
procedure SelectNextLink(ANext: boolean); virtual;
procedure SwitchToIndex; virtual;
procedure SwitchToTopic(SourceFileID: word; Context: THelpCtx); virtual;
procedure SetTopic(Topic: PTopic); virtual;
procedure SetCurLink(Link: sw_integer); virtual;
procedure SelectLink(Index: sw_integer); virtual;
procedure PrevTopic; virtual;
procedure RenderTopic; virtual;
procedure Lookup(S: string); virtual;
function GetPalette: PPalette; virtual;
constructor Load(var S: TStream);
procedure Store(var S: TStream);
destructor Done; virtual;
private
History : array[0..HistorySize] of THelpHistoryEntry;
HistoryPtr : integer;
WordList : PKeywordCollection;
Lookupword : string;
InLookUp : boolean;
IndexTopic : PTopic;
IndexHelpTopic: PHelpTopic;
function LinkContainsPoint(var R: TRect; var P: TPoint): boolean;
procedure ISwitchToTopic(SourceFileID: word; Context: THelpCtx; RecordInHistory: boolean);
procedure ISwitchToTopicPtr(P: PTopic; RecordInHistory: boolean);
procedure BuildTopicWordList;
end;
PHelpFrame = ^THelpFrame;
THelpFrame = object(TFrame)
function GetPalette: PPalette; virtual;
end;
PHelpWindow = ^THelpWindow;
THelpWindow = object(TWindow)
HSB,VSB : PScrollBar;
HelpView: PHelpViewer;
HideOnClose: boolean;
constructor Init(var Bounds: TRect; ATitle: TTitleStr; ASourceFileID: word; AContext: THelpCtx; ANumber: Integer);
procedure InitFrame; virtual;
procedure InitScrollBars; virtual;
procedure InitHelpView; virtual;
procedure ShowIndex; virtual;
procedure ShowDebugInfos; virtual;
procedure ShowTopic(SourceFileID: word; Context: THelpCtx); virtual;
procedure HandleEvent(var Event: TEvent); virtual;
procedure Close; virtual;
function GetPalette: PPalette; virtual; { needs to be overridden }
end;
implementation
uses
Video,
WConsts;
const CommentColor = Blue;
function NewLink(FileID: longint; Topic: THelpCtx; StartP, EndP: TPoint): PHelpLink;
var P: PHelpLink;
begin
New(P); FillChar(P^, SizeOf(P^), 0);
P^.FileID:=FileID;
P^.Context:=Topic; P^.Bounds.A:=StartP; P^.Bounds.B:=EndP;
NewLink:=P;
end;
procedure DisposeLink(P: PHelpLink);
begin
if P<>nil then Dispose(P);
end;
function NewColorArea(Color, AttrMask: byte; StartP, EndP: TPoint): PHelpColorArea;
var P: PHelpColorArea;
begin
New(P); FillChar(P^, SizeOf(P^), 0);
P^.Color:=Color; P^.AttrMask:=AttrMask;
P^.Bounds.A:=StartP; P^.Bounds.B:=EndP;
NewColorArea:=P;
end;
procedure DisposeColorArea(P: PHelpColorArea);
begin
if P<>nil then Dispose(P);
end;
function NewKeyword(Index: sw_integer; KWord: string): PHelpKeyword;
var P: PHelpKeyword;
begin
New(P); FillChar(P^, SizeOf(P^), 0);
P^.Index:=Index; P^.KWord:=NewStr(KWord);
NewKeyword:=P;
end;
procedure DisposeKeyword(P: PHelpKeyword);
begin
if P<>nil then
begin
if P^.KWord<>nil then DisposeStr(P^.KWord);
Dispose(P);
end;
end;
procedure TLinkCollection.FreeItem(Item: Pointer);
begin
if Item<>nil then DisposeLink(Item);
end;
procedure TColorAreaCollection.FreeItem(Item: Pointer);
begin
if Item<>nil then DisposeColorArea(Item);
end;
function TKeywordCollection.At(Index: sw_Integer): PHelpKeyword;
begin
At:=inherited At(Index);
end;
procedure TKeywordCollection.FreeItem(Item: Pointer);
begin
if Item<>nil then DisposeKeyword(Item);
end;
function TKeywordCollection.Compare(Key1, Key2: Pointer): sw_Integer;
var R: sw_integer;
K1: PHelpKeyword absolute Key1;
K2: PHelpKeyword absolute Key2;
S1,S2: string;
begin
S1:=UpcaseStr(K1^.KWord^); S2:=UpcaseStr(K2^.KWord^);
if S1<S2 then R:=-1 else
if S1>S2 then R:=1 else
R:=0;
Compare:=R;
end;
{function TAdvancedStringCollection.SearchItem(Key: pointer; Rel: TSearchRelation; var Index: sw_integer): boolean;
var
L, H, I, C: sw_Integer;
const resSmaller = -1; resEqual = 0; resGreater = 1;
begin
Index:=-1;
case Rel of
srEqual :
while (L <= H) and (Index=-1) do
begin
I := (L + H) shr 1;
C := Compare(KeyOf(Items^[I]), Key);
if C = resSmaller then L := I + 1 else
begin
H := I - 1;
if C = resEqual then
begin
if not Duplicates then L := I;
Index := L;
end;
end;
end;
srGreater :
begin
end;
srLess :
;
srGreatEqu :
;
srLessEqu :
;
else Exit;
end;
Search:=Index<>-1;
end;}
constructor TNamedMark.Init(const AName: string; AX, AY: integer);
begin
inherited Init;
Name:=NewStr(AName);
Pos.X:=AX; Pos.Y:=AY;
end;
function TNamedMark.GetName: string;
begin
GetName:=GetStr(Name);
end;
destructor TNamedMark.Done;
begin
if Assigned(Name) then DisposeStr(Name); Name:=nil;
inherited Done;
end;
function TNamedMarkCollection.At(Index: sw_Integer): PNamedMark;
begin
At:=inherited At(Index);
end;
function TNamedMarkCollection.Compare(Key1, Key2: Pointer): sw_Integer;
var K1: PNamedMark absolute Key1;
K2: PNamedMark absolute Key2;
R: integer;
N1,N2: string;
begin
N1:=UpcaseStr(K1^.GetName); N2:=UpcaseStr(K2^.GetName);
if N1<N2 then R:=-1 else
if N1>N2 then R:= 1 else
R:=0;
Compare:=R;
end;
function TNamedMarkCollection.SearchMark(const Name: string): PNamedMark;
var M,P: PNamedMark;
I: sw_integer;
begin
New(M, Init(Name,0,0));
if Search(M,I)=false then P:=nil else
P:=At(I);
Dispose(M, Done);
SearchMark:=P;
end;
function TNamedMarkCollection.GetMarkPos(const Name: string; var P: TPoint): boolean;
var M: PNamedMark;
begin
M:=SearchMark(Name);
if Assigned(M) then
P:=M^.Pos;
GetMarkPos:=Assigned(M);
end;
procedure TNamedMarkCollection.Add(const Name: string; P: TPoint);
begin
Insert(New(PNamedMark, Init(Name, P.X, P.Y)));
end;
function TLinePosCollection.At(Index: sw_Integer): sw_integer;
begin
at := longint (inherited at(Index));
end;
procedure TLinePosCollection.Insert (Item: pointer);
begin
Inherited Insert(Item);
end;
constructor THelpTopic.Init(ATopic: PTopic);
begin
inherited Init;
Topic:=ATopic;
New(Lines, Init(100,100));
New(LinesPos, Init(100,100));
New(Links, Init(50,50));
New(ColorAreas, Init(50,50));
New(NamedMarks, Init(10,10));
end;
procedure THelpTopic.SetParams(AMargin, AWidth: sw_integer);
begin
if Width<>AWidth then
begin
Width:=AWidth; Margin:=AMargin;
ReBuild;
end;
end;
procedure THelpTopic.ReBuild;
var TextPos,LinePos,LinkNo,NamedMarkNo: sw_word;
Line,CurWord: string;
C: AnsiChar;
InLink,InCodeArea,InColorArea,InImage: boolean;
LinkStart,LinkEnd,CodeAreaStart,CodeAreaEnd: TPoint;
ColorAreaStart,ColorAreaEnd: TPoint;
ColorAreaType: (atText,atFull);
CurPos: TPoint;
ZeroLevel: sw_integer;
LineStart,NextLineStart: sw_integer;
LineAlign : (laLeft,laCenter,laRight);
FirstLink,LastLink: sw_integer;
AreaColor: word;
NextByte: (nbNormal,nbAreaColor,nbDirect);
procedure ClearLine;
begin
Line:='';
end;
procedure AddWord(TheWord: string); forward;
procedure NextLine;
var P: sw_integer;
I,Delta: sw_integer;
begin
Line:=CharStr(' ',Margin)+Line;
if not InImage then
repeat
P:=Pos(#255,Line);
if P>0 then
Line[P]:=#32;
until P=0;
if Not InImage then
while copy(Line,length(Line),1)=' ' do
Delete(Line,length(Line),1);
Delta:=0;
if Line<>'' then
case LineAlign of
laLeft : ;
laCenter : if Margin+length(Line)+Margin<Width then
begin
Delta:=(Width-(Margin+length(Line)+Margin)) div 2;
Line:=CharStr(' ',Delta)+Line;
end;
laRight : if Margin+length(Line)+Margin<Width then
begin
Delta:=Width-(Margin+length(Line)+Margin);
Line:=CharStr(' ',Delta)+Line;
end;
end;
if (Delta>0) and (FirstLink<>LastLink) then
for I:=FirstLink to LastLink-1 do
with PHelpLink(Links^.At(I))^ do
Bounds.Move(Delta,0);
if Line='' then Line:=' ';
Lines^.Insert(NewStr(Line));
LinesPos^.Insert(pointer(LinePos));
ClearLine;
LineStart:=NextLineStart;
CurPos.X:=Margin+LineStart; Line:=CharStr(#255,LineStart); Inc(CurPos.Y);
if InLink then LinkStart:=CurPos;
FirstLink:=LastLink;
LinePos:=TextPos;
end;
procedure FlushLine;
var W: string;
begin
if CurWord<>'' then begin W:=CurWord; CurWord:=''; AddWord(W); end;
NextLine;
end;
procedure AddWord(TheWord: string);
var W: string;
begin
W:=TheWord;
while (length(W)>0) and (W[length(W)] in [' ',#255]) do
Delete(W,length(W),1);
if (copy(Line+TheWord,1,1)<>' ') then
if (Line<>'') and (Margin+length(Line)+length(W)+Margin>Width) and
not InImage then
NextLine;
Line:=Line+TheWord;
CurPos.X:=Margin+length(Line);
end;
procedure CheckZeroLevel;
begin
if ZeroLevel<>0 then
begin
if CurWord<>'' then AddWord(CurWord+' ');
CurWord:='';
ZeroLevel:=0;
end;
end;
procedure EndColorArea;
var Mask: word;
begin
if ColorAreaType=atText then Mask:=$f0 else Mask:=$00;
if CurWord<>'' then AddWord(CurWord); CurWord:='';
ColorAreaEnd:=CurPos; Dec(ColorAreaEnd.X);
ColorAreas^.Insert(NewColorArea(AreaColor,Mask,ColorAreaStart,ColorAreaEnd));
InColorArea:=false; AreaColor:=0;
end;
begin
Lines^.FreeAll; LinesPos^.FreeAll;
Links^.FreeAll; NamedMarks^.FreeAll; ColorAreas^.FreeAll;
if Topic=nil then Lines^.Insert(NewStr(msg_nohelpavailabelforthistopic)) else
begin
LineStart:=0; NextLineStart:=0;
TextPos:=0; ClearLine; CurWord:=''; Line:='';
CurPos.X:=Margin+LineStart; CurPos.Y:=0; LinkNo:=0;
NamedMarkNo:=0; LinePos:=0;
InLink:=false; InCodeArea:=false; InColorArea:=false;
InImage:=false;
ZeroLevel:=0;
LineAlign:=laLeft;
FirstLink:=0; LastLink:=0; NextByte:=nbNormal;
while (TextPos<Topic^.TextSize) or InImage do
begin
C:=chr(PByteArray(Topic^.Text)^[TextPos]);
case NextByte of
nbAreaColor :
begin
AreaColor:=ord(C);
NextByte:=nbNormal;
end;
nbDirect :
begin
NextByte:=nbNormal;
CurWord:=CurWord+C;
end;
nbNormal :
begin
case C of
hscLineBreak :
{if ZeroLevel=0 then ZeroLevel:=1 else
begin FlushLine; FlushLine; ZeroLevel:=0; end;}
if InLink then CurWord:=CurWord+' ' else
begin
NextLineStart:=0;
FlushLine;
LineStart:=0;
LineAlign:=laLeft;
end;
#1 : {Break};
hscLink :
begin
CheckZeroLevel;
if InLink=false then
begin LinkStart:=CurPos; InLink:=true; end else
begin
if CurWord<>'' then AddWord(CurWord); CurWord:='';
LinkEnd:=CurPos; Dec(LinkEnd.X);
if Topic^.Links<>nil then
begin
if LinkNo<Topic^.LinkCount then
begin
Inc(LastLink);
Links^.Insert(NewLink(Topic^.Links^[LinkNo].FileID,
Topic^.Links^[LinkNo].Context,LinkStart,LinkEnd));
end;
Inc(LinkNo);
end;
InLink:=false;
end;
end;
hscLineStart :
begin
NextLineStart:=length(Line)+length(CurWord);
{ LineStart:=LineStart+(NextLineStart-LineStart);}
end;
hscCode :
begin
if InCodeArea=false then
CodeAreaStart:=CurPos else
begin
if CurWord<>'' then AddWord(CurWord); CurWord:='';
CodeAreaEnd:=CurPos; Dec(CodeAreaEnd.X);
ColorAreas^.Insert(NewColorArea(CommentColor,$f0,CodeAreaStart,CodeAreaEnd));
end;
InCodeArea:=not InCodeArea;
end;
hscCenter :
LineAlign:=laCenter;
hscRight :
LineAlign:=laRight{was laCenter, typo error ? PM };
hscNamedMark :
begin
if NamedMarkNo<Topic^.NamedMarks^.Count then
NamedMarks^.Add(GetStr(Topic^.NamedMarks^.At(NamedMarkNo)),CurPos);
Inc(NamedMarkNo);
end;
hscTextAttr,hscTextColor :
begin
if InColorArea then
EndColorArea;
if C=hscTextAttr then
ColorAreaType:=atFull
else
ColorAreaType:=atText;
NextByte:=nbAreaColor;
ColorAreaStart:=CurPos;
InColorArea:=true;
end;
hscDirect :
NextByte:=nbDirect;
hscInImage :
begin
InImage := not InImage;
end;
hscNormText :
begin
if InColorArea then
EndColorArea;
end;
#32: if InLink then CurWord:=CurWord+C else
begin CheckZeroLevel; AddWord(CurWord+C); CurWord:=''; end;
else begin CheckZeroLevel; CurWord:=CurWord+C; end;
end;
end;
end;
CurPos.X:=Margin+length(Line)+length(CurWord);
Inc(TextPos);
end;
if (Line<>'') or (CurWord<>'') then FlushLine;
end;
end;
function THelpTopic.GetLineCount: sw_integer;
begin
GetLineCount:=Lines^.Count;
end;
function THelpTopic.GetLineText(Line: sw_integer): string;
var S: string;
begin
if Line<GetLineCount then S:=PString(Lines^.At(Line))^ else S:='';
GetLineText:=S;
end;
function THelpTopic.GetLinkCount: sw_integer;
begin
GetLinkCount:=Links^.Count;
end;
procedure THelpTopic.GetLinkBounds(Index: sw_integer; var R: TRect);
var P: PHelpLink;
begin
P:=Links^.At(Index);
R:=P^.Bounds;
end;
function THelpTopic.GetLinkFileID(Index: sw_integer): word;
var P: PHelpLink;
begin
P:=Links^.At(Index);
GetLinkFileID:=P^.FileID;
end;
function THelpTopic.GetLinkContext(Index: sw_integer): THelpCtx;
var P: PHelpLink;
begin
P:=Links^.At(Index);
GetLinkContext:=P^.Context;
end;
function THelpTopic.GetColorAreaCount: sw_integer;
begin
GetColorAreaCount:=ColorAreas^.Count;
end;
procedure THelpTopic.GetColorAreaBounds(Index: sw_integer; var R: TRect);
var P: PHelpColorArea;
begin
P:=ColorAreas^.At(Index);
R:=P^.Bounds;
end;
function THelpTopic.GetColorAreaColor(Index: sw_integer): word;
var P: PHelpColorArea;
begin
P:=ColorAreas^.At(Index);
GetColorAreaColor:=P^.Color;
end;
function THelpTopic.GetColorAreaMask(Index: sw_integer): word;
var P: PHelpColorArea;
begin
P:=ColorAreas^.At(Index);
GetColorAreaMask:=P^.AttrMask;
end;
destructor THelpTopic.Done;
begin
inherited Done;
Dispose(Lines, Done);
Dispose(LinesPos, Done);
Dispose(Links, Done);
Dispose(ColorAreas, Done);
Dispose(NamedMarks, Done);
if (Topic<>nil) then DisposeTopic(Topic);
end;
constructor THelpViewer.Init(var Bounds: TRect; AHScrollBar, AVScrollBar: PScrollBar);
begin
inherited Init(Bounds, AHScrollBar, AVScrollBar, nil, nil);
Flags:=efInsertMode or efPersistentBlocks;
ReadOnly:=true;
New(WordList, Init(50,50));
Margin:=1; CurLink:=-1;
end;
procedure THelpViewer.ChangeBounds(var Bounds: TRect);
var
LinePos,NewLineIndex,I : longint;
ymin, ymax : sw_integer;
prop : real;
begin
if Owner<>nil then Owner^.Lock;
ymin:=Delta.Y;
ymax:=ymin+Size.Y;
if ymax>ymin then
prop:=(CurPos.Y-ymin)/(ymax-ymin)
else
prop:=0;
inherited ChangeBounds(Bounds);
if (HelpTopic<>nil) and (HelpTopic^.Topic<>nil) and
(HelpTopic^.Topic^.FileID<>0) then
Begin
LinePos:=HelpTopic^.LinesPos^.At(CurPos.Y)+CurPos.X;
RenderTopic;
NewLineIndex:=-1;
For i:=0 to HelpTopic^.LinesPos^.Count-1 do
if LinePos<HelpTopic^.LinesPos^.At(i) then
begin
NewLineIndex:=i-1;
break;
end;
if NewLineIndex>=0 then
Begin
ymin:=NewLineIndex - trunc(prop * Size.Y);
if ymin<0 then
ymin:=0;
ScrollTo(0,ymin);
SetCurPtr(LinePos-HelpTopic^.LinesPos^.At(NewLineIndex),NewLineIndex);
End;
End;
if Owner<>nil then Owner^.UnLock;
end;
procedure THelpViewer.RenderTopic;
begin
if HelpTopic<>nil then
HelpTopic^.SetParams(Margin,Size.X);
SetLimit(255,GetLineCount);
DrawView;
end;
function THelpViewer.LinkContainsPoint(var R: TRect; var P: TPoint): boolean;
var OK: boolean;
begin
if (R.A.Y=R.B.Y) then
OK:= (P.Y=R.A.Y) and (R.A.X<=P.X) and (P.X<=R.B.X) else
OK:=
( (R.A.Y=P.Y) and (R.A.X<=P.X) ) or
( (R.A.Y<P.Y) and (P.Y<R.B.Y) ) or
( (R.B.Y=P.Y) and (P.X<=R.B.X) );
LinkContainsPoint:=OK;
end;
procedure THelpViewer.SetCurPtr(X,Y: sw_integer);
var OldCurLink,I: sw_integer;
OldPos,P: TPoint;
R: TRect;
begin
OldPos:=CurPos;
OldCurLink:=CurLink;
inherited SetCurPtr(X,Y);
CurLink:=-1;
P:=CurPos;
for I:=0 to GetLinkCount-1 do
begin
GetLinkBounds(I,R);
if LinkContainsPoint(R,P) then
begin CurLink:=I; Break; end;
end;
if OldCurLink<>CurLink then DrawView;
if ((OldPos.X<>CurPos.X) or (OldPos.Y<>CurPos.Y)) and (InLookup=false) then
Lookup('');
end;
function THelpViewer.GetLineCount: sw_integer;
var Count: sw_integer;
begin
if HelpTopic=nil then Count:=0 else Count:=HelpTopic^.GetLineCount;
GetLineCount:=Count;
end;
function THelpViewer.GetLine(LineNo: sw_integer): PCustomLine;
begin
{Abstract; used in wcedit unit ! }
GetLine:=nil;
end;
function THelpViewer.GetDisplayText(I: sw_integer): sw_astring;
begin
GetDisplayText:=ExtractTabs(GetLineText(I),DefaultTabSize);
end;
function THelpViewer.GetLineText(Line: sw_integer): sw_astring;
var S: sw_astring;
begin
if HelpTopic=nil then S:='' else S:=HelpTopic^.GetLineText(Line);
GetLineText:=S;
end;
function THelpViewer.GetLinkCount: sw_integer;
var Count: sw_integer;
begin
if HelpTopic=nil then Count:=0 else Count:=HelpTopic^.GetLinkCount;
GetLinkCount:=Count;
end;
procedure THelpViewer.GetLinkBounds(Index: sw_integer; var R: TRect);
begin
HelpTopic^.GetLinkBounds(Index,R);
end;
function THelpViewer.GetLinkFileID(Index: sw_integer): word;
begin
GetLinkFileID:=HelpTopic^.GetLinkFileID(Index);
end;
function THelpViewer.GetLinkContext(Index: sw_integer): THelpCtx;
begin
GetLinkContext:=HelpTopic^.GetLinkContext(Index);
end;
function THelpViewer.GetLinkTarget(Index: sw_integer): string;
var
Ctx : THelpCtx;
ID : sw_integer;
begin
GetLinkTarget:='';
if HelpTopic=nil then begin ID:=0; Ctx:=0; end else
begin
ID:=GetLinkFileID(Index);
Ctx:=GetLinkContext(Index);
end;
GetLinkTarget:=HelpFacility^.GetTopicInfo(ID,CTx);
end;
function THelpViewer.GetLinkText(Index: sw_integer): string;
var S: string;
R: TRect;
Y,StartX,EndX: sw_integer;
begin
S:=''; GetLinkBounds(Index,R);
Y:=R.A.Y;
while (Y<=R.B.Y) do
begin
if Y=R.A.Y then StartX:=R.A.X else StartX:=Margin;
if Y=R.B.Y then EndX:=R.B.X else EndX:=High(S);
S:=S+copy(GetLineText(Y),StartX+1,EndX-StartX+1); { Note: AnsiString to ShortString convertino}
Inc(Y);
end;
GetLinkText:=S;
end;
function THelpViewer.GetColorAreaCount: sw_integer;
var Count: sw_integer;
begin
if HelpTopic=nil then Count:=0 else Count:=HelpTopic^.GetColorAreaCount;
GetColorAreaCount:=Count;
end;
procedure THelpViewer.GetColorAreaBounds(Index: sw_integer; var R: TRect);
begin
HelpTopic^.GetColorAreaBounds(Index,R);
end;
function THelpViewer.GetColorAreaColor(Index: sw_integer): word;
begin
GetColorAreaColor:=HelpTopic^.GetColorAreaColor(Index);
end;
function THelpViewer.GetColorAreaMask(Index: sw_integer): word;
begin
GetColorAreaMask:=HelpTopic^.GetColorAreaMask(Index);
end;
procedure THelpViewer.SelectNextLink(ANext: boolean);
var I,Link: sw_integer;
R: TRect;
begin
if HelpTopic=nil then Exit;
Link:=CurLink;
if Link<>-1 then
begin
if ANext then
begin Inc(Link); if Link>=GetLinkCount then Link:=0; end else
begin Dec(Link); if Link=-1 then Link:=GetLinkCount-1; end;
end else
for I:=0 to GetLinkCount-1 do
begin
GetLinkBounds(I,R);
if (R.A.Y>CurPos.Y) or
(R.A.Y=CurPos.Y) and (R.A.X>CurPos.X) then
begin Link:=I; Break; end;
end;
if (Link=-1) and (GetLinkCount>0) then
if ANext then Link:=0
else Link:=GetLinkCount-1;
SetCurLink(Link);
end;
procedure THelpViewer.SetCurLink(Link: sw_integer);
var R: TRect;
begin
if Link<>-1 then
begin
GetLinkBounds(Link,R);
SetCurPtr(R.A.X,R.A.Y);
TrackCursor(do_centre);
{St:=GetLinkTarget(Link);
If St<>'' then
SetTitle('Help '+St);}
end;
end;
procedure THelpViewer.SwitchToIndex;
begin
if IndexTopic=nil then
IndexTopic:=HelpFacility^.BuildIndexTopic;
ISwitchToTopicPtr(IndexTopic,true);
end;
procedure THelpViewer.SwitchToTopic(SourceFileID: word; Context: THelpCtx);
begin
ISwitchToTopic(SourceFileID,Context,true);
end;
procedure THelpViewer.ISwitchToTopic(SourceFileID: word; Context: THelpCtx; RecordInHistory: boolean);
var P: PTopic;
begin
if HelpFacility=nil then P:=nil else
if (SourceFileID=0) and (Context=0) and (HelpTopic<>nil) then
P:=IndexTopic else
P:=HelpFacility^.LoadTopic(SourceFileID, Context);
ISwitchToTopicPtr(P,RecordInHistory);
end;
procedure THelpViewer.ISwitchToTopicPtr(P: PTopic; RecordInHistory: boolean);
var HistoryFull: boolean;
begin
if (P<>nil) and RecordInHistory and (HelpTopic<>nil) then
begin
HistoryFull:=HistoryPtr>=HistorySize;
if HistoryFull then
Move(History[1],History[0],SizeOf(History)-SizeOf(History[0]));
with History[HistoryPtr] do
begin
{SourceTopic_:=SourceTopic; }Context_:=HelpTopic^.Topic^.HelpCtx;
FileID_:=HelpTopic^.Topic^.FileID;
Delta_:=Delta; CurPos_:=CurPos; CurLink_:=CurLink;
end;
if HistoryFull=false then Inc(HistoryPtr);
end;
if Owner<>nil then Owner^.Lock;
SetTopic(P);
DrawView;
if Owner<>nil then Owner^.UnLock;
end;
procedure THelpViewer.PrevTopic;
begin
if HistoryPtr>0 then
begin
if Owner<>nil then Owner^.Lock;
Dec(HistoryPtr);
with History[HistoryPtr] do
begin
ISwitchToTopic(FileID_,Context_,false);
ScrollTo(Delta_.X,Delta_.Y);
SetCurPtr(CurPos_.X,CurPos_.Y);
TrackCursor(do_not_centre);
if CurLink<>CurLink_ then SetCurLink(CurLink_);
end;
DrawView;
if Owner<>nil then Owner^.UnLock;
end;
end;
procedure THelpViewer.SetTopic(Topic: PTopic);
var Bookmark: string;
P: TPoint;
begin
CurLink:=-1;
if (HelpTopic=nil) or (Topic<>HelpTopic^.Topic) then
begin
if (HelpTopic<>nil) and (HelpTopic<>IndexHelpTopic) then
Dispose(HelpTopic, Done);
HelpTopic:=nil;
if Topic<>nil then
begin
if (Topic=IndexTopic) and (IndexHelpTopic<>nil) then
HelpTopic:=IndexHelpTopic else
New(HelpTopic, Init(Topic));
if Topic=IndexTopic then
IndexHelpTopic:=HelpTopic;
end;
end;
if Owner<>nil then
Owner^.Lock;
SetCurPtr(0,0);
TrackCursor(do_not_centre);
RenderTopic;
BuildTopicWordList;
Lookup('');
if Assigned(Topic) then
if Topic^.StartNamedMark>0 then
if Topic^.NamedMarks^.Count>=Topic^.StartNamedMark then
begin
Bookmark:=GetStr(Topic^.NamedMarks^.At(Topic^.StartNamedMark-1));
if HelpTopic^.NamedMarks^.GetMarkPos(Bookmark,P) then
begin
SetCurPtr(P.X,P.Y);
ScrollTo(0,Max(0,P.Y-1));
end;
end;
SetSelection(CurPos,CurPos);
DrawView;
if Owner<>nil then Owner^.UnLock;
end;
procedure THelpViewer.BuildTopicWordList;
var I: sw_integer;
begin
WordList^.FreeAll;
for I:=0 to GetLinkCount-1 do
WordList^.Insert(NewKeyword(I,Trim(GetLinkText(I))));
end;
procedure THelpViewer.Lookup(S: string);
var Index, I: Sw_integer;
W: string;
OldLookup: string;
R: TRect;
P: PHelpKeyword;
begin
InLookup:=true;
OldLookup:=LookupWord;
S:=UpcaseStr(S);
Index:=-1;
I:=0; {J:=0;
while (J<GetLinkCount) do
begin
GetLinkBounds(J,R);
if (R.A.Y<CurPos.Y) or ((R.A.Y=CurPos.Y) and (R.B.X<CurPos.X))
then Inc(J) else
begin I:=J; Break; end;
end;}
if S='' then LookupWord:='' else
begin
while (Index=-1) and (I<WordList^.Count) do
begin
P:=WordList^.At(I);
if P^.KWord<>nil then
begin
W:=UpcaseStr(Trim(P^.KWord^));
if copy(W,1,length(S))=S then Index:=I;
end;
{ if W>S then Break else}
Inc(I);
end;
if Index<>-1 then
begin
W:=Trim(WordList^.At(Index)^.KWord^);
LookupWord:=copy(W,1,length(S));
end;
end;
if LookupWord<>OldLookup then
begin
if Index=-1 then SetCurLink(CurLink) else
begin
if Owner<>nil then Owner^.Lock;
P:=WordList^.At(Index);
S:=GetLinkText(P^.Index);
I:=Pos(LookupWord,S); if I=0 then I:=1;
GetLinkBounds(P^.Index,R);
SetCurPtr(R.A.X+(I-1)+length(Lookupword),R.A.Y);
CurLink:=P^.Index; DrawView;
TrackCursor(do_centre);
if Owner<>nil then Owner^.UnLock;
end;
end;
InLookup:=false;
end;
procedure THelpViewer.SelectLink(Index: sw_integer);
var ID: word;
Ctx: THelpCtx;
begin
if Index=-1 then Exit;
if HelpTopic=nil then begin ID:=0; Ctx:=0; end else
begin
ID:=GetLinkFileID(Index);
Ctx:=GetLinkContext(Index);
end;
SwitchToTopic(ID,Ctx);
end;
procedure THelpViewer.HandleEvent(var Event: TEvent);
var DontClear: boolean;
procedure GetMousePos(var P: TPoint);
begin
MakeLocal(Event.Where,P);
Inc(P.X,Delta.X); Inc(P.Y,Delta.Y);
end;
begin
case Event.What of
evMouseDown :
if MouseInView(Event.Where) then
if (Event.Buttons=mbLeftButton) and (Event.Double) then
begin
inherited HandleEvent(Event);
if CurLink<>-1 then
SelectLink(CurLink);
end;
evBroadcast :
case Event.Command of
cmHelpFilesChanged :
begin
if HelpTopic=IndexHelpTopic then HelpTopic:=nil;
IndexTopic:=nil;
if IndexHelpTopic<>nil then Dispose(IndexHelpTopic, Done);
IndexHelpTopic:=nil;
end;
end;
evCommand :
begin
DontClear:=false;
case Event.Command of
cmPrevTopic :
PrevTopic;
else DontClear:=true;
end;
if not DontClear then ClearEvent(Event);
end;
evKeyDown :
begin
DontClear:=false;
case Event.KeyCode of
kbTab :
SelectNextLink(true);
kbShiftTab :
begin
NoSelect:=true;
SelectNextLink(false);
NoSelect:=false;
end;
kbEnter :
if CurLink<>-1 then
SelectLink(CurLink);
kbBack,kbDel :
if Length(LookupWord)>0 then
Lookup(Copy(LookupWord,1,Length(LookupWord)-1));
else
case Event.CharCode of
#32..#255 :
begin
NoSelect:=true;
Lookup(LookupWord+Event.CharCode);
NoSelect:=false;
end;
else
DontClear:=true;
end;
end;
TrackCursor(do_not_centre);
if not DontClear then
ClearEvent(Event);
end;
end;
inherited HandleEvent(Event);
end;
procedure THelpViewer.Draw;
var NormalColor, LinkColor,
SelectColor, SelectionColor: word;
B: TDrawBuffer;
DX,DY,X,Y,I,MinX,MaxX,ScreenX: sw_integer;
LastLinkDrawn,LastColorAreaDrawn: sw_integer;
S: sw_astring;
R: TRect;
SelR : TRect;
C,Mask: word;
CurP: TPoint;
ANDSB,ORSB: word;
begin
if ELockFlag>0 then
begin
DrawCalled:=true;
Exit;
end;
DrawCalled:=false;
NormalColor:=GetColor(1); LinkColor:=GetColor(2);
SelectColor:=GetColor(3); SelectionColor:=GetColor(4);
SelR.A:=SelStart; SelR.B:=SelEnd;
LastLinkDrawn:=0; LastColorAreaDrawn:=0;
for DY:=0 to Size.Y-1 do
begin
Y:=Delta.Y+DY;
MoveChar(B,' ',NormalColor,Size.X);
if Y<GetLineCount then
begin
S:=GetLineText(Y);
S:=copy(S,Delta.X+1,Length(S));
S:=copy(S,1,MaxViewWidth);
MoveStr(B,S,NormalColor);
for I:=LastColorAreaDrawn to GetColorAreaCount-1 do
begin
GetColorAreaBounds(I,R);
if R.A.Y>Y then Break;
LastColorAreaDrawn:=I;
if Y=R.B.Y then MaxX:=R.B.X else MaxX:=(length(S)+Delta.X-1);
if Y=R.A.Y then MinX:=R.A.X else MinX:=0;
if (R.A.Y<=Y) and (Y<=R.B.Y) then
begin
C:=GetColorAreaColor(I);
Mask:=GetColorAreaMask(I);
for DX:=MinX to MaxX do
begin
X:=DX;
ScreenX:=X-(Delta.X);
if (ScreenX>=0) and (ScreenX<=High(B)) then
begin
{ CurP.X:=X; CurP.Y:=Y;
if LinkAreaContainsPoint(R,CurP) then}
(* B[ScreenX]:=(B[ScreenX] and $f0ff) or (C shl 8);*)
ANDSB:=(Mask shl 8)+$ff;
ORSB:=(C shl 8);
B[ScreenX]:=(B[ScreenX] and ANDSB) or ORSB;
end;
end;
end;
end;
for I:=LastLinkDrawn to GetLinkCount-1 do
begin
GetLinkBounds(I,R);
if R.A.Y>Y then Break;
LastLinkDrawn:=I;
if Y=R.B.Y then MaxX:=R.B.X else MaxX:=(length(S)-1);
if Y=R.A.Y then MinX:=R.A.X else MinX:=0;
if (R.A.Y<=Y) and (Y<=R.B.Y) then
for DX:=MinX to MaxX do
begin
X:=DX;
ScreenX:=X-(Delta.X);
if (ScreenX>=0) and (ScreenX<=High(B)) then
begin
CurP.X:=X; CurP.Y:=Y;
if LinkContainsPoint(R,CurP) then
if I=CurLink then C:=SelectColor else C:=LinkColor;
B[ScreenX]:=(B[ScreenX] and $ff) or (C shl 8);
end;
end;
end;
if ((SelR.A.X<>SelR.B.X) or (SelR.A.Y<>SelR.B.Y)) and (SelR.A.Y<=Y) and (Y<=SelR.B.Y) then
begin
if Y=SelR.A.Y then MinX:=SelR.A.X else MinX:=0;
if Y=SelR.B.Y then MaxX:=SelR.B.X-1 else MaxX:=High(string);
for DX:=MinX to MaxX do
begin
X:=DX;
ScreenX:=X-(Delta.X);
if (ScreenX>=0) and (ScreenX<High(B)) then
B[ScreenX]:=(B[ScreenX] and $0fff) or ((SelectionColor and $f0) shl 8);
end;
end;
end;
WriteLine(0,DY,Size.X,1,B);
end;
DrawCursor;
end;
function THelpViewer.GetPalette: PPalette;
const P: string[length(CHelpViewer)] = CHelpViewer;
begin
GetPalette:=@P;
end;
constructor THelpViewer.Load(var S: TStream);
begin
inherited Load(S);
end;
procedure THelpViewer.Store(var S: TStream);
begin
inherited Store(S);
end;
destructor THelpViewer.Done;
begin
if (HelpTopic<>nil) and (HelpTopic<>IndexHelpTopic) then
Dispose(HelpTopic, Done);
HelpTopic:=nil;
if IndexHelpTopic<>nil then
Dispose(IndexHelpTopic, Done);
IndexHelpTopic:=nil;
inherited Done;
if assigned(WordList) then
Dispose(WordList, Done);
end;
function THelpFrame.GetPalette: PPalette;
const P: string[length(CHelpFrame)] = CHelpFrame;
begin
GetPalette:=@P;
end;
constructor THelpWindow.Init(var Bounds: TRect; ATitle: TTitleStr; ASourceFileID: word; AContext: THelpCtx; ANumber: Integer);
begin
inherited Init(Bounds, ATitle, ANumber);
InitScrollBars;
if Assigned(HSB) then Insert(HSB);
if Assigned(VSB) then Insert(VSB);
InitHelpView;
if Assigned(HelpView) then
begin
if (ASourceFileID<>0) or (AContext<>0) then
ShowTopic(ASourceFileID, AContext);
Insert(HelpView);
end;
end;
procedure THelpWindow.ShowDebugInfos;
begin
{$ifdef DEBUG}
DebugMessage(GetTitle(255),'Generic Help window',1,1);
if HelpView^.CurLink<>-1 then
begin
DebugMessage('','Curlink is '+IntToStr(HelpView^.CurLink),1,1);
DebugMessage('',HelpView^.GetLinkTarget(HelpView^.CurLink),1,1);
end;
{$endif DEBUG}
end;
procedure THelpWindow.InitScrollBars;
var R: TRect;
begin
GetExtent(R); R.Grow(0,-1); R.A.X:=R.B.X-1;
New(VSB, Init(R)); VSB^.GrowMode:=gfGrowLoX+gfGrowHiX+gfGrowHiY;
GetExtent(R); R.Grow(-1,0); R.A.Y:=R.B.Y-1;
New(HSB, Init(R)); HSB^.GrowMode:=gfGrowLoY+gfGrowHiX+gfGrowHiY;
end;
procedure THelpWindow.InitHelpView;
var R: TRect;
begin
GetExtent(R); R.Grow(-1,-1);
New(HelpView, Init(R, HSB, VSB));
HelpView^.GrowMode:=gfGrowHiX+gfGrowHiY;
end;
procedure THelpWindow.InitFrame;
var R: TRect;
begin
GetExtent(R);
Frame:=New(PHelpFrame, Init(R));
end;
procedure THelpWindow.ShowIndex;
begin
HelpView^.SwitchToIndex;
end;
procedure THelpWindow.ShowTopic(SourceFileID: word; Context: THelpCtx);
begin
HelpView^.SwitchToTopic(SourceFileID, Context);
end;
procedure THelpWindow.HandleEvent(var Event: TEvent);
begin
case Event.What of
evKeyDown :
case Event.KeyCode of
kbEsc :
begin
Event.What:=evCommand; Event.Command:=cmClose;
end;
end;
end;
inherited HandleEvent(Event);
end;
procedure THelpWindow.Close;
begin
if HideOnClose then Hide else inherited Close;
end;
function THelpWindow.GetPalette: PPalette;
begin
GetPalette:=nil;
end;
END.