TweetFollow Us on Twitter

MACINTOSH C
MACINTOSH C: A Hobbyist's Guide To Programming the Mac OS in C
Version 2.3

© 2000 K. J. Bricknell

Go to Contents

(Chapter 20)

LISTS AND CUSTOM LIST DEFINITION FUNCTIONS

A link to the associated demonstration program listing is at the bottom of this page



Introduction to Lists

If you need the user to be able to select a single item from a small group of items, you typically provide a pop-up menu. Pop-up menus, however, do not allow the user to select multiple items from a group of items, are not especially suitable for the presentation of large numbers of items, and cannot present items in columns as well as rows. Furthermore, the items in a pop-up menu remain displayed only as long as the user holds the mouse button down.

By using lists to present a group of items to the user, you can overcome these limitations. Although lists, like pop-up menus, are generally used to solicit the user's choices, they can also be used to simply present information. Perhaps the most familiar example of such a list is that at the bottom of the window opened when you choose About This Computer... from the Finder's Apple menu.

In essence, then, the List Manager allows you to create either one-column or multi-column scrollable lists which may be used to simply present items of information or, as is most often the case, to enable the user to select one or more of a group of items.

By default, the List Manager creates lists which contain only monostyled text. However, with a little additional effort, you can create lists which display items graphically (as does the list on the left side of the window opened when you choose Chooser from the Apple menu), or which display more than one type of information in each item (as does the list in the About This Computer... window).

List Manager Limitations

Although the List Manager can handle small, simple lists effectively, it is not suitable for displaying large amounts of data such as, for example, that used by a spreadsheet application. The List Manager cannot maintain lists whose data occupies more than 32 KB of memory.

Options For Creating and Managing Lists

You can use the List Manager function LNew to create a list, in which case you must provide all the application-defined functions necessary to add rows and data to the list, handle mouse and keyboard events, etc. Alternatively, you can use the list box control to simplify the matter of list creation and handling.

The first section of this chapter addresses the former method and the subject of lists in general. The second section addresses the list box control, and indicates those areas in the first section which are not relevant when you use list box controls.

Historical Note

The list box control was introduced with Mac OS 8 and the Appearance Manager.

Appearance and Features of Lists

Fig 1 shows a dialog box with two typical single-column lists. The items in the list on the left are exclusively text items and the items in the list on the right are recorded pictures comprising a graphic and a title string. The list on the left supports the selection of multiple items.

To create a list with graphical elements, such as the list at the right at Fig 1, you must write a custom list definition function (see below), because the default list definition function only supports the display of text.

(Dialog with two lists)

Cells, Cell Font, and Cell Highlighting

Cells

A list is a series of items displayed within a rectangle. Each item is contained within an invisible rectangular cell. All cells within a list are of the same size, but cells may contain different types of data.

Cell Font

By default, lists inherit the font of the colour graphics port associated with the window or dialog box in which they reside. Ordinarily, your text-only lists should use the large or small system font

In the case of list control boxes, the font may be set using SetControlFontStyle or a 'dftb' resource.

Regardless of the font your application uses, if a string is too long to fit in its cell using the current font, the List Manager uses condensed type in an effort to make it fit. If the string is still too long, the List Manager truncates the string and appends the ellipsis character.

Cell HighLighting

Your application may or may not allow the user to select one or more cells in a list. If your application allows users to select cells, then, when the user selects a cell, the List Manager automatically highlights that cell.

Scroll Bars

Lists may contain a vertical scroll bar (see Fig 1), a horizontal scroll bar, or both. By using scroll bars, you can include more items in a list than can fit within the list's display rectangle, and the user can then scroll the list to view multiple items. If a list includes a scroll bar but the number of cells is such that they are all visible, the List Manager automatically disables the scroll bar.

Selection of Cells Using The Mouse

LClick

Your application must call LClick whenever a mouse-down occurs in an active list. LClick handles all user interaction until the user releases the mouse button. This includes cell highlighting and, when the user drags the mouse outside the list's display rectangle, automatic list scrolling. LClick also examines the state of the Shift and Command keys, which are central to the process of multiple cell selection in lists.

Multiple Cell Selection Using the Default Cell-Selection Algorithm

The List Manager's cell-selection algorithm allows the user to select a contiguous range of cells, or even several discontiguous ranges of cells, by using the Shift and Command keys in conjunction with the mouse.

If the user presses both the Shift and Command keys when clicking a cell, the Shift key is ignored.

The following describes the default cell-selection behaviour.

Cell Selection With the Shift Key

The user can extend a selection of just one cell to several contiguous cells by pressing the Shift key and clicking another item. By clicking and dragging with the Shift key down, the user can extend or shrink the range of selected cells. If the cursor is dragged outside the list's display rectangle, the list will scroll so as to enable the user to include cells which were not initially visible.

Cell Selection With the Command Key

To add or remove a range of cells from the current selection, the user can press the Command key and then drag the cursor over the other cells. The List Manager determines whether to add or remove selections in a range of cells by checking the status of the first cell clicked in. If that cell is initially selected, then Command-dragging deselects all cells in the range over which the cursor passes. If, on the other hand, that cell is initially not selected, Command-dragging selects all cells in the range over which the cursor passes.

Once the user changes a cell's selection status by Command-dragging over a cell, the selection status of the cell stays the same for the duration of the drag even if the user moves the cursor back over that cell. The effect of the Command key thus differs from that of the Shift key in this respect.

Shift-Clicking - Discontiguous Cells Selected

If the user Shift-clicks a cell after having created discontiguous selection ranges, the discontiguity is lost. The List Manager selects all cells in the range of the first selected cell (that is, the selected cell closest to the top of the list) and the newly selected cell - unless the newly selected cell precedes the first selected cell, in which case the List Manager selects all cells in the range of the newly selected cell and the last selected cell (that is, the selected cell closest to the bottom of the list.)

Customising the Cell-Selection Algorithm

As will be seen, the List Manager's cell-selection algorithm may easily be customised so as to modify its default behaviour. The most common modification is to defeat multiple cell selection, allowing the user to select only one cell.

Selection of Cells Using the Keyboard

Some users prefer to use the keyboard to select cells in lists. Your application should support the selection of cells using the keyboard in two ways:

  • Cell Selection Using Arrow Keys. Your application should support the use of the Arrow keys to move and extend cell selections.

  • Type Selection. If your application uses text-only lists (or lists whose items can be identified by text strings), your application should allow the user to select an item by simply typing the text associated with that item. This method of cell selection is known as type selection.
The List Manager does not provide any functions to support cell selection by Arrow key or type selection. Accordingly, your application must supply all of the necessary code. The following describes what that code should do.

Moving the Selection Using Arrow Keys

Shift and Command Keys Not Down

When the user presses an Arrow key, and is not at the same time pressing the Shift or Command key, the user is attempting to move the selection by one cell.

If the user presses the Up Arrow, for example, your application should respond by selecting the cell which is above the first selected cell and by deselecting all other selected cells. (Of course, if the first selected cell is the topmost cell in the list, your application should respond by simply deselecting all cells other than the first selected cell.) If necessary, your application should then scroll the list to ensure that the newly-selected cell is visible.

Command Key Down

When the user presses an Arrow key while the Command key is down, your application should move the first selected cell or the last selected cell, depending on which arrow key is used, as far as it can move in the appropriate direction. For example, in a single-column list, pressing of the Up Arrow key should select the first cell in the list and deselect all other cells. Once again, your application should scroll the list, if necessary, to ensure that the newly-selected cell is visible.

Extending the Selection Using Arrow Keys

When the user presses an Arrow key while the Shift key is down, the user is attempting to extend the selection. There are two different algorithms your application can use to respond to Shift-Arrow key combinations: the extend algorithm and the anchor algorithm. The easiest one to implement is the extend algorithm.

The Extend Algorithm

Using the extend algorithm, your application simply finds the first (or last) selected cell, and then selects another cell in the direction of the Arrow key. For example, if the user presses Shift-Down Arrow in a single-column list, the application should find the last selected cell and select the cell immediately below it, or, if the user presses Shift-Up Arrow, the application should find the first selected cell and select the cell above it. As always, the list should then be scrolled, if necessary, to make the newly-selected cell visible.

Type Selection

In a text-only list, when the user types the text of an item in a list, your application should respond by scrolling to the cell containing that text and selecting it.

However, rather than requiring the user to type the entire text of the item before searching for a match, your application should repeatedly search for a match as each character is entered. Accordingly, every time the user types a character, your application should add it to a string. If this string is currently two characters long, for example, your application should then walk the cells of the list, comparing these two characters with the first two characters of the text in each cell. If a match is found, that cell should be selected and the list scrolled, if necessary, to make the cell visible.

Your application should automatically reset the internal string to a null string when the user has not pressed a key for a given amount of time. To make your application consistent with other applications and the Finder, this time should be twice the number of ticks contained in the low memory global KeyThresh or 120 ticks, whichever is the greater.

The value in KeyThresh is set by the user at the "Delay Until Repeat" section of the Keyboard control panel. Call LMGetKeyThresh to obtain this value.

Implementing Type Selection

To implement type selection, your application must keep a record of the characters the user has typed, the time when the user last typed a character, the amount of time which must elapse since that last character was typed before the type selection string is reset, and which list the last typed character affected. The following shows the variables you might use for this purpose, together with their usage:

Variable Name Type Usage
gTSString Str255 Stores the string which represents current status of the type selection.
gTSThresh short Stores the number of ticks after which type selection resets. For example, if the user types "abcde'" but waits for more than gTSThresh, before typing "f", the application should set gTSString to "f", not "abcdef".
gTSElapse long Stores the time in ticks of the last key-down.
gTSLastListHit ListHandle Stores the list affected by the last typed character.

Creating, Disposing Of, and Managing Lists

The List Structure

The list structure, which the List Manager uses to keep track of information about a list, is central to the creation and management of lists. In most cases, your application can get or set information in a list structure using List Manager functions.

Before describing the list structure, however, it is necessary to describe another data type used exclusively by the List Manager, that is, the Cell data type.

The Cell Data Type

Each cell in a list can be described by a data structure of type Cell, which has the same structure as the Point data type:

     typedef Point Cell;

The Cell data type's fields, however, have a different meaning from those of the Point data type. In the Cell data type, the h field specifies the row number and the v field specifies the column number. The first cell in a list is defined as cell (0,0). Fig 2 shows a multi-column list in which each cell's text is set to the coordinates of the cell.

(Coordinates of cells)

The ListRec Data Type

The list structure is defined by the ListRec data type:

     struct ListRec 
     {
       Rect             rView;        // List's display rectangle.
       GrafPtr          port;         // List's graphics port.
       Point            indent;       // Indent distance for drawing.
       Point            cellSize;     // Size in pixels of a cell.
       Rect             visible;      // Boundary of visible cells.
       ControlRef       vScroll;      // Vertical scroll bar.
       ControlRef       hScroll;      // Horizontal scroll bar.
       SInt8            selFlags;     // Selection flags.
       Boolean          lActive;      // true if list is active.
       SInt8            lReserved;    // (Reserved.)
       Sint8            listFlags;    // Automatic scrolling flags.
       long             clikTime;     // TickCount at time of last tick.
       Point            clikLoc;      // Position of last click.
       Point            mouseLoc;     // Current mouse location.
       ListClickLoopUPP lClickLoop;   // Function called by LClick.
       Cell             lastClick;    // Last cell clicked.
       long             refCon;       // For application use.
       Handle           listDefProc;  // List definition function.
       Handle           userHandle;   // For application use.
       ListBounds       dataBounds;   // Boundary of cells allocated.
       DataHandle       cells;        // Cell data.
       short            maxIndex;     // (Used internally.)
       short            cellArray[1]; // Offsets to data.
     };

     typedef struct ListRec ListRec;
     typedef ListRec *ListPtr;
     typedef ListPtr *ListHandle;

Field Descriptions

rView Specifies the list's display rectangle in the local coordinates of the graphics port specified by the port field (see below). Note that the display rectangle does not include the area occupied by a list's scroll bars.
port The graphics port of the window containing the list.
indent Indicates the location, relative to the upper left corner of the cell, at which drawing should begin. For example, the default list definition function sets the vertical coordinate of this field to near the bottom of the cell so that characters drawn with QuickDraw's DrawText function are centred vertically in the cell.
cellSize Specifies the size in pixels of each cell in the list. For text-only lists, you usually let the List Manager automatically calculate the cell dimensions. In this case, the List Manager determines the vertical size of a cell by adding the ascent, descent and leading of the port's font (which works out as 16 pixels for 12-point Charcoal for example). You should make the height of your list equal to a multiple of this height. The default horizontal size of a cell is determined by dividing the width of the list's display rectangle by the number of columns in the list.
visible The visible field specifies which cells in a list are visible within the rectangle specified by the rView field. The List Manager sets the left and top fields to the coordinates of the first visible cell, and it sets the right and bottom fields to so that each is one greater than the horizontal and vertical coordinates of the last visible cell. For example, if a list contains 4 columns and 10 rows but only the first two columns and five rows are visible (that is, the last visible cell has coordinates (1,4), the List Manager sets the visible field to (0,0,2,5).

The List Manager sets the right and bottom fields to one greater than the horizontal and vertical coordinates of the last visible cell so as to facilitate the use of QuickDraw's PtInRect function to determine whether a cell is currently visible. When PtInRect is used for this purpose, a Cell variable is passed as the first parameter and the visible field is passed as the second parameter. Recall from Chapter 12 - Drawing With QuickDraw that the mathematical borders of a rectangle are infinitely thin and that the displayed rectangle of pixels "hangs" down and to the right of the mathematical rectangle. When PtInRect's parameters are expressed as cell coordinates, it is the cells which "hang" down and to the right of the mathematical rectangle. Thus, in the above example, if the cell passed as the first parameter to PtInRect specifies row 5 or higher or column 2 or higher, PtInRect returns false.

The fact that the visible field is set in this way also means that the number of visible rows and columns may be determined by simply subtracting the value in the top field from the value in the bottom field (rows) and the value in the left field from the value in the right field (columns).

vScroll A handle to the vertical scroll bar, or NULL if the list does not have a vertical scroll bar.
hScroll A handle to the horizontal scroll bar, or NULL if the list does not have a horizontal scroll bar.
selFlags Specifies the algorithm the List Manager uses to select cells in response to a click in the list.
lActive true if a list is active or false if it is inactive. Do not change this field directly. Use LActivate to activate or deactivate a list.
listFlags Indicates whether automatic vertical and horizontal scrolling is enabled. If automatic scrolling is enabled, then a list scrolls when the user clicks a cell and then drags the cursor out of the rectangle specified by the rView field. By default, the List Manager enables automatic scrolling if the list has the associated scroll bar (horizontal or vertical). The following constants define bits in this field which determine whether horizontal or vertical autoscrolling are enabled:

     lDoVAutoscroll = 2  Allows vertical scrolling.
     lDoHAutoscroll = 1  Allows horizontal scrolling.
clikTime Indicates the time when the user last clicked the mouse.
clikLoc Indicates the local coordinates of the last mouse click.
mouseLoc Indicates the current location of the cursor in local coordinates. Ordinarily you would use the Event Manager's GetMouse function to obtain this information, but this field may be more convenient to access from within a click-loop function (see below).
lClickLoop Contains a universal procedure pointer to a click-loop function continually called by LClick, or NULL if the default click loop function is to be used. Your application may place a universal procedure pointer to a custom click-loop function in this field.

It is unlikely that your application will need to define its own click-loop function because the List Manager's default click-loop function uses a rather robust algorithm to respond to mouse clicks. Your application needs a custom function only if it needs to perform some special processing while the user drags the cursor after clicking in a list.

lastClick Indicates the cell coordinates of the last click. You can access the value in this field using LLastClick. If your application depends on the accuracy of the information in this field and the clikTime and clikLoc fields, and if your application treats keyboard selection of list items identically to mouse selection of list items, then it should update the values of these fields after highlighting a cell in response to a keyboard event.
refCon For your application's use.
listDefProc Contains a handle to the code used by the list definition function.
userHandle For your application's use. Typically, an application uses this field to store a handle to some additional storage associated with a list.
dataBounds Specifies the total cell dimensions of the list, including cells which are not visible. It is similar to the visible field in that its right and bottom fields are each set to one greater than the horizontal and vertical coordinates of the last cell - except that, in this case, the "last cell" is the last cell in the list, not the last cell in the display rectangle. For example, if a list contains 4 columns and 10 rows (that is, the last cell in the list has coordinates (3,9)), the List Manager sets the dataBounds field to (0,0,4,10).
cells Contains a handle to a relocatable block used to store cell data. The handle is defined like this:

     typedef char DataArray[32001];
     typedef char *DataPtr;
     typedef DataPtr *DataHandle;
     
Because of the way the cells field is defined, therefore, no list can contain more than 32,000 bytes of data.
cellArray Used to store offsets to data in the relocatable block specified by the cells field. Your application should not change the cells field directly or access the information in the cellArray field directly. The List Manager provides functions for manipulating the information in the list.

The fields of a list structure that you will be most concerned with are the rView, port, cellSize, visible, and dataBounds fields.

Creating a List

LNew

You create a list using LNew:

     ListHandle	LNew(const Rect *rView,const ListBounds *dataBounds,Point cSize,
                     short theProc,WindowRef theWindow,Boolean drawIt,Boolean hasGrow,
                     Boolean scrollHoriz,Boolean scrollVert);

rView The rectangle in which to display the list, in local coordinates. (Does not include the area taken up by the list's scroll bars.)
dataBounds The initial data bounds for the list. Set the left and top fields to (0,0) and the right and bottom fields to kInitialColumns and kInitialRows, to create a list with kInitialColumns columns and kInitialRows rows.
cSize The size of each cell in the list. If your application specifies (0,0) and is using the default list definition function, the List Manager computes the size automatically, setting the v field to the sum of the ascent, descent, and leading of the current font and the h field using the following formula:

     cSize.h = (rView.right - rView.left) / 
     dataBounds.right - dataBounds.left)
theProc The resource ID of the list definition function to use for the list. To use the default list definition function, specify 0.
theWindow Pointer to the window in which to install the list.
drawIt Indicates whether automatic drawing mode is initially enabled. When automatic redrawing is enabled (by setting this parameter to true), the list is automatically redrawn whenever a change is made to it.

You can later change this setting using LSetDrawingMode. If your application chooses to disable automatic drawing mode (for example, for aesthetic reasons while adding rows and columns to a list) it should do so only for short periods of time.

hasGrow Indicates whether space should be left for a size box.
scrollHoriz Specify true if your list requires a horizontal scroll bar, otherwise specify false.
scrollVert Specify true if your list requires a vertical scroll bar, otherwise specify false.

Drawing List Box Frames and Focus Rectangles

List Box Frame. The List Manager does not draw the list box frame around the list. Accordingly, this must be drawn by your application.

Focus Rectangle. In a window with multiple lists, you need to indicate to the user which list is the current list, that is, which list is the target of current mouse and keyboard activity. Accordingly, you should draw a focus rectangle around the current list. (See the list on the left at Fig 1). The focus rectangle should be removed when the window or dialog box containing the lists is deactivated.

A single list in a window should also be outlined with a focus rectangle if keyboard input could have some other effect in the window not related to the list (for example, if the list is in a dialog box containing both a list and an editable text item).

Disposing of a List

When you are finished with a list, you should dispose of it using LDispose, which disposes of the list structure as well as the data associated with the list. LDispose does not, however, dispose of any application-specific data you may have stored in a relocatable block specified by the userHandle field of the list structure. This should be separately disposed of before the call to LDispose.

Adding Rows and Columns to a List

When an application creates a list, it might choose to, for example, pre-allocate the columns it needs and then add rows to the list one by one. It might also create the list and add both rows and columns to it later.

Rows are inserted into a list using LAddRow and deleted using LDelRow. Columns are inserted in a list using LAddColumn and deleted using LDelColumn.

Disabling and Enabling the Automatic Drawing Mode

LSetDrawingMode should be used to turn off the automatic drawing mode before making changes to a list. After the changes have been made, LSetDrawingMode should be called again, this time to turn the automatic drawing mode back on.

InvalRect should be called after the second call to LSetDrawingMode to invalidate the rectangle containing the list and its scroll bars. LUpdate, which should be called when your application receives an update event, will then redraw the list.

Responding to Events in a List

Mouse-Down Events

As previously stated, when a mouse-down event occurs in a list, including in the associated scroll bar areas, your application must call LClick. If the click is outside the list's display rectangle or scroll bars, LClick returns immediately, otherwise it handles all user interaction until the user releases the mouse button. While the mouse button is down, the List Manager performs scrolling as necessary, selects or de-selects cells as appropriate, and adjusts the scroll bars.

Note that LClick returns true if the click was a double click. If the list is in a dialog box, your application should respond to a double click in the same way that it would respond to a click on the default (OK) button.

In the case of multiple lists, if the mouse-down occurs inside a non-current list's display rectangle or scroll bar area, your application should call its application-defined function for changing the current list.

Key-Down Events

If a key-down event is received, and assuming that your application supports cell selection by Arrow key and/or type selection, your application should call its appropriate application-defined functions. In the case of multiple lists, your application should also respond to Tab key presses by changing the current list.

Update Events

If an update event is received, your application must call LUpdate to redraw the list. The region specified in the first parameter to the LUpdate call is usually the window's visible region as retrieved from the colour graphics port's visRgn field.

Your application will also need to draw the list box frame in the correct state (window active or inactive) and, if a focus rectangle is required and the window is active, the focus rectangle.

Activate Events

If a window containing a list is activated or deactivated, your application must call LActivate to activate or deactivate the list as appropriate. Your application will also need to draw the list box frame in the correct state, and either draw or erase the keyboard focus rectangle, depending on whether the window is becoming active or inactive.

If your application supports type selection in a list, it will also need to reset certain type selection variables when the window containing that list is becoming active.

Getting and Setting List Selections

The List Manager provides functions for determining which cells are currently selected and for selecting and deselecting cells. LGetSelect is used to either determine whether a specified cell is selected or to keep advancing from a specified starting cell until the next selected cell is found. LSetSelect is used to select or deselect a specified cell.

LNextCell, which simply advances from one cell in a list to the next, is often used in application-defined functions associated with getting and setting list selections.

Scrolling a List

LAutoScroll may be used to scroll the first selected cell to the upper-left corner of the list's display rectangle.

LScroll allows your application to scroll the list by a specified number of rows and/or columns. Typically, you would use LScroll when you want your application to scroll a list just enough so that a certain cell (such as the cell the user has just selected using the an Arrow key or type selection) is visible.

Storing, Adding To, Getting, and Clearing Cell Data

Storing Data

Your application can store data in a cell using LSetCell. LSetCell's parameters include a pointer to the data, the length of the data, the location of the cell whose data you wish to set, and a handle to the list containing the cell. The data stored in a cell might be sourced from, for example, a string list resource.

Adding to Data

Your application can append data to a cell using LAddToCell.

Getting Cell Data

LGetCell may be used to copy the contents of a cell into a buffer. LGetCellDataLocation may be used to obtain the address and length of a cell's data. Unlike LGetCell, LGetCellDataLocation does not make a copy of the data, and should thus be used when you want to access, but not manipulate, the data.

Clearing Data

Your application can remove all data from a cell using LClrCell.

Searching a List

Your application can use LSearch to search through a list for a particular item. LSearch takes, as one parameter, a universal procedure pointer to a match function. If NULL is specified for this parameter, LSearch searches the list for the first cell whose data matches the specified data, calling the Text Utilities IdenticalString function to compare each cell's data with the specified data until IdenticalString returns 0, indicating that a match has been found.

Custom Match Functions

The default match function is useful for text-only lists. Your application can use a different match function to facilitate searches in other types of lists as long as that function is defined just like IdenticalString.

A common custom match function is one which supports type selection in lists, that is, one which works like the default match function but which allows the cell data to be longer than the data being searched for. For example, a search for the string "be" would match a cell containing the string "Beams".

Changing the Current List

As previously stated, when a window or dialog box contains multiple lists, your application should allow the user to change the current list by clicking in one of the non-current lists or by pressing the Tab key or Shift-Tab. In a window with more than two lists, Tab key presses should make the next list in a pre-determined sequence the current list, and Shift-Tab should make the previous list in that sequence the current list. The pre-determined sequence is best implemented using a linked ring.

Linked Ring

Your application can use the refCon field of each list structure to create the linked ring. The refCon field of the first list is assigned the handle to the second list, the refCon field of the second list is assigned the handle to the third list, and so on, until the refCon field of the last list is assigned the handle to the first list. Then, in response to a Tab key press in the current list, your application can determine the next list in the sequence by looking at the current list's refCon field.

Responding to Shift-Tab is a little more complex. The following example application-defined function shows how this can be done:

     ListHandle	gCurrentListHdl;

     void  doFindPreviousListInRing(void)
     {
       ListHandle listHdl;

       listHdl = gCurrentListHdl;

       while((ListHandle) (*listHdl)->refCon != gCurrentList)
         listHdl = (ListHandle) (*listHdl)->refCon;

       gCurrentListHdl = listHdl;
     }

Customising the Cell-Selection Algorithm

You can modify the algorithm the List Manager uses to select cells in response to mouse clicking and dragging by changing the value in the selFlags field of the list structure. (Recall that, by default, mouse clicks deselect all cells and select the current cell, Shift-click and Shift-drag extend the selection as a rectangular range, and Command-click and Command drag toggle selections according to the selection state of the initial cell.)

The bits in the selFlags field are represented by the following constants. Those constants, and the effect the values they represent have on the cell-selection algorithm, are as follows:

Constant Value Effect
lOnlyOne 128 Allow only one cell to be selected at any one time.
lExtendDrag 64 Allow the user to select a range of cells by clicking the first cell and dragging to the last cell without necessarily pressing the Shift or Command key. (Ordinarily, dragging in this manner results in only the last cell being selected.)
lNoDisjoint 32 Prevent discontiguous selections using the Command key, while still allowing the user to select a contiguous range of cells.
lNoExtend 16 Cause all previously selected cells to be deselected when the user Shift-clicks.
lNoRect 8 Disable the feature which allows the user to shrink a selection by Shift-clicking to select a range of cells and then dragging the cursor to a position within that range. (With this feature is disabled, all cells in the cursor's path during a Shift-drag become selected even if the user drags the cursor back over the cell.)
lUseSense 4 Allow the user to deselect a range of cells by Shift-dragging. (Ordinarily, Shift-dragging causes cells to become selected even if the first cell clicked is already selected.)
lNoNilHilite 2 Turn off the highlighting of cells which contain no data. (Note that the this constant is somewhat different from the others in that it affects the display of a list, not the way that the List Manager selects items in response to a click.)

These constants are often used additively. For example, you could make the Shift key work just like the Command key using the following code:

     (*listHdl)->selFlags = lNoRect + lNoExtend + lUseSense;

If your application customises the cell-selection algorithm in lists which allow multiple cell selection, it should make the non-standard behaviour clear to the user. Typically, this is done by displaying explanatory text above the list's display rectangle.

The List Box Control

The list box control reduces the programming effort involved in managing lists. Basically, this control frees your application from the requirement to provide its own functions for attending to mouse and keyboard interaction with the list (except for type selection). To create and manage lists using the list box control, you need to:

  • Provide a list box 'CNTL' resource and a list box description ('ldes') resource (see below).

  • Provide application-defined functions for storing data in the list's cells and, where required, for adding rows and/or columns.

  • Provide an application-defined function to support type selection, if required.

  • Modify the list's cell selection algorithm, if required.

  • Provide an application-defined function which searches for, and returns the data in, the selected cell or cells.
The handle to the control is assigned to the refCon field of the list structure. This allows a custom list definition function to determine whether the control should be drawn in the activated or deactivated state by looking at the contrlHilite field of the control structure.

List Box Variants, Values, Constants, and Resources

Variant and Control Definition ID

The list box CDEF resource ID is 22. The two available variants and their control definition IDs are as follows:

Variant Var Code Control Definition ID
List box. 0 352 kControlListBoxProc
Autosizing list box. 1 353 kControlListBoxAutoSizeProc

Control Values

Control Value Content
Initial Resource ID of the 'ldes' resource holding the list box information. Reset to 0 after creation. An initial value of 0 indicates not to read an 'ldes' resource. (See The List Box Description Resource, below.)
Minimum Reserved. Set to 0.
Maximum Reserved. Set to 0.

Control Data Tag Constants

Control Data Tag Constant Meaning and Data Type Returned or Set
kControlListBoxListHandleTag Gets a handle to a list box.

Data type returned or set: ListHandle

kControlListBoxDoubleClickTag Checks to see whether the most recent click in a list box was a double click.

Data type returned or set: Boolean. If true, the last click was a double click. If false, not.

kControlListBoxLDEFTag Sets the 'LDEF' resource to be used to draw a list box's contents. This is useful for creating a list box without an 'ldes' resource.

Data type returned or set: SInt16

kControlListBoxKeyFilterTag Gets or sets a key filter function.

Data type returned or set:ControlKeyFilterUPP

kControlListBoxFontStyleTag Gets or sets the font style.

Data type returned or set: ControlFontStyleRec

Control Part Codes

Constant Value Description
kControlListBoxPart 24 Event occurred in a list box.
kControlListBoxDoubleClickPart 25 Double-click occurred in a list box.

The List Box Description Resource

You can use a list box description resource to specify information in a list box. A list box description resource is a resource of type 'ldes'. All list box description resources must have resource ID of greater than 127. The Control Manager uses the information you specify to provide additional information to the corresponding list box control. Fig 3 shows the structure of a compiled 'ldes' resource.

('ldes' resource)

The following describes the main fields of a compiled 'ldes' resource:

Field Description
NUMBER OF ROWS An integer specifying the number of rows in the list box.
NUMBER OF COLUMNS An integer specifying the number of columns in the list box.
CELL HEIGHT An integer specifying the height of a list item. If 0 is specified, the list item height is automatically calculated.
CELL WIDTH An integer specifying the width of a list item. If 0 is specified, the list item width is automatically calculated.
HAS VERTICAL SCROLL BAR A Boolean value that indicates whether the list box should contain a vertical scroll bar. If true, the list box contains a vertical scroll bar. If false, no vertical scroll bar.
HAS HORIZONTAL SCROLL BAR A Boolean value that indicates whether the list should contain a horizontal scroll bar. Specify true if your list requires a horizontal scroll bar. Specify false otherwise.
RESOURCE ID The resource ID of the list definition function to use for the list. To use the default list definition function, which supports the display of unstyled text, specify a resource ID of 0.
HAS SIZE BOX A Boolean value that indicates whether the List Manager should leave room for a size box. If true, a size box will be drawn. If false, a size box will not be drawn.

Custom List Definition Functions

As previously stated, the default list definition function supports the display of unstyled text only. If your application needs to display items graphically, or display more than one type of information in each cell, you must create your own list definition function.

For example, the Finder's About This Computer... dialog box contains a single-column list of applications currently in use. Each cell in the list contains an icon, the name of the application, the amount of memory in the application partition, and a graphical indication of how much of that memory has been used.

After writing a list definition function, you must compile it as a resource of type 'LDEF' and store it in the resource fork of the application that uses the function.

Your custom list definition function must be defined like this:

     pascal void  listDef (SInt16 lMessage,Boolean lSelect,Rect *lRect,Cell lCell,
                           SInt16 lDataOffset,SInt16 lDataLen,ListHandle lHandle);

Messages Sent by List Manager

In essence, the sole requirement of your list definition function is to respond appropriately to four types of messages sent to it by the List Manager, and which are received in the lMessage parameter. The following constants define the four message types:

Constant Value Meaning
lInitMsg 0 Do any special list initialisation.
lDrawMsg 1 Draw the cell.
lHiliteMsg 2 Invert the cell's highlight state.
lCloseMsg 3 Take any special disposal action.

The lSelect, lRect, lCell, lDataOffset, and lDataLen parameters pass information to your list definition function only when the value in the lMessage parameter contains either the lDrawMsg or lHiliteMsg constants. These parameters provide information about the cell affected by the message. The selected parameter indicates whether the cell should be highlighted. The lRect and lCell parameters indicate the cell's rectangle and coordinates. The lDataOffset and lDataLen parameters specify the offset and length of the cell's data within the relocatable block referenced by the cells field of the list structure.

Responding to the Initialisation Message

The List Manager automatically allocates memory for a list and fills out the fields of a list structure before calling your list definition function with an lInitMsg message. Your application might respond to the initialisation message by changing, say, the cellSize and indent fields of the list structure. However, many list definition functions do not need to perform any action in response to the lInitMsg message.

Responding to the Draw Message

The list definition function must respond to the draw message by examining the specified cell's data and drawing the cell as appropriate, ensuring that the characteristics of the drawing environment are not altered.

Responding to the HighLighting Message

Virtually every list definition function should respond to the lHiliteMsg message in the same way, that is, by highlighting the cell's rectangle. The following example shows how this might be done:

     void  doLDEFHighlight(Rect *cellRect)
     {
       UInt8  hiliteVal;

       hiliteVal = LMGetHiliteMode();
       BitClr(&hiliteVal,pHiliteBit);
       LMSetHiliteMode(hiliteVal);

       InvertRect(cellRect);
     }

Responding to the Close Message

The List Manager sends your list definition function the lCloseMsg immediately before disposing of the memory occupied by list. Your list definition function needs to respond only if it needs to perform some special processing before a list is disposed of, such as releasing memory associated with the list that would not be released by LDispose.


Main List Manager Constants, Data Types, and Functions

Constants

Masks For listFlags Field of List Structure

lDoVAutoscroll  = 2  Allow vertical autoscrolling.
lDoHAutoscroll  = 1  Allow horizontal autoscrolling.

Masks For selFlags Field of List Structure

lOnlyOne      = -128  Allow only one item to be selected at once.
lExtendDrag   = 64  Enable multiple item selection without Shift.
lNoDisjoint   = 32  Prevent discontiguous selections.
lNoExtend     = 16  Reset list before responding to Shift-click.
lNoRect       = 8  Shift-drag selects items passed by cursor.
lUseSense     = 4  Allow use of Shift key to deselect items.
lNoNilHilite  = 2  Disable highlighting of empty cells.

Messages to List Definition Function

lInitMsg    = 0  Do any special list initialisation.
lDrawMsg    = 1  Draw the cell.
lHiliteMsg  = 2  Invert cell's highlight state.
lCloseMsg   = 3  Take any special disposal action.

Data Types

typedef Point Cell;
typedef Rect ListBounds;
typedef char DataArray[32001];
typedef char *DataPtr;
typedef DataPtr *DataHandle;

List Structure

struct ListRec 
{
  Rect             rView;        // List's display rectangle.
  GrafPtr          port;         // List's graphics port.
  Point            indent;       // Indent distance for drawing.
  Point            cellSize;     // Size in pixels of a cell.
  Rect             visible;      // Boundary of visible cells.
  ControlRef       vScroll;      // Vertical scroll bar.
  ControlRef       hScroll;      // Horizontal scroll bar.
  SInt8            selFlags;     // Selection flags.
  Boolean          lActive;      // true if list is active.
  SInt8            lReserved;    // (Reserved.)
  Sint8            listFlags;    // Automatic scrolling flags.
  long             clikTime;     // TickCount at time of last tick.
  Point            clikLoc;      // Position of last click.
  Point            mouseLoc;     // Current mouse location.
  ListClickLoopUPP lClickLoop;   // Function called by LClick.
  Cell             lastClick;    // Last cell clicked.
  long             refCon;       // For application use.
  Handle           listDefProc;  // List definition function.
  Handle           userHandle;   // For application use.
  ListBounds       dataBounds;   // Boundary of cells allocated.
  DataHandle       cells;        // Cell data.
  short            maxIndex;     // (Used internally.)
  short            cellArray[1]; // Offsets to data.
};
typedef struct ListRec ListRec;
typedef ListRec *ListPtr;
typedef ListPtr *ListHandle;

Functions

Creating and Disposing of Lists

ListHandle  LNew(const Rect *rView,const ListBounds *dataBounds,Point cSize,
                 short theProc,WindowRef theWindow,Boolean drawIt,Boolean hasGrow,
                 Boolean scrollHoriz,Boolean scrollVert);
void        LDispose(ListHandle lHandle);

Adding and Deleting Rows and Columns

short  LAddColumn(short count,short colNum,ListHandle lHandle);
short  LAddRow(short count,short rowNum,ListHandle lHandle);
void   LDelColumn(short count,short colNum,ListHandle lHandle);
void   LDelRow(short count,short rowNum,ListHandle lHandle);

Determining or Changing a Selection

Boolean  LGetSelect(Boolean next,Cell *theCell,ListHandle lHandle);
void     LSetSelect(Boolean setIt,Cell theCell,ListHandle lHandle);

Accessing and Manipulating Data Cells

void  LSetCell(const void *dataPtr,short dataLen,Cell theCell,ListHandle lHandle);
void  LAddToCell(const void *dataPtr,short dataLen,Cell theCell,ListHandle lHandle);
void  LClrCell(Cell theCell,ListHandle lHandle);
void  LGetCellDataLocation(short *offset,short *len,Cell theCell,ListHandle lHandle);
void  LGetCell(void *dataPtr,short *dataLen,Cell theCell,ListHandle lHandle);

Responding to Events

Boolean  LClick(Point pt,short modifiers,ListHandle lHandle);
void     LUpdate(RgnHandle theRgn,ListHandle lHandle);
void     LActivate(Boolean act,ListHandle lHandle);

Modifying a List's Appearance

void  LSetDrawingMode(Boolean drawIt,ListHandle lHandle);
void  LDraw(Cell theCell,ListHandle lHandle);
void  LAutoScroll(ListHandle lHandle);
void  LScroll(short dCols,short dRows,ListHandle lHandle);

Searching For a List Containing a Particular Item

Boolean  LSearch(const void *dataPtr,short dataLen,ListSearchUPP searchProc,
         Cell *theCell,ListHandle lHandle);

Changing the Size of Cells and Lists

void  LSize(short listWidth,short listHeight,ListHandle lHandle);
void  LCellSize(Point cSize,ListHandle lHandle);

Getting Information About Cells

Boolean  LNextCell(Boolean hNext,Boolean vNext,Cell *theCell,ListHandle lHandle);
void     LRect(Rect *cellRect,Cell theCell,ListHandle lHandle);
Cell     LLastClick(ListHandle lHandle);

Go to Demo

 

Community Search:
MacTech Search:

Software Updates via MacUpdate

Latest Forum Discussions

See All

Whitethorn Games combines two completely...
If you have ever gone fishing then you know that it is a lesson in patience, sitting around waiting for a bite that may never come. Well, that's because you have been doing it wrong, since as Whitehorn Games now demonstrates in new release Skate... | Read more »
Call of Duty Warzone is a Waiting Simula...
It's always fun when a splashy multiplayer game comes to mobile because they are few and far between, so I was excited to see the notification about Call of Duty: Warzone Mobile (finally) launching last week and wanted to try it out. As someone who... | Read more »
Albion Online introduces some massive ne...
Sandbox Interactive has announced an upcoming update to its flagship MMORPG Albion Online, containing massive updates to its existing guild Vs guild systems. Someone clearly rewatched the Helms Deep battle in Lord of the Rings and spent the next... | Read more »
Chucklefish announces launch date of the...
Chucklefish, the indie London-based team we probably all know from developing Terraria or their stint publishing Stardew Valley, has revealed the mobile release date for roguelike deck-builder Wildfrost. Developed by Gaziter and Deadpan Games, the... | Read more »
Netmarble opens pre-registration for act...
It has been close to three years since Netmarble announced they would be adapting the smash series Solo Leveling into a video game, and at last, they have announced the opening of pre-orders for Solo Leveling: Arise. [Read more] | Read more »
PUBG Mobile celebrates sixth anniversary...
For the past six years, PUBG Mobile has been one of the most popular shooters you can play in the palm of your hand, and Krafton is celebrating this milestone and many years of ups by teaming up with hit music man JVKE to create a special song for... | Read more »
ASTRA: Knights of Veda refuse to pump th...
In perhaps the most recent example of being incredibly eager, ASTRA: Knights of Veda has dropped its second collaboration with South Korean boyband Seventeen, named so as it consists of exactly thirteen members and a video collaboration with Lee... | Read more »
Collect all your cats and caterpillars a...
If you are growing tired of trying to build a town with your phone by using it as a tiny, ineffectual shover then fear no longer, as Independent Arts Software has announced the upcoming release of Construction Simulator 4, from the critically... | Read more »
Backbone complete its lineup of 2nd Gene...
With all the ports of big AAA games that have been coming to mobile, it is becoming more convenient than ever to own a good controller, and to help with this Backbone has announced the completion of their 2nd generation product lineup with their... | Read more »
Zenless Zone Zero opens entries for its...
miHoYo, aka HoYoverse, has become such a big name in mobile gaming that it's hard to believe that arguably their flagship title, Genshin Impact, is only three and a half years old. Now, they continue the road to the next title in their world, with... | Read more »

Price Scanner via MacPrices.net

B&H has Apple’s 13-inch M2 MacBook Airs o...
B&H Photo has 13″ MacBook Airs with M2 CPUs and 256GB of storage in stock and on sale for up to $150 off Apple’s new MSRP, starting at only $849. Free 1-2 day delivery is available to most US... Read more
M2 Mac minis on sale for $100-$200 off MSRP,...
B&H Photo has Apple’s M2-powered Mac minis back in stock and on sale today for $100-$200 off MSRP. Free 1-2 day shipping is available for most US addresses: – Mac mini M2/256GB SSD: $499, save $... Read more
Mac Studios with M2 Max and M2 Ultra CPUs on...
B&H Photo has standard-configuration Mac Studios with Apple’s M2 Max & Ultra CPUs in stock today and on Easter sale for $200 off MSRP. Their prices are the lowest available for these models... Read more
Deal Alert! B&H Photo has Apple’s 14-inch...
B&H Photo has new Gray and Black 14″ M3, M3 Pro, and M3 Max MacBook Pros on sale for $200-$300 off MSRP, starting at only $1399. B&H offers free 1-2 day delivery to most US addresses: – 14″ 8... Read more
Department Of Justice Sets Sights On Apple In...
NEWS – The ball has finally dropped on the big Apple. The ball (metaphorically speaking) — an antitrust lawsuit filed in the U.S. on March 21 by the Department of Justice (DOJ) — came down following... Read more
New 13-inch M3 MacBook Air on sale for $999,...
Amazon has Apple’s new 13″ M3 MacBook Air on sale for $100 off MSRP for the first time, now just $999 shipped. Shipping is free: – 13″ MacBook Air (8GB RAM/256GB SSD/Space Gray): $999 $100 off MSRP... Read more
Amazon has Apple’s 9th-generation WiFi iPads...
Amazon has Apple’s 9th generation 10.2″ WiFi iPads on sale for $80-$100 off MSRP, starting only $249. Their prices are the lowest available for new iPads anywhere: – 10″ 64GB WiFi iPad (Space Gray or... Read more
Discounted 14-inch M3 MacBook Pros with 16GB...
Apple retailer Expercom has 14″ MacBook Pros with M3 CPUs and 16GB of standard memory discounted by up to $120 off Apple’s MSRP: – 14″ M3 MacBook Pro (16GB RAM/256GB SSD): $1691.06 $108 off MSRP – 14... Read more
Clearance 15-inch M2 MacBook Airs on sale for...
B&H Photo has Apple’s 15″ MacBook Airs with M2 CPUs (8GB RAM/256GB SSD) in stock today and on clearance sale for $999 in all four colors. Free 1-2 delivery is available to most US addresses.... Read more
Clearance 13-inch M1 MacBook Airs drop to onl...
B&H has Apple’s base 13″ M1 MacBook Air (Space Gray, Silver, & Gold) in stock and on clearance sale today for $300 off MSRP, only $699. Free 1-2 day shipping is available to most addresses in... Read more

Jobs Board

Medical Assistant - Surgical Oncology- *Apple...
Medical Assistant - Surgical Oncology- Apple Hill Location: WellSpan Medical Group, York, PA Schedule: Full Time Sign-On Bonus Eligible Remote/Hybrid Regular Apply Read more
Omnichannel Associate - *Apple* Blossom Mal...
Omnichannel Associate - Apple Blossom Mall Location:Winchester, VA, United States (https://jobs.jcp.com/jobs/location/191170/winchester-va-united-states) - Apple Read more
Cashier - *Apple* Blossom Mall - JCPenney (...
Cashier - Apple Blossom Mall Location:Winchester, VA, United States (https://jobs.jcp.com/jobs/location/191170/winchester-va-united-states) - Apple Blossom Mall Read more
Operations Associate - *Apple* Blossom Mall...
Operations Associate - Apple Blossom Mall Location:Winchester, VA, United States (https://jobs.jcp.com/jobs/location/191170/winchester-va-united-states) - Apple Read more
Business Analyst | *Apple* Pay - Banco Popu...
Business Analyst | Apple PayApply now " Apply now + Apply Now + Start applying with LinkedIn Start + Please wait Date:Mar 19, 2024 Location: San Juan-Cupey, PR Read more
All contents are Copyright 1984-2011 by Xplain Corporation. All rights reserved. Theme designed by Icreon.