Path: news.uiowa.edu!chi-news.cic.net!cs.utexas.edu!cs.utexas.edu!howland.reston.ans.net!swrinde!elroy.jpl.nasa.gov!ames!waikato!news.express.co.nz!actrix.gen.nz!atlantis.actrix.gen.nz!not-for-mail From: dempson@atlantis.actrix.gen.nz (David Empson) Newsgroups: comp.sys.apple2.programmer Subject: Re: Creating Lists & Using them Date: 23 Jun 1996 03:50:44 +1200 Organization: Actrix - Internet Services Lines: 229 Message-ID: <4qh4ok$n1n@atlantis.atlantis.actrix.gen.nz> References: <31C58183.41C6@aix.ensam.fr> NNTP-Posting-Host: atlantis.actrix.gen.nz In article <31C58183.41C6@aix.ensam.fr>, BERNARD Benjamin ENSAM 1ere Annee wrote: > I really have no idea how to use Lists. The ToolBox Ref 1&3 are not > clear enough, and I have no programming example (excepted one TechNote > on Lists in a dialog window). I haven't used lists myself, but I have looked into it, and I think I can understand enough about the details of using them to point you in the right direction. > - How do I create lists? I see from your later article that you have already managed to create the list itself using Genesys. I assume that you are creating a window using NewWindow2(), which creates the windows and all associated controls. (You asked about NewControl2 in your later article: you don't need to call this if your resources are set up correctly, because NewWindow2 calls it for you.) When you create a List Control, Genesys offers options for Invisible (should not be marked unless you want to hide the list until something else happens), Multi-select (should not be marked in this case), and a reference constant (this is an arbitrary value that you can use for anything you like). It has dimmed buttons for editing the list and setting the colours, so I assume that these features were not implemented. Looking at the List control template (page 28-57 of TB Ref III), the Genesys list definition is missing options to set the colours (you probably won't need that), and a method for attaching data to the list automatically. It also doesn't let you set some important details of the list definition. The list control is automatically created with the following settings: listSize = 0 (no members) listView = variable (set according to the size of the control) listType = variable (2 or 0, depending on the multiple/single option) listStart = 0 listMemHeight = 10 (correct for a standard list) listMemSize = 5 (minimum value) It should be possible to set up the list with data already attached, if you use Rez to generate the controls. (You can generate Rez source for what you have so far from within Genesys, then edit the output file as necessary). Genesys doesn't let you set the option for whether the scroll bar is inside or outside the rectangle (not a major issue if you are placing the list visually). More importantly, it doesn't indicate whether the list is set to hold Pascal or C strings. From the Rez source output, I can see that bit 0 of listType is clear, thus it will expect C strings. These are you main alternatives: 1. Stick with the window design as you have it, with Genesys creating the list control. You then have to add the data to the list after the window has been created (you should set the window to be invisible in the resource definition, then make it visible after you have finished setting up the list control). 2. Detach the list control from the window definition, but leave the control resource there. Create the control yourself (using NewControl2, referring to the resource) after the window has been created. You will still have to provide the data in a separate step, unless you use Rez to define the resource. 3. Load the List Control resource manually, detach it from the resource, and modify the handle contents to attach the list data, then call NewControl2 to create the list control. 4. Get the details of the list definition, and create it manually using NewControl2 (with a pointer-based template in your source code). Option 3 is probably the easiest one in the long term, but option 1 is where you are at now, so I'll explain what else is needed there. You have just created your invisible window using NewWindow2. You now need to locate the list control and update it as required. First, note the ID of the list control (it is shown in the configuration dialog for the control in Genesys). Call GetCtlHandleFromID to get the handle of the control. You can now use the handle to make calls to the List Manager to set up the list. You should be using the calls documented in TB Ref Vol 3 (chapter 35), but you also need to refer to volume 1 (chapter 11) to get some background information on the List Manager. The first call you will have to make is NewList2. This forgets about any data associated with the list and replaces it with new data you provide. To understand the parameters to NewList2, refer to the description of the "list record" on pages 11-4 to 11-8 of TB Ref Vol 1. listStart should probably be 1. It indicates which item in the list is to be displayed initially at the top of the list. listRef should be a pointer or handle to your list data. The data must be organised as a series of "member records" (see page 11-6). The member record is at least five bytes per list entry: a four-byte pointer to the string to be displayed (for a standard list), and a one byte flag indicating whether this member is selected, disabled or enabled but not selected. You can attach an arbitrary amount of data to each member record, e.g. if you want to store an identification code, or a pointer or handle to further data for the member, then you just need to enlarge the member record to fit the extra information. All member records must be the same size. However, Genesys doesn't let you set the member size (it is fixed at 5 bytes per member). If you want to attach extra data to each member record, you will have to directly modify the ctlMemSize field in the control record (accessed via the handle). Continuing with the parameters to NewList2: listRefDesc indicates whether listRef is a pointer, handle or resource ID (you can put your list data in resources, but I haven't looked into the details on that). listSize indicates how many members are in the list. Here is some example code. I am assuming that you have a predetermined list of strings, and you don't need to associate any extra data with the list member records. #define MyWindowResID 0x00000FFAL /* Resource ID of the window */ #define MyListCtlID 0x00000001L /* Control ID for the list */ #define NumberOfMembers 10 typedef struct { char *memPtr; /* Pointer to the member text */ byte memFlag; /* Flags */ } member; static member MyListData[NumberOfMembers] = { {"The quick brown fox", memSelected}, {"The owl and the pussycat", 0}, {"Jabberwocky", 0}, {"The Vogon Captain's poem", 0}, {"Ode to a small lump of green putty...", 0}, {"I'm running out of ideas", 0}, {"Throw a few more lines in here", 0}, {"Oh freddled gruntbuggly, thy micturations are to me", 0}, {"as plurdled gabbleblotchits on a lurgid bee.", 0}, {"This is the last entry", 0} }; grafPortPtr CreateMyWindowAndList(void) { grafPortPtr theWindow; ctlHandle theList; theWindow = NewWindow2(NULL, /* No title */ 0, /* No refCon */ NULL, /* No content draw */ NULL, /* Standard defProc */ refIsResource, /* Getting a resource */ MyWindowResID, /* The Resource ID */ rWindParam1); /* The resource type */ if (theWindow == NULL) return NULL; /* It didn't work! */ theList = GetCtlHandleFromID(theWindow, MyListCtlID); if (theList == NULL) return theWindow; /* Hm, where did it go? */ /* At this point, you could patch the member size field if you need extra data, e.g. by using something like this (see the header files for exact details - there may be a union involved, or you might have to do a horrible expression to refer directly to the field). (**theList).ctlMemSize = sizeof(member); */ /* Now we set up the list contents */ NewList2(NULL, /* Standard draw procedure */ 1, /* Show item 1 at the top */ (long)MyListData, /* Pointer to data */ refIsPtr, /* It is a pointer */ NumberOfMembers, /* List size */ theList); /* Control handle */ /* You can now make the window visible and get on with using it. */ return theWindow; }/*CreateMyWindowAndList*/ If you already have a separate array of C-strings, then you will have to construct the member record array, setting up a pointer to each C-string and an appropriate memFlag. Note that in my example, I made the first item selected initially, but you don't have to do this. Once you have created the list, you can let the Control Manager and List Manager take care of the user interface details. When the dialog is complete, and you want to find out which item the user selected, use the ResetMember2 call. (If it is a multiple-selection list, use NextMember2 to find subsequent selections.) You might also want to use the other list manager calls in special situations. Note that SortList2 will rearrange your member records (but it won't touch the strings that are pointed to by the member records). I think that about covers it. One last detail: if you want to use method 3 instead (loading the template resource and calling NewControl2 directly), then you can avoid patching the control record (for a larger member size) and you won't need to call NewList2, because all of the data is provided in the template to NewControl2. -- David Empson dempson@actrix.gen.nz Snail mail: P.O. Box 27-103, Wellington, New Zealand