Palette Selection
Volume Number: 2
Issue Number: 5
Column Tag: C Workshop
Palette Selection in Aztec C
By Mike Schuster, Adobe Systems, MacTutor Contributing Editor
Mike wins our prize of $50 for this month's outstanding article with this fine
demonstration of a new ROM routine. Congratulations Mike!
Making Palettes with the List Manager
Apple's December 1985 Macintosh software supplement (which was shipped to
“the rest of us” in March 1986) contains a variety of useful items, including the new
List Manager Package. The List Manager provides a set of routines and data types for
creating, maintaining and displaying lists and arrays of data elements. In its simplest
form, you can use the List Manager to display a scrollable list of names, as in the
Standard File Open dialog box. In other, more complex forms, you can use the List
Manager to display arrays of arbitrary graphic images, as the displays of pictures and
icons in the Resource Editor and the Chooser desk accessory.
Apple implemented the List Manager as a package (like the Standard File, Disk
Initialization and International Utilities packages) and placed it (as package 0) in the
System resource file (version 3.1.1) which is included with the supplement. The
supplement also contains an alpha draft of the new List Manager Package chapter of
Inside Macintosh Volume IV.
To show you what you can do with the List Manager, I used it implement a
MacPaint-like palette of tools:
In this example, the palette is represented as a 2 column by 10 row array (only
5 rows of which are visible at any one time), where each list element is a MacPaint tool
icon. I instructed the List Manager to display the array and its scroll bar in a rectangle
within its own window. Once the array is setup, the List Manager handles all mouse
events, selections, and scrolling of the icons within the palette.
The List Manager provides a variety of display alternatives. In the following two
example, I arranged the palette as 10 column by 2 row array and as a 20 column by 1
row array.
In the following example, the palette is arranged as a 10 column by 2 row array,
where the whole palette is visible in its window, and so a scroll bar is not needed.
The List Manager's Structure
The List Manager is designed to maintain a set of data elements within a list, and
to display the list in a rectangle within a window. The data elements themselves are
displayed in the rectangle as a two dimensional array of cells. Although the size of each
data element may vary, the cells in which they are displayed must be the same size.
When you create the list, you specify the horizontal and vertical size of a cell, as well as
the number of rows and columns of cells the list is to contain. After the list is created,
you can at any time add new rows or columns to the list as well as delete existing rows
and columns. The cells in a new list and in any new rows and columns are initially
empty.
Once you have created the list, or added rows or columns, you can set the values
of the cells. The value of a cell is any arbitrary consecutive sequence of bytes of data,
with the restriction that the total size of a list cannot exceed 32K bytes. Hence, a cell
can store most anything - a text string, the bits of an icon, or the resource ID of a
picture.
At any given time, only a subset of the cells in the list may be visible in the list's
rectangle within the window. The set of visible cells is determined by the size of a cell,
the number of rows and columns in the list, and the current horizontal and vertical
scrolling positions.
The location of each cell in a list is specified by its row and column number. The
top-left cell in the list is in column 0 and row 0. The bottom-right cell in the list is
in column c-1, row r-1, where the list contains c columns and r rows. The List
Manager uses the Quickdraw Point data type to specify a cell's location. The horizontal
coordinate specifies the cell's column, and the vertical coordinate specifies the cell's
row.
The List Manager calls a list definition procedure, which is normally stored as a
resource in a resource file, to draw and hilite the data elements within a cell. Apple
supplied a default text-only procedure with the software supplement. For the palette,
we'll have to write our own custom procedure to draw and hilite the palette's icons.
The List Manager routine LNew creates a list, and returns a handle to the new
list.
ListHandle LNew(rView, dataBounds, cSize, theProc, theWindow,
drawIt, hasGrow, scrollHoriz, scrollVert)
Rect *rView, *dataBounds;
Point cSize;
int theProc;
WindowPtr theWindow;
Boolean drawIt, hasGrow, scrollHoriz, scrollVert;
The list will be displayed in the window specified by theWindow. RView
specifies, in the local coordinates of theWindow, the rectangle in which the list will be
drawn.
The rectangle DataBounds specifies the initial dimensions of the list. Its top and
left coordinates should both be 0. Its bottom coordinate specifies the number of rows in
the list. Its right coordinate specifies the number of columns in the list. The point
cSize specifies the size of each cell. Its horizontal coordinate specifies the width of a
cell. Its vertical coordinate specifies the height of a cell.
TheProc is the resource ID of the list definition procedure that will be used to
draw and hilite the data elements within the cells. For the default text-only list, pass 0
and Apple's default list definition procedure will be used.
If scrollHoriz is TRUE, the List Manager will place a horizontal scroll bar
immediate below rView in the window and will enable all of the list's horizontal
scrolling functions. Similarly, if scrollVert is TRUE, the List Manager will place a
vertical scroll bar immediately to the right of rView in the window and will enable all
of the list's vertical scrolling functions. If hasGrow is TRUE, the scroll bars are sized
to make room for a size box in the standard position.
DrawIt specifies the initial value of the list's drawing mode. If the list's drawing
mode is TRUE, all routines that affect the contents of cells, the number of rows and
columns in the list, the size of the window, or which cells are visible within the
rectangle, will cause the updated list to be drawn. If the list's drawing mode is FALSE,
none of these operations will cause the updated list to be drawn, until the drawing mode
is later set to TRUE, using the List Manager routine LDoDraw.
void LDoDraw(drawIt, lHandle)
Boolean drawIt;
ListHandle lHandle;
LDoDraw sets the list's drawing mode to the state specified by drawIt.
The ListHandle returned by LNew is defined as follows. For a more detailed
description, refer to the List Manager Package chapter in the supplement.
typedef Point Cell;
typedef struct
{
Rect rView; /* list's display rectangle */
GrafPtr port; /* list's grafPort */
Point indent; /* indent distance */
Point cellSize; /* cell size */
Rect visible; /* boundary of visible cells */
ControlHandle vScroll; /* vertical scroll bar */
ControlHandle hScroll; /* horizontal scroll bar */
char selFlags; /* selection flags */
Boolean lActive; /* TRUE if active */
char lReserved; /* reserved */
char listFlags; /* automatic scrolling flags */
long clikTime; /* time of last click */
Point clikLoc; /* position of last click */
Point mouseLoc; /* current mouse location */
Ptr lClikLoop; /* routine for LClick */
Cell lastClick; /* last cell clicked */
long refCon; /* list's reference value */
Handle listDefProc; /* list definition procedure */
Handle userHandle; /* additional storage */
Rect dataBounds; /* boundary of cells allocated */
Handle cells; /* cell data */
int maxIndex; /* used internally */
int cellArray[1]; /* offsets to data */
} ListRec, *ListPtr, **ListHandle;
The List Manager provides a variety of cell selection algorithms, and defines the
following predefined flags for the selFlags field of the list record shown on the top of
the next page.
#define lOnlyOne 128 /* set if only one selected cell */
#define lExtendDrag 64 /* set for dragging without shift */
#define lNoDisjoint 32 /* set turns off multiple selects */
#define lNoExtend 16 /* set to not extend shift selects */
#define lNoRect 8 /* set to not expand selections */
#define lUseSense 4 /* set for shift to use first cell's
sense */
#define lNoNilHilite 2 /* set to not hilite empty cells */
For our purposes, only the lOnlyOne flag is useful, since only one icon may be
selected from the palette at any time. Check the supplement for a description of the
other flags.
Once the list is created, the List Manager routine LSetCell may be called to set
the value of a particular cell in the list.
void LSetCell(dataPtr, dataLen, theCell, lHandle)
Ptr dataPtr;
int dataLen;