home *** CD-ROM | disk | FTP | other *** search
/ Programmer 7500 / MAX_PROGRAMMERS.iso / PASCAL / TPPICK.ZIP / TPPICK.PAS < prev   
Encoding:
Pascal/Delphi Source File  |  1988-01-21  |  16.6 KB  |  491 lines

  1. {
  2. Copyright (c) 1987 by TurboPower Software. May be freely used by and
  3. distributed to owners of Turbo Professional 4.0.
  4.  
  5. Modified by Dan T. Davis, January 1988.
  6.  
  7. See TPDir for an example of using the TPPick unit.
  8. }
  9.  
  10. {$R-,I-,S-,V-}
  11.  
  12. unit TpPick;
  13.   {-Manage scrolling pick windows}
  14.   {{}
  15. interface
  16.  
  17. uses
  18.   TPString,
  19.   TPCrt,
  20.   TPWindow;
  21.  
  22. const
  23.   PickAttr : Boolean = False; {If True, special color attributes used to pick item}
  24.   PickAttrN : Byte = $00;    {Special Color Attribute; normal color}
  25.   PickAttrH : Byte = $00;    {Special Color Attribute; highlight color}
  26.   HideCursor : Boolean = True; {False to leave hardware cursor on screen}
  27.   PickMinRows : Word = 0;    {We want at least this many rows in PickWindow}
  28.   PickMaxRows : Word = 9999; {We want at most this many rows in PickWindow}
  29.   PickMatrix : Byte = 1;     {Number of Horizontal Fields in window}
  30.   PickStick : Boolean = True; {Get "stuck" at top/bottom on SCROLLING PickWindows?}
  31.  
  32. type
  33.   CharSet = set of Char;
  34.  
  35. function PickWindow
  36.   (StringFunc : Pointer;     {Pointer to function to return each item string}
  37.    NumItems : Word;          {Number of items to pick from}
  38.    XLow, YLow : Byte;        {Window coordinates, including frame if any}
  39.    XHigh, YHigh : Byte;      {Window coordinates, including frame if any}
  40.    DrawFrame : Boolean;      {True to draw a frame around window}
  41.    WindowAttr : Byte;        {Video attribute for body of window}
  42.    FrameAttr : Byte;         {Video attribute for frame}
  43.    HeaderAttr : Byte;        {Video attribute for header}
  44.    SelectAttr : Byte;        {Video attribute for selected item}
  45.    Header : string;          {Title for window}
  46.    PickSet : CharSet;        {Selection characters}
  47.    var Choice : Word;        {The item selected, in the range 1..NumItems}
  48.    var PickChar : Char       {Character used to perform selection}
  49.    ) : Boolean;              {True if PickWindow was successful}
  50.   {-Display a window, let user scroll around in it, and return choice.
  51.     Choice returned is in the range 1..NumItems.
  52.     PickChar is an element of PickSet.}
  53.  
  54. procedure FillPickWindow
  55.   (W : WindowPtr;            {Which window to display pick list}
  56.    StringFunc : Pointer;     {Pointer to function to return each item string}
  57.    Choice : Word;            {Choice,row tell how the items should be drawn}
  58.    Row : Word;               {           in a manner consistent with PickBar}
  59.    NumItems : Word);         {Number of items in PickArray}
  60.   {-Display a window, fill it with choices, and return.
  61.     Choice specifies the initial item highlighted.}
  62.  
  63. procedure PickBar
  64.   (W : WindowPtr;            {The window to operate in}
  65.    StringFunc : Pointer;     {Pointer to function to return items}
  66.    var Choice : Word;        {The item selected, range 1..numitems}
  67.    var Row : Word;           {The row to draw the bar on}
  68.    NumItems : Word;          {The number of items to pick from}
  69.    SelectAttr : Byte;        {Video attribute for bars}
  70.    PickSet : CharSet;        {Selection Characters}
  71.    var PickChar : Char;      {Character used to perform selection}
  72.    EraseBar : Boolean);      {Should we recolor the bar when finished?}
  73.   {-Choose from a pick list already displayed on the screen}
  74.  
  75.   {=========================================================================}
  76.  
  77.   (*}*)
  78. implementation
  79.  
  80. type
  81.  
  82.   {Details of window record. Must match that of TPWINDOW!}
  83.   {This type section can be removed if using TPWINDOW version 4.02 or later}
  84.  
  85.   BufferArray = array[1..MaxInt] of Char; {Will hold screen image}
  86.   BufP = ^BufferArray;
  87.   WindowRec =                {Details of a window}
  88.   record
  89.     XL, YL : Byte;           {Turbo window coordinates (no frame included)}
  90.     XH, YH : Byte;
  91.     XL1, YL1 : Byte;         {Overall window coordinates (frame included)}
  92.     XH1, YH1 : Byte;
  93.     FAttr : Byte;            {Attribute for frame}
  94.     WAttr : Byte;            {Attribute for window contents}
  95.     HAttr : Byte;            {Attribute for header}
  96.     Framed : Boolean;        {True to draw frame around window}
  97.     Clear : Boolean;         {True to clear window when it is displayed}
  98.     Save : Boolean;          {True to save contents when window is erased}
  99.     Active : Boolean;        {True if window is currently on screen}
  100.     DisplayedOnce : Boolean; {True if window displayed at least once}
  101.     Covers : BufP;           {Points to buffer of what window covers}
  102.     Holds : BufP;            {Points to buffer of what window holds if Save is True}
  103.     BufSize : Word;          {Size of screen buffers}
  104.     CStart : Byte;           {Scan lines for cursor}
  105.     CEnd : Byte;
  106.     CursorX : Byte;          {Position of cursor}
  107.     CursorY : Byte;
  108.     Frame : FrameArray;      {Stores frame type of window if Framed is True}
  109.     HeaderP : ^string;       {Stores frame title, nil if none}
  110.     Exploding : Boolean;     {True if window displays and erases in stages}
  111.     ExploDelay : Word;       {Milliseconds per stage of explosion}
  112.   end;
  113.   WindowP = ^WindowRec;
  114.  
  115. var
  116.   XSize : Word;              {Active width of pick window (no frame)}
  117.   YSize : Word;              {Active height of pick window}
  118.   PickFunc : Pointer;        {Pointer to function that returns each string}
  119.  
  120.   Items : Word;              {Total Items being considered}
  121.   ItemWidth : Byte;          {Maximum width for an item}
  122.   ItemOffSet : Word;         {Offset Between Item Numbers in different Columns}
  123.   ItemWrap : Boolean;        {Wrap when hitting PickWindow periphery}
  124.  
  125.   procedure Lower(var Source : Word; MaxVal : Word);
  126.   begin
  127.     if Source > MaxVal then
  128.       Source := MaxVal;
  129.   end;
  130.  
  131.   function InitPickVars
  132.     (W : WindowPtr;
  133.      NumItems : Word;
  134.      StringFunc : Pointer) : Boolean;
  135.     {-Initialize variables we'll use for display}
  136.   begin
  137.     InitPickVars := True;
  138.  
  139.     {Make sure the window is on screen; if it is, ASSUME that}
  140.     {the user has made it the top window with SETTOPWINDOW or SELECTWINDOW}
  141.     {Otherwise, assume the user wants us to turn it on}
  142.     if DisplayWindow(W) then {we had to turn it on} ;
  143.  
  144.     if W <> nil then
  145.       with WindowP(W)^ do begin
  146.         XSize := Succ(XH-XL);
  147.         YSize := Succ(YH-YL);
  148.     end else ;
  149.     { you should have already set XSize and YSize }
  150.  
  151.     Items := NumItems;
  152.     ItemWidth := XSize div PickMatrix;
  153.  
  154.     Lower(YSize, Items);
  155.     Lower(YSize, PickMaxRows);
  156.  
  157.     ItemOffSet := (Items+Pred(PickMatrix)) div PickMatrix;
  158.     if ItemOffSet < PickMinRows then
  159.       ItemOffSet := PickMinRows;
  160.     Lower(ItemOffSet, Items);
  161.  
  162.     Lower(YSize, ItemOffSet);
  163.  
  164.     ItemWrap := (YSize = ItemOffSet) or not PickStick;
  165.  
  166.     PickFunc := StringFunc;
  167.  
  168.     {Validate item information}
  169.     if (YSize = 0) or (PickFunc = nil) then
  170.       InitPickVars := False;
  171.  
  172.     {Were we able to show the window?}
  173.     if (W <> nil) and not WindowP(W)^.Active then
  174.       InitPickVars := False;
  175.   end;
  176.  
  177.   procedure ReCalc(var Row : Word; var Choice : Word; var Top : Word);
  178.   var
  179.     I : Integer;
  180.   begin
  181.     {make sure that we are asking for a valid Choice/Row combination}
  182.     I := Succ(Pred(Choice) mod ItemOffSet);
  183.     Lower(Row, I);
  184.     Lower(Row, YSize);
  185.     I := YSize-(ItemOffSet-I);
  186.     if Row < I then
  187.       Row := I;
  188.     if Row < 1 then
  189.       Row := 1;
  190.     Top := Succ((Choice-Row) mod ItemOffSet);
  191.   end;
  192.  
  193.   {{}
  194.   function GetString(Item : Word) : string;
  195.     {-Return the name of each item}
  196.     inline($FF/$1E/>PickFunc); {CALL DWORD PTR [>PickFunc]}
  197.   (*}*)
  198.  
  199.   procedure DrawItem(ItemNum : Word; Row, Col, Attr, SpAttr : Byte);
  200.     {-Draw the specified item}
  201.   var
  202.     S : string;
  203.   begin
  204.     if ItemNum <= Items then
  205.       S := GetString(ItemNum)
  206.     else
  207.       S := '';
  208.     if Length(S) <= ItemWidth then
  209.       S := Pad(S, ItemWidth)
  210.     else
  211.       S[0] := Chr(ItemWidth);
  212.     if PickAttr then begin
  213.       FastWriteWindow(S, Row, Col, SpAttr);
  214.       PickAttr := False;
  215.     end else
  216.       FastWriteWindow(S, Row, Col, Attr);
  217.   end;
  218.  
  219.   procedure DrawPage(Top : Word; Attr, SpAttr : Byte);
  220.     {-Draw a full page of items, with Choice shown on Row}
  221.   var
  222.     I, J, BeforeTop, AtCol : Word;
  223.   begin
  224.     for I := 0 to Pred(PickMatrix) do begin
  225.       AtCol := Succ(I*ItemWidth);
  226.       BeforeTop := Pred(Top+I*ItemOffSet);
  227.       for J := 1 to YSize do
  228.         DrawItem(J+BeforeTop, J, AtCol, Attr, SpAttr);
  229.     end;
  230.   end;
  231.  
  232.   procedure PickBar
  233.     (W : WindowPtr;          {The window to operate in}
  234.      StringFunc : Pointer;   {Pointer to function to return items}
  235.      var Choice : Word;      {The item selected, range 1..numitems}
  236.      var Row : Word;         {The row to draw the bar on}
  237.      NumItems : Word;        {The number of items to pick from}
  238.      SelectAttr : Byte;      {Video attribute for bars}
  239.      PickSet : CharSet;      {Selection Characters}
  240.      var PickChar : Char;    {Character used to perform selection}
  241.      EraseBar : Boolean);    {Should we recolor the bar when finished?}
  242.   var
  243.     SaveBreak : Boolean;
  244.     XY, CursorScanLines : Word;
  245.     Done : Boolean;
  246.     KW : Word;
  247.     Top, PrevTop, PrevChoice, PrevRow : Word;
  248.     Column : Word;
  249.     AtLoc : Word;
  250.     MoveMax : Word;
  251.  
  252.   begin
  253.     if not InitPickVars(W, NumItems, StringFunc) then
  254.       Exit;
  255.  
  256.     { Initialize PrevTop to make sure we draw page initially }
  257.     PrevTop := 0;
  258.  
  259.     with WindowP(W)^ do begin
  260.  
  261.       GetCursorState(XY, CursorScanLines);
  262.       if HideCursor then
  263.         HiddenCursor
  264.       else
  265.         NormalCursor;
  266.       SaveBreak := CheckBreak;
  267.       CheckBreak := False;
  268.  
  269.       {Loop getting characters}
  270.       Done := False;
  271.       repeat
  272.  
  273.         {Check to see if we need to redraw the page or erase the bar}
  274.         ReCalc(Row, Choice, Top);
  275.         if PrevTop <> Top then
  276.           DrawPage(Top, WAttr, PickAttrN)
  277.         else if (PrevChoice <> Choice) or (PrevRow <> Row) then
  278.           DrawItem(PrevChoice, PrevRow, Column, WAttr, PickAttrN);
  279.  
  280.         PrevTop := Top;
  281.         PrevChoice := Choice;
  282.         PrevRow := Row;
  283.         Column := Succ((Pred(Choice) div ItemOffSet)*ItemWidth);
  284.  
  285.         {Highlight the selected entry}
  286.         DrawItem(Choice, Row, Column, SelectAttr, PickAttrH);
  287.  
  288.         GoToXY(Column, Row);
  289.  
  290.         {Find our relative Location in the PickList}
  291.         AtLoc := Succ(Pred(Choice) mod ItemOffSet);
  292.  
  293.         {Get a command}
  294.         KW := ReadKeyWord;
  295.  
  296.         {See if a pick character first}
  297.         PickChar := Char(lo(KW));
  298.         if PickChar = #0 then
  299.           PickChar := Char(hi(KW) or $80);
  300.         if PickChar in PickSet then
  301.           Done := True;
  302.  
  303.         if not Done then
  304.           case KW of
  305.             $4700 :          {Home}
  306.               Choice := 1;
  307.  
  308.             $4800 :          {Up arrow}
  309.               if AtLoc <> 1 then begin
  310.                 {Move to previous item}
  311.                 Dec(Choice);
  312.                 {Move selection bar}
  313.                 Dec(Row);
  314.               end else if ItemWrap then begin
  315.                 {Wrap to previous column, if any}
  316.                 if Choice > 1 then
  317.                   Dec(Choice)
  318.                 else
  319.                   Choice := Items;
  320.                 Row := YSize;
  321.               end;
  322.  
  323.             $4900 :          {PgUp}
  324.               begin
  325.                 MoveMax := Pred(AtLoc);
  326.                 Lower(MoveMax, YSize);
  327.                 if MoveMax > 0 then
  328.                   Dec(Choice, MoveMax)
  329.                 else if ItemWrap then begin
  330.                   {Wrap to previous column, if any}
  331.                   if Choice > 1 then
  332.                     Dec(Choice)
  333.                   else
  334.                     Choice := Items;
  335.                   Row := YSize;
  336.                 end;
  337.               end;
  338.  
  339.             $4B00 :          {Left Arrow}
  340.               begin
  341.                 if Choice > ItemOffSet then
  342.                   Dec(Choice, ItemOffSet)
  343.                 else if Choice > 1 then begin
  344.                   Choice := Pred(Choice)+Pred(PickMatrix)*ItemOffSet;
  345.                   Dec(Row);
  346.                 end else if ItemWrap then
  347.                   Choice := PickMatrix*ItemOffSet;
  348.                 if Choice > Items then
  349.                   repeat Dec(Choice, ItemOffSet) until Choice <= Items;
  350.               end;
  351.  
  352.             $4D00 :          {Right Arrow}
  353.               if Choice <= Items-ItemOffSet then
  354.                 Inc(Choice, ItemOffSet)
  355.               else if AtLoc <> ItemOffSet then begin
  356.                 Choice := Succ(AtLoc);
  357.                 Inc(Row);
  358.               end else if ItemWrap then
  359.                 Choice := 1;
  360.  
  361.             $4F00 :          {End}
  362.               begin
  363.                 Choice := Items;
  364.                 Row := 1;
  365.               end;
  366.  
  367.             $5000 :          {Down arrow}
  368.               if (AtLoc <> ItemOffSet) and (Choice < Items) then begin
  369.                 {Move to next item}
  370.                 Inc(Choice);
  371.                 {Move selection bar}
  372.                 Inc(Row);
  373.               end else if ItemWrap then begin
  374.                 {Wrap to next column, if any}
  375.                 if Choice < Items then
  376.                   Inc(Choice)
  377.                 else
  378.                   Choice := 1;
  379.                 Row := 1;
  380.               end else if (Choice = Items) then
  381.                 Dec(Row);
  382.  
  383.             $5100 :          {PgDn}
  384.               begin
  385.                 MoveMax := ItemOffSet-AtLoc;
  386.                 Lower(MoveMax, YSize);
  387.                 if (MoveMax > 0) and (Choice < Items) then begin
  388.                   Inc(Choice, MoveMax);
  389.                   if Choice > Items then begin
  390.                     Choice := Items;
  391.                     Row := 1;
  392.                   end;
  393.                 end else if ItemWrap then begin
  394.                   {Wrap to next column, if any}
  395.                   if Choice < Items then
  396.                     Inc(Choice)
  397.                   else
  398.                     Choice := 1;
  399.                   Row := 1;
  400.                 end;
  401.               end;
  402.           end;
  403.       until Done;
  404.       if EraseBar then
  405.         DrawItem(Choice, Row, Column, WAttr, PickAttrN);
  406.       CheckBreak := SaveBreak;
  407.       RestoreCursorState(XY, CursorScanLines);
  408.     end;
  409.   end;
  410.  
  411.   function PickWindow
  412.     (StringFunc : Pointer;   {Pointer to function to return each item string}
  413.      NumItems : Word;        {Number of items in PickArray}
  414.      XLow, YLow : Byte;      {Window coordinates, including frame if any}
  415.      XHigh, YHigh : Byte;    {Window coordinates, including frame if any}
  416.      DrawFrame : Boolean;    {True to draw a frame around window}
  417.      WindowAttr : Byte;      {Video attribute for body of window}
  418.      FrameAttr : Byte;       {Video attribute for frame}
  419.      HeaderAttr : Byte;      {Video attribute for header}
  420.      SelectAttr : Byte;      {Video attribute for selected item}
  421.      Header : string;        {Title for window}
  422.      PickSet : CharSet;      {Selection characters}
  423.      var Choice : Word;      {The item selected, in the range 1..NumItems}
  424.      var PickChar : Char     {Character used to perform selection}
  425.      ) : Boolean;            {True if PickWindow was successful}
  426.   var
  427.     Correction : Integer;
  428.     Row : Word;
  429.     W : WindowPtr;
  430.  
  431.   begin
  432.  
  433.     {Assume failure}
  434.     PickWindow := False;
  435.  
  436.     {Get a Value for YHigh}
  437.     if DrawFrame then
  438.       Correction := -1
  439.     else
  440.       Correction := +1;
  441.     XSize := XHigh-XLow+Correction;
  442.     YSize := YHigh-YLow+Correction;
  443.     if not InitPickVars(nil, NumItems, StringFunc) then
  444.       Exit;
  445.     if YSize >= PickMinRows then
  446.       YHigh := YLow+YSize-Correction
  447.     else
  448.       YHigh := YLow+PickMinRows-Correction;
  449.  
  450.     {Initialize the window}
  451.     if not MakeWindow(W, XLow, YLow, XHigh, YHigh,
  452.                       DrawFrame, True, False,
  453.                       WindowAttr, FrameAttr, HeaderAttr,
  454.                       Header) then Exit;
  455.  
  456.     if not InitPickVars(W, NumItems, StringFunc) then
  457.       Exit;
  458.  
  459.     {Initial item is the first one}
  460.     Choice := 1;
  461.     Row := 1;
  462.     PickBar(W, PickFunc, Choice, Row, Items,
  463.             SelectAttr, PickSet, PickChar, False);
  464.  
  465.     {Restore the screen and deallocate the window}
  466.     W := EraseTopWindow;
  467.     DisposeWindow(W);
  468.  
  469.     {If we get to here, all was well}
  470.     PickWindow := True;
  471.   end;
  472.  
  473.   procedure FillPickWindow
  474.     (W : WindowPtr;          {Which window to display pick list}
  475.      StringFunc : Pointer;   {Pointer to function to return each item string}
  476.      Choice : Word;          {Choice,row tell how the items should be drawn}
  477.      Row : Word;             {           in a manner consistent with PickBar}
  478.      NumItems : Word);       {Number of items in PickArray}
  479.   var
  480.     Top : Word;
  481.   begin
  482.     if not InitPickVars(W, NumItems, StringFunc) then
  483.       Exit;
  484.  
  485.     ReCalc(Row, Choice, Top);
  486.     DrawPage(Top, WindowP(W)^.WAttr, PickAttrN);
  487.   end;
  488.  
  489. end.
  490.  
  491.