TweetFollow Us on Twitter

List of Controls
Volume Number:5
Issue Number:6
Column Tag:Advanced Mac'ing

Related Info: List Manager Control Manager

List of Controls LDEF

By James Plamondon, Berkeley, CA

Note: Source code files accompanying article are located on MacTech CD-ROM or source code disks.

List-Of-Controls LDEF

Introduction

I recently needed to implement a list, in which each cell would be an active control. It turned out to be a little harder to do than I thought it would be. To save others the trouble, I thought I’d describe how I made it all work.

Overview

I use Apple’s List Manager to manipulate my list of controls. Each element of the list contains a ControlHandle to a PopUp-Menu control. Whenever a mouseDown event occurs in the list, I find out if it is one of the controls, and if so, call TrackControl() (IM v1 p323) to deal with it. If the mouseDown is in the list, but not in an active part of the control, I pass the event off to LClick() (IM v4 p273), so the Apple List Manager can handle it.

Whenever the user selects or unselects a list element, or brings a new control into view by scrolling the list, the List Manager will send a message to the list’s LDEF telling it to draw or hilite the list element. My LDEF will then set the control’s hilite state as needed to assure that it is drawn properly, and then call Draw1Control() (IM v4 p53) to do the actual drawing.

A routine called FixCtlRects() is called in the test program whenever a control may have changed position in the list’s display, to make sure that its controlRect field matches its list rectangle, and that it won’t be drawn if it is out of the list’s display area.

The example program uses the PopUp-Menu control described in MacTutor, September 1988, PopUp-Menu Control CDEF. I could have used a different CDEF, but I would have had to include the CDEF’s source code, and I didn’t want to make this article any longer than necessary.

LDEFs

LDEFs are described on pages 278-277 of Inside Mac, Volume Four, in the List Manager chapter (pages 259-282). The ‘LDEF’ associated with a list is loaded into memory when the list is created. Like other _DEFs (MDEFs, CDEFs, etc.), the code resource has a single entry point at its first byte (i.e., it has no jump table). The entry point must be a procedure with the following definition:

PROCEDURE MyLDEF(
 lMessage: INTEGER;
 lSelect: Boolean;
 lRect: Rect;
 lCell: Cell;
 lDataOffset,
 lDataLen: INTEGER;
 lHandle: ListHandle);

The function and argument names may be changed, of course, but their order and type must be as shown here (from IM v4 p276).

When a new list is created using the LNew() function (IM v4 p270), one of the parameters you must give to LNew() is the resource ID of the LDEF you want the list to use. Apple’s default LDEF has a resource ID of 0. Our LDEF has a resource ID of RES_ID (128). When we create the new list, the List Manager will load the specified LDEF, and store a handle to it in the listDefProc field of the resulting list record. Whenever a cell of the list needs to be drawn or hilited, the List Manager will send a message to the LDEF, and the LDEF will do the work.

LDEF Messages

An LDEF message is just a procedure call to the LDEF’s MyLDEF() routine, with lMessage (an integer) equal to a meaningful value. If the List Manager wants the LDEF to draw a cell, it calls MyLDEF() with lMessage equal to lDrawMsg (1). If the cell is to be hilited, MyLDEF() is called with lMessage equal to lHiliteMsg (2). MyLDEF() contains a CASE statement, keyed to the lMessage parameter’s value. If lMessage equals lDrawMsg, the routine doDrawMsg() is called. If lMessage equals lHiliteMsg, doHiliteMsg() is called. That’s all there is to LDEF message passing.

There are four different messages an LDEF may receive. Two of them, lDrawMsg and lHiliteMsg, must be handled by all LDEFs.

When the LDEF gets a lDrawMsg message, it needs to draw the given list cell. If the list cell is selected (ie., if lSelect is TRUE), then you need to hilite the cell, to tell the user that it’s been selected. The LDEF used in this article simply calls Draw1Control() to draw the control stored in the given cell. First it has to diddle with the control’s rectangle, though, as we’ll see later.

The lHiliteMsg message is sent to the LDEF when a previously drawn cell needs to be hilited or unhilited. In most cases, this is done by simply inverting the cell’s rectangle. Our LDEF has to get a little fancier.

The other two LDEF messages, lInitMsg and lCloseMsg, need only be implemented by the LDEF if each list handled by the LDEF needs to be initialized in some way, and then have its initialization voided when the list is disposed of. In this LDEF, however, no such initialization or deinitialization need be done, so it does nothing when it receives those messages.

List Hilighting

We need to be able to draw the control in such a way as to make it look selected in the list. The mechanism for inverting the control’s title already exists in the CDEF, so we’ll use that to indicate that the control is selected in the list.

The careful readers of the PopUp-Menu CDEF article and code may have noticed that a partCode was defined for the title of the pop-up menu (titlePart = 2), but that this partCode was never returned by doTestCntl(). The part code exists solely for this article. By setting the contrlHilite field of the control to be drawn to titlePart before calling Draw1Control(), we can guarantee that the control will have its title hilighted when it is drawn.

The Example Program

The example program is a very stripped Mac application. It simply initializes all of the usual managers, throws up a dialog, and cycles through ModalDialog() (IM v1 p415) until the user selects the dialog’s OK button. Most of the work of handling the list and the controls it contains is done by the filterProc MyFilter() -- the address of which is passed to ModalDialog() in the main program -- and its helper functions, doMouseDown() and doKeyDown().

After the user clicks the OK button, the program exits the ModalDialog() loop, disposes of the controls, list, and dialog, and quits. The final values of the controls are not accessed, because I’m not actually doing anything with them. In a real program you’d get the final values out of the controls, using GetCtlMax() and GetCtlMin() as described in PopUp-Menu Control CDEF.

Using the List-Of-Controls LDEF

The LDEF expects to find a control handle in each of its cells. We have to put these handles there ourselves. First we need to create the list itself, which we do with a call to LNew() in the routine InitList(). The only interesting part of this call is the use of RES_ID (128, the resource ID of our LDEF), rather than zero (0), Apple’s default LDEF.

Next, we need to create the controls we wish to add to the list. This is accomplished with calls to NewControl() (IM v1 p319), in the routine ReadData(). I read the resource ID’s of the controls I need from the ‘INT#’’ resource I’ve placed in the resource fork, and then read in the associated ‘CNTL’ resources.

I give the control a rectangle that is out of sight. It gets drawn despite my saying that I want it to be invisible (very irritating), so I just hide it, so that it can’t be seen until I want it to be seen.

After getting a control handle from NewControl(), the control is made visible (but not drawn) by placing TRUE (255) in its contrlVis field. ShowControl() (IM v1 p322) would try to draw the control, but that’s a waste of time, because the window is still invisible.

Finally, the control handle is placed in a new cell in the list. From there, we can extract it, and pass it along to Draw1Control() and TrackControl() as necessary.

Problems

At first I thought that I could just update a control’s rectangle whenever the cell it was in received an lDrawMsg or an lHiliteMsg. But that alone won’t work, because the List Manager uses ScrollRect() (IM v1 p187) to scroll the bits inside the list’s rectangle, and only redraws cells as they come into view. This means that after the initial drawing of the list, the only place in which cells are redrawn is in the top cell frame or in the bottom cell frame. If you modify the control rectangle to match the cell rectangle only when the cell is redrawn, then sooner or later, all of the controls are going to have either the top or bottom cell frame as their rectangles. It may look like there are controls in the middle of the list, but those are just scrolled bit-images; the controls will think they are in the top and bottom frames.

So, when you click in a control in the middle of the list, the control does not respond because it’s not really there. The thing you thought was a control was just a picture of a control. The control is in either the top or bottom cell frame (depending on where it was drawn last). If you click in the top or bottom cell frame, you’ll click in a control, all right, but not necessarily the one you see there. Your click will get picked up by the first control in the window’s control list (not the List Manager list) that was recently redrawn in that frame. Argh!

Here comes the kludge. The only way the user can move the controls on the list is with the list’s scroll bar. Therefore, whenever we receive a mouseDown event in the list that is not in one of our controls, we have to call FixCtlRects(). FixCtlRects() just walks through the list, getting each cell’s rectangle and setting the rectangle of the control in the cell to match. If the cell is invisible, then control is made invisible, and vice versa. This doesn’t take too long for a short list, but if you had a couple of hundred controls, it would be noticeably slow.

We also have to call FixCtlRects() after reading in the controls the first time, to make sure they’re displayed properly.

It’s a kludge, but it works, so what the hey.

Miscellaneous Notes

There are few other things about the LDEF, the pop-up menu CDEF, and its example program that are worth mentioning.

Note that I pass POINTER(-1) to TrackControl() in doMouseDown(). This enables the pop-up menu’s CDEF’s autoTrack function. This is the function that pops up the PopUp-Menu via PopUpMenuSelect() (IM v5 p241), as described in detail in PopUp-Menu Control CDEF.

CenterWindow() just centers a window in the screen, about two-thirds of the way up.

Acknowledgements

I started this project in order to do something we needed to do at work, but it kind of took on a life of its own when I realized that there was an article in it. I’d like to thank the guys at Abacus -- Dan, Jim, and Will -- for letting me spend the time I did on this. It won’t happen again for another week or two, anyway.

Listing:  Test.make

#Test.make
#
#
 
Test    ƒƒTest.r ControlLDEF.LDEF PopMenuCDEF.CDEF
 Rez -rd Test.r -o Test

Test    ƒƒTest.p.o 
 ControlLDEF.LDEF
 PopMenuCDEF.CDEF
 Test.r 
 Link   
 Test.p.o 
 “{Libraries}”Runtime.o   
 “{Libraries}”Interface.o 
 “{PLibraries}”PasLib.o   
 -o Test

ControlLDEF.LDEF ƒƒ ControlLDEF.p.o
 Link -sg ControlLDEF     
  -rt LDEF=1     
  -m MYLDEF ControlLDEF.p.o 
 “{Libraries}”Interface.o 
 -o ControlLDEF.LDEF

PopMenuCDEF.CDEF ƒƒ PopMenuCDEF.p.o
 Link -sg PopMenuCDEF     
  -rt CDEF=1     
  -m MYCONTROL PopMenuCDEF.p.o
 “{Libraries}”Interface.o 
 “{PLibraries}”PasLib.o   
 -o PopMenuCDEF.CDEF

PopMenuCDEF.p.o  ƒ PopMenuCDEF.p PopMenuIntf.p
 Pascal PopMenuCDEF.p -o PopMenuCDEF.p.o

Test.p.oƒ Test.p
 Pascal Test.p -o Test.p.o

ControlLDEF.p.o  ƒ ControlLDEF.p PopMenuIntf.p
 Pascal ControlLDEF.p -o ControlLDEF.p.o

# END OF FILE: Test.make
Listing: ControlLDEF.P

(*****************************************************
ControlLDEF.p:  List Definition Function for list of controls.
*****************************************************)

UNIT ControlLDEF;

INTERFACE
USES
 {$U MemTypes.p  } MemTypes,
 {$U QuickDraw.p   } QuickDraw,
 {$U OSIntf.p      } OSIntf,
 {$U ToolIntf.p    } ToolIntf,
 {$U PackIntf.p    } PackIntf,
 {$U PopMenuIntf.p } PopMenuIntf;

PROCEDURE MyLDEF(lMessage: INTEGER;lSelect: Boolean;
 lRect: Rect;lCell: Cell;lDataOffset,lDataLen: INTEGER;
 lHandle: ListHandle);

IMPLEMENTATION
CONST
 isVIS  = 255;
 notVIS = 0;
 
TYPE
 StateStuff = record
 oldPen:PenState;
 oldPort: GrafPtr;
 oldClip: RgnHandle;
 newClip: RgnHandle;
 end;  { StateStuff }

PROCEDURE DrawCell(lSelect: Boolean;lRect: Rect;
 lCell: Cell;lHandle: ListHandle);FORWARD;
 
(*****************************************************
MyLDEF:  List Definition Function for Controls list.
 Responds to LDrawMsg and lHiliteMsg; ignores
 lInitMsg and lCloseMsg.
*****************************************************)

PROCEDURE MyLDEF(lMessage: INTEGER;lSelect: Boolean;
 lRect: Rect;lCell: Cell;lDataOffset,lDataLen: INTEGER;
 lHandle: ListHandle);
BEGIN
 CASE lMessage OF
 lInitMsg:
 ; { no initialization needed }
 lCloseMsg:
 ; { no deallocation needed }
 
 lDrawMsg, lHiliteMsg:
 DrawCell(lSelect, lRect, lCell, lHandle);
 END;  { case }
END;  { MyLDEF }

(*****************************************************
SaveState:  Saves the current drawing environment.
*****************************************************)

PROCEDURE SaveState(VAR oldState:  StateStuff; 
 lRect:  Rect;lHandle: ListHandle);
BEGIN
 WITH oldState DO BEGIN
 { save the current pen state }
 GetPenState(oldPen);
 { save current grafPort, set new grafPort }
 GetPort(oldPort);
 SetPort(lHandle^^.port);
 { allocate space for old and new clipping regions }
 oldClip := NewRgn;
 newClip := NewRgn;
 { save old clipping region }
 GetClip(oldClip);
 { set newClip region to given rectangle }
 RectRgn(newClip, lRect);
 { intersection of rect and region }
 SectRgn(oldClip, newClip, newClip);
 { set grafPorts’ clip region to the intersection }
 SetClip(newClip);
 END;  { with }
END;  { SaveState }

(*****************************************************
RestoreState: Restores current drawing environment.
*****************************************************)

PROCEDURE RestoreState(oldState:  StateStuff);
BEGIN
 WITH oldState DO BEGIN
 { restore the previous clipping region }
 SetClip(oldClip);
 { restore the previous pen state }
 SetPenState(oldPen);
 { restore the previous grafPort }
 SetPort(oldPort);
 { dispose of the regions’ storage }
 DisposeRgn(oldClip);
 DisposeRgn(newClip);
 END;  { with }
END;  { RestoreState }

(*****************************************************
DrawCell:  Draws the given cell, either selected or
 normal, by drawing the control stored in the cell.
*****************************************************)

PROCEDURE DrawCell(lSelect: Boolean;lRect: Rect;
 lCell: Cell;lHandle: ListHandle);
VAR
 oldState:StateStuff;
 ch:    ControlHandle;
 dl:    INTEGER;

BEGIN
 { save the current drawing environment }
 SaveState(oldState, lRect, lHandle);
 
 { get the cell’s data }
 dl := sizeof(Handle);
 LGetCell(@ch, dl, lCell, lHandle);
 
 { update the control’s fields }
 with ch^^ do begin
 contrlRect := lRect;
 contrlVis:= isVIS;
 
 { ensure proper hiliting }
 if (lSelect) then
 contrlHilite := titlePart
 else begin
 contrlHilite := 0;
 end;  { if }
 end;  { with ch^^ }
 
 { draw the control }
 Draw1Control(ch);

 { restore the previous drawing state }
 RestoreState(oldState);
END;  { DrawCell }

END.  { ControlLDEF}
Listing:  Test.p

(*****************************************************
Test.p
 List-of-Controls example, using pop-up menu controls.
*****************************************************)

PROGRAM Test;

USES
 {$U MemTypes.p    } MemTypes,
 {$U QuickDraw.p   } QuickDraw,
 {$U OSIntf.p      } OSIntf,
 {$U ToolIntf.p    } ToolIntf,
 {$U PackIntf.p    } PackIntf,
 {$U PopMenuIntf.p } PopMenuIntf;

CONST
 RES_ID =    128;{ resource ID’s }
 
 iOK    = 1;{ OK button }
 iLIST  = 2;{ list of controls}
 
 { visibility }
 isVIS  =    255;
 notVIS = 0;

TYPE
 { Pascal equivalent of ‘INT#’ resource type }
 IntList = record
 count: INTEGER;
 int:   array[1..1024] of INTEGER;
 end;  { IntList }
 
 ILPointer = ^IntList;
 ILHandle = ^ILPointer;

VAR
 myDialog:DialogPtr; { test dialog }
 lh:    ListHandle;{ handle to list}
 itemHit: INTEGER; { user’s choice}
 savePort:GrafPtr; { to save port in}

(*****************************************************
CenterWindow:  Centers the given window in the screen.  If the ‘show’ 
argument is TRUE, then the window is shown.
*****************************************************)

PROCEDURE CenterWindow(wPtr: WindowPtr; show: Boolean);
VAR
 pRect: Rect;
 wRect: Rect;
 h, v:  INTEGER;
 
BEGIN
 pRect := screenBits.bounds;
 wRect := WindowPeek(wPtr)^.port.portRect;
 v := ((pRect.bottom - pRect.top) -
 (wRect.bottom - wRect.top)) div 3;
 h := ((pRect.right - pRect.left) -
 (wRect.right - wRect.left)) div 2;
 MoveWindow(wPtr, h, v, show);
 if (show) then begin
 ShowWindow(wPtr);
 end;
END;  { CenterWindow }

(*****************************************************
FixCtlRects:  Make the contrlRects of all controls in
 the list match their list rectangles, and that controls
 in invisible cells are also invisible.
*****************************************************)

PROCEDURE FixCtlRects(lh: ListHandle);
VAR
 ch:    ControlHandle;
 i:INTEGER;
 dl:    INTEGER;
 toRect:Rect;
 c:Cell;
 
BEGIN
 { default }
 dl := sizeof(Handle);
 { update the controls in the list }
 FOR i := 0 to (lh^^.dataBounds.bottom - 1) DO BEGIN
 { define cell to access }
 SetPt(Point(c), 0, i);
 { get the control handle from the cell }
 LGetCell(@ch, dl, c, lh);
 IF (PtInRect(Point(c), lh^^.visible)) THEN
 BEGIN
 { get cell rect; copy into control rect }
 LRect(toRect, c, lh);
 ch^^.contrlRect := toRect;
 { make sure the control is visible }
 ch^^.contrlVis := isVIS;
 END
 ELSE BEGIN
 { make sure the control is invisible }
 ch^^.contrlVis := notVIS;
 END;
 END;
END;  { FixCtlRects }

(*****************************************************
FindCell:  Find the cell in the given list containing
 the given point, which is assumed to be in local
 coördinates.  If the point is not in the list’s
 rectangle, the resulting cell will have both
 h and v set to (-1).
*****************************************************)

FUNCTION FindCell(p: Point; lh: ListHandle): Cell;
VAR
 c:   Cell;

BEGIN
 with lh^^ do begin
 if (not PtInRect(p, rView)) then
 SetPt(Point(c), -1, -1)
 else with rView.topLeft do begin
 c.h := ((p.h - h) DIV cellSize.h) + visible.left;
 c.v := ((p.v - v) DIV cellSize.v) + visible.top;
 end;  { else, with rView.topLeft }
 end;  { with lh^^ }
 FindCell := c;
END;  { FindCell }

(*****************************************************
doKeyDown:  Filters all keyDown events in the modal
 dialog, implementing the standard keyboard
 equivalents for the OK button.
*****************************************************)
FUNCTION doKeyDown(dPtr: DialogPtr; VAR theEvent:  EventRecord; VAR itemHit: 
INTEGER): Boolean;
VAR
 c:LONGINT;
BEGIN
 { default }
 doKeyDown := FALSE;
 
 { get the ascii code }
 c := BitAnd(theEvent.message, charCodeMask);
 
 { check for Return or Enter }
 IF ((c = 3) or ( c = 13)) THEN BEGIN
 itemHit := iOK;
 doKeyDown := TRUE;
 END;  { if }
END;  { doKeyDown }

(*****************************************************
doMouseDown
*****************************************************)
FUNCTION doMouseDown(dPtr: DialogPtr; VAR theEvent:  EventRecord; VAR 
itemHit: INTEGER): Boolean;
VAR
 item:  INTEGER;
 part:  INTEGER;
 pt:    Point;
 c:Cell;
 ch:    ControlHandle;
 dbl:   Boolean;
 sel:   Boolean;
BEGIN
 pt := theEvent.where;
 GlobalToLocal(pt);
 
 { See Tech Note #112, FindDItem() }
 item := FindDItem(dPtr, pt) + 1;
 
 IF (item = iLIST) THEN
 BEGIN
 { in whom did the mouseDown occur? }
 part := FindControl(pt, dPtr, ch);
 
 IF ((ch = nil) or (ch = lh^^.vScroll)) THEN
 BEGIN
 { clicked in list or in scroll bar }
 dbl := LClick(pt,
 theEvent.modifiers,
 lh);
 
 { fix the controls’ contrlRects }
 FixCtlRects(lh);
 END
 ELSE BEGIN { clicked in pop-up menu }
 part := TrackControl(ch, pt, POINTER(-1));
 { what cell was the mouseDown in? }
 c := FindCell(pt, lh);
 { redraw the control if cell was selected }
 if (LGetSelect(false, c, lh)) then begin
 HiliteControl(ch, titlePart);
 end;  { if }
 END;  { else }
 doMouseDown := TRUE;
 END  { item = iLIST }
 ELSE BEGIN
 doMouseDown := FALSE;
 END;
END;  { doMouseDown }

(*****************************************************
doUpdateEvt
*****************************************************)
FUNCTION doUpdateEvt(dPtr: DialogPtr; VAR theEvent:  EventRecord; VAR 
itemHit: INTEGER): Boolean;
BEGIN
 { begin the update }
 BeginUpdate(dPtr);
 
 { update the dialog items }
 UpdtDialog(dPtr, dPtr^.visRgn);
 
 { update the list }
 LUpdate(dPtr^.visRgn, lh);
 
 { end the update } 
 EndUpdate(dPtr);
 
 { always return true (we handled it) }
 doUpdateEvt := TRUE;
END;  { doUpdateEvt }

(*****************************************************
MyFilter
*****************************************************)
FUNCTION MyFilter(dPtr: DialogPtr; VAR theEvent:  EventRecord; VAR itemHit: 
INTEGER): Boolean;
BEGIN
 CASE theEvent.what OF
 keyDown:
 MyFilter := doKeyDown(dPtr, theEvent,
 itemHit);
 mouseDown:
 MyFilter := doMouseDown(dPtr, theEvent, 
 itemHit);
 updateEvt:
 MyFilter := doUpdateEvt(dPtr, theEvent, 
 itemHit);
 OTHERWISE
 MyFilter := FALSE;
 END;  { case }
END;  { MyFilter }

(*****************************************************
DrawUserItems
*****************************************************)
PROCEDURE DrawUserItems(wPtr: WindowPtr;itemNo: INTEGER);
VAR
 savePen: PenState;
 ik:    INTEGER;
 ih:    Handle;
 ib:    Rect;
BEGIN { DrawUserItems }
 { save, naormalize the pen state }
 GetPenState(savePen);
 PenNormal;
 
 { frame the list }
 GetDItem(wPtr, iLIST, ik, ih, ib);
 FrameRect(ib);
 
 { frame the default button }
 GetDItem(wPtr, iOK, ik, ih, ib);
 InsetRect(ib, -4, -4);
 PenSize(3, 3);
 FrameRoundRect(ib, 16, 16);
 
 { restore the pen’s state }
 SetPenState(savePen);
END;  { DrawUserItems }

(*****************************************************
ReadData: Reads in a number of controls, as specified
 by a ‘INT#’ integer-array resource.  Defines new
 controls for each.
*****************************************************)
FUNCTION ReadData(dPtr: DialogPtr): Boolean;
VAR
 ch:    ControlHandle;
 iah:   ILHandle;
 i:INTEGER;
 n:INTEGER;
 ignore:INTEGER;
 aCell: Cell;
 p:Point;
 aRect: Rect;
BEGIN { ReadData }
 { get handle to ‘INT#’ resource }
 iah := ILHandle(GetResource(‘INT#’, RES_ID));
 
 IF (iah <> nil) THEN BEGIN
 { disable list drawing }
 LDoDraw(false, lh);
 
 FOR i := 1 TO iah^^.count DO BEGIN
 { create a new control  }
 ch := GetNewControl(iah^^.int[i], dPtr);
 
 IF (ch = nil) THEN LEAVE;
 
 { make the control visible, without drawing }
 ch^^.contrlVis := 255;
 
 ignore := LAddRow(1, 32767, lh);
 SetPt(Point(aCell), 0, i - 1);
 LSetCell(@ch, sizeof(Handle), aCell, lh);
 END;  { for }
 
 { fix the controls’ contrlRects }
 FixCtlRects(lh);
 
 { select first control }
 SetPt(Point(aCell), 0, 0);
 LSetSelect(true, aCell, lh);
 
 { enable list drawing }
 LDoDraw(true, lh);
 END;  { iah <> nil }
 
 { return TRUE if controls were read OK }
 ReadData := (iah <> nil);
END;  { ReadData }

(*****************************************************
InitList:  Define and allocate new list, into which
 will be placed a number of control handles.
 (See ReadData(), above.)
*****************************************************)
PROCEDURE InitList(dPtr: DialogPtr);
VAR
 ik:    INTEGER;
 ih:    Handle;
 ib:    Rect;
 dBounds: Rect;
 cSize: Point;
BEGIN
 { set up the userItem drawing routine }
 GetDItem(dPtr, iLIST, ik, ih, ib);
 SetDItem(dPtr, iLIST, ik, Handle(@DrawUserItems), ib);
 
 { inset rect, for drawing; leave room for scroll bar }
 InsetRect(ib, 1, 1);
 ib.right := ib.right - 15;
 
 { allocate space for a single column, no rows }
 SetRect(dBounds, 0, 0, 1, 0);
 
 { indicate cell size }
 SetPt(cSize, ib.right-ib.left, 20);
 
 { create the list }
 lh := LNew(ib,  { rView  }
 dBounds, { dataBounds  }
 cSize, { cell size}
 RES_ID,   { resource ID  }
 dPtr,    { this window }
 false, { draw it}
 false, { grow box }
 false, { sBar, horiz}
 true); { sBar, vert }
END;  { InitList }

(*****************************************************
CleanUp:  My name is CleanUp().  You killed my dialog.
 Prepare to die!
*****************************************************)
PROCEDURE CleanUp(dPtr: DialogPtr);
VAR
 ch:    ControlHandle;
 i:INTEGER;
 dl:    INTEGER;
 c:Cell;
BEGIN
 { default }
 dl := sizeof(Handle);
 
 { indicate wait }
 SetCursor(GetCursor(watchCursor)^^);
 
 { deallocate the controls from the list }
 FOR i := 0 to (lh^^.dataBounds.bottom - 1) DO BEGIN
 SetPt(Point(c), 0, i);
 LGetCell(@ch, dl, c, lh);
 DisposeControl(ch);
 END;  { for }
 
 { dispose of the list }
 LDispose(lh);
 { dispose of the dialog }
 DisposDialog(dPtr);
END;  { CleanUp }

(*****************************************************
Main
*****************************************************)
BEGIN
 { perform the ritual incantation }
 InitGraf(@thePort); 
 InitFonts; 
 FlushEvents(everyEvent, 0);
 InitWindows;    
 InitMenus; 
 TEInit;
 InitDialogs(NIL); 
 InitCursor;

 { read in the dialog from its resource template }
 myDialog := GetNewDialog(RES_ID, NIL, POINTER(-1));
 
 { create and init the list of controls }
 InitList(myDialog);
 
 IF (ReadData(myDialog)) THEN BEGIN
 { center and show the dialog }
 CenterWindow(myDialog, true);
 
 { save grafPort, make ours current }
 GetPort(savePort);
 SetPort(myDialog);
 
 { cycle through ModalDialog() }
 REPEAT
 ModalDialog(@MyFilter, itemHit);
 UNTIL itemHit = iOK;
 
 { restore grafPort }
 SetPort(savePort);
 END;
 { dispose of the dialog’s storage }
 CleanUp(myDialog);
END.  { FILE Test.p, PROGRAM Test.p }
Listing:  Test.r

/*****************************************************
Test.r
 Resources for List-Of-Controls example.
*****************************************************/
/***********************Types***********************/
#include “Types.r”
#include “PopMenuCDEF.r”

type ‘INT#’ {
 integer = $$Countof(IntegerArray);
 
 array IntegerArray {
 integer;
 };
};
/**********************Defines**********************/
#define RES_ID   128
/*********************Resources********************/
data ‘LDEF’ (RES_ID, “ControlLDEF”) {
 $$resource(“ControlLDEF.LDEF”, ‘LDEF’, 1)
};
data ‘CDEF’ (pmCDEFResID, “popMenus”) {
 $$resource(“PopMenuCDEF.CDEF”, ‘CDEF’, 1)
};
resource ‘DLOG’ (RES_ID, “RES_ID”) {
 {54, 170, 254, 470},
 dBoxProc,
 invisible,
 noGoAway,
 0x0,
 RES_ID,
 “”
};
resource ‘DITL’ (RES_ID, “RES_ID”) {
 { /* array DITLarray: 3 elements */
 /* [1] */
 {170, 125, 190, 185},
 Button {
 enabled,
 “OK”
 },
 /* [2] */
 {10, 10, 72, 290},
 UserItem {
 enabled
 },
 /* [3] */
 {82, 10, 160, 290},
 StaticText {
 disabled,
 “List of Controls LDEF example.  “
 “James Plamondon, Abacus Concepts, “
 “1984 Bonita Avenue, Berkeley, CA  “
 “94704.”
 }
 }
};
resource ‘INT#’ (RES_ID, “Control ID’s”) {
 { /* array INTArray: 5 elements */
 /* [1] */
 128,
 /* [2] */
 129,
 /* [3] */
 130,
 /* [4] */
 131,
 /* [5] */
 132
 }
};
resource ‘CNTL’ (128) {
 {0, 0, 0, 0},   /* rect:  contrlRect*/
 128,   /* value: menu rsrc ID   */
 invisible, /* vis:  standard */
 128,   /* max:  default menuID  */
 2,/* min:  default item #*/
 popMenuProc   /* ProcID:  3  */
 + mCheck,/* var: Check selection  */
 0,/* rfCon: for user’s use */
 “Thanks to: “   /* title: standard*/
};
resource ‘MENU’ (128) {
 128,
 textMenuProc,
 allEnabled,
 enabled,
 “Thanks To: “,
 { /* 11 items */
 “Mark Williams”,
 noIcon, noKey, noMark, plain;
 “Mark Bennet”,
 noIcon, noKey, appleChar, plain;
 “Joseph Daniel”,
 noIcon, noKey, noMark, plain;
 “Dr. Don Morrison”,
 noIcon, noKey, noMark, plain;
 “Andrew Stone”,
 noIcon, noKey, noMark, plain;
 “Eleanor Plamondon”,
 noIcon, noKey, noMark, plain;
 “Bruce Wampler”,
 noIcon, noKey, noMark, plain;
 “Patricia Guffey”,
 noIcon, noKey, noMark, plain;
 “Greta Shaw”,
 noIcon, noKey, noMark, plain;
 “Monty \”Montana-Unit\” Cole”,
 noIcon, noKey, noMark, plain;
 “Dr. Bernard Moret”,
 noIcon, noKey, noMark, plain
 }
};
resource ‘CNTL’ (129) {
 {0, 0, 0, 0},   /* rect:  contrlRect*/
 129,   /* value: rsrc ID */
 invisible, /* vis:  standard */
 129,   /* max: default  menuID  */
 2,/* min:  default item #*/
 popMenuProc   /* ProcID: 3 */
 + mRes /* var: add res names */
 + mCheck,/* var: Check selection  */
 ‘FONT’,/* rfCon: OSType  */
 “Fonts: “/* title: standard*/
};
resource ‘MENU’ (129) {
 129,
 textMenuProc,
 allEnabled,
 enabled,
 “Fonts:        “,
 { /* 0 items */
 }
};
resource ‘CNTL’ (130) {
 {0, 0, 0, 0},   /* rect:  contrlRect*/
 130,   /* value: rsrc ID */
 invisible, /* vis:  standard */
 133,   /* max:  default menuID  */
 1,/* min: default  item #*/
 popMenuProc/* ProcID: 3  */
 + mCheck /* var: Check selection  */
 + mSub,/* var: sub-menus */
 0,/* rfCon: for user’s use */
 “SubMenu: “/* title: standard*/
};
resource ‘MENU’ (130) {
 130,
 textMenuProc,
 allEnabled,
 enabled,
 “Root:          “,
 { /* 2 items */
 “Root Item1”,
 noIcon, parent, “\0D131”, plain;
 “Root Item2”,
 noIcon, parent, “\0D132”, plain
 }
};
resource ‘MENU’ (131) {
 131,
 textMenuProc,
 allEnabled,
 enabled,
 “”,
 { /* 2 items */
 “Sub-1 Item1”,
 noIcon, noKey, noMark, plain;
 “Sub-1 Item2”,
 noIcon, noKey, noMark, plain;
 “Sub-1 Item3”,
 noIcon, parent, “\0D133”, plain
 }
};
resource ‘MENU’ (132) {
 132,
 textMenuProc,
 allEnabled,
 enabled,
 “”,
 { /* 2 items */
 “Sub-2 Item1”,
 noIcon, noKey, noMark, plain;
 “Sub-2 Item2”,
 noIcon, noKey, noMark, plain;
 “Sub-2 Item3 (a very, very, very wide item)”,
 noIcon, noKey, noMark, plain
 }
};
resource ‘MENU’ (133) {
 133,
 textMenuProc,
 allEnabled,
 enabled,
 “”,
 { /* 2 items */
 “Sub-3 Item1”,
 noIcon, noKey, noMark, plain;
 “Sub-3 Item2”,
 noIcon, noKey, noMark, plain;
 “Sub-3 Item3”,
 noIcon, noKey, noMark, plain
 }
};
resource ‘CNTL’ (131) {
 {0, 0, 0, 0},   /* rect:  contrlRect*/
 134,   /* value: menu rsrc ID   */
 invisible, /* vis:  standard */
 134,   /* max:  default menuID  */
 1,/* min:  default item #*/
 popMenuProc   /* ProcID:  3  */
 + mCheck,/* var: Check selection  */
 0,/* rfCon: for user’s use */
 “At Abacus: “   /* title: standard*/
};
resource ‘MENU’ (134) {
 134,
 textMenuProc,
 allEnabled,
 enabled,
 “At Abacus: “,
 { /* 5 items */
 “Dan Feldman”,
 noIcon, noKey, noMark, plain;
 “Jim Gagnon”,
 noIcon, noKey, noMark, plain;
 “Will Scoggin”,
 noIcon, noKey, noMark, plain;
 “James Plamondon”,
 noIcon, noKey, noMark, plain;
 “Jay Roth”,
 noIcon, noKey, noMark, plain;
 “Tiffiny Fyans”,
 noIcon, noKey, noMark, plain;
 “Jeanette Stafford”,
 noIcon, noKey, noMark, plain
 }
};
resource ‘CNTL’ (132) {
 {0, 0, 0, 0},   /* rect:  contrlRect*/
 135,   /* value: menu rsrc ID   */
 invisible, /* vis:  standard */
 135,   /* max:  default menuID  */
 1,/* min:  default item #*/
 popMenuProc   /* ProcID:  3  */
 + mCheck,/* var: Check selection  */
 0,/* rfCon: for user’s use */
 “Programs: “    /* title: standard*/
};
\resource ‘MENU’ (135) {
 135,
 textMenuProc,
 allEnabled,
 enabled,
 “Programs: “,
 { /* 5 items */
 “StatView”,
 noIcon, noKey, noMark, plain;
 “StatView 512+”,
 noIcon, noKey, noMark, plain;
 “StatView SE+Graphics”,
 noIcon, noKey, noMark, plain;
 “StatView II”,
 noIcon, noKey, noMark, plain;
 “SuperANOVA”,
 noIcon, noKey, noMark, plain
 }
};

 
AAPL
$102.47
Apple Inc.
+2.71
MSFT
$44.88
Microsoft Corpora
+0.80
GOOG
$526.54
Google Inc.
+5.70

MacTech Search:
Community Search:

Software Updates via MacUpdate

RapidWeaver 6.0 - Create template-based...
RapidWeaver is a next-generation Web design application to help you easily create professional-looking Web sites in minutes. No knowledge of complex code is required, RapidWeaver will take care of... Read more
NTFS 12.0.39 - Provides full read and wr...
Paragon NTFS breaks down the barriers between Windows and OS X. Paragon NTFS effectively solves the communication problems between the Mac system and NTFS, providing full read and write access to... Read more
RestoreMeNot 2.0.3 - Disable window rest...
RestoreMeNot provides a simple way to disable the window restoration for individual applications so that you can fine-tune this behavior to suit your needs. Please note that RestoreMeNot is designed... Read more
Macgo Blu-ray Player 2.10.9.1750 - Blu-r...
Macgo Mac Blu-ray Player can bring you the most unforgettable Blu-ray experience on your Mac. Overview Macgo Mac Blu-ray Player can satisfy just about every need you could possibly have in a Blu-ray... Read more
Apple iOS 8.1 - The latest version of Ap...
The latest version of iOS can be downloaded through iTunes. Apple iOS 8 comes with big updates to apps you use every day, like Messages and Photos. A whole new way to share content with your family.... Read more
TechTool Pro 7.0.5 - 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
PDFKey Pro 4.0.2 - Edit and print passwo...
PDFKey Pro can unlock PDF documents protected for printing and copying when you've forgotten your password. It can now also protect your PDF files with a password to prevent unauthorized access and/... Read more
Yasu 2.9.1 - System maintenance app; per...
Yasu was originally created with System Administrators who service large groups of workstations in mind, Yasu (Yet Another System Utility) was made to do a specific group of maintenance tasks... Read more
Hazel 3.3 - Create rules for organizing...
Hazel is your personal housekeeper, organizing and cleaning folders based on rules you define. Hazel can also manage your trash and uninstall your applications. Organize your files using a... Read more
Autopano Giga 3.7 - Stitch multiple imag...
Autopano Giga allows you to stitch 2, 20, or 2,000 images. Version 3.0 integrates impressive new features that will definitely make you adopt Autopano Pro or Autopano Giga: Choose between 9... Read more

Latest Forum Discussions

See All

Fiete – A Day on a Farm Review
Fiete – A Day on a Farm Review By Amy Solomon on October 21st, 2014 Our Rating: :: A MEMORABLE EXPERIENCEUniversal App - Designed for iPhone and iPad Fiete – A day on a farm in an interactive app for young children full of... | Read more »
Tilt to Live: Gauntlet’s Revenge is Almo...
Tilt to Live: Gauntlet’s Revenge is Almost Here Posted by Jessica Fisher on October 21st, 2014 [ permalink ] One Man Left has announced the official release date of Tilt to Live: Gauntlet’s Re | Read more »
Sago Mini Monsters Celebrates Halloween...
Sago Mini Monsters Celebrates Halloween with Fun Costumes and Special Treats. Posted by Jessica Fisher on October 21st, 2014 [ permal | Read more »
Inferno 2 Review
Inferno 2 Review By Andrew Fisher on October 21st, 2014 Our Rating: :: TWIN STICK GOODNESSUniversal App - Designed for iPhone and iPad With tight controls and awesome, stark visuals, Inferno 2 is loads of fun.   | Read more »
Clips Review
Clips Review By Jennifer Allen on October 21st, 2014 Our Rating: :: CONVENIENT PASTINGUniversal App - Designed for iPhone and iPad Making copying and pasting more powerful than usual, Clips is a great way to move stuff around.   | Read more »
MonSense Review
MonSense Review By Jennifer Allen on October 21st, 2014 Our Rating: :: ORGANIZED FINANCESiPhone App - Designed for the iPhone, compatible with the iPad Organize your finances with the quick and easy to use, MonSense.   | Read more »
This Week at 148Apps: October 13-17, 201...
Expert App Reviewers   So little time and so very many apps. What’s a poor iPhone/iPad lover to do? Fortunately, 148Apps is here to give you the rundown on the latest and greatest releases. And we even have a tremendous back catalog of reviews; just... | Read more »
Angry Birds Transformers Review
Angry Birds Transformers Review By Jennifer Allen on October 20th, 2014 Our Rating: :: TRANSFORMED BIRDSUniversal App - Designed for iPhone and iPad Transformed in a way you wouldn’t expect, Angry Birds Transformers is a quite... | Read more »
GAMEVIL Announces the Upcoming Launch of...
GAMEVIL Announces the Upcoming Launch of Mark of the Dragon Posted by Jessica Fisher on October 20th, 2014 [ permalink ] Mark of the Dragon, by GAMEVIL, put | Read more »
Interview With the Angry Birds Transform...
Angry Birds Transformers recently transformed and rolled out worldwide. This run-and-gun title is a hit with young Transformers fans, but the ample references to classic Transformers fandom has also earned it a place in the hearts of long-time... | Read more »

Price Scanner via MacPrices.net

Select MacBook Airs $100 off MSRP, free shipp...
B&H Photo has 2014 a couple of MacBook Airs on sale for $100 off MSRP. Shipping is free, and B&H charges NY sales tax only. They also include free copies of Parallels Desktop and LoJack for... Read more
13-inch 2.5GHz MacBook Pro on sale for $100 o...
B&H Photo has the 13″ 2.5GHz MacBook Pro on sale for $999.99 including free shipping plus NY sales tax only. Their price is $100 off MSRP. Read more
Strong iPhone, Mac And App Store Sales Drive...
Apple on Monday announced financial results for its fiscal 2014 fourth quarter ended September 27, 2014. The Company posted quarterly revenue of $42.1 billion and quarterly net profit of $8.5 billion... Read more
Apple Posts How-To For OS X Recovery
OS X 10.7 Lion and later include OS X Recovery. This feature includes all of the tools you need to reinstall OS X, repair your disk, and even restore from a Time Machine backup. OS X Recovery... Read more
Mac OS X Versions (Builds) Supported By Vario...
Apple Support has posted a handy resource explaining which Mac OS X versions (builds) originally shipped with or are available for your computer via retail discs, downloads, or Software Update. Apple... Read more
Deals on 2011 13-inch MacBook Airs, from $649
Daily Steals has the Mid-2011 13″ 1.7GHz i5 MacBook Air (4GB/128GB) available for $699 with a 90 day warranty. The Mid-2011 13″ 1.7GHz i5 MacBook Air (4GB/128GB SSD) is available for $649 at Other... Read more
2013 15-inch 2.0GHz Retina MacBook Pro availa...
B&H Photo has leftover previous-generation 15″ 2.0GHz Retina MacBook Pros now available for $1599 including free shipping plus NY sales tax only. Their price is $400 off original MSRP. B&H... Read more
Updated iPad Prices
We’ve updated our iPad Air Price Tracker and our iPad mini Price Tracker with the latest information on prices and availability from Apple and other resellers, including the new iPad Air 2 and the... Read more
Apple Pay Available to Millions of Visa Cardh...
Visa Inc. brings secure, convenient payments to iPad Air 2 and iPad mini 3as well as iPhone 6 and 6 Plus. Starting October 20th, eligible Visa cardholders in the U.S. will be able to use Apple Pay,... Read more
Textkraft Pocket – the missing TextEdit for i...
infovole GmbH has announced the release and immediate availability of Textkraft Pocket 1.0, a professional text editor and note taking app for Apple’s iPhone. In March 2014 rumors were all about... Read more

Jobs Board

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
*Apple* Solutions Consultant (ASC) - Apple (...
**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 / Business Analyst, WW *Appl...
…a senior project manager / business analyst to work within our Worldwide Apple Fulfillment Operations and the Business Process Re-engineering team. This role will work Read more
*Apple* Retail - Multiple Positions (US) - A...
Job Description: Sales Specialist - Retail Customer Service and Sales Transform Apple Store visitors into loyal Apple customers. When customers enter the store, Read more
Position Opening at *Apple* - Apple (United...
…customers purchase our products, you're the one who helps them get more out of their new Apple technology. Your day in the Apple Store is filled with a range of Read more
All contents are Copyright 1984-2011 by Xplain Corporation. All rights reserved. Theme designed by Icreon.