💾 Archived View for mirrors.apple2.org.za › archive › apple.cabi.net › FAQs.and.INFO › GSOS › lists.… captured on 2023-03-20 at 22:50:21.

View Raw

More Information

⬅️ Previous capture (2023-01-29)

-=-=-=-=-=-=-

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  <bernardb@aix.ensam.fr> 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