home *** CD-ROM | disk | FTP | other *** search
- /*
- * crushmenu.c - a custom Menu Definition procedure.
- */
-
- #include <MemoryMgr.h>
- #include <Quickdraw.h>
- #include <MenuMgr.h>
- #include <ToolboxUtil.h>
-
- #define ICONSIDE 32 /* Size (pixels) of one side of an icon */
- #define ICON_HMARG 4 /* Margin for left and right of an icon */
- #define ICON_VMARG 2 /* Margin for top and bottom of an icon */
-
- #define HSLIDE 6 /* number of pixels each successive entry is shifted left */
- #define RMARG 5 /* pixels of blank to the right of the item text */
-
- /*
- * The menuData field of the menu's structure
- * is a pile of variable-length fields. Basically, it's:
- * Pascal string of the Title;
- * Pascal string of the first menu item;
- * struct iteminfo of the first menu item;
- * Pascal string of the second menu item...
- * The list is ended by a Pascal string of length 0.
- */
-
- struct iteminfo {
- char iconnum; /* encoded Resource ID of the item's icon (or 0) */
- char keyequiv; /* its keyboard equivalent (or 0) */
- char mark; /* its marking character (or 0) */
- Style tstyle; /* its text's style */
- };
-
- /*
- * struct commons - common information each routine will be interested in.
- *
- * To save code, the main routine calculates the common information,
- * then passes to each subroutine a pointer to the block of information.
- */
-
- struct commons {
- FontInfo finfo; /* the dimensions of the System Font */
- int lheight; /* the height of one text line */
- int cloverwidth; /* the width of the clover ("command") symbol */
- int checkwidth; /* the width of the check-mark character */
- int numitems; /* the number of items in the menu */
- };
-
- /*
- * main() - the entry-point to our custom menu definition.
- *
- * Because the MDEF must be a pure-code resource,
- * we can't use any global or static data,
- * which forces us to recalculate a lot of information
- * each time we're called.
- */
-
- pascal void
- main(op, menuh, mrectp, pt, theitemp)
- int op; /* the operation to perform */
- MenuHandle menuh; /* the menu to operate on */
- Rect *mrectp; /* the Rect enclosing the menu (global coordinates) */
- Point pt; /* the mouse location (global coordinates) */
- int *theitemp; /* the highlighted item */
- {
- struct commons comm; /* the info of common interest */
- char *mcp; /* "Menu Char-Pointer" for traversing the menuData fields */
-
- /*
- * Calculate the info we need regardless of the operation.
- */
-
- GetFontInfo(&comm.finfo);
- comm.lheight = comm.finfo.ascent + comm.finfo.descent + comm.finfo.leading;
- comm.cloverwidth = CharWidth((char) 0x11);
- comm.checkwidth = CharWidth((char) 0x12);
-
- comm.numitems = 0;
- mcp = (char *) &((*menuh)->menuData);
- mcp += ((int) *mcp & 0xFF) + 1; /* skip past the title string */
- while (*mcp) {
- ++comm.numitems;
- mcp += ((int) *mcp & 0xFF) + 1 + sizeof(struct iteminfo);
- }
-
- /*
- * Now do the requested operation.
- */
-
- switch(op) {
- case mSizeMsg: /* find the dimensions of the menu */
- msize(&comm, menuh);
- break;
- case mDrawMsg: /* draw the menu */
- mdraw(&comm, menuh, mrectp);
- break;
- case mChooseMsg: /* find and highlight the item the mouse is in */
- mchoose(&comm, menuh, mrectp, pt, theitemp);
- break;
- /* This MDEF doesn't support the popup message, mPopupMsg. */
- }
- }
-
- /*
- * msize() - calculate the dimensions of the given menu,
- * placing them in the appropriate fields of the menu structure.
- */
-
- msize(commp, menuh)
- struct commons *commp; /* the common information */
- MenuHandle menuh;
- {
- char *mcp; /* "Menu Char-Pointer" for traversing the menuData fields */
- int itemnum; /* item number of the current item */
- char *name; /* the (Pascal) name of the current item */
- struct iteminfo *infop; /* pointer to the current item's info */
- int thisheight; /* height of this item */
- int totalheight;/* total height of the menu */
- int thiswidth; /* width of the current item's text */
- int maxright; /* maximum width to the right of the reference point */
-
- maxright = 0;
- totalheight = 0;
-
- itemnum = 0;
- mcp = (char *) &((*menuh)->menuData);
- mcp += ((int) *mcp & 0xFF) + 1;
- while (*mcp) {
- ++itemnum;
- name = mcp;
- mcp += ((int) *mcp & 0xFF) + 1;
- infop = (struct iteminfo *) mcp;
- mcp += sizeof(struct iteminfo);
-
- /*
- * If we're drawing an icon, our line is that high,
- * otherwise, the line is one text-line high.
- * (This code assumes that the system font isn't huge.)
- */
-
- if (infop->iconnum) {
- thisheight = ICON_VMARG + ICONSIDE + ICON_VMARG;
- } else {
- thisheight = commp->lheight;
- }
-
- /*
- * Sum-up the item's width:
- * The item contains:
- * a check (or other mark) [optional]
- * an icon (and its margins) [optional]
- * the item's name
- * a clover-key equivalent [optional]
- * a right-margin
- */
-
- thiswidth = 0;
-
- if (infop->mark) {
- thiswidth += CharWidth(infop->mark);
- } else {
- thiswidth += commp->checkwidth;
- }
-
- if (infop->iconnum) {
- thiswidth += ICON_HMARG + ICONSIDE + ICON_HMARG;
- }
-
- thiswidth += StringWidth(name);
-
- if (infop->keyequiv != '\0') {
- thiswidth += commp->cloverwidth * 2 + commp->finfo.widMax;
- }
-
- thiswidth += RMARG;
-
- /*
- * Adjust the width by the amount this entry is shifted left.
- */
-
- thiswidth -= (itemnum - 1) * HSLIDE;
- if (maxright < thiswidth) {
- maxright = thiswidth;
- }
- totalheight += thisheight;
- }
-
- (*menuh)->menuHeight = commp->lheight / 2 + totalheight;
- (*menuh)->menuWidth = commp->numitems * HSLIDE + maxright;
- }
-
- /*
- * mdraw() - draw the initial picture of the given menu within the given Rect.
- */
-
- mdraw(commp, menuh, mrectp)
- struct commons *commp; /* the common information */
- MenuHandle menuh;
- Rect *mrectp;
- {
- char *mcp; /* "Menu Char-Pointer" for traversing the menuData fields */
- int itemnum; /* the item number of the current item */
- char *name; /* the (Pascal) name of the current item */
- struct iteminfo *infop; /* pointer to the current item's info */
- Rect itemrect; /* rect enclosing the current item */
- Rect barrect; /* rect enclosing the vertical bar for this item */
- int textvert; /* vertical position of text in this item */
- PenState oldpen;/* the original Pen of the port (to be restored) */
- Pattern fuzz; /* pattern to dim with */
- int curhorz; /* current horizontal position of the next piece */
- Handle iconh; /* handle to the current icon */
- Rect iconrect; /* Rect enclosing the icon to draw */
-
- GetPenState(&oldpen);
-
- /*
- * Since we can't access the quickdraw global patterns
- * (or even our own globals),
- * we have to create this pattern each time we're called.
- */
-
- fuzz[0] = (unsigned char) 0xAA;
- fuzz[1] = (unsigned char) 0x55;
- fuzz[2] = (unsigned char) 0xAA;
- fuzz[3] = (unsigned char) 0x55;
- fuzz[4] = (unsigned char) 0xAA;
- fuzz[5] = (unsigned char) 0x55;
- fuzz[6] = (unsigned char) 0xAA;
- fuzz[7] = (unsigned char) 0x55;
-
-
- /* EraseRect(mrectp); The Menu Manager seems to do this for us */
-
-
- itemrect.top = mrectp->top + commp->lheight / 2;
- itemrect.left = mrectp->left + commp->numitems * HSLIDE;
- itemrect.right = mrectp->right;
-
- itemnum = 0;
- mcp = (char *) &((*menuh)->menuData);
- mcp += ((int) *mcp & 0xFF) + 1;
- while (*mcp) {
- ++itemnum;
- name = mcp;
- mcp += ((int) *mcp & 0xFF) + 1;
- infop = (struct iteminfo *) mcp;
- mcp += sizeof(struct iteminfo);
-
- /*
- * Calculate where in the menu this item goes:
- * Its item rectangle, its associated vertical bar,
- * and where (vertically) its text goes.
- */
-
- if (infop->iconnum) {
- itemrect.bottom = itemrect.top + ICON_VMARG + ICONSIDE + ICON_VMARG;
- } else {
- itemrect.bottom = itemrect.top + commp->lheight;
- }
-
- barrect.left = itemrect.left - HSLIDE;
- barrect.right = itemrect.left;
- barrect.top = mrectp->top;
- barrect.bottom = itemrect.bottom;
-
- textvert = (itemrect.top + itemrect.bottom) / 2 -
- (commp->lheight / 2) + commp->finfo.ascent;
-
- /*
- * Now draw the item:
- * a line demarking the vertical bar;
- * a line for empty items, otherwise...
- * the check (or other mark) [if any]
- * the icon [if any]
- * the text of the item
- * the clover-key equivalent [if any]
- */
-
- MoveTo(barrect.right - 1, barrect.top);
- LineTo(barrect.right - 1, itemrect.top - 1);
-
- TextFace(infop->tstyle);
-
- curhorz = itemrect.left;
- if (name[1] == '-') {
- MoveTo(curhorz, (itemrect.top + itemrect.bottom) / 2);
- LineTo(itemrect.right - 1, (itemrect.top + itemrect.bottom) / 2);
- } else {
- if (infop->mark) {
- MoveTo(curhorz, textvert);
- DrawChar(infop->mark);
- curhorz += CharWidth(infop->mark);
- } else {
- curhorz += commp->checkwidth;
- }
-
- if (infop->iconnum) {
-
- /*
- * Menu icon numbers start at 257.
- */
-
- iconh = GetIcon(((int) infop->iconnum & 0xFF) + 256);
- if (iconh) {
- iconrect.left = curhorz + ICON_HMARG;
- iconrect.top = itemrect.top + ICON_VMARG;
- iconrect.right = iconrect.left + ICONSIDE;
- iconrect.bottom = iconrect.top + ICONSIDE;
- PlotIcon(&iconrect, iconh);
- }
- curhorz += ICON_HMARG + ICONSIDE + ICON_HMARG;
- }
-
- MoveTo(curhorz, textvert);
- DrawString(name);
-
- if (infop->keyequiv != '\0') {
- MoveTo(itemrect.right -
- (commp->cloverwidth + commp->finfo.widMax + RMARG),
- textvert);
- DrawChar((char) 0x11);
- DrawChar(infop->keyequiv);
- }
- }
-
- /*
- * The item is disabled if either the whole menu is disabled
- * or the item can be and is disabled.
- * (Only the first 31 items in a menu have disable/enable flags.)
- *
- * If the item is disabled, make it gray.
- */
-
- if (((*menuh)->enableFlags & 1) == 0L || (itemnum < 32 &&
- ((*menuh)->enableFlags & ((unsigned long) 1 << itemnum)) == 0L)) {
- PenMode(patBic);
- PenPat(&fuzz);
- PaintRect(&itemrect);
- }
-
- /*
- * Set things up for the next item in the menu.
- */
-
- SetPenState(&oldpen);
- itemrect.top = itemrect.bottom;
- itemrect.left -= HSLIDE;
- }
- }
-
- /*
- * mchoose() - Find which item (if any) is selected by the given mouse location,
- * unhighlight the previously-selected item (if any),
- * and highlight the newly-selected item (again, if any).
- */
-
- mchoose(commp, menuh, mrectp, pt, theitemp)
- struct commons *commp; /* the common information */
- MenuHandle menuh;
- Rect *mrectp;
- Point pt;
- int *theitemp; /* if non-zero, the old item; set it to the new item */
- {
- char *mcp; /* "Menu Char-Pointer" for traversing the menuData fields */
- int itemnum; /* the item number of the current item */
- char *name; /* the (Pascal) name of the current item */
- struct iteminfo *infop; /* pointer to the current item's info */
- Rect itemrect; /* rect enclosing the current item */
- Rect barrect; /* rect enclosing the vertical bar for this item */
- int wasitem; /* item number of the previously-selected item */
- int isitem; /* ditto for the newly-selected item */
-
- /*
- * See which item the mouse used to be in (rejecting nonsensical answers)
- * and initialize our idea of where the mouse is
- * (to be updated if/when we find the true mouse item).
- */
-
- wasitem = *theitemp;
- if (wasitem < 0 || wasitem > commp->numitems) {
-
- /*
- * We get illegal wasitem numbers when the menu manager tries
- * to blink the selected item.
- * I haven't found any description of these illegal item numbers.
- * If you know how to interpret these numbers, please drop me a note:
- * Brad Needham
- * 2239 SE 74th Ave.
- * Hillsboro, OR 97123 USA
- */
-
- wasitem = 0;
- }
- isitem = 0;
-
- /*
- * Now traverse the menu, looking for the item containing the mouse
- * or the item that used to contain the mouse.
- *
- * These two items are the only ones that will need to be redrawn --
- * nothing else has changed appearance.
- */
-
- itemrect.top = mrectp->top + commp->lheight / 2;
- itemrect.left = mrectp->left + commp->numitems * HSLIDE;
- itemrect.right = mrectp->right;
-
- itemnum = 0;
- mcp = (char *) &((*menuh)->menuData);
- mcp += ((int) *mcp & 0xFF) + 1;
- while (*mcp) {
- ++itemnum;
- name = mcp;
- mcp += ((int) *mcp & 0xFF) + 1;
- infop = (struct iteminfo *) mcp;
- mcp += sizeof(struct iteminfo);
-
- if (infop->iconnum) {
- itemrect.bottom = itemrect.top + ICON_VMARG + ICONSIDE + ICON_VMARG;
- } else {
- itemrect.bottom = itemrect.top + commp->lheight;
- }
-
- barrect.left = itemrect.left - HSLIDE;
- barrect.right = itemrect.left;
- barrect.top = mrectp->top;
- barrect.bottom = itemrect.bottom;
-
- /*
- * The item is disabled if either the whole menu is disabled
- * or the item can be and is disabled.
- * (Only the first 31 items in a menu have disable/enable flags.)
- *
- * If the item is disabled, we can't select it.
- */
-
- if (((*menuh)->enableFlags & 1) == 0L || (itemnum < 32 &&
- ((*menuh)->enableFlags & ((unsigned long) 1 << itemnum)) == 0L)) {
- goto notenabled;
- }
-
- /*
- * If the mouse is inside this item, then
- * this is the newly-selected item.
- */
-
- if (PtInRect(pt, &itemrect) || PtInRect(pt, &barrect)) {
- isitem = itemnum;
- }
-
- /*
- * We want to invert this item if either
- * this item is the mouse's item (to be inverted) or
- * this item used to be selected (and we want to clear the inversion).
- *
- * To avoid flicker, we change nothing if the mouse hasn't moved.
- */
-
- if ((itemnum == isitem || itemnum == wasitem) &&
- isitem != wasitem) {
- InvertRect(&itemrect);
- InvertRect(&barrect);
- }
-
- notenabled:
- itemrect.top = itemrect.bottom;
- itemrect.left -= HSLIDE;
- }
-
- /*
- * Report either the found item,
- * or the fact that we found no item.
- */
-
- *theitemp = isitem;
-
- }
-