Logo Search packages:      
Sourcecode: falconseye version File versions  Download package

macmenu.c

/*    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 <Menus.h>
#include <Devices.h>
#include <Resources.h>
#include <TextUtils.h>
#include <ToolUtils.h>
#include <Sound.h>

/******** 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 = " XD";


      /* 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 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 *)&rect;
            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);
            }
      }
}


Generated by  Doxygen 1.6.0   Back to index