home *** CD-ROM | disk | FTP | other *** search
/ Power-Programmierung / CD1.mdf / pascal / library / dos / t_power / tphelp.pas < prev    next >
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.