home *** CD-ROM | disk | FTP | other *** search
- From: kurisuto@BACH.UDEL.EDU ("Sean J. Crist")
- Subject: More free code: Simplifying the List Manager
- Date: 18 Sep 92 03:33:13 GMT
-
-
- The following code, once again, is nothing particularly glamorous; it
- simply makes it easier to use the List Manager to create and manage lists
- of strings. One of the most common uses for the List Manager is
- scrollable, one-dimensional, fixed-size
- lists of strings (as in SFGetFile, SFPutFile). The List Manager is good
- for creating all kinds of lists (such as lists of icons), but a lot of
- this functionality is a hassle for programmers who only need a simple list
- of strings.
- The code below allows you create and dispose of lists of strings. It
- allows you to add, rename, and remove elements in the list, and handles
- mouse clicks and update events. It also keeps the lists in alphabetical
- order.
- I remember having a lot of trouble learning how to call the List
- Manager properly; I hope that this code helps somebody else.
-
- How to use these routines:
- Every one of these routines takes a ListHandle as one of its
- parameters. It is OK to have several lists going at one time; just make
- sure you pass the right ListHandle when you call one of these routines.
-
- CreateList: Call this routine to create a new list of strings. Pass it
- an empty ListHandle, as well as the pointer to the window to contain the
- list, and the rectangle in which the list should be enclosed. The list
- can take up an entire window, or only
- part of it, as you prefer. The scroll bar will be drawn inside the
- rectangle you specify, so you don't need to leave extra room for it.
- Initially, the list will contain no strings.
-
- UpdateList: Call this in response to an Update event to redraw the
- portions of the list which need it. This routine assumes that you have
- already called BeginUpdate for the window containing the list, and that
- you have not yet called EndUpdate.
-
- DoClick: Call this function in response to a MouseDown event inside your
- list's rectangle. DoClick usually returns FALSE, but it returns TRUE if
- this click is the second click of a double-click (i.e., TRUE means the
- user double-clicked an item).
-
- TurnOffSelection: This routine unhilights the currently hilighted cell,
- if any.
-
- ListSelection: This returns the string of the currently selected cell.
- If no cell is currently selected, the empty string is returned.
-
- AddCell: Call this routine to add a new cell to the list. The string you
- pass to this routine is automatically alphabetized within the list. Bug
- alert: the first element or two of the list are sometimes not in
- alphabetical order. If you take the time
- to work out this kink, please let me know what you did (I could figure
- this out, but I just haven't taken the time to). This bug is cosmetic and
- does not crash the program.
-
- RenameCell: Changes the string in a cell to another string, and
- realphabetizes the list, if necessary.
-
- DeleteCell: Removes the cell with the given string from the list.
-
- DisposList: Call this routine when you are completely finished with a
- list and want to deallocate its memory.
-
- Credit: The routines CreateList, UpdateList, DoClick, and DisposList
- are loosely based on some code I received from somebody of
- comp.sys.mac.programmer around two years ago. I've rewritten these
- routines, but credit is due to this contributor, whose
- name I cannot remember.
-
- I have successfully called these routines for lists in regular
- windows as well as in modal dialogs. Please send bug reports, praise,
- money, etc. to kurisuto@bach.udel.edu.
-
- unit StringListInterface;
-
- interface
-
- {Create a new list with no elements.}
- procedure CreateList (var TheListHandle: ListHandle; TheWindow:
- WindowPtr; TheRect: Rect);
-
- {Update the art of a list.}
- procedure UpdateList (TheListHandle: ListHandle);
-
- {Handle a click in the list rectangle. If it was a double-click, we will
- return TRUE.}
- function DoClick (TheListHandle: ListHandle; TheWhere: Point): Boolean;
-
- {Turn off any hilited item.}
- procedure TurnOffSelection (TheListHandle: ListHandle);
-
- {Return the string currently selected; empty string if no selection.}
- function ListSelection (TheListHandle: ListHandle): string;
-
- {Add a new cell containing the string parameter to the end of the list}
- procedure AddCell (TheListHandle: ListHandle; NewString: str255);
-
- {Change the name of an existing cell}
- procedure RenameCell (TheListHandle: ListHandle; OldString, NewString:
- Str255);
-
- {Remove the cell with the given name from the list.}
- procedure DeleteCell (TheListHandle: ListHandle; TheString: string);
-
- {Get rid of the list when we're done with it, cleaning up all the memory.}
- procedure DisposList (TheListHandle: ListHandle);
-
- implementation
-
- procedure CreateList;
- const
- StandardList = 0;
- var
- ViewRect: Rect;
- DataBounds: Rect;
- CellSize: Point;
- TempInteger: Integer; {Just to do a little math}
- begin
- {Inset the box to make room for the scroll bar. Also inset it so we've
- got room for a border.}
- ViewRect := TheRect;
- InsetRect(ViewRect, 1, 1);
- ViewRect.Right := ViewRect.Right - 15;
- {Set the cell size to the size of the cell}
- CellSize.v := TheWindow^.txSize + 3;
- if CellSize.v = 3 then {If it hasn't been set, then make it 12 point.}
- begin
- TextSize(12);
- CellSize.v := 15;
- end;
- CellSize.h := ViewRect.Right - ViewRect.Left;
- {Now adjust the ViewRect to avoid cutting off the last visible cell}
- TempInteger := (ViewRect.Bottom - ViewRect.Top) div CellSize.v;
- ViewRect.Bottom := ViewRect.Top + (TempInteger * CellSize.v);
- {Create the new list.}
- SetRect(DataBounds, 0, 0, 1, 0);
- TheListHandle := LNew(ViewRect, DataBounds, CellSize, StandardList,
- TheWindow, FALSE, FALSE, FALSE, TRUE);
- UpdateList(TheListHandle);
- end;
-
- {Update the display of a list.}
- procedure UpdateList;
- var
- ViewRect: Rect;
- ListUpdateRgn: RgnHandle;
- begin
- SetPort(TheListHandle^^.Port);
- {Get the List manager to update the list.}
- ViewRect := TheListHandle^^.rView;
- LDoDraw(true, TheListHandle);
- ListUpdateRgn := NewRgn;
- RectRgn(ListUpdateRgn, ViewRect);
- LUpdate(ListUpdateRgn, TheListHandle);
- {Draw the border}
- InsetRect(ViewRect, -1, -1);
- FrameRect(ViewRect);
- {Clean up after ourselves}
- DisposeRgn(ListUpdateRgn);
- end;
-
- {Handle a click in the list rectangle. If it was a double-click, we will
- return TRUE.}
- function DoClick;
- begin
- SetPort(TheListHandle^^.Port);
- LDoDraw(TRUE, TheListHandle);
- DoClick := LClick(TheWhere, 0, TheListHandle);
- end;
-
- {Turn off any hilited item.}
- procedure TurnOffSelection;
- var
- ResultPoint: Point;
- begin
- SetPt(ResultPoint, 0, 0);
- if LGetSelect(TRUE, ResultPoint, TheListHandle) then
- LSetSelect(FALSE, ResultPoint, TheListHandle);
- end;
-
- {Return the string currently selected; empty string if no selection.}
- function ListSelection;
- var
- ResultPoint: Point;
- ResultString: Str255;
- StringPointer: Ptr;
- StringLength: Integer;
- begin
- SetPt(ResultPoint, 0, 0);
- if LGetSelect(TRUE, ResultPoint, TheListHandle) then
- {If there is a cell selected, then get the string value of that string.
- There ought to be an}
- {easier way to do this than mucking around in the memory like this. >:-(
- }
- begin {If there is a cell selected, then return the string of the cell.}
- StringPointer := Ptr(Ord(@ResultString) + 1);
- StringLength := 255; {This is the maximum amount of data we are
- allowed to move.}
- LGetCell(StringPointer, StringLength, ResultPoint, TheListHandle);
- StringPointer := Ptr(Ord(@ResultString));
- StringPointer^ := StringLength;
- ListSelection := ResultString;
- end
- else {Otherwise, return the empty string to show that nothing is selected.}
- ListSelection := '';
- end;
-
- {Add a new cell containing the string parameter to the end of the list}
- procedure AddCell;
- var
- Counter: Integer;
- CellPoint: Point;
- OldString: Str255;
- CompResult: Integer;
- StringLength: Integer;
- StringPointer: Ptr;
- done: Boolean;
- begin
- {Step 1: Circle through the loop and figure out where we should insert
- the new}
- {cell. We do this to put the list in alphabetical order, and to keep it
- that way as}
- {new items are added.}
- CellPoint.h := 0;
- CellPoint.v := 0;
- Done := false;
- while not done do
- begin
- if LNextCell(TRUE, TRUE, CellPoint, TheListHandle) then
- begin
- StringPointer := Ptr(Ord(@OldString) + 1);
- StringLength := 255; {This is the maximum amount of data we are
- allowed to move.}
- LGetCell(StringPointer, StringLength, CellPoint, TheListHandle);
- StringPointer := Ptr(Ord(@OldString));
- StringPointer^ := StringLength;
- {Now, compare the new string with the contents of the cell and decide
- whether the new string}
- {should come before or after this cell.}
- CompResult := RelString(NewString, OldString, false, true);
- case CompResult of
- sortsBefore, sortsEqual:
- done := true;
- SortsAfter:
- ;
- end;
- end
- else
- {There are no more rows, so that's all.}
- begin
- done := true;
- end;
- end;
-
- {Add the new row at the top of the list.}
- CellPoint.v := LAddRow(1, CellPoint.v, TheListHandle);
- {Put the string into the cell. Once again, there ought to be an easier
- way to do this.}
- LSetCell(Pointer(Ord(@NewString) + 1), Length(NewString), CellPoint,
- TheListHandle);
- end;
-
-
- procedure RenameCell;
- var
- CellPoint: Point;
- DataPtr: Ptr;
- DataLen: Integer;
- begin
- SetPt(CellPoint, 0, 0);
- DataPtr := Pointer(Ord(@OldString) + 1);
- dataLen := Length(OldString);
- if LSearch(dataPtr, dataLen, nil, CellPoint, TheListHandle) then
- begin
- DataPtr := Pointer(Ord(@NewString) + 1);
- dataLen := Length(NewString);
- LSetCell(DataPtr, dataLen, CellPoint, TheListHandle);
- end
- else
- begin
- {The programmer asked us to rename a cell which doesn't exist. We'll just
- beep angrily}
- {three times. It's the programmer's responsibility to see that the cell
- in question actually}
- {does exist before calling this routine.}
- Sysbeep(1);
- Sysbeep(1);
- Sysbeep(1);
- end;
- end;
-
-
- {Remove the cell with the given name from the list.}
- procedure DeleteCell;
- var
- CellPoint: Point;
- DataPtr: Ptr;
- DataLen: Integer;
- begin
- SetPt(CellPoint, 0, 0);
- DataPtr := Pointer(Ord(@TheString) + 1);
- dataLen := Length(TheString);
- if LSearch(dataPtr, dataLen, nil, CellPoint, TheListHandle) then
- begin
- LDelRow(1, CellPoint.v, TheListHandle);
- end
- else
- begin
- {The programmer asked us to delete a cell which doesn't exist. We'll just
- beep angrily}
- {three times. It's the programmer's responsibility to see that the cell
- in question actually}
- {does exist before calling this routine.}
- Sysbeep(1);
- Sysbeep(1);
- Sysbeep(1);
- end;
- end;
-
- {Get rid of the list when we're done with it, cleaning up all the memory.}
- procedure DisposList;
- begin
- LDispose(TheListHandle);
- end;
-
-
- end.
-
-
-
-
-
-
-