home *** CD-ROM | disk | FTP | other *** search
/ Mac-Source 1994 July / Mac-Source_July_1994.iso / Pascal / source / simplify-list-manager-pas.txt < prev   
Internet Message Format  |  1994-03-23  |  11KB

  1. From: kurisuto@BACH.UDEL.EDU ("Sean J. Crist")
  2. Subject: More free code: Simplifying the List Manager 
  3. Date: 18 Sep 92 03:33:13 GMT 
  4.  
  5.  
  6.      The following code, once again, is nothing particularly glamorous; it
  7. simply makes it easier to use the List Manager to create and manage lists
  8. of strings.  One of the most common uses for the List Manager is
  9. scrollable, one-dimensional, fixed-size
  10. lists of strings (as in SFGetFile, SFPutFile).  The List Manager is good
  11. for creating all kinds of lists (such as lists of icons), but a lot of
  12. this functionality is a hassle for programmers who only need a simple list
  13. of strings.
  14.      The code below allows you create and dispose of lists of strings.  It
  15. allows you to add, rename, and remove elements in the list, and handles
  16. mouse clicks and update events.  It also keeps the lists in alphabetical
  17. order.
  18.      I remember having a lot of trouble learning how to call the List
  19. Manager properly; I hope that this code helps somebody else.
  20.  
  21. How to use these routines:
  22.      Every one of these routines takes a ListHandle as one of its
  23. parameters.  It is OK to have several lists going at one time; just make
  24. sure you pass the right ListHandle when you call one of these routines.
  25.      
  26. CreateList:  Call this routine to create a new list of strings.  Pass it
  27. an empty ListHandle, as well as the pointer to the window to contain the
  28. list, and the rectangle in which the list should be enclosed.  The list
  29. can take up an entire window, or only
  30. part of it, as you prefer.  The scroll bar will be drawn inside the
  31. rectangle you specify, so you don't need to leave extra room for it. 
  32. Initially, the list will contain no strings.
  33.  
  34. UpdateList:  Call this in response to an Update event to redraw the
  35. portions of the list which need it.  This routine assumes that you have
  36. already called BeginUpdate for the window containing the list, and that
  37. you have not yet called EndUpdate.
  38.  
  39. DoClick:  Call this function in response to a MouseDown event inside your
  40. list's rectangle.  DoClick usually returns FALSE, but it returns TRUE if
  41. this click is the second click of a double-click (i.e., TRUE means the
  42. user double-clicked an item).
  43.  
  44. TurnOffSelection:  This routine unhilights the currently hilighted cell,
  45. if any.
  46.  
  47. ListSelection:  This returns the string of the currently selected cell. 
  48. If no cell is currently selected, the empty string is returned.
  49.  
  50. AddCell:  Call this routine to add a new cell to the list.  The string you
  51. pass to this routine is automatically alphabetized within the list.  Bug
  52. alert:  the first element or two of the list are sometimes not in
  53. alphabetical order.  If you take the time
  54. to work out this kink, please let me know what you did (I could figure
  55. this out, but I just haven't taken the time to).  This bug is cosmetic and
  56. does not crash the program.
  57.  
  58. RenameCell:  Changes the string in a cell to another string, and
  59. realphabetizes the list, if necessary.  
  60.  
  61. DeleteCell:  Removes the cell with the given string from the list.
  62.  
  63. DisposList:  Call this routine when you are completely finished with a
  64. list and want to deallocate its memory.
  65.  
  66.      Credit: The routines CreateList, UpdateList, DoClick, and DisposList
  67. are loosely based on some code I received from somebody of
  68. comp.sys.mac.programmer around two years ago.  I've rewritten these
  69. routines, but credit is due to this contributor, whose
  70. name I cannot remember.
  71.  
  72.      I have successfully called these routines for lists in regular
  73. windows as well as in modal dialogs.  Please send bug reports, praise,
  74. money, etc. to kurisuto@bach.udel.edu.
  75.  
  76. unit StringListInterface;
  77.  
  78. interface
  79.  
  80. {Create a new list with no elements.}
  81.  procedure CreateList (var TheListHandle: ListHandle; TheWindow:
  82. WindowPtr; TheRect: Rect);
  83.  
  84. {Update the art of a list.}
  85.  procedure UpdateList (TheListHandle: ListHandle);
  86.  
  87. {Handle a click in the list rectangle.  If it was a double-click, we will
  88. return TRUE.}
  89.  function DoClick (TheListHandle: ListHandle; TheWhere: Point): Boolean;
  90.  
  91. {Turn off any hilited item.}
  92.  procedure TurnOffSelection (TheListHandle: ListHandle);
  93.  
  94. {Return the string currently selected; empty string if no selection.}
  95.  function ListSelection (TheListHandle: ListHandle): string;
  96.  
  97. {Add a new cell containing the string parameter to the end of the list}
  98.  procedure AddCell (TheListHandle: ListHandle; NewString: str255);
  99.  
  100. {Change the name of an existing cell}
  101.  procedure RenameCell (TheListHandle: ListHandle; OldString, NewString:
  102. Str255);
  103.  
  104. {Remove the cell with the given name from the list.}
  105.  procedure DeleteCell (TheListHandle: ListHandle; TheString: string);
  106.  
  107. {Get rid of the list when we're done with it, cleaning up all the memory.}
  108.  procedure DisposList (TheListHandle: ListHandle);
  109.  
  110. implementation
  111.  
  112.  procedure CreateList;
  113.   const
  114.    StandardList = 0;
  115.   var
  116.    ViewRect: Rect;
  117.    DataBounds: Rect;
  118.    CellSize: Point;
  119.    TempInteger: Integer;  {Just to do a little math}
  120.  begin
  121. {Inset the box to make room for the scroll bar.  Also inset it so we've
  122. got room for a border.}
  123.   ViewRect := TheRect;
  124.   InsetRect(ViewRect, 1, 1);
  125.   ViewRect.Right := ViewRect.Right - 15;
  126. {Set the cell size to the size of the cell}
  127.   CellSize.v := TheWindow^.txSize + 3;
  128.   if CellSize.v = 3 then  {If it hasn't been set, then make it 12 point.}
  129.    begin
  130.     TextSize(12);
  131.     CellSize.v := 15;
  132.    end;
  133.   CellSize.h := ViewRect.Right - ViewRect.Left;
  134. {Now adjust the ViewRect to avoid cutting off the last visible cell}
  135.   TempInteger := (ViewRect.Bottom - ViewRect.Top) div CellSize.v;
  136.   ViewRect.Bottom := ViewRect.Top + (TempInteger * CellSize.v);
  137. {Create the new list.}
  138.   SetRect(DataBounds, 0, 0, 1, 0);
  139.   TheListHandle := LNew(ViewRect, DataBounds, CellSize, StandardList,
  140. TheWindow, FALSE, FALSE, FALSE, TRUE);
  141.   UpdateList(TheListHandle);
  142.  end;
  143.  
  144. {Update the display of a list.}
  145.  procedure UpdateList;
  146.   var
  147.    ViewRect: Rect;
  148.    ListUpdateRgn: RgnHandle;
  149.  begin
  150.   SetPort(TheListHandle^^.Port);
  151. {Get the List manager to update the list.}
  152.   ViewRect := TheListHandle^^.rView;
  153.   LDoDraw(true, TheListHandle);
  154.   ListUpdateRgn := NewRgn;
  155.   RectRgn(ListUpdateRgn, ViewRect);
  156.   LUpdate(ListUpdateRgn, TheListHandle);
  157. {Draw the border}
  158.   InsetRect(ViewRect, -1, -1);
  159.   FrameRect(ViewRect);
  160. {Clean up after ourselves}
  161.   DisposeRgn(ListUpdateRgn);
  162.  end;
  163.  
  164. {Handle a click in the list rectangle.  If it was a double-click, we will
  165. return TRUE.}
  166.  function DoClick;
  167.  begin
  168.   SetPort(TheListHandle^^.Port);
  169.   LDoDraw(TRUE, TheListHandle);
  170.   DoClick := LClick(TheWhere, 0, TheListHandle);
  171.  end;
  172.  
  173. {Turn off any hilited item.}
  174.  procedure TurnOffSelection;
  175.   var
  176.    ResultPoint: Point;
  177.  begin
  178.   SetPt(ResultPoint, 0, 0);
  179.   if LGetSelect(TRUE, ResultPoint, TheListHandle) then
  180.    LSetSelect(FALSE, ResultPoint, TheListHandle);
  181.  end;
  182.  
  183. {Return the string currently selected; empty string if no selection.}
  184.  function ListSelection;
  185.   var
  186.    ResultPoint: Point;
  187.    ResultString: Str255;
  188.    StringPointer: Ptr;
  189.    StringLength: Integer;
  190.  begin
  191.   SetPt(ResultPoint, 0, 0);
  192.   if LGetSelect(TRUE, ResultPoint, TheListHandle) then
  193. {If there is a cell selected, then get the string value of that string. 
  194. There ought to be an}
  195. {easier way to do this than mucking around in the memory like this.  >:-( 
  196.   }
  197.    begin  {If there is a cell selected, then return the string of the cell.}
  198.     StringPointer := Ptr(Ord(@ResultString) + 1);
  199.     StringLength := 255;  {This is the maximum amount of data we are
  200. allowed to move.}
  201.     LGetCell(StringPointer, StringLength, ResultPoint, TheListHandle);
  202.     StringPointer := Ptr(Ord(@ResultString));
  203.     StringPointer^ := StringLength;
  204.     ListSelection := ResultString;
  205.    end
  206.   else  {Otherwise, return the empty string to show that nothing is selected.}
  207.    ListSelection := '';
  208.  end;
  209.  
  210. {Add a new cell containing the string parameter to the end of the list}
  211.  procedure AddCell;
  212.   var
  213.    Counter: Integer;
  214.    CellPoint: Point;
  215.    OldString: Str255;
  216.    CompResult: Integer;
  217.    StringLength: Integer;
  218.    StringPointer: Ptr;
  219.    done: Boolean;
  220.  begin
  221. {Step 1:  Circle through the loop and figure out where we should insert
  222. the new}
  223. {cell.  We do this to put the list in alphabetical order, and to keep it
  224. that way as}
  225. {new items are added.}
  226.   CellPoint.h := 0;
  227.   CellPoint.v := 0;
  228.   Done := false;
  229.   while not done do
  230.    begin
  231.     if LNextCell(TRUE, TRUE, CellPoint, TheListHandle) then
  232.      begin
  233.       StringPointer := Ptr(Ord(@OldString) + 1);
  234.       StringLength := 255;  {This is the maximum amount of data we are
  235. allowed to move.}
  236.       LGetCell(StringPointer, StringLength, CellPoint, TheListHandle);
  237.       StringPointer := Ptr(Ord(@OldString));
  238.       StringPointer^ := StringLength;
  239. {Now, compare the new string with the contents of the cell and decide
  240. whether the new string}
  241. {should come before or after this cell.}
  242.       CompResult := RelString(NewString, OldString, false, true);
  243.       case CompResult of
  244.        sortsBefore, sortsEqual: 
  245.        done := true;
  246.        SortsAfter: 
  247.        ;
  248.       end;
  249.      end
  250.     else
  251. {There are no more rows, so that's all.}
  252.      begin
  253.       done := true;
  254.      end;
  255.    end;
  256.  
  257. {Add the new row at the top of the list.}
  258.   CellPoint.v := LAddRow(1, CellPoint.v, TheListHandle);
  259. {Put the string into the cell.  Once again, there ought to be an easier
  260. way to do this.}
  261.   LSetCell(Pointer(Ord(@NewString) + 1), Length(NewString), CellPoint,
  262. TheListHandle);
  263.  end;
  264.  
  265.  
  266.  procedure RenameCell;
  267.   var
  268.    CellPoint: Point;
  269.    DataPtr: Ptr;
  270.    DataLen: Integer;
  271.  begin
  272.   SetPt(CellPoint, 0, 0);
  273.   DataPtr := Pointer(Ord(@OldString) + 1);
  274.   dataLen := Length(OldString);
  275.   if LSearch(dataPtr, dataLen, nil, CellPoint, TheListHandle) then
  276.    begin
  277.     DataPtr := Pointer(Ord(@NewString) + 1);
  278.     dataLen := Length(NewString);
  279.     LSetCell(DataPtr, dataLen, CellPoint, TheListHandle);
  280.    end
  281.   else
  282.    begin
  283. {The programmer asked us to rename a cell which doesn't exist.  We'll just
  284. beep angrily}
  285. {three times.  It's the programmer's responsibility to see that the cell
  286. in question actually}
  287. {does exist before calling this routine.}
  288.     Sysbeep(1);
  289.     Sysbeep(1);
  290.     Sysbeep(1);
  291.    end;
  292.  end;
  293.  
  294.  
  295. {Remove the cell with the given name from the list.}
  296.  procedure DeleteCell;
  297.   var
  298.    CellPoint: Point;
  299.    DataPtr: Ptr;
  300.    DataLen: Integer;
  301.  begin
  302.   SetPt(CellPoint, 0, 0);
  303.   DataPtr := Pointer(Ord(@TheString) + 1);
  304.   dataLen := Length(TheString);
  305.   if LSearch(dataPtr, dataLen, nil, CellPoint, TheListHandle) then
  306.    begin
  307.     LDelRow(1, CellPoint.v, TheListHandle);
  308.    end
  309.   else
  310.    begin
  311. {The programmer asked us to delete a cell which doesn't exist.  We'll just
  312. beep angrily}
  313. {three times.  It's the programmer's responsibility to see that the cell
  314. in question actually}
  315. {does exist before calling this routine.}
  316.     Sysbeep(1);
  317.     Sysbeep(1);
  318.     Sysbeep(1);
  319.    end;
  320.  end;
  321.  
  322. {Get rid of the list when we're done with it, cleaning up all the memory.}
  323.  procedure DisposList;
  324.  begin
  325.   LDispose(TheListHandle);
  326.  end;
  327.  
  328.  
  329. end.
  330.  
  331.  
  332.  
  333.  
  334.  
  335.  
  336.