home *** CD-ROM | disk | FTP | other *** search
/ Developer CD Series 1994 February: Tool Chest / Dev.CD Feb 94.toast / Tool Chest / Development Platforms / AppsToGo / AppsToGo.src / DTS.Lib / ListControl.c < prev    next >
Encoding:
C/C++ Source or Header  |  1993-06-18  |  38.1 KB  |  1,491 lines  |  [TEXT/MPS ]

  1. /*
  2. ** Apple Macintosh Developer Technical Support
  3. **
  4. ** Program:         listcontrol.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. ** To create a List control, you only need a single call.  For example:
  22. **
  23. **    list = CLNew(rViewCtl,            Resource ID of view control for List control.
  24. **                 true,                 Control initially visible.
  25. **                 &viewRct,            View rect of list.
  26. **                 numRows,            Number of rows to create List with.
  27. **                 numCols,            Number of columns to create List with.
  28. **                 cellHeight,
  29. **                 cellWidth,
  30. **                 theLProc,            Custom List procedure resource ID.
  31. **                 window,            Window to hold List control.
  32. **                 clHScroll | blBrdr | clActive        Horizontal scrollbar, active List.
  33. **    );
  34. **
  35.  
  36. ** If the CLNew call succeeds, you then have a List control in your
  37. ** window.  It will be automatically disposed of when you close the window.
  38. ** If you don't waht this to happen, then you can detach it from the
  39. ** view control which owns it.  To do this, you would to the following:
  40. **
  41. **  viewCtl = CLViewFromList(theListHndl);
  42. **  if (viewCtl) SetCRefCon(viewCtl, nil);
  43. **
  44. ** The view control keeps a reference to the List record in the refCon.
  45. ** If the refCon is cleared, then the view control does nothing.  So, all that
  46. ** is needed to detach a List record from a view control is to set the
  47. ** view control's refCon nil.  Now if you close the window, you will still
  48. ** have the List record.
  49. **
  50. **
  51. ** To remove a List control completely from a window, just dispose of the view
  52. ** control that holds the List record.  To do this, just do something like the below:
  53. **
  54. **  DisposeControl(CLViewFromList(theListHndl));
  55. **
  56. ** This completely disposes of the List control.
  57. **
  58. **
  59. ** Events for the List record are handled nearly automatically.  Just make the
  60. ** following call:
  61. **
  62. **  CLClick(window, eventPtr, &action);
  63. **
  64. ** If the event was handled, true is returned.  If the event is false, then the
  65. ** event doesn't belong to a List control, and further processing of the event
  66. ** should be done.
  67. */
  68.  
  69.  
  70.  
  71. /*****************************************************************************/
  72.  
  73.  
  74.  
  75. #ifndef __CONTROLS__
  76. #include <Controls.h>
  77. #endif
  78.  
  79. #ifndef __DTSLib__
  80. #include "DTS.Lib.h"
  81. #endif
  82.  
  83. #ifndef __ERRORS__
  84. #include <Errors.h>
  85. #endif
  86.  
  87. #ifndef __LISTCONTROL__
  88. #include "ListControl.h"
  89. #endif
  90.  
  91. #ifndef __MEMORY__
  92. #include <Memory.h>
  93. #endif
  94.  
  95. #ifndef __PACKAGES__
  96. #include <Packages.h>
  97. #endif
  98.  
  99. #ifndef __RESOURCES__
  100. #include <Resources.h>
  101. #endif
  102.  
  103. #ifndef __UTILITIES__
  104. #include "Utilities.h"
  105. #endif
  106.  
  107.  
  108.  
  109. /*****************************************************************************/
  110.  
  111.  
  112.  
  113. #define kListPosTextLen 32
  114. #define kPrevSel        16
  115.  
  116. typedef struct cdefRsrcJMP {
  117.     long    moveInst;
  118.     long    jsrInst;
  119.     short    jmpInst;
  120.     long    jmpAddress;
  121. } cdefRsrcJMP;
  122. typedef cdefRsrcJMP *cdefRsrcJMPPtr, **cdefRsrcJMPHndl;
  123.  
  124.  
  125.  
  126. /*****************************************************************************/
  127.  
  128.  
  129.  
  130. short    gListCtl = rListCtl;
  131.  
  132. static long                gLastKeyTime;
  133. static char                gListPosText[kListPosTextLen];
  134. static short            gListPosTextLen;
  135. static cdefRsrcJMPHndl    gCDEF;
  136.  
  137. static void            CLBorderDraw(ListHandle listHndl);
  138. static pascal long    CLCtl(short varCode, ControlHandle ctl, short msg, long parm);
  139. static pascal short    MyIntlCompare(Ptr aPtr, Ptr bPtr, short aLen, short bLen);
  140.  
  141. static void                dummyCLActivate(Boolean active, ListHandle listHndl);
  142. static Boolean            dummyCLClick(WindowPtr window, EventRecord *event, short *action);
  143. static ControlHandle    dummyCLCtlHit(void);
  144. static ListHandle        dummyCLFindActive(WindowPtr window);
  145. static Boolean            dummyCLKey(WindowPtr window, EventRecord *event);
  146. static ControlHandle    dummyCLNext(WindowPtr window, ListHandle *listHndl, ControlHandle ctl, short dir, Boolean justActive);
  147. static ControlHandle    dummyCLViewFromList(ListHandle listHndl);
  148. static ListHandle        dummyCLWindActivate(WindowPtr window, Boolean displayIt);
  149.  
  150. CLActivateProcPtr        gclActivate       = dummyCLActivate;
  151. CLClickProcPtr            gclClick          = dummyCLClick;
  152. CLCtlHitProcPtr            gclCtlHit         = dummyCLCtlHit;
  153. CLFindActiveProcPtr        gclFindActive     = dummyCLFindActive;
  154. CLKeyProcPtr            gclKey            = dummyCLKey;
  155. CLNextProcPtr            gclNext           = dummyCLNext;
  156. CLViewFromListProcPtr    gclViewFromList   = dummyCLViewFromList;
  157. CLWindActivateProcPtr    gclWindActivate   = dummyCLWindActivate;
  158.  
  159. extern short    gPrintPage;        /* Non-zero means we are printing. */
  160.  
  161.  
  162.  
  163. /*****************************************************************************/
  164.  
  165.  
  166.  
  167. static ListHandle        gFoundLHndl;
  168.     /* Global value used to return info from the List control proc. */
  169.  
  170. static ControlHandle    gFoundViewCtl;
  171.     /* Global value used to return info from the List control proc. */
  172.  
  173.  
  174.  
  175. /*****************************************************************************/
  176. /*****************************************************************************/
  177. /*****************************************************************************/
  178.  
  179.  
  180.  
  181. /* Instead of calling the functions directly, you can reference the global
  182. ** proc pointers that reference the functions.  This keeps everything from
  183. ** being linked in.  The default global proc pointers point to dummy functions
  184. ** that behave as if there aren't any list controls.  The calls can still be
  185. ** made, yet the runtime behavior is such that it will operate as if there
  186. ** no instances of the List control.  This allows intermediate code to access
  187. ** the functions or not without automatically linking in all sorts of stuff
  188. ** into the application that isn't desired.  To change the global proc pointers
  189. ** so that they point to the actual functions, just call CLInitialize() once
  190. ** in the beginning of the application.  If CLInitialize() is referenced, it will
  191. ** get linked in.  In turn, everything that it references directly or indirectly
  192. ** will get linked in. */
  193.  
  194. #pragma segment Controls
  195. void    CLInitialize(void)
  196. {
  197.     if (gclActivate != CLActivate) {
  198.         gclActivate       = CLActivate;
  199.         gclClick          = CLClick;
  200.         gclCtlHit         = CLCtlHit;
  201.         gclFindActive     = CLFindActive;
  202.         gclKey            = CLKey;
  203.         gclNext           = CLNext;
  204.         gclViewFromList   = CLViewFromList;
  205.         gclWindActivate   = CLWindActivate;
  206.     }
  207. }
  208.  
  209.  
  210.  
  211. /*****************************************************************************/
  212.  
  213.  
  214.  
  215. /* Activate this List record.  Activation is not done by calling LActivate().
  216. ** The active control is indicated by the 2-pixel thick border around the
  217. ** List control.  This allows all List controls in a window to display which
  218. ** cells are selected.  This behavior can be overridden by calling LActivate()
  219. ** on the List record for List controls.
  220. ** Human interface dictates that only at most a single List control has this
  221. ** active border.  For this reason, this function scans for other List
  222. ** controls in the window and removes the border from any other that it finds. */
  223.  
  224. #pragma segment Controls
  225. void    CLActivate(Boolean active, ListHandle listHndl)
  226. {
  227.     WindowPtr        window, oldPort;
  228.     ControlHandle    viewCtl;
  229.     short            oldDisplay, newDisplay;
  230.     ListHandle        list;
  231.     CLDataHndl        listData;
  232.  
  233.     if (listHndl) {
  234.         window = (WindowPtr)(*listHndl)->port;
  235.         for (viewCtl = nil;;) {
  236.             viewCtl = CLNext(window, &list, viewCtl, 1, false);
  237.             if (!viewCtl) break;
  238.             listData   = (CLDataHndl)(*viewCtl)->contrlData;
  239.             oldDisplay = (*listData)->mode;
  240.             newDisplay = (oldDisplay & (0xFFFF - clActive));
  241.             if (active)
  242.                 if (list == listHndl)
  243.                     newDisplay |= clActive;
  244.             if (oldDisplay != newDisplay) {
  245.                 (*listData)->mode = newDisplay;
  246.                 GetPort(&oldPort);
  247.                 SetPort(window);
  248.                 CLBorderDraw(list);
  249.                 SetPort(oldPort);
  250.             }
  251.         }
  252.     }
  253. }
  254.  
  255.  
  256.  
  257. static void    dummyCLActivate(Boolean active, ListHandle listHndl)
  258. {
  259. #pragma unused (active, listHndl)
  260. }
  261.  
  262.  
  263.  
  264. /*****************************************************************************/
  265.  
  266.  
  267.  
  268. #pragma segment Controls
  269. static void    CLBorderDraw(ListHandle listHndl)
  270. {
  271.     ControlHandle    viewCtl;
  272.     WindowPtr        oldPort, listPort;
  273.     short            displayInfo;
  274.     Rect            rct;
  275.     PenState        oldPen;
  276.     CLDataHndl        listData;
  277.  
  278.     if (listHndl) {
  279.         if (viewCtl = CLViewFromList(listHndl)) {
  280.             GetPort(&oldPort);
  281.             SetPort(listPort = (*listHndl)->port);
  282.             GetPenState(&oldPen);
  283.             PenNormal();
  284.             listData    = (CLDataHndl)(*viewCtl)->contrlData;
  285.             displayInfo = (*listData)->mode;
  286.             rct = (*listHndl)->rView;
  287.             InsetRect(&rct, -1, -1);
  288.             FrameRect(&rct);
  289.             if (displayInfo & clShowActive) {
  290.                 rct = (*listHndl)->rView;
  291.                 InsetRect(&rct, -4, -4);
  292.                 if ((*listHndl)->vScroll)
  293.                     rct.right  += 15;
  294.                 if ((*listHndl)->hScroll)
  295.                     rct.bottom += 15;
  296.                 PenSize(2, 2);
  297.                 if ((!((WindowPeek)listPort)->hilited) || (!(displayInfo & clActive)))
  298.                     PenPat((ConstPatternParam)&qd.white);
  299.                 FrameRect(&rct);
  300.             }
  301.             SetPenState(&oldPen);
  302.             SetPort(oldPort);
  303.         }
  304.     }
  305. }
  306.  
  307.  
  308.  
  309. /*****************************************************************************/
  310.  
  311.  
  312.  
  313. /* This is called when a mouseDown occurs in the content of a window.  It
  314. ** returns true if the mouseDown caused a List action to occur.  Events
  315. ** that are handled include if the user clicks on a scrollbar that is
  316. ** associated with a List control. */
  317.  
  318. #pragma segment Controls
  319. Boolean    CLClick(WindowPtr window, EventRecord *event, short *action)
  320. {
  321.     WindowPtr        oldPort;
  322.     Point            mouseLoc;
  323.     ListHandle        list;
  324.     ControlHandle    ctlHit, viewCtl;
  325.  
  326.     if (action)
  327.         *action = 0;
  328.     gLastKeyTime = 0;
  329.  
  330.     GetPort(&oldPort);
  331.     if (!((WindowPeek)window)->hilited) return(false);
  332.  
  333.     SetPort(window);
  334.     mouseLoc = event->where;
  335.     GlobalToLocal(&mouseLoc);
  336.  
  337.     if (!(viewCtl = CLFindCtl(window, event, &list, &ctlHit))) return(false);
  338.  
  339.     if (!list) {
  340.         SetPort(oldPort);
  341.         return(false);
  342.     }        /* Didn't hit list control or related scrollbar.  No action taken. */
  343.  
  344.     if (CLFindActive(window) != list) {        /* If not active list control, activate it.       */
  345.         CLActivate(true, list);                /* Now is the active list control.               */
  346.         if (action)                            /* CLClick can be called again if the control  */
  347.             *action = -1;                    /* activates and operates with the same click. */
  348.     }
  349.     else {
  350.         UseControlStyle(viewCtl);
  351.         if (LClick(mouseLoc, event->modifiers, list))
  352.             if (action)
  353.                 *action = 1;        /* If double-click, then return that it was. */
  354.         UseControlStyle(nil);
  355.     }
  356.  
  357.     SetPort(oldPort);
  358.     return(true);
  359. }
  360.  
  361.  
  362.  
  363. static Boolean    dummyCLClick(WindowPtr window, EventRecord *event, short *action)
  364. {
  365. #pragma unused (window, event)
  366.  
  367.     if (action)
  368.         *action = 0;
  369.     return(false);
  370. }
  371.  
  372.  
  373.  
  374. /*****************************************************************************/
  375.  
  376.  
  377.  
  378. #pragma segment Controls
  379. static pascal long    CLCtl(short varCode, ControlHandle ctl, short msg, long parm)
  380. {
  381. #pragma unused (varCode)
  382.  
  383.     Rect            viewRct;
  384.     ListHandle        list;
  385.     WindowPtr        curPort, ww;
  386.     ControlHandle    vScroll, hScroll;
  387.  
  388.     if (list = (ListHandle)GetCRefCon(ctl))
  389.         viewRct = (*list)->rView;
  390.     else
  391.         SetRect(&viewRct, 0, 0, 0, 0);
  392.  
  393.     switch (msg) {
  394.         case drawCntl:
  395.             GetPort(&curPort);
  396.             if (vScroll = (*list)->vScroll) {
  397.                 ww = (*vScroll)->contrlOwner;
  398.                 if (!((WindowPeek)ww)->hilited) (*list)->vScroll = nil;
  399.             }
  400.             if (hScroll = (*list)->hScroll) {
  401.                 ww = (*hScroll)->contrlOwner;
  402.                 if (!((WindowPeek)ww)->hilited) (*list)->hScroll = nil;
  403.             }
  404.             CLUpdate(curPort->visRgn, list);
  405.             (*list)->vScroll = vScroll;
  406.             (*list)->hScroll = hScroll;
  407.             CLBorderDraw(list);
  408.             break;
  409.  
  410.         case testCntl:
  411.             if (PtInRect(*(Point *)&parm, &viewRct)) {
  412.                 gFoundViewCtl = ctl;
  413.                 gFoundLHndl   = list;
  414.                 return(1);
  415.             }
  416.             return(0);
  417.             break;
  418.  
  419.         case calcCRgns:
  420.         case calcCntlRgn:
  421.             if (msg == calcCRgns)
  422.                 parm &= 0x00FFFFFF;
  423.             RectRgn((RgnHandle)parm, &viewRct);
  424.             break;
  425.  
  426.         case initCntl:
  427.             break;
  428.  
  429.         case dispCntl:
  430.             if (list) {
  431.                 LDispose(list);
  432.                 DisposeHandle((Handle)(*ctl)->contrlData);
  433.             }
  434.             break;
  435.  
  436.         case posCntl:
  437.             break;
  438.  
  439.         case thumbCntl:
  440.             break;
  441.  
  442.         case dragCntl:
  443.             break;
  444.  
  445.         case autoTrack:
  446.             break;
  447.     }
  448.  
  449.     return(0);
  450. }
  451.  
  452.  
  453.  
  454. /*****************************************************************************/
  455.  
  456.  
  457.  
  458. /* The List control that was hit by calling FindControl is saved in a
  459. ** global variable, since the CDEF has no way of returning what kind it was.
  460. ** To determine that it was a List control that was hit, first call this
  461. ** function.  The first call returns the old value in the global variable,
  462. ** plus it resets the global to nil.  Then call FindControl(), and then
  463. ** call this function again.  If it returns nil, then a List control
  464. ** wasn't hit.  If it returns non-nil, then it was a List control that
  465. ** was hit, and specifically the one returned. */
  466.  
  467. #pragma segment Controls
  468. ControlHandle    CLCtlHit(void)
  469. {
  470.     ControlHandle    ctl;
  471.  
  472.     ctl = gFoundViewCtl;
  473.     gFoundViewCtl = nil;
  474.     return(ctl);
  475. }
  476.  
  477.  
  478.  
  479. static ControlHandle    dummyCLCtlHit(void)
  480. {
  481.     return(nil);
  482. }
  483.  
  484.  
  485.  
  486. /*****************************************************************************/
  487.  
  488.  
  489.  
  490. /* Handle the event if it applies to the active List control.  If some
  491. ** action occured due to the event, return true. */
  492.  
  493. #pragma segment Controls
  494. Boolean    CLEvent(WindowPtr window, EventRecord *event, short *action)
  495. {
  496.     WindowPtr    clickWindow;
  497.     short        actn;
  498.  
  499.     if (action)
  500.         *action = 0;
  501.  
  502.     switch(event->what) {
  503.  
  504.         case mouseDown:
  505.             if (FindWindow(event->where, &clickWindow) == inContent)
  506.                 if (window == clickWindow)
  507.                     if (((WindowPeek)window)->hilited) return(CLClick(window, event, action));
  508.             break;
  509.  
  510.         case autoKey:
  511.         case keyDown:
  512.             if (!(event->modifiers & cmdKey)) {
  513.                 actn = CLKey(window, event);
  514.                 if (action)
  515.                     *action = actn;
  516.                 if (actn) return(true);
  517.             }
  518.             break;
  519.     }
  520.  
  521.     return(false);
  522. }
  523.  
  524.  
  525.  
  526. /*****************************************************************************/
  527.  
  528.  
  529.  
  530. /* Returns the active List control, if any.  Unlike the TextEdit control, passing
  531. ** in nil doesn't return the currently active control independent of window.  The
  532. ** only reason that the TextEdit control returns the "globally active" control is
  533. ** so that the TEIdle procedure can do its thing.  The List control doesn't have
  534. ** such a thing, so there is no purpose for a "globally active" control.  If the
  535. ** window pointer passed in is nil (requesting the "globally active" List control),
  536. ** we just return nil, indicating that there isn't one. */
  537.  
  538. #pragma segment Controls
  539. ListHandle    CLFindActive(WindowPtr window)
  540. {
  541.     ControlHandle    viewCtl;
  542.     ListHandle        list;
  543.     short            display;
  544.     CLDataHndl        listData;
  545.  
  546.     if (!window) return(nil);
  547.  
  548.     for (viewCtl = nil;;) {
  549.         viewCtl = CLNext(window, &list, viewCtl, 1, true);
  550.         if (!viewCtl) break;
  551.         listData = (CLDataHndl)(*viewCtl)->contrlData;
  552.         display  = (*listData)->mode;
  553.         if (display & clActive) break;
  554.     }
  555.     return(list);
  556. }
  557.  
  558.  
  559.  
  560. static ListHandle    dummyCLFindActive(WindowPtr window)
  561. {
  562. #pragma unused (window)
  563.     return(nil);
  564. }
  565.  
  566.  
  567.  
  568. /*****************************************************************************/
  569.  
  570.  
  571.  
  572. /* This determines if a List control was clicked on directly.  This does
  573. ** not determine if a related scrollbar was clicked on.  If a List
  574. ** control was clicked on, then true is returned, as well as the List
  575. ** handle and the handle to the view control. */
  576.  
  577. #pragma segment Controls
  578. ControlHandle    CLFindCtl(WindowPtr window, EventRecord *event, ListHandle *listHndl, ControlHandle *ctlHit)
  579. {
  580.     WindowPtr        oldPort;
  581.     Point            mouseLoc;
  582.     ControlHandle    ctl, listctl;
  583.     ListHandle        list;
  584.  
  585.     if (window) {
  586.         GetPort(&oldPort);
  587.         SetPort(window);
  588.         mouseLoc = event->where;
  589.         GlobalToLocal(&mouseLoc);
  590.         SetPort(oldPort);
  591.  
  592.         gFoundLHndl = nil;
  593.  
  594.         if (!WhichControl(mouseLoc, 0, window, &ctl)) return(nil);
  595.             /* Didn't hit a thing, so forget it. */
  596.  
  597.         if (list = CLFromScroll(ctl, &listctl)) {
  598.             if (ctlHit)
  599.                 *ctlHit = ctl;
  600.             if ((*listctl)->contrlHilite == 255) return(nil);
  601.             if (listHndl)
  602.                 *listHndl = list;
  603.             return(listctl);
  604.         }
  605.  
  606.         FindControl(mouseLoc, window, &ctl);
  607.         if (*(*ctl)->contrlDefProc != *(Handle)gCDEF) return(nil);
  608.             /* Control hit was above List control, so we didn't hit a List control. */
  609.         if (ctlHit)
  610.             *ctlHit = ctl;
  611.         if (listHndl)
  612.             *listHndl = gFoundLHndl;
  613.         if (gFoundLHndl) return(ctl);
  614.     }
  615.  
  616.     if (listHndl)
  617.         *listHndl = nil;
  618.     if (ctlHit)
  619.         *ctlHit = nil;
  620.     return(nil);
  621. }
  622.  
  623.  
  624.  
  625. /*****************************************************************************/
  626.  
  627.  
  628.  
  629. /* Find the List record that is related to the indicated scrollbar. */
  630.  
  631. #pragma segment Controls
  632. ListHandle    CLFromScroll(ControlHandle scrollCtl, ControlHandle *retCtl)
  633. {
  634.     WindowPtr        window;
  635.     ControlHandle    viewCtl;
  636.     ListHandle        list;
  637.  
  638.     *retCtl = nil;
  639.     if (!IsScrollBar(scrollCtl)) return(nil);
  640.  
  641.     window = (*scrollCtl)->contrlOwner;
  642.  
  643.     for (*retCtl = viewCtl = nil;;) {
  644.         viewCtl = CLNext(window, &list, viewCtl, 1, false);
  645.         if (!viewCtl) return(nil);
  646.         list = (ListHandle)GetCRefCon(viewCtl);
  647.         if (
  648.             ((*list)->vScroll == scrollCtl) || 
  649.             ((*list)->hScroll == scrollCtl)
  650.         ) {
  651.             *retCtl = viewCtl;
  652.             return(list);
  653.         }
  654.     }
  655. }
  656.  
  657.  
  658.  
  659. /*****************************************************************************/
  660.  
  661.  
  662.  
  663. #pragma segment Controls
  664. ListHandle    CLGetList(WindowPtr window, short lnum)
  665. {
  666.     ControlHandle    ctl;
  667.     ListHandle        list;
  668.  
  669.     for (ctl = nil; lnum--; ctl = CLNext(window, &list, ctl, 1, false));
  670.     return(list);
  671. }
  672.  
  673.  
  674.  
  675. /*****************************************************************************/
  676.  
  677.  
  678.  
  679. /* Insert a cell alphabetically into the list.  Whichever parameter is passed in
  680. ** as -1, either row or column, that is the dimension that is determined. */
  681.  
  682. #pragma segment Controls
  683. short    CLInsert(ListHandle listHndl, char *data, short dataLen, short row, short col)
  684. {
  685.     short    loc;
  686.     Point    cell;
  687.  
  688.     if (!listHndl) return(-1);
  689.  
  690.     loc = CLRowOrColSearch(listHndl, data, dataLen, row, col);
  691.  
  692.     if (row == -1) {
  693.         LAddRow(1, cell.v = loc, listHndl);
  694.         cell.h = col;
  695.     }
  696.     else {
  697.         LAddColumn(1, cell.h = loc, listHndl);
  698.         cell.v = row;
  699.     }
  700.  
  701.     LSetCell(data, dataLen, cell, listHndl);
  702.     return(loc);
  703. }
  704.  
  705.  
  706.  
  707. /*****************************************************************************/
  708.  
  709.  
  710.  
  711. /* See if the keypress event applies to the List control, and if it does,
  712. ** handle it and return true. */
  713.  
  714. #pragma segment Controls
  715. Boolean    CLKey(WindowPtr window, EventRecord *event)
  716. {
  717.     ListHandle        list;
  718.     ControlHandle    listCtl;
  719.     short            key, mode;
  720.     Point            cell, dcell;
  721.     Rect            bnds, visCells;
  722.     CLDataHndl        listData;
  723.  
  724.     if (list = CLFindActive(window)) {
  725.  
  726.         listCtl  = CLViewFromList(list);
  727.         listData = (CLDataHndl)(*listCtl)->contrlData;
  728.         mode     = (*listData)->mode;
  729.         if (!(mode & clKeyPos)) return(false);
  730.  
  731.         bnds = (*list)->dataBounds;
  732.         if (bnds.top == bnds.bottom) return(true);
  733.         if (bnds.left == bnds.right) return(true);
  734.             /* The list is empty, so whatever was typed has been "handled". */
  735.  
  736.         cell.h = bnds.left;
  737.         cell.v = bnds.top;
  738.         key = event->message & charCodeMask;
  739.  
  740.         if ((key >= chLeft) && (key <= chDown)) {
  741.             if (LGetSelect(true, &cell, list))
  742.                 key -= kPrevSel;
  743.             switch (key) {
  744.                 case chLeft - kPrevSel:
  745.                     if (cell.h > bnds.left)
  746.                         --cell.h;
  747.                     break;
  748.                 case chRight - kPrevSel:
  749.                     if (cell.h < bnds.right - 1)
  750.                         ++cell.h;
  751.                     break;
  752.                 case chUp - kPrevSel:
  753.                     if (cell.v > bnds.top)
  754.                         --cell.v;
  755.                     break;
  756.                 case chDown - kPrevSel:
  757.                     if (cell.v < bnds.bottom - 1)
  758.                         ++cell.v;
  759.                     break;
  760.                 case chLeft:
  761.                     if (bnds.top < bnds.bottom - 1) return(true);
  762.                         /* With no previous selection, if the list has
  763.                         ** more than one row, we don't know which to use.
  764.                         ** Selection is indeterminate, so do nothing. */
  765.                     cell.v = bnds.top;
  766.                     cell.h = bnds.right - 1;
  767.                     break;
  768.                 case chRight:
  769.                     if (bnds.top < bnds.bottom - 1) return(true);
  770.                         /* With no previous selection, if the list has
  771.                         ** more than one row, we don't know which to use.
  772.                         ** Selection is indeterminate, so do nothing. */
  773.                     cell.v = bnds.top;
  774.                     cell.h = bnds.left;
  775.                     break;
  776.                 case chUp:
  777.                     if (bnds.left < bnds.right - 1) return(true);
  778.                         /* With no previous selection, if the list has
  779.                         ** more than one row, we don't know which to use.
  780.                         ** Selection is indeterminate, so do nothing. */
  781.                     cell.h = bnds.left;
  782.                     cell.v = bnds.bottom - 1;
  783.                     break;
  784.                 case chDown:
  785.                     if (bnds.left < bnds.right - 1) return(true);
  786.                         /* With no previous selection, if the list has
  787.                         ** more than one row, we don't know which to use.
  788.                         ** Selection is indeterminate, so do nothing. */
  789.                     cell.h = bnds.left;
  790.                     cell.v = bnds.top;
  791.                     break;
  792.             }
  793.         }
  794.         else {
  795.             if ((bnds.right - bnds.left > 1) && (bnds.bottom - bnds.top > 1)) return(true);
  796.             if (gLastKeyTime + 45 < TickCount()) {        /* Reset character collection. */
  797.                 gListPosTextLen = 0;
  798.                 gLastKeyTime = TickCount();
  799.             }
  800.             if (gListPosTextLen < kListPosTextLen)
  801.                 gListPosText[gListPosTextLen++] = key;
  802.             LSearch(gListPosText, gListPosTextLen, MyIntlCompare, &cell, list);
  803.                 /* Find the cell closest to the query test. */
  804.             if (cell.h >= bnds.right)
  805.                 cell.h = bnds.right - 1;
  806.             if (cell.v >= bnds.bottom)
  807.                 cell.v = bnds.bottom - 1;
  808.         }
  809.  
  810.         UseControlStyle(listCtl);
  811.         LSetSelect(true, cell, list);        /* Select cell that is closest. */
  812.         dcell.h = bnds.left;
  813.         dcell.v = bnds.top;
  814.         for (;;) {                /* Deselect old cells. */
  815.             if (!LGetSelect(true, &dcell, list)) break;
  816.             if ((dcell.h == cell.h) && (dcell.v == cell.v)) {
  817.                 if (++dcell.h >= bnds.right) {
  818.                     dcell.h = bnds.left;
  819.                     ++dcell.v;
  820.                 }
  821.             }
  822.             else LSetSelect(false, dcell, list);
  823.         }
  824.         UseControlStyle(nil);
  825.  
  826.         visCells = (*list)->visible;
  827.         if (PtInRect(cell, &visCells)) return(true);        /* Already in view. */
  828.  
  829.         if (
  830.             (key != (chDown - kPrevSel)) || 
  831.             (cell.v < visCells.top) || 
  832.             (cell.h < visCells.left)
  833.         ) {
  834.             UseControlStyle(listCtl);        /* Let List manager scroll into view. */
  835.             LAutoScroll(list);                /* It handles these cases correctly.  */
  836.             UseControlStyle(nil);
  837.             return(true);
  838.         }
  839.  
  840.         UseControlStyle(listCtl);            /* Scroll into view the way we want it done. */
  841.         LScroll(cell.h - --visCells.right, cell.v - --visCells.bottom, list);
  842.         UseControlStyle(nil);
  843.  
  844.         return(true);
  845.     }
  846.  
  847.     return(false);
  848. }
  849.  
  850.  
  851.  
  852. static Boolean    dummyCLKey(WindowPtr window, EventRecord *event)
  853. {
  854. #pragma unused (window, event)
  855.     return(false);
  856. }
  857.  
  858.  
  859.  
  860. /*****************************************************************************/
  861.  
  862.  
  863.  
  864. /* Create a new List control.  See the comments at the beginning of this
  865. ** file for more information.  Note that this function doesn't get a dummy,
  866. ** as you really mean to have this code if you call it.  It calls CLInitialize(),
  867. ** just to make sure that the proc pointers are set to point to the real function,
  868. ** instead of the dummy functions.  By having CLNew() call CLInitialize(), the
  869. ** application won't have to worry about calling CLInitialize().  By the time that
  870. ** the application is using a List control, the proc pointers will be initialized. */
  871.  
  872. #pragma segment Controls
  873. ListHandle    CLNew(short viewID, Boolean vis, Rect *vrct, short numRows, short numCols,
  874.                   short cellHeight, short cellWidth, short theLProc, WindowPtr window, short mode)
  875. {
  876.     WindowPtr        oldPort;
  877.     Rect            viewRct, dataBnds, rct;
  878.     Point            cellSize;
  879.     ListHandle        list;
  880.     Boolean            err;
  881.     ControlHandle    viewCtl;
  882.     Boolean            drawIt, hasGrow;
  883.     short            hScroll, vScroll;
  884.     CLDataHndl        listData;
  885.     ControlHandle    ctl;
  886.  
  887.     CLInitialize();            /* Make sure that this code gets linked in, in case the application
  888.                             ** is using the proc pointers.  CtlHandler.c uses the proc pointers
  889.                             ** so that if the application doesn't use List controls, this code
  890.                             ** won't get linked in. */
  891.     GetPort(&oldPort);
  892.     SetPort(window);
  893.  
  894.     viewRct         = *vrct;
  895.     dataBnds.top    = dataBnds.left = 0;
  896.     dataBnds.right  = numCols;
  897.     dataBnds.bottom = numRows;
  898.  
  899.     cellSize.h = cellWidth;
  900.     cellSize.v = cellHeight;
  901.  
  902.     drawIt  = (mode & clDrawIt)  ? 1 : 0;
  903.     hScroll = (mode & clHScroll) ? 1 : 0;
  904.     vScroll = (mode & clVScroll) ? 1 : 0;
  905.     hasGrow = (mode & clHasGrow) ? 1 : 0;
  906.  
  907.     viewCtl = nil;
  908.     list = LNew(&viewRct, &dataBnds, cellSize, theLProc, window, false, hasGrow, hScroll, vScroll);
  909.  
  910.     err = false;
  911.     if (list) {        /* If we were able to create the List record... */
  912.  
  913.         if ((hasGrow) && (hScroll + vScroll == 1)) {
  914.             if (ctl = (*list)->hScroll) {
  915.                 rct = (*ctl)->contrlRect;
  916.                 if (rct.right >= viewRct.right)
  917.                     SizeControl(ctl, viewRct.right - viewRct.left - 13, rct.bottom - rct.top);
  918.             }
  919.             if (ctl = (*list)->vScroll) {
  920.                 rct = (*ctl)->contrlRect;
  921.                 if (rct.bottom >= viewRct.bottom)
  922.                     SizeControl(ctl, rct.right - rct.left, viewRct.bottom - viewRct.top - 13);
  923.             }
  924.         }
  925.  
  926.         if (!gCDEF) {
  927.             gCDEF = (cdefRsrcJMPHndl)GetResource('CDEF', (viewID / 16));
  928.             if (gCDEF) {
  929.                 (*gCDEF)->jmpAddress = (long)CLCtl;
  930.                 FlushInstructionCache();    /* Make sure that instruction caches don't kill us. */
  931.             }
  932.             else err = true;
  933.         }
  934.  
  935.         if (!err)
  936.             viewCtl = NewControl(window, &viewRct, "\p", false, 0, 0, 0, viewID, (long)list);
  937.                 /* Use our custom view cdef.  It's wierd, but it's small. */
  938.                 /* We have to create the control initially invisible because we haven't */
  939.                 /* initialized all of the data needed by the update procedure.  If it   */
  940.                 /* is created visible, the update procedure will be immediately called, */
  941.                 /* and this would be very bad to do until all of the data is there.     */
  942.  
  943.         mode &= (0xFFFF - clDrawIt);
  944.  
  945.         if (!viewCtl) err = true;
  946.  
  947.         if (!err) {
  948.             (*viewCtl)->contrlData = nil;
  949.             if (listData = (CLDataHndl)NewHandle(sizeof(CLDataRec))) {
  950.                 (*listData)->mode   = mode;
  951.                 (*viewCtl)->contrlData = (Handle)listData;
  952.                 LDoDraw(drawIt, list);
  953.                 if (vis) ShowControl(viewCtl);
  954.                     /* Now that the data is initialized, we can show the control. */
  955.                 if (mode & clActive)
  956.                     CLActivate(true, list);
  957.             }
  958.             else err = true;
  959.         }
  960.     }
  961.     else err = true;
  962.  
  963.     SetPort(oldPort);
  964.  
  965.     if (err) {        /* Oops.  Somebody wasn't happy. */
  966.         if (viewCtl)
  967.             DisposeControl(viewCtl);
  968.                 /* This also disposes of the List handle! */
  969.         else
  970.             if (list)
  971.                 LDispose(list);
  972.                     /* We have to dispose of the List handle ourselves if
  973.                     ** creating the view control failed. */
  974.  
  975.         list = nil;        /* Return that there is no List control. */
  976.     }
  977.  
  978.     return(list);
  979. }
  980.  
  981.  
  982.  
  983. /*****************************************************************************/
  984.  
  985.  
  986.  
  987. /* Get the next List control in the window.  You pass it a control handle
  988. ** for the view control, or nil to start at the beginning of the window.
  989. ** It returns both a List handle and the view control handle for that
  990. ** List record.  If none is found, nil is returned.  This allows you to
  991. ** repeatedly call this function and walk through all the List controls
  992. ** in a window. */
  993.  
  994. #pragma segment Controls
  995. ControlHandle    CLNext(WindowPtr window, ListHandle *listHndl, ControlHandle ctl, short dir, Boolean justActive)
  996. {
  997.     ControlHandle    nextCtl, priorCtl;
  998.  
  999.     if (listHndl)
  1000.         *listHndl = nil;
  1001.  
  1002.     if (!window) return(nil);
  1003.     if (!gCDEF)  return(nil);
  1004.  
  1005.     if (dir > 0) {
  1006.         if (!ctl)
  1007.             ctl = ((WindowPeek)window)->controlList;
  1008.         else
  1009.             ctl = (*ctl)->nextControl;
  1010.         while (ctl) {
  1011.             if ((!justActive) || ((*ctl)->contrlVis)) {
  1012.                 if ((!justActive) || ((*ctl)->contrlHilite != 255)) {
  1013.                     if (*(*ctl)->contrlDefProc == *(Handle)gCDEF) {
  1014.                             /* The handle may be locked, which means that the hi-bit
  1015.                             ** may be on, thus invalidating the compare.  Dereference the
  1016.                             ** handles to get rid of this possibility. */
  1017.                         if (listHndl)
  1018.                             *listHndl = (ListHandle)GetCRefCon(ctl);
  1019.                         return(ctl);
  1020.                     }
  1021.                 }
  1022.             }
  1023.             ctl = (*ctl)->nextControl;
  1024.         }
  1025.         return(ctl);
  1026.     }
  1027.  
  1028.     nextCtl = ((WindowPeek)window)->controlList;
  1029.     for (priorCtl = nil; ;nextCtl = (*nextCtl)->nextControl) {
  1030.         if ((!nextCtl) || (nextCtl == ctl)) {
  1031.             if (priorCtl)
  1032.                 if (listHndl)
  1033.                     *listHndl = (ListHandle)GetCRefCon(priorCtl);
  1034.             return(priorCtl);
  1035.         }
  1036.         if ((!justActive) || ((*nextCtl)->contrlVis)) {
  1037.             if ((!justActive) || ((*nextCtl)->contrlHilite != 255)) {
  1038.                 if (*(*nextCtl)->contrlDefProc == *(Handle)gCDEF)
  1039.                     priorCtl = nextCtl;
  1040.                         /* The handle may be locked, which means that the hi-bit
  1041.                         ** may be on, thus invalidating the compare.  Dereference the
  1042.                         ** handles to get rid of this possibility. */
  1043.             }
  1044.         }
  1045.     }
  1046. }
  1047.  
  1048.  
  1049.  
  1050. static ControlHandle    dummyCLNext(WindowPtr window, ListHandle *listHndl, ControlHandle ctl, short dir, Boolean justActive)
  1051. {
  1052. #pragma unused (window, ctl, dir, justActive)
  1053.     *listHndl = nil;
  1054.     return(nil);
  1055. }
  1056.  
  1057.  
  1058.  
  1059. /*****************************************************************************/
  1060.  
  1061.  
  1062.  
  1063. /* From the starting for or column, print as many cells as will fit into the
  1064. ** designated rect.  Pass in a starting row and column, and they will be
  1065. ** adjusted to indicate the first cell that didn't fit into the rect.  If all
  1066. ** remaining cells were printed, the row is returned as -1.  The bottom of the
  1067. ** rect to print in is also adjusted to indicate where the actual cut-off
  1068. ** point was. */
  1069.  
  1070. #pragma segment Controls
  1071. void    CLPrint(RgnHandle clipRgn, ListHandle listHndl, short *row, short *col,
  1072.                 short leftEdge, Rect *drawRct)
  1073. {
  1074.     Rect        dataBnds, keepView, keepVis;
  1075.     Point        csize;
  1076.     short        h, v;
  1077.     RgnHandle    rgn;
  1078.  
  1079.     if (!listHndl) return;
  1080.  
  1081.     dataBnds = (*listHndl)->dataBounds;
  1082.     if ((*col < dataBnds.left) || (*col >= dataBnds.right))
  1083.         *col = leftEdge;
  1084.     if (*row < dataBnds.top)
  1085.         *row = dataBnds.top;
  1086.     if (*row >= dataBnds.bottom) {
  1087.         *row = -1;
  1088.         return;
  1089.     }
  1090.  
  1091.     keepView = (*listHndl)->rView;
  1092.     csize    = (*listHndl)->cellSize;
  1093.     keepVis  = (*listHndl)->visible;
  1094.  
  1095.     h = (drawRct->right - drawRct->left) / csize.h;
  1096.     if (!h)
  1097.         ++h;
  1098.     v = (drawRct->bottom - drawRct->top) / csize.v;
  1099.     if (!v)
  1100.         ++v;
  1101.  
  1102.     if (*col + h > dataBnds.right)
  1103.         h = dataBnds.right  - *col;
  1104.     if (*row + v > dataBnds.bottom)
  1105.         v = dataBnds.bottom - *row;
  1106.  
  1107.     drawRct->bottom = drawRct->top + v * csize.v;
  1108.  
  1109.     (*listHndl)->rView = *drawRct;
  1110.     (*listHndl)->visible.right  = ((*listHndl)->visible.left = *col) + h;
  1111.     (*listHndl)->visible.bottom = ((*listHndl)->visible.top  = *row) + v;
  1112.  
  1113.     if (!(rgn = clipRgn)) {
  1114.         rgn = NewRgn();
  1115.         RectRgn(rgn, drawRct);
  1116.     }
  1117.     CLUpdate(rgn, listHndl);
  1118.     if (!clipRgn)
  1119.         DisposeRgn(rgn);
  1120.  
  1121.     (*listHndl)->rView   = keepView;
  1122.     (*listHndl)->visible = keepVis;
  1123.  
  1124.     *col += h;
  1125.     if (*col >= dataBnds.right) {
  1126.         *col = leftEdge;
  1127.         *row += v;
  1128.         if (*row >= dataBnds.bottom)
  1129.             *row = -1;
  1130.     }
  1131. }
  1132.  
  1133.  
  1134.  
  1135. /*****************************************************************************/
  1136.  
  1137.  
  1138.  
  1139. /* Find the location in the list where the data would belong if inserted.  The row
  1140. ** and column are passed in.  If either is -1, that is the dimension that will be
  1141. ** determined and returned. */
  1142.  
  1143. #pragma segment Controls
  1144. short    CLRowOrColSearch(ListHandle listHndl, char *data, short dataLen, short row, short col)
  1145. {
  1146.     Rect    dataBnds;
  1147.     short    numCells, baseCell, iter, pow, loc, cdataLen;
  1148.     Point    cell;
  1149.     Str255    cdata;
  1150.  
  1151.     if (!listHndl) return(-1);
  1152.  
  1153.     dataBnds = (*listHndl)->dataBounds;
  1154.     if (row == -1)
  1155.         numCells = dataBnds.bottom - (baseCell = dataBnds.top);
  1156.     else
  1157.         numCells = dataBnds.right  - (baseCell = dataBnds.left);
  1158.             /* Get some reference info on the size/start of the list. */
  1159.  
  1160.     cell.v = cell.h = 0;
  1161.     if (numCells) {
  1162.         if (row != -1)
  1163.             cell.v = row;
  1164.         if (col != -1)
  1165.             cell.h = col;
  1166.         for (pow = 1; pow < numCells; ++iter, pow <<= 1);
  1167.         pow >>= 1;        /* pow = 2^n such that pow < numCells. */
  1168.  
  1169.         for (loc = pow; pow;) {            /* Do binary search for where to insert. */
  1170.             if (loc >= numCells)
  1171.                 loc = numCells - 1;        /* Off the end is bad. */
  1172.             if (row == -1)
  1173.                 cell.v = baseCell + loc;
  1174.             else
  1175.                 cell.h = baseCell + loc;
  1176.             pow >>= 1;
  1177.  
  1178.             cdataLen = 255;
  1179.             LGetCell(cdata, &cdataLen, cell, listHndl);
  1180.                 /* Get cell data to compare against. */
  1181.  
  1182.             loc += (pow * IUMagString(data, cdata, dataLen, cdataLen));
  1183.                 /* Adjust location based on compare result. */
  1184.         }
  1185.  
  1186.         /* The binary search got us close, but not exact.  We may be off by one
  1187.         ** in either direction.  (The binary search can't position in front of
  1188.         ** the first cell in the list, for example.)  Do a linear compare from
  1189.         ** this point to find the correct cell we should insert in front of. */
  1190.  
  1191.         if (loc) --loc;        /* Start linear search one back. */
  1192.         for (;; ++loc) {
  1193.             if (row == -1)
  1194.                 cell.v = baseCell + loc;
  1195.             else
  1196.                 cell.h = baseCell + loc;
  1197.             if (loc >= numCells) break;
  1198.             cdataLen = 255;
  1199.             LGetCell(cdata, &cdataLen, cell, listHndl);
  1200.             if (IUMagString(data, cdata, dataLen, cdataLen) < 1) break;
  1201.                 /* If we are less than or equal to this cell, we have
  1202.                 ** found our insertion point, so break. */
  1203.         }
  1204.     }
  1205.  
  1206.     if (row == -1) return(cell.v);
  1207.     else           return(cell.h);
  1208. }
  1209.  
  1210.  
  1211.  
  1212. /*****************************************************************************/
  1213.  
  1214.  
  1215.  
  1216. /* Draw the List control in the correct form. */
  1217.  
  1218. #pragma segment Controls
  1219. void    CLUpdate(RgnHandle clipRgn, ListHandle listHndl)
  1220. {
  1221.     WindowPtr        curPort, listPort;
  1222.     ControlHandle    ctl;
  1223.     Rect            view, vis, bnds, r;
  1224.     RgnHandle        rgn1, rgn2;
  1225.  
  1226.     if (listHndl) {
  1227.  
  1228.         if (ctl = CLViewFromList(listHndl)) {
  1229.     
  1230.             GetPort(&curPort);
  1231.  
  1232.             listPort = (*listHndl)->port;
  1233.             (*listHndl)->port = curPort;
  1234.             LUpdate(clipRgn, listHndl);
  1235.             (*listHndl)->port = listPort;
  1236.  
  1237.             view = (*listHndl)->rView;
  1238.             vis  = (*listHndl)->visible;
  1239.             bnds = (*listHndl)->dataBounds;
  1240.             SectRect(&vis, &bnds, &vis);
  1241.  
  1242.             r = view;
  1243.             r.right  = r.left + (vis.right  - vis.left) * (*listHndl)->cellSize.h;
  1244.             r.bottom = r.top  + (vis.bottom - vis.top ) * (*listHndl)->cellSize.v;
  1245.             SectRect(&r, &view, &r);
  1246.  
  1247.             RectRgn(rgn1 = NewRgn(), &view);
  1248.             RectRgn(rgn2 = NewRgn(), &r);
  1249.             DiffRgn(rgn1, rgn2, rgn1);
  1250.             EraseRgn(rgn1);
  1251.             DisposeRgn(rgn1);
  1252.             DisposeRgn(rgn2);
  1253.         }
  1254.     }
  1255. }
  1256.  
  1257.  
  1258.  
  1259. /*****************************************************************************/
  1260.  
  1261.  
  1262.  
  1263. /* Return the control handle for the view control that owns the List
  1264. ** record.  Use this to find the view to do customizations such as changing
  1265. ** the update procedure for this List control. */
  1266.  
  1267. #pragma segment Controls
  1268. ControlHandle    CLViewFromList(ListHandle listHndl)
  1269. {
  1270.     WindowPtr        window;
  1271.     ControlHandle    viewCtl;
  1272.     ListHandle        list;
  1273.  
  1274.     if (!listHndl) return(nil);
  1275.  
  1276.     window = (WindowPtr)(*listHndl)->port;
  1277.  
  1278.     for (viewCtl = nil;;) {
  1279.         viewCtl = CLNext(window, &list, viewCtl, 1, false);
  1280.         if ((!viewCtl) || (list == listHndl)) return(viewCtl);
  1281.     }
  1282. }
  1283.  
  1284.  
  1285.  
  1286. static ControlHandle    dummyCLViewFromList(ListHandle listHndl)
  1287. {
  1288. #pragma unused (listHndl)
  1289.     return(nil);
  1290. }
  1291.  
  1292.  
  1293.  
  1294. /*****************************************************************************/
  1295.  
  1296.  
  1297.  
  1298. /* This window is becoming active or inactive.  The borders of the List
  1299. ** controls need to be redrawn due to this.  For each List control in the
  1300. ** window, redraw the active border. */
  1301.  
  1302. #pragma segment Controls
  1303. ListHandle    CLWindActivate(WindowPtr window, Boolean displayIt)
  1304. {
  1305.     ListHandle    list;
  1306.  
  1307.     gLastKeyTime = 0;        /* Restart the entry collection for Lists. */
  1308.  
  1309.     if (!window) return(nil);
  1310.  
  1311.     if (list = CLFindActive(window)) {
  1312.         if (displayIt)
  1313.             CLBorderDraw(list);
  1314.         return(list);
  1315.     }
  1316.  
  1317.     return(nil);
  1318. }
  1319.  
  1320.  
  1321.  
  1322. static ListHandle    dummyCLWindActivate(WindowPtr window, Boolean displayIt)
  1323. {
  1324. #pragma unused (window, displayIt)
  1325.  
  1326.     return(nil);
  1327. }
  1328.  
  1329.  
  1330.  
  1331. /*****************************************************************************/
  1332.  
  1333.  
  1334.  
  1335. #pragma segment Controls
  1336. pascal short MyIntlCompare(Ptr aPtr, Ptr bPtr, short aLen, short bLen)
  1337. {
  1338.     short    cmp;
  1339.  
  1340.     cmp = IUMagString(aPtr, bPtr, aLen, bLen);
  1341.     if (cmp == -1) return(1);
  1342.     else           return(0);
  1343. }
  1344.  
  1345.  
  1346.  
  1347. /*****************************************************************************/
  1348.  
  1349.  
  1350.  
  1351. #pragma segment Controls
  1352. void    CLSize(ListHandle list, short newH, short newV)
  1353. {
  1354. #pragma unused (oldh, oldv)
  1355.  
  1356.     WindowPtr        oldPort;
  1357.     ControlHandle    viewCtl, ctl;
  1358.     Rect            viewRct, rct;
  1359.     RgnHandle        oldClip, newClip;
  1360.     CLDataHndl        listData;
  1361.     short            mode, hScroll, vScroll;
  1362.  
  1363.     if (!(viewCtl = CLViewFromList(list))) return;
  1364.  
  1365.     GetPort(&oldPort);
  1366.     SetPort((*list)->port);
  1367.  
  1368.     viewRct  = (*viewCtl)->contrlRect;
  1369.     listData = (CLDataHndl)(*viewCtl)->contrlData;
  1370.     mode     = (*listData)->mode;
  1371.  
  1372.     GetClip(oldClip = NewRgn());
  1373.     SetClip(newClip = NewRgn());
  1374.         /* Prevent any drawing, since the newly resized scrollbars may not account for
  1375.         ** the growIcon area.  We don't want them temporarily redrawing over the
  1376.         ** growIcon. */
  1377.  
  1378.     LSize(newH, newV, list);
  1379.  
  1380.     hScroll = (mode & clHScroll) ? 1 : 0;
  1381.     vScroll = (mode & clVScroll) ? 1 : 0;
  1382.         /* Get enough info to determine if we need to fix the scrollbar sizes. */
  1383.  
  1384.     viewRct.right  = viewRct.left + newH;
  1385.     viewRct.bottom = viewRct.top  + newV;
  1386.     (*viewCtl)->contrlRect = viewRct;
  1387.  
  1388.     if ((mode & clHasGrow) && (hScroll + vScroll == 1)) {
  1389.         if (ctl = (*list)->hScroll) {
  1390.             rct = (*ctl)->contrlRect;
  1391.             if (rct.right >= viewRct.right)
  1392.                 SizeControl(ctl, viewRct.right - viewRct.left - 13, rct.bottom - rct.top);
  1393.         }
  1394.         if (ctl = (*list)->vScroll) {
  1395.             rct = (*ctl)->contrlRect;
  1396.             if (rct.bottom >= viewRct.bottom)
  1397.                 SizeControl(ctl, rct.right - rct.left, viewRct.bottom - viewRct.top - 13);
  1398.         }
  1399.     }
  1400.  
  1401.     SetClip(oldClip);
  1402.     DisposeRgn(oldClip);
  1403.     DisposeRgn(newClip);
  1404.         /* Allow drawing again so we can redisplay the newly resized list control and scrollbars. */
  1405.  
  1406.     InsetRect(&viewRct, -1, -1);        /* Erase all of the old list control and scrollbars. */
  1407.     if (vScroll)
  1408.         viewRct.right += 15;
  1409.     if (hScroll)
  1410.         viewRct.bottom += 15;
  1411.     if (mode & clShowActive)
  1412.         InsetRect(&viewRct, -4, -4);
  1413.     EraseRect(&viewRct);
  1414.  
  1415.     Draw1Control(viewCtl);
  1416.     SetPort(oldPort);
  1417. }
  1418.  
  1419.  
  1420.  
  1421. /*****************************************************************************/
  1422.  
  1423.  
  1424.  
  1425. #pragma segment Controls
  1426. void    CLMove(ListHandle list, short newH, short newV)
  1427. {
  1428. #pragma unused (oldh, oldv)
  1429.  
  1430.     WindowPtr        oldPort;
  1431.     ControlHandle    viewCtl, ctl;
  1432.     Rect            viewRct, rct;
  1433.     RgnHandle        oldClip, newClip;
  1434.     CLDataHndl        listData;
  1435.     short            mode, hScroll, vScroll, dx, dy;
  1436.  
  1437.     if (!(viewCtl = CLViewFromList(list))) return;
  1438.  
  1439.     GetPort(&oldPort);
  1440.     SetPort((*list)->port);
  1441.  
  1442.     viewRct  = (*viewCtl)->contrlRect;
  1443.     listData = (CLDataHndl)(*viewCtl)->contrlData;
  1444.     mode     = (*listData)->mode;
  1445.  
  1446.     dx = newH - viewRct.left;
  1447.     dy = newV - viewRct.top;
  1448.     if ((!dx) && (!dy)) return;
  1449.  
  1450.     hScroll = (mode & clHScroll) ? 1 : 0;
  1451.     vScroll = (mode & clVScroll) ? 1 : 0;
  1452.         /* Get enough info to determine if we need to fix the scrollbar sizes. */
  1453.  
  1454.     rct = viewRct;                /* Erase all of the old list control and scrollbars. */
  1455.     InsetRect(&rct, -1, -1);
  1456.     if (vScroll)
  1457.         rct.right += 15;
  1458.     if (hScroll)
  1459.         rct.bottom += 15;
  1460.     if (mode & clShowActive)
  1461.         InsetRect(&rct, -4, -4);
  1462.     EraseRect(&rct);
  1463.  
  1464.     OffsetRect(&viewRct, dx, dy);
  1465.     (*viewCtl)->contrlRect = viewRct;
  1466.     (*list)->rView = viewRct;
  1467.  
  1468.     GetClip(oldClip = NewRgn());
  1469.     SetClip(newClip = NewRgn());
  1470.  
  1471.     if (ctl = (*list)->hScroll) {
  1472.         rct = (*ctl)->contrlRect;
  1473.         MoveControl(ctl, rct.left + dx, rct.top + dy);
  1474.     }
  1475.  
  1476.     if (ctl = (*list)->vScroll) {
  1477.         rct = (*ctl)->contrlRect;
  1478.         MoveControl(ctl, rct.left + dx, rct.top + dy);
  1479.     }
  1480.  
  1481.     SetClip(oldClip);
  1482.     DisposeRgn(oldClip);
  1483.     DisposeRgn(newClip);
  1484.  
  1485.     Draw1Control(viewCtl);
  1486.     SetPort(oldPort);
  1487. }
  1488.  
  1489.  
  1490.  
  1491.