TweetFollow Us on Twitter

MACINTOSH C CARBON
MACINTOSH C CARBON: A Hobbyist's Guide To Programming the Macintosh in C
Version 1.0
2001 K. J. Bricknell
Go to Contents Go to Program Listing

CHAPTER 22

LISTS AND CUSTOM LIST DEFINITION FUNCTIONS

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 Mac OS 8/9 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 Mac OS 8/9 Apple menu), or which display more than one type of information in each item (as does the list in the Mac OS 8/9 About This Computer... window).

List Manager Limitations

The List Manager is not suitable for displaying large amounts of data. The limiting size for list data is 32KB, and performance degrades well before that limit is reached.

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 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.

Appearance and Features of Lists

Fig 1 shows a dialog 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.

Cells, Cell Font, and Cell Highlighting

Cells

A list is a number of items displayed within a rectangle, each item being contained within an invisible rectangular cell. Cells may contain different types of data, but all cells within a particular list are of the same size.

Cell Font

By default, lists inherit the font of the graphics port associated with the window or dialog 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 attempt to make it fit (Mac OS 8/9 only). Failing that, 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 scroll bars, which allow you to include more items in a list than can be contained within the list's display rectangle. If a list includes a scroll bar but the number of cells is such that they are all visible, the List Manager 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 within the list 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. The following describes the default cell-selection behaviour.

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

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

A range of cells may be added or deleted from the current selection by pressing the Command key and then dragging the cursor over other cells. The List Manager checks the status of the first cell clicked in so as to determine whether to add or remove selections. All cells in the range over which the cursor passes will be deselected if that first cell is initially selected. On the other hand, all cells in the range over which the cursor passes will be selected if that first cell is initially not selected.

When a cell's selection status is changed by Command-dragging, that selection status remains the same for the duration of the drag, that is, it will not change if the user moves the cursor back over the cell. The effect of the Command key thus differs from that of the Shift key in this respect.

Shift-Clicking - Discontiguous Cells Selected

Discontiguity is lost if the user Shift-clicks a cell after having previously created discontiguous selections. The List Manager selects all cells in the range of 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 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 following methods of cell selection via the keyboard:

  • Cell Selection Using Arrow Keys. This method involves the use of the Arrow keys to move and extend cell selections.

  • Type Selection. This method involves the user simply typing the text associated with an item. It is thus only relevant to text-only lists (or lists whose items can be identified by text strings).

Cell Selection Using Arrow Keys

The List Manager does not provide any functions to support cell selection by Arrow key. 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 selection should be moved 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 at the same time pressing the Command key, 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 the Up Arrow key should select the first cell in the list, deselect all other cells, and 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 alternative 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

The List Manager does not provide any functions to support type selection, although the Text Utilities provide a data type and functions which support this method of keyboard selection. That said, your application must provide most of the code. The following describes what that code should do.

In a text-only list, when the user types the text of an item in a list, the list should scroll to that cell and select 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. (The value in KeyThresh is set by the user at the "Delay Until Repeat" section of the Keyboard control panel (Mac OS 8/9) and System Preferences/Keyboard (Mac OS X).)

Implementing Type Selection

To implement type selection, your application must store the characters the user has typed and the time when the user last typed a character. The Text Utilities TypeSelectRecord structure may be used for this purpose:

     struct TypeSelectRecord 
     {
       unsigned long tsrLastKeyTime;  // Time when the last character was typed
       ScriptCode    tsrScript;
       Str63         tsrKeyStrokes;   // Characters typed by the user
     };
     typedef struct TypeSelectRecord TypeSelectRecord;

The Text Utilities function TypeSelectNewKey adds a new character to the tsrKeyStrokes field.

A global variable of type SInt16 should be used to store the number of ticks after which type selection must be reset. The low memory accessor function LMGetKeyThresh may be used to obtain the value in the low memory global KeyThresh.

The Text Utilities function TypeSelectClear may be used to reset the tsrKeyStrokes and tsrLastKeyTime fields of the TypeSelectRecord structure to NULL and 0 respectively.

LSearch should be called to search the list's cells for a match with the specified characters, a universal procedure pointer to a comparison function being passed in the searchProc parameter.

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. Although the list structure is not opaque, you are encouraged to access the list structure indirectly using the provided accessor functions because this will give your application greater threading capability on Mac OS X.

Before describing the list structure and its associated accessor functions, 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

A cell in a list can be described by the Cell data type, 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.

The ListRec Structure

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 and Associated Accessor Functions

rView

The list's visible rectangle (local coordinates). This does not include the area occupied by the list's scroll bars (if any).

Accessor Functions: GetListViewBounds SetListViewBounds

port The graphics port of the window containing the list. The coordinates of the list's visible rectangle are local to this port.

Accessor Functions: GetListPort SetListPort

indent

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.

Accessor Functions: GetListCellIndent SetListCellIndent

cellSize

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 adds the ascent, descent and leading of the port's font to arrive at the height of a cell (which works out as 16 pixels for 12-point Charcoal on Mac OS 8/9, for example). You should make the height of your list equal to a multiple of cell height. For cell width, the List Manager divides the width of the list's display rectangle by the number of columns in the list.

Accessor Functions: GetListCellSize SetListCellSize

visible

Specifies those cells in a list that are visible within the rView rectangle. The left and top fields are set by the List Manager to the coordinates of the first visible cell. The right and bottom fields are set to one greater than the horizontal and vertical coordinates of the last visible cell. If, for example, the first three columns and six rows are visible (that is, the last visible cell has coordinates (2,5), the List Manager sets the visible field to (0,0,3,6).

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. When PtInRect's parameters are expressed as cell coordinates, the cells "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 6 or higher or column 3 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).

Accessor Functions: GetListVisibleCells SetListVisibleCells

vScroll

Handle to the vertical scroll bar (or NULL if there is no vertical scroll bar).

Accessor Functions: GetListVerticalScrollBar SetListVerticalScrollBar

hScroll

Handle to the horizontal scroll bar (or NULL if there is no horizontal scroll bar).

Accessor Functions: GetListHorizontalScrollBar SetListHorizontalScrollBar

selFlags

The algorithm the List Manager uses to select cells in response to a click in the list.

Accessor Functions: GetListSelectionFlags SetListSelectionFlags

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.)

Accessor Functions: GetListActive LActivate

listFlags

Flags indicating whether automatic vertical and horizontal scrolling is enabled. If automatic scrolling is enabled, the list scrolls when the user clicks a cell and then drags the cursor out of the rView rectangle. If the list has the associated scroll bar (horizontal or vertical), automatic scrolling is enabled by default. The following constants are used to specify whether horizontal and vertical autoscrolling should be enabled or disabled:

     lDoVAutoscroll = 2  Allows vertical scrolling.
     lDoHAutoscroll = 1  Allows horizontal scrolling.

Accessor Functions: GetListFlags SetListFlags

clikTime

Time when the user last clicked the mouse.

Accessor Functions: GetListClickTime SetListClickTime

clikLoc Local coordinates of the last mouse click. >

Accessor Function: GetListClickLocation

mouseLoc

Current location of the cursor in local coordinates.

Accessor Function: GetListMouseLocation

lClickLoop

Contains NULL if the default click loop function is to be used. However, your application cab assign a universal procedure pointer to a custom click-loop function to this field. Your application will not need a custom click-loop function unless it needs to perform some special processing while the user drags the cursor.

Accessor Functions: GetListClickLoop SetListClickLoop

lastClick

Cell coordinates of the last click. You can access the value in this field using LLastClick.

Accessor Function: SetListLastClick

refCon

For your application's use.

Accessor Functions: GetListRefCon SetListRefCon

listDefProc

Handle to the list definition function code.

Accessor Functions: GetListDefinition SetListDefinition

userHandle

For your application's use. Typically, applications use this field to store a handle to some additional storage associated with a list.

Accessor Functions: GetListUserHandle SetListUserHandle

dataBounds

The total cell dimensions of the list. 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 visible rectangle. For example, if a list contains 5 columns and 12 rows (that is, the last cell in the list has coordinates (4,10)), the dataBounds field is set to (0,0,5,12).

Accessor Function: GetListDataBounds

cells

Handle to a relocatable block where cell data is stored. Because of the way this field is defined, no list can contain more than 32,000 bytes of data.

Accessor Function: GetListDataHandle

cellArray

Offsets to data in the relocatable block specified by the cells field. Do not change the cells field, or access the information in the cellArray field, directly.

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

Creating Lists

Creating Lists Which Do Not Use a Custom List Definition Function

If you are creating a list that does not use a custom list definition function, you should use the function LNew to create the list:

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

rView

Rectangle in which to display the list. This rectangle is in the local coordinates of the window passed in the theWindow parameter, and does not include the area occupied by the list's scroll bars.

dataBounds

Initial data bounds. For example, to create a list with 5 columns and 10 rows, set the left and top fields to (0,0) and the right and bottom fields to 5 and 10 respectively.

cSize

Size of each cell. If your application is using the default list definition function and passes (0,0) in this field, the size is calculated automatically.

theProc

Pass 0 in this parameter to cause the default list definition function to be used. (See also the Carbon Note below.)

theWindow

Reference to the window in which the list is to be installed.

drawIt

Specifies whether automatic drawing mode is to be initially enabled. When automatic redrawing is enabled (by setting this parameter to true), the list is automatically redrawn whenever it is changed.

This setting can be changed later 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

Specifies whether space should be left for a size box/resize control.

scrollHoriz

Pass true if your list requires a horizontal scroll bar, otherwise pass false.

scrollVert

Pass true if your list requires a vertical scroll bar, otherwise pass false.

Creating Lists Which Use a Custom List Definition Function

If you are creating a list which uses a custom list definition function, you should use the function CreateCustomList to create the list:

     OSStatus  CreateCustomList(const Rect *rView,const ListBounds *  dataBounds,
               Point cellSize,const ListDefSpec *theSpec,
               WindowRef theWindow,Boolean drawIt,Boolean hasGrow,
               Boolean scrollHoriz,Boolean scrollVert,ListHandle *outList);

The main difference between LNew and CreateCustomList is that the former takes the resource ID of a list definition function whereas the latter takes a universal procedure pointer to a list definition function.

In the Classic API, custom list definition functions are compiled separately as 'CODE' resources and the resource ID is passed in the theProc parameter of LNew. In Carbon, custom definition functions (and, indeed, all other custom definition functions) cannot be stored in resources; accordingly, the function CreateCustomList was introduced with Carbon to accommodate that situation.

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 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 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, 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 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 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 (Classic event model) or kEventWindowDrawContent event type (Carbon event model) 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 by GetPortVisibleRegion.

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 an activate event (Classic event model) or kEventWindowActivated or kEventWindowDeactivated event type is received (Carbon event model), 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 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 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

To create a linked ring, you can use the refCon field of each list structure. Assign the handle to the second list to the refCon field of the first list, assign the handle to the third list to the refCon field of the second list, and so on, until, to close the circle, the handle to the first list is assigned to the refCon field of the last list. Then, in response to a Tab key press in the current list, your application can ascertain the next list in the ring by looking at the current list's refCon field.

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

     ListHandle  gCurrentListHdl;

     void  doFindPreviousListInRing(void)
     {
       ListHandle  listHdl;

       listHdl = gCurrentListHdl;

       while((ListHandle) GetListRefCon(listHdl) != gCurrentList)
         listHdl = (ListHandle) GetListRefCon(listHdl);

       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 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:

     SetListSelectionFlags(listHdl,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 functions for storing data in the list's cells and, where required, for adding rows and/or columns.

  • Provide a function to support type selection, if required.

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

  • Provide a 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

The list box description ('ldes') resource, which must have resource ID of greater than 127, is used to specify information for a list box. The information is used by The Control Manager to provide additional information to the relevant list box control. Fig 3 shows the structure of a compiled 'ldes' resource.

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

Field

Description

NUMBER OF ROWS

The number of rows in the list box.

NUMBER OF COLUMNS

The number of columns in the list box.

CELL HEIGHT

The height of the list cells. Specify 0 to cause the height to be calculated automatically.

CELL WIDTH

The width of a the list cells. Specify 0 to cause the width to be calculated automatically.

HAS VERTICAL SCROLL BAR

true causes the list box to contain a vertical scroll bar.

HAS HORIZONTAL SCROLL BAR

true causes the list box to contain a horizontal scroll bar.

RESOURCE ID

The resource ID of the list definition function to use for the list. In Carbon, always set to 0.

HAS SIZE BOX

true causes the List Manager to leave room for, and draw, a size box.

Programmatic Creation

List box controls may be created programmatically using the function CreateListBoxControl:

     OSStatus  CreateListBoxControl(WindowRef window,const Rect *boundsRect,
               Boolean autoSize,SInt16 numRows,SInt16 numColumns,Boolean horizScroll,
               Boolean vertScroll,SInt16 cellHeight,SInt16 cellWidth,
               Boolean hasGrowSpace,const ListDefSpec *listDef,ControlRef *outControl);

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 MAC OS 8/9 Finder's About This Computer... dialog 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.

Your custom list definition function must be declared like this:

     void  myListDefinition(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, which contain information about the cell affected by the message, pass information to your custom list definition function only when the lDrawMsg or lHiliteMsg messages are received. The lSelect parameter indicates whether the cell should be highlighted. lRect and lCell provide the cell's rectangle and coordinates. lDataOffset and lDataLen parameters provide the offset and length of the cell's data referenced by the cells field of the list structure.

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.

The Draw Message

In response to the lDrawMsg message, your custom list definition function must examine the specified cell's data and draw the cell as appropriate, ensuring that the characteristics of the drawing environment are not altered.

The HighLighting Message

In response to the lHiliteMsg message, your custom list definition function should highlight 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 lCloseMsg is sent immediately before the List Manager disposes of the memory occupied by the list. Your custom list definition function needs to respond only if it needs to perform some special processing at that point, such as releasing any additional memory associated with the list.

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.

Control Kind (Mac OS X Only)

kControlKindListBox = FOUR_CHAR_CODE('lbox')

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);
OSStatus    CreateCustomList(const Rect *rView,const ListBounds *dataBounds,
            Point   cellSize,const ListDefSpec *theSpec,WindowRef theWindow,Boolean drawIt,
            Boolean hasGrow,Boolean scrollHoriz,Boolean scrollVert,ListHandle *outList);
void        LDispose(ListHandle lHandle);

Creating List Box Controls

OSStatus   CreateListBoxControl(WindowRef window,const Rect *boundsRect,
           Boolean autoSize,SInt16 numRows,SInt16 numColumns,Boolean horizScroll,
           Boolean vertScroll,SInt16 cellHeight,SInt16 cellWidth,Boolean hasGrowSpace,
           const ListDefSpec *listDef,ControlRef *outControl);

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);

List Structure Accessor Functions

Rect*             GetListViewBounds(ListRef list,Rect *view);
void              SetListViewBounds(ListRef list,const Rect *view);
CGrafPtr          GetListPort(ListRef list);
void              SetListPort(ListRef list,CGrafPtr port);
Point*            GetListCellIndent(ListRef list,Point *indent);
void              SetListCellIndent(ListRef list,Point *indent);
Point*            GetListCellSize(ListRef list,Point *size);
void              SetListCellSize(ListRef list,Point *size);
ListBounds*       GetListVisibleCells(ListRef list,ListBounds *visible);
void              SetListVisibleCells(ListRef list,ListBounds *visible);
ControlHandle     GetListVerticalScrollBar(ListRef list);
void              SetListVerticalScrollBar(ListRef list,ControlHandle vScroll);
ControlHandle     GetListHorizontalScrollBar(ListRef list);
void              SetListHorizontalScrollBar(ListRef list,ControlHandle hScroll);
OptionBits        GetListSelectionFlags(ListRef list);
void              SetListSelectionFlags(ListRef list,OptionBits selectionFlags);
Boolean           GetListActive(ListRef list);
OptionBits        GetListFlags(ListRef list);
void              SetListFlags(ListRef list,OptionBits listFlags);
SInt32            GetListClickTime(ListRef list);
void              SetListClickTime(ListRef list,SInt32 time);
Point*            GetListClickLocation(ListRef list,Point *click);
Point*            GetListMouseLocation(ListRef list,Point *mouse);
ListClickLoopUPP  GetListClickLoop(ListRef list);
void              SetListClickLoop(ListRef list,ListClickLoopUPP clickLoop);
void              SetListLastClick(ListRef list,Cell *lastClick);
SInt32            GetListRefCon(ListRef list);
void              SetListRefCon(ListRef list,SInt32 refCon);
Handle            GetListUserHandle(ListRef list);
void              SetListUserHandle(ListRef list,Handle userHandle);
Handle            GetListDefinition(ListRef list);
void              SetListDefinition(ListRef list,Handle listDefProc);
ListBounds*       GetListDataBounds(ListRef list,ListBounds *bounds);
DataHandle        GetListDataHandle(ListRef list);

Creating and Disposing of Creating and Disposing of Universal Procedure Pointers

ListSearchUPP     NewListSearchUPP(ListSearchProcPtr userRoutine);
ListClickLoopUPP  NewListClickLoopUPP(ListClickLoopProcPtruserRoutine);
ListDefUPP        NewListDefUPP(ListDefProcPtr userRoutine);
void              DisposeListSearchUPP(ListSearchUPP userUPP);
void              DisposeListClickLoopUPP(ListClickLoopUPP userUPP);
void              DisposeListDefUPP(ListDefUPP userUPP);

Application-Defined (Callback) Function

void             myListDefinition(short lMessage, Boolean lSelect, Rect *lRect, Cell lCell,
                 short lDataOffset, short lDataLen, ListHandle lHandle);

Relevant Text Utilities Data Type and Functions

Data Type

struct TypeSelectRecord 
{
  unsigned long tsrLastKeyTime;
  ScriptCode    tsrScript;
  Str63         tsrKeyStrokes;
};
typedef struct TypeSelectRecord TypeSelectRecord;

Functions

void      TypeSelectClear(TypeSelectRecord *tsr);
Boolean   TypeSelectNewKey  (const EventRecord *theEvent,TypeSelectRecord *tsr);

 
AAPL
$116.47
Apple Inc.
+0.16
MSFT
$47.98
Microsoft Corpora
-0.72
GOOG
$537.50
Google Inc.
+2.67

MacTech Search:
Community Search:

Software Updates via MacUpdate

Cobook 3.0.7 - Intelligent address book....
Cobook Contacts is an intuitive, engaging address book. Solve the problem of contact management with Cobook Contacts and its simple interface and powerful syncing and integration possibilities.... Read more
StatsBar 1.9 - Monitor system processes...
StatsBar gives you a comprehensive and detailed analysis of the following areas of your Mac: CPU usage Memory usage Disk usage Network and bandwidth usage Battery power and health (MacBooks only)... Read more
Cyberduck 4.6 - FTP and SFTP browser. (F...
Cyberduck is a robust FTP/FTP-TLS/SFTP browser for the Mac whose lack of visual clutter and cleverly intuitive features make it easy to use. Support for external editors and system technologies such... Read more
Maya 2015 - Professional 3D modeling and...
Maya is an award-winning software and powerful, integrated 3D modeling, animation, visual effects, and rendering solution. Because Maya is based on an open architecture, all your work can be scripted... Read more
Evernote 6.0.1 - Create searchable notes...
Evernote allows you to easily capture information in any environment using whatever device or platform you find most convenient, and makes this information accessible and searchable at anytime, from... Read more
calibre 2.11 - Complete e-library manage...
Calibre is a complete e-book library manager. Organize your collection, convert your books to multiple formats, and sync with all of your devices. Let Calibre be your multi-tasking digital... Read more
Herald 5.0.1 - Notification plugin for M...
Note: Versions 2.1.3 (for OS X 10.7), 3.0.6 (for OS X 10.8), and 4.0.8 (for OS X 10.9) are no longer supported by the developer. Herald is a notification plugin for Mail.app, Apple's Mac OS X email... Read more
Firetask 3.7 - Innovative task managemen...
Firetask uniquely combines the advantages of classical priority-and-due-date-based task management with GTD. Stay focused and on top of your commitments - Firetask's "Today" view shows all relevant... Read more
TechTool Pro 7.0.6 - Hard drive and syst...
TechTool Pro is now 7, and this is the most advanced version of the acclaimed Macintosh troubleshooting utility created in its 20-year history. Micromat has redeveloped TechTool Pro 7 to be fully 64... Read more
PhotoDesk 3.0.1 - Instagram client for p...
PhotoDesk lets you view, like, comment, and download Instagram pictures/videos! (NO Uploads! / Image Posting! Instagram forbids that! AND you *need* an *existing* Instagram account). But you can do... Read more

Latest Forum Discussions

See All

Ubisoft Gives Everyone Two New Ways to E...
Ubisoft Gives Everyone Two New Ways to Earn In-Game Stuff for Far Cry 4 Posted by Jessica Fisher on November 21st, 2014 [ permalink ] | Read more »
Golfinity – Tips, Tricks, Strategies, an...
Dig this: Would you like to know what we thought of being an infinite golfer? Check out our Golfinity review! Golfinity offers unlimited ways to test your skills at golf. Here are a few ways to make sure your score doesn’t get too high and your... | Read more »
Dark Hearts, The Sequel to Haunting Meli...
Dark Hearts, The Sequel to Haunting Melissa, is Available Now Posted by Jessica Fisher on November 21st, 2014 [ permalink ] Universal App - Designed for iPhone and iPad | Read more »
Meowza! Toyze Brings Talking Tom to Life...
Meowza! | Read more »
Square Enix Announces New Tactical RPG f...
Square Enix Announces New Tactical RPG for Mobile, Heavenstrike Rivals. Posted by Jessica Fisher on November 21st, 2014 [ permalink ] With their epic stories and gorgeous graphics, | Read more »
Quest for Revenge (Games)
Quest for Revenge 1.0.0 Device: iOS Universal Category: Games Price: $4.99, Version: 1.0.0 (iTunes) Description: The great Kingdom of the west has fallen. The gods ignore the prayers of the desperate. A dark warlord has extinguished... | Read more »
Threadz is a New Writing Adventure for Y...
Threadz is a New Writing Adventure for You and Your Friends Posted by Jessica Fisher on November 21st, 2014 [ permalink ] In the tradition of round-robin storytelling, | Read more »
SteelSeries Stratus XL Hardware Review
Made by: SteelSeries Price: $59.99 Hardware/iOS Integration Rating: 4 out of 5 stars Usability Rating: 4.5 out of 5 stars Reuse Value Rating: 4.25 out of 5 stars Build Quality Rating: 4.5 out of 5 stars Overall Rating: 4.31 out of 5 stars | Read more »
ACDSee (Photography)
ACDSee 1.0.0 Device: iOS iPhone Category: Photography Price: $1.99, Version: 1.0.0 (iTunes) Description: Capture, perfect, and share your photos with ACDSee. The ACDSee iPhone app combines an innovative camera, a powerful photo... | Read more »
ProTube for YouTube (Entertainment)
ProTube for YouTube 2.0.2 Device: iOS Universal Category: Entertainment Price: $1.99, Version: 2.0.2 (iTunes) Description: ProTube is the ultimate, fully featured YouTube app. With it's highly polished design, ProTube offers ad-free... | Read more »

Price Scanner via MacPrices.net

Save up to $400 with Apple refurbished 2014 1...
The Apple Store has restocked Apple Certified Refurbished 2014 15″ Retina MacBook Pros for up to $400 off the cost of new models. An Apple one-year warranty is included with each model, and shipping... Read more
New 13-inch 1.4GHz MacBook Air on sale for $8...
 Adorama has the 2014 13″ 1.4GHz/128GB MacBook Air on sale for $899.99 including free shipping plus NY & NJ tax only. Their price is $100 off MSRP. B&H Photo has the 13″ 1.4GHz/128GB MacBook... Read more
Apple Expected to Reverse Nine-Month Tablet S...
Apple and Samsung combined accounted for 62 percent of the nearly 36 million branded tablets shipped in 3Q 2014, according to early vendor shipment share estimates from market intelligence firm ABI... Read more
Stratos: 30 Percent of US Smartphone Owners t...
Stratos, Inc., creator of the Bluetooth Connected Card Platform, has announced results from its 2014 Holiday Mobile Payments Survey. The consumer survey found that nearly one out of three (30 percent... Read more
2014 1.4GHz Mac mini on sale for $449, save $...
 B&H Photo has lowered their price on the new 1.4GHz Mac mini to $449.99 including free shipping plus NY tax only. Their price is $50 off MSRP, and it’s the lowest price available for this new... Read more
Check Apple prices on any device with the iTr...
MacPrices is proud to offer readers a free iOS app (iPhones, iPads, & iPod touch) and Android app (Google Play and Amazon App Store) called iTracx, which allows you to glance at today’s lowest... Read more
64GB iPod touch on sale for $249, save $50
Best Buy has the 64GB iPod touch on sale for $249 on their online store for a limited time. Their price is $50 off MSRP. Choose free shipping or free local store pickup (if available). Sale price for... Read more
15″ 2.2GHz Retina MacBook Pro on sale for $17...
 B&H Photo has the 2014 15″ 2.2GHz Retina MacBook Pro on sale for $1799.99 for a limited time. Shipping is free, and B&H charges NY sales tax only. B&H will also include free copies of... Read more
New Logitech AnyAngle Case/Stand Brings Flexi...
Logitec has announced the newest addition to its suite of tablet products — the Logitech AnyAngle. A protective case with an any-angle stand for iPad Air 2 and all iPad mini models, AnyAngle is the... Read more
Notebook PC Shipments Rise Year-Over-Year as...
According to preliminary results from the upcoming DisplaySearch Quarterly Mobile PC Shipment and Forecast Report, the global notebook PC market grew 10 percent year-over-year in Q3’14 to 49.4... Read more

Jobs Board

*Apple* Solutions Consultant (ASC)- Retail S...
**Job Summary** The ASC is an Apple employee who serves as an Apple brand ambassador and influencer in a Reseller's store. The ASC's role is to grow Apple Read more
Project Manager, *Apple* Financial Services...
**Job Summary** Apple Financial Services (AFS) offers consumers, businesses and educational institutions ways to finance Apple purchases. We work with national and Read more
*Apple* Store Leader Program - College Gradu...
Job Description: Job Summary As an Apple Store Leader Program agent, you can continue your education as you major in the art of leadership at the Apple Store. You'll Read more
*Apple* Retail - Multiple Positions (US) - A...
Sales Specialist - Retail Customer Service and Sales Transform Apple Store visitors into loyal Apple customers. When customers enter the store, you're also the Read more
Senior Event Manager, *Apple* Retail Market...
…This senior level position is responsible for leading and imagining the Apple Retail Team's global event strategy. Delivering an overarching brand story; in-store, Read more
All contents are Copyright 1984-2011 by Xplain Corporation. All rights reserved. Theme designed by Icreon.