home *** CD-ROM | disk | FTP | other *** search
/ MacFormat 1995 March / macformat-022.iso / Shareware City / Developers / src / out-of-phase-102-c / OutOfPhase 1.02 Source / OutOfPhase Folder / Level 1 Extensions 29Sep94 / StringList.c < prev    next >
Encoding:
C/C++ Source or Header  |  1994-11-23  |  24.0 KB  |  916 lines  |  [TEXT/KAHL]

  1. /* StringList.c */
  2. /*****************************************************************************/
  3. /*                                                                           */
  4. /*    System Dependency Library for Building Portable Software               */
  5. /*    Macintosh Version                                                      */
  6. /*    Written by Thomas R. Lawrence, 1993 - 1994.                            */
  7. /*                                                                           */
  8. /*    This file is Public Domain; it may be used for any purpose whatsoever  */
  9. /*    without restriction.                                                   */
  10. /*                                                                           */
  11. /*    This package is distributed in the hope that it will be useful,        */
  12. /*    but WITHOUT ANY WARRANTY; without even the implied warranty of         */
  13. /*    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.                   */
  14. /*                                                                           */
  15. /*    Thomas R. Lawrence can be reached at tomlaw@world.std.com.             */
  16. /*                                                                           */
  17. /*****************************************************************************/
  18.  
  19. #include "MiscInfo.h"
  20. #include "Audit.h"
  21. #include "Debug.h"
  22. #include "Definitions.h"
  23.  
  24. #include "StringList.h"
  25. #include "Memory.h"
  26. #include "DataMunging.h"
  27. #include "Scroll.h"
  28. #include "Array.h"
  29.  
  30.  
  31. #define BorderInset (1)
  32. #define TextInset (3)
  33.  
  34.  
  35. typedef struct ElementRec
  36.     {
  37.         char*                            Name;
  38.         void*                            Reference;
  39.         MyBoolean                    Selected;
  40.     } ElementRec;
  41.  
  42. struct StringListRec
  43.     {
  44.         WinType*                    Window;
  45.         OrdType                        X;
  46.         OrdType                        Y;
  47.         OrdType                        Width;
  48.         OrdType                        Height;
  49.         FontType                    Font;
  50.         FontSizeType            FontSize;
  51.         OrdType                        LineHeight;
  52.         ArrayRec*                    ItemList;
  53.         long                            TopElement;
  54.         ScrollRec*                Scrollbar;
  55.         MyBoolean                    AllowMultipleSelection;
  56.         char*                            Title;
  57.         double                        LastMouseDownTime;
  58.         OrdType                        LastMouseXLoc;
  59.         OrdType                        LastMouseYLoc;
  60.     };
  61.  
  62.  
  63. static void                StringListScrollHook(long Parameter, ScrollType How,
  64.                                         StringListRec* ScrollTemp);
  65.  
  66. static void                RecalibrateScrollBar(StringListRec* List);
  67.  
  68.  
  69. /* allocate a new, empty string list.  Title is null terminated */
  70. StringListRec*        NewStringList(WinType* Window, OrdType X, OrdType Y,
  71.                                         OrdType Width, OrdType Height, FontType Font, FontSizeType FontSize,
  72.                                         MyBoolean AllowMultipleSelection, char* Title)
  73.     {
  74.         StringListRec*    List;
  75.  
  76.         List = (StringListRec*)AllocPtrCanFail(sizeof(StringListRec),"StringListRec");
  77.         if (List == NIL)
  78.             {
  79.                 return NIL;
  80.             }
  81.         List->Window = Window;
  82.         List->X = X;
  83.         List->Y = Y;
  84.         List->Width = Width;
  85.         List->Height = Height;
  86.         List->Font = Font;
  87.         List->FontSize = FontSize;
  88.         List->LineHeight = GetFontHeight(Font,FontSize);
  89.         List->ItemList = NewArray();
  90.         if (List->ItemList == NIL)
  91.             {
  92.                 ReleasePtr((char*)List);
  93.                 return NIL;
  94.             }
  95.         List->TopElement = 0;
  96.         if (Title == NIL)
  97.             {
  98.                 List->Scrollbar = NewScrollBar(Window,eVScrollBar,X + Width - 16,Y,Height);
  99.             }
  100.          else
  101.             {
  102.                 List->Scrollbar = NewScrollBar(Window,eVScrollBar,X + Width - 16,
  103.                     Y + List->LineHeight,Height - List->LineHeight);
  104.             }
  105.         if (List->Scrollbar == NIL)
  106.             {
  107.                 DisposeArray(List->ItemList);
  108.                 ReleasePtr((char*)List);
  109.                 return NIL;
  110.             }
  111.         List->AllowMultipleSelection = AllowMultipleSelection;
  112.         if (Title != NIL)
  113.             {
  114.                 /* an error here will only make the display look weird */
  115.                 List->Title = StringToBlockCopy(Title);
  116.             }
  117.          else
  118.             {
  119.                 List->Title = NIL;
  120.             }
  121.         List->LastMouseDownTime = 0;
  122.         RecalibrateScrollBar(List);
  123.         return List;
  124.     }
  125.  
  126.  
  127. /* dispose the string list and all of the items in it */
  128. void                            DisposeStringList(StringListRec* List)
  129.     {
  130.         CheckPtrExistence(List);
  131.         while (ArrayGetLength(List->ItemList) > 0)
  132.             {
  133.                 ElementRec*        Element;
  134.  
  135.                 Element = (ElementRec*)ArrayGetElement(List->ItemList,0);
  136.                 ArrayDeleteElement(List->ItemList,0);
  137.                 ReleasePtr(Element->Name);
  138.                 ReleasePtr((char*)Element);
  139.             }
  140.         if (List->Title != NIL)
  141.             {
  142.                 ReleasePtr(List->Title);
  143.             }
  144.         DisposeScrollBar(List->Scrollbar);
  145.         DisposeArray(List->ItemList);
  146.         ReleasePtr((char*)List);
  147.     }
  148.  
  149.  
  150. /* find out where the string list is located */
  151. OrdType                        GetStringListXLoc(StringListRec* List)
  152.     {
  153.         CheckPtrExistence(List);
  154.         return List->X;
  155.     }
  156.  
  157.  
  158. /* find out where the string list is located */
  159. OrdType                        GetStringListYLoc(StringListRec* List)
  160.     {
  161.         CheckPtrExistence(List);
  162.         return List->Y;
  163.     }
  164.  
  165.  
  166. /* find out where the string list is located */
  167. OrdType                        GetStringListWidth(StringListRec* List)
  168.     {
  169.         CheckPtrExistence(List);
  170.         return List->Width;
  171.     }
  172.  
  173.  
  174. /* find out where the string list is located */
  175. OrdType                        GetStringListHeight(StringListRec* List)
  176.     {
  177.         CheckPtrExistence(List);
  178.         return List->Height;
  179.     }
  180.  
  181.  
  182. /* what font is being used to display the string list */
  183. FontType                    GetStringListFont(StringListRec* List)
  184.     {
  185.         CheckPtrExistence(List);
  186.         return List->Font;
  187.     }
  188.  
  189.  
  190. /* what point size is being used to display the string list */
  191. FontSizeType            GetStringListFontSize(StringListRec* List)
  192.     {
  193.         CheckPtrExistence(List);
  194.         return List->FontSize;
  195.     }
  196.  
  197.  
  198. /* how many lines of text are visible in the string list */
  199. long                            GetStringListNumVisibleLines(StringListRec* List)
  200.     {
  201.         OrdType                    Height;
  202.         long                        Temp;
  203.  
  204.         CheckPtrExistence(List);
  205.         Height = List->Height;
  206.         if (List->Title != NIL)
  207.             {
  208.                 Height -= List->LineHeight;
  209.             }
  210.         Temp = Height / List->LineHeight;
  211.         if ((Height % List->LineHeight) != 0)
  212.             {
  213.                 /* part of a line is visible */
  214.                 Temp += 1;
  215.             }
  216.         return Temp;
  217.     }
  218.  
  219.  
  220. /* change the location of the string list */
  221. void                            SetStringListLoc(StringListRec* List, OrdType X, OrdType Y,
  222.                                         OrdType Width, OrdType Height)
  223.     {
  224.         CheckPtrExistence(List);
  225.         List->X = X;
  226.         List->Y = Y;
  227.         List->Width = Width;
  228.         List->Height = Height;
  229.         if (List->Title == NIL)
  230.             {
  231.                 SetScrollLocation(List->Scrollbar,X + Width - 16,Y,Height);
  232.             }
  233.          else
  234.             {
  235.                 SetScrollLocation(List->Scrollbar,X + Width - 16,
  236.                     Y + List->LineHeight,Height - List->LineHeight);
  237.             }
  238.         RecalibrateScrollBar(List);
  239.         SetClipRect(List->Window,List->X,List->Y,List->Width,List->Height);
  240.         DrawBoxErase(List->Window,List->X,List->Y,List->Width,List->Height);
  241.         RedrawStringList(List);
  242.     }
  243.  
  244.  
  245. /* change the font being used to display the string list */
  246. void                            SetStringListFontInfo(StringListRec* List, FontType Font,
  247.                                         FontSizeType FontSize)
  248.     {
  249.         CheckPtrExistence(List);
  250.         List->Font = Font;
  251.         List->FontSize = FontSize;
  252.         List->LineHeight = GetFontHeight(Font,FontSize);
  253.         RedrawStringList(List);
  254.     }
  255.  
  256.  
  257. /* internal routine for redrawing string list */
  258. static void                RedrawStringListOneLine(StringListRec* List,
  259.                                         long LineIndex, MyBoolean PotentialSelection)
  260.     {
  261.         CheckPtrExistence(List);
  262.         if ((LineIndex >= List->TopElement)
  263.             && (LineIndex <= List->TopElement + List->Height / List->LineHeight))
  264.             {
  265.                 long                YOffset;
  266.                 OrdType            Top;
  267.                 OrdType            Height;
  268.  
  269.                 Top = List->Y;
  270.                 Height = List->Height;
  271.                 if (List->Title != NIL)
  272.                     {
  273.                         Top += List->LineHeight;
  274.                         Height -= List->LineHeight;
  275.                     }
  276.                 YOffset = (LineIndex - List->TopElement) * List->LineHeight + BorderInset;
  277.                 SetClipRect(List->Window,List->X + BorderInset,Top + BorderInset,
  278.                     List->Width - (2 * BorderInset) - 15,Height - (2 * BorderInset));
  279.                 AddClipRect(List->Window,List->X,Top + YOffset,
  280.                     List->Width,List->LineHeight);
  281.                 if ((LineIndex < 0) || (LineIndex >= ArrayGetLength(List->ItemList)))
  282.                     {
  283.                         /* entry out of range, so we draw an empty line */
  284.                         DrawBoxErase(List->Window,List->X,Top + YOffset,
  285.                             List->Width,List->LineHeight);
  286.                     }
  287.                  else
  288.                     {
  289.                         ElementRec*        Element;
  290.  
  291.                         /* entry is within range, so we really draw something */
  292.                         Element = (ElementRec*)ArrayGetElement(List->ItemList,LineIndex);
  293.                         CheckPtrExistence(Element);
  294.                         if (Element->Selected)
  295.                             {
  296.                                 /* selected */
  297.                                 DrawBoxPaint(List->Window,eBlack,List->X + BorderInset,
  298.                                     Top + YOffset,TextInset,List->LineHeight);
  299.                                 InvertedTextLine(List->Window,List->Font,List->FontSize,
  300.                                     Element->Name,PtrSize(Element->Name),
  301.                                     List->X + BorderInset + TextInset,Top + YOffset,ePlain);
  302.                                 DrawBoxPaint(List->Window,eBlack,List->X + BorderInset + TextInset
  303.                                     + LengthOfText(List->Font,List->FontSize,
  304.                                     Element->Name,PtrSize(Element->Name),
  305.                                     ePlain),Top + YOffset,List->Width,List->LineHeight);
  306.                             }
  307.                          else
  308.                             {
  309.                                 /* notselected */
  310.                                 DrawBoxErase(List->Window,List->X + BorderInset,
  311.                                     Top + YOffset,TextInset,List->LineHeight);
  312.                                 DrawTextLine(List->Window,List->Font,List->FontSize,
  313.                                     Element->Name,PtrSize(Element->Name),
  314.                                     List->X + BorderInset + TextInset,Top + YOffset,ePlain);
  315.                                 DrawBoxErase(List->Window,List->X + BorderInset + TextInset
  316.                                     + LengthOfText(List->Font,List->FontSize,
  317.                                     Element->Name,PtrSize(Element->Name),
  318.                                     ePlain),Top + YOffset,List->Width,List->LineHeight);
  319.                             }
  320.                         if (PotentialSelection)
  321.                             {
  322.                                 DrawBoxFrame(List->Window,eMediumGrey,List->X + BorderInset,
  323.                                     Top + YOffset,List->Width - 15 - (2 * BorderInset),
  324.                                     List->LineHeight);
  325.                             }
  326.                     }
  327.             }
  328.     }
  329.  
  330.  
  331. /* do a complete redraw of the string list */
  332. void                            RedrawStringList(StringListRec* List)
  333.     {
  334.         long                        Scan;
  335.         OrdType                    Top;
  336.         OrdType                    Height;
  337.         long                        Limit;
  338.  
  339.         CheckPtrExistence(List);
  340.         RecalibrateScrollBar(List);
  341.         Limit = List->TopElement + GetStringListNumVisibleLines(List);
  342.         for (Scan = List->TopElement; Scan < Limit; Scan += 1)
  343.             {
  344.                 RedrawStringListOneLine(List,Scan,False);
  345.             }
  346.         SetClipRect(List->Window,List->X,List->Y,List->Width,List->Height);
  347.         Top = List->Y;
  348.         Height = List->Height;
  349.         if (List->Title != NIL)
  350.             {
  351.                 DrawTextLine(List->Window,List->Font,List->FontSize,List->Title,
  352.                     PtrSize(List->Title),List->X
  353.                     + (List->Width - LengthOfText(List->Font,List->FontSize,
  354.                     List->Title,PtrSize(List->Title),ePlain)) / 2,Top,ePlain);
  355.                 Top += List->LineHeight;
  356.                 Height -= List->LineHeight;
  357.             }
  358.         DrawBoxFrame(List->Window,eBlack,List->X,Top,List->Width,Height);
  359.         RedrawScrollBar(List->Scrollbar);
  360.     }
  361.  
  362.  
  363. /* return a count of the number of selected items in the string list */
  364. long                            GetStringListHowManySelectedItems(StringListRec* List)
  365.     {
  366.         long                        Scan;
  367.         long                        Count;
  368.         long                        Limit;
  369.  
  370.         CheckPtrExistence(List);
  371.         Limit = ArrayGetLength(List->ItemList);
  372.         /* first, count how many */
  373.         Count = 0;
  374.         for (Scan = 0; Scan < Limit; Scan += 1)
  375.             {
  376.                 ElementRec*            Temp;
  377.  
  378.                 Temp = (ElementRec*)ArrayGetElement(List->ItemList,Scan);
  379.                 CheckPtrExistence(Temp);
  380.                 if (Temp->Selected)
  381.                     {
  382.                         Count += 1;
  383.                     }
  384.             }
  385.         return Count;
  386.     }
  387.  
  388.  
  389. /* return an Array containing a list of the References of all selected items */
  390. ArrayRec*                    GetListOfSelectedItems(StringListRec* List)
  391.     {
  392.         ArrayRec*                Them;
  393.  
  394.         CheckPtrExistence(List);
  395.         Them = NewArray();
  396.         if (Them != NIL)
  397.             {
  398.                 long                        Scan;
  399.                 long                        Limit;
  400.  
  401.                 Limit = ArrayGetLength(List->ItemList);
  402.                 for (Scan = 0; Scan < Limit; Scan += 1)
  403.                     {
  404.                         ElementRec*            Temp;
  405.  
  406.                         Temp = (ElementRec*)ArrayGetElement(List->ItemList,Scan);
  407.                         CheckPtrExistence(Temp);
  408.                         if (Temp->Selected)
  409.                             {
  410.                                 ArrayAppendElement(Them,Temp->Reference);
  411.                             }
  412.                     }
  413.             }
  414.         return Them;
  415.     }
  416.  
  417.  
  418. /* routine to verify that items don't get put on list more than once */
  419. #if DEBUG
  420. static void                StringListVerifyUniqueID(StringListRec* List, void* Reference)
  421.     {
  422.         long                        Scan;
  423.         long                        Limit;
  424.  
  425.         Limit = ArrayGetLength(List->ItemList);
  426.         for (Scan = 0; Scan < Limit; Scan += 1)
  427.             {
  428.                 ElementRec*            Temp;
  429.  
  430.                 Temp = (ElementRec*)ArrayGetElement(List->ItemList,Scan);
  431.                 CheckPtrExistence(Temp);
  432.                 if (Temp->Reference == Reference)
  433.                     {
  434.                         PRERR(ForceAbort,"StringListVerifyUniqueID failed");
  435.                     }
  436.             }
  437.     }
  438. #else
  439.     #define StringListVerifyUniqueID(stupid,dumb)
  440. #endif
  441.  
  442.  
  443. /* add a new element to the string list.  String is the string to be added to the */
  444. /* list, and OurReference is the reference pointer that identifies the item.  */
  445. /* BeforeThisReference is the item to insert it before.  if it is NIL then the */
  446. /* item is appended to the list.  NIL can be passed for the name if the name isn't */
  447. /* known yet.  Returns True if insertion was successful. */
  448. MyBoolean                    InsertStringListElement(StringListRec* List, char* String,
  449.                                         void* BeforeThisReference, void* OurReference, MyBoolean Redraw)
  450.     {
  451.         ElementRec*            NewBox;
  452.         long                        InsertionPoint;
  453.         long                        Scan;
  454.         long                        Limit;
  455.  
  456.         CheckPtrExistence(List);
  457.         ERROR(OurReference == NIL,PRERR(ForceAbort,
  458.             "InsertStringListElement:  references can not be NIL"));
  459.         /* converting the reference of an object into an real numerical index into the list */
  460.         /* if we can't find the reference, we default to insertion at end of list */
  461.         Limit = ArrayGetLength(List->ItemList);
  462.         InsertionPoint = Limit;
  463.         if (BeforeThisReference != NIL)
  464.             {
  465.                 for (Scan = 0; Scan < Limit; Scan += 1)
  466.                     {
  467.                         ElementRec*            Item;
  468.  
  469.                         Item = (ElementRec*)ArrayGetElement(List->ItemList,Scan);
  470.                         CheckPtrExistence(Item);
  471.                         if (BeforeThisReference == Item->Reference)
  472.                             {
  473.                                 InsertionPoint = Scan;
  474.                                 goto NextThingPoint;
  475.                             }
  476.                     }
  477.                 EXECUTE(PRERR(AllowResume,
  478.                     "InsertStringListElement:  couldn't find element to insert before"));
  479.              NextThingPoint:
  480.                 ;
  481.             }
  482.         /* else InsertionPoint is already correct */
  483.         /* making the new object */
  484.         StringListVerifyUniqueID(List,OurReference);
  485.         NewBox = (ElementRec*)AllocPtrCanFail(sizeof(ElementRec),"ElementRec");
  486.         if (NewBox == NIL)
  487.             {
  488.              FailedPoint0:
  489.                 return False; /* failed! */
  490.             }
  491.         NewBox->Selected = False;
  492.         NewBox->Reference = OurReference;
  493.         if (String != NIL)
  494.             {
  495.                 NewBox->Name = StringToBlockCopy(String);
  496.             }
  497.          else
  498.             {
  499.                 NewBox->Name = AllocPtrCanFail(0,"StringListName");
  500.             }
  501.         if (NewBox->Name == NIL)
  502.             {
  503.              FailedPoint1:
  504.                 ReleasePtr((char*)NewBox);
  505.                 goto FailedPoint0;
  506.             }
  507.         if (!ArrayInsertElement(List->ItemList,NewBox,InsertionPoint))
  508.             {
  509.              FailedPoint2:
  510.                 goto FailedPoint1;
  511.             }
  512.         if (Redraw)
  513.             {
  514.                 RecalibrateScrollBar(List);
  515.                 RedrawStringList(List);
  516.             }
  517.         return True;
  518.     }
  519.  
  520.  
  521. /* change the name of a string list element associated with the specified reference */
  522. void                            ChangeStringListElementName(StringListRec* List, char* NewName,
  523.                                         void* Reference)
  524.     {
  525.         long                        Scan;
  526.         long                        Limit;
  527.  
  528.         CheckPtrExistence(List);
  529.         Limit = ArrayGetLength(List->ItemList);
  530.         for (Scan = 0; Scan < Limit; Scan += 1)
  531.             {
  532.                 ElementRec*        Temp;
  533.  
  534.                 Temp = (ElementRec*)ArrayGetElement(List->ItemList,Scan);
  535.                 CheckPtrExistence(Temp);
  536.                 if (Reference == Temp->Reference)
  537.                     {
  538.                         char*                    NameTemp;
  539.  
  540.                         NameTemp = StringToBlockCopy(NewName);
  541.                         if (NameTemp != NIL)
  542.                             {
  543.                                 ReleasePtr(Temp->Name);
  544.                                 Temp->Name = NameTemp;
  545.                             }
  546.                         RedrawStringListOneLine(List,Scan,False);
  547.                         return;
  548.                     }
  549.             }
  550.         EXECUTE(PRERR(AllowResume,"ChangeStringListElementName:  Unknown element"));
  551.     }
  552.  
  553.  
  554. /* remove an element from the string list */
  555. void                            RemoveStringListElement(StringListRec* List, void* Reference,
  556.                                         MyBoolean Redraw)
  557.     {
  558.         long                        Scan;
  559.         long                        Limit;
  560.  
  561.         CheckPtrExistence(List);
  562.         Limit = ArrayGetLength(List->ItemList);
  563.         for (Scan = 0; Scan < Limit; Scan += 1)
  564.             {
  565.                 ElementRec*            Temp;
  566.  
  567.                 Temp = (ElementRec*)ArrayGetElement(List->ItemList,Scan);
  568.                 CheckPtrExistence(Temp);
  569.                 if (Reference == Temp->Reference)
  570.                     {
  571.                         ArrayDeleteElement(List->ItemList,Scan);
  572.                         ReleasePtr(Temp->Name);
  573.                         ReleasePtr((char*)Temp);
  574.                         if (Redraw)
  575.                             {
  576.                                 RecalibrateScrollBar(List);
  577.                                 RedrawStringList(List);
  578.                             }
  579.                         return;
  580.                     }
  581.             }
  582.         EXECUTE(PRERR(AllowResume,"RemoveStringListElement:  Unknown element"));
  583.     }
  584.  
  585.  
  586. /* see if the specified location is within the string list box */
  587. MyBoolean                    StringListHitTest(StringListRec* List, OrdType X, OrdType Y)
  588.     {
  589.         CheckPtrExistence(List);
  590.         return ((X >= List->X) && (Y >= List->Y)
  591.             && (X < List->X + List->Width) && (Y < List->Y + List->Height));
  592.     }
  593.  
  594.  
  595. /* do a mouse down in the string list to select items.  returns True if it was */
  596. /* a double click. */
  597. MyBoolean                    StringListMouseDown(StringListRec* List, OrdType X, OrdType Y,
  598.                                         ModifierFlags Modifiers)
  599.     {
  600.         MyBoolean                Inside;
  601.         long                        Hilited;
  602.         OrdType                    Top;
  603.         OrdType                    Height;
  604.  
  605.         CheckPtrExistence(List);
  606.         if (ScrollHitTest(List->Scrollbar,X,Y))
  607.             {
  608.                 ScrollHitProc(List->Scrollbar,eNoModifiers,X,Y,List,
  609.                     (void (*)(long,ScrollType,void*))&StringListScrollHook);
  610.                 return False;
  611.             }
  612.         if ((TimerDifference(ReadTimer(),List->LastMouseDownTime)
  613.             < GetDoubleClickInterval()) && (X - List->LastMouseXLoc > -3)
  614.             && (X - List->LastMouseXLoc < 3) && (Y - List->LastMouseYLoc > -3)
  615.             && (Y - List->LastMouseYLoc < 3) && ((Modifiers & eCommandKey) == 0)
  616.             && ((Modifiers & eShiftKey) == 0))
  617.             {
  618.                 List->LastMouseDownTime = ReadTimer();
  619.                 List->LastMouseXLoc = X;
  620.                 List->LastMouseYLoc = Y;
  621.                 return True;
  622.             }
  623.         List->LastMouseDownTime = ReadTimer();
  624.         List->LastMouseXLoc = X;
  625.         List->LastMouseYLoc = Y;
  626.  
  627.         Inside = False;
  628.         Top = List->Y;
  629.         Height = List->Height;
  630.         if (List->Title != NIL)
  631.             {
  632.                 Top += List->LineHeight;
  633.                 Height -= List->LineHeight;
  634.             }
  635.         do
  636.             {
  637.                 if ((X < List->X) || (X > List->Width + List->X - 15))
  638.                     {
  639.                         if (Inside)
  640.                             {
  641.                                 Inside = False;
  642.                                 RedrawStringListOneLine(List,Hilited,False);
  643.                             }
  644.                     }
  645.                  else
  646.                     {
  647.                         long                PossibleIndex;
  648.  
  649.                         if (Y < Top)
  650.                             {
  651.                                 Y = Top;
  652.                                 if (Inside)
  653.                                     {
  654.                                         Inside = False;
  655.                                         RedrawStringListOneLine(List,Hilited,False);
  656.                                     }
  657.                                 StringListScrollHook(0,eScrollLineMinus,List);
  658.                             }
  659.                         else if (Y > Top + Height - 1)
  660.                             {
  661.                                 Y = Top + Height - 1;
  662.                                 if (Inside)
  663.                                     {
  664.                                         Inside = False;
  665.                                         RedrawStringListOneLine(List,Hilited,False);
  666.                                     }
  667.                                 StringListScrollHook(0,eScrollLinePlus,List);
  668.                             }
  669.                         else
  670.                             {
  671.                                 PossibleIndex = (Y - Top - BorderInset) / List->LineHeight
  672.                                     + List->TopElement;
  673.                                 if (Inside && (Hilited != PossibleIndex))
  674.                                     {
  675.                                         Inside = False;
  676.                                         RedrawStringListOneLine(List,Hilited,False);
  677.                                     }
  678.                                 if (!Inside)
  679.                                     {
  680.                                         Inside = True;
  681.                                         Hilited = PossibleIndex;
  682.                                         RedrawStringListOneLine(List,Hilited,True);
  683.                                     }
  684.                             }
  685.                     }
  686.             } while (eMouseUp != GetAnEvent(&X,&Y,&Modifiers,NIL,NIL,NIL));
  687.         if (Inside)
  688.             {
  689.                 if ((Hilited >= 0) && (Hilited < ArrayGetLength(List->ItemList)))
  690.                     {
  691.                         ElementRec*        Item;
  692.  
  693.                         Item = (ElementRec*)ArrayGetElement(List->ItemList,Hilited);
  694.                         CheckPtrExistence(Item);
  695.                         if (((Modifiers & eCommandKey) != 0) || ((Modifiers & eShiftKey) != 0))
  696.                             {
  697.                                 if (Item->Selected)
  698.                                     {
  699.                                         DeselectStringListElement(List,Item->Reference);
  700.                                     }
  701.                                  else
  702.                                     {
  703.                                         SelectStringListElement(List,Item->Reference);
  704.                                     }
  705.                             }
  706.                          else
  707.                             {
  708.                                 DeselectAllStringListElements(List);
  709.                                 SelectStringListElement(List,Item->Reference);
  710.                             }
  711.                     }
  712.             }
  713.         return False; /* no double click */
  714.     }
  715.  
  716.  
  717. /* select (hilite) the specified element in the list */
  718. void                            SelectStringListElement(StringListRec* List, void* Reference)
  719.     {
  720.         long                        Scan;
  721.         long                        Limit;
  722.  
  723.         CheckPtrExistence(List);
  724.         /* first, deselect anything if multiple selection isn't allowed */
  725.         if (!List->AllowMultipleSelection)
  726.             {
  727.                 DeselectAllStringListElements(List);
  728.             }
  729.         /* now, select the element we are interested in */
  730.         Limit = ArrayGetLength(List->ItemList);
  731.         for (Scan = 0; Scan < Limit; Scan += 1)
  732.             {
  733.                 ElementRec*        Item;
  734.  
  735.                 Item = (ElementRec*)ArrayGetElement(List->ItemList,Scan);
  736.                 CheckPtrExistence(Item);
  737.                 if (Reference == Item->Reference)
  738.                     {
  739.                         if (!Item->Selected)
  740.                             {
  741.                                 Item->Selected = True;
  742.                                 RedrawStringListOneLine(List,Scan,False);
  743.                             }
  744.                         return;
  745.                     }
  746.             }
  747.         EXECUTE(PRERR(AllowResume,"SelectStringListElement:  Unknown element"));
  748.     }
  749.  
  750.  
  751. /* deselect the specified element in the list */
  752. void                            DeselectStringListElement(StringListRec* List, void* Reference)
  753.     {
  754.         long                        Scan;
  755.         long                        Limit;
  756.  
  757.         CheckPtrExistence(List);
  758.         /* first, deselect anything if multiple selection isn't allowed */
  759.         if (!List->AllowMultipleSelection)
  760.             {
  761.                 DeselectAllStringListElements(List);
  762.             }
  763.         /* now, select the element we are interested in */
  764.         Limit = ArrayGetLength(List->ItemList);
  765.         for (Scan = 0; Scan < Limit; Scan += 1)
  766.             {
  767.                 ElementRec*        Item;
  768.  
  769.                 Item = (ElementRec*)ArrayGetElement(List->ItemList,Scan);
  770.                 CheckPtrExistence(Item);
  771.                 if (Reference == Item->Reference)
  772.                     {
  773.                         if (Item->Selected)
  774.                             {
  775.                                 Item->Selected = False;
  776.                                 RedrawStringListOneLine(List,Scan,False);
  777.                             }
  778.                         return;
  779.                     }
  780.             }
  781.         EXECUTE(PRERR(AllowResume,"SelectStringListElement:  Unknown element"));
  782.     }
  783.  
  784.  
  785. /* enable the scrollbar display in the list */
  786. void                            EnableStringList(StringListRec* List)
  787.     {
  788.         CheckPtrExistence(List);
  789.         EnableScrollBar(List->Scrollbar);
  790.     }
  791.  
  792.  
  793. /* disable the scrollbar display in the list */
  794. void                            DisableStringList(StringListRec* List)
  795.     {
  796.         CheckPtrExistence(List);
  797.         DisableScrollBar(List->Scrollbar);
  798.     }
  799.  
  800.  
  801. /* internal scrollhook for scrolling in the string list */
  802. static void                StringListScrollHook(long Parameter, ScrollType How,
  803.                                         StringListRec* ScrollTemp)
  804.     {
  805.         CheckPtrExistence(ScrollTemp);
  806.         switch (How)
  807.             {
  808.                 case eScrollToPosition:
  809.                     ScrollTemp->TopElement = Parameter;
  810.                     break;
  811.                 case eScrollPageMinus:
  812.                     ScrollTemp->TopElement -= GetStringListNumVisibleLines(ScrollTemp) - 2;
  813.                     break;
  814.                 case eScrollPagePlus:
  815.                     ScrollTemp->TopElement += GetStringListNumVisibleLines(ScrollTemp) - 2;
  816.                     break;
  817.                 case eScrollLineMinus:
  818.                     ScrollTemp->TopElement -= 1;
  819.                     break;
  820.                 case eScrollLinePlus:
  821.                     ScrollTemp->TopElement += 1;
  822.                     break;
  823.                 default:
  824.                     EXECUTE(PRERR(AllowResume,"StringListScrollHook:  Unknown scroll opcode"));
  825.                     break;
  826.             }
  827.         if (ScrollTemp->TopElement > ArrayGetLength(ScrollTemp->ItemList)
  828.             - GetStringListNumVisibleLines(ScrollTemp) + 1)
  829.             {
  830.                 ScrollTemp->TopElement = ArrayGetLength(ScrollTemp->ItemList)
  831.                     - GetStringListNumVisibleLines(ScrollTemp) + 1;
  832.             }
  833.         if (ScrollTemp->TopElement < 0)
  834.             {
  835.                 ScrollTemp->TopElement = 0;
  836.             }
  837.         RecalibrateScrollBar(ScrollTemp);
  838.         RedrawStringList(ScrollTemp);
  839.     }
  840.  
  841.  
  842. /* deselect all of the items in the string list that are selected */
  843. void                            DeselectAllStringListElements(StringListRec* List)
  844.     {
  845.         long                        Scan;
  846.         long                        Limit;
  847.  
  848.         CheckPtrExistence(List);
  849.         Limit = ArrayGetLength(List->ItemList);
  850.         for (Scan = 0; Scan < Limit; Scan += 1)
  851.             {
  852.                 ElementRec*        Item;
  853.  
  854.                 Item = (ElementRec*)ArrayGetElement(List->ItemList,Scan);
  855.                 CheckPtrExistence(Item);
  856.                 if (Item->Selected)
  857.                     {
  858.                         Item->Selected = False;
  859.                         RedrawStringListOneLine(List,Scan,False);
  860.                     }
  861.             }
  862.     }
  863.  
  864.  
  865. static void                RecalibrateScrollBar(StringListRec* List)
  866.     {
  867.         long                        Maximum;
  868.  
  869.         CheckPtrExistence(List);
  870.         Maximum = ArrayGetLength(List->ItemList) - GetStringListNumVisibleLines(List) + 2;
  871.         if (Maximum < 1)
  872.             {
  873.                 Maximum = 1;
  874.             }
  875.         SetMaxScrollIndex(List->Scrollbar,Maximum);
  876.         SetScrollIndex(List->Scrollbar,List->TopElement);
  877.     }
  878.  
  879.  
  880. /* make sure selection is visible in the window */
  881. void                            MakeStringListSelectionVisible(StringListRec* List)
  882.     {
  883.         long                        WhatIndexToUse;
  884.         long                        Scan;
  885.         long                        Count;
  886.         long                        Limit;
  887.  
  888.         CheckPtrExistence(List);
  889.         Limit = ArrayGetLength(List->ItemList);
  890.         /* first, count how many */
  891.         Count = 0;
  892.         for (Scan = 0; Scan < Limit; Scan += 1)
  893.             {
  894.                 ElementRec*            Temp;
  895.  
  896.                 Temp = (ElementRec*)ArrayGetElement(List->ItemList,Scan);
  897.                 CheckPtrExistence(Temp);
  898.                 if (Temp->Selected)
  899.                     {
  900.                         WhatIndexToUse = Scan;
  901.                         if (WhatIndexToUse < List->TopElement)
  902.                             {
  903.                                 List->TopElement = WhatIndexToUse;
  904.                             }
  905.                         if (WhatIndexToUse > List->TopElement
  906.                             + (GetStringListNumVisibleLines(List) - 2))
  907.                             {
  908.                                 List->TopElement = WhatIndexToUse
  909.                                     - (GetStringListNumVisibleLines(List) - 2);
  910.                             }
  911.                         RedrawStringList(List);
  912.                         return;
  913.                     }
  914.             }
  915.     }
  916.