From: nuk@wpi.WPI.EDU (Jacob W Anderson)
Subject: Problems with PopUp Menus
Organization: Worcester Polytechnic Institute
Date: Sun, 12 Apr 1992 07:16:47 GMT




In the code that follows this letter, there is a problem that I can not find.
I am using a MacSE with 4 megs of memory.  The problem is that when I try
to access the popup menus, one of the menus does not work properly.  More
specifically, this menu seems to be lost and one of the other menus is
substituted for it.  The menus that work are the "RaceMenu","ProfessionMenu"
and the menu that does not work properly is the "SexMenu".  The method that
I am using to place the heirarchical menus is to insert them in the (-1) 
position at the beginning of the program:
	InsertMenu(theMenu,-1)
This is what IM-V says to do when making these menus, but it seems that the
last menu that I place in the menulist (the order that I place them in the
menu has no effect on this problem) does not seem to work properly.  What is
happening is that when I select the "SexMenu" in the dialog, the "RaceMenu" is
displayed, but the indexing for finding the data from the selected menu
works properly.  I have changed the ID number of the faulty menu many times,
but this has not proven to be sufficient.  As far as I can see, this code
should work (it works for 2 out of 3 menus, hmmmm) and it does follow the
proper protocol that is present in IM-V.
	I think that it is a problem with the ID number of the lost menu, but
I can not seem to determine a safe ID number.  If anyone could show me where
my error is, I would greatly appreciate it.  Thank you very much.

		Please respond via E-Mail
	
		-Jake Anderson
		nuk@wpi.wpi.edu




/*
 * Character generation.c
 *
 */
 

#define	StatDLG		128
#define	OccupatDLG	129

#define	MAXSTATS	8
#define	NUMBMODS	4
#define	MAXDLGITEMS	10

#define	PLAY		1
#define	CANCEL		2
#define	PIKSKILLS	3
#define	PIKSTATS	3
#define	NAMEID		6
#define	REROLLID	4
#define	FIRSTSTAT	20
#define	LASTSTAT	27
#define SKILLPTS	52
#define	PROFESSIONTITLE	18
#define	RACETITLE		19
#define	RACEMENUITM	54
#define	PROFMENUITM	53
#define	SEXMENUITEM	56
#define	SEXTITLE	55

#define	FIRSTLIST	10
#define	LASTLIST	14

typedef struct ditem_type {
	int		itemType;
	Handle	item;
	Rect	box;
	} DItem;
	
typedef struct ditemlist_type {
	DItem	dItems[MAXDLGITEMS];
	} DItemList;

typedef int		StatList[MAXSTATS][NUMBMODS];

enum race_type	{RBLANK,HIGHELF,DARKELF,COMMONMAN,MTNDWARF,HIGHLANDER,HALFELF,HALFLING,
				 HALFTROLL,XENOBORG,HYLING};
enum sex_type	{SBLANK,MALE,FEMALE};
enum prof_type	{PBLANK,PALADIN,TRACKER,WARRIOR,HIWARRIOR,ROGUE,NINJA,NECROMANCER,WIZARD,
				 WARRMAGE,SAMURAI,MONK,HIMONK,BLACKMAGE,WARLOCKWITCH};
enum skill_etype {CLIMBIMG};

typedef enum race_type	RACE;
typedef enum prof_type	PROF;
typedef enum sex_type	SEX;
typedef enum skill_etype SKILL;

typedef struct skill_type {
	SKILL	theSkill;
	int		Rank;
	int		Bonus;
	struct skill_type	*next;
	} ASKILL;

typedef struct char_type {
	Str255		Name;
	StatList	Stats;
	RACE		Race;
	PROF		Profession;
	SEX			Sex;
	ASKILL		SkillHead;
	} ACHAR;

ACHAR			thePlayer;

DialogPtr		StatDialog;
DialogPtr		OccupationDialog;

DItem		ProfessionItem,RaceItem,SexItem;
DItem		SkillPnts;

Rect		RaceTitleBox,ProfessionTitleBox,SexTitleBox;

int			RollDone = FALSE;
long		PopUpSelect;

RollStats()
{
	int		index;
	float	PotPerc;
	
	for(index=0;index<MAXSTATS;index++) {
		thePlayer.Stats[index][0] = abs((Random() % 100)) + 1;
		PotPerc = (abs((Random() % 100)) + 1.0)/100.0;
		thePlayer.Stats[index][1] = (int)((100.0 - (float) thePlayer.Stats[index][0])*PotPerc) + thePlayer.Stats[index][0];
		}
}

UpdateStats(statList,whichStat)
DItemList	*statList;
int			whichStat;
{
	Str255	StringNum;
	int		index;
	
	for(index=FIRSTSTAT;index<=LASTSTAT;index++) {
		NumToString((long) thePlayer.Stats[index-FIRSTSTAT][whichStat],&StringNum);
		SetIText(statList->dItems[index-FIRSTSTAT].item,StringNum);
		}
}

UpdateSkillPnts(SkillPoints)
DItem	*SkillPoints;
{
	Str255	StringNum;
	
	NumToString((long) thePlayer.Profession,&StringNum);
	SetIText(SkillPoints->item,StringNum);
}

RetrieveDItem(theDialog,theItem,theID)
DialogPtr	theDialog;
DItem		*theItem;
int			theID;
{
	GetDItem(theDialog,theID,&(theItem->itemType),&(theItem->item),
											&(theItem->box));
}

SetPopMenu(thePopUpItem,thePopUpMenu,whichItem)
DItem		thePopUpItem;
MenuHandle	thePopUpMenu;
int			whichItem;
{
	Str255	theString;

	GetItem(thePopUpMenu,whichItem,&theString);
	SetIText(thePopUpItem.item,theString);
}

UpdatePopBox(thePopUpItem)
DItem		thePopUpItem;
{
	PenNormal();
	FrameRect(&thePopUpItem.box);
	HidePen();
	MoveTo(thePopUpItem.box.left+1,thePopUpItem.box.bottom);
	ShowPen();
	LineTo(thePopUpItem.box.right,thePopUpItem.box.bottom);
	LineTo(thePopUpItem.box.right,thePopUpItem.box.top+1);
}

PopUpControl(theMenu,thePoint,theResult,TitleBoundary,theItem,CurrVal)
MenuHandle	theMenu;
Point		thePoint;
int			*theResult;
Rect		TitleBoundary;
DItem		theItem;
int			CurrVal;
{
	long	PopUpSelect;
	
	SetPt(&thePoint,theItem.box.left,theItem.box.top);
	LocalToGlobal(&thePoint);
	InvertRect(&TitleBoundary);
	PopUpSelect = PopUpMenuSelect(theMenu,thePoint.v,
					thePoint.h,CurrVal);
	InvertRect(&TitleBoundary);
	*theResult = LoWord(PopUpSelect);
	if(*theResult == 0)
		*theResult = CurrVal;
	SetPopMenu(theItem,theMenu,*theResult);
	UpdatePopBox(theItem);
}

FixProfessionMenu()
{
	Str255	theString;
	char	*cString;
	
	GetItem(ProfessionMenu,WARLOCKWITCH,&theString);
	cString = PtoCstr(&theString);
	if((thePlayer.Sex == MALE)&&(strcmp(cString,"Warlock")!=0)) {
		SetItem(ProfessionMenu,WARLOCKWITCH,"\pWarlock");
		SetPopMenu(ProfessionItem,ProfessionMenu,thePlayer.Profession);
		UpdatePopBox(ProfessionItem);
		}
	else if((thePlayer.Sex == FEMALE)&&(strcmp(cString,"Witch")!=0)) {
		SetItem(ProfessionMenu,WARLOCKWITCH,"\pWitch");
		SetPopMenu(ProfessionItem,ProfessionMenu,thePlayer.Profession);
		UpdatePopBox(ProfessionItem);
		}
}

pascal Boolean StatFilter(theDialog,theEvent,itemHit)
DialogPtr	theDialog;
EventRecord	*theEvent;
int			*itemHit;
{
	Point	thePoint;
	WindowPtr	whichWindow;
	int		Selection;
	
	switch(theEvent->what) {
		case mouseDown: 
			SetPt(&thePoint,theEvent->where.h,theEvent->where.v);
			GlobalToLocal(&thePoint);
			if(PtInRect(thePoint,&RaceItem.box)) {
				Selection = thePlayer.Race;
				PopUpControl(RaceMenu,thePoint,&Selection,RaceTitleBox,
														RaceItem,Selection);
				thePlayer.Race = Selection;
				}
			else if(PtInRect(thePoint,&ProfessionItem.box)) {
				Selection = thePlayer.Profession;
				PopUpControl(ProfessionMenu,thePoint,&Selection,
							ProfessionTitleBox,ProfessionItem,Selection);
				thePlayer.Profession = Selection;
				UpdateSkillPnts(&SkillPnts);
				}
			else if(PtInRect(thePoint,&SexItem.box)) {
				Selection = thePlayer.Sex;
				PopUpControl(SexMenu,thePoint,&Selection,SexTitleBox,SexItem,
																	Selection);
				thePlayer.Sex = Selection;
				FixProfessionMenu();
				}
			break;
		case updateEvt:
			whichWindow = (WindowPtr) theEvent->message;
			if(whichWindow == StatDialog) {
				UpdatePopBox(RaceItem);
				UpdatePopBox(ProfessionItem);
				UpdatePopBox(SexItem);
				}
			break;
		}
	return(FALSE);
}

InitStats(TempStats,PotStats)
DItemList	*TempStats;
DItemList	*PotStats;
{
	int		whichItem;
	
	if(!RollDone) {
		thePlayer.Race = COMMONMAN;
		thePlayer.Sex = MALE;
		thePlayer.Profession = WARRIOR;
		}
	for(whichItem=FIRSTSTAT;whichItem<=LASTSTAT;whichItem++) { 
		RetrieveDItem(StatDialog,&(TempStats->dItems[whichItem-FIRSTSTAT]),whichItem);
		RetrieveDItem(StatDialog,&(PotStats->dItems[whichItem-FIRSTSTAT]),whichItem+8);
		}
	RetrieveDItem(StatDialog,&SkillPnts,SKILLPTS);
	RetrieveDItem(StatDialog,&ProfessionItem,PROFESSIONTITLE);
	SetRect(&ProfessionTitleBox,ProfessionItem.box.left,ProfessionItem.box.top,
					ProfessionItem.box.right,ProfessionItem.box.bottom);
	RetrieveDItem(StatDialog,&ProfessionItem,PROFMENUITM);
	RetrieveDItem(StatDialog,&RaceItem,RACETITLE);
	SetRect(&RaceTitleBox,RaceItem.box.left,RaceItem.box.top,
								RaceItem.box.right,RaceItem.box.bottom);
	RetrieveDItem(StatDialog,&RaceItem,RACEMENUITM);
	RetrieveDItem(StatDialog,&SexItem,SEXTITLE);
	SetRect(&SexTitleBox,SexItem.box.left,SexItem.box.top,SexItem.box.right,
								SexItem.box.bottom);
	RetrieveDItem(StatDialog,&SexItem,SEXMENUITEM);
}

DoStats()
{
	int		CharDone = FALSE;
	int		whichItem;
	DItemList	TempStats;
	DItemList	PotStats;
	GrafPtr	OldPort;
	
	GetPort(&OldPort);
	StatDialog = GetNewDialog(StatDLG,NULL,(Ptr) -1);
	SetPort(StatDialog);
	InitStats(&TempStats,&PotStats);
	SelectWindow(StatDialog);
	ShowWindow(StatDialog);
	DrawDialog(StatDialog);
	if(!RollDone)
		RollStats();
	FixProfessionMenu();
	UpdateStats(&TempStats,0);
	UpdateStats(&PotStats,1);
	UpdatePopBox(RaceItem);
	UpdatePopBox(ProfessionItem);
	UpdatePopBox(SexItem);
	SetPopMenu(RaceItem,RaceMenu,thePlayer.Race);
	SetPopMenu(ProfessionItem,ProfessionMenu,thePlayer.Profession);
	SetPopMenu(SexItem,SexMenu,thePlayer.Sex);
	UpdateSkillPnts(&SkillPnts);
	whichItem = 0;
	while(!CharDone) {
		ModalDialog(StatFilter,&whichItem);
		switch(whichItem) {
			case PLAY:
				CharDone = TRUE;
				RollDone = TRUE;
				break;
			case CANCEL:
				CharDone = TRUE;
				RollDone = FALSE;
				break;
			case PIKSKILLS:
				RollDone = TRUE;
				DoSkills();
				break;
			case REROLLID:
				RollStats();
				UpdateStats(&TempStats,0);
				UpdateStats(&PotStats,1);
				RollDone = FALSE;
				break;
			}
		}
	DisposDialog(StatDialog);
	SetPort(OldPort);
}

DoSkills()
{