home *** CD-ROM | disk | FTP | other *** search
/ MacFormat 1995 January / macformat-020.iso / Shareware City / Developers / apps.to.go / DTS.Lib / ListVarControl.c < prev    next >
Encoding:
Text File  |  1994-05-04  |  36.6 KB  |  1,472 lines  |  [TEXT/MPS ]

  1. /*
  2. ** Apple Macintosh Developer Technical Support
  3. **
  4. ** Program:         listvarcontrol.c
  5. ** Written by:      Eric Soldan
  6. **
  7. ** Copyright © 1991 Apple Computer, Inc.
  8. ** All rights reserved.
  9. */
  10.  
  11. /* You may incorporate this sample code into your applications without
  12. ** restriction, though the sample code has been provided "AS IS" and the
  13. ** responsibility for its operation is 100% yours.  However, what you are
  14. ** not permitted to do is to redistribute the source as "DSC Sample Code"
  15. ** after having made changes. If you're going to re-distribute the source,
  16. ** we require that you make it clear in the source that the code was
  17. ** descended from Apple Sample Code, but that you've made changes. */
  18.  
  19.  
  20. /*
  21.  
  22. A number of developers have expressed a desire to have the List Manager support
  23. variable-size cells.  In response to this, the List control has been extended to
  24. support variable-size rows and columns.
  25.  
  26. The first problem is where to store the size for each row and column.  This
  27. implementation expects the sizes for the individual column widths to be stored
  28. in row 0, cells 1 through numCols, and the individual row widths to be stored in
  29. column 0, rows 1 through numRows.  The values are placed in the cells in decimal
  30. ascii.  (This is so that the AppsToGo editor can easily be used to create lists
  31. with variable-size cells.  You just enter the decimal ascii value in the editor.)
  32. Any row or column without a decimal ascii entry for the size will get the regular
  33. size for a cell.
  34.  
  35. Since row 0 and column 0 are used to store the widths, these cells are not available
  36. in the list.  They are not displayed, and you can not scroll into them.  Due to this,
  37. the list is one column narrower and one row shorter than a regular list.
  38.  
  39. The variable-size list expects the dataBounds upper-left to be 0,0.  Any other
  40. upper-left for the dataBounds will cause the variable-size list to misbehave.  
  41. A dataBounds other than 0,0 is very rare, and unnecessary, so it seemed better
  42. to not have the code to support it, than to code for a feature almost never used.
  43.  
  44. Bit 14 of the mode field needs to be set to true for the list to be converted to
  45. a variable-size list.  Also, CLVInitialize() has to be called at some time, or else
  46. the framework will create the list as a regular list.  (Start.c is a good place.)
  47.  
  48. For the most part, the List control is managed just like the regular List control.
  49. If you need to access the List itself, it is stored in the refCon of the List control.
  50. However, since the List Manager calls aren't expecting the list to be of variable-size
  51. cells, you can't make all of the calls to the List Manager you would normally make.
  52.  
  53. If you create a regular list, and then place decimal ascii values in row 0 and
  54. column 0 (where needed), you can then directly call CLVVariableSizeCells() for that
  55. list, and it will be converted.  (If you call CLVVariableSizeCells() directly, you
  56. don't actually need to call CLVInitialize(), as it does this for you.)
  57.  
  58. Below are the List Manager calls, and how they should be handled when using a
  59. variable-size list:
  60.  
  61.  
  62. LActivate:
  63.     Call CLActivate().
  64.  
  65. LAddColumn:
  66.     Call CLVAddColumn().
  67.  
  68. LAddRow:
  69.     Call CLVAddRow().
  70.  
  71. LAddToCell:
  72.     Okay to call.  Cell won't be drawn, though.  Standard list drawing is disabled
  73.     when using variable-size cell mode.  Call CLVDraw() afterwards to draw the cell.
  74.  
  75. LAutoScroll:
  76.     Call CLVAutoScroll().
  77.  
  78. LCellSize:
  79.     New meaning.  You can set the size of a column or row.  To do, do the following:
  80.         1)    LGetCell() for the row or column width to change.  Example:
  81.                 For column 3,
  82.                     short    len, locSize[2];
  83.                     Point    cell;
  84.  
  85.                     len = 2 * sizeof(short);
  86.                     cell.h = 3;
  87.                     cell.v = 0;
  88.                     LGetCell(locSize, &len, cell, list);
  89.         2)    Set the size (2nd word) to new size (locSize[1] = newSize).
  90.         3)    LSetCell(locSize, len, cell, list);
  91.         4)    CLVAdjustCellLocs(list)
  92.         5)    CLVUpdate(list)
  93.  
  94. LClick:
  95.     Call CLVClick().
  96.  
  97. LClrCell:
  98.     Okay to call.  Cell won't be drawn, though.  Standard list drawing is disabled
  99.     when using variable-size cell mode.  Call CLVDraw() afterwards to draw the cell.
  100.  
  101. LDelColumn:
  102.     Call LDelColumn(), followed by CLVAdjustCellLocs() and CLVUpdate().
  103.  
  104. LDelRow:
  105.     Call LDelRow(), followed by CLVAdjustCellLocs() and CLVUpdate().
  106.  
  107. LDispose:
  108.     Don't call it.  Dispose by DisposeControl(CLViewFromList(list)).
  109.  
  110. LDoDraw:
  111.     Don't call it.  The variable-sized control should always have doDraw false.
  112.     (You can hide the list by making the control invisible.)
  113.  
  114. LDraw:
  115.     Call CLVDraw().
  116.  
  117. LFind:
  118.     Okay to call.
  119.  
  120. LGetCell:
  121.     Okay to call.
  122.  
  123. LGetSelect:
  124.     Okay to call.
  125.  
  126. LLastClick:
  127.     Okay to call.
  128.  
  129. LNextCell:
  130.     Okay to call.
  131.  
  132. LRect:
  133.     Call CLVGetCellInfo().
  134.     It's overkill, since it gets everything, but tough.  There aren't too many
  135.     occasions for the app to get the cell rect, so I'm not going to have another
  136.     call to do it.
  137.  
  138. LScroll:
  139.     Don't call.
  140.  
  141. LSearch:
  142.     Okay to call.
  143.  
  144. LSetCell:
  145.     Okay to call.  Cell won't be drawn, though.  Standard list drawing is disabled
  146.     when using variable-size cell mode.  Call CLVDraw() afterwards to draw the cell.
  147.  
  148. LSetSelect:
  149.     Call CLVSetSelect().
  150.  
  151. LUpdate:
  152.     Call CLVUpdate
  153.  
  154. */
  155.  
  156.  
  157. /*****************************************************************************/
  158.  
  159.  
  160.  
  161. #ifndef __CONTROLS__
  162. #include <Controls.h>
  163. #endif
  164.  
  165. #ifndef __DTSLib__
  166. #include "DTS.Lib.h"
  167. #endif
  168.  
  169. #ifndef __ERRORS__
  170. #include <Errors.h>
  171. #endif
  172.  
  173. #ifndef __LISTCONTROL__
  174. #include "ListControl.h"
  175. #endif
  176.  
  177. #ifndef __CLPROCS__
  178. #include "ListControlProcs.h"
  179. #endif
  180.  
  181. #ifndef __MEMORY__
  182. #include <Memory.h>
  183. #endif
  184.  
  185. #ifndef __PACKAGES__
  186. #include <Packages.h>
  187. #endif
  188.  
  189. #ifndef __RESOURCES__
  190. #include <Resources.h>
  191. #endif
  192.  
  193. #ifndef __UTILITIES__
  194. #include "Utilities.h"
  195. #endif
  196.  
  197.  
  198.  
  199. /*****************************************************************************/
  200.  
  201.  
  202.  
  203. typedef pascal void    (*LDEFProcPtr)(short lMessage, Boolean lSelect, Rect *lRect, Cell lCell,
  204.                                    short lDataOffset, short lDataLen, ListHandle list);
  205.  
  206. static ListHandle    gCLVList;
  207.  
  208. static void            CLVScrollContent(short h, short v);
  209. static WindowPtr    CLVSetClip(ListHandle list);
  210.  
  211.  
  212. Boolean        gMoveCell;
  213. Point        gMoveCellStart, gMoveCellEnd;
  214.  
  215.  
  216.  
  217. /*****************************************************************************/
  218.  
  219.  
  220.  
  221. #pragma segment ListControl
  222. void    CLVInitialize(void)
  223. {
  224.     if (!gclvVariableSizeCells) {
  225.         gclvVariableSizeCells = CLVVariableSizeCells;
  226.         gclvGetCellRect       = CLVGetCellRect;
  227.         gclvUpdate            = CLVUpdate;
  228.         gclvAutoScroll        = CLVAutoScroll;
  229.         gclvSetSelect         = CLVSetSelect;
  230.         gclvClick             = CLVClick;
  231.         gclvAdjustScrollBars  = CLVAdjustScrollBars;
  232.     }
  233. }
  234.  
  235.  
  236.  
  237. /*****************************************************************************/
  238.  
  239.  
  240.  
  241. #pragma segment ListControl
  242.  
  243. static void    CLVScrollContent(short h, short v)
  244. {
  245.     RgnHandle    updateRgn;
  246.     Rect        rView;
  247.  
  248.     rView  = (*gCLVList)->rView;
  249.     ScrollRect(&rView, h, v, updateRgn = NewRgn());
  250.     CLVUpdate(updateRgn, gCLVList);
  251.     DisposeRgn(updateRgn);
  252. }
  253.  
  254. static pascal void    CLVScrollAction(ControlHandle ctl, short part);
  255. static pascal void    CLVScrollAction(ControlHandle ctl, short part)
  256. {
  257.     short        delta, value;
  258.     short        oldValue, max, dx, dy;
  259.     Boolean        vert;
  260.     Rect        rct, rr, rrr;
  261.     Point        pp, cell;
  262.  
  263.     vert = (((*ctl)->contrlRect.right - (*ctl)->contrlRect.left) == 16);
  264.     rct  = (*gCLVList)->visible;
  265.  
  266.     CLVGetCellRect(gCLVList, rct.left, rct.top, &rr);
  267.     rrr = rr;
  268.  
  269.     switch (part) {
  270.         case inPageUp:
  271.             pp.h = rr.left;
  272.             pp.v = rr.top;
  273.             if (vert) {
  274.                 pp.v -= (*gCLVList)->rView.bottom;
  275.                 pp.v += (*gCLVList)->rView.top;
  276.                 pp.v += (rr.bottom - rr.top);
  277.                 pp.v++;
  278.                 CLVFindCell(gCLVList, pp, &cell);
  279.                 CLVGetCellRect(gCLVList, cell.h, cell.v, &rrr);
  280.                 delta = rrr.top - rr.top;
  281.             }
  282.             else {
  283.                 pp.h -= (*gCLVList)->rView.right;
  284.                 pp.h += (*gCLVList)->rView.left;
  285.                 pp.h += (rr.right - rr.left);
  286.                 pp.h++;
  287.                 CLVFindCell(gCLVList, pp, &cell);
  288.                 CLVGetCellRect(gCLVList, cell.h, cell.v, &rrr);
  289.                 delta = rrr.left - rr.left;
  290.             }
  291.             if (delta > 0) part = inUpButton;
  292.             break;
  293.         case inPageDown:
  294.             pp.h = rr.left;
  295.             pp.v = rr.top;
  296.             if (vert) {
  297.                 pp.v += (*gCLVList)->rView.bottom;
  298.                 pp.v -= (*gCLVList)->rView.top;
  299.                 pp.v--;
  300.                 CLVFindCell(gCLVList, pp, &cell);
  301.                 CLVGetCellRect(gCLVList, cell.h, cell.v, &rrr);
  302.                 delta = rrr.top - rr.top;
  303.             }
  304.             else {
  305.                 pp.h += (*gCLVList)->rView.right;
  306.                 pp.h -= (*gCLVList)->rView.left;
  307.                 pp.h--;
  308.                 CLVFindCell(gCLVList, pp, &cell);
  309.                 CLVGetCellRect(gCLVList, cell.h, cell.v, &rrr);
  310.                 delta = rrr.left - rr.left;
  311.             }
  312.             if (delta < 0) part = inDownButton;
  313.             break;
  314.     }
  315.     switch (part) {
  316.         case inUpButton:
  317.             for (;;) {
  318.                 if (vert) {
  319.                     if (rct.top == 1) break;
  320.                     --rct.top;
  321.                 }
  322.                 if (!vert) {
  323.                     if (rct.left == 1) break;
  324.                     --rct.left;
  325.                 }
  326.                 CLVGetCellRect(gCLVList, rct.left, rct.top, &rrr);
  327.                 if (!EmptyRect(&rrr)) break;
  328.             }
  329.             if (vert) delta = rrr.top  - rr.top;
  330.             else      delta = rrr.left - rr.left;
  331.             if (delta > 0) delta = 0;
  332.             break;
  333.         case inDownButton:
  334.             if (vert) delta = rr.bottom - rr.top;
  335.             else      delta = rr.right  - rr.left;
  336.             if (delta < 0) delta = 0;
  337.             break;
  338.     }
  339.  
  340.     if (part) {                        /* If it was actually in the control. */
  341.         pp.h = rr.left;
  342.         pp.v = rr.top;
  343.         if (vert) pp.v += delta;
  344.         else      pp.h += delta;
  345.         CLVFindCell(gCLVList, pp, &cell);
  346.         CLVGetCellRect(gCLVList, cell.h, cell.v, &rrr);
  347.  
  348.         if (vert) delta = rrr.top  - rr.top;
  349.         else      delta = rrr.left - rr.left;
  350.  
  351.         value = (oldValue = GetControlValue(ctl)) + delta;
  352.         if (value < 0)                                value = 0;
  353.         if (value > (max = GetControlMaximum(ctl))) value = max;
  354.  
  355.         if (value != oldValue) {
  356.             SetControlValue(ctl, value);
  357.             dx = (vert) ? 0 : (oldValue - value);
  358.             dy = (vert) ? (oldValue - value) : 0;
  359.             CLVAdjustScrollBars(gCLVList);
  360.             CLVScrollContent(dx, dy);
  361.         }
  362.     }
  363. }
  364.  
  365. static Boolean    CLVScroll(ControlHandle ctl, short part, Point where);
  366. static Boolean    CLVScroll(ControlHandle ctl, short part, Point where)
  367. {
  368.     ControlHandle    cc;
  369.     short            oldValue, newValue, vv, dx, dy, nn;
  370.     Point            pp, cell;
  371.     Rect            rView, rct;
  372.     Boolean            vert;
  373.  
  374.     static ControlActionUPP    cupp;
  375.  
  376.     oldValue = newValue = GetControlValue(ctl);
  377.     switch (part) {
  378.         case inThumb:
  379.             if (TrackControl(ctl, where, nil)) {
  380.                 newValue = GetControlValue(ctl);
  381.                 if (oldValue != newValue) {
  382.                     if ((*gCLVList)->hScroll) (*gCLVList)->visible.left = 1;
  383.                     if ((*gCLVList)->vScroll) (*gCLVList)->visible.top  = 1;
  384.                     vert = (((*ctl)->contrlRect.right - (*ctl)->contrlRect.left) == 16);
  385.                     vv = 0;
  386.                     if (vert) {
  387.                         cc = (*gCLVList)->hScroll;
  388.                         if (cc)
  389.                             vv = (*cc)->contrlValue;
  390.                     }
  391.                     else {
  392.                         cc = (*gCLVList)->vScroll;
  393.                         if (cc)
  394.                             vv = (*cc)->contrlValue;
  395.                     }
  396.                     (vert) ? (pp.h = vv, pp.v = newValue) : (pp.h = newValue, pp.v = vv);
  397.                     rView = (*gCLVList)->rView;
  398.                     pp.h += rView.left;
  399.                     pp.v += rView.top;
  400.                     CLVFindCell(gCLVList, pp, &cell);
  401.                     CLVGetCellRect(gCLVList, cell.h, cell.v, &rct);
  402.  
  403.                     if (vert) nn = newValue + ((rct.bottom - rct.top) / 2);
  404.                     else      nn = newValue + ((rct.right  - rct.left) / 2);
  405.                     (vert) ? (pp.h = vv, pp.v = nn) : (pp.h = nn, pp.v = vv);
  406.                     pp.h += rView.left;
  407.                     pp.v += rView.top;
  408.                     CLVFindCell(gCLVList, pp, &cell);
  409.                     CLVGetCellRect(gCLVList, cell.h, cell.v, &rct);
  410.  
  411.                     OffsetRect(&rct, -rView.left, -rView.top);
  412.                     newValue = (vert) ? rct.top : rct.left;
  413.                     SetControlValue(ctl, newValue);
  414.                     newValue = (*ctl)->contrlValue;
  415.  
  416.                     dx = (vert) ? 0 : (oldValue - newValue);
  417.                     dy = (vert) ? (oldValue - newValue) : 0;
  418.                     CLVAdjustScrollBars(gCLVList);
  419.                     CLVScrollContent(dx, dy);
  420.                     rct = (*gCLVList)->visible;
  421.                 }
  422.             }
  423.             break;
  424.         default:
  425.             if (!cupp) cupp = NewControlActionProc(CLVScrollAction);
  426.             TrackControl(ctl, where, cupp);
  427.             newValue = GetControlValue(ctl);
  428.             break;
  429.     }
  430.  
  431.     return((oldValue != newValue) ? true : false);
  432. }
  433.  
  434.  
  435.  
  436. /*****************************************************************************/
  437.  
  438.  
  439.  
  440. #pragma segment ListControl
  441. void    CLVUpdate(RgnHandle clipRgn, ListHandle list)
  442. {
  443.     WindowPtr    oldPort;
  444.     Rect        vbnds, cbnds, rView;
  445.     short        xx, yy, cellNum, ofst, len, select;
  446.     Point        cell;
  447.     RgnHandle    oldClip, newClip;
  448.  
  449.     GetPort(&oldPort);
  450.     SetPort((*list)->port);
  451.  
  452.     rView = (*list)->rView;
  453.     GetClip(oldClip = NewRgn());
  454.     RectRgn(newClip = NewRgn(), &rView);
  455.     SectRgn(newClip, oldClip, newClip);
  456.     SectRgn(newClip, clipRgn, newClip);
  457.     SetClip(newClip);
  458.  
  459.     vbnds = (*list)->visible;
  460.     for (yy = vbnds.top; yy < vbnds.bottom; ++yy) {
  461.         for (xx = vbnds.left; xx < vbnds.right; ++xx) {
  462.             CLVGetCellInfo(list, xx, yy, &cbnds, &cellNum, &select, &ofst, &len);
  463.             cell.h = xx;
  464.             cell.v = yy;
  465.             CLVCallDefProc(lDrawMsg, select, &cbnds, cell, ofst, len, list);
  466.         }
  467.     }
  468.  
  469.     SetClip(oldClip);
  470.     DisposeRgn(oldClip);
  471.     DisposeRgn(newClip);
  472.     SetPort(oldPort);
  473. }
  474.  
  475.  
  476.  
  477. /*****************************************************************************/
  478.  
  479.  
  480.  
  481. #pragma segment ListControl
  482. static void    CLVCallDefProc(short lMessage, short lSelect, Rect *lRect, Cell lCell,
  483.                            short lDataOffset, short lDataLen, ListHandle list)
  484. {
  485.     Handle        ldp;
  486.     LDEFProcPtr    proc;
  487.  
  488.     if (!(ldp = (*list)->listDefProc)) return;
  489.  
  490.     if (!*ldp) LoadResource(ldp);
  491.     if (!*ldp) return;
  492.  
  493.     HLock(ldp);
  494.     proc = (LDEFProcPtr)*ldp;
  495.     lSelect = (lSelect) ? true: false;
  496.  
  497.     CallListDefProc(((ListDefUPP)proc), lMessage, lSelect, lRect, lCell, lDataOffset, lDataLen, list);
  498.     HUnlock(ldp);
  499. }
  500.  
  501.  
  502.  
  503. /*****************************************************************************/
  504.  
  505.  
  506.  
  507. #pragma segment ListControl
  508. Boolean    CLVClick(Point mouseLoc, short modifiers, ListHandle list)
  509. {
  510.     WindowPtr        oldPort, window;
  511.     ControlHandle    ctl;
  512.     RgnHandle        oldClip, newClip;
  513.     Boolean            dbl, tracked, turnOff, doRects, inBounds;
  514.     Point            cc, dd, cell, lastCell, anchor, ulSel, lrSel, pp, mm;
  515.     short            cellNum, ofst, len, newsel, oldsel, sense, part, dx, dy, data1len, data2len;
  516.     Rect            rView, cbnds, rr, rct, dbnds, vbnds;
  517.     long            ll, ctime;
  518.     char            selFlags, listFlags;
  519.     char            data1[256], data2[256];
  520.  
  521.     gMoveCellStart.v = gMoveCellStart.h = gMoveCellEnd.v = gMoveCellEnd.h = -1;
  522.  
  523.     GetPort(&oldPort);
  524.     SetPort(window = (*list)->port);
  525.  
  526.     rView    = (*list)->rView;
  527.     selFlags = (*list)->selFlags;
  528.     if (selFlags & lOnlyOne) {
  529.         selFlags  &= (lNoNilHilite | lUseSense | lOnlyOne);
  530.         modifiers &= (0xFFFF - shiftKey - cmdKey);
  531.     }
  532.  
  533.     (*list)->clikLoc = mouseLoc;
  534.  
  535.     if (WhichControl(mouseLoc, 0, window, &ctl)) {
  536.         if (!(part = FindControl(mouseLoc, window, &ctl))) {
  537.             (*list)->clikTime = 0L;
  538.             return(false);
  539.         }
  540.         if ((ctl == (*list)->hScroll) || (ctl == (*list)->vScroll)) {
  541.             gCLVList = list;
  542.             tracked  = CLVScroll(ctl, part, mouseLoc);
  543.             return(false);
  544.         }
  545.     }
  546.  
  547.     if (!PtInRect(mouseLoc, &rView)) {
  548.         (*list)->clikTime = 0L;
  549.         return(false);
  550.     }
  551.  
  552.     CLVFindCell(list, mouseLoc, &cell);
  553.     (*list)->clikLoc = mouseLoc;
  554.     if (cell.h == -1) {
  555.         (*list)->clikTime = 0L;
  556.         return(false);
  557.     }
  558.     if (gMoveCell) gMoveCellStart = cell;
  559.  
  560.     CLVGetCellInfo(list, cell.h, cell.v, &cbnds, &cellNum, &sense, &ofst, &len);
  561.  
  562.     GetClip(oldClip = NewRgn());
  563.     RectRgn(newClip = NewRgn(), &rView);
  564.     SectRgn(newClip, oldClip, newClip);
  565.     SetClip(newClip);
  566.  
  567.     ulSel.h = ulSel.v = 0x7FFF;
  568.     lrSel.h = lrSel.v = 0;
  569.  
  570.     if (selFlags & lUseSense) {
  571.         if (modifiers & shiftKey) {
  572.             modifiers |= cmdKey;
  573.         }
  574.     }
  575.  
  576.     cc.h = cc.v = 1;
  577.     turnOff = true;
  578.     if (modifiers & shiftKey) {
  579.         if (!(selFlags & lUseSense)) turnOff = false;
  580.         if (!sense)                  turnOff = false;
  581.         if (selFlags & lNoExtend)    turnOff = false;
  582.     }
  583.     else {
  584.         if (modifiers & cmdKey)   turnOff = false;
  585.         if (sense)                turnOff = false;
  586.     }
  587.     while (LGetSelect(true, &cc, list)) {
  588.         CLVGetCellInfo(list, cc.h, cc.v, &cbnds, &cellNum, &oldsel, &ofst, &len);
  589.         if (turnOff) {
  590.             if ((cell.h != cc.h) || (cell.v != cc.v)) {
  591.                 (*list)->cellArray[cellNum] &= 0x7FFF;
  592.                 CLVCallDefProc(lHiliteMsg, false, &cbnds, cc, ofst, len, list);
  593.             }
  594.         }
  595.         else {
  596.             if (ulSel.v > cc.v) ulSel.v = cc.v;
  597.             if (ulSel.h > cc.h) ulSel.h = cc.h;
  598.             if (lrSel.v < cc.v) lrSel.v = cc.v;
  599.             if (lrSel.h < cc.h) lrSel.h = cc.h;
  600.             if (selFlags & lNoDisjoint) {
  601.                 (*list)->cellArray[cellNum] &= 0x7FFF;
  602.                 CLVCallDefProc(lHiliteMsg, false, &cbnds, cc, ofst, len, list);
  603.             }
  604.         }
  605.         if (!LNextCell(true, true, &cc, list)) break;
  606.     }
  607.  
  608.     anchor = cell;
  609.     if (!(selFlags & lNoExtend)) {
  610.         if (lrSel.v) {
  611.             for (;;) {
  612.                 if (cell.h <= ulSel.h) {
  613.                     anchor = lrSel;
  614.                     break;
  615.                 }
  616.                 if (cell.v <= ulSel.v) {
  617.                     anchor = lrSel;
  618.                     break;
  619.                 }
  620.                 anchor = ulSel;
  621.                 break;
  622.             }
  623.         }
  624.     }
  625.  
  626.     lastCell.h = lastCell.v = -1;
  627.  
  628.     cc  = (*list)->lastClick;
  629.     dbl = ((cc.h == cell.h) && (cc.v == cell.v)) ? true : false;
  630.     (*list)->lastClick = cell;
  631.     ctime = (*list)->clikTime;
  632.     (*list)->clikTime = TickCount();
  633.  
  634.     doRects = true;
  635.  
  636.     do {
  637.  
  638.         if ((cell.h != lastCell.h) || (cell.v != lastCell.v)) {
  639.  
  640.             for (;;) {
  641.  
  642.                 if (doRects) {
  643.                     if (modifiers & shiftKey) {
  644.                         rr.top    = (cell.v < anchor.v) ? cell.v : anchor.v;
  645.                         rr.left   = (cell.h < anchor.h) ? cell.h : anchor.h;
  646.                         rr.bottom = (cell.v > anchor.v) ? cell.v : anchor.v;
  647.                         rr.right  = (cell.h > anchor.h) ? cell.h : anchor.h;
  648.                         ++rr.bottom;
  649.                         ++rr.right;
  650.                         cc.h = cc.v = 1;
  651.                         turnOff = true;
  652.                         if (selFlags & lNoExtend) turnOff = false;
  653.                         if (turnOff) {
  654.                             while (LGetSelect(true, &cc, list)) {
  655.                                 if (!PtInRect(cc, &rr)) {
  656.                                     CLVGetCellInfo(list, cc.h, cc.v, &cbnds, &cellNum,
  657.                                                    &oldsel, &ofst, &len);
  658.                                     (*list)->cellArray[cellNum] &= 0x7FFF;
  659.                                     CLVCallDefProc(lHiliteMsg, false, &cbnds, cc, ofst, len, list);
  660.                                 }
  661.                                 if (!LNextCell(true, true, &cc, list)) break;
  662.                             }
  663.                         }
  664.                         for (cc.v = rr.top; cc.v < rr.bottom; ++cc.v) {
  665.                             for (cc.h = rr.left; cc.h < rr.right; ++cc.h) {
  666.                                 oldsel = (LGetSelect(false, &cc, list)) ? 0x8000 : 0x0000;
  667.                                 newsel = 0x8000;
  668.                                 if (selFlags & lUseSense)
  669.                                     newsel = sense ^ 0x8000;
  670.                                 if (selFlags & lNoNilHilite)
  671.                                     if (!len)
  672.                                         newsel = 0;
  673.                                 if (newsel != oldsel) {
  674.                                     CLVGetCellInfo(list, cc.h, cc.v, &cbnds, &cellNum,
  675.                                                    &oldsel, &ofst, &len);
  676.                                     (*list)->cellArray[cellNum] &= 0x7FFF;
  677.                                     (*list)->cellArray[cellNum] |= newsel;
  678.                                     CLVCallDefProc(lHiliteMsg, newsel, &cbnds, cc, ofst, len, list);
  679.                                 }
  680.                             }
  681.                         }
  682.                         if (selFlags & lNoRect) doRects = false;
  683.                         break;
  684.                     }
  685.                 }
  686.  
  687.                 if (lastCell.h != -1) {
  688.                     oldsel = (LGetSelect(false, &lastCell, list)) ? 0x8000 : 0x0000;
  689.                     newsel = 0;
  690.                     if (modifiers & cmdKey) newsel = (sense ^ 0x8000);
  691.                     else {
  692.                         if (selFlags & lNoRect) 
  693.                             if (modifiers & shiftKey)
  694.                                 newsel = 0x8000;
  695.                     }
  696.                     if (selFlags & lExtendDrag)
  697.                         if (!(modifiers & (cmdKey | shiftKey)))
  698.                             newsel = 0x8000;
  699.                     if (newsel != oldsel) {
  700.                         CLVGetCellInfo(list, lastCell.h, lastCell.v, &cbnds, &cellNum,
  701.                                        &oldsel, &ofst, &len);
  702.                         (*list)->cellArray[cellNum] &= 0x7FFF;
  703.                         (*list)->cellArray[cellNum] |= newsel;
  704.                         CLVCallDefProc(lHiliteMsg, false, &cbnds, lastCell, ofst, len, list);
  705.                     }
  706.                 }
  707.                 if (cell.h != -1) {
  708.                     oldsel = (LGetSelect(false, &cell, list)) ? 0x8000 : 0x0000;
  709.                     newsel = 0x8000;
  710.                     if (modifiers & cmdKey) newsel = (sense ^ 0x8000);
  711.                     if (selFlags & lNoNilHilite)
  712.                         if (!len)
  713.                             newsel = 0;
  714.                     if (newsel != oldsel) {
  715.                         CLVGetCellInfo(list, cell.h, cell.v, &cbnds, &cellNum,
  716.                                        &oldsel, &ofst, &len);
  717.                         (*list)->cellArray[cellNum] &= 0x7FFF;
  718.                         (*list)->cellArray[cellNum] |= newsel;
  719.                         CLVCallDefProc(lHiliteMsg, newsel, &cbnds, cc, ofst, len, list);
  720.                     }
  721.                 }
  722.  
  723.                 break;
  724.             }
  725.         }
  726.  
  727.         GetMouse(&mouseLoc);
  728.         lastCell = cell;
  729.         dbnds    = (*list)->dataBounds;
  730.  
  731.         CLVGetCellRect(list, dbnds.right - 1, dbnds.bottom - 1, &rct);
  732.         rr = rView;
  733.         rr.right  = rct.right;
  734.         rr.bottom = rct.bottom;
  735.         SectRect(&rView, &rr, &rr);
  736.         ll = PinRect(&rr, mouseLoc);
  737.         mm = *(Point *)≪
  738.         CLVFindCell(list, mm, &cc);
  739.         if (!EqualPt(cc, lastCell)) {
  740.             cell = lastCell;
  741.             if (cc.h > lastCell.h) ++cell.h;
  742.             if (cc.h < lastCell.h) --cell.h;
  743.             if (cc.v > lastCell.v) ++cell.v;
  744.             if (cc.v < lastCell.v) --cell.v;
  745.             if (gMoveCell) {
  746.                 data1len = data2len = 256;
  747.                 LGetCell(data1, &data1len, cell,     list);
  748.                 LGetCell(data2, &data2len, lastCell, list);
  749.                 LSetCell(data1,  data1len, lastCell, list);
  750.                 LSetCell(data2,  data2len, cell,     list);
  751.                 CLVGetCellInfo(list, cell.h,     cell.v,     &cbnds, &cellNum, &sense, &ofst, &len);
  752.                 CLVCallDefProc(lDrawMsg, sense, &cbnds, cell, ofst, len, list);
  753.                 CLVGetCellInfo(list, lastCell.h, lastCell.v, &cbnds, &cellNum, &sense, &ofst, &len);
  754.                 CLVCallDefProc(lDrawMsg, sense, &cbnds, cell, ofst, len, list);
  755.                 gMoveCellEnd = cell;
  756.             }
  757.             continue;
  758.         }
  759.  
  760.         if (!PtInRect(mouseLoc, &rView)) {
  761.             listFlags = (*list)->listFlags;
  762.             vbnds = (*list)->visible;
  763.             dx = dy = 0;
  764.             if (listFlags & lDoHAutoscroll) {
  765.                 if (mouseLoc.h <  rView.left)  dx = -1;
  766.                 if (mouseLoc.h >= rView.right) dx = 1;
  767.             }
  768.             if (listFlags & lDoVAutoscroll) {
  769.                 if (mouseLoc.v <  rView.top)    dy = -1;
  770.                 if (mouseLoc.v >= rView.bottom) dy = 1;
  771.             }
  772.  
  773.             CLVGetCellRect(list, vbnds.right - 1, vbnds.bottom - 1, &rct);
  774.             if (dx == 1)
  775.                 if (vbnds.right >= dbnds.right)
  776.                     if (rct.right <= rView.right)
  777.                         dx = 0;
  778.             if (dy == 1)
  779.                 if (vbnds.bottom >= dbnds.bottom)
  780.                     if (rct.bottom <= rView.bottom)
  781.                         dy = 0;
  782.  
  783.             if (dx | dy) {
  784.                 pp.h  = (*list)->visible.left;
  785.                 pp.v  = (*list)->visible.top;
  786.                 cc    = pp;
  787.                 for (;;) {
  788.                     inBounds = false;
  789.                     cc.h += dx;
  790.                     cc.v += dy;
  791.                     if (!cc.h)                  break;
  792.                     if (!cc.v)                  break;
  793.                     if (cc.h == dbnds.right)  break;
  794.                     if (cc.v == dbnds.bottom) break;
  795.                     inBounds = true;
  796.                     CLVGetCellRect(list, cc.h, cc.v, &rr);
  797.                     if (!EmptyRect(&rr)) break;
  798.                 }
  799.                 if (inBounds) {
  800.                     CLVGetCellRect(list, pp.h, pp.v, &rct);
  801.                     gCLVList = list;
  802.                     dx = rr.left - rct.left;
  803.                     dy = rr.top  - rct.top;
  804.                     SetClip(oldClip);
  805.                     ctl = (*list)->hScroll;
  806.                     if (ctl)
  807.                         SetControlValue(ctl, (*ctl)->contrlValue + dx);
  808.                     ctl = (*list)->vScroll;
  809.                     if (ctl)
  810.                         SetControlValue(ctl, (*ctl)->contrlValue + dy);
  811.                     SetClip(newClip);
  812.                     CLVAdjustScrollBars(list);
  813.                     CLVScrollContent(-dx, -dy);
  814.  
  815.                     CLVGetCellRect(list, dbnds.right - 1, dbnds.bottom - 1, &rct);
  816.                     rr = rView;
  817.                     rr.right  = rct.right;
  818.                     rr.bottom = rct.bottom;
  819.                     SectRect(&rView, &rr, &rr);
  820.                     ll = PinRect(&rr, mouseLoc);
  821.                     mm = *(Point *)≪
  822.                     CLVFindCell(list, mm, &cell);
  823.                     if (gMoveCell) {
  824.                         if (cell.v >= 0) {
  825.                             cc = lastCell;
  826.                             for (cc = lastCell; !EqualPt(cc, cell); cc = dd) {
  827.                                 dd = cc;
  828.                                 if (dd.h < cell.h) ++dd.h;
  829.                                 if (dd.h > cell.h) --dd.h;
  830.                                 if (dd.v < cell.v) ++dd.v;
  831.                                 if (dd.v > cell.v) --dd.v;
  832.                                 data1len = data2len = 256;
  833.                                 LGetCell(data1, &data1len, cc, list);
  834.                                 LGetCell(data2, &data2len, dd, list);
  835.                                 LSetCell(data1,  data1len, dd, list);
  836.                                 LSetCell(data2,  data2len, cc, list);
  837.                                 CLVGetCellInfo(list, cc.h, cc.v, &cbnds, &cellNum, &sense, &ofst, &len);
  838.                                 CLVCallDefProc(lDrawMsg, sense, &cbnds, cell, ofst, len, list);
  839.                                 CLVGetCellInfo(list, dd.h, dd.v, &cbnds, &cellNum, &sense, &ofst, &len);
  840.                                 CLVCallDefProc(lDrawMsg, sense, &cbnds, cell, ofst, len, list);
  841.                                 gMoveCellEnd = cell;
  842.                             }
  843.                         }
  844.                     }
  845.                 }
  846.             }
  847.         }
  848.  
  849.     } while (StillDown());
  850.  
  851.     SetClip(oldClip);
  852.     DisposeRgn(oldClip);
  853.     DisposeRgn(newClip);
  854.     SetPort(oldPort);
  855.  
  856.     if (dbl) {
  857.         cc = (*list)->lastClick;
  858.         if ((cc.h == cell.h) && (cc.v == cell.v)) {
  859.             if (TickCount() > (ctime + GetDblTime()))
  860.                 dbl = false;
  861.             else
  862.                 (*list)->clikTime = 0L;
  863.         }
  864.         else {
  865.             dbl = false;
  866.             (*list)->clikTime = 0L;
  867.         }
  868.     }
  869.  
  870.     return(dbl);
  871. }
  872.  
  873.  
  874.  
  875. /*****************************************************************************/
  876.  
  877.  
  878.  
  879. #pragma segment ListControl
  880. static WindowPtr    CLVSetClip(ListHandle list)
  881. {
  882.     static WindowPtr    oldPort;
  883.     WindowPtr            window;
  884.     static RgnHandle    oldClip;
  885.     RgnHandle            newClip;
  886.     Rect                rView;
  887.  
  888.     if (list) {
  889.         GetPort(&oldPort);
  890.         SetPort(window = (*list)->port);
  891.         rView = (*list)->rView;
  892.         GetClip(oldClip = NewRgn());
  893.         RectRgn(newClip = NewRgn(), &rView);
  894.         SectRgn(newClip, oldClip, newClip);
  895.         SetClip(newClip);
  896.         DisposeRgn(newClip);
  897.     }
  898.     else {
  899.         SetClip(oldClip);
  900.         SetPort(oldPort);
  901.     }
  902.  
  903.     return(window);
  904. }
  905.  
  906.  
  907.  
  908. /*****************************************************************************/
  909. /*****************************************************************************/
  910. /*****************************************************************************/
  911.  
  912.  
  913.  
  914. #pragma segment ListControl
  915. void    CLVVariableSizeCells(ListHandle list)
  916. {
  917.     ControlHandle    viewCtl;
  918.     CLDataHndl        listData;
  919.     short            mode, len;
  920.     short            locSize[2];
  921.     Rect            dbnds;
  922.     Point            cell;
  923.     Str255            pstr;
  924.  
  925.     CLVInitialize();
  926.  
  927.     if (!(viewCtl = CLViewFromList(list))) return;
  928.  
  929.     listData = (CLDataHndl)(*viewCtl)->contrlData;
  930.     mode     = (*listData)->mode;
  931.     if (mode & clVariable) return;        /* List already variable mode. */
  932.  
  933.     mode |= clVariable;
  934.     (*listData)->mode = mode;
  935.     LSetDrawingMode(false, list);        /* We're doing it now.  Don't let List Manager play. */
  936.  
  937.     dbnds = (*list)->dataBounds;
  938.  
  939.     for (locSize[0] = cell.h = cell.v = 0; ++cell.h < dbnds.right;) {
  940.         len = 255;
  941.         LGetCell(pstr + 1, &len, cell, list);
  942.         pstr[0] = len;
  943.         locSize[1] = (pstr[0]) ? p2dec(pstr, nil) : (*list)->cellSize.h;
  944.         LSetCell(locSize, (2 * sizeof(short)), cell, list);
  945.         locSize[0] += locSize[1];
  946.     }
  947.  
  948.     for (locSize[0] = cell.h = cell.v = 0; ++cell.v < dbnds.bottom;) {
  949.         len = 255;
  950.         LGetCell(pstr + 1, &len, cell, list);
  951.         pstr[0] = len;
  952.         locSize[1] = (pstr[0]) ? p2dec(pstr, nil) : (*list)->cellSize.v;
  953.         LSetCell(locSize, (2 * sizeof(short)), cell, list);
  954.         locSize[0] += locSize[1];
  955.     }
  956.  
  957.     CLVAdjustScrollBars(list);        /* Fix scrollbars to reflect the size of the List. */
  958.                                     /* This also fixes the visible field of the list.  */
  959. }
  960.  
  961.  
  962.  
  963. /*****************************************************************************/
  964.  
  965.  
  966. /* Figure out which cells are at least partially visible.  It's a pain...
  967. ** This also saves the visible cells rect into (*list)->visible so that other functions
  968. ** can get it quicker than the below hunk-o-code. */
  969.  
  970. #pragma segment ListControl
  971. void    CLVGetVisCells(ListHandle list, Rect *vbnds)
  972. {
  973.     Rect            rView, cellRct, rct;
  974.     ControlHandle    ctl;
  975.     short            len, locSize[2], dx, dy;
  976.     Point            cell;
  977.  
  978.     *vbnds = (*list)->dataBounds;
  979.     rView  = (*list)->rView;
  980.  
  981.     ctl = (*list)->hScroll;
  982.     if (ctl) dx = (*ctl)->contrlValue;
  983.     else {
  984.         cell.v = 0;
  985.         if (!(cell.h = (*list)->visible.left)) ++cell.h;
  986.         len = 2 * sizeof(short);
  987.         LGetCell(locSize, &len, cell, list);
  988.         dx = locSize[0];
  989.     }
  990.     ctl = (*list)->vScroll;
  991.     if (ctl) dy = (*ctl)->contrlValue;
  992.     else {
  993.         cell.h = 0;
  994.         if (!(cell.v = (*list)->visible.top)) ++cell.v;
  995.         len = 2 * sizeof(short);
  996.         LGetCell(locSize, &len, cell, list);
  997.         dy = locSize[0];
  998.     }
  999.  
  1000.     OffsetRect(&rView, dx, dy);
  1001.     (*list)->visible.left = (*list)->visible.top = 1;
  1002.  
  1003.     for (; vbnds->left < vbnds->right; ++vbnds->left) {
  1004.         CLVGetCellRect(list, vbnds->left, 1, &cellRct);
  1005.         cellRct.top    = rView.top;
  1006.         cellRct.bottom = rView.bottom;
  1007.         SectRect(&rView, &cellRct, &rct);
  1008.         if (!EmptyRect(&rct)) break;
  1009.     }
  1010.     for (; vbnds->right > vbnds->left;) {
  1011.         CLVGetCellRect(list, --vbnds->right, 1, &cellRct);
  1012.         cellRct.top    = rView.top;
  1013.         cellRct.bottom = rView.bottom;
  1014.         SectRect(&rView, &cellRct, &rct);
  1015.         if (!EmptyRect(&rct)) {
  1016.             ++vbnds->right;
  1017.             break;
  1018.         }
  1019.     }
  1020.  
  1021.     for (; vbnds->top < vbnds->bottom; ++vbnds->top) {
  1022.         CLVGetCellRect(list, 1, vbnds->top, &cellRct);
  1023.         cellRct.left  = rView.left;
  1024.         cellRct.right = rView.right;
  1025.         SectRect(&rView, &cellRct, &rct);
  1026.         if (!EmptyRect(&rct)) break;
  1027.     }
  1028.     for (; vbnds->bottom > vbnds->top;) {
  1029.         CLVGetCellRect(list, 1, --vbnds->bottom, &cellRct);
  1030.         cellRct.left  = rView.left;
  1031.         cellRct.right = rView.right;
  1032.         SectRect(&rView, &cellRct, &rct);
  1033.         if (!EmptyRect(&rct)) {
  1034.             ++vbnds->bottom;
  1035.             break;
  1036.         }
  1037.     }
  1038.  
  1039.     (*list)->visible = *vbnds;
  1040.  
  1041.     return;
  1042. }
  1043.  
  1044.  
  1045.  
  1046. /*****************************************************************************/
  1047.  
  1048.  
  1049.  
  1050. /* This function looks up the position of cell x,y by getting the info from
  1051. ** x,0 and 0,y cells.  Row 0 and column 0 are never displayed.  They hold the
  1052. ** row and column sizes. */
  1053.  
  1054. #pragma segment ListControl
  1055. void    CLVGetCellRect(ListHandle list, short xx, short yy, Rect *cbnds)
  1056. {
  1057.     Point    cell;
  1058.     short    len, locSize[2], dx, dy;
  1059.  
  1060.     if ((!xx) || (!yy)) {
  1061.         SetRect(cbnds, 0, 0, 0, 0);
  1062.         return;
  1063.     }
  1064.  
  1065.     cell.h = 0;
  1066.     cell.v = yy;
  1067.     len = 2 * sizeof(short);
  1068.     LGetCell(locSize, &len, cell, list);
  1069.     cbnds->top    = locSize[0];
  1070.     cbnds->bottom = locSize[0] + locSize[1];
  1071.  
  1072.     cell.h = xx;
  1073.     cell.v = 0;
  1074.     len = 2 * sizeof(short);
  1075.     LGetCell(locSize, &len, cell, list);
  1076.     cbnds->left   = locSize[0];
  1077.     cbnds->right  = locSize[0] + locSize[1];
  1078.  
  1079.     OffsetRect(cbnds, (*list)->rView.left, (*list)->rView.top);
  1080.  
  1081.     if (!(cell.h = (*list)->visible.left)) ++cell.h;
  1082.     cell.v = 0;
  1083.     len = 2 * sizeof(short);
  1084.     LGetCell(locSize, &len, cell, list);
  1085.     dx = locSize[0];
  1086.  
  1087.     cell.h = 0;
  1088.     if (!(cell.v = (*list)->visible.top)) ++cell.v;
  1089.     len = 2 * sizeof(short);
  1090.     LGetCell(locSize, &len, cell, list);
  1091.     dy = locSize[0];
  1092.  
  1093.     OffsetRect(cbnds, -dx, -dy);
  1094. }
  1095.  
  1096.  
  1097.  
  1098. /*****************************************************************************/
  1099.  
  1100.  
  1101.  
  1102. #pragma segment ListControl
  1103. void    CLVFindCell(ListHandle list, Point mouseLoc, Point *cell)
  1104. {
  1105.     Rect    dbnds, rrct, rct;
  1106.     short    xx, yy;
  1107.  
  1108.     dbnds = (*list)->dataBounds;
  1109.  
  1110.     CLVGetCellRect(list, 1, 1, &rct);
  1111.     rrct.left = rct.left;
  1112.     CLVGetCellRect(list, dbnds.right - 1, 1, &rct);
  1113.     rrct.right = rct.right;
  1114.  
  1115.     for (yy = dbnds.top; yy < dbnds.bottom; ++yy) {
  1116.         CLVGetCellRect(list, 1, yy, &rct);
  1117.         rrct.top    = rct.top;
  1118.         rrct.bottom = rct.bottom;
  1119.         if (PtInRect(mouseLoc, &rrct)) break;
  1120.     }
  1121.  
  1122.     if (yy < dbnds.bottom) {
  1123.         for (xx = dbnds.left; xx < dbnds.right; ++xx) {
  1124.             CLVGetCellRect(list, xx, yy, &rct);
  1125.             if (PtInRect(mouseLoc, &rct)) {
  1126.                 cell->h = xx;
  1127.                 cell->v = yy;
  1128.                 return;
  1129.             }
  1130.         }
  1131.     }
  1132.  
  1133.     cell->h = cell->v = -1;
  1134.     return;
  1135. }
  1136.  
  1137.  
  1138.  
  1139. /*****************************************************************************/
  1140.  
  1141.  
  1142.  
  1143. #pragma segment ListControl
  1144. void    CLVGetCellInfo(ListHandle list, short xx, short yy, Rect *cbnds, short *cellNum,
  1145.                        short *select, short *ofst, short *len)
  1146. {
  1147.     short    ww;
  1148.  
  1149.     CLVGetCellRect(list, xx, yy, cbnds);
  1150.     ww       = (*list)->dataBounds.right - (*list)->dataBounds.left;
  1151.     *cellNum = ww * yy + xx;
  1152.     *ofst    = (*list)->cellArray[*cellNum];
  1153.     *len     = (*list)->cellArray[*cellNum + 1] & 0x7FFF;
  1154.     *select  = *ofst & 0x8000;
  1155.     *ofst   &= 0x7FFF;
  1156.     *len    -= *ofst;
  1157. }
  1158.  
  1159.  
  1160.  
  1161. /*****************************************************************************/
  1162.  
  1163.  
  1164.  
  1165. #pragma segment ListControl
  1166. void    CLVAdjustScrollBars(ListHandle list)
  1167. {
  1168.     Rect            rView, dbnds, rct;
  1169.     short            oldx, oldy, max;
  1170.     ControlHandle    ctl;
  1171.     Point            pp, cell;
  1172.  
  1173.     rView = (*list)->rView;
  1174.     dbnds = (*list)->dataBounds;
  1175.     ++rView.right;            /* Account for the fact that the top of a rect is in, whereas the */
  1176.     ++rView.bottom;            /* bottom of a rect is out.  This makes top and bottom the same.  */
  1177.  
  1178.     if ((*list)->hScroll) (*list)->visible.left = 1;
  1179.     if ((*list)->vScroll) (*list)->visible.top  = 1;
  1180.  
  1181.     oldx = oldy = 0;
  1182.     ctl = (*list)->hScroll;
  1183.     if (ctl) {
  1184.         oldx = (*ctl)->contrlValue;
  1185.         CLVGetCellRect(list, dbnds.right - 1, 1, &rct);
  1186.         max = rct.right - rView.right;
  1187.         if (max < 0) max = 0;
  1188.         else {
  1189.             pp.h = rView.left + max;
  1190.             pp.v = rView.top;
  1191.             CLVFindCell(list, pp, &cell);
  1192.             CLVGetCellRect(list, cell.h, cell.v, &rct);
  1193.             max = rct.right - rView.left;
  1194.         }
  1195.         SetControlMaximum(ctl, max);
  1196.     }
  1197.     ctl = (*list)->vScroll;
  1198.     if (ctl) {
  1199.         oldy = (*ctl)->contrlValue;
  1200.         CLVGetCellRect(list, 1, dbnds.bottom - 1, &rct);
  1201.         max = rct.bottom - rView.bottom;
  1202.         if (max < 0) max = 0;
  1203.         else {
  1204.             pp.h = rView.left;
  1205.             pp.v = rView.top + max;
  1206.             CLVFindCell(list, pp, &cell);
  1207.             CLVGetCellRect(list, cell.h, cell.v, &rct);
  1208.             max = rct.bottom - rView.top;
  1209.         }
  1210.         SetControlMaximum(ctl, max);
  1211.     }
  1212.  
  1213.     CLVGetVisCells(list, &rct);        /* Calc vis area and store in list. */
  1214. }
  1215.  
  1216.  
  1217.  
  1218. /*****************************************************************************/
  1219.  
  1220.  
  1221.  
  1222. #pragma segment ListControl
  1223. void    CLVSetSelect(Boolean select, Point cell, ListHandle list)
  1224. {
  1225.     WindowPtr    oldPort;
  1226.     RgnHandle    oldClip, newClip;
  1227.     Rect        rView, cbnds;
  1228.     short        cellNum, oldsel, newsel, ofst, len;
  1229.  
  1230.     GetPort(&oldPort);
  1231.     SetPort((*list)->port);
  1232.     rView = (*list)->rView;
  1233.     GetClip(oldClip = NewRgn());
  1234.     RectRgn(newClip = NewRgn(), &rView);
  1235.     SectRgn(newClip, oldClip, newClip);
  1236.     SetClip(newClip);
  1237.  
  1238.     CLVGetCellInfo(list, cell.h, cell.v, &cbnds, &cellNum, &oldsel, &ofst, &len);
  1239.     newsel = (select) ? 0x8000 : 0x0000;
  1240.     if (newsel != oldsel) {
  1241.         (*list)->cellArray[cellNum] &= 0x7FFF;
  1242.         (*list)->cellArray[cellNum] |= newsel;
  1243.         CLVCallDefProc(lHiliteMsg, newsel, &cbnds, cell, ofst, len, list);
  1244.     }
  1245.  
  1246.     SetClip(oldClip);
  1247.     DisposeRgn(oldClip);
  1248.     DisposeRgn(newClip);
  1249.     SetPort(oldPort);
  1250. }
  1251.  
  1252.  
  1253.  
  1254. /*****************************************************************************/
  1255.  
  1256.  
  1257.  
  1258. #pragma segment ListControl
  1259. void    CLVAutoScroll(ListHandle list)
  1260. {
  1261.     WindowPtr        oldPort;
  1262.     RgnHandle        oldClip, newClip;
  1263.     Rect            rView, dbnds, vbnds, rct, rr;
  1264.     Point            cell, cc, pp;
  1265.     short            dx, dy, ddx, ddy;
  1266.     ControlHandle    ctl;
  1267.     Boolean            inBounds;
  1268.  
  1269.     ddx = ddy = 0;
  1270.     cell.h = cell.v = 1;
  1271.  
  1272.     if (LGetSelect(true, &cell, list)) {
  1273.  
  1274.         rView = (*list)->rView;
  1275.         dbnds = (*list)->dataBounds;
  1276.         vbnds = (*list)->visible;
  1277.  
  1278.         while ((!PtInRect(cell, &vbnds))) {
  1279.  
  1280.             if (EmptyRect(&vbnds)) return;
  1281.                     /* This shouldn't happen, but it would be bad if it did. */
  1282.  
  1283.             dx = dy = 0;
  1284.             if (cell.h <  vbnds.left)   dx = -1;
  1285.             if (cell.h >= vbnds.right)  dx = 1;
  1286.             if (cell.v <  vbnds.top)    dy = -1;
  1287.             if (cell.v >= vbnds.bottom) dy = 1;
  1288.  
  1289.             CLVGetCellRect(list, vbnds.right - 1, vbnds.bottom - 1, &rct);
  1290.             if (dx == 1)
  1291.                 if (vbnds.right >= dbnds.right)
  1292.                     if (rct.right <= rView.right)
  1293.                         dx = 0;
  1294.             if (dy == 1)
  1295.                 if (vbnds.bottom >= dbnds.bottom)
  1296.                     if (rct.bottom <= rView.bottom)
  1297.                         dy = 0;
  1298.             if ((!dx) && (!dy)) break;
  1299.  
  1300.             pp.h  = (*list)->visible.left;
  1301.             pp.v  = (*list)->visible.top;
  1302.             cc    = pp;
  1303.  
  1304.             for (;;) {
  1305.                 inBounds = false;
  1306.                 cc.h += dx;
  1307.                 cc.v += dy;
  1308.                 if (!cc.h)                  break;
  1309.                 if (!cc.v)                  break;
  1310.                 if (cc.h == dbnds.right)  break;
  1311.                 if (cc.v == dbnds.bottom) break;
  1312.                 inBounds = true;
  1313.                 CLVGetCellRect(list, cc.h, cc.v, &rr);
  1314.                 if (!EmptyRect(&rr)) break;
  1315.             }
  1316.             if (!inBounds) break;
  1317.  
  1318.             CLVGetCellRect(list, pp.h, pp.v, &rct);
  1319.             ddx += rr.left - rct.left;
  1320.             ddy += rr.top  - rct.top;
  1321.  
  1322.             OffsetRect(&vbnds, dx, dy);
  1323.             (*list)->visible = vbnds;
  1324.             ctl = (*list)->hScroll;
  1325.             if (ctl) (*ctl)->contrlValue += ddx;
  1326.             ctl = (*list)->vScroll;
  1327.             if (ctl) (*ctl)->contrlValue += ddy;
  1328.             CLVGetVisCells(list, &vbnds);
  1329.             ctl = (*list)->hScroll;
  1330.             if (ctl) (*ctl)->contrlValue -= ddx;
  1331.             ctl = (*list)->vScroll;
  1332.             if (ctl) (*ctl)->contrlValue -= ddy;
  1333.         }
  1334.  
  1335.         if ((ddx) || (ddy)) {
  1336.  
  1337.             GetPort(&oldPort);
  1338.             SetPort((*list)->port);
  1339.  
  1340.             ctl = (*list)->hScroll;
  1341.             if (ctl) SetControlValue(ctl, (*ctl)->contrlValue + ddx);
  1342.             ctl = (*list)->vScroll;
  1343.             if (ctl) SetControlValue(ctl, (*ctl)->contrlValue + ddy);
  1344.  
  1345.             GetClip(oldClip = NewRgn());
  1346.             RectRgn(newClip = NewRgn(), &rView);
  1347.             SectRgn(newClip, oldClip, newClip);
  1348.             SetClip(newClip);
  1349.             
  1350.             CLVAdjustScrollBars(list);
  1351.             gCLVList = list;
  1352.             ctl = CLViewFromList(list);
  1353.             if ((*ctl)->contrlVis)
  1354.                 CLVScrollContent(-ddx, -ddy);
  1355.  
  1356.             SetClip(oldClip);
  1357.             DisposeRgn(oldClip);
  1358.             DisposeRgn(newClip);
  1359.             SetPort(oldPort);
  1360.         }
  1361.     }
  1362. }
  1363.  
  1364.  
  1365.  
  1366. /*****************************************************************************/
  1367.  
  1368.  
  1369.  
  1370. #pragma segment ListControl
  1371. void    CLVAdjustCellLocs(ListHandle list)
  1372. {
  1373.     short    len, locSize[2], ls[2];
  1374.     Rect    dbnds;
  1375.     Point    cell;
  1376.  
  1377.     dbnds = (*list)->dataBounds;
  1378.  
  1379.     for (locSize[0] = cell.h = cell.v = 0; ++cell.h < dbnds.right;) {
  1380.         len = 2 * sizeof(short);
  1381.         LGetCell(ls, &len, cell, list);
  1382.         locSize[1] = ls[1];
  1383.         LSetCell(locSize, len, cell, list);
  1384.         locSize[0] += locSize[1];
  1385.     }
  1386.  
  1387.     for (locSize[0] = cell.h = cell.v = 0; ++cell.v < dbnds.bottom;) {
  1388.         len = 2 * sizeof(short);
  1389.         LGetCell(ls, &len, cell, list);
  1390.         locSize[1] = ls[1];
  1391.         LSetCell(locSize, len, cell, list);
  1392.         locSize[0] += locSize[1];
  1393.     }
  1394.  
  1395.     CLVAdjustScrollBars(list);
  1396. }
  1397.  
  1398.  
  1399.  
  1400. /*****************************************************************************/
  1401.  
  1402.  
  1403.  
  1404. #pragma segment ListControl
  1405. short    CLVAddColumn(short count, short colNum, short ww, ListHandle list)
  1406. {
  1407.     short    rval, locSize[2], xx;
  1408.     Point    cell;
  1409.  
  1410.     rval = LAddColumn(count, colNum, list);
  1411.  
  1412.     cell.v = 0;
  1413.     locSize[0] = 0;
  1414.     locSize[1] = ww;
  1415.     for (xx = 0; xx < count; ++xx) {
  1416.         cell.h = rval + xx;
  1417.         LSetCell(locSize, (2 * sizeof(short)), cell, list);
  1418.     }
  1419.     CLVAdjustCellLocs(list);
  1420.  
  1421.     return(rval);
  1422. }
  1423.  
  1424.  
  1425.  
  1426. /*****************************************************************************/
  1427.  
  1428.  
  1429.  
  1430. #pragma segment ListControl
  1431. short    CLVAddRow(short count, short rowNum, short hh, ListHandle list)
  1432. {
  1433.     short    rval, locSize[2], yy;
  1434.     Point    cell;
  1435.  
  1436.     rval = LAddRow(count, rowNum, list);
  1437.  
  1438.     cell.h = 0;
  1439.     locSize[0] = 0;
  1440.     locSize[1] = hh;
  1441.     for (yy = 0; yy < count; ++yy) {
  1442.         cell.v = rval + yy;
  1443.         LSetCell(locSize, (2 * sizeof(short)), cell, list);
  1444.     }
  1445.     CLVAdjustCellLocs(list);
  1446.  
  1447.     return(rval);
  1448. }
  1449.  
  1450.  
  1451.  
  1452. /*****************************************************************************/
  1453.  
  1454.  
  1455.  
  1456. #pragma segment ListControl
  1457. void    CLVDraw(Point cell, ListHandle list)
  1458. {
  1459.     Rect            cbnds;
  1460.     short            cellNum, select, ofst, len;
  1461.  
  1462.     if (list) {
  1463.         CLVSetClip(list);
  1464.         CLVGetCellInfo(list, cell.h, cell.v, &cbnds, &cellNum, &select, &ofst, &len);
  1465.         CLVCallDefProc(lDrawMsg, select, &cbnds, cell, ofst, len, list);
  1466.         CLVSetClip(nil);
  1467.     }
  1468. }
  1469.  
  1470.  
  1471.  
  1472.