whlpview.pas 31 KB

12345678910111213141516171819202122232425262728293031323334353637383940414243444546474849505152535455565758596061626364656667686970717273747576777879808182838485868788899091929394959697989910010110210310410510610710810911011111211311411511611711811912012112212312412512612712812913013113213313413513613713813914014114214314414514614714814915015115215315415515615715815916016116216316416516616716816917017117217317417517617717817918018118218318418518618718818919019119219319419519619719819920020120220320420520620720820921021121221321421521621721821922022122222322422522622722822923023123223323423523623723823924024124224324424524624724824925025125225325425525625725825926026126226326426526626726826927027127227327427527627727827928028128228328428528628728828929029129229329429529629729829930030130230330430530630730830931031131231331431531631731831932032132232332432532632732832933033133233333433533633733833934034134234334434534634734834935035135235335435535635735835936036136236336436536636736836937037137237337437537637737837938038138238338438538638738838939039139239339439539639739839940040140240340440540640740840941041141241341441541641741841942042142242342442542642742842943043143243343443543643743843944044144244344444544644744844945045145245345445545645745845946046146246346446546646746846947047147247347447547647747847948048148248348448548648748848949049149249349449549649749849950050150250350450550650750850951051151251351451551651751851952052152252352452552652752852953053153253353453553653753853954054154254354454554654754854955055155255355455555655755855956056156256356456556656756856957057157257357457557657757857958058158258358458558658758858959059159259359459559659759859960060160260360460560660760860961061161261361461561661761861962062162262362462562662762862963063163263363463563663763863964064164264364464564664764864965065165265365465565665765865966066166266366466566666766866967067167267367467567667767867968068168268368468568668768868969069169269369469569669769869970070170270370470570670770870971071171271371471571671771871972072172272372472572672772872973073173273373473573673773873974074174274374474574674774874975075175275375475575675775875976076176276376476576676776876977077177277377477577677777877978078178278378478578678778878979079179279379479579679779879980080180280380480580680780880981081181281381481581681781881982082182282382482582682782882983083183283383483583683783883984084184284384484584684784884985085185285385485585685785885986086186286386486586686786886987087187287387487587687787887988088188288388488588688788888989089189289389489589689789889990090190290390490590690790890991091191291391491591691791891992092192292392492592692792892993093193293393493593693793893994094194294394494594694794894995095195295395495595695795895996096196296396496596696796896997097197297397497597697797897998098198298398498598698798898999099199299399499599699799899910001001100210031004100510061007100810091010101110121013101410151016101710181019102010211022102310241025102610271028102910301031103210331034103510361037103810391040104110421043104410451046104710481049105010511052105310541055105610571058105910601061106210631064106510661067106810691070107110721073107410751076107710781079108010811082108310841085108610871088108910901091109210931094109510961097109810991100110111021103110411051106110711081109111011111112111311141115111611171118111911201121112211231124112511261127112811291130113111321133113411351136113711381139114011411142
  1. {
  2. $Id$
  3. This file is part of the Free Pascal Integrated Development Environment
  4. Copyright (c) 1998 by Berczi Gabor
  5. Help display objects
  6. See the file COPYING.FPC, included in this distribution,
  7. for details about the copyright.
  8. This program is distributed in the hope that it will be useful,
  9. but WITHOUT ANY WARRANTY; without even the implied warranty of
  10. MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
  11. **********************************************************************}
  12. unit WHlpView;
  13. interface
  14. uses
  15. Objects,Drivers,Commands,Views,
  16. {$ifdef EDITORS}
  17. Editors,
  18. {$else}
  19. WEditor,
  20. {$endif}
  21. WHelp;
  22. {$IFNDEF EDITORS}
  23. type
  24. TEditor = TCodeEditor; PEditor = PCodeEditor;
  25. {$ENDIF}
  26. const
  27. cmPrevTopic = 90;
  28. HistorySize = 30;
  29. CHelpViewer = #33#34#35#36;
  30. CHelpFrame = #37#37#38#38#39;
  31. type
  32. PHelpLink = ^THelpLink;
  33. THelpLink = record
  34. Bounds : TRect;
  35. FileID : longint;
  36. Context : THelpCtx;
  37. end;
  38. PHelpColorArea = ^THelpColorArea;
  39. THelpColorArea = record
  40. Color : byte;
  41. Bounds : TRect;
  42. end;
  43. PHelpKeyword = ^THelpKeyword;
  44. THelpKeyword = record
  45. KWord : PString;
  46. Index : integer;
  47. end;
  48. PLinkCollection = ^TLinkCollection;
  49. TLinkCollection = object(TCollection)
  50. procedure FreeItem(Item: Pointer); virtual;
  51. end;
  52. PColorAreaCollection = ^TColorAreaCollection;
  53. TColorAreaCollection = object(TCollection)
  54. procedure FreeItem(Item: Pointer); virtual;
  55. end;
  56. PKeywordCollection = ^TKeywordCollection;
  57. TKeywordCollection = object({TSorted}TCollection)
  58. function At(Index: Integer): PHelpKeyword;
  59. procedure FreeItem(Item: Pointer); virtual;
  60. function Compare(Key1, Key2: Pointer): Integer; virtual;
  61. end;
  62. { TSearchRelation = (srEqual,srGreater,srLess,srGreatEqu,srLessEqu);
  63. PAdvancedStringCollection = ^TAdvancedStringCollection;
  64. TAdvancedStringCollection = object(TStringCollection)
  65. function SearchItem(Key: pointer; Rel: TSearchRelation; var Index: integer): boolean; virtual;
  66. end;}
  67. PHelpTopic = ^THelpTopic;
  68. THelpTopic = object(TObject)
  69. Topic: PTopic;
  70. Lines: PUnsortedStringCollection;
  71. Links: PLinkCollection;
  72. ColorAreas: PColorAreaCollection;
  73. constructor Init(ATopic: PTopic);
  74. procedure SetParams(AMargin, AWidth: integer); virtual;
  75. function GetLineCount: integer; virtual;
  76. function GetLineText(Line: integer): string; virtual;
  77. function GetLinkCount: integer; virtual;
  78. procedure GetLinkBounds(Index: integer; var R: TRect); virtual;
  79. function GetLinkFileID(Index: integer): word; virtual;
  80. function GetLinkContext(Index: integer): THelpCtx; virtual;
  81. function GetColorAreaCount: integer; virtual;
  82. procedure GetColorAreaBounds(Index: integer; var R: TRect); virtual;
  83. function GetColorAreaColor(Index: integer): word; virtual;
  84. destructor Done; virtual;
  85. private
  86. Width,Margin: integer;
  87. StockItem: boolean;
  88. procedure ReBuild;
  89. end;
  90. THelpHistoryEntry = record
  91. Context_ : THelpCtx;
  92. Delta_ : TPoint;
  93. CurPos_ : TPoint;
  94. CurLink_ : integer;
  95. FileID_ : word;
  96. end;
  97. PHelpViewer = ^THelpViewer;
  98. THelpViewer = object(TEditor)
  99. Margin: integer;
  100. HelpTopic: PHelpTopic;
  101. CurLink: integer;
  102. constructor Init(var Bounds: TRect; AHScrollBar, AVScrollBar: PScrollBar);
  103. procedure ChangeBounds(var Bounds: TRect); virtual;
  104. procedure Draw; virtual;
  105. procedure HandleEvent(var Event: TEvent); virtual;
  106. procedure SetCurPtr(X,Y: integer); virtual;
  107. function GetLineCount: integer; virtual;
  108. function GetLineText(Line: integer): string; virtual;
  109. function GetLinkCount: integer; virtual;
  110. procedure GetLinkBounds(Index: integer; var R: TRect); virtual;
  111. function GetLinkFileID(Index: integer): word; virtual;
  112. function GetLinkContext(Index: integer): THelpCtx; virtual;
  113. function GetLinkText(Index: integer): string; virtual;
  114. function GetColorAreaCount: integer; virtual;
  115. procedure GetColorAreaBounds(Index: integer; var R: TRect); virtual;
  116. function GetColorAreaColor(Index: integer): word; virtual;
  117. procedure SelectNextLink(ANext: boolean); virtual;
  118. procedure SwitchToIndex; virtual;
  119. procedure SwitchToTopic(SourceFileID: word; Context: THelpCtx); virtual;
  120. procedure SetTopic(Topic: PTopic); virtual;
  121. procedure SetCurLink(Link: integer); virtual;
  122. procedure SelectLink(Index: integer); virtual;
  123. procedure PrevTopic; virtual;
  124. procedure RenderTopic; virtual;
  125. procedure Lookup(S: string); virtual;
  126. function GetPalette: PPalette; virtual;
  127. destructor Done; virtual;
  128. private
  129. History : array[0..HistorySize] of THelpHistoryEntry;
  130. HistoryPtr : integer;
  131. WordList : PKeywordCollection;
  132. Lookupword : string;
  133. InLookUp : boolean;
  134. IndexTopic : PTopic;
  135. IndexHelpTopic: PHelpTopic;
  136. function LinkContainsPoint(var R: TRect; var P: TPoint): boolean;
  137. procedure ISwitchToTopic(SourceFileID: word; Context: THelpCtx; RecordInHistory: boolean);
  138. procedure ISwitchToTopicPtr(P: PTopic; RecordInHistory: boolean);
  139. procedure BuildTopicWordList;
  140. end;
  141. PHelpFrame = ^THelpFrame;
  142. THelpFrame = object(TFrame)
  143. function GetPalette: PPalette; virtual;
  144. end;
  145. PHelpWindow = ^THelpWindow;
  146. THelpWindow = object(TWindow)
  147. HelpView: PHelpViewer;
  148. HideOnClose: boolean;
  149. constructor Init(var Bounds: TRect; ATitle: TTitleStr; ASourceFileID: word; AContext: THelpCtx; ANumber: Integer);
  150. procedure InitFrame; virtual;
  151. procedure ShowIndex; virtual;
  152. procedure ShowTopic(SourceFileID: word; Context: THelpCtx); virtual;
  153. procedure HandleEvent(var Event: TEvent); virtual;
  154. procedure Close; virtual;
  155. function GetPalette: PPalette; virtual; { needs to be overriden }
  156. end;
  157. implementation
  158. uses
  159. Video;
  160. const CommentColor = Blue;
  161. function Min(A,B: longint): longint; begin if A<B then Min:=A else Min:=B; end;
  162. function Max(A,B: longint): longint; begin if A>B then Max:=A else Max:=B; end;
  163. function CharStr(C: char; Count: byte): string;
  164. var S: string;
  165. begin S[0]:=chr(Count); if Count>0 then FillChar(S[1],Count,C); CharStr:=S; end;
  166. function Trim(S: string): string;
  167. const TrimChars : set of char = [#0,#9,' ',#255];
  168. begin
  169. while (length(S)>0) and (S[1] in TrimChars) do Delete(S,1,1);
  170. while (length(S)>0) and (S[length(S)] in TrimChars) do Delete(S,length(S),1);
  171. Trim:=S;
  172. end;
  173. function UpcaseStr(S: string): string;
  174. var I: integer;
  175. begin
  176. for I:=1 to length(S) do
  177. S[I]:=Upcase(S[I]);
  178. UpcaseStr:=S;
  179. end;
  180. function NewLink(FileID: longint; Topic: THelpCtx; StartP, EndP: TPoint): PHelpLink;
  181. var P: PHelpLink;
  182. begin
  183. New(P); FillChar(P^, SizeOf(P^), 0);
  184. P^.FileID:=FileID;
  185. P^.Context:=Topic; P^.Bounds.A:=StartP; P^.Bounds.B:=EndP;
  186. NewLink:=P;
  187. end;
  188. procedure DisposeLink(P: PHelpLink);
  189. begin
  190. if P<>nil then Dispose(P);
  191. end;
  192. function NewColorArea(Color: byte; StartP, EndP: TPoint): PHelpColorArea;
  193. var P: PHelpColorArea;
  194. begin
  195. New(P); FillChar(P^, SizeOf(P^), 0);
  196. P^.Color:=Color; P^.Bounds.A:=StartP; P^.Bounds.B:=EndP;
  197. NewColorArea:=P;
  198. end;
  199. procedure DisposeColorArea(P: PHelpColorArea);
  200. begin
  201. if P<>nil then Dispose(P);
  202. end;
  203. function NewKeyword(Index: integer; KWord: string): PHelpKeyword;
  204. var P: PHelpKeyword;
  205. begin
  206. New(P); FillChar(P^, SizeOf(P^), 0);
  207. P^.Index:=Index; P^.KWord:=NewStr(KWord);
  208. NewKeyword:=P;
  209. end;
  210. procedure DisposeKeyword(P: PHelpKeyword);
  211. begin
  212. if P<>nil then
  213. begin
  214. if P^.KWord<>nil then DisposeStr(P^.KWord);
  215. Dispose(P);
  216. end;
  217. end;
  218. procedure TLinkCollection.FreeItem(Item: Pointer);
  219. begin
  220. if Item<>nil then DisposeLink(Item);
  221. end;
  222. procedure TColorAreaCollection.FreeItem(Item: Pointer);
  223. begin
  224. if Item<>nil then DisposeColorArea(Item);
  225. end;
  226. function TKeywordCollection.At(Index: Integer): PHelpKeyword;
  227. begin
  228. At:=inherited At(Index);
  229. end;
  230. procedure TKeywordCollection.FreeItem(Item: Pointer);
  231. begin
  232. if Item<>nil then DisposeKeyword(Item);
  233. end;
  234. function TKeywordCollection.Compare(Key1, Key2: Pointer): Integer;
  235. var R: integer;
  236. K1: PHelpKeyword absolute Key1;
  237. K2: PHelpKeyword absolute Key2;
  238. S1,S2: string;
  239. begin
  240. S1:=UpcaseStr(K1^.KWord^); S2:=UpcaseStr(K2^.KWord^);
  241. if S1<S2 then R:=-1 else
  242. if S1>S2 then R:=1 else
  243. R:=0;
  244. Compare:=R;
  245. end;
  246. {function TAdvancedStringCollection.SearchItem(Key: pointer; Rel: TSearchRelation; var Index: integer): boolean;
  247. var
  248. L, H, I, C: Integer;
  249. const resSmaller = -1; resEqual = 0; resGreater = 1;
  250. begin
  251. Index:=-1;
  252. case Rel of
  253. srEqual :
  254. while (L <= H) and (Index=-1) do
  255. begin
  256. I := (L + H) shr 1;
  257. C := Compare(KeyOf(Items^[I]), Key);
  258. if C = resSmaller then L := I + 1 else
  259. begin
  260. H := I - 1;
  261. if C = resEqual then
  262. begin
  263. if not Duplicates then L := I;
  264. Index := L;
  265. end;
  266. end;
  267. end;
  268. srGreater :
  269. begin
  270. end;
  271. srLess :
  272. ;
  273. srGreatEqu :
  274. ;
  275. srLessEqu :
  276. ;
  277. else Exit;
  278. end;
  279. Search:=Index<>-1;
  280. end;}
  281. constructor THelpTopic.Init(ATopic: PTopic);
  282. begin
  283. inherited Init;
  284. Topic:=ATopic;
  285. New(Lines, Init(100,100)); New(Links, Init(50,50)); New(ColorAreas, Init(50,50));
  286. end;
  287. procedure THelpTopic.SetParams(AMargin, AWidth: integer);
  288. begin
  289. if Width<>AWidth then
  290. begin
  291. Width:=AWidth; Margin:=AMargin;
  292. ReBuild;
  293. end;
  294. end;
  295. procedure THelpTopic.ReBuild;
  296. var TextPos,LinkNo: word;
  297. Line,CurWord: string;
  298. C: char;
  299. InLink,InColorArea: boolean;
  300. LinkStart,LinkEnd,ColorAreaStart,ColorAreaEnd: TPoint;
  301. CurPos: TPoint;
  302. ZeroLevel: integer;
  303. LineStart,NextLineStart: integer;
  304. LineAlign : (laLeft,laCenter,laRight);
  305. FirstLink,LastLink: integer;
  306. procedure ClearLine;
  307. begin
  308. Line:='';
  309. end;
  310. procedure AddWord(TheWord: string); forward;
  311. procedure NextLine;
  312. var P: sw_integer;
  313. I,Delta: integer;
  314. begin
  315. Line:=CharStr(' ',Margin)+Line;
  316. repeat
  317. P:=Pos(#255,Line);
  318. if P>0 then Line[P]:=#32;
  319. until P=0;
  320. while copy(Line,length(Line),1)=' ' do Delete(Line,length(Line),1);
  321. Delta:=0;
  322. if Line<>'' then
  323. case LineAlign of
  324. laLeft : ;
  325. laCenter : if Margin+length(Line)+Margin<Width then
  326. begin
  327. Delta:=(Width-(Margin+length(Line)+Margin)) div 2;
  328. Line:=CharStr(' ',Delta)+Line;
  329. end;
  330. laRight : if Margin+length(Line)+Margin<Width then
  331. begin
  332. Delta:=Width-(Margin+length(Line)+Margin);
  333. Line:=CharStr(' ',Delta)+Line;
  334. end;
  335. end;
  336. if (Delta>0) and (FirstLink<>LastLink) then
  337. for I:=FirstLink to LastLink-1 do
  338. with PHelpLink(Links^.At(I))^ do
  339. Bounds.Move(Delta,0);
  340. if Line='' then Line:=' ';
  341. Lines^.Insert(NewStr(Line));
  342. ClearLine;
  343. LineStart:=NextLineStart;
  344. CurPos.X:=Margin+LineStart; Line:=CharStr(#255,LineStart); Inc(CurPos.Y);
  345. if InLink then LinkStart:=CurPos;
  346. FirstLink:=LastLink;
  347. end;
  348. procedure FlushLine;
  349. var W: string;
  350. begin
  351. if CurWord<>'' then begin W:=CurWord; CurWord:=''; AddWord(W); end;
  352. NextLine;
  353. end;
  354. procedure AddWord(TheWord: string);
  355. var W: string;
  356. begin
  357. W:=TheWord;
  358. while (length(W)>0) and (W[length(W)] in [' ',#255]) do
  359. Delete(W,length(W),1);
  360. if (copy(Line+TheWord,1,1)<>' ') then
  361. if (Line<>'') and (Margin+length(Line)+length(W)+Margin>Width) then
  362. NextLine;
  363. Line:=Line+TheWord;
  364. CurPos.X:=Margin+length(Line);
  365. end;
  366. procedure CheckZeroLevel;
  367. begin
  368. if ZeroLevel<>0 then
  369. begin
  370. if CurWord<>'' then AddWord(CurWord+' ');
  371. CurWord:='';
  372. ZeroLevel:=0;
  373. end;
  374. end;
  375. var Diff: integer;
  376. begin
  377. Lines^.FreeAll; Links^.FreeAll;
  378. if Topic=nil then Lines^.Insert(NewStr('No help available for this topic.')) else
  379. begin
  380. LineStart:=0; NextLineStart:=0;
  381. TextPos:=0; ClearLine; CurWord:=''; Line:='';
  382. CurPos.X:=Margin+LineStart; CurPos.Y:=0; LinkNo:=0;
  383. InLink:=false; InColorArea:=false; ZeroLevel:=0;
  384. LineAlign:=laLeft;
  385. FirstLink:=0; LastLink:=0;
  386. while (TextPos<Topic^.TextSize) do
  387. begin
  388. C:=chr(PByteArray(Topic^.Text)^[TextPos]);
  389. case C of
  390. hscLineBreak :
  391. {if ZeroLevel=0 then ZeroLevel:=1 else
  392. begin FlushLine; FlushLine; ZeroLevel:=0; end;}
  393. if InLink then CurWord:=CurWord+' ' else
  394. begin
  395. NextLineStart:=0;
  396. FlushLine;
  397. LineStart:=0;
  398. LineAlign:=laLeft;
  399. end;
  400. #1 : Break;
  401. hscLink :
  402. begin
  403. CheckZeroLevel;
  404. if InLink=false then
  405. begin LinkStart:=CurPos; InLink:=true; end else
  406. begin
  407. if CurWord<>'' then AddWord(CurWord); CurWord:='';
  408. LinkEnd:=CurPos; Dec(LinkEnd.X);
  409. if Topic^.Links<>nil then
  410. begin
  411. Inc(LastLink);
  412. Links^.Insert(NewLink(Topic^.Links^[LinkNo].FileID,
  413. Topic^.Links^[LinkNo].Context,LinkStart,LinkEnd));
  414. Inc(LinkNo);
  415. end;
  416. InLink:=false;
  417. end;
  418. end;
  419. hscLineStart :
  420. begin
  421. NextLineStart:=length(Line)+length(CurWord);
  422. { LineStart:=LineStart+(NextLineStart-LineStart);}
  423. end;
  424. hscCode :
  425. begin
  426. if InColorArea=false then
  427. ColorAreaStart:=CurPos else
  428. begin
  429. if CurWord<>'' then AddWord(CurWord); CurWord:='';
  430. ColorAreaEnd:=CurPos; Dec(ColorAreaEnd.X);
  431. ColorAreas^.Insert(NewColorArea(CommentColor,ColorAreaStart,ColorAreaEnd));
  432. end;
  433. InColorArea:=not InColorArea;
  434. end;
  435. hscCenter :
  436. LineAlign:=laCenter;
  437. hscRight :
  438. LineAlign:=laCenter;
  439. #32: if InLink then CurWord:=CurWord+C else
  440. begin CheckZeroLevel; AddWord(CurWord+C); CurWord:=''; end;
  441. else begin CheckZeroLevel; CurWord:=CurWord+C; end;
  442. end;
  443. CurPos.X:=Margin+length(Line)+length(CurWord);
  444. Inc(TextPos);
  445. end;
  446. if (Line<>'') or (CurWord<>'') then FlushLine;
  447. end;
  448. end;
  449. function THelpTopic.GetLineCount: integer;
  450. begin
  451. GetLineCount:=Lines^.Count;
  452. end;
  453. function THelpTopic.GetLineText(Line: integer): string;
  454. var S: string;
  455. begin
  456. if Line<GetLineCount then S:=PString(Lines^.At(Line))^ else S:='';
  457. GetLineText:=S;
  458. end;
  459. function THelpTopic.GetLinkCount: integer;
  460. begin
  461. GetLinkCount:=Links^.Count;
  462. end;
  463. procedure THelpTopic.GetLinkBounds(Index: integer; var R: TRect);
  464. var P: PHelpLink;
  465. begin
  466. P:=Links^.At(Index);
  467. R:=P^.Bounds;
  468. end;
  469. function THelpTopic.GetLinkFileID(Index: integer): word;
  470. var P: PHelpLink;
  471. begin
  472. P:=Links^.At(Index);
  473. GetLinkFileID:=P^.FileID;
  474. end;
  475. function THelpTopic.GetLinkContext(Index: integer): THelpCtx;
  476. var P: PHelpLink;
  477. begin
  478. P:=Links^.At(Index);
  479. GetLinkContext:=P^.Context;
  480. end;
  481. function THelpTopic.GetColorAreaCount: integer;
  482. begin
  483. GetColorAreaCount:=ColorAreas^.Count;
  484. end;
  485. procedure THelpTopic.GetColorAreaBounds(Index: integer; var R: TRect);
  486. var P: PHelpColorArea;
  487. begin
  488. P:=ColorAreas^.At(Index);
  489. R:=P^.Bounds;
  490. end;
  491. function THelpTopic.GetColorAreaColor(Index: integer): word;
  492. var P: PHelpColorArea;
  493. begin
  494. P:=ColorAreas^.At(Index);
  495. GetColorAreaColor:=P^.Color;
  496. end;
  497. destructor THelpTopic.Done;
  498. begin
  499. inherited Done;
  500. Dispose(Lines, Done); Dispose(Links, Done); Dispose(ColorAreas, Done);
  501. if (Topic<>nil) then DisposeTopic(Topic);
  502. end;
  503. constructor THelpViewer.Init(var Bounds: TRect; AHScrollBar, AVScrollBar: PScrollBar);
  504. begin
  505. inherited Init(Bounds, AHScrollBar, AVScrollBar, nil, 0);
  506. Flags:=efInsertMode; IsReadOnly:=true;
  507. New(WordList, Init(50,50));
  508. Margin:=1; CurLink:=-1;
  509. end;
  510. procedure THelpViewer.ChangeBounds(var Bounds: TRect);
  511. begin
  512. if Owner<>nil then Owner^.Lock;
  513. inherited ChangeBounds(Bounds);
  514. if (HelpTopic<>nil) and (HelpTopic^.Topic<>nil) and
  515. (HelpTopic^.Topic^.FileID<>0) then RenderTopic;
  516. if Owner<>nil then Owner^.UnLock;
  517. end;
  518. procedure THelpViewer.RenderTopic;
  519. begin
  520. if HelpTopic<>nil then
  521. HelpTopic^.SetParams(Margin,Size.X);
  522. {$ifndef EDITORS}
  523. SetLimit(255,GetLineCount);
  524. {$endif}
  525. DrawView;
  526. end;
  527. function THelpViewer.LinkContainsPoint(var R: TRect; var P: TPoint): boolean;
  528. var OK: boolean;
  529. begin
  530. if (R.A.Y=R.B.Y) then
  531. OK:= (P.Y=R.A.Y) and (R.A.X<=P.X) and (P.X<=R.B.X) else
  532. OK:=
  533. ( (R.A.Y=P.Y) and (R.A.X<=P.X) ) or
  534. ( (R.A.Y<P.Y) and (P.Y<R.B.Y) ) or
  535. ( (R.B.Y=P.Y) and (P.X<=R.B.X) );
  536. LinkContainsPoint:=OK;
  537. end;
  538. procedure THelpViewer.SetCurPtr(X,Y: integer);
  539. var OldCurLink,I: integer;
  540. OldPos,P: TPoint;
  541. R: TRect;
  542. begin
  543. OldPos:=CurPos;
  544. OldCurLink:=CurLink;
  545. inherited SetCurPtr(X,Y);
  546. CurLink:=-1;
  547. P:=CurPos;
  548. for I:=0 to GetLinkCount-1 do
  549. begin
  550. GetLinkBounds(I,R);
  551. if LinkContainsPoint(R,P) then
  552. begin CurLink:=I; Break; end;
  553. end;
  554. if OldCurLink<>CurLink then DrawView;
  555. if ((OldPos.X<>CurPos.X) or (OldPos.Y<>CurPos.Y)) and (InLookup=false) then
  556. Lookup('');
  557. end;
  558. function THelpViewer.GetLineCount: integer;
  559. var Count: integer;
  560. begin
  561. if HelpTopic=nil then Count:=0 else Count:=HelpTopic^.GetLineCount;
  562. GetLineCount:=Count;
  563. end;
  564. function THelpViewer.GetLineText(Line: integer): string;
  565. var S: string;
  566. begin
  567. if HelpTopic=nil then S:='' else S:=HelpTopic^.GetLineText(Line);
  568. GetLineText:=S;
  569. end;
  570. function THelpViewer.GetLinkCount: integer;
  571. var Count: integer;
  572. begin
  573. if HelpTopic=nil then Count:=0 else Count:=HelpTopic^.GetLinkCount;
  574. GetLinkCount:=Count;
  575. end;
  576. procedure THelpViewer.GetLinkBounds(Index: integer; var R: TRect);
  577. begin
  578. HelpTopic^.GetLinkBounds(Index,R);
  579. end;
  580. function THelpViewer.GetLinkFileID(Index: integer): word;
  581. begin
  582. GetLinkFileID:=HelpTopic^.GetLinkFileID(Index);
  583. end;
  584. function THelpViewer.GetLinkContext(Index: integer): THelpCtx;
  585. begin
  586. GetLinkContext:=HelpTopic^.GetLinkContext(Index);
  587. end;
  588. function THelpViewer.GetLinkText(Index: integer): string;
  589. var S: string;
  590. R: TRect;
  591. Y,StartX,EndX: integer;
  592. begin
  593. S:=''; GetLinkBounds(Index,R);
  594. Y:=R.A.Y;
  595. while (Y<=R.B.Y) do
  596. begin
  597. if Y=R.A.Y then StartX:=R.A.X else StartX:=Margin;
  598. if Y=R.B.Y then EndX:=R.B.X else EndX:=255;
  599. S:=S+copy(GetLineText(Y),StartX+1,EndX-StartX+1);
  600. Inc(Y);
  601. end;
  602. GetLinkText:=S;
  603. end;
  604. function THelpViewer.GetColorAreaCount: integer;
  605. var Count: integer;
  606. begin
  607. if HelpTopic=nil then Count:=0 else Count:=HelpTopic^.GetColorAreaCount;
  608. GetColorAreaCount:=Count;
  609. end;
  610. procedure THelpViewer.GetColorAreaBounds(Index: integer; var R: TRect);
  611. begin
  612. HelpTopic^.GetColorAreaBounds(Index,R);
  613. end;
  614. function THelpViewer.GetColorAreaColor(Index: integer): word;
  615. begin
  616. GetColorAreaColor:=HelpTopic^.GetColorAreaColor(Index);
  617. end;
  618. procedure THelpViewer.SelectNextLink(ANext: boolean);
  619. var I,Link: integer;
  620. R: TRect;
  621. begin
  622. if HelpTopic=nil then Exit;
  623. Link:=CurLink;
  624. if Link<>-1 then
  625. begin
  626. if ANext then
  627. begin Inc(Link); if Link>=GetLinkCount then Link:=0; end else
  628. begin Dec(Link); if Link=-1 then Link:=GetLinkCount-1; end;
  629. end else
  630. for I:=0 to GetLinkCount-1 do
  631. begin
  632. GetLinkBounds(I,R);
  633. if (R.A.Y>CurPos.Y) or
  634. (R.A.Y=CurPos.Y) and (R.A.X>CurPos.X) then
  635. begin Link:=I; Break; end;
  636. end;
  637. if (Link=-1) and (GetLinkCount>0) then
  638. if ANext then Link:=0
  639. else Link:=GetLinkCount-1;
  640. SetCurLink(Link);
  641. end;
  642. procedure THelpViewer.SetCurLink(Link: integer);
  643. var R: TRect;
  644. begin
  645. if Link<>-1 then
  646. begin
  647. GetLinkBounds(Link,R);
  648. SetCurPtr(R.A.X,R.A.Y);
  649. TrackCursor(true);
  650. end;
  651. end;
  652. procedure THelpViewer.SwitchToIndex;
  653. begin
  654. if IndexTopic=nil then
  655. IndexTopic:=HelpFacility^.BuildIndexTopic;
  656. ISwitchToTopicPtr(IndexTopic,true);
  657. end;
  658. procedure THelpViewer.SwitchToTopic(SourceFileID: word; Context: THelpCtx);
  659. begin
  660. ISwitchToTopic(SourceFileID,Context,true);
  661. end;
  662. procedure THelpViewer.ISwitchToTopic(SourceFileID: word; Context: THelpCtx; RecordInHistory: boolean);
  663. var P: PTopic;
  664. begin
  665. if HelpFacility=nil then P:=nil else
  666. if (SourceFileID=0) and (Context=0) and (HelpTopic<>nil) then
  667. P:=IndexTopic else
  668. P:=HelpFacility^.LoadTopic(SourceFileID, Context);
  669. ISwitchToTopicPtr(P,RecordInHistory);
  670. end;
  671. procedure THelpViewer.ISwitchToTopicPtr(P: PTopic; RecordInHistory: boolean);
  672. var HistoryFull: boolean;
  673. begin
  674. if (P<>nil) and RecordInHistory and (HelpTopic<>nil) then
  675. begin
  676. HistoryFull:=HistoryPtr>=HistorySize;
  677. if HistoryFull then
  678. Move(History[1],History[0],SizeOf(History)-SizeOf(History[0]));
  679. with History[HistoryPtr] do
  680. begin
  681. {SourceTopic_:=SourceTopic; }Context_:=HelpTopic^.Topic^.HelpCtx;
  682. FileID_:=HelpTopic^.Topic^.FileID;
  683. Delta_:=Delta; CurPos_:=CurPos; CurLink_:=CurLink;
  684. end;
  685. if HistoryFull=false then Inc(HistoryPtr);
  686. end;
  687. if Owner<>nil then Owner^.Lock;
  688. SetTopic(P);
  689. DrawView;
  690. if Owner<>nil then Owner^.UnLock;
  691. end;
  692. procedure THelpViewer.PrevTopic;
  693. begin
  694. if HistoryPtr>0 then
  695. begin
  696. if Owner<>nil then Owner^.Lock;
  697. Dec(HistoryPtr);
  698. with History[HistoryPtr] do
  699. begin
  700. ISwitchToTopic(FileID_,Context_,false);
  701. ScrollTo(Delta_.X,Delta_.Y);
  702. SetCurPtr(CurPos_.X,CurPos_.Y);
  703. TrackCursor(false);
  704. if CurLink<>CurLink_ then SetCurLink(CurLink_);
  705. end;
  706. DrawView;
  707. if Owner<>nil then Owner^.UnLock;
  708. end;
  709. end;
  710. procedure THelpViewer.SetTopic(Topic: PTopic);
  711. begin
  712. CurLink:=-1;
  713. if (HelpTopic=nil) or (Topic<>HelpTopic^.Topic) then
  714. begin
  715. if (HelpTopic<>nil) and (HelpTopic<>IndexHelpTopic) then
  716. Dispose(HelpTopic, Done);
  717. HelpTopic:=nil;
  718. if Topic<>nil then
  719. begin
  720. if (Topic=IndexTopic) and (IndexHelpTopic<>nil) then
  721. HelpTopic:=IndexHelpTopic else
  722. New(HelpTopic, Init(Topic));
  723. if Topic=IndexTopic then
  724. IndexHelpTopic:=HelpTopic;
  725. end;
  726. end;
  727. if Owner<>nil then Owner^.Lock;
  728. SetCurPtr(0,0); TrackCursor(false);
  729. RenderTopic;
  730. BuildTopicWordList;
  731. Lookup('');
  732. SetSelection(CurPos,CurPos);
  733. DrawView;
  734. if Owner<>nil then Owner^.UnLock;
  735. end;
  736. procedure THelpViewer.BuildTopicWordList;
  737. var I: integer;
  738. begin
  739. WordList^.FreeAll;
  740. for I:=0 to GetLinkCount-1 do
  741. WordList^.Insert(NewKeyword(I,Trim(GetLinkText(I))));
  742. end;
  743. procedure THelpViewer.Lookup(S: string);
  744. var Index, I: Sw_integer;
  745. W: string;
  746. OldLookup: string;
  747. R: TRect;
  748. P: PHelpKeyword;
  749. begin
  750. InLookup:=true;
  751. OldLookup:=LookupWord;
  752. S:=UpcaseStr(S);
  753. Index:=-1;
  754. I:=0; {J:=0;
  755. while (J<GetLinkCount) do
  756. begin
  757. GetLinkBounds(J,R);
  758. if (R.A.Y<CurPos.Y) or ((R.A.Y=CurPos.Y) and (R.B.X<CurPos.X))
  759. then Inc(J) else
  760. begin I:=J; Break; end;
  761. end;}
  762. if S='' then LookupWord:='' else
  763. begin
  764. while (Index=-1) and (I<WordList^.Count) do
  765. begin
  766. P:=WordList^.At(I);
  767. if P^.KWord<>nil then
  768. begin
  769. W:=UpcaseStr(Trim(P^.KWord^));
  770. if copy(W,1,length(S))=S then Index:=I;
  771. end;
  772. { if W>S then Break else}
  773. Inc(I);
  774. end;
  775. if Index<>-1 then
  776. begin
  777. W:=Trim(WordList^.At(Index)^.KWord^);
  778. LookupWord:=copy(W,1,length(S));
  779. end;
  780. end;
  781. if LookupWord<>OldLookup then
  782. begin
  783. if Index=-1 then SetCurLink(CurLink) else
  784. begin
  785. if Owner<>nil then Owner^.Lock;
  786. P:=WordList^.At(Index);
  787. S:=GetLinkText(P^.Index);
  788. I:=Pos(LookupWord,S); if I=0 then I:=1;
  789. GetLinkBounds(P^.Index,R);
  790. SetCurPtr(R.A.X+(I-1)+length(Lookupword),R.A.Y);
  791. CurLink:=P^.Index; DrawView;
  792. TrackCursor(true);
  793. if Owner<>nil then Owner^.UnLock;
  794. end;
  795. end;
  796. InLookup:=false;
  797. end;
  798. procedure THelpViewer.SelectLink(Index: integer);
  799. var ID: word;
  800. Ctx: THelpCtx;
  801. begin
  802. if Index=-1 then Exit;
  803. if HelpTopic=nil then begin ID:=0; Ctx:=0; end else
  804. begin
  805. ID:=GetLinkFileID(Index);
  806. Ctx:=GetLinkContext(Index);
  807. end;
  808. SwitchToTopic(ID,Ctx);
  809. end;
  810. procedure THelpViewer.HandleEvent(var Event: TEvent);
  811. var DontClear: boolean;
  812. procedure GetMousePos(var P: TPoint);
  813. begin
  814. MakeLocal(Event.Where,P);
  815. Inc(P.X,Delta.X); Inc(P.Y,Delta.Y);
  816. end;
  817. begin
  818. case Event.What of
  819. evMouseDown :
  820. if MouseInView(Event.Where) then
  821. if (Event.Buttons=mbLeftButton) and (Event.Double) then
  822. begin
  823. inherited HandleEvent(Event);
  824. if CurLink<>-1 then
  825. SelectLink(CurLink);
  826. end;
  827. evCommand :
  828. begin
  829. DontClear:=false;
  830. case Event.Command of
  831. cmPrevTopic :
  832. PrevTopic;
  833. else DontClear:=true;
  834. end;
  835. if DontClear=false then ClearEvent(Event);
  836. end;
  837. evKeyDown :
  838. begin
  839. DontClear:=false;
  840. case Event.KeyCode of
  841. kbTab :
  842. SelectNextLink(true);
  843. kbShiftTab :
  844. begin NoSelect:=true; SelectNextLink(false); NoSelect:=false; end;
  845. kbEnter :
  846. if CurLink<>-1 then
  847. SelectLink(CurLink);
  848. else
  849. case Event.CharCode of
  850. #32..#255 :
  851. begin NoSelect:=true; Lookup(LookupWord+Event.CharCode); NoSelect:=false; end;
  852. else DontClear:=true;
  853. end;
  854. end;
  855. TrackCursor(false);
  856. if DontClear=false then ClearEvent(Event);
  857. end;
  858. end;
  859. inherited HandleEvent(Event);
  860. end;
  861. procedure THelpViewer.Draw;
  862. var NormalColor, LinkColor,
  863. SelectColor, SelectionColor: word;
  864. B: TDrawBuffer;
  865. DX,DY,X,Y,I,MinX,MaxX,ScreenX: integer;
  866. LastLinkDrawn,LastColorAreaDrawn: integer;
  867. S: string;
  868. R: TRect;
  869. {$ifndef EDITORS}
  870. SelR : TRect;
  871. {$endif}
  872. C: word;
  873. CurP: TPoint;
  874. begin
  875. NormalColor:=GetColor(1); LinkColor:=GetColor(2);
  876. SelectColor:=GetColor(3); SelectionColor:=GetColor(4);
  877. {$ifndef EDITORS}
  878. SelR.A:=SelStart; SelR.B:=SelEnd;
  879. {$endif}
  880. LastLinkDrawn:=0; LastColorAreaDrawn:=0;
  881. for DY:=0 to Size.Y-1 do
  882. begin
  883. Y:=Delta.Y+DY;
  884. MoveChar(B,' ',NormalColor,Size.X);
  885. if Y<GetLineCount then
  886. begin
  887. S:=copy(GetLineText(Y),Delta.X+1,255);
  888. S:=copy(S,1,MaxViewWidth);
  889. MoveStr(B,S,NormalColor);
  890. for I:=LastColorAreaDrawn to GetColorAreaCount-1 do
  891. begin
  892. GetColorAreaBounds(I,R);
  893. if R.A.Y>Y then Break;
  894. LastColorAreaDrawn:=I;
  895. if Y=R.B.Y then MaxX:=R.B.X else MaxX:=(length(S)-1);
  896. if Y=R.A.Y then MinX:=R.A.X else MinX:=0;
  897. if (R.A.Y<=Y) and (Y<=R.B.Y) then
  898. begin
  899. C:=GetColorAreaColor(I);
  900. for DX:=MinX to MaxX do
  901. begin
  902. X:=DX;
  903. ScreenX:=X-(Delta.X);
  904. if (ScreenX>0) then
  905. begin
  906. { CurP.X:=X; CurP.Y:=Y;
  907. if LinkAreaContainsPoint(R,CurP) then}
  908. B[ScreenX]:=(B[ScreenX] and $f0ff) or (C shl 8);
  909. end;
  910. end;
  911. end;
  912. end;
  913. for I:=LastLinkDrawn to GetLinkCount-1 do
  914. begin
  915. GetLinkBounds(I,R);
  916. if R.A.Y>Y then Break;
  917. LastLinkDrawn:=I;
  918. if Y=R.B.Y then MaxX:=R.B.X else MaxX:=(length(S)-1);
  919. if Y=R.A.Y then MinX:=R.A.X else MinX:=0;
  920. if (R.A.Y<=Y) and (Y<=R.B.Y) then
  921. for DX:=MinX to MaxX do
  922. begin
  923. X:=DX;
  924. ScreenX:=X-(Delta.X);
  925. if (ScreenX>=0) then
  926. begin
  927. CurP.X:=X; CurP.Y:=Y;
  928. if LinkContainsPoint(R,CurP) then
  929. if I=CurLink then C:=SelectColor else C:=LinkColor;
  930. B[ScreenX]:=(B[ScreenX] and $ff) or (C shl 8);
  931. end;
  932. end;
  933. end;
  934. {$ifndef EDITORS}
  935. 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
  936. begin
  937. if Y=SelR.A.Y then MinX:=SelR.A.X else MinX:=0;
  938. if Y=SelR.B.Y then MaxX:=SelR.B.X-1 else MaxX:=255;
  939. for DX:=MinX to MaxX do
  940. begin
  941. X:=DX;
  942. ScreenX:=X-(Delta.X);
  943. if (ScreenX>=0) and (ScreenX<MaxViewWidth) then
  944. B[ScreenX]:=(B[ScreenX] and $0fff) or ((SelectionColor and $f0) shl 8);
  945. end;
  946. end;
  947. {$endif}
  948. end;
  949. WriteLine(0,DY,Size.X,1,B);
  950. end;
  951. DrawCursor;
  952. end;
  953. function THelpViewer.GetPalette: PPalette;
  954. const P: string[length(CHelpViewer)] = CHelpViewer;
  955. begin
  956. GetPalette:=@P;
  957. end;
  958. destructor THelpViewer.Done;
  959. begin
  960. inherited Done;
  961. Dispose(WordList, Done);
  962. end;
  963. function THelpFrame.GetPalette: PPalette;
  964. const P: string[length(CHelpFrame)] = CHelpFrame;
  965. begin
  966. GetPalette:=@P;
  967. end;
  968. constructor THelpWindow.Init(var Bounds: TRect; ATitle: TTitleStr; ASourceFileID: word; AContext: THelpCtx; ANumber: Integer);
  969. var R: TRect;
  970. VSB,HSB: PScrollBar;
  971. begin
  972. inherited Init(Bounds, ATitle, ANumber);
  973. GetExtent(R); R.Grow(0,-1); R.A.X:=R.B.X-1;
  974. New(VSB, Init(R)); VSB^.GrowMode:=gfGrowLoX+gfGrowHiX+gfGrowHiY; Insert(VSB);
  975. GetExtent(R); R.Grow(-1,0); R.A.Y:=R.B.Y-1;
  976. New(HSB, Init(R)); HSB^.GrowMode:=gfGrowLoY+gfGrowHiX+gfGrowHiY; Insert(HSB);
  977. GetExtent(R); R.Grow(-1,-1);
  978. New(HelpView, Init(R, HSB, VSB));
  979. HelpView^.GrowMode:=gfGrowHiX+gfGrowHiY;
  980. if (ASourceFileID<>0) or (AContext<>0) then
  981. ShowTopic(ASourceFileID, AContext);
  982. Insert(HelpView);
  983. end;
  984. procedure THelpWindow.InitFrame;
  985. var R: TRect;
  986. begin
  987. GetExtent(R);
  988. Frame:=New(PHelpFrame, Init(R));
  989. end;
  990. procedure THelpWindow.ShowIndex;
  991. begin
  992. HelpView^.SwitchToIndex;
  993. end;
  994. procedure THelpWindow.ShowTopic(SourceFileID: word; Context: THelpCtx);
  995. begin
  996. HelpView^.SwitchToTopic(SourceFileID, Context);
  997. end;
  998. procedure THelpWindow.HandleEvent(var Event: TEvent);
  999. begin
  1000. case Event.What of
  1001. evKeyDown :
  1002. case Event.KeyCode of
  1003. kbEsc :
  1004. begin
  1005. Event.What:=evCommand; Event.Command:=cmClose;
  1006. end;
  1007. end;
  1008. end;
  1009. inherited HandleEvent(Event);
  1010. end;
  1011. procedure THelpWindow.Close;
  1012. begin
  1013. if HideOnClose then Hide else inherited Close;
  1014. end;
  1015. function THelpWindow.GetPalette: PPalette;
  1016. begin
  1017. GetPalette:=nil;
  1018. end;
  1019. END.
  1020. {
  1021. $Log$
  1022. Revision 1.4 1999-02-08 10:37:47 peter
  1023. + html helpviewer
  1024. Revision 1.3 1999/01/21 11:54:32 peter
  1025. + tools menu
  1026. + speedsearch in symbolbrowser
  1027. * working run command
  1028. Revision 1.2 1998/12/28 15:47:57 peter
  1029. + Added user screen support, display & window
  1030. + Implemented Editor,Mouse Options dialog
  1031. + Added location of .INI and .CFG file
  1032. + Option (INI) file managment implemented (see bottom of Options Menu)
  1033. + Switches updated
  1034. + Run program
  1035. Revision 1.31 1998/12/27 12:07:30 gabor
  1036. * changed THelpViewer.Init to reflect changes in WEDITOR
  1037. Revision 1.3 1998/12/22 10:39:56 peter
  1038. + options are now written/read
  1039. + find and replace routines
  1040. }