home *** CD-ROM | disk | FTP | other *** search
/ Celestin Apprentice 5 / Apprentice-Release5.iso / Source Code / Pascal / Snippets / vListMngr 1.0 / Sources ƒ / vListMngr9.2.5 < prev   
Encoding:
Text File  |  1996-04-10  |  82.6 KB  |  2,360 lines  |  [TEXT/PJMM]

  1. unit vListMngr;
  2.  
  3. {version 3}
  4. {    handles copying and pasting from scrap}
  5. {version 4}
  6. {    fixed problems with multi-cell selection}
  7. {version 7}
  8. {    attempt to activate/deactivate scroll bar as number of lines needed varies}
  9. {version 8.6}
  10. {    changed vLNew to create a list with:}
  11. {        No heading}
  12. {        list font = window font}
  13. {    added routines:}
  14. {        SetHeading to add/change heading}
  15. {        SetListFont to change list font}
  16. {        SetHeadingFont to change list font}
  17. {version 8.9}
  18. {    got resizing of list to work by adding/modifying routines:}
  19. {        AdjustScrollBars}
  20. {        vLInsetList}
  21. {        vLSize}
  22. {    8.9.4}
  23. {        Altered SetMaxScrollBar to avoid cutting off right side of rightmost cell}
  24. {9.01}
  25. {    vLNew uses same call as LNew - can be used interchangeably}
  26. {9.02}
  27. {    changed vLInset}
  28. {**PROBLEM  -  if last column shows only partially, we move over a whold column in order to display it, and then move the Scroll bars}
  29. {**SOLUTION - don't move scroll bars around every time we scroll - only when:}
  30. {    rView or lView changes}
  31. {    rows are added or deleted}
  32. {    cols are added or deleted}
  33. {9.05    }
  34. {    vLDrawCell changed to fix problem with unerased cell areas and port Clip}
  35. {    removed  HLock/HUnLock/With from all internally called routines}
  36. {9.06}
  37. {    vLCalcCellWidths changed to avoid trashing existing cell widths}
  38. {    vLScrollHorz  changed  to keep headings straight}
  39. {9.1.0}
  40. {    removed format record}
  41. {    removed vListHeading record}
  42. {9.1.1}
  43. { added fields:}
  44. {    listTE}
  45. {    lActiveTE}
  46. {    lEditMode}
  47. {9.2.0}
  48. {    ScrapToCells}
  49. {    CellsToScrap}
  50. {    maxOffsets}
  51. {    maxChars}
  52. {9.21}
  53. {    vLAddCol}
  54. {9.2.2}
  55. {    Fix vLInsetList}
  56. {    Add CalcVisBottom}
  57. {PROBLEM}
  58. {    shrink window with headings on}
  59. {    List is drawn outside scroll bars}
  60. {    Can't replicate problem!!}
  61. {PROBLEM}
  62. {    Top border is not drawn around list when there are no headings}
  63. {    Top border is drawn when headings are present, but border is not erased on resizing }
  64. {        border is outside clip rectangle}
  65. {9.2.3}
  66. {    Changed frame drawing in vLDrawCell}
  67. {        frame top & left in Cell rectangle}
  68. {        frame bottom & right outside Cell rectangle}
  69. {        clip to CalcVisRect to avoid trashing scroll bars}
  70. {    Changed AdjustScrollBars to coincide}
  71. {    Changed vLDrawHeading similarly}
  72. {     Changed StartEdit similarly}
  73. {    vLTEDispose}
  74. {9.2.4}
  75. {    vLCalcCellWidths}
  76. {    vLInsetList}
  77. {    vLSizeList}
  78. {9.2.5}
  79. {    vLNew - changed cellSize to pcellSize for passed value, was getting confused with vList field cellSize}
  80. {            - check for allocation of vList and cells}
  81.  
  82.  
  83. {PROBLEM}
  84. {TE has weird outline}
  85.  
  86. interface
  87.     const
  88. { Masks for selection flags (selFlags) }
  89.         LOnlyOne = -128;                 { 0 = multiple selections, 1 = one }
  90.         LExtendDrag = 64;                 { 1 = drag select without shift key }
  91.         LNoDisjoint = 32;                     { 1 = turn off selections on click }
  92.         LNoExtend = 16;                     { 1 = don't extend shift selections }
  93.         LNoRect = 8;                         { 1 = don't grow (shift,drag) selection as rect }
  94.         LUseSense = 4;                     { 1 = shift should use sense of start cell }
  95.         LNoNilHilite = 2;                     { 1 = don't hilite empty cells }
  96.  
  97. { Masks for other flags (listFlags) }
  98.         LDoVAutoscroll = 2;                 { 1 = allow vertical autoscrolling }
  99.         LDoHAutoscroll = 1;                 { 1 = allow horizontal autoscrolling }
  100.  
  101. {Size of list}
  102.         maxCols = 31;
  103.         maxChars = 16000;
  104.         maxOffsets = 4095;
  105.  
  106.     type
  107.         Cell = Point;
  108.  
  109.         EditModeType = (editCell, editTE);
  110.  
  111.         DataArray = packed array[0..maxChars] of Char;
  112.         DataPtr = ^DataArray;
  113.         DataHandle = ^DataPtr;
  114.  
  115.         OffsetArray = array[0..maxOffsets] of INTEGER;
  116.  
  117.         vLScrapHandle = ^vLScrapPtr;
  118.         vLScrapPtr = ^vListScrapRec;
  119.         vListScrapRec = record
  120.                 scrapBounds: RECT;            {}
  121.                 scrapData: dataArray;
  122.                 scrapOffsets: offsetArray;
  123.             end;
  124.  
  125.         lHeadArray = array[1..4] of STR255;
  126.  
  127.         WidthArray = array[0..maxCols] of Integer;
  128.  
  129.         modifierType = (none, command, option, control, shift);
  130.  
  131.         vListHandle = ^vListPtr;
  132.         vListPtr = ^vListRec;
  133.         vListRec = record
  134.                 rView: RECT;                    {rectangle in which list heading and are viewed}
  135.                 port: GrafPtr;                     {Grafport that owns us}
  136.                 indent: Point;                      {Indent pixels in cell}
  137.                 cellSize: Point;                {Cell width and height (width is ignored)}
  138.                 visible: Rect;                       {visible row/column bounds, i.e. indices of top left and bottom right cells}
  139.                 vScroll: ControlHandle;        {vertical scroll bar (or NIL)}
  140.                 hScroll: ControlHandle;        {horizontal scroll bar (or NIL)}
  141.                 selFlags: SignedByte;        { defines selection characteristics}
  142.                 LActive: Boolean;            { active or not}
  143.                 LReserved: SignedByte;        { internally used flags}
  144.                 listFlags: SignedByte;        { other flags}
  145.                 clikTime: Longint;            { save time of last click}
  146.                 clikLoc: Point;                { save position of last click}
  147.                 mouseLoc: Point;                 { current mouse position}
  148.                 lClikLoop: Ptr;                 { routine called repeatedly during ListClick}
  149.                 lastClick: Cell;                  { the last cell clicked in}
  150.                 refCon: Longint;                    { reference value}
  151.                 listDefProc: Handle;            { Handle to the defProc}
  152.                 userHandle: Handle;              { General purpose handle for user}
  153.                 dataBounds: Rect;            { Total number of rows/columns}
  154.                 cells: DataHandle;            { Handle to data}
  155.                 maxIndex: Integer;               { index past the last element = length of cellArray}
  156.                 cellArray: OffsetArray;        { offsets to elements  up to maxCols and maxOffsets/(maxCols+1) rows}
  157.                 cellWidth: WidthArray;        {array of cell widths}
  158.                 lView: Rect;                        {Rect in which list alone is viewed}
  159.                 frameWidth: INTEGER;        {width of frame around cells}
  160.                 just: INTEGER;                {text justification mode}
  161.                 lFont, lSize: INTEGER;        {list font info}
  162.                 lFace: Style;                    {list font info}
  163.                 nhRows: Integer;                {# rows in heading}
  164.                 lHead: lHeadArray;            {heading text}
  165.                 hFont, hSize: INTEGER;        {list font info}
  166.                 hFace: Style;                    {list font info}
  167.                 hCellHeight: INTEGER;        {height of heading cell}
  168.                 listTE: TEHandle;                {edit TE (or NIL)}
  169.                 lActiveTE: BOOLEAN;        {is the TE active?}
  170.                 lEditMode: BOOLEAN;            {are we editing a TE?}
  171.             end;
  172.  
  173.  
  174.     procedure vLActivate (act: Boolean; vlHandle: vListHandle);
  175.     {hilight selected cells and scroll bars}
  176.  
  177.     function vLAddColumn (count, colNum: Integer; vlHandle: vListHandle): Integer;
  178.  
  179.     function vLAddRow (count, rowNum: Integer; vlHandle: vListHandle): Integer;
  180.  
  181.     procedure vLAddToCell (dataPtr: Ptr; dataLen: Integer; theCell: Cell; vlHandle: vListHandle);
  182.  
  183.     procedure vLAutoScroll (vlHandle: vListHandle);
  184.  
  185.     procedure vLCalcCellWidths (var newWidth: WidthArray; var nCol: INTEGER; vlHandle: vListHandle);
  186.  
  187.     procedure vLCellSize (cSize: Point; vlHandle: vListHandle);
  188.  
  189.     function vLClick (pt: Point; modifiers: Integer; vlHandle: vListHandle): Boolean;
  190.  
  191.     procedure vLClrCell (theCell: Cell; vlHandle: vListHandle);
  192.  
  193.     procedure vLDelColumn (count, colNum: Integer; vlHandle: vListHandle);
  194.  
  195.     procedure vLDelRow (count, rowNum: Integer; vlHandle: vListHandle);
  196.  
  197.     procedure vLDispose (vlHandle: vListHandle);
  198.  
  199.     procedure vLDoDraw (drawIt: Boolean; vlHandle: vListHandle);
  200.  
  201.     procedure vLDraw (theCell: Cell; vlHandle: vListHandle);
  202.  
  203.     procedure vLFind (var offset, len: Integer; theCell: Cell; vlHandle: vListHandle);
  204.  
  205.     procedure vLFont (myFont, mySize: INTEGER; myFace: Style; vlHandle: vListHandle);
  206.  
  207.     procedure vLGetCell (dataPtr: Ptr; var dataLen: Integer; theCell: Cell; vlHandle: vListHandle);
  208.  
  209.     function vLGetSelect (next: Boolean; var theCell: Cell; vlHandle: vListHandle): Boolean;
  210.  
  211.     function vLLastClick (vlHandle: vListHandle): Cell;
  212.  
  213.     procedure vLSetHeadings (nhRows: INTEGER; headings: lHeadArray; vlHandle: vListHandle);
  214.  
  215.     procedure vLSetWidths (widths: WidthArray; vlHandle: vListHandle);
  216.  
  217.     function vLNew (plView, pdatabounds: RECT; pcellSize: POINT; procID: INTEGER; theWindow: WindowPtr; drawIt, hasGrow, scrollHoriz, scrollVert: Boolean): vListHandle;
  218.  
  219.     function vLNewScrap: vLScrapHandle;
  220.  
  221.     function vLNextCell (hNext, vNext: Boolean; var theCell: Cell; vlHandle: vListHandle): Boolean;
  222.  
  223.     procedure vLRect (var cellRect: Rect; theCell: Cell; vlHandle: vListHandle);
  224.  
  225.     procedure vLScroll (dRows, dCols: Integer; vlHandle: vListHandle);
  226.  
  227.     function vLSearch (dataPtr: Ptr; dataLen: Integer; SearchProc: Ptr; var theCell: Cell; vlHandle: vListHandle): Boolean;
  228.  
  229.     procedure vLSetCell (dataPtr: Ptr; dataLen: Integer; theCell: Cell; vlHandle: vListHandle);
  230.  
  231.     procedure vLSetSelect (setIt: Boolean; theCell: Cell; vlHandle: vListHandle);
  232.  
  233.     procedure vLInsetList (dH, dV: Integer; vlHandle: vListHandle);
  234.  
  235.     procedure vLSize (newWidth, newHeight: INTEGER; vlHandle: vListHandle);
  236.  
  237.     procedure vLUpdate (theRgn: RgnHandle; vlHandle: vListHandle);
  238.  
  239.     procedure vLUpdateSelRect (selRect: Rect; vlHandle: vListHandle);
  240.  
  241.     procedure vLCellsToScrap (whatCells: RECT; vlHandle: vListHandle; hScrap: vLScrapHandle);    {copy cells to scrap}
  242.  
  243.     procedure vLDrawHeading (vlHandle: vListHandle);
  244.  
  245.     function vLEncloseSel (vlHandle: vListHandle): Rect;
  246.  
  247.     procedure vLFrame (frameWidth: INTEGER; var vlHandle: vListHandle);
  248.  
  249.     procedure vLIndent (indent: POINT; var vlHandle: vListHandle);
  250.  
  251.     procedure vLJust (just: INTEGER; var vlHandle: vListHandle);
  252.  
  253.     procedure vLScrapToCells (whatCells: RECT; vlHandle: vListHandle; hScrap: vLScrapHandle);
  254.  
  255.     procedure vLTENew (active: BOOLEAN; whatCell: Cell; vlHandle: vListHandle);
  256.  
  257.     procedure vLTEDispose (vlHandle: vListHandle);
  258.  
  259.     procedure vLActivateTE (active: BOOLEAN; vlHandle: vListHandle);
  260.  
  261.     procedure vLKey (ch: CHAR; modifiers: Integer; vlHandle: vListHandle; vScrap: vLScrapHandle);
  262.  
  263. implementation
  264.     var
  265.         oldFont, oldSize: INTEGER;            {current font stuff}
  266.         oldFace: Style;                        {current font stuff}
  267.         oldPen: PenState;                    {current font stuff}
  268.         oldPort: GrafPtr;                        {the current GrafPort}
  269.         oldClip: RgnHandle;
  270.         oldSelectRect, SelectRect: RECT;    {selection range}
  271.  
  272.     procedure AdjustList (vlHandle: vListHandle);
  273.     forward;
  274.  
  275.     function vLCellRect (theCell: Cell; vlHandle: vListHandle): RECT;
  276.     forward;
  277.  
  278.     procedure vLUnSelectAll (vlHandle: vListHandle);
  279.     forward;
  280.  
  281.     procedure SaveFont;
  282.     begin
  283.         oldFont := oldPort^.txFont;
  284.         oldSize := oldPort^.txSize;
  285.         oldFace := oldPort^.txFace;
  286.     end;        {}
  287.  
  288.     procedure RestoreFont;
  289.     begin
  290.         TextFont(oldFont);                    {set font info}
  291.         TextSize(oldSize);
  292.         TextFace(oldFace);
  293.     end;        {}
  294.  
  295.     procedure StartEdit (theCell: Cell; vlHandle: vListHandle);
  296. {begin editing a cell using}
  297. {need to make sure cell is visible before editing}
  298.         var
  299.             cRect: RECT;
  300.             offset, len: INTEGER;
  301.     begin
  302.         vLFind(offset, len, theCell, vlHandle);        {get offset of data in vlHandle^^.cells and length of data}
  303.         vLRect(cRect, theCell, vlHandle);            {cell rectangle of the cell}
  304.     {don't edit cell which is not visible}
  305.         if vlHandle^^.listTE <> nil then
  306.             if (cRect.right - cRect.left) * (cRect.bottom - cRect.top) > 1 then
  307.                 begin
  308.                     InsetRect(cRect, 3, 3);    {}
  309. {    cRect.top := cRect.top + 1;                    {don't trash borders}
  310.                     cRect.left := cRect.left + vlHandle^^.indent.h;
  311.                     if (cRect.right - cRect.left) < 30 then        {make it at least 30 pixels wide}
  312.                         cRect.right := cRect.left + 30;
  313.                     vlHandle^^.listTE^^.destRect := cRect;        {position TE record over new cell}
  314.                     vlHandle^^.listTE^^.viewRect := cRect;
  315.                     vLFind(offset, len, theCell, vlHandle);
  316.                     HLock(Handle(vlHandle^^.cells));
  317.                     TESetText(Ptr(ORD4(vlHandle^^.cells^) + offset), len, vlHandle^^.listTE);    {move cell contents to TERec}
  318.                     HUnLock(Handle(vlHandle^^.cells));
  319.                     vlHandle^^.lastClick := theCell;
  320.                     vlHandle^^.leditMode := TRUE;
  321.                     vlHandle^^.lActiveTE := TRUE;
  322.                     TEActivate(vlHandle^^.listTE);
  323.                     TESetSelect(0, 0, vlHandle^^.listTE);                {select all text}
  324.                     TEUpdate(cRect, vlHandle^^.listTE);                {show the text}
  325.                 end;
  326.     end;        {procedure StartEdit}
  327.  
  328.     procedure StopEdit (save: BOOLEAN; theCell: Cell; vlHandle: vListHandle);
  329. {if save is true,transfer text to cell}
  330. {change editMode to editCell}
  331.         var
  332.             hChars: CharsHandle;
  333.     begin
  334.         if save then
  335.             begin
  336.         {transfer text to cell}
  337.                 hChars := TEGetText(vlHandle^^.listTE);
  338.                 HLock(Handle(hChars));
  339.                 vLSetCell(Ptr(hChars^), vlHandle^^.listTE^^.teLength, theCell, vlHandle);
  340.                 HUnLock(Handle(hChars));
  341.             end;     {if save..}
  342.         EraseRect(vlHandle^^.listTE^^.viewRect);    {}
  343.         InvalRect(vlHandle^^.listTE^^.viewRect);            {force redraw}
  344. {    vLDraw(theCell, vlHandle);        {}
  345.         vlHandle^^.leditMode := FALSE;
  346.         vlHandle^^.lActiveTE := FALSE;
  347.         TEDeActivate(vlHandle^^.listTE);
  348.         TESetSelect(0, 0, vlHandle^^.listTE);                {no  text selected}
  349.     end;        {procedure StopEdit}
  350.  
  351.     function CalcVisibleBottom (firstRow: INTEGER; var dangle: INTEGER; vlHandle: vListHandle): INTEGER;
  352.         var
  353.             i, j, nVrow: INTEGER;
  354.     begin
  355.         nVrow := 0;
  356.         i := firstRow;
  357.         j := vlHandle^^.lView.bottom - vlHandle^^.lView.top;
  358.     {calculate how many rows fit in lView}
  359.         nVrow := j div vlHandle^^.cellSize.v;
  360.         CalcVisibleBottom := firstRow + nVrow;
  361.         dangle := j - nVrow * vlHandle^^.cellSize.v;
  362.     end;        {function CalcVisibleBottom}
  363.  
  364.     function CalcVisibleRight (firstCol: INTEGER; var dangle: INTEGER; vlHandle: vListHandle): INTEGER;
  365.         var
  366.             i, j, nVcol: INTEGER;
  367.     begin
  368.         nVcol := 0;
  369.         i := firstCol;
  370.         j := vlHandle^^.lView.right - vlHandle^^.lView.left;
  371.     {calculate how many columns fit in lView}
  372.         while (j > 0) and (i < vlHandle^^.databounds.right) do
  373.             begin
  374.                 nVcol := nVcol + 1;
  375.                 if vlHandle^^.cellWidth[i] > 1 then
  376.                     j := j - vlHandle^^.cellWidth[i]
  377.                 else
  378.                     j := j - 1;
  379.                 i := i + 1;
  380.             end;        {while j>0}
  381.         CalcVisibleRight := firstCol + nVcol;
  382.         if j < 0 then
  383.             dangle := -j
  384.         else
  385.             dangle := 0;
  386.     end;        {function CalcVisible}
  387.  
  388.     procedure SetScrollMax (vlHandle: vListhandle);
  389. {set ControlMax such that if column # ControllMax is leftmost column}
  390. {the rightmost column will be fully visible}
  391.         const
  392.             active = 0;
  393.             inactive = 255;
  394.         var
  395.             i, j, dangle: INTEGER;
  396.     begin
  397. {visible.bottom-visible.top = # lines which can be seen}
  398. {set control max to # of columns which lie outside the visible rectangle}
  399.         with vlHandle^^ do
  400.             begin
  401.                 if vScroll <> nil then
  402.                     begin
  403.                         i := databounds.bottom - visible.bottom + visible.top;
  404.                         if i > 0 then
  405.                             begin
  406.                                 SetCtlMax(vScroll, i);
  407.                                 HiliteControl(vScroll, active);
  408.                             end
  409.                         else
  410.                             begin
  411.                                 SetCtlMax(vScroll, 0);
  412.                                 HiliteControl(vScroll, inactive);
  413.                             end;
  414.                     end;        {if vScroll <> nil}
  415.                 if hScroll <> nil then
  416.                     begin
  417.     {check for partially showing columns}
  418. {++++++++}
  419.                         i := databounds.right - 1;
  420.                         j := 0;
  421.                         repeat
  422.                             begin
  423.                                 j := j + cellWidth[i];
  424.                                 i := i - 1;
  425.                             end;
  426.                         until (j >= lView.right - lView.left) or (i < 0);
  427.                         if j > (lView.right - lView.left) then
  428.                             i := i + 2
  429.                         else
  430.                             i := i + 1;
  431.  
  432.                         if i > 0 then
  433.                             begin
  434.                                 SetCtlMax(hScroll, i);
  435.                                 HiliteControl(hScroll, active);
  436.                             end
  437.                         else
  438.                             begin
  439.                                 SetCtlMax(hScroll, 0);
  440.                                 HiliteControl(hScroll, inactive);
  441.                             end;
  442.                     end;        {if hScroll <> nil}
  443.             end;        {with vlHandle..}
  444.     end;        {procedure SetScrollMax}
  445.  
  446.     function CalcVisRect (vlHandle: vListHandle): RECT;
  447. {return rectangle enclosing visible cells of list}
  448. {clip rectangle to lView in case some cells are only partially visible}
  449.         var
  450.             tBool: BOOLEAN;
  451.             tCell: Cell;
  452.             tRect1, tRect2, visRect: RECT;
  453.     begin
  454.         SetPt(tCell, vlHandle^^.visible.left, vlHandle^^.visible.top);                     {first visible cell}
  455.         tRect1 := vLCellRect(tCell, vlHandle);                                            {rect of first visible cell}
  456.         SetPt(tCell, vlHandle^^.visible.right - 1, vlHandle^^.visible.bottom - 1);     {last visible cell}
  457.         tRect2 := vLCellRect(tCell, vlHandle);                                            {rect of last visible cell}
  458.         UnionRect(tRect1, tRect2, visRect);                                            {rect enclosing visible cells}
  459.         tBool := SectRect(vlHandle^^.lView, visRect, visRect);                        {make visRect smaller of lView, visible}
  460.         CalcVisRect := visRect;
  461.     end;        {CalcVisRect}
  462.  
  463.     procedure AdjustScrollBars (vlHandle: vListHandle);
  464. {adjust size and postion of scroll bars}
  465. {put scroll bars along edge of CalcVisRect}
  466. {call  if rView or lView is changed, or after scrolling}
  467.         var
  468.             tBool: BOOLEAN;
  469.             tCell: Cell;
  470.             tRect1, tRect2, visRect: RECT;
  471.     begin
  472.         visRect := CalcVisRect(vlHandle);
  473.         if vlHandle^^.hScroll <> nil then
  474.             begin
  475.                 MoveControl(vlHandle^^.hScroll, visRect.left, visRect.bottom);
  476.                 SizeControl(vlHandle^^.hScroll, visRect.right - visRect.left + 1, 16);
  477.                 vLDrawHeading(vlHandle);
  478.             end;
  479.         if vlHandle^^.vScroll <> nil then
  480.             begin
  481.                 MoveControl(vlHandle^^.vScroll, visRect.right, visRect.top);
  482.                 SizeControl(vlHandle^^.vScroll, 16, visRect.bottom - visRect.top + 1);
  483.             end;
  484.     end;        {procedure AdjustScrollBars}
  485.  
  486.     procedure AdjustList (vlHandle: vListHandle);
  487. {adjust list display to match scroll bar and redraw cells}
  488. {control values show columns and rows which should be visible}
  489. {control range max should not leave one row (or column) of cells at top (left) of screen}
  490.         var
  491.             i, j, dangle: INTEGER;
  492.             tPt: Point;
  493.             tBool: BOOLEAN;
  494.             visRect: RECT;        {contains visible cells}
  495.             tCell1, tCell2: Cell;
  496.     begin
  497.     {erase old cells}
  498.         visRect := CalcVisRect(vlHandle);
  499.         EraseRect(visRect);
  500.     {determine visible cells}
  501.         vlHandle^^.visible.top := 0;
  502.         vlHandle^^.visible.left := 0;
  503.         if vlHandle^^.vScroll <> nil then
  504.             vlHandle^^.visible.top := GetCtlValue(vlHandle^^.vScroll);
  505.         if vlHandle^^.hScroll <> nil then
  506.             vlHandle^^.visible.left := GetCtlValue(vlHandle^^.hScroll);
  507.         vlHandle^^.visible.bottom := vlHandle^^.visible.top + (vlHandle^^.lView.bottom - vlHandle^^.lView.top) div vlHandle^^.cellSize.v;
  508.     {determine # of columns at least partially visible in lView}
  509.         vlHandle^^.visible.right := CalcVisibleRight(vlHandle^^.visible.left, dangle, vlHandle);
  510.         tBool := SectRect(vlHandle^^.databounds, vlHandle^^.visible, vlHandle^^.visible);                {make visible smaller of databounds, visible}
  511.     {redraw cells}
  512.         for i := vlHandle^^.visible.top to vlHandle^^.visible.bottom do
  513.             for j := vlHandle^^.visible.left to vlHandle^^.visible.right do
  514.                 begin
  515.                     SetPt(tPt, j, i);
  516.                     vLDraw(tPt, vlHandle);
  517.                 end;
  518.     end;        {procedure AdjustList}
  519.  
  520.     function CalcDelta (vRect: RECT; code: INTEGER): INTEGER;    {0=pageUp, 1=pageDwn, 2=pageLeft, 3=pageRight}
  521. {calculate change in control setting for control hits}
  522.         var
  523.             tDelta: INTEGER;
  524.     begin
  525.         with vRect do
  526.             case code of
  527.                 0:                 {pageUp}
  528.                     tDelta := -(bottom - top - 1);
  529.                 1:                  {pageDwn}
  530.                     tDelta := bottom - top - 1;
  531.                 2:                  {pageLeft}
  532.                     tDelta := -(right - left - 1);
  533.                 3:                  {pageRight}
  534.                     tDelta := right - left - 1;
  535.                 otherwise
  536.     {do nothing}
  537.             end;        {case}
  538.         CalcDelta := tDelta;
  539.     end;        {procedure CalcDelta}
  540.  
  541.     function LoBits (bigNum: INTEGER): INTEGER;
  542. {returns lower 15 bits of INTEGER}
  543.     begin
  544.         LoBits := BitAnd(bigNum, $7FFF);
  545.     end;        {function LoBits}
  546.  
  547.     function PtToCell (pt: Point; vlHandle: vListHandle): Cell;        {return cell located at this point}
  548. {does not check to see if cell is valid}
  549.         var
  550.             tCell: Cell;
  551.             tWidth: WidthArray;
  552.             tVis: Rect;
  553.             i, j, k, tHeight: INTEGER;
  554.     begin
  555.         pt.h := pt.h - vlHandle^^.lView.left;            {convert to list coordinates}
  556.         pt.v := pt.v - vlHandle^^.lView.top;
  557.         tWidth := vlHandle^^.cellWidth;
  558.         tVis := vlHandle^^.visible;
  559.         tHeight := vlHandle^^.cellSize.v;
  560.         SetPt(tCell, tVis.left, tVis.top);            {start at left of window}
  561.         tCell.v := pt.v div tHeight + tVis.top;        {adjust vertical}
  562.         i := 0;
  563.         j := tVis.left;                                    {start at left}
  564.         repeat
  565.             i := i + tWidth[j];                            {add width of this column}
  566.             if pt.h <= i then
  567.                 tCell.h := j;
  568.             j := j + 1;                                    {increment column}
  569.         until (i > pt.h) or (j > tVis.right);
  570.         PtToCell := tCell;
  571.     end;        {function PtToCell}
  572.  
  573.     procedure vLActivate (act: Boolean; vlHandle: vListHandle);
  574. {activates list if act = TRUE}
  575. {deactivates list if act=FALSE}
  576.         const
  577.             active = 0;
  578.             inactive = 255;
  579.     begin
  580.         if act <> vlHandle^^.LActive then
  581.             begin
  582.                 vlHandle^^.LActive := act;            { active or not}
  583.                 if act = TRUE then
  584.                     begin         {activate}
  585.                         if vlHandle^^.vScroll <> nil then
  586.                             HiliteControl(vlHandle^^.vScroll, active);
  587.                         if vlHandle^^.hScroll <> nil then
  588.                             HiliteControl(vlHandle^^.hScroll, active);
  589.                         InvalRect(vlHandle^^.rView);
  590.                         if vlHandle^^.listTE <> nil then
  591.                             TEActivate(vlHandle^^.listTE);
  592.                     end
  593.                 else
  594.                     begin         {deactivate}
  595.                         if vlHandle^^.vScroll <> nil then
  596.                             HiliteControl(vlHandle^^.vScroll, inactive);
  597.                         if vlHandle^^.hScroll <> nil then
  598.                             HiliteControl(vlHandle^^.hScroll, inactive);
  599.                         InvalRect(vlHandle^^.rView);
  600.                     end;
  601.             end;
  602.     end;        {procedure vLActivate}
  603.  
  604.     procedure vLActivateTE (active: BOOLEAN; vlHandle: vListHandle);
  605.     begin
  606.         if (vlHandle^^.listTE <> nil) and (active <> vlHandle^^.lActiveTE) then
  607.             begin
  608.                 vlHandle^^.lActiveTE := active;
  609.                 if active then
  610.                     begin
  611.                         TEActivate(vlHandle^^.listTE);
  612.                         vlHandle^^.lEditMode := TRUE;
  613.                         StartEdit(vlHandle^^.lastClick, vlHandle);    {}
  614.                     end
  615.                 else
  616.                     begin
  617.                         TEDeactivate(vlHandle^^.listTE);
  618.                         vlHandle^^.lEditMode := FALSE;
  619.                         StopEdit(False, vlHandle^^.lastClick, vlHandle);
  620.                     end;
  621.             end;        {active <> vlHandle^^.lActiveTE}
  622.     end;        {procedure vLActivateTE}
  623.  
  624.     function vLAddColumn (count, colNum: Integer; vlHandle: vListHandle): Integer;
  625. {inserts count columns into list starting at colNum, using the default column width}
  626. {the number of the first added column is returned}
  627. {if drawing is on and the columns are visible, the list and its scroll bars is updated}
  628. {does NOT fix headings}
  629.     begin
  630. {NOT IMPLEMENTED}
  631.     end;        {function vLAddCol}
  632.  
  633.     function vLAddRow (count, rowNum: Integer; vlHandle: vListHandle): Integer;
  634. {adds/inserts count rows into list starting at rowNum}
  635. {the number of the first added row is returned}
  636. {if drawing is on and the rows are visible, the list and its scroll bars is updated}
  637.         var
  638.             nCol, nRow, index: Integer;
  639.             newcells, lastcell: Integer;
  640.             i, j, k: Integer;
  641.             startOffset, endOffset: INTEGER;
  642.             tPtr: Ptr;
  643.             nVcol, nVrow: INTEGER;
  644.     begin
  645.         HLock(Handle(vlHandle));
  646.         with vlHandle^^ do
  647.             begin
  648.                 vLUnSelectAll(vlHandle);                                        {eliminate confusion over LoBits, etc.}
  649.                 nCol := databounds.right;                                        {# columns}
  650.                 nRow := databounds.bottom;                                        {# rows}
  651.                 if rowNum > nRow then                                            { rowNum > nRow,  add rows to end}
  652.                     begin
  653.                         index := nRow * nCol;                                        {get index to end of offset array}
  654.                         newcells := count * nCol;                                    {# new cells to add}
  655.                         for i := index to index + newcells do
  656.                             cellArray[i] := cellArray[index];                            {set offsets of new cells to last offset}
  657.                         databounds.bottom := databounds.bottom + count;            {set databounds}
  658.                     end        { rowNum > nRow}
  659.                 else
  660.                     begin                                                            { rowNum <= nRow,  insert rows}
  661.                         index := rowNum * nCol;                                    {get index into offset array}
  662.                         newcells := count * nCol;                                    {# new cells to add}
  663.                         lastcell := nRow * nCol;
  664.                         for i := lastcell downto index do                            {move offsets down in array}
  665.                             cellArray[i + newcells] := cellArray[i];
  666.                         for i := index to index + newcells - 1 do
  667.                             cellArray[i] := cellArray[index + newcells];
  668.         {fix databounds}
  669.                         databounds.bottom := databounds.bottom + count;            {set databounds}
  670.                     end;        { rowNum <= nRow,  insert rows}
  671.                 maxIndex := databounds.right * databounds.bottom;
  672.                 SetScrollMax(vlHandle);                                            {fix control max}
  673.                 if rowNum + count > visible.bottom then                        {if new rows are not on screen then..}
  674.                     SetCtlValue(vScroll, rowNum);                                {position new row at top of screen if necessary}
  675.                 AdjustList(vlHandle);                                            {scroll and adjust visible rectangle}
  676.                 SetScrollMax(vlHandle);
  677.                 AdjustScrollBars(vlHandle);
  678.                 vLUpdate(port^.visRgn, vlHandle)
  679.             end;        {with vlHandle...}
  680.         HUnLock(Handle(vlHandle));
  681.         if rowNum > nRow then
  682.             vLAddRow := nRow
  683.         else
  684.             vLAddRow := rowNum;
  685.     end;        {function vLAddRow}
  686.  
  687.     procedure vLAddToCell (dataPtr: Ptr; dataLen: Integer; theCell: Cell; vlHandle: vListHandle);
  688.     begin
  689. {NOT IMPLEMENTED}
  690.     end;
  691.  
  692.     procedure vLAutoScroll (vlHandle: vListHandle);
  693.     begin
  694. {NOT IMPLEMENTED}
  695.     end;
  696.  
  697.     procedure vLCalcCellWidths (var newWidth: WidthArray; var nCol: INTEGER; vlHandle: vListHandle);
  698. {calculate number of columns and column widths based on heading string, using | to delineate columns}
  699. {minumum column width is 1}
  700. {default to current column width if there is no header string}
  701.         var
  702.             tStr1, tStr2, tStr3: STR255;
  703.             i, rowNum, charIndex, k: INTEGER;
  704.             teRect: RECT;
  705.     begin
  706.         HLock(Handle(vlHandle));
  707.         with vlHandle^^ do
  708.             begin
  709.                 GetPort(oldPort);
  710.                 SetPort(port);
  711.                 SaveFont;
  712.                 if nhRows > 0 then
  713.                     begin
  714.                         TextFont(hfont);                        {set font info}
  715.                         TextSize(hSize);
  716.                         TextFace(hFace);
  717.                         for i := 0 to maxCols do
  718.                             newWidth[i] := cellWidth[i];
  719.     {calculate  column widths}
  720.                         for rowNum := 1 to nhRows do
  721.                             begin
  722.                                 tStr1 := lHead[rowNum];
  723.                                 tStr2 := '';
  724.                                 k := 0;                                {column counter}
  725.                                 charIndex := Pos('|', tStr1);
  726.                                 while charIndex <> 0 do
  727.                                     begin
  728.                                         tStr3 := Copy(tStr1, 1, charIndex - 1);                {copy substring}
  729.                                         if tStr3 <> '' then
  730.                                             newWidth[k] := 1;                            {don't change existing widths if header is blank}
  731.                                         if StringWidth(tStr3) + 1 > newWidth[k] then
  732.                                             newWidth[k] := StringWidth(tStr3) + 1;            {get width of string + 1 pixel for vertical line}
  733.                                         nCol := k;
  734.                                         k := k + 1;
  735.                                         Delete(tStr1, 1, charIndex);                            {remove  substring}
  736.                                         charIndex := Pos('|', tStr1);
  737.                                     end;
  738.                             end;  {for rowNum ..}
  739.                         nCol := k;
  740.                     end;        {with myHeading}
  741.             end;        {with vlHandle}
  742.         RestoreFont;
  743.         SetPort(oldPort);
  744.         HLock(Handle(vlHandle));
  745.     end;        {procedure vLCalcCellWidths}
  746.  
  747.     function vLCellRect (theCell: Cell; vlHandle: vListHandle): RECT;
  748. {give a cell and a list, return rectangle to draw cell in}
  749.         var
  750.             cRect: Rect;
  751.             i, vRoffset, hRoffset: Integer;    {offsets for cell rectangle}
  752.     begin
  753.     {create cell rectangle}
  754.         SetRect(cRect, 0, 0, 0, 0);
  755.         if (theCell.h >= 0) and (theCell.v >= 0) then
  756.             begin
  757.                 SetRect(cRect, 0, 0, vlHandle^^.cellWidth[theCell.h], vlHandle^^.cellSize.v); {left,top,right,bottom}
  758.                 vRoffset := (theCell.v - vlHandle^^.visible.top) * vlHandle^^.cellSize.v;
  759.                 hRoffset := 0;
  760.                 for i := vlHandle^^.visible.left to theCell.h - 1 do
  761.                     hRoffset := hRoffset + vlHandle^^.cellWidth[i];
  762.                 OffsetRect(cRect, hRoffset, vRoffset);    {}
  763.                 OffsetRect(cRect, vlHandle^^.lView.left, vlHandle^^.lView.top);
  764.             end;    {if ...}
  765.         vLCellRect := cRect;
  766.     end;        {function vLCellRect}
  767.  
  768.     procedure vLCellSize (cSize: Point; vlHandle: vListHandle);
  769.     begin
  770. {NOT IMPLEMENTED}
  771.     end;        {procedure vLCellSize}
  772.  
  773.     procedure vLCellsToScrap (whatCells: RECT; vlHandle: vListHandle; hScrap: vLScrapHandle);
  774. {transfer cells in whatCells to the scrap, replacing scrap contents}
  775. {selected points are within whatCells, i.e. whatCells.right is 1 greater than rightmost cell index}
  776. {cells are not neccesarily contiguous}
  777.         var
  778.             i, j, k, cLen: INTEGER;
  779.             theCell: Cell;
  780.             tPtr: Ptr;
  781.             tRect: RECT;
  782.             tBool: BOOLEAN;
  783.     begin
  784.         tBool := SectRect(whatCells, vlHandle^^.databounds, whatCells);        {Clip whatCells to databounds}
  785.         if tBool then                                                                    {if some of whatCells is in databounds}
  786.             begin
  787.                 HLock(Handle(hScrap));
  788.                 with hScrap^^ do
  789.                     begin
  790.                         scrapBounds := whatCells;
  791.                         OffsetRect(scrapBounds, -whatCells.left, -whatCells.top);        {make first cell in scrap 0,0}
  792.                         k := 0;
  793.                         hScrap^^.scrapOffsets[k] := 0;
  794.                         for i := whatCells.top to whatCells.bottom - 1 do
  795.                             for j := whatCells.left to whatCells.right - 1 do
  796.                                 begin
  797.                                     SetPt(theCell, j, i);                                            {h,v}
  798.                                     tPtr := PTR(ORD4(@scrapData) + scrapOffsets[k]);        {destination pointer to data array location for copied data}
  799.                                     SetPtrSize(tPtr, maxChars - scrapOffsets[k]);                {make sure tPtr big enough}
  800.                                     vLGetCell(tPtr, cLen, theCell, vlHandle);                    {copy cell data inot scrap}
  801.                                     k := k + 1;
  802.                                     scrapOffsets[k] := scrapOffsets[k - 1] + cLen;
  803.                                 end;        {for j..}
  804.                     end;        {with hScrap}
  805.                 HUnLock(Handle(hScrap));
  806.             end;        {if tBool}
  807.     end;        {vLCellsToScrap}
  808.  
  809.     function vLClick (pt: Point; modifiers: Integer; vlHandle: vListHandle): Boolean;
  810.     {called when mouse is down in the list window}
  811.     {tracks mouse and selects cells and scrolls display if neccesary}
  812.     {result is true if a double click occured in a single cell}
  813.         var
  814.             myPart: INTEGER;                {part code}
  815.             myControl: ControlHandle;
  816.             myTime, clickInt: LONGINT;
  817.             newPt: Point;
  818.             mySelect: BOOLEAN;
  819.             optionKey, cmdKey, shiftKey, noKey: BOOLEAN;
  820.             selAnchor: Point;
  821.             selRect: Rect;
  822.             oldCell, newCell, midCell, tCell: Cell;
  823.             i: INTEGER;
  824.  
  825.         function GetMods: modifierType;
  826.             var
  827.                 myKeyMap: KeyMap;
  828.         begin
  829.             GetKeys(myKeyMap);
  830.             GetMods := none;
  831.             if myKeyMap[56] then
  832.                 GetMods := shift;
  833.             if myKeyMap[56] then
  834.                 GetMods := shift;
  835.             if myKeyMap[58] then
  836.                 GetMods := option;
  837.             if myKeyMap[55] then
  838.                 GetMods := command;
  839.         end;        {function GetMods}
  840.  
  841.         procedure AdjustSelRect1 (var mySel: Rect; var myAnchor: Point; myCell: Cell);
  842. {add cell(s) to existing selection}
  843. {may change myAnchor}
  844. {  Regions:  put myCell at center, and determine region by relative position of anchor}
  845. {                 4  |  3}
  846. {                _____}
  847. {                2  |  1}
  848. {may need to swap topleft and botRight of SelRect}
  849.         begin
  850.             if EmptyRect(mySel) then
  851.                 begin
  852.                     mySel.topLeft := myCell;
  853.                     myAnchor := myCell;
  854.                     mySel.right := myCell.h + 1;
  855.                     mySel.bottom := myCell.v + 1;
  856.                 end
  857.             else
  858.                 begin
  859.                     midCell.h := mySel.left + (mySel.right - 1 - mySel.left) div 2;
  860.                     midCell.v := mySel.top + (mySel.bottom - 1 - mySel.top) div 2;
  861.                     if (myCell.v <= midCell.v) and (myCell.h <= midCell.h) then
  862.                         begin                                        {region 1}
  863.                             myAnchor.v := mySel.bottom - 1;
  864.                             myAnchor.h := mySel.right - 1;
  865.                             mySel.topLeft := myCell;
  866.                         end;
  867.                     if (myCell.v <= midCell.v) and (myCell.h > midCell.h) then
  868.                         begin                                        {region 2}
  869.                             myAnchor.v := mySel.bottom - 1;
  870.                             myAnchor.h := mySel.left;
  871.                             mySel.top := myCell.v;
  872.                             mySel.right := myCell.h + 1;
  873.                         end;
  874.                     if (myCell.v > midCell.v) and (myCell.h <= midCell.h) then
  875.                         begin                                        {region 3}
  876.                             myAnchor.v := mySel.top;
  877.                             myAnchor.h := mySel.right - 1;
  878.                             mySel.bottom := myCell.v + 1;
  879.                             mySel.left := myCell.h;
  880.                         end;
  881.                     if (myCell.v > midCell.v) and (myCell.h > midCell.h) then
  882.                         begin                                        {region 4}
  883.                             myAnchor.v := mySel.top;
  884.                             myAnchor.h := mySel.left;
  885.                             mySel.bottom := myCell.v + 1;
  886.                             mySel.right := myCell.h + 1;
  887.                         end
  888.                 end;
  889.         end;        {procedure AdjustSelRect1}
  890.  
  891.         procedure AdjustSelRect2 (var mySel: Rect; myAnchor: Point; myCell: Cell);
  892. {adjust selection to accomodate myCell}
  893. {do not change anchor}
  894. {mySel  can extend to databounds, i.e. 1 cell below and right of actual data}
  895.         begin
  896.             if (myCell.v <= myAnchor.v) and (myCell.h <= myAnchor.h) then        {region 1}
  897.                 SetRect(mySel, myCell.h, myCell.v, myAnchor.h + 1, myAnchor.v + 1);    {left, top, right, bottom}
  898.             if (myCell.v <= myAnchor.v) and (myCell.h > myAnchor.h) then         {region 2}
  899.                 SetRect(mySel, myAnchor.h, myCell.v, myCell.h + 1, myAnchor.v + 1);    {left, top, right, bottom}
  900.             if (myCell.v > myAnchor.v) and (myCell.h <= myAnchor.h) then        {region 3}
  901.                 SetRect(mySel, myCell.h, myAnchor.v, myAnchor.h + 1, myCell.v + 1);    {left, top, right, bottom}
  902.             if (myCell.v > myAnchor.v) and (myCell.h > myAnchor.h) then        {region 4}
  903.                 SetRect(mySel, myAnchor.h, myAnchor.v, myCell.h + 1, myCell.v + 1);    {left, top, right, bottom}
  904.         end;        {procedure AdjustSelRect2}
  905.  
  906.  
  907.         procedure DoVertScroll (myPt: Point; myPart: INTEGER);
  908. {handle mousedown in scroll bar}
  909.             var
  910.                 newPt: Point;
  911.                 delta, oldvalue: INTEGER;
  912.         begin
  913.             if myPart = InThumb then
  914.                 begin
  915.                     myPart := TrackControl(vlHandle^^.vScroll, myPt, nil);
  916.                     AdjustList(vlHandle);                                                {adjust list display to match scroll bar}
  917.                 end
  918.             else
  919.                 repeat
  920.                     GetMouse(newpt);                                                    {get new mouse location}
  921.                     if TestControl(vlHandle^^.vScroll, newPt) = myPart then     {are we in same part where mouse was pressed?}
  922.                         case myPart of
  923.                             inUpButton: 
  924.                                 begin
  925.                                     delta := -1;
  926.                                     HiliteControl(vlHandle^^.vScroll, inUpButton);            {hilite it}
  927.                                 end;
  928.                             inDownButton: 
  929.                                 begin
  930.                                     delta := 1;
  931.                                     HiliteControl(vlHandle^^.vScroll, inDownButton);        {hilite it}
  932.                                 end;
  933.                             inPageUp: 
  934.                                 delta := CalcDelta(vlHandle^^.visible, 0);
  935.                             inPageDown: 
  936.                                 delta := CalcDelta(vlHandle^^.visible, 1);    {0=pageUp, 1=pageDwn, 2=pageLeft, 3=pageRight}
  937.                             otherwise
  938.                 {do nothing}
  939.                         end;        {case myPart of}
  940.                     if myPart <> 0 then
  941.                         begin
  942.                             oldValue := GetCtlValue(myControl);
  943.                             SetCtlValue(myControl, oldValue + delta);                {let SetCtl handle out of range values}
  944.                             if GetCtlValue(myControl) <> oldValue then
  945.                                 AdjustList(vlHandle);                                    {adjust list display if necessary}
  946.                             case myPart of
  947.                                 inUpButton: 
  948.                                     begin
  949.                                         HiliteControl(vlHandle^^.vScroll, 0);                {unhilite it}
  950.                                     end;
  951.                                 inDownButton: 
  952.                                     begin
  953.                                         HiliteControl(vlHandle^^.vScroll, 0);                {unhilite it}
  954.                                     end;
  955.                                 otherwise
  956.                 {do nothing}
  957.                             end;        {case myPart..}
  958.                         end;        {if myPart <> 0}
  959.                 until not StillDown;
  960.         end;        {procedure DoVertScroll}
  961.  
  962.         procedure DoHorzScroll (myPt: Point; myPart: INTEGER);
  963. {handle mousedown in scroll bar}
  964.             var
  965.                 newPt: Point;
  966.                 delta, oldvalue: INTEGER;
  967.         begin
  968.             delta := 0;
  969.             if myPart = InThumb then
  970.                 begin
  971.                     myPart := TrackControl(vlHandle^^.hScroll, myPt, nil);
  972.                     AdjustList(vlHandle);                                                {adjust list display to match scroll bar}
  973.                 end
  974.             else
  975.                 repeat
  976.                     GetMouse(newpt);                                                    {get new mouse location}
  977.                     if TestControl(vlHandle^^.hScroll, newPt) = myPart then     {are we in same part where mouse was pressed?}
  978.                         case myPart of
  979.                             inUpButton: 
  980.                                 begin
  981.                                     delta := -1;
  982.                                     HiliteControl(vlHandle^^.hScroll, inUpButton);            {hilite it}
  983.                                 end;
  984.                             inDownButton: 
  985.                                 begin
  986.                                     delta := 1;
  987.                                     HiliteControl(vlHandle^^.hScroll, inDownButton);        {hilite it}
  988.                                 end;
  989.                             inPageUp: 
  990.                                 delta := CalcDelta(vlHandle^^.visible, 2);
  991.                             inPageDown: 
  992.                                 delta := CalcDelta(vlHandle^^.visible, 3);    {0=pageUp, 1=pageDwn, 2=pageLeft, 3=pageRight}
  993.                             otherwise
  994.                 {do nothing}
  995.                         end;        {case myPart of}
  996.                     if myPart <> 0 then
  997.                         begin
  998.                             oldValue := GetCtlValue(myControl);
  999.                             SetCtlValue(myControl, oldValue + delta);                {let SetCtl handle out of range values}
  1000.                             if GetCtlValue(myControl) <> oldValue then
  1001.                                 AdjustList(vlHandle);                                    {adjust list display if necessary}
  1002.                             vLDrawHeading(vlHandle);                                    {redraw the heading}
  1003.                         end;        {if myPart..}
  1004.                 until not StillDown;
  1005.         end;        {procedure DoHorzScroll}
  1006.  
  1007.         function TrackList (var oldCell: Cell; vlHandle: vListHandle): BOOLEAN;
  1008. {track list - return if mouse button up or mouse location moves from oldCell}
  1009.             var
  1010.                 newCell: Cell;
  1011.                 validRect: Rect;
  1012.         begin
  1013.             validRect := vlHandle^^.visible;
  1014.             repeat
  1015.                 GetMouse(newpt);                                                {get new mouse location}
  1016.                 newCell := PtToCell(newPt, vlHandle);
  1017.                 if not PtInRect(newCell, validRect) then
  1018.                     newCell := oldCell;                                                {don't accept invalid cells}
  1019.             until (not EqualPt(oldCell, newCell)) or (not StillDown);
  1020.             oldCell := newCell;
  1021.             TrackList := StillDown;
  1022.         end;        {function TrackList}
  1023.  
  1024.         procedure DoScrollClick;
  1025.         begin
  1026.             if (myControl = vlHandle^^.vScroll) and (myControl <> nil) then
  1027.                 DoVertScroll(pt, myPart);                                        {handle v scroll bar}
  1028.             if (myControl = vlHandle^^.hScroll) and (myControl <> nil) then
  1029.                 DoHorzScroll(pt, myPart);                                        {handle h scroll bar}
  1030.         end;
  1031.  
  1032.         procedure DoCellClick;
  1033. {handle mouseclick in cell editing mode}
  1034.             var
  1035.                 i: INTEGER;
  1036.         begin
  1037. {determine modifier status}
  1038.             case GetMods of
  1039.                 none: 
  1040.                     begin
  1041.                         selAnchor := newCell;
  1042.                         SetRect(selRect, 0, 0, 0, 0);                        {deselect all cells}
  1043.                         vLUpdateSelRect(selRect, vlHandle);                {redraw cells}
  1044.                         vLSetSelect(TRUE, newCell, vlHandle);            {select the new cell}
  1045.                     end;
  1046.                 option: 
  1047.                     begin
  1048.                         selAnchor := newCell;
  1049.                         SetRect(selRect, 0, 0, 0, 0);                        {deselect all cells}
  1050.                         vLUpdateSelRect(selRect, vlHandle);                {redraw cells}
  1051.                         for i := 0 to vlHandle^^.databounds.right - 1 do
  1052.                             begin
  1053.                                 SetPt(tCell, i, newCell.v);                        {select whole row}
  1054.                                 vLSetSelect(TRUE, tCell, vlHandle);
  1055.                             end;        {for i..}
  1056.                     end;        {if optionKey}
  1057.                 shift: 
  1058.                     begin
  1059.                         selRect := vLEncloseSel(vlHandle);                    {get rect of current selections}
  1060.                         AdjustSelRect1(selRect, selAnchor, newCell);    {extend/alter selection to enclose new cell}
  1061.                         vLUpdateSelRect(selRect, vlHandle);                {select all cells in the selRect and update display}
  1062.                     end;        {if shiftKey.}
  1063.                 otherwise
  1064.                     selAnchor := newCell;
  1065.             end;        {case...}
  1066.     {track mouse until mouse released}
  1067.             oldCell := vlHandle^^.lastClick;
  1068.             newCell := oldCell;
  1069.             while TrackList(newCell, vlHandle) do        {}
  1070.                 begin
  1071.                     case GetMods of
  1072.                         none: 
  1073.                             begin
  1074.                                 selAnchor := newCell;
  1075.                                 vLSetSelect(FALSE, oldCell, vlHandle);
  1076.                                 vLSetSelect(TRUE, newCell, vlHandle);
  1077.                                 SetRect(selRect, newCell.h, newCell.v, newCell.h + 1, newCell.v + 1);
  1078.                                 vLUpdateSelRect(selRect, vlHandle);            {select all cells in the selRect and update display}
  1079.                                 oldCell := newCell;
  1080.                             end;
  1081.                         shift: 
  1082.                             begin
  1083.                                 selRect := vLEncloseSel(vlHandle);                {get rect of current selections}
  1084.                                 AdjustSelRect2(selRect, selAnchor, newCell);    {}
  1085.                                 vLUpdateSelRect(selRect, vlHandle);            {select all cells in the selRect and update display}
  1086.                             end;    {if shiftKey.}
  1087.                         otherwise
  1088.                             ;        {nothing}
  1089.                     end;        {case...}
  1090.                 end;        {while  TrackList}
  1091.         end;        {procedure DoCellClick}
  1092.  
  1093.  
  1094. {START  procedure vLClick}
  1095.     begin
  1096.         HLock(Handle(vlHandle));
  1097.         with vlHandle^^ do
  1098.             begin
  1099.                 myPart := FindControl(pt, WindowPtr(port), myControl);        {are we in a control?}
  1100.                 if myPart <> 0 then
  1101.     {handle mouse in scroll bars}
  1102.                     begin
  1103.                         DoScrollClick;
  1104.                     end;
  1105.                 if myPart = 0 then
  1106.                     begin
  1107.     {handle mouse in list}
  1108.                         newCell := PtToCell(pt, vlHandle);
  1109.                         if (PtInRect(pt, lView)) and (PtInRect(newCell, databounds)) then
  1110.                             begin
  1111.                                 myTime := TickCount;
  1112.         {check for double click}
  1113.                                 clickInt := myTime - clikTime;
  1114.                                 if EqualPt(pt, clikLoc) and ((myTime - clikTime) < GetDblTime) then
  1115.                                     begin
  1116.                                         vLClick := TRUE;
  1117.                                         if (listTE <> nil) then
  1118.                                             begin
  1119.                                                 if (lActiveTE) then
  1120.                                                     StopEdit(FALSE, lastClick, vlHandle);        {quit editing previous cell}
  1121.                                                 StartEdit(newCell, vlHandle);                    {start editing new cell}
  1122.                                             end;        {listTE <>nil}
  1123.                                     end        {if double click}
  1124.                                 else
  1125.                                     vLClick := FALSE;
  1126.                                 clikTime := myTime;
  1127.         {check if click in active TE}
  1128.                                 if (listTE <> nil) and (lActiveTE) and (leditMode) then
  1129.                                     begin
  1130.                                         if PtInRect(pt, listTE^^.viewRect) then
  1131.                                             begin
  1132.                                                 if GetMods = shift then
  1133.                                                     TEClick(pt, TRUE, listTE)
  1134.                                                 else
  1135.                                                     TEClick(pt, FALSE, listTE);
  1136.                                             end        {if PtInRect}
  1137.                                         else
  1138.                                             StopEdit(FALSE, lastClick, vlHandle)                {stop editing if click outside TE}
  1139.                                     end;        {(listActive)}
  1140.                                 if not leditMode then
  1141.                                     begin {handle click in list}
  1142.                                         oldSelectRect := SelectRect;                        {keep previous selection rect}
  1143.                                         DoCellClick;
  1144.                                         SetPt(tCell, 0, 0);                                    {edit first selected cell}
  1145.                                         SelectRect := vLEncloseSel(vlHandle);                {save selection rect}
  1146.                                     end;        {if leditMode}
  1147.                             end;        {not leditMode}
  1148.         {update stored values}
  1149.                         clikLoc := pt;
  1150.                         lastClick := newCell;
  1151.                         clikTime := myTime;
  1152.                     end;        {myPart = 0}
  1153.             end;        {with vlHandle}
  1154.         HUnLock(Handle(vlHandle));
  1155.     end;        {procedure vLClick}
  1156.  
  1157.  
  1158.     procedure vLClrCell (theCell: Cell; vlHandle: vListHandle);
  1159.     begin
  1160.         vLSetCell(nil, 0, theCell, vlHandle);        {set cell to 0 length data}
  1161.     end;
  1162.  
  1163.     procedure vLDelColumn (count, colNum: Integer; vlHandle: vListHandle);
  1164. {deletes count columns into list starting at colNum}
  1165. {if colNum is greater than databounds nothing is done}
  1166. {if drawing is on and the columns are visible, the list and its scroll bars is updated}
  1167. {if count = 0 all columns are deleted}
  1168.     begin
  1169. {NOT IMPLEMENTED}
  1170.     end;
  1171.  
  1172.     procedure vLDelRow (count, rowNum: Integer; vlHandle: vListHandle);
  1173. {deletes count rows in list starting at colNum}
  1174. {if rowNum is greater than databounds nothing is done}
  1175. {if drawing is on and the rows are visible, the list and its scroll bars are updated}
  1176. {if count = 0 all rows are deleted}
  1177.         var
  1178.             nCol, nRow, index1, index2: Integer;
  1179.             ncells, lastcell, dlen: Integer;
  1180.             i, j, k: Integer;
  1181.             startOffset, endOffset: INTEGER;
  1182.             tPtr: Ptr;
  1183.             nVcol, nVrow: INTEGER;
  1184.             tBool: BOOLEAN;
  1185.     begin
  1186.         HLock(Handle(vlHandle));
  1187.         with vlHandle^^ do
  1188.             begin
  1189.     {theCell.h = column number}
  1190.     {theCell.v = row number}
  1191.                 nCol := databounds.right;                                        {# columns}
  1192.                 nRow := databounds.bottom;                                        {# rows}
  1193.                 if rowNum < nRow then                                            {only process valid row #}
  1194.                     begin
  1195.                         vLUnSelectAll(vlHandle);                                    {eliminate confusion over LoBits, etc.}
  1196.                         index1 := rowNum * nCol;                                    {index to first cell to be deleted}
  1197.                         index2 := (rowNum + count) * nCol;                        {index to last cell to be deleted}
  1198.                         if index2 > maxindex then
  1199.                             index2 := maxIndex;
  1200.                         ncells := count * nCol;                                        {# cells to delete}
  1201.                         dlen := cellArray[index2] - cellArray[index1];            {# data bytes to delete}
  1202.         {fix data}
  1203.                         HLock(Handle(cells));
  1204.                         for i := cellArray[index1] to cellArray[maxIndex] do
  1205.                             cells^^[i] := cells^^[i + dlen];
  1206.                         HUnLock(Handle(cells));
  1207.         {fix offsets}
  1208.                         for i := index1 + 1 to maxindex - ncells do
  1209.                             cellArray[i] := cellArray[i + ncells] - dlen;                {set new cell offsets}
  1210.         {set visible rectangle}
  1211.                         databounds.bottom := databounds.bottom - count;            {set databounds}
  1212.                         maxIndex := databounds.right * databounds.bottom;
  1213.                         nVrow := (lView.bottom - lView.top) div cellSize.v;
  1214.                         nVcol := 0;
  1215.                         i := 0;
  1216.                         j := lView.right - lView.left;
  1217.                         while (j > 0) and (i < databounds.right) do
  1218.                             begin
  1219.                                 nVcol := nVcol + 1;
  1220.                                 j := j - cellWidth[i];
  1221.                                 i := i + 1;
  1222.                             end;        {while j>0}
  1223.                         SetRect(visible, 0, 0, nVcol, nVrow);
  1224.                         tBool := SectRect(databounds, visible, visible);            {make visible smaller of databounds, visible}
  1225.                     end;        {if rowNum < nRow}
  1226.                 SetScrollMax(vlHandle);                                            {fix control max}
  1227.                 if rowNum + count > visible.bottom then                        {if new rows are not on screen then..}
  1228.                     SetCtlValue(vScroll, rowNum);                                {position new row at top of screen if necessary}
  1229.     {redraw everything}
  1230.                 AdjustList(vlHandle);
  1231.                 AdjustScrollBars(vlHandle);
  1232.                 vLUpdate(port^.visRgn, vlHandle);
  1233.             end;        {with vlHandle...}
  1234.         HUnLock(Handle(vlHandle));
  1235.     end;        {procedure vLDelRow}
  1236.  
  1237.     procedure vLDispose (vlHandle: vListHandle);
  1238.     begin
  1239.         if vlHandle^^.hScroll <> nil then
  1240.             DisposeControl(vlHandle^^.hScroll);
  1241.         if vlHandle^^.vScroll <> nil then
  1242.             DisposeControl(vlHandle^^.vScroll);
  1243.         if (vlHandle^^.listTE <> nil) then
  1244.             TEDispose(vlHandle^^.listTE);
  1245.         DisposHandle(Handle(vlHandle^^.cells));
  1246.         DisposHandle(Handle(vlHandle));
  1247.     end;
  1248.  
  1249.     procedure vLDoDraw (drawIt: Boolean; vlHandle: vListHandle);
  1250. {set drawing mode (stored in lActive) as appropriate}
  1251.     begin
  1252.         vlHandle^^.lActive := drawIt;
  1253.     end;
  1254.  
  1255.     procedure vLDrawCell (theCell: Cell; lSelect: Boolean; cRect: Rect; lDataOffset, lDataLen: INTEGER; vlHandle: vListHandle);
  1256. {draw a cell with a given rectangle with given select mode}
  1257. {save old port and clipping region}
  1258. {set clip to VisRect}
  1259. {draw cell}
  1260. {restore port and clipping region}
  1261.         var
  1262.             tPtr: Ptr;
  1263.             tRect: RECT;
  1264.             tBool: BOOLEAN;
  1265.     begin
  1266.         if vlHandle^^.lActive then
  1267.             begin
  1268.     {set port}
  1269.                 GetPort(oldPort);
  1270.                 SetPort(vlHandle^^.port);
  1271.                 SaveFont;    {get data}
  1272.                 oldClip := NewRgn;{}
  1273.                 GetClip(oldClip);                                            {save Clip Rect}
  1274.                 ClipRect(CalcVisRect(vlHandle));                        {don't draw outside VisRect so scroll bars don't get trashed}
  1275.                 TextFont(vlHandle^^.lFont);                                {set font info}
  1276.                 TextSize(vlHandle^^.lSize);
  1277.                 TextFace(vlHandle^^.lFace);
  1278.                 EraseRect(cRect);
  1279.                 InsetRect(cRect, vlHandle^^.indent.h, vlHandle^^.indent.v);
  1280.                 HLock(Handle(vlHandle^^.cells));
  1281.                 tPtr := Ptr(ORD4(vlHandle^^.cells^) + lDataOffset);
  1282.                 TextBox(tPtr, lDataLen, cRect, vlHandle^^.just);
  1283.                 HUnLock(Handle(vlHandle^^.cells));
  1284.                 InsetRect(cRect, -vlHandle^^.indent.h, -vlHandle^^.indent.v);
  1285.     {frame left and top are within rectangle}
  1286.     {frame bottom  and right are outside of rectangle}
  1287.     {FrameRect draws INSIDE the Rectangle boundaries}
  1288.                 if vlHandle^^.frameWidth > 0 then
  1289.                     begin
  1290.                         tRect := cRect;
  1291.                         tRect.bottom := tRect.bottom + 1;
  1292.                         tRect.right := tRect.right + 1;
  1293.                         GetPenState(oldPen);
  1294.                         PenSize(vlHandle^^.frameWidth, vlHandle^^.frameWidth);
  1295.                         FrameRect(tRect);
  1296.                         SetPenState(oldPen);
  1297.                         if lSelect then
  1298.                             InvertRect(tRect);
  1299.                     end     {if frameWidth > 0}
  1300.                 else if lSelect then
  1301.                     InvertRect(cRect);
  1302.                 SetClip(oldClip);
  1303.                 DisposeRgn(oldClip);
  1304.                 RestoreFont;
  1305.                 SetPort(oldPort);
  1306.             end;        {if lActive}
  1307.     end;        {vLDrawCell}
  1308.  
  1309.     procedure vLDraw (theCell: Cell; vlHandle: vListHandle);
  1310. {draw the selected cell}
  1311. {figure out where to draw the cell}
  1312. {call listdefcon to draw cell}
  1313.         var
  1314.             cRect: Rect;
  1315.             i: Integer;
  1316.             index, dataOffset, dataLen: Integer;
  1317.             lSelect: BOOLEAN;
  1318.     begin
  1319.     {is cell visible?}
  1320.     {is drawing enabled?}
  1321.         if PtInRect(theCell, vlHandle^^.visible) and vlHandle^^.lActive then
  1322.             begin
  1323.     {create cell rectangle}
  1324.                 cRect := vLCellRect(theCell, vlHandle);
  1325.                 index := theCell.v * vlHandle^^.databounds.right + theCell.h;        {get index into offset array}
  1326.                 dataOffset := LoBits(vlHandle^^.cellArray[index]);
  1327.                 dataLen := LoBits(vlHandle^^.cellArray[index + 1]) - LoBits(vlHandle^^.cellArray[index]);
  1328.                 if vlHandle^^.cellArray[index] < 0 then
  1329.                     lSelect := TRUE
  1330.                 else
  1331.                     lSelect := FALSE;
  1332.                 vLDrawCell(theCell, lSelect, cRect, dataOffset, dataLen, vlHandle);
  1333.             end;        {if PtInRect}
  1334.     end;        { procedure vLDraw}
  1335.  
  1336.     procedure vLDrawHeading (vlHandle: vListHandle);
  1337. {draw heading strings}
  1338. {surround strings with a frame which is one pixel above and one pixel to the right of the text area}
  1339. {draw a two pixel line between heading and list}
  1340.         var
  1341.             tStr1, tStr2: str255;
  1342.             i, j, k, colIndex, endIndex, index, nCol, hoffset, loffset, roffset, voffset: INTEGER;
  1343.             oldFont, oldSize: INTEGER;
  1344.             oldFace: Style;
  1345.             colWidth: WidthArray;
  1346.             tByte: Byte;
  1347.             headRect, tRect: RECT;
  1348.     begin
  1349.         if (vlHandle^^.lActive) and (vlHandle^^.nhRows > 0) then
  1350.             begin
  1351.                 GetPort(oldPort);
  1352.                 SetPort(vlHandle^^.port);
  1353.                 GetPenState(oldPen);
  1354.                 SaveFont;
  1355.                 oldClip := NewRgn;
  1356.                 GetClip(oldClip);
  1357.                 PenSize(vlHandle^^.frameWidth, vlHandle^^.frameWidth);
  1358.                 TextFont(vlHandle^^.hfont);                                        {set font info}
  1359.                 TextSize(vlHandle^^.hSize);
  1360.                 TextFace(vlHandle^^.hFace);
  1361.     {erase old heading}
  1362.                 headRect := vlHandle^^.rView;
  1363.                 headRect.bottom := vlHandle^^.lView.top;
  1364.                 headRect.right := headRect.right + 1;
  1365.                 EraseRect(headRect);
  1366.     {set clip}
  1367.                 headRect := CalcVisRect(vlHandle);
  1368.                 headRect.bottom := headRect.top + 1;                            {so border lines up with scroll bar}
  1369.                 headRect.top := vlHandle^^.rView.top - 1;
  1370.                 headRect.right := headRect.right + 1;                            {so border lines up with scroll bar}
  1371.                 ClipRect(headRect);                                                {don't draw outside headRect}
  1372.     {Offset left by width of non-visible columns}
  1373.                 hOffset := 0;
  1374.                 for i := 1 to vlHandle^^.visible.left do
  1375.                     hOffset := hOffset + vlHandle^^.cellWidth[i - 1];
  1376.                 voffset := vlHandle^^.rView.top;
  1377.     {loop through rows}
  1378.                 for index := 1 to vlHandle^^.nhRows do
  1379.                     begin
  1380.                         colIndex := 0;
  1381.                         loffset := vlHandle^^.rView.left;
  1382.                         tStr1 := vlHandle^^.lHead[index];
  1383.         {process heading string}
  1384.                         while Length(tStr1) > 1 do
  1385.                             begin
  1386.                                 roffset := loffset;
  1387.                                 tStr2 := Copy(tStr1, 1, Pos('|', tStr1) - 1);                     {get substring}
  1388.                                 tStr1 := Omit(tStr1, 1, Pos('|', tStr1));                        {remove first substring}
  1389.             {strip spaces from tStr2}
  1390.                                 while (tStr2[1] = ' ') and (Length(tStr2) > 1) do
  1391.                                     tStr2 := Omit(tStr2, 1, 1);                                    {strip leading spaces}
  1392.                                 endIndex := Length(tStr2);
  1393.                                 while (tStr2[endIndex] = ' ') and (Length(tStr2) > 1) do
  1394.                                     begin
  1395.                                         tStr2 := Omit(tStr2, endIndex, endIndex);                    {strip trailing spaces}
  1396.                                         endIndex := Length(tStr2);
  1397.                                     end;
  1398.                                 colWidth := vlHandle^^.cellWidth;
  1399.             {Print Heading[index] centered over next nCol cols}
  1400.                                 tByte := Byte(tStr2[1]);
  1401.                                 if (tByte > 48) and (tByte < 58) then            {is there a number at the beginning of the string?}
  1402.                                     begin
  1403.                                         nCol := tByte - 48;                            {remember how many columns to center this heading over}
  1404.                                         tStr2 := Omit(tStr2, 1, 1);                    {omit the number}
  1405.                                     end
  1406.                                 else
  1407.                                     nCol := 1;
  1408.                                 for j := 1 to nCol do
  1409.                                     roffset := roffset + colWidth[colIndex + j - 1];
  1410.                                 colIndex := colIndex + nCol;
  1411.                                 SetRect(tRect, loffset, voffset, roffset, voffset + vlHandle^^.hCellHeight);
  1412.                                 OffsetRect(tRect, -hOffset, 0);                    {account for scrolled position}
  1413.                                 InsetRect(tRect, 1, 1);
  1414.                                 TextBox(Ptr(Ord4(@tStr2) + 1), Length(tStr2), tRect, teJustCenter);    {print substring}
  1415.                                 if vlHandle^^.frameWidth > 0 then
  1416.                                     begin
  1417.                                         SetRect(tRect, loffset, voffset, roffset + 1, voffset + vlHandle^^.hCellHeight + 1);    {add 1 to bottom and add one to right for frame}
  1418.                                         OffsetRect(tRect, -hOffset, 0);                {account for scrolled position}
  1419.                                         FrameRect(tRect);
  1420.                                     end;
  1421.                                 loffset := roffset;    {}
  1422.                             end; {while Length ( tStr1 ) > 1}
  1423.                         voffset := voffset + vlHandle^^.hCellHeight;
  1424.                     end;        {for index}
  1425.     {Draw line under last heading row}
  1426.                 MoveTo(vlHandle^^.rView.left, vlHandle^^.lView.top - 1);
  1427.                 PenSize(1, 1);    {}
  1428.                 LineTo(headRect.right, vlHandle^^.lView.top - 1);    {}
  1429.                 RestoreFont;
  1430.                 SetPenState(oldPen);
  1431.                 SetClip(oldClip);
  1432.                 DisposeRgn(oldClip);
  1433.                 SetPort(oldPort);
  1434.             end;        {if active}
  1435.     end;        {procedure DrawHeading}
  1436.  
  1437.     function vLEncloseSel (vlHandle: vListHandle): Rect;
  1438. {return smallest rectangle which encloses all selected cells}
  1439.         var
  1440.             i, nCol, nRow, imax: INTEGER;
  1441.             tRect: Rect;
  1442.     begin
  1443.         nCol := vlHandle^^.databounds.right;                        {# columns}
  1444.         nRow := vlHandle^^.databounds.bottom;                    {# rows}
  1445.         imax := vlHandle^^.maxindex;
  1446.         SetRect(tRect, 0, 0, 0, 0);
  1447.     {find first selected cell}
  1448.         i := -1;
  1449.         repeat
  1450.             i := i + 1;
  1451.         until (vlHandle^^.cellArray[i] < 0) or (i > imax);
  1452.         if i <= imax then
  1453.             begin
  1454.                 tRect.top := i div nCol;
  1455.                 tRect.left := i - tRect.top * nCol;
  1456.             end;
  1457.     {find last selected cell}
  1458.         i := vlHandle^^.maxindex + 1;
  1459.         repeat
  1460.             i := i - 1;
  1461.         until (vlHandle^^.cellArray[i] < 0) or (i <= 0);
  1462.         if i >= 0 then
  1463.             begin
  1464.                 tRect.bottom := i div nCol + 1;
  1465.                 tRect.right := i - (tRect.bottom - 1) * nCol + 1;
  1466.             end;
  1467.         vLEncloseSel := tRect;
  1468.     end;        { function vLEncloseSel}
  1469.  
  1470.     procedure vLFind (var offset, len: Integer; theCell: Cell; vlHandle: vListHandle);
  1471. {returns the offset and length of theCell's data}
  1472. {if theCell is invalid, offset and len are set to -1}
  1473.         var
  1474.             nCol, nRow, index: Integer;
  1475.     begin
  1476.         nCol := vlHandle^^.databounds.right;                    {# columns}
  1477.         nRow := vlHandle^^.databounds.bottom;                {# rows}
  1478.         index := theCell.v * nCol + theCell.h;                    {get index into offset array}
  1479.         if index <= vlHandle^^.maxIndex then
  1480.             begin
  1481.                 offset := LoBits(vlHandle^^.cellArray[index]);
  1482.                 len := LoBits(vlHandle^^.cellArray[index + 1]) - LoBits(vlHandle^^.cellArray[index]);
  1483.             end
  1484.         else
  1485.             begin
  1486.                 offset := -1;
  1487.                 len := -1;
  1488.             end;
  1489.     end;        {procedure vLFind}
  1490.  
  1491.     procedure vLFrame (frameWidth: INTEGER; var vlHandle: vListHandle);
  1492. {set frame width (default = 0)}
  1493.     begin
  1494.         vlHandle^^.frameWidth := frameWidth;
  1495.     end;        {}
  1496.  
  1497.     procedure vLFont (myFont, mySize: INTEGER; myFace: Style; vlHandle: vListHandle);
  1498. {set list font info}
  1499.     begin
  1500.         vlHandle^^.lFont := myFont;
  1501.         vlHandle^^.lSize := mySize;
  1502.         vlHandle^^.lFace := myFace;
  1503.     end;        {procedure vLFont}
  1504.  
  1505.     procedure vLGetCell (dataPtr: Ptr; var dataLen: Integer; theCell: Cell; vlHandle: vListHandle);
  1506. {copy contents of cell to dataPtr}
  1507. {if theCell is not valid return 0 for length}
  1508.         var
  1509.             nCol, nRow, cLen, offset, index: Integer;
  1510.     begin
  1511.         nCol := vlHandle^^.databounds.right;                    {# columns}
  1512.         nRow := vlHandle^^.databounds.bottom;                {# rows}
  1513.         index := theCell.v * nCol + theCell.h;                    {get index into offset array}
  1514.         if index < vlHandle^^.maxIndex then                    {make sure we have valid cell}
  1515.             begin
  1516.                 offset := LoBits(vlHandle^^.cellArray[index]);
  1517.                 cLen := LoBits(vlHandle^^.cellArray[index + 1]) - LoBits(vlHandle^^.cellArray[index]);
  1518.     {make sure we don't copy too many bytes to dataPtr}
  1519.                 if cLen > GetPtrSize(dataPtr) then
  1520.                     dataLen := GetPtrSize(dataPtr)
  1521.                 else
  1522.                     dataLen := cLen;
  1523.     {rely on caller to make sure we don't copy too many bytes to dataPtr}
  1524.                 dataLen := cLen;
  1525.                 HLock(Handle(vlHandle^^.cells));
  1526.                 BlockMove(Ptr(ORD4(vlHandle^^.cells^) + offset), dataPtr, dataLen);
  1527.                 HUnLock(Handle(vlHandle^^.cells));
  1528.             end
  1529.         else
  1530.             dataLen := 0;
  1531.     end;
  1532.  
  1533.     function vLGetSelect (next: Boolean; var theCell: Cell; vlHandle: vListHandle): Boolean;
  1534. {return select status of theCell}
  1535. {if next is FALSE, returns True if theCell is selected}
  1536. {if next is TRUE, returns in theCell the next selected cell (start at theCell)}
  1537.         var
  1538.             nCol, nRow, cLen, offset, index: Integer;
  1539.             treply: BOOLEAN;
  1540.     begin
  1541.         tReply := FALSE;
  1542.         vLGetSelect := FALSE;
  1543.         HLock(Handle(vlHandle));
  1544.         with vlHandle^^ do
  1545.             begin
  1546.                 if next then
  1547.                     begin
  1548.                         nCol := databounds.right;                                {# columns}
  1549.                         index := theCell.v * nCol + theCell.h - 1;                {get index to next cell in offset array}
  1550.                         while (index <= maxIndex) and (tReply = FALSE) do
  1551.                             begin
  1552.                                 index := index + 1;
  1553.                                 if cellArray[index] < 0 then
  1554.                                     begin
  1555.                                         tReply := TRUE;
  1556.                                         theCell.v := index div nCol;
  1557.                                         theCell.h := index - theCell.v * nCol;
  1558.                                     end;        {if cellArray...}
  1559.                             end
  1560.                     end        {if next...}
  1561.                 else
  1562.                     begin
  1563.                         nCol := databounds.right;                    {# columns}
  1564.                         index := theCell.v * nCol + theCell.h;        {get index into offset array}
  1565.                         if cellArray[index] < 0 then
  1566.                             tReply := TRUE
  1567.                     end;
  1568.             end;        {with...}
  1569.         HUnLock(Handle(vlHandle));
  1570.         vLGetSelect := tReply;
  1571.     end;        {procedure vLGetSelect}
  1572.  
  1573.  
  1574.     procedure vLIndent (indent: POINT; var vlHandle: vListHandle);
  1575. {set indentation mode (default = 0,0)}
  1576.     begin
  1577.         vlHandle^^.indent := indent;
  1578.     end;        { procedure vLIndent}
  1579.  
  1580.     procedure vLInsetList (dH, dV: Integer; vlHandle: vListHandle);
  1581. {handle change to our view rectangle}
  1582. {keep top left of visible same}
  1583. {calculate new visible rectangle}
  1584. {redraw list and scrollbars}
  1585.         var
  1586.             i, j, myCtlValue, dangle: INTEGER;
  1587.             tBool: BOOLEAN;
  1588.     begin
  1589.         HLock(Handle(vlHandle));
  1590.         with vlHandle^^ do
  1591.             begin
  1592.                 GetPort(oldPort);
  1593.                 SetPort(port);
  1594.                 EraseRect(rView);
  1595.                 rView.right := rView.right - dH;
  1596.                 rView.bottom := rView.bottom - dV;
  1597.                 lView.right := lView.right - dH;
  1598.                 lView.bottom := lView.bottom - dV;
  1599.                 tBool := vlHandle^^.lActive;                            {save status}
  1600.                 vlHandle^^.lActive := FALSE;                        {don't draw yet}
  1601.     {avoid problem of scroll bar staying narrow when window expanded}
  1602.     {reduce ctlvalue while keeping visible.right rightmost in lView}
  1603.                 j := vlHandle^^.visible.right - 1;
  1604.                 myCtlValue := GetCtlValue(vlHandle^^.hScroll);
  1605.                 if vlHandle^^.hScroll <> nil then
  1606.                     if (myCtlValue > 0) then
  1607.                         begin
  1608.                             i := CalcVisibleRight(myCtlValue, dangle, vlHandle);
  1609.                             while (myCtlValue > -1) and (i >= j) do
  1610.                                 begin
  1611.                                     i := CalcVisibleRight(myCtlValue, dangle, vlHandle);
  1612.                                     myCtlValue := myCtlValue - 1;
  1613.                                 end;
  1614.                             myCtlValue := myCtlValue + 1;
  1615.                         end;
  1616.                 SetCtlValue(vlHandle^^.hScroll, myCtlValue);
  1617.     {avoid problem of scroll bar staying short when window expanded}
  1618.     {reduce ctlvalue while keeping visible.bottom lowest in lView}
  1619.                 j := vlHandle^^.visible.bottom - 1;
  1620.                 myCtlValue := GetCtlValue(vlHandle^^.vScroll);
  1621.                 if vlHandle^^.vScroll <> nil then
  1622.                     if (myCtlValue > 0) then
  1623.                         begin
  1624.                             i := CalcVisibleBottom(myCtlValue, dangle, vlHandle);
  1625.                             while (myCtlValue > -1) and (i >= j) do
  1626.                                 begin
  1627.                                     i := CalcVisibleBottom(myCtlValue, dangle, vlHandle);
  1628.                                     myCtlValue := myCtlValue - 1;
  1629.                                 end;
  1630.                             myCtlValue := myCtlValue + 1;
  1631.                         end;
  1632.                 SetCtlValue(vlHandle^^.vScroll, myCtlValue);
  1633.                 AdjustList(vlHandle);                                {calculate visible rectangle}
  1634.                 vlHandle^^.lActive := tBool;                            {restore status}
  1635.                 SetScrollMax(vlHandle);
  1636.                 AdjustScrollBars(vlHandle);
  1637.                 AdjustList(vlHandle);                                {draw cells}
  1638.             end;        {with}
  1639.         SetPort(oldPort);
  1640.         HUnLock(Handle(vlHandle));
  1641.     end;        {vLInsetList}
  1642.  
  1643.     procedure vLJust (just: INTEGER; var vlHandle: vListHandle);
  1644. {set justification mode (default = teJustLeft)}
  1645.     begin
  1646.         vlHandle^^.just := just;
  1647.     end;        {procedure vLJust}
  1648.  
  1649.     procedure vLKey (ch: CHAR; modifiers: Integer; vlHandle: vListHandle; vScrap: vLScrapHandle);
  1650. {Handle a key press when our window is frontmost and list is active}
  1651. {Determine whether key press applies to a TE or to a Cell/Cells}
  1652.         const
  1653.             tab = chr(9);
  1654.             larrow = chr(28);
  1655.             rarrow = chr(29);
  1656.             uarrow = chr(30);
  1657.             darrow = chr(31);
  1658.             del = chr(8);
  1659.             enter = chr(3);
  1660.             return = chr(13);
  1661.         var
  1662.             myPt: Point;             {Point where event happened}
  1663.             theControl: ControlHandle;{Handle for a control}
  1664.             MyErr: OSErr;            {OS error returned}
  1665.             dblClick: BOOLEAN;
  1666.             chCode: INTEGER;
  1667.             hNext, vNext: BOOLEAN;
  1668.             hChars: CharsHandle;
  1669.             nextCell, theCell: Cell;
  1670.             dummy: BOOLEAN;
  1671.  
  1672.         function TestMods (modifiers: INTEGER): modifierType;
  1673.         begin
  1674.             if BitAND(modifiers, cmdKey) <> 0 then
  1675.                 TestMods := command;
  1676.             if BitAND(modifiers, shiftKey) <> 0 then
  1677.                 TestMods := shift;
  1678.             if BitAND(modifiers, optionKey) <> 0 then
  1679.                 TestMods := option;
  1680.             if BitAND(modifiers, controlKey) <> 0 then
  1681.                 TestMods := control;
  1682.         end;        {function TestMods}
  1683.  
  1684.         function RectSize (theRect: Rect): INTEGER;
  1685. {return size of selection in cells}
  1686.         begin
  1687.             RectSize := (theRect.right - theRect.left) * (theRect.bottom - theRect.top);
  1688.         end;        {function RectSize}
  1689.  
  1690.         function CellAction (ch: CHAR; mode: BOOLEAN): BOOLEAN;
  1691. {determine whether to perform TE or Cell editing}
  1692.         begin
  1693.             CellAction := FALSE;
  1694.             if mode = FALSE then                        {if not in edit mode then must be cell editing}
  1695.                 CellAction := TRUE;
  1696.             if RectSize(SelectRect) > 1 then
  1697.                 CellAction := TRUE;                         {if more than one cell then must be cell editing}
  1698.             if (RectSize(oldSelectRect) > 1) and (RectSize(SelectRect) = 1) then
  1699.                 CellAction := TRUE;                         {if more than one cell previously selected and one cell now selected then cell editing}
  1700.             if (vlHandle^^.listTE^^.selStart = 0) and (vlHandle^^.listTE^^.selEnd = vlHandle^^.listTE^^.teLength) then
  1701.                 ch := ch;
  1702.             if (ch >= ' ') then
  1703.                 CellAction := FALSE;                        {only do cell edit on non-printable chars}
  1704.         end;        {function CellAction}
  1705.  
  1706.         procedure CopyCells (whatCells: Rect; whatList: vListHandle; whatScrap: vLScrapHandle);
  1707.         begin
  1708.             vLCellsToScrap(whatCells, whatList, whatScrap);
  1709.         end;        {procedure CopyCells}
  1710.  
  1711.         procedure CutCells (whatCells: Rect; whatList: vListHandle; whatScrap: vLScrapHandle);
  1712.             var
  1713.                 i, j: INTEGER;
  1714.                 tCell: Cell;
  1715.         begin
  1716.     {copy selected cells}
  1717.             vLCellsToScrap(whatCells, whatList, whatScrap);
  1718.     {clear selected cells}
  1719.             for i := whatCells.top to whatCells.bottom - 1 do
  1720.                 for j := whatCells.left to whatCells.right - 1 do
  1721.                     begin
  1722.                         SetPt(tCell, j, i);
  1723.                         vLClrCell(tCell, vlHandle);
  1724.                     end;        {for j..}
  1725.         end;        {procedure CutCells}
  1726.  
  1727.         procedure PasteCells (whatCells: Rect; whatList: vListHandle; whatScrap: vLScrapHandle);
  1728. {copy data in the scrap to cells contained in whatCells}
  1729. {handle selections which are not identical in size}
  1730.             var
  1731.                 tRect: Rect;
  1732.                 i, j, k, sourceSize, destSize: INTEGER;
  1733.         begin
  1734.             sourceSize := RectSize(whatScrap^^.scrapBounds);
  1735.             destSize := RectSize(whatCells);
  1736.             if sourceSize = destSize then
  1737.                 begin
  1738.                     vLScrapToCells(whatCells, whatList, whatScrap);
  1739.                 end;        {if sourceSize = destSize}
  1740.             if sourceSize > destSize then
  1741.                 begin
  1742.                     if destSize = 1 then
  1743.     {paste whole scrap starting at this cell if only one cell selected}
  1744.     {have to trick ScrapToCells by setting tRect = scrapBounds but offset to location of whatCells}
  1745.                         begin
  1746.                             tRect := whatScrap^^.scrapBounds;
  1747.                             OffsetRect(tRect, whatCells.left - tRect.left, whatCells.top - tRect.top);
  1748.                             vLScrapToCells(tRect, whatList, whatScrap);
  1749.                         end
  1750.                     else
  1751.                         vLScrapToCells(whatCells, whatList, whatScrap);
  1752.                 end;        { if sourceSize > destSize}
  1753.             if sourceSize < destSize then
  1754.                 begin
  1755.                     if sourceSize = 1 then
  1756.                         begin
  1757.                             for i := whatCells.top to whatCells.bottom - 1 do
  1758.                                 for j := whatCells.left to whatCells.right - 1 do
  1759.                                     begin
  1760.                                         SetRect(tRect, j, i, j + 1, i + 1);                        {repeatedly paste source to destination cells}
  1761.                                         vLScrapToCells(tRect, whatList, whatScrap);
  1762.                                     end;        {for j..}
  1763.                         end        {if sourceSize=1}
  1764.                     else
  1765.     {'trick' ScrapToCells by setting tRect = scrapBounds but offset to location of whatCells}
  1766.                         begin
  1767.                             tRect := whatScrap^^.scrapBounds;
  1768.                             OffsetRect(tRect, whatCells.left - tRect.left, whatCells.top - tRect.top);        {align tRect to whatCells topleft}
  1769.                             i := 0;
  1770.                             j := whatScrap^^.scrapBounds.bottom - whatScrap^^.scrapBounds.top;            {height of source}
  1771.                             k := whatCells.bottom - whatCells.top;
  1772.                             if j > 0 then
  1773.                                 while i < k do
  1774.                                     begin
  1775.                                         vLScrapToCells(tRect, whatList, whatScrap);
  1776.                                         OffsetRect(tRect, 0, j);
  1777.                                         i := i + j;
  1778.                                     end;        {while i<k..}
  1779.                         end;        {sourceSize<>1}
  1780.                 end;        {if sourceSize < destSize}
  1781.     {adjust rectangles so that  paste works}
  1782.             SelectRect := oldSelectRect;
  1783.         end;        {procedure PasteCells}
  1784.  
  1785.         procedure FindNextCell (ch: CHAR);
  1786.         begin
  1787.             with vlHandle^^ do
  1788.                 begin
  1789.                     theCell := lastClick;
  1790.     {set up search}
  1791.                     case ch of
  1792.                         return: 
  1793.                             begin
  1794.                                 hNext := FALSE;
  1795.                                 vNext := TRUE;
  1796.                             end;
  1797.                         enter: 
  1798.                             begin
  1799.                                 hNext := FALSE;
  1800.                                 vNext := TRUE;
  1801.                             end;
  1802.                         darrow: 
  1803.                             begin
  1804.                                 hNext := FALSE;
  1805.                                 vNext := TRUE;
  1806.                             end;
  1807.                         rarrow: 
  1808.                             begin
  1809.                                 hNext := TRUE;
  1810.                                 vNext := FALSE;
  1811.                             end;
  1812.                         tab: 
  1813.                             begin
  1814.                                 hNext := TRUE;
  1815.                                 vNext := FALSE;
  1816.                             end;
  1817.                         uarrow: 
  1818.                             begin
  1819.                                 hNext := FALSE;
  1820.                                 vNext := TRUE;
  1821.                                 theCell.v := theCell.v - 2;
  1822.                             end;
  1823.                         larrow: 
  1824.                             begin
  1825.                                 hNext := TRUE;
  1826.                                 vNext := FALSE;
  1827.                                 theCell.h := theCell.h - 2;
  1828.                             end;
  1829.                         otherwise
  1830.                             begin
  1831.                                 hNext := FALSE;
  1832.                                 vNext := FALSE;
  1833.                             end;
  1834.                     end;    {case}
  1835.     {search}
  1836.                     nextCell := theCell;
  1837.                     if vLNextCell(hNext, vNext, theCell, vlHandle) = FALSE then
  1838.                         begin
  1839.         {must be out of databounds}
  1840.                             if nextCell.h >= databounds.right - 1 then
  1841.                                 begin                                                {went off right edge}
  1842.                                     theCell.h := databounds.left;
  1843.                                     theCell.v := theCell.v + 1;                        {move to start of next row}
  1844.                                     if theCell.v > databounds.bottom - 1 then
  1845.                                         theCell.v := databounds.top;                    {if last row, go to first row}
  1846.                                 end
  1847.                             else if nextCell.v >= databounds.bottom - 1 then
  1848.                                 begin                                                {went off bottom edge}
  1849.                                     theCell.v := databounds.top;
  1850.                                     theCell.h := theCell.h + 1;                        {move to start of next col}
  1851.                                     if theCell.h > databounds.right - 1 then
  1852.                                         theCell.h := databounds.left;                    {if last col, go to first col}
  1853.                                 end
  1854.                             else if nextCell.h < databounds.left then
  1855.                                 begin                                                {went off left edge}
  1856.                                     theCell.h := databounds.right - 1;
  1857.                                     theCell.v := theCell.v - 1;                        {move to start of next row}
  1858.                                     if theCell.v < databounds.top then
  1859.                                         theCell.v := databounds.bottom - 1;        {if last row, go to first row}
  1860.                                 end
  1861.                             else if nextCell.v < databounds.top then
  1862.                                 begin                                                {went off top edge}
  1863.                                     theCell.v := databounds.bottom - 1;
  1864.                                     theCell.h := theCell.h - 1;                        {move to start of next col}
  1865.                                     if theCell.h < databounds.left then
  1866.                                         theCell.h := databounds.right - 1;            {if last col, go to first col}
  1867.                                 end;
  1868.                         end;    {if vLNextCell}
  1869.                     oldSelectRect := SelectRect;
  1870.                     SetRect(SelectRect, 0, 0, 0, 0);
  1871.                     vLUpdateSelRect(SelectRect, vlHandle);                {unselect all cells}
  1872.                     vLSetSelect(TRUE, theCell, vlHandle);                {select found cell}
  1873.                     SelectRect := vLEncloseSel(vlHandle);                {save selection rect}
  1874.                     lastClick := theCell;
  1875.                 end;        {with..}
  1876.         end;        {FindNextCell}
  1877.  
  1878.         procedure DoEditTE;
  1879. {Handle keypress in editTE mode}
  1880.         begin
  1881.             with vlHandle^^ do
  1882.                 begin
  1883.                     if TestMods(modifiers) = command then
  1884.                         begin
  1885.         {handle command keys}
  1886.                             if (ch = 'x') or (ch = 'X') then
  1887.                                 TECut(listTE);
  1888.                             if (ch = 'c') or (ch = 'C') then
  1889.                                 TECopy(listTE);
  1890.                             if (ch = 'v') or (ch = 'V') then
  1891.                                 TEPaste(listTE);
  1892.                         end
  1893.                     else
  1894.                         begin
  1895.         {handle non-command keys}
  1896.                             if (ch = return) or (ch = enter) or (ch = tab) then
  1897.                                 begin
  1898.                                     StopEdit(TRUE, vLLastClick(vlHandle), vlHandle);        {stop editing and save results on TAB, RETURN or ENTER}
  1899.                                     FindNextCell(ch);
  1900.                                 end        {if(ch = return) or (ch = enter)..}
  1901.                             else
  1902.                                 TEKey(ch, listTE)        {pass other keys to TEDit}
  1903.                         end;        {non-command keys}
  1904.                 end;        {with}
  1905.         end;        {procedure DoEditTE}
  1906.  
  1907.  
  1908.         procedure DoEditCells;
  1909.         begin
  1910.             if (TestMods(modifiers) = command) and (vScrap <> nil) then
  1911.                 begin
  1912.         {handle command keys}
  1913.                     SelectRect := vLEncloseSel(vlHandle);                {get selection rect}
  1914.                     if (ch = 'x') or (ch = 'X') then
  1915.                         CutCells(SelectRect, vlHandle, vScrap);
  1916.                     if (ch = 'c') or (ch = 'C') then
  1917.                         CopyCells(SelectRect, vlHandle, vScrap);
  1918.                     if (ch = 'v') or (ch = 'V') then
  1919.                         PasteCells(SelectRect, vlHandle, vScrap);
  1920.                 end    {if command}
  1921.             else
  1922.                 begin
  1923.         {handle non-command keys}
  1924.                     if ch = del then
  1925.                         vLClrCell(vlHandle^^.lastClick, vlHandle)
  1926.                     else
  1927.                         FindNextCell(ch);
  1928.                 end;        {non-command keys}
  1929.         end;        {procedure DoEditCells}
  1930.  
  1931. {START procedure vLKey}
  1932. {need to double click in a cell to edit text}
  1933.     begin
  1934.         HLock(Handle(vlHandle));
  1935.         with vlHandle^^ do
  1936.             begin
  1937.                 SelectRect := vLEncloseSel(vlHandle);
  1938.                 if (listTE <> nil) and (lActiveTE) then
  1939.                     if CellAction(ch, leditMode) then
  1940.     {handle editing cells}
  1941.                         DoEditCells
  1942.                     else
  1943.     {handle editing TE}
  1944.                         DoEditTE
  1945.                 else
  1946.                     DoEditCells;
  1947.             end;        {with vlHandle...}
  1948.         oldSelectRect := SelectRect;
  1949.         HUnLock(Handle(vlHandle));
  1950.     end;        {function vLKey}
  1951.     function vLLastClick (vlHandle: vListHandle): Cell;
  1952. {return last cell clicked in}
  1953.     begin
  1954.         vLLastClick := vlHandle^^.lastClick;
  1955.     end;        { function vLLastClick}
  1956.  
  1957.     function vLNew (plView, pdatabounds: RECT; pcellSize: POINT; procID: INTEGER; theWindow: WindowPtr; drawIt, hasGrow, scrollHoriz, scrollVert: Boolean): vListHandle;
  1958. {return a new vListHandle}
  1959. {return nil if memory can't be allocated for the list}
  1960.         var
  1961.             MyvListh: vListHandle;
  1962.             hcntrlRect, vcntrlRect, prView, cRect: Rect;
  1963.             i, j, nVcol, nVrow: Integer;
  1964.             tBool: BOOLEAN;
  1965.             myCell: Cell;
  1966.             myFontInfo: FontInfo;
  1967.     begin
  1968.         MyvListh := vListHandle(NewHandle(SIZEOF(vListRec)));
  1969.         if MyvListh <> nil then                                            {in case out of memory!}
  1970.             begin
  1971.                 MyvListh^^.cells := DataHandle(NewHandle(SIZEOF(DataArray)));
  1972.                 if MyvListh^^.cells <> nil then
  1973.                     begin
  1974.                         HLock(Handle(MyvListh));
  1975.              cell in the column is returned}
  1976.         var
  1977.             newCell: Cell;
  1978.             tRect: RECT;
  1979.     begin
  1980.         newCell := theCell;
  1981.         vLNextCell := FALSE;
  1982.         if (hNext = TRUE) and (vNext = TRUE) then
  1983.             if newCell.h + 1 < vlHandle^^.databounds.right then            {are we at the end of the row?}
  1984.                 begin
  1985.                     newCell.h := newCell.h + 1;
  1986.                     vLNextCell := TRUE;
  1987.                 end
  1988.             else if newCell.v + 1 < vlHandle^^.databounds.bottom then    {are there more columns?}
  1989.                 begin
  1990.                     newCell.h := 0;
  1991.                     newCell.v := newCell.v + 1;
  1992.                     vLNextCell := TRUE;
  1993.                 end;        {else}
  1994.         if (hNext = TRUE) and (vNext = FALSE) then
  1995.             if newCell.h + 1 < vlHandle^^.databounds.right then            {are we at the end of the row?}
  1996.                 begin
  1997.                     newCell.h := newCell.h + 1;
  1998.                     vLNextCell := TRUE;
  1999.                 end;
  2000.         if (hNext = FALSE) and (vNext = TRUE) then
  2001.             if newCell.v + 1 < vlHandle^^.databounds.bottom then            {are there more rows?}
  2002.                 begin
  2003.                     newCell.v := newCell.v + 1;
  2004.                     vLNextCell := TRUE;
  2005.                 end;
  2006.         if PtInRect(newCell, vlHandle^^.databounds) then                {make sure we have a valid cell}
  2007.             theCell := newCell
  2008.         else
  2009.             vLNextCell := FALSE;
  2010.     end;        {function vLNextCell}
  2011.  
  2012.     procedure vLRect (var cellRect: Rect; theCell: Cell; vlHandle: vListHandle);
  2013. {return the local coordinates of theCell}
  2014. {return 0,0,0,0 if invalid cell}
  2015.         var
  2016.             i, vRoffset, hRoffset: Integer;    {offsets for cell rectangle}
  2017.     begin {is cell visible?}
  2018.         if PtInRect(theCell, vlHandle^^.visible) then
  2019.             begin
  2020.     {create cell rectangle}
  2021.                 SetRect(cellRect, 0, 0, vlHandle^^.cellWidth[theCell.h], vlHandle^^.cellSize.v); {left,top,right,bottom}
  2022.                 vRoffset := (theCell.v - vlHandle^^.visible.top) * vlHandle^^.cellSize.v;
  2023.                 hRoffset := 0;
  2024.                 for i := vlHandle^^.visible.left to theCell.h - 1 do
  2025.                     hRoffset := hRoffset + vlHandle^^.cellWidth[i];
  2026.                 OffsetRect(cellRect, hRoffset, vRoffset);    {}
  2027.                 OffsetRect(cellRect, vlHandle^^.lView.left, vlHandle^^.lView.top);        {**NEW**}
  2028.             end
  2029.         else
  2030.             SetRect(cellRect, 0, 0, 0, 0);
  2031.     end;        { procedure vLRect}
  2032.  
  2033.     procedure vLScrapToCells (whatCells: RECT; vlHandle: vListHandle; hScrap: vLScrapHandle);
  2034. {transfer data in scrap to whatCells}
  2035. {selected points are within whatCells, i.e. whatCells.right is 1 greater than rightmost cell index}
  2036. {limits cells to smaller of whatCells and scrapBounds}
  2037.         var
  2038.             i, j, k, cLen: INTEGER;
  2039.             theCell: Cell;
  2040.             tPtr: Ptr;
  2041.             tRect: RECT;
  2042.             tBool: BOOLEAN;
  2043.     begin
  2044.         tBool := SectRect(whatCells, vlHandle^^.databounds, whatCells);    {Clip whatCells to databounds}
  2045.         if tBool then                                                                {if some of whatCells is in databounds}
  2046.             begin
  2047.                 HLock(Handle(hScrap));
  2048.                 with hScrap^^ do
  2049.                     begin
  2050.                         k := 0;
  2051.                         tRect := scrapBounds;
  2052.                         OffsetRect(tRect, whatCells.left, whatCells.top);                {align tRect with whatCells}
  2053.                         tBool := SectRect(whatCells, tRect, tRect);                    {set tRect to intersection of whatCells and scrapBounds}
  2054.                         for i := tRect.top to tRect.bottom - 1 do
  2055.                             for j := tRect.left to tRect.right - 1 do
  2056.                                 begin
  2057.                                     SetPt(theCell, j, i);
  2058.                                     tPtr := @scrapData;
  2059.                                     tPtr := Ptr(ORD4(tPtr) + scrapOffsets[k]);                {pointer to data array location for copied data}
  2060.                                     cLen := scrapOffsets[k + 1] - scrapOffsets[k];
  2061.                                     vLSetCell(tPtr, cLen, theCell, vlHandle);
  2062.                                     k := k + 1;
  2063.                                 end;        {for j..}
  2064.                     end;        {with hScrap}
  2065.                 HUnLock(Handle(hScrap));
  2066.             end;        {if tBool}
  2067.     end;        {procedure vLScrapToCells}
  2068.  
  2069.  
  2070.     procedure vLScroll (dRows, dCols: Integer; vlHandle: vListHandle);
  2071. {scrolls the list the specified number of rows and columns}
  2072. {screen is updated if drawing is on}
  2073.     begin
  2074.         if vlHandle^^.vScroll <> nil then
  2075.             SetCtlValue(vlHandle^^.vScroll, GetCtlValue(vlHandle^^.vScroll) + dRows);        {let SetCtl handle out of range values}
  2076.         if vlHandle^^.hScroll <> nil then
  2077.             SetCtlValue(vlHandle^^.hScroll, GetCtlValue(vlHandle^^.hScroll) + dCols);        {let SetCtl handle out of range values}
  2078.         AdjustList(vlHandle);
  2079.     end;
  2080.  
  2081.     function vLSearch (dataPtr: Ptr; dataLen: Integer; SearchProc: Ptr; var theCell: Cell; vlHandle: vListHandle): Boolean;
  2082. {returns the first cell after theCell which contains the specified data}
  2083. {result is TRUE if a match is found}
  2084. {if searchProc is nil, IUMagIDString is used to compare the data}
  2085.     begin
  2086. {NOT IMPLEMENTED}
  2087.     end;
  2088.  
  2089.     procedure vLSetHeadFont (myFont, mySize: INTEGER; myFace: Style; vlHandle: vListHandle);
  2090. {set the heading font info}
  2091.         var
  2092.             myFontInfo: FontInfo;
  2093.     begin
  2094.         GetPort(oldPort);
  2095.         SetPort(vlHandle^^.port);
  2096.         SaveFont;
  2097.         vlHandle^^.hFont := myFont;
  2098.         vlHandle^^.hSize := mySize;
  2099.         vlHandle^^.hFace := myFace;
  2100.         TextFont(vlHandle^^.hfont);                    {set font info}
  2101.         TextSize(vlHandle^^.hSize);
  2102.         TextFace(vlHandle^^.hFace);
  2103.         GetFontInfo(myFontInfo);
  2104.         vlHandle^^.hCellHeight := myFontInfo.ascent + myFontInfo.descent + myFontInfo.leading + 3;
  2105.         RestoreFont;
  2106.         SetPort(oldPort);
  2107.     end;        {vLSetHeadFont}
  2108.  
  2109.     procedure vLSetHeadings (nhRows: INTEGER; headings: lHeadArray; vlHandle: vListHandle);
  2110. {set the heading info and adjust lView and list display accordingly}
  2111.         var
  2112.             tBool: BOOLEAN;
  2113.     begin
  2114.     {default to list font}
  2115.         vLSetHeadFont(vlHandle^^.lFont, vlHandle^^.lSize, vlHandle^^.lFace, vlHandle);
  2116.         vlHandle^^.nhRows := nhRows;
  2117.         vlHandle^^.lHead := headings;
  2118.         vlHandle^^.lView.top := vlHandle^^.rView.top + nhRows * vlHandle^^.hCellHeight + 1;        {leave room for dividing line}
  2119.         GetPort(oldPort);
  2120.         SetPort(vlHandle^^.port);
  2121.         EraseRect(vlHandle^^.rView);
  2122.         tBool := vlHandle^^.lActive;
  2123.         vlHandle^^.lActive := FALSE;                                {don't draw yet}
  2124.         AdjustList(vlHandle);                                        {calculate visible rectangle}
  2125.         vlHandle^^.lActive := tBool;                                    {now draw}
  2126.         SetScrollMax(vlHandle);
  2127.         AdjustScrollBars(vlHandle);                                {draw heading and scroll bars}
  2128.         AdjustList(vlHandle);                                        {draw cells}
  2129.         SetPort(oldPort);
  2130.     end;        {procedure vLSetHeadings}
  2131.  
  2132.     procedure vLSetWidths (widths: WidthArray; vlHandle: vListHandle);
  2133. {set the column widths and display list}
  2134.     begin
  2135.         vlHandle^^.cellWidth := widths;
  2136.         GetPort(oldPort);
  2137.         SetPort(vlHandle^^.port);
  2138.         EraseRect(vlHandle^^.rView);
  2139.         vLDrawHeading(vlHandle);
  2140.         AdjustScrollBars(vlHandle);
  2141.         SetScrollMax(vlHandle);
  2142.         AdjustList(vlHandle);                {draw cells}
  2143.         SetPort(oldPort);
  2144.     end;        {procedure vLSetWidths}
  2145.  
  2146.  
  2147.     procedure vLSetListFont (myFont, mySize: INTEGER; myFace: Style; vlHandle: vListHandle);
  2148. {set the heading font info}
  2149.         var
  2150.             myFontInfo: FontInfo;
  2151.     begin
  2152.         GetPort(oldPort);
  2153.         SetPort(vlHandle^^.port);
  2154.         SaveFont;
  2155.         vlHandle^^.lFont := myFont;
  2156.         vlHandle^^.lSize := mySize;
  2157.         vlHandle^^.lFace := myFace;
  2158.         TextFont(vlHandle^^.lFont);                    {set font info}
  2159.         TextSize(vlHandle^^.lSize);
  2160.         TextFace(vlHandle^^.lFace);
  2161.         GetFontInfo(myFontInfo);
  2162.         vlHandle^^.cellSize.v := myFontInfo.ascent + myFontInfo.descent + myFontInfo.leading + 3;
  2163.         RestoreFont;
  2164.         SetPort(oldPort);
  2165.     end;        {vLSetListFont}
  2166.  
  2167.     procedure vLSetCell (dataPtr: Ptr; dataLen: Integer; theCell: Cell; vlHandle: vListHandle);
  2168. {set the contents of a cell}
  2169. {EXAMPLE:}
  2170. {0,0    1,0    2,0}
  2171. {0,1    1,1    2,1}
  2172. {0,2    1,2    2,2}
  2173. { cellArray[0] -> offset to 0,0}
  2174. { cellArray[1] -> offset to 1,0}
  2175. { cellArray[2] -> offset to 2,0}
  2176. { cellArray[3] -> offset to 0,1}
  2177. { cellArray[4] -> offset to 1,1}
  2178. { cellArray[5] -> offset to 2,1}
  2179. { cellArray[6] -> offset to 0,2}
  2180. { cellArray[7] -> offset to 1,2}
  2181.         var
  2182.             nCol, nRow, index: Integer;
  2183.             i, j, k: Integer;
  2184.             oldLen, dOffset: Integer;
  2185.             startOffset, endOffset: Integer;
  2186.             tPtr: Ptr;
  2187.     begin
  2188.     {theCell.h = column number}
  2189.     {theCell.v = row number}
  2190.         nCol := vlHandle^^.databounds.right;                                    {# columns}
  2191.         nRow := vlHandle^^.databounds.bottom;                                {# rows}
  2192.         index := theCell.v * nCol + theCell.h;                                    {get index into offset array}
  2193.         if index < vlHandle^^.maxIndex then                                    {make sure we have valid cell}
  2194.             begin
  2195.                 oldLen := LoBits(vlHandle^^.cellArray[index + 1]) - LoBits(vlHandle^^.cellArray[index]);
  2196.                 dOffset := dataLen - oldLen;
  2197.         {adjust data}
  2198.                 HLock(Handle(vlHandle^^.cells));
  2199.                 startOffset := LoBits(vlHandle^^.cellArray[index + 1]);
  2200.                 endOffset := LoBits(vlHandle^^.cellArray[vlHandle^^.maxIndex]);
  2201.                 for i := 0 to endOffset - startOffset do
  2202.                     begin
  2203.                         if dOffset >= 0 then
  2204.                             begin
  2205.                                 j := endOffset - i;
  2206.                                 k := j + dOffset;
  2207.                             end        {dOffset >= 0}
  2208.                         else
  2209.                             begin
  2210.                                 j := startOffset + i;
  2211.                                 k := j + dOffset;
  2212.                             end;        {dOffset<0}
  2213.                         vlHandle^^.cells^^[k] := vlHandle^^.cells^^[j];
  2214.                     end;        {for i...}
  2215.         {copy new data into data array}
  2216.                 if dataLen > 0 then
  2217.                     BlockMove(dataPtr, Ptr(ORD4(vlHandle^^.cells^) + LoBits(vlHandle^^.cellArray[index])), dataLen);
  2218.                 HUnLock(Handle(vlHandle^^.cells));
  2219.         {adjust offsets}
  2220.                 for i := index + 1 to vlHandle^^.maxIndex do
  2221.                     vlHandle^^.cellArray[i] := vlHandle^^.cellArray[i] + dOffset;    {adjust offsets for all cells following theCell}
  2222.             end;        {if index < maxIndex}
  2223.         vLDraw(theCell, vlHandle);
  2224.     end;        {procedure vLSetCell}
  2225.  
  2226.     procedure vLSetSelect (setIt: Boolean; theCell: Cell; vlHandle: vListHandle);
  2227. {if setIt is TRUE, select cell}
  2228. {if setIt is FALSE, deselect cell}
  2229. {redraw cell if it is visible}
  2230.         var
  2231.             nCol, nRow, cLen, offset, index: INTEGER;
  2232.             oldSelect: BOOLEAN;
  2233.     begin
  2234.         if PtInRect(theCell, vlHandle^^.databounds) then
  2235.             begin
  2236.                 HLock(Handle(vlHandle));
  2237.                 with vlHandle^^ do
  2238.                     begin
  2239.                         nCol := databounds.right;                        {# columns}
  2240.                         nRow := databounds.bottom;                        {# rows}
  2241.                         index := theCell.v * nCol + theCell.h;            {get index into offset array}
  2242.                         if index < maxIndex then                        {make sure we have valid cell}
  2243.                             begin
  2244.                                 offset := LoBits(cellArray[index]);
  2245.                                 oldSelect := BitTst(@cellArray[index], 0);
  2246.                                 if setIt then                                    {set or clear high order bit}
  2247.                                     BitSet(@cellArray[index], 0)
  2248.                                 else
  2249.                                     BitClr(@cellArray[index], 0);
  2250.                                 if setIt <> oldSelect then
  2251.                                     vLDraw(theCell, vlHandle);                {redraw the cell if select status is changed}
  2252.                             end;        {if index < maxIndex}
  2253.                     end;        {with...}
  2254.                 HUnLock(Handle(vlHandle));
  2255.             end;        {if PtInRect}
  2256.     end;        {procedure vLSetSelect}
  2257.  
  2258.     procedure vLSize (newWidth, newHeight: INTEGER; vlHandle: vListHandle);
  2259. {handle change in our view rectangle}
  2260. {keep top left of visible same}
  2261. {calculate new visible rectangle}
  2262.         var
  2263.             tBool: BOOLEAN;
  2264.             visRect: RECT;
  2265.             dH, dV, oldWidth, oldHeight: INTEGER;
  2266.     begin
  2267.         HLock(Handle(vlHandle));
  2268.         with vlHandle^^ do
  2269.             begin
  2270.                 oldWidth := rView.right - rView.left;
  2271.                 oldHeight := rView.bottom - rView.top;
  2272.                 dH := newWidth - oldWidth;
  2273.                 dV := newHeight - oldHeight;
  2274.             end;        {with}
  2275.         HUnLock(Handle(vlHandle));
  2276.         vLInsetList(dH, dV, vlHandle);
  2277.     end;        {procedure vLSize}
  2278.  
  2279.     procedure vLTENew (active: BOOLEAN; whatCell: Cell; vlHandle: vListHandle);
  2280. {create a new TERecord for editing cells}
  2281.         var
  2282.             tRect: RECT;
  2283.     begin
  2284.         GetPort(oldPort);
  2285.         SetPort(vlHandle^^.port);
  2286.         TextFont(vlHandle^^.lFont);                                {set font info}
  2287.         TextSize(vlHandle^^.lSize);
  2288.         TextFace(vlHandle^^.lFace);
  2289.         tRect := vLCellRect(whatCell, vlHandle);
  2290.         InsetRect(tRect, 1, 1);
  2291.         vlHandle^^.listTE := TENew(tRect, tRect);
  2292.         TEAutoView(TRUE, vlHandle^^.listTE);        {}
  2293.         vLActivateTE(active, vlHandle);
  2294.         SetPort(oldPort);
  2295.     end;        {vLTENew}
  2296.  
  2297.     procedure vLTEDispose (vlHandle: vListHandle);
  2298. {dispose of TERecord for editing cells}
  2299.         var
  2300.             tRect: RECT;
  2301.     begin
  2302.         TEDispose(vlHandle^^.listTE);
  2303.         vlHandle^^.listTE := nil;
  2304.     end;        {vLTENew}
  2305.  
  2306.     procedure vLUnSelectAll (vlHandle: vListHandle);
  2307. {deselect all selected cells}
  2308.         var
  2309.             i, nCol, nRow: INTEGER;
  2310.             tCell: Cell;
  2311.     begin
  2312.         nCol := vlHandle^^.databounds.right;                        {# columns}
  2313.         nRow := vlHandle^^.databounds.bottom;                    {# rows}
  2314.         for i := 0 to vlHandle^^.maxIndex do
  2315.             if vlHandle^^.cellArray[i] < 0 then
  2316.                 begin
  2317.                     vlHandle^^.cellArray[i] := BitAnd(vlHandle^^.cellArray[i], $7FFF);
  2318.                     tCell.v := i div nCol;
  2319.                     tCell.h := i - tCell.v * nCol;
  2320.                     vLSetSelect(FALSE, tCell, vlHandle);
  2321.                 end;
  2322.     end;            {procedure vLUnSelectAll}
  2323.  
  2324.     procedure vLUpdateSelRect (selRect: Rect; vlHandle: vListHandle);
  2325. {select all cells in SelRect}
  2326. {deselect all cells outside SelRect}
  2327. {redraw any cells which change select status}
  2328.         var
  2329.             i, j: INTEGER;
  2330.             tPt: Point;
  2331.     begin
  2332.         for i := 0 to vlHandle^^.databounds.bottom - 1 do
  2333.             begin
  2334.                 for j := 0 to vlHandle^^.databounds.right - 1 do
  2335.                     begin
  2336.                         tPt.v := i;
  2337.                         tPt.h := j;
  2338.                         if PtInRect(tPt, selRect) then
  2339.                             vLSetSelect(TRUE, tPt, vlHandle)
  2340.                         else
  2341.                             vLSetSelect(FALSE, tPt, vlHandle);
  2342.                     end;        {for i...}
  2343.             end;    {for j...}
  2344.     end;
  2345.  
  2346.     procedure vLUpdate (theRgn: RgnHandle; vlHandle: vListHandle);
  2347. {redraw any visible cells in theRgn (which should be set to the visRgn of our window on entry)}
  2348. {called in response to update event}
  2349.     begin
  2350.         vLDrawHeading(vlHandle);
  2351.         AdjustList(vlHandle);
  2352.         if vlHandle^^.vScroll <> nil then
  2353.             Draw1Control(vlHandle^^.vScroll);
  2354.         if vlHandle^^.hScroll <> nil then
  2355.             Draw1Control(vlHandle^^.hScroll);
  2356.         if (vlHandle^^.listTE <> nil) and (vlHandle^^.lActiveTE) then
  2357.             TEUpdate(vlHandle^^.listTE^^.viewRect, vlHandle^^.listTE);
  2358.     end;
  2359.  
  2360. end.        {unit vListMngrProcs}