home *** CD-ROM | disk | FTP | other *** search
/ Power-Programmierung / CD1.mdf / pascal / library / dos / help / tphelp / tphelp.pas < prev   
Encoding:
Pascal/Delphi Source File  |  1988-02-07  |  22.9 KB  |  780 lines

  1. {TPHELP.PAS Copyright (C) 1988, by TurboPower Software}
  2.  
  3. {$R-,S-,I-}
  4.  
  5. {Activate the following define if you have the TPPICK unit}
  6. { $DEFINE UsingPickUnit}
  7.  
  8. Unit TpHelp;
  9.   {-General purpose help facility}
  10.  
  11. Interface
  12.  
  13. Uses
  14.   Dos,
  15.   TPDos,
  16.   TPString,
  17.   TPCrt,
  18.   TPWindow
  19.   {$IFDEF UsingPickUnit}
  20.   , TpPick
  21.   {$ENDIF}
  22.   ;
  23.  
  24. CONST
  25.   HelpId : ARRAY[0..3] OF CHAR = 'TPH0'; {Identifier at start of help file}
  26.   NoHelpAvailable = $FFFFFFFF;    {Flag that no help is available for topic}
  27.   MaxPagesPerSection = 21;        {Maximum number of pages of help per section}
  28.   Attr1Toggle    = ^A;            {Character toggles special attribute 1}
  29.   Attr2Toggle    = ^B;            {Character toggles special attribute 2}
  30.   Attr3Toggle    = ^C;            {Character toggles special attribute 3}
  31.   LineBrkMark    = ^M;            {Denotes end of line of help}
  32.   PageBrkMark    = ^L;            {Denotes end of page of help}
  33.   SectEndMark    = #0;            {Denotes end of help section}
  34.   PickTitle : STRING[80] = ' Topics ';
  35.  
  36. TYPE
  37.   HelpAttrType   = (FrAttr, TeAttr, HeAttr, SpAtt1, SpAtt2, SpAtt3);
  38.   HelpAttrArray  = ARRAY[HelpAttrType] OF Byte;
  39.   HelpAttrState  = ARRAY[SpAtt1..SpAtt3] OF BOOLEAN;
  40.   HelpHeader =
  41.     RECORD
  42.       ID             : LongInt;   {Marks file as help file}
  43.       MaxSection     : Word;      {Size of largest help section in bytes}
  44.       ItemCnt        : Word;      {Number of help entries in index}
  45.       NameSize       : Byte;      {Size of each entry in pick table, 0 for none}
  46.       Width          : Byte;      {Width of help window, with frame}
  47.     END;
  48.   CharArray      = ARRAY[0..64000] OF CHAR; {List of names of help entries}
  49.   HelpIndex      = ARRAY[1..16000] OF LongInt; {Index of file positions}
  50.   CharArrayPtr   = ^CharArray;
  51.   HelpIndexPtr   = ^HelpIndex;
  52.   HelpHeaderPtr  = ^HelpHeader;
  53.  
  54.   HelpPtr        = ^HelpDesc;     {The user hook to the help system}
  55.   HelpDesc =                      {Holds parameters of help system}
  56.     RECORD
  57.       RowH           : Byte;      {Upper left corner of help window - Row}
  58.       ColH           : Byte;      {Upper left corner of help window - Col}
  59.       CAttr          : HelpAttrArray; {Attributes used to draw help in color}
  60.       MAttr          : HelpAttrArray; {Attributes used to draw help in monoc}
  61.       Frame          : FrameArray; {Frame characters to use}
  62.       Hdr            : HelpHeader; {Copy of header for fast reference}
  63.       Height         : Byte;      {Height of help window, with frame}
  64.       CASE InRAM     : BOOLEAN OF {True if help file is bound into code}
  65.         TRUE :
  66.           (HdrP           : HelpHeaderPtr; {Points to base of structure in RAM}
  67.            NamP           : CharArrayPtr; {Points to pick name array in RAM}
  68.            IndP           : HelpIndexPtr); {Points to help section index in RAM}
  69.         FALSE :
  70.           (Open           : BOOLEAN; {True when file is open}
  71.            BufP           : CharArrayPtr; {Points to a buffer that will hold largest section}
  72.            Fil            : FILE); {Untyped file variable for help}
  73.     END;
  74.  
  75. CONST
  76.   {Default help colors}
  77.   HelpColorAttr : HelpAttrArray = ($71, $30, $71, $1F, $3E, $31);
  78.   HelpMonocAttr : HelpAttrArray = ($07, $07, $0F, $70, $0F, $01);
  79.  
  80.   {Context sensitive help}
  81.   CurrentTopic : Word = 0;        {Current help topic}
  82.   HelpIntInstalled : BOOLEAN = FALSE; {True if interrupt handler installed}
  83.  
  84. FUNCTION OpenHelpFile(HelpFileName   : STRING;
  85.                       XLow, YLow, YHigh : Byte;
  86.                       VAR Help : HelpPtr) : Word;
  87.   {-Find and open help file, returning 0 or error code, and
  88.     an initialized help descriptor if successful}
  89.  
  90. FUNCTION OpenHelpMem(HPtr           : Pointer;
  91.                      XLow, YLow, YHigh : Byte;
  92.                      VAR Help : HelpPtr) : Word;
  93.   {-Initialize help descriptor for a help structure bound into code}
  94.  
  95. PROCEDURE SetHelpPos(Help : HelpPtr; XLow, YLow, YHigh : Byte);
  96.   {-Change the position and height of a help window}
  97.  
  98. FUNCTION ShowHelp(Help : HelpPtr; Item : Word) : BOOLEAN;
  99.   {-Display help screen, returning true if successful}
  100.  
  101. FUNCTION ShowHelpByName(Help : HelpPtr; Name : STRING) : BOOLEAN;
  102.   {-Display help screen for topic with pick name Name}
  103.  
  104.   {$IFDEF UsingPickUnit}
  105. FUNCTION PickHelp(Help : HelpPtr; XLow, YLow, YHigh, PickCols : Byte) : Word;
  106.   {-Display help pick list, returning Item number, or 0 for none}
  107.   {$ENDIF}
  108.  
  109. PROCEDURE SetContextHelp(Help : HelpPtr; Key : Word);
  110.   {-Install a keyboard interrupt handler to pop help when Key is pressed}
  111.  
  112. PROCEDURE RemoveHelp;
  113.   {-Deinstall context sensitive help}
  114.  
  115.   {=========================================================================}
  116.  
  117. Implementation
  118.  
  119. TYPE
  120.   PageIndex      = ARRAY[1..MaxPagesPerSection] OF Word;
  121.   PageAttr       = ARRAY[1..MaxPagesPerSection] OF HelpAttrState;
  122.  
  123.   {$F+}
  124.   FUNCTION HeapFunc(Size : Word)   : INTEGER;
  125.     {-Return nil pointer if insufficient memory}
  126.   BEGIN
  127.     HeapFunc := 1;
  128.   END;
  129.   {$F-}
  130.  
  131.   FUNCTION GetMemCheck(VAR P; Bytes : Word) : BOOLEAN;
  132.     {-Allocate heap space, returning true if successful}
  133.   VAR
  134.     SaveHeapError  : Pointer;
  135.     Pt             : Pointer Absolute P;
  136.   BEGIN
  137.     {Take over heap error control}
  138.     SaveHeapError := HeapError;
  139.     HeapError := @HeapFunc;
  140.     GetMem(Pt, Bytes);
  141.     GetMemCheck := (Pt <> NIL);
  142.     {Restore heap error control}
  143.     HeapError := SaveHeapError;
  144.   END;
  145.  
  146.   PROCEDURE FreeMemCheck(VAR P; Bytes : Word);
  147.     {-Deallocate heap space}
  148.   VAR
  149.     Pt             : Pointer Absolute P;
  150.   BEGIN
  151.     IF Pt <> NIL THEN
  152.       FreeMem(Pt, Bytes);
  153.   END;
  154.  
  155.   FUNCTION OpenHelpFile(HelpFileName   : STRING;
  156.                         XLow, YLow, YHigh : Byte;
  157.                         VAR Help : HelpPtr) : Word;
  158.     {-Find and open help file, returning 0 or error code, and
  159.       an initialized help descriptor if successful}
  160.   LABEL
  161.     ErrorExit;
  162.   VAR
  163.     IO             : Word;
  164.     BytesRead      : Word;
  165.     IsOpen         : BOOLEAN;
  166.   BEGIN
  167.     {Initialize the result}
  168.     Help := NIL;
  169.     IsOpen := FALSE;
  170.  
  171.     {Find the help file}
  172.     IF NOT ExistOnPath(HelpFileName, HelpFileName) THEN BEGIN
  173.       OpenHelpFile := 2;
  174.       GOTO ErrorExit;
  175.     END;
  176.  
  177.     {Allocate space for help descriptor}
  178.     IF NOT GetMemCheck(Help, SIZEOF(HelpDesc)) THEN BEGIN
  179.       OpenHelpFile := 203;
  180.       GOTO ErrorExit;
  181.     END;
  182.  
  183.     {Initialize the help descriptor}
  184.     WITH Help^ DO BEGIN
  185.       {Most help information is on disk}
  186.       InRAM := FALSE;
  187.  
  188.       {Open the help file}
  189.       ASSIGN(Fil, HelpFileName);
  190.       RESET(Fil, 1);
  191.       IO := IOResult;
  192.       IF IO <> 0 THEN BEGIN
  193.         OpenHelpFile := IO;
  194.         GOTO ErrorExit;
  195.       END;
  196.       IsOpen := TRUE;
  197.  
  198.       {Get header from file}
  199.       BlockRead(Fil, Hdr, SIZEOF(HelpHeader), BytesRead);
  200.       IO := IOResult;
  201.       IF IO <> 0 THEN BEGIN
  202.         OpenHelpFile := IO;
  203.         GOTO ErrorExit;
  204.       END;
  205.       IF BytesRead <> SIZEOF(HelpHeader) THEN BEGIN
  206.         OpenHelpFile := 100;
  207.         GOTO ErrorExit;
  208.       END;
  209.  
  210.       WITH Hdr DO BEGIN
  211.         {Check file ID}
  212.         IF ID <> LongInt(HelpId) THEN BEGIN
  213.           {"Invalid numeric format" - used as error code for invalid ID}
  214.           OpenHelpFile := 106;
  215.           GOTO ErrorExit;
  216.         END;
  217.         {Get buffer space for reading help sections}
  218.         IF NOT GetMemCheck(BufP, MaxSection) THEN BEGIN
  219.           OpenHelpFile := 203;
  220.           GOTO ErrorExit;
  221.         END;
  222.       END;
  223.  
  224.       {Initialize remaining fields}
  225.       RowH := YLow;
  226.       ColH := XLow;
  227.       Height := YHigh-YLow+1;
  228.       CAttr := HelpColorAttr;
  229.       MAttr := HelpMonocAttr;
  230.       Frame := FrameChars;
  231.       Open := TRUE;
  232.  
  233.       {Successful initialization}
  234.       OpenHelpFile := 0;
  235.       Exit;
  236.     END;
  237.  
  238. ErrorExit:
  239.     IF IsOpen THEN BEGIN
  240.       CLOSE(Help^.Fil);
  241.       IsOpen := FALSE;
  242.       IO := IOResult;
  243.     END;
  244.     FreeMemCheck(Help, SIZEOF(HelpDesc))
  245.   END;
  246.  
  247.   FUNCTION OpenHelpMem(HPtr           : Pointer;
  248.                        XLow, YLow, YHigh : Byte;
  249.                        VAR Help : HelpPtr) : Word;
  250.     {-Initialize help descriptor for a help structure bound into code}
  251.   LABEL
  252.     ErrorExit;
  253.   BEGIN
  254.     {Initialize the result in case of failure}
  255.     Help := NIL;
  256.  
  257.     {Allocate space for help descriptor}
  258.     IF NOT GetMemCheck(Help, SIZEOF(HelpDesc)) THEN BEGIN
  259.       OpenHelpMem := 203;
  260.       GOTO ErrorExit;
  261.     END;
  262.  
  263.     {Initialize the help descriptor}
  264.     WITH Help^ DO BEGIN
  265.       {Help information is in RAM}
  266.       InRAM := TRUE;
  267.  
  268.       {Check out header}
  269.       HdrP := HPtr;
  270.       Hdr := HdrP^;
  271.       WITH Hdr DO BEGIN
  272.         IF ID <> LongInt(HelpId) THEN BEGIN
  273.           {"Invalid numeric format" - used as error code for invalid ID}
  274.           OpenHelpMem := 106;
  275.           GOTO ErrorExit;
  276.         END;
  277.         NamP := HPtr;
  278.         Inc(LongInt(NamP), SIZEOF(HelpHeader));
  279.         IndP := Pointer(NamP);
  280.         Inc(LongInt(IndP), ItemCnt*NameSize);
  281.       END;
  282.  
  283.       {Initialize remaining fields}
  284.       RowH := YLow;
  285.       ColH := XLow;
  286.       Height := YHigh-YLow+1;
  287.       CAttr := HelpColorAttr;
  288.       MAttr := HelpMonocAttr;
  289.       Frame := FrameChars;
  290.  
  291.       {Successful initialization}
  292.       OpenHelpMem := 0;
  293.       Exit;
  294.     END;
  295.  
  296. ErrorExit:
  297.     FreeMemCheck(Help, SIZEOF(HelpDesc))
  298.   END;
  299.  
  300.   PROCEDURE SetHelpPos(Help : HelpPtr; XLow, YLow, YHigh : Byte);
  301.     {-Change the position of a help window}
  302.   BEGIN
  303.     WITH Help^ DO
  304.       IF Hdr.ID = LongInt(HelpId) THEN BEGIN
  305.         RowH := YLow;
  306.         ColH := XLow;
  307.         Height := YHigh-YLow+1;
  308.       END;
  309.   END;
  310.  
  311.   FUNCTION GetNameString(Help : HelpPtr; Item : Word) : STRING;
  312.     {-Return name string for help item, if any}
  313.   VAR
  314.     N              : ^STRING;
  315.     S              : STRING;
  316.     C              : CharArrayPtr;
  317.   BEGIN
  318.     GetNameString := '';
  319.     WITH Help^, Hdr DO
  320.       IF NameSize <> 0 THEN
  321.         IF InRAM THEN BEGIN
  322.           N := Pointer(NamP);
  323.           Inc(LongInt(N), NameSize*(Item-1));
  324.           GetNameString := N^;
  325.         END ELSE IF Open THEN BEGIN
  326.           Seek(Fil, LongInt(SIZEOF(HelpHeader))+NameSize*(Item-1));
  327.           IF IOResult <> 0 THEN
  328.             Exit;
  329.           BlockRead(Fil, S, NameSize);
  330.           IF (IOResult <> 0) THEN
  331.             Exit;
  332.           GetNameString := S;
  333.         END;
  334.   END;
  335.  
  336.   FUNCTION PaginateHelp(VAR C : CharArray; TextHgt : Word;
  337.                         VAR P : PageIndex; VAR PA : PageAttr) : Word;
  338.     {-Paginate help text for a single section}
  339.   VAR
  340.     Cpos           : Word;
  341.     Pofs           : Word;
  342.     Pcnt           : Word;
  343.     Phgt           : Word;
  344.     Done           : BOOLEAN;
  345.     HA, LA         : HelpAttrState;
  346.  
  347.     PROCEDURE NewPage;
  348.       {-Store information about previous page}
  349.     BEGIN
  350.       IF Pcnt+1 >= MaxPagesPerSection THEN
  351.         Done := TRUE
  352.       ELSE BEGIN
  353.         Inc(Pcnt);                {Increment page count}
  354.         P[Pcnt] := Pofs;          {Character offset at start of page}
  355.         PA[Pcnt] := LA;           {Attrubute at start of page}
  356.         Pofs := Cpos+1;           {Start of next page}
  357.         P[Pcnt+1] := Pofs;        {Sentinel to end last page}
  358.         Phgt := 0;                {New page has no lines}
  359.         LA := HA;                 {Attributes at start of new page}
  360.       END;
  361.     END;
  362.  
  363.   BEGIN
  364.     Pcnt := 0;
  365.     Cpos := 0;
  366.     Pofs := 0;
  367.     Phgt := 0;
  368.     FillChar(HA, SIZEOF(HelpAttrState), FALSE);
  369.     LA := HA;
  370.     Done := FALSE;
  371.     REPEAT
  372.       CASE C[Cpos] OF
  373.         Attr1Toggle :
  374.           HA[SpAtt1] := NOT HA[SpAtt1];
  375.         Attr2Toggle :
  376.           HA[SpAtt2] := NOT HA[SpAtt2];
  377.         Attr3Toggle :
  378.           HA[SpAtt3] := NOT HA[SpAtt3];
  379.         LineBrkMark :
  380.           BEGIN
  381.             Inc(Phgt);
  382.             IF Phgt >= TextHgt THEN
  383.               NewPage;
  384.           END;
  385.         PageBrkMark :
  386.           IF Cpos = Pofs THEN
  387.             Inc(Pofs)
  388.           ELSE
  389.             NewPage;
  390.         SectEndMark :
  391.           BEGIN
  392.             IF Cpos <> Pofs THEN
  393.               NewPage;
  394.             Done := TRUE;
  395.           END;
  396.       END;
  397.       Inc(Cpos);
  398.     UNTIL Done;
  399.     PaginateHelp := Pcnt;
  400.   END;
  401.  
  402.   PROCEDURE ShowPrompt(Pnum, Pcnt : Word; Row, ColMin, ColMax, Attr : Byte);
  403.     {-Show information about help}
  404.   CONST
  405.     MoreMsg : STRING[13] = '  for more,';
  406.     ExitMsg : STRING[13] = ' Esc to exit ';
  407.   VAR
  408.     Cpos           : Byte;
  409.   BEGIN
  410.     Cpos := ColMax+1-LENGTH(ExitMsg);
  411.     IF Cpos < ColMin THEN
  412.       {No room for any messages}
  413.       Exit;
  414.     FastWrite(ExitMsg, Row, Cpos, Attr);
  415.     IF Pcnt = 1 THEN
  416.       {No need for More message}
  417.       Exit;
  418.     Dec(Cpos, LENGTH(MoreMsg));
  419.     IF Cpos < ColMin THEN
  420.       {No room for More message}
  421.       Exit;
  422.     IF Pnum = 1 THEN
  423.       MoreMsg[2] := ' '
  424.     ELSE
  425.       MoreMsg[2] := ^X;
  426.     IF Pnum = Pcnt THEN
  427.       MoreMsg[3] := ' '
  428.     ELSE
  429.       MoreMsg[3] := ^Y;
  430.     FastWrite(MoreMsg, Row, Cpos, Attr);
  431.   END;
  432.  
  433.   FUNCTION GetAttr(VAR A          : HelpAttrArray;
  434.                    VAR AtSt : HelpAttrState) : Byte;
  435.     {-Return attribute for current attribute state}
  436.   BEGIN
  437.     IF AtSt[SpAtt1] THEN
  438.       GetAttr := A[SpAtt1]
  439.     ELSE IF AtSt[SpAtt2] THEN
  440.       GetAttr := A[SpAtt2]
  441.     ELSE IF AtSt[SpAtt3] THEN
  442.       GetAttr := A[SpAtt3]
  443.     ELSE
  444.       GetAttr := A[TeAttr];
  445.   END;
  446.  
  447.   FUNCTION ToggleAttr(VAR A          : HelpAttrArray;
  448.                       VAR AtSt       : HelpAttrState;
  449.                       SpAtt : HelpAttrType) : Byte;
  450.     {-Toggle attribute state and return new video attribute}
  451.   BEGIN
  452.     AtSt[SpAtt] := NOT AtSt[SpAtt];
  453.     ToggleAttr := GetAttr(A, AtSt);
  454.   END;
  455.  
  456.   PROCEDURE DrawPage(VAR C : CharArray; Pstart, Pend : Word; ColMax : Byte;
  457.                      VAR A : HelpAttrArray; AtSt : HelpAttrState);
  458.     {-Draw one page of help}
  459.   CONST
  460.     ColSt          = 2;
  461.   VAR
  462.     Attr           : Byte;
  463.     Pdone          : BOOLEAN;
  464.     Cpos           : Word;
  465.     Row            : Byte;
  466.     Col            : Byte;
  467.     Ch             : CHAR;
  468.   BEGIN
  469.     Row := 1;
  470.     Col := ColSt;
  471.     Attr := GetAttr(A, AtSt);
  472.     ClrScr;
  473.     Cpos := Pstart;
  474.     Pdone := FALSE;
  475.     REPEAT
  476.       Ch := C[Cpos];
  477.       CASE Ch OF
  478.         LineBrkMark :
  479.           BEGIN
  480.             Inc(Row);
  481.             Col := ColSt;
  482.           END;
  483.         Attr1Toggle :
  484.           Attr := ToggleAttr(A, AtSt, SpAtt1);
  485.         Attr2Toggle :
  486.           Attr := ToggleAttr(A, AtSt, SpAtt2);
  487.         Attr3Toggle :
  488.           Attr := ToggleAttr(A, AtSt, SpAtt3);
  489.         PageBrkMark, SectEndMark :
  490.           Pdone := TRUE;
  491.       ELSE
  492.         IF Col <= ColMax THEN
  493.           FastWriteWindow(Ch, Row, Col, Attr);
  494.         Inc(Col);
  495.       END;
  496.       Inc(Cpos);
  497.       IF Cpos >= Pend THEN
  498.         Pdone := TRUE;
  499.     UNTIL Pdone;
  500.   END;
  501.  
  502.   FUNCTION ShowHelp(Help : HelpPtr; Item : Word) : BOOLEAN;
  503.     {-Display help screen, returning true if successful}
  504.   VAR
  505.     Done           : BOOLEAN;
  506.     Ch             : CHAR;
  507.     Pnum           : Word;
  508.     Lnum           : Word;
  509.     Pcnt           : Word;
  510.     BytesRead      : Word;
  511.     Fpos           : LongInt;
  512.     W              : WindowPtr;
  513.     A              : HelpAttrArray;
  514.     C              : CharArrayPtr;
  515.     P              : PageIndex;
  516.     PA             : PageAttr;
  517.     HeaderStr      : STRING[80];
  518.   BEGIN
  519.     ShowHelp := FALSE;
  520.     IF Item = 0 THEN
  521.       Exit;
  522.  
  523.     WITH Help^, Hdr DO BEGIN
  524.  
  525.       {Get help text into memory and initialize pointer to it}
  526.       IF InRAM THEN BEGIN
  527.         {Already in memory, just compute the pointer}
  528.         C := Pointer(HdrP);
  529.         Inc(LongInt(C), IndP^[Item]);
  530.       END ELSE IF Open THEN BEGIN
  531.         {On disk, first read the index}
  532.         Seek(Fil, SIZEOF(HelpHeader)+LongInt(NameSize)*ItemCnt+SIZEOF(LongInt)*(Item-1));
  533.         IF IOResult <> 0 THEN
  534.           Exit;
  535.         BlockRead(Fil, Fpos, SIZEOF(LongInt), BytesRead);
  536.         IF (IOResult <> 0) OR (BytesRead <> SIZEOF(LongInt)) THEN
  537.           Exit;
  538.         {Check for available help}
  539.         IF Fpos = NoHelpAvailable THEN
  540.           Exit;
  541.         {Now read the help section}
  542.         Seek(Fil, Fpos);
  543.         IF IOResult <> 0 THEN
  544.           Exit;
  545.         BlockRead(Fil, BufP^, MaxSection, BytesRead);
  546.         IF (IOResult <> 0) OR (BytesRead = 0) THEN
  547.           Exit;
  548.         C := BufP;
  549.       END ELSE
  550.         {Help file not open}
  551.         Exit;
  552.  
  553.       {Scan help text to find page boundaries}
  554.       Pcnt := PaginateHelp(C^, Height-2, P, PA);
  555.  
  556.       IF Pcnt = 0 THEN
  557.         {No help for this topic}
  558.         Exit;
  559.  
  560.       {Set colors and frame}
  561.       CASE LastMode AND $FF OF
  562.         0, 2, 7 : A := MAttr;
  563.         1, 3 : A := CAttr;
  564.       ELSE
  565.         Exit;
  566.       END;
  567.       FrameChars := Frame;
  568.  
  569.       {Display window}
  570.       HeaderStr := GetNameString(Help, Item);
  571.       IF LENGTH(HeaderStr) > 0 THEN
  572.         HeaderStr := ' '+HeaderStr+' ';
  573.       IF NOT MakeWindow(W, ColH, RowH, ColH+Width-1, RowH+Height-1,
  574.                         TRUE, TRUE, FALSE, A[TeAttr], A[FrAttr], A[HeAttr],
  575.                         HeaderStr) THEN
  576.         Exit;
  577.       IF NOT DisplayWindow(W) THEN
  578.         Exit;
  579.       HiddenCursor;
  580.  
  581.       {Allow user to browse help}
  582.       Done := FALSE;
  583.       Pnum := 1;
  584.       Lnum := 0;
  585.       REPEAT
  586.         IF Pnum <> Lnum THEN BEGIN
  587.           DrawPage(C^, P[Pnum], P[Pnum+1], Width-3, A, PA[Pnum]);
  588.           ShowPrompt(Pnum, Pcnt, RowH+Height-1, ColH+1, ColH+Width-2, A[HeAttr]);
  589.           Lnum := Pnum;
  590.         END;
  591.         CASE ReadKeyWord OF
  592.           $011B :                 {Escape}
  593.             Done := TRUE;
  594.           $4700 :                 {Home}
  595.             Pnum := 1;
  596.           $4800, $4900 :          {Up arrow, PgUp}
  597.             IF Pnum > 1 THEN
  598.               Dec(Pnum);
  599.           $4F00 :                 {End}
  600.             Pnum := Pcnt;
  601.           $5000, $5100 :          {Down arrow, PgDn}
  602.             IF Pnum < Pcnt THEN
  603.               Inc(Pnum);
  604.         END;
  605.       UNTIL Done;
  606.  
  607.       {Restore the screen}
  608.       DisposeWindow(EraseTopWindow);
  609.       ShowHelp := TRUE;
  610.     END;
  611.   END;
  612.  
  613.   FUNCTION GetNameBuffer(Help           : HelpPtr;
  614.                          VAR P          : CharArrayPtr;
  615.                          VAR SizeAlloc : Word) : BOOLEAN;
  616.     {-Return pointer to loaded array of pick names}
  617.   VAR
  618.     BytesRead      : Word;
  619.   BEGIN
  620.     GetNameBuffer := FALSE;
  621.     SizeAlloc := 0;
  622.     WITH Help^, Hdr DO BEGIN
  623.       IF InRAM THEN BEGIN
  624.         {Already in memory, just compute the pointer}
  625.         P := Pointer(HdrP);
  626.         Inc(LongInt(P), SIZEOF(HelpHeader));
  627.       END ELSE IF Open THEN BEGIN
  628.         {On disk, first allocate space}
  629.         IF NOT GetMemCheck(P, ItemCnt*NameSize) THEN
  630.           Exit;
  631.         SizeAlloc := ItemCnt*NameSize;
  632.         {Read names into buffer}
  633.         Seek(Fil, SIZEOF(HelpHeader));
  634.         IF IOResult <> 0 THEN
  635.           Exit;
  636.         BlockRead(Fil, P^, SizeAlloc, BytesRead);
  637.         IF (IOResult <> 0) OR (BytesRead <> SizeAlloc) THEN
  638.           Exit;
  639.       END ELSE
  640.         {Help file not open}
  641.         Exit;
  642.     END;
  643.     GetNameBuffer := TRUE;
  644.   END;
  645.  
  646.   FUNCTION ShowHelpByName(Help : HelpPtr; Name : STRING) : BOOLEAN;
  647.     {-Display help screen for topic with pick name Name}
  648.   VAR
  649.     P              : CharArrayPtr;
  650.     NP             : ^STRING;
  651.     SizeAlloc      : Word;
  652.     I              : Word;
  653.   BEGIN
  654.     ShowHelpByName := FALSE;
  655.     IF GetNameBuffer(Help, P, SizeAlloc) THEN
  656.       WITH Help^, Hdr DO BEGIN
  657.         {Match the name}
  658.         Name := StUpcase(Name);
  659.         NP := Pointer(P);
  660.         I := 1;
  661.         WHILE I <= ItemCnt DO BEGIN
  662.           IF StUpcase(NP^) = Name THEN BEGIN
  663.             {Show the help, getting status from that routine}
  664.             ShowHelpByName := ShowHelp(Help, I);
  665.             {Force exit}
  666.             I := ItemCnt;
  667.           END;
  668.           Inc(I);
  669.           Inc(LongInt(NP), NameSize);
  670.         END;
  671.       END;
  672.     IF SizeAlloc <> 0 THEN
  673.       FreeMem(P, SizeAlloc);
  674.   END;
  675.  
  676.   {$IFDEF UsingPickUnit}
  677.   VAR
  678.     PBuff : CharArrayPtr;  {Pointer to buffer of pick names}
  679.     NSize : Byte;          {Size of array element in pick buffer}
  680.  
  681.   {$F+}
  682.   FUNCTION SendHelpName(Item : Word) : STRING;
  683.     {-Pass each help item to the pick unit}
  684.   VAR
  685.     NP : ^STRING;
  686.   BEGIN
  687.     NP := pointer(PBuff);
  688.     Inc(LongInt(NP),NSize*(Item-1));
  689.     SendHelpName := ' '+NP^;
  690.   END;
  691.   {$F-}
  692.  
  693.   FUNCTION PickHelp(Help : HelpPtr; XLow, YLow, YHigh, PickCols : Byte) : Word;
  694.     {-Display help pick list, returning Item number, or 0 for none}
  695.   VAR
  696.     SizeAlloc : Word;
  697.     Choice : Word;
  698.     PickChar : CHAR;
  699.     XHigh : Byte;
  700.     A : HelpAttrArray;
  701.   BEGIN
  702.     PickHelp := 0;
  703.     IF GetNameBuffer(Help, PBuff, SizeAlloc) THEN
  704.       WITH Help^, Hdr DO BEGIN
  705.         {Set up global with NameSize}
  706.         NSize := NameSize;
  707.  
  708.         {Choose the window width}
  709.         XHigh := XLow+PickCols*(NSize+1)+1;
  710.         IF XHigh > CurrentWidth THEN
  711.           XHigh := CurrentWidth;
  712.  
  713.         {Set colors and frame}
  714.         CASE LastMode AND $FF OF
  715.           0, 2, 7 : A := MAttr;
  716.           1, 3 : A := CAttr;
  717.         ELSE
  718.           Exit;
  719.         END;
  720.         FrameChars := Frame;
  721.         TpPick.PickMatrix := PickCols;
  722.  
  723.         {Pick from list}
  724.         IF PickWindow(@SendHelpName, ItemCnt, XLow, YLow, XHigh, YHigh, TRUE,
  725.                       A[TeAttr], A[FrAttr], A[HeAttr], A[SpAtt1], PickTitle,
  726.                       [#13, #27], Choice, PickChar) THEN
  727.           IF PickChar = #13 THEN
  728.             PickHelp := Choice;
  729.       END;
  730.     IF SizeAlloc <> 0 THEN
  731.       FreeMem(PBuff, SizeAlloc);
  732.   END;
  733.   {$ENDIF}
  734.  
  735. CONST
  736.   StackSize      = 2000;          {Size of stack for int 16 handler}
  737. VAR
  738.   SaveExit       : Pointer;       {Exit chain}
  739.   SaveInt16      : Pointer;       {Previous int 16}
  740.   HelpSystem     : HelpPtr;       {Help system for context sensitive help}
  741.   HelpActive     : BOOLEAN;       {True if context sensitive help popped up}
  742.   HelpKey        : Word;          {Scan word for help popup}
  743.   StackSpace     : Pointer;       {Pointer to alternate stack}
  744.  
  745.   {$L TPHELP.OBJ}
  746.   PROCEDURE Int16Handler;
  747.     {-Handle int 16 for popup context sensitive help}
  748.     EXTERNAL;
  749.  
  750.   PROCEDURE RemoveHelp;
  751.     {-Deinstall context sensitive help}
  752.   BEGIN
  753.     IF HelpIntInstalled THEN BEGIN
  754.       ExitProc := SaveExit;
  755.       FreeMem(StackSpace, StackSize);
  756.       SetIntVec($16, SaveInt16);
  757.       HelpIntInstalled := FALSE;
  758.     END;
  759.   END;
  760.  
  761.   PROCEDURE SetContextHelp(Help : HelpPtr; Key : Word);
  762.     {-Install a keyboard interrupt handler to pop help when Key is pressed}
  763.   BEGIN
  764.     IF NOT HelpIntInstalled THEN
  765.       IF Help^.InRAM THEN
  766.         IF MaxAvail >= StackSize THEN BEGIN
  767.           GetMem(StackSpace, StackSize);
  768.           GetIntVec($16, SaveInt16);
  769.           SetIntVec($16, @Int16Handler);
  770.           SaveExit := ExitProc;
  771.           ExitProc := @RemoveHelp;
  772.           HelpIntInstalled := TRUE;
  773.         END;
  774.     HelpActive := FALSE;
  775.     HelpKey := Key;
  776.     HelpSystem := Help;
  777.   END;
  778.  
  779. END.
  780.