From 46ec9feac79cb6d6a75cff2f3c86aa826b9862e8 Mon Sep 17 00:00:00 2001 From: jwalz Date: Sat, 5 Jan 2002 21:05:55 +0000 Subject: [PATCH] *** empty log message *** --- sys/mac/macmenu.c | 1184 +++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 1184 insertions(+) create mode 100644 sys/mac/macmenu.c diff --git a/sys/mac/macmenu.c b/sys/mac/macmenu.c new file mode 100644 index 000000000..186532e16 --- /dev/null +++ b/sys/mac/macmenu.c @@ -0,0 +1,1184 @@ +/* SCCS Id: @(#)macmenu.c 3.3 99/11/24 */ +/* Copyright (c) Macintosh NetHack Port Team, 1993. */ +/* NetHack may be freely redistributed. See license for details. */ + +/****************************************\ + * Extended Macintosh menu support + * + * provides access to all keyboard commands from cmd.c + * provides control key functionality for classic keyboards + * provides key equivalent references and logical menu groups + * supports various menu highlighting modes +\****************************************/ + +/****************************************\ + * Edit History: + * + * 930512 - More bug fixes and getting tty to work again, Jon W{tte + * 930508 - Bug fixes in-flight, Jon W{tte + * 04/29/93 - 1st Release Draft, David Hairston + * 04/11/93 - 1st Draft, David Hairston +\****************************************/ + +/******** Application Defines ********/ +#include "hack.h" +#include "mactty.h" +#include "macwin.h" +#include "macpopup.h" +#include "patchlevel.h" + +/******** Toolbox Defines ********/ +#include +#include +#include +#include +#include +#include + +/******** Local Defines ********/ + +/* 'MNU#' (menu list record) */ +typedef union menuRefUnn +{ + short mresID; /* MENU resource ID (before GetMenu) */ + MenuHandle mhnd; /* MENU handle (after GetMenu) */ +} menuRefUnn; + +typedef struct menuListRec +{ + short firstMenuID; + short numMenus; + menuRefUnn mref[]; +} menuListRec, *menuListPtr, **menuListHandle; + +/* indices and resource IDs of the menu list data */ +enum +{ + listMenubar, + listSubmenu, + + menuBarListID = 128, + subMenuListID +}; + +/* the following mref[] indices are reserved */ +enum +{ + /* menu bar */ + menuApple, + menuFile, + menuEdit, + + /* submenu */ + menuWizard = 0 +}; + +/* the following menu items are reserved */ +enum +{ + /* apple */ + menuAppleAboutBox = 1, + ____Apple__1, + + /* File */ + menuFileRedraw = 1, + menuFilePrevMsg, + menuFileCleanup, + ____File___1, + menuFilePlayMode, + menuFileEnterExplore, + ____File___2, + menuFileSave, + ____File___3, + menuFileQuit, + + /* standard minimum Edit menu items */ + + /* Wizard */ + menuWizardAttributes = 1 +}; + + +/* + * menuListRec data (preloaded and locked) specifies the number of menus in + * the menu bar, the number of hierarchal or submenus and the menu IDs of + * all of those menus. menus that go into in the menu bar are specified by + * 'MNU#' 128 and submenus are specified by 'MNU#' 129. the fields of the + * menuListRec are: + * firstMenuID - the menu ID (not resource ID) of the 1st menu. subsequent + * menus in the list are _forced_ to have consecutively incremented IDs. + * numMenus - the total count of menus in a given list (and the extent of + * valid menu IDs). + * mref[] - initially the MENU resource ID is stored in the placeholder for + * the resource handle. after loading (GetResource), the menu handle + * is stored and the menu ID, in memory, is set as noted above. + * + * NOTE: a ResEdit template editor is supplied to edit the 'MNU#' resources. + * + * NOTE: the resource IDs do not need to match the menu IDs in a menu list + * record although they have been originally set that way. + * + * NOTE: the menu ID's of menus in the submenu list record may be reset, as + * noted above. it is the programmers responsibility to make sure that + * submenu references/IDs are valid. + * + * WARNING: the existence of the submenu list record is assumed even if the + * number of submenus is zero. also, no error checking is done on the + * extents of the menu IDs. this must be correctly setup by the programmer. + */ + +#define ID1_MBAR pMenuList[listMenubar]->firstMenuID +#define ID1_SUBM pMenuList[listSubmenu]->firstMenuID + +#define NUM_MBAR pMenuList[listMenubar]->numMenus +#define NUM_SUBM pMenuList[listSubmenu]->numMenus + +#define MHND_APPLE pMenuList[listMenubar]->mref[menuApple].mhnd +#define MHND_FILE pMenuList[listMenubar]->mref[menuFile].mhnd +#define MHND_EDIT pMenuList[listMenubar]->mref[menuEdit].mhnd + +#define MBARHND(x) pMenuList[listMenubar]->mref[(x)].mhnd + +#define MHND_WIZ pMenuList[listSubmenu]->mref[menuWizard].mhnd + + +/* mutually exclusive (and prioritized) menu bar states */ +enum +{ + mbarDim, + mbarNoWindows, + mbarDA, + mbarNoMap, + mbarRegular, + mbarSpecial /* explore or debug mode */ +}; + +#define WKND_MAP (WIN_BASE_KIND + NHW_MAP) + + +/* menu routine error numbers */ +enum +{ + errGetMenuList, + errGetMenu, + errGetANDlogTemplate, + errGetANDlogItems, + errGetANDialog, + errANNewMenu, + err_Menu_total +}; + + +/* menu 'STR#' comment char */ +#define mstrEndChar 0xA5 /* '\245' or option-* or "bullet" */ + +/* 'ALRT' */ +enum +{ + alrt_Menu_start = 5000, + alrtMenuNote = alrt_Menu_start, + alrtMenu_NY, + alrt_Menu_limit +}; + +#define beepMenuAlertErr 1 /* # of SysBeep()'s before exitting */ +enum +{ + bttnMenuAlertNo = 1, + bttnMenuAlertYes +}; + + +/******** Globals ********/ +static unsigned char *menuErrStr[err_Menu_total] = + { + "\pAbort: Bad \'MNU#\' resource!", /* errGetMenuList */ + "\pAbort: Bad \'MENU\' resource!", /* errGetMenu */ + "\pAbort: Bad \'DLOG\' resource!", /* errGetANDlogTemplate */ + "\pAbort: Bad \'DITL\' resource!", /* errGetANDlogItems */ + "\pAbort: Bad Dialog Allocation!", /* errGetANDialog */ + "\pAbort: Bad Menu Allocation!", /* errANNewMenu */ + }; +static menuListPtr pMenuList[2]; +static short theMenubar = mbarDA; /* force initial update */ +static short kAdjustWizardMenu = 1; + + +/******** Prototypes ********/ +static void alignAD(Rect *, short); +static void mustGetMenuAlerts(void); +static void menuError(short); +static pascal void drawANUserItem(WindowPtr, short); +static void aboutNetHack(void); +static void optionEditor(void); +static void askSave(void); +static void askQuit(void); + + +/*** Askname dialog box ***/ + +#define RSRC_ASK 6000 /* Askname dialog and item list */ +#define RSRC_ASK_PLAY 1 /* Play button */ +#define RSRC_ASK_QUIT 2 /* Quit button */ +#define RSRC_ASK_DEFAULT 3 /* Default ring */ +#define RSRC_ASK_ROLE 4 /* Role popup menu */ +#define RSRC_ASK_RACE 5 /* Race popup menu */ +#define RSRC_ASK_GEND 6 /* Gender popup menu */ +#define RSRC_ASK_ALIGN 7 /* Alignment popup menu */ +#define RSRC_ASK_MODE 8 /* Mode popup menu */ +#define RSRC_ASK_NAME 9 /* Name text field */ +#define RSRC_ASK_MAX 10 /* Maximum enabled item */ + +#define KEY_MASK 0xff00 +#define KEY_RETURN 0x2400 +#define KEY_ENTER 0x4c00 +#define KEY_ESCAPE 0x3500 +#define CH_MASK 0x00ff +#define CH_RETURN 0x000d +#define CH_ENTER 0x0003 +#define CH_ESCAPE 0x001b + +static void ask_restring(const char *cstr, unsigned char *pstr); +static void ask_enable(WindowPtr wind, short item, int enable); +static pascal void ask_redraw(WindowPtr wind, DialogItemIndex item); +static pascal Boolean ask_filter(WindowPtr wind, EventRecord *event, DialogItemIndex *item); +#define noresource(t,n) {SysBeep(3); ExitToShell();} +#define fatal(s) {SysBeep(3); ExitToShell();} + +static MenuHandle askmenu[RSRC_ASK_MAX]; +static int askselect[RSRC_ASK_MAX]; +#define currrole askselect[RSRC_ASK_ROLE] +#define currrace askselect[RSRC_ASK_RACE] +#define currgend askselect[RSRC_ASK_GEND] +#define curralign askselect[RSRC_ASK_ALIGN] +#define currmode askselect[RSRC_ASK_MODE] + +static RGBColor + blackcolor = {0x0000, 0x0000, 0x0000}, + indentcolor = {0x4000, 0x4000, 0x4000}, + darkcolor = {0x8000, 0x8000, 0x8000}, + backcolor = {0xdddd, 0xdddd, 0xdddd}, + lightcolor = {0xffff, 0xffff, 0xffff}, + whitecolor = {0xffff, 0xffff, 0xffff}; + + +/* Convert a mixed-case C string to a Capitalized Pascal string */ +static void +ask_restring (const char *cstr, unsigned char *pstr) +{ + int i; + + + for (i = 0; *cstr && (i < 255); i++) + pstr[i+1] = *cstr++; + pstr[0] = i; + if ((pstr[1] >= 'a') && (pstr[1] <= 'z')) + pstr[1] += 'A' - 'a'; + return; +} + + +/* Enable the dialog item with the given index */ +static void +ask_enable (WindowPtr wind, short item, int enable) +{ + short type; + Handle handle; + Rect rect; + + + /* Enable or disable the appropriate item */ + GetDItem(wind, item, &type, &handle, &rect); + if (enable) type &= ~itemDisable; + else type |= itemDisable; + HiliteControl((ControlHandle)handle, enable ? 0 : 255); + SetDItem(wind, item, type, handle, &rect); + return; +} + + +static pascal void +ask_redraw (WindowPtr wind, DialogItemIndex item) +{ + short type; + Handle handle; + Rect rect; + static char *modechar = "NED"; + + + /* Which item shall we redraw? */ + GetDItem(wind, item, &type, &handle, &rect); + switch (item) { + case RSRC_ASK_DEFAULT: + PenSize(3, 3); + FrameRoundRect(&rect, 16, 16); + break; + + case RSRC_ASK_ROLE: + case RSRC_ASK_RACE: + case RSRC_ASK_GEND: + case RSRC_ASK_ALIGN: + case RSRC_ASK_MODE: + if (macFlags.color) { + RGBForeColor(&blackcolor); + RGBBackColor(&backcolor); + } + PenNormal(); + TextMode(srcOr); + EraseRect(&rect); + + /* Draw the frame and drop shadow */ + rect.right--; + rect.bottom--; + FrameRect(&rect); + MoveTo(rect.right, rect.top+1); + LineTo(rect.right, rect.bottom); + LineTo(rect.left+1, rect.bottom); + + /* Draw the menu character */ + MoveTo(rect.left+4, rect.top+12); + switch (item) { + case RSRC_ASK_ROLE: + DrawText(roles[askselect[item]].filecode, 0, 3); + break; + case RSRC_ASK_RACE: + DrawText(races[askselect[item]].filecode, 0, 3); + break; + case RSRC_ASK_GEND: + DrawText(genders[askselect[item]].filecode, 0, 3); + break; + case RSRC_ASK_ALIGN: + DrawText(aligns[askselect[item]].filecode, 0, 3); + break; + case RSRC_ASK_MODE: + DrawChar(modechar[askselect[item]]); + break; + } + + /* Draw the popup symbol */ + MoveTo(rect.right - 16, rect.top + 5); + LineTo(rect.right - 6, rect.top + 5); + LineTo(rect.right - 11, rect.top + 10); + LineTo(rect.right - 15, rect.top + 6); + LineTo(rect.right - 8, rect.top + 6); + LineTo(rect.right - 11, rect.top + 9); + LineTo(rect.right - 13, rect.top + 7); + LineTo(rect.right - 10, rect.top + 7); + LineTo(rect.right - 11, rect.top + 8); + + /* Draw the shadow */ + InsetRect(&rect, 1, 1); + if (macFlags.color) { + RGBColor color; + + + /* Save the foreground color */ + GetForeColor(&color); + + /* Draw the top and left */ + RGBForeColor(&lightcolor); + MoveTo(rect.left, rect.bottom-1); + LineTo(rect.left, rect.top); + LineTo(rect.right-1, rect.top); + + /* Draw the bottom and right */ + RGBForeColor(&darkcolor); + MoveTo(rect.right-1, rect.top+1); + LineTo(rect.right-1, rect.bottom-1); + LineTo(rect.left+1, rect.bottom-1); + + /* Restore the foreground color */ + RGBForeColor(&color); + } + break; + + case RSRC_ASK_NAME: + PenNormal(); + if (macFlags.color) { + RGBForeColor(&whitecolor); + RGBBackColor(&whitecolor); + TextMode(srcOr); + } else { + PenMode(notPatCopy); + TextMode(srcBic); + } + InsetRect(&rect, -1, -1); + FrameRect(&rect); + InsetRect(&rect, -1, -1); + FrameRect(&rect); + InsetRect(&rect, -2, -2); + if (macFlags.color) { + /* Draw the top and left */ + RGBForeColor(&darkcolor); + MoveTo(rect.left, rect.bottom-1); + LineTo(rect.left, rect.top); + LineTo(rect.right-1, rect.top); + + /* Draw the bottom and right */ + RGBForeColor(&lightcolor); + MoveTo(rect.right-1, rect.top+1); + LineTo(rect.right-1, rect.bottom-1); + LineTo(rect.left+1, rect.bottom-1); + + /* Restore the colors */ + RGBForeColor(&blackcolor); + RGBBackColor(&backcolor); + } + break; + } + return; +} + + +static pascal Boolean +ask_filter (WindowPtr wind, EventRecord *event, DialogItemIndex *item) +{ + short ch, key; + + + switch (event->what) { + case keyDown: + case autoKey: + ch = event->message & CH_MASK; + key = event->message & KEY_MASK; + /* Handle equivalents for OK */ + if ((ch == CH_RETURN) || (key == KEY_RETURN) || + (ch == CH_ENTER) || (key == KEY_ENTER)) { + if ((*((DialogRecord *)wind)->textH)->teLength) { + FlashButton(wind, RSRC_ASK_PLAY); + *item = RSRC_ASK_PLAY; + } else + *item = 0; + return (TRUE); + } + /* Handle equivalents for Normal/Explore/Debug */ + if ((event->modifiers & cmdKey) && (ch == 'n')) { + currmode = 0; + ask_redraw(wind, RSRC_ASK_MODE); + *item = RSRC_ASK_MODE; + return (TRUE); + } + if ((event->modifiers & cmdKey) && (ch == 'e')) { + currmode = 1; + ask_redraw(wind, RSRC_ASK_MODE); + *item = RSRC_ASK_MODE; + return (TRUE); + } + if ((event->modifiers & cmdKey) && (ch == 'd')) { + currmode = 2; + ask_redraw(wind, RSRC_ASK_MODE); + *item = RSRC_ASK_MODE; + return (TRUE); + } + /* Handle equivalents for Cancel and Quit */ + if ((ch == CH_ESCAPE) || (key == KEY_ESCAPE) || + ((event->modifiers & cmdKey) && (ch == 'q')) || + ((event->modifiers & cmdKey) && (ch == '.'))) { + FlashButton(wind, RSRC_ASK_QUIT); + *item = RSRC_ASK_QUIT; + return (TRUE); + } + return (FALSE); + case updateEvt: + ask_redraw(wind, RSRC_ASK_NAME); + return (FALSE); + default: + return (FALSE); + } +} + + +void mac_askname () +{ + GrafPtr oldport; + WindowPtr askdialog; + short i, j, item, type; + Handle handle; + Rect rect; + Str255 str; + Point pt; + UserItemUPP redraw = NewUserItemProc(ask_redraw); + ModalFilterUPP filter = NewModalFilterProc(ask_filter); + + + /* Create the dialog */ + if (!(askdialog = GetNewDialog(RSRC_ASK, NULL, (WindowPtr)-1))) + noresource('DLOG', RSRC_ASK); + GetPort(&oldport); + SetPort(askdialog); + + /* Initialize the name text item */ + ask_restring(plname, str); + if (plname[0]) { + GetDItem(askdialog, RSRC_ASK_NAME, &type, &handle, &rect); + SetIText(handle, str); + } +#if 0 + { + Str32 pName; + pName [0] = 0; + if (plname && plname [0]) { + strcpy ((char *) pName, plname); + c2pstr ((char *) pName); + } else { + Handle h; + h = GetResource ('STR ', -16096); + if (((Handle) 0 != h) && (GetHandleSize (h) > 0)) { + DetachResource (h); + HLock (h); + if (**h > 31) { + **h = 31; + } + BlockMove (*h, pName, **h + 1); + DisposeHandle (h); + } + } + if (pName [0]) { + GetDItem(askdialog, RSRC_ASK_NAME, &type, &handle, &rect); + SetIText(handle, pName); + if (pName [0] > 2 && pName [pName [0] - 1] == '-') { + short role = (*pANR).anMenu[anRole]; + char suffix = (char) pName[pName[0]], + *sfxindx = strchr(pl_classes, suffix); + + if (sfxindx) + role = (short) (sfxindx - pl_classes); + else if (suffix == '@') + role = (short) rn2((int) strlen(pl_classes)); + (*pANR).anMenu[anRole] = role; + } + } + } +#endif + SelIText(askdialog, RSRC_ASK_NAME, 0, 32767); + + /* Initialize the role popup menu */ + if (!(askmenu[RSRC_ASK_ROLE] = NewMenu(RSRC_ASK_ROLE, "\p"))) + fatal("\pCannot create role menu"); + for (i = 0; roles[i].name.m; i++) { + ask_restring(roles[i].name.m, str); + AppendMenu(askmenu[RSRC_ASK_ROLE], str); + } + InsertMenu(askmenu[RSRC_ASK_ROLE], hierMenu); + if (flags.initrole >= 0) + currrole = flags.initrole; + /* Check for backward compatibility */ + else if ((currrole = str2role(pl_character)) < 0) + currrole = randrole(); + + /* Initialize the race popup menu */ + if (!(askmenu[RSRC_ASK_RACE] = NewMenu(RSRC_ASK_RACE, "\p"))) + fatal("\pCannot create race menu"); + for (i = 0; races[i].noun; i++) { + ask_restring(races[i].noun, str); + AppendMenu(askmenu[RSRC_ASK_RACE], str); + } + InsertMenu(askmenu[RSRC_ASK_RACE], hierMenu); + if (flags.initrace >= 0) + currrace = flags.initrace; + else + currrace = randrace(currrole); + + /* Initialize the gender popup menu */ + if (!(askmenu[RSRC_ASK_GEND] = NewMenu(RSRC_ASK_GEND, "\p"))) + fatal("\pCannot create gender menu"); + for (i = 0; i < ROLE_GENDERS; i++) { + ask_restring(genders[i].adj, str); + AppendMenu(askmenu[RSRC_ASK_GEND], str); + } + InsertMenu(askmenu[RSRC_ASK_GEND], hierMenu); + if (flags.initgend >= 0) + currgend = flags.initgend; + else if (flags.female) + currgend = 1; + else + currgend = randgend(currrole, currrace); + + /* Initialize the alignment popup menu */ + if (!(askmenu[RSRC_ASK_ALIGN] = NewMenu(RSRC_ASK_ALIGN, "\p"))) + fatal("\pCannot create alignment menu"); + for (i = 0; i < ROLE_ALIGNS; i++) { + ask_restring(aligns[i].adj, str); + AppendMenu(askmenu[RSRC_ASK_ALIGN], str); + } + InsertMenu(askmenu[RSRC_ASK_ALIGN], hierMenu); + if (flags.initalign >= 0) + curralign = flags.initalign; + else + curralign = randalign(currrole, currrace); + + /* Initialize the mode popup menu */ + if (!(askmenu[RSRC_ASK_MODE] = NewMenu(RSRC_ASK_MODE, "\p"))) + fatal("\pCannot create mode menu"); + AppendMenu(askmenu[RSRC_ASK_MODE], "\pNormal"); + AppendMenu(askmenu[RSRC_ASK_MODE], "\pExplore"); +#ifdef WIZARD + AppendMenu(askmenu[RSRC_ASK_MODE], "\pDebug"); +#endif + InsertMenu(askmenu[RSRC_ASK_MODE], hierMenu); + currmode = 0; + + /* Set the redraw procedures */ + for (item = RSRC_ASK_DEFAULT; item <= RSRC_ASK_MODE; item++) { + GetDItem(askdialog, item, &type, &handle, &rect); + SetDItem(askdialog, item, type, (Handle)redraw, &rect); + } + + /* Handle dialog events */ + do { + /* Adjust the Play button */ + ask_enable(askdialog, RSRC_ASK_PLAY, + (*((DialogRecord *)askdialog)->textH)->teLength); + + /* Adjust the race popup menu */ + i = j = currrace; + do { + if (validrace(currrole, j)) { + EnableItem(askmenu[RSRC_ASK_RACE], j+1); + CheckItem(askmenu[RSRC_ASK_RACE], j+1, + currrace == j); + } else { + DisableItem(askmenu[RSRC_ASK_RACE], j+1); + CheckItem(askmenu[RSRC_ASK_RACE], j+1, FALSE); + if ((currrace == j) && !races[++currrace].noun) + currrace = 0; + } + if (!races[++j].noun) j = 0; + } while (i != j); + if (currrace != i) { + GetDItem(askdialog, RSRC_ASK_RACE, &type, &handle, &rect); + InvalRect(&rect); + } + + /* Adjust the gender popup menu */ + i = j = currgend; + do { + if (validgend(currrole, currrace, j)) { + EnableItem(askmenu[RSRC_ASK_GEND], j+1); + CheckItem(askmenu[RSRC_ASK_GEND], j+1, + currgend == j); + } else { + DisableItem(askmenu[RSRC_ASK_GEND], j+1); + CheckItem(askmenu[RSRC_ASK_GEND], j+1, FALSE); + if ((currgend == j) && (++currgend >= ROLE_GENDERS)) + currgend = 0; + } + if (++j >= ROLE_GENDERS) j = 0; + } while (i != j); + if (currgend != i) { + GetDItem(askdialog, RSRC_ASK_GEND, &type, &handle, &rect); + InvalRect(&rect); + } + + /* Adjust the alignment popup menu */ + i = j = curralign; + do { + if (validalign(currrole, currrace, j)) { + EnableItem(askmenu[RSRC_ASK_ALIGN], j+1); + CheckItem(askmenu[RSRC_ASK_ALIGN], j+1, + curralign == j); + } else { + DisableItem(askmenu[RSRC_ASK_ALIGN], j+1); + CheckItem(askmenu[RSRC_ASK_ALIGN], j+1, FALSE); + if ((curralign == j) && (++curralign >= ROLE_ALIGNS)) + curralign = 0; + } + if (++j >= ROLE_ALIGNS) j = 0; + } while (i != j); + if (curralign != i) { + GetDItem(askdialog, RSRC_ASK_ALIGN, &type, &handle, &rect); + InvalRect(&rect); + } + + /* Adjust the role popup menu */ + for (i = 0; roles[i].name.m; i++) { + ask_restring((currgend && roles[i].name.f) ? + roles[i].name.f : roles[i].name.m, str); + SetItem(askmenu[RSRC_ASK_ROLE], i+1, str); + CheckItem(askmenu[RSRC_ASK_ROLE], i+1, currrole == i); + } + + /* Adjust the mode popup menu */ + CheckItem(askmenu[RSRC_ASK_MODE], 1, currmode == 0); + CheckItem(askmenu[RSRC_ASK_MODE], 2, currmode == 1); +#ifdef WIZARD + CheckItem(askmenu[RSRC_ASK_MODE], 3, currmode == 2); +#endif + + /* Wait for an action on an item */ + ModalDialog(filter, &item); + switch (item) { + case RSRC_ASK_PLAY: + break; + case RSRC_ASK_QUIT: + currmode = -1; + break; + case RSRC_ASK_ROLE: + case RSRC_ASK_RACE: + case RSRC_ASK_ALIGN: + case RSRC_ASK_GEND: + case RSRC_ASK_MODE: + GetDItem(askdialog, item, &type, &handle, &rect); + pt = *(Point *)▭ + LocalToGlobal(&pt); + if (!!(i = PopUpMenuSelect(askmenu[item], pt.v, pt.h, + askselect[item] + 1))) + askselect[item] = LoWord(i) - 1; + InvalRect(&rect); + break; + case RSRC_ASK_NAME: +#if 0 + /* limit the data here to 25 chars */ + { + short beepTEDelete = 1; + + while ((**dRec.textH).teLength > 25) + { + if (beepTEDelete++ <= 3) + SysBeep(3); + TEKey('\b', dRec.textH); + } + } + + /* special case filter (that doesn't plug all the holes!) */ + if (((**dRec.textH).teLength == 1) && (**((**dRec.textH).hText) < 32)) + TEKey('\b', dRec.textH); +#endif + break; + } + } while ((item != RSRC_ASK_PLAY) && (item != RSRC_ASK_QUIT)); + + /* Process the name */ + GetDItem(askdialog, RSRC_ASK_NAME, &type, &handle, &rect); + GetIText(handle, str); + if (str[0] > PL_NSIZ-1) str[0] = PL_NSIZ-1; + BlockMove(&str[1], plname, str[0]); + plname[str[0]] = '\0'; + + /* Destroy the dialog */ + for (i = RSRC_ASK_ROLE; i <= RSRC_ASK_MODE; i++) { + DeleteMenu(i); + DisposeMenu(askmenu[i]); + } + SetPort(oldport); + DisposeDialog(askdialog); + DisposeRoutineDescriptor(filter); + DisposeRoutineDescriptor(redraw); + + /* Process the mode */ +#ifdef WIZARD + wizard = +#endif + discover = 0; + switch (currmode) { + case 0: /* Normal */ + break; + case 1: /* Explore */ + discover = 1; + break; +#ifdef WIZARD + case 2: /* Debug */ + wizard = 1; + strcpy(plname, WIZARD); + break; +#endif + default: /* Quit */ + ExitToShell(); + } + + /* Process the role */ + strcpy(pl_character, roles[currrole].name.m); + flags.initrole = currrole; + + /* Process the race */ + flags.initrace = currrace; + + /* Process the gender */ + flags.female = flags.initgend = currgend; + + /* Process the alignment */ + flags.initalign = curralign; + + return; +} + + + +/*** Menu bar routines ***/ + +static void +alignAD(Rect *pRct, short vExempt) +{ + (*pRct).right -= (*pRct).left; /* width */ + (*pRct).bottom -= (*pRct).top; /* height */ + (*pRct).left = (qd.screenBits.bounds.right - (*pRct).right) / 2; + (*pRct).top = (qd.screenBits.bounds.bottom - (*pRct).bottom - vExempt) / 2; + (*pRct).top += vExempt; + (*pRct).right += (*pRct).left; + (*pRct).bottom += (*pRct).top; +} + +static void +mustGetMenuAlerts() +{ + short i, mbarHgt = GetMBarHeight(); + Rect **hRct; + + for (i = alrt_Menu_start; i < alrt_Menu_limit; i++) + { + if (! (hRct = (Rect **) GetResource('ALRT', i))) /* AlertTHndl */ + { + for (i = 0; i < beepMenuAlertErr; i++) + SysBeep(3); + ExitToShell(); + } + + alignAD(*hRct, mbarHgt); + } +} + +static void +menuError(short menuErr) +{ + short i; + + for (i = 0; i < beepMenuAlertErr; i++) + SysBeep(3); + + ParamText(menuErrStr[menuErr], "\p", "\p", "\p"); + (void) Alert(alrtMenuNote, (ModalFilterUPP) 0L); + + ExitToShell(); +} + +void +InitMenuRes() +{ + static Boolean was_inited = 0; + short i, j; + menuListHandle mlHnd; + MenuHandle mHnd; + + if (was_inited) + return; + was_inited = 1; + + mustGetMenuAlerts(); + + for (i = listMenubar; i <= listSubmenu; i++) + { + if (! (mlHnd = (menuListHandle) GetResource('MNU#', (menuBarListID + i)))) + menuError(errGetMenuList); + + pMenuList[i] = *mlHnd; + + for (j = 0; j < (**mlHnd).numMenus; j++) + { + if (! (mHnd = (MenuHandle) GetMenu((**mlHnd).mref[j].mresID))) { + Str31 d; + NumToString ((**mlHnd).mref[j].mresID, d); + menuError(errGetMenu); + } + + (**mlHnd).mref[j].mhnd = mHnd; + * ((short *) *mHnd) = j + (**mlHnd).firstMenuID; /* consecutive IDs */ + + /* expand apple menu */ + if ((i == listMenubar) && (j == menuApple)) { + AppendResMenu(mHnd, 'DRVR'); + } + + InsertMenu(mHnd, ((i == listSubmenu) ? hierMenu : 0)); + } + } + DrawMenuBar(); + return; +} + +void +AdjustMenus(short dimMenubar) +{ + short newMenubar = mbarRegular; + WindowPeek peekWindow = (WindowPeek) FrontWindow(); + short i; + + /* + * if (windowprocs != mac_procs) { + * return; + * } + */ + /* determine the new menubar state */ + if (dimMenubar) { + newMenubar = mbarDim; + } else if (! peekWindow) { + newMenubar = mbarNoWindows; + } else if (peekWindow->windowKind < 0) { + newMenubar = mbarDA; + } else { + while (peekWindow && (peekWindow->windowKind != WKND_MAP)) { + peekWindow = peekWindow->nextWindow; + } + if ((! peekWindow) || (! peekWindow->visible)) { + newMenubar = mbarNoMap; + } + } + + if (newMenubar != mbarRegular) + ; /* we've already found its state */ +#ifdef WIZARD + else if (wizard) + { + newMenubar = mbarSpecial; + + if (kAdjustWizardMenu) + { + kAdjustWizardMenu = 0; + + SetMenuItemText(MHND_FILE, menuFilePlayMode, "\pDebug"); + } + } +#endif + + else if (discover) + { + newMenubar = mbarSpecial; + + if (kAdjustWizardMenu) + { + kAdjustWizardMenu = 0; + + SetMenuItemText(MHND_FILE, menuFilePlayMode, "\pExplore"); + + for (i = CountMItems(MHND_WIZ); i > menuWizardAttributes; i--) + DeleteMenuItem(MHND_WIZ, i); + } + } + + /* adjust the menubar, if there's a state change */ + if (theMenubar != newMenubar) + { + switch(theMenubar = newMenubar) + { + case mbarDim: + /* disable all menus (except the apple menu) */ + for (i = menuFile; i < NUM_MBAR; i++) + DisableItem(MBARHND(i), 0); + break; + + case mbarNoWindows: + case mbarDA: + case mbarNoMap: + /* enable the file menu, but ... */ + EnableItem(MHND_FILE, 0); + + /* ... disable the window commands! */ + for (i = menuFileRedraw; i <= menuFileEnterExplore; i++) + DisableItem(MHND_FILE, i); + + /* ... and disable the rest of the menus */ + for (i = menuEdit; i < NUM_MBAR; i++) + DisableItem(MBARHND(i), 0); + + if (theMenubar == mbarDA) + EnableItem(MHND_EDIT, 0); + + break; + + case mbarRegular: + case mbarSpecial: + /* enable all menus ... */ + for (i = menuFile; i < NUM_MBAR; i++) + EnableItem(MBARHND(i), 0); + + /* ... except the unused Edit menu */ + DisableItem(MHND_EDIT, 0); + + /* ... enable the window commands */ + for (i = menuFileRedraw; i <= menuFileEnterExplore; i++) + EnableItem(MHND_FILE, i); + + if (theMenubar == mbarRegular) + DisableItem(MHND_FILE, menuFilePlayMode); + else + DisableItem(MHND_FILE, menuFileEnterExplore); + + break; + } + + DrawMenuBar(); + } +} + +void +DoMenuEvt(long menuEntry) +{ + short menuID = HiWord(menuEntry); + short menuItem = LoWord(menuEntry); + + switch(menuID - ID1_MBAR) /* all submenus are default case */ + { + case menuApple: + if (menuItem == menuAppleAboutBox) + aboutNetHack(); + else + { + unsigned char daName[32]; + + GetMenuItemText(MHND_APPLE, menuItem, * (Str255 *) daName); + (void) OpenDeskAcc(daName); + } + break; + + /* + * Those direct calls are ugly: they should be installed into cmd.c . + * Those AddToKeyQueue() calls are also ugly: they should be put into + * the 'STR#' resource. + */ + case menuFile: + switch(menuItem) + { + case menuFileRedraw: + AddToKeyQueue ('R' & 0x1f, 1); + break; + + case menuFilePrevMsg: + AddToKeyQueue ('P' & 0x1f, 1); + break; + + case menuFileCleanup: + (void) SanePositions(); + break; + + case menuFileEnterExplore: + AddToKeyQueue ('X', 1); + break; + + case menuFileSave: + askSave(); + break; + + case menuFileQuit: + askQuit(); + break; + } + break; + + case menuEdit: + (void) SystemEdit(menuItem - 1); + break; + + default: /* get associated string and add to key queue */ + { + Str255 mstr; + short i; + + GetIndString(mstr, menuID, menuItem); + if (mstr[0] > QUEUE_LEN) + mstr[0] = QUEUE_LEN; + + for (i = 1; ((i <= mstr[0]) && (mstr[i] != mstrEndChar)); i++) + AddToKeyQueue(mstr[i], false); + } + break; + } + + HiliteMenu(0); +} + + +static void +aboutNetHack() { + if (theMenubar >= mbarRegular) { + (void) doversion(); /* is this necessary? */ + } else { + unsigned char aboutStr[32] = "\pNetHack 3.3."; + + if (PATCHLEVEL > 10) { + aboutStr[++aboutStr[0]] = '0'+PATCHLEVEL/10; + } + + aboutStr[++aboutStr[0]] = '0' + (PATCHLEVEL % 10); + + ParamText(aboutStr, "\p\rdevteam@www.nethack.org", "\p", "\p"); + (void) Alert(alrtMenuNote, (ModalFilterUPP) 0L); + ResetAlertStage(); + } +} + + +static void +askSave() +{ + Boolean doSave = 1; + Boolean doYes = 0; + + if (theMenubar < mbarRegular) { + short itemHit; + + ParamText("\pReally Save?", "\p", "\p", "\p"); + itemHit = Alert(alrtMenu_NY, (ModalFilterUPP) 0L); + ResetAlertStage(); + + if (itemHit != bttnMenuAlertYes) { + doSave = 0; + } else { + doYes = 1; + } + } + if (doSave) { + AddToKeyQueue ('S', 1); + if (doYes) { + AddToKeyQueue ('y', 1); + } + } +} + +static void +askQuit() +{ + Boolean doQuit = 1; + Boolean doYes = 0; + Boolean winMac; + char *quitinput; + + if (!strcmp (windowprocs.name, "mac")) + winMac = 1; + else + winMac = 0; + + if (theMenubar < mbarRegular) { + short itemHit; + + ParamText("\pReally Quit?", "\p", "\p", "\p"); + itemHit = Alert(alrtMenu_NY, (ModalFilterUPP) 0L); + ResetAlrtStage(); + + if (itemHit != bttnMenuAlertYes) { + doQuit = 0; + } else { + doYes = 1; + } + } + if (doQuit) { + /* MWM -- forgive me lord, an even uglier kludge to deal with differences + in command input handling + */ + if (winMac) + quitinput = "#quit\r"; + else + quitinput = "#q\r"; + + /* KMH -- Ugly kludge */ + while (*quitinput) + AddToKeyQueue(*quitinput++, 1); + if (doYes) { + if (winMac) + quitinput = "y\rq\r\r\r"; + else + quitinput = "yq\r"; + while (*quitinput) + AddToKeyQueue(*quitinput++, 1); + } + } +} +