home *** CD-ROM | disk | FTP | other *** search
- /***************************************************************************
- * popmenu_pak.c -general-purpose dynamic Pop-up Menu routines to help make*
- * programming alot easier. *
- * (c) 1990 VIDEOWORKS Computer Applications *
- * All rights reserved. *
- * 129 Orchard Avenue, Rocky Mount, VA 24151 *
- * (703) 483-8219 / 489-3863 *
- * *
- * Designed and Developed by Paul T. Miller *
- * *
- * Program Name: N/A *
- * Version: 1 *
- * Revision: 0 *
- *-------------------------------------------------------------------------*
- * File: (popmenu_pak.c) dynamic window-relative pop-up menu routines *
- *-------------------------------------------------------------------------*
- * Modification History *
- * Date Author Comment *
- * -------- ------ ------- *
- * 03-29-90 PTM Created. Initialization/Setup
- * 04-01-90 PTM PMenu drawing/handling. RastPort FONT characteristics
- * 05-07-90 PTM Modify PMenu box expansion to fit in window
- * 05-09-90 PTM Move itemtext positioning to drawmenu()
- *
- ***************************************************************************/
-
- #include "popmenu_pak.h"
-
- #ifndef GRAPHICS_GFXMACROS_H
- #include <graphics/gfxmacros.h>
- #endif
-
- /* Here are some constants for itemtext placement and item sizes */
- #define PMENU_WOFF 16 /* sixteen pixels wider than longest text */
- #define PITEM_VOFF 2 /* extra pixels for item (+font height) */
- #define PITEM_YOFF 2 /* vertical index into item for text */
- #define PITEM_XOFF 2 /* horizontal index into item for text */
-
- struct PMenu *BuildPMenu(item, flags, inum, title, id)
- struct PMenuItem *item;
- USHORT flags;
- SHORT inum;
- UBYTE *title;
- USHORT id;
- {
- struct PMenu *pmenu;
- struct IntuiText *itext = NULL;
- struct Border *border;
- struct Gadget *gad;
-
- /* Allocate memory for menu, gadget, gadget text, and border */
-
- pmenu = (struct PMenu *)AllocMem(sizeof(struct PMenu), MEMF_CLEAR);
- if (!pmenu) return(NULL);
-
- gad = (struct Gadget *)AllocMem(sizeof(struct Gadget), MEMF_CLEAR);
- if (!gad)
- {
- FreeMem(pmenu, sizeof(struct PMenu));
- return(NULL);
- }
-
- border = (struct Border *)AllocMem(sizeof(struct Border), MEMF_CLEAR);
- if (!border)
- {
- FreeMem(gad, sizeof(struct Gadget));
- FreeMem(pmenu, sizeof(struct PMenu));
- return(NULL);
- }
-
- itext = (struct IntuiText *)AllocMem(sizeof(struct IntuiText), MEMF_CLEAR);
- if (!itext)
- {
- FreeMem(border, sizeof(struct Border));
- FreeMem(gad, sizeof(struct Gadget));
- FreeMem(pmenu, sizeof(struct PMenu));
- return(NULL);
- }
-
- if (flags & SHADOWED)
- border->Count = 8;
- else
- border->Count = 5;
-
- border->XY = (SHORT *)AllocMem(sizeof(SHORT)*16, MEMF_CLEAR);
- border->FrontPen = 1;
- border->BackPen = 0;
- border->DrawMode = JAM1;
-
- pmenu->FirstPItem = item;
- pmenu->Flags = flags;
- pmenu->MenuName = (UBYTE *)AllocMem(80, MEMF_CLEAR);
- if (title)
- {
- strcpy(pmenu->MenuName, title);
- pmenu->Flags |= TITLED; /* title supplied by user */
- }
-
- if (pmenu->FirstPItem)
- {
- if (inum < 1) inum = 1;
- pmenu->ActiveItem = GetPItem(pmenu, inum);
- pmenu->Flags |= PREDEFINED;
- }
- itext->FrontPen = 1; /* Build text for user-controlled menu title */
- itext->BackPen = 0;
- itext->DrawMode = JAM1;
- itext->IText = pmenu->MenuName;
-
- gad->NextGadget = NULL;
- gad->GadgetType = BOOLGADGET;
- gad->Activation = GADGIMMEDIATE | FOLLOWMOUSE;
- gad->Flags = GADGHCOMP;
- gad->GadgetRender = (APTR)border;
- gad->SelectRender = NULL;
- gad->MutualExclude = NULL;
- gad->SpecialInfo = NULL;
- gad->GadgetText = itext;
- gad->GadgetID = id;
- gad->UserData = (APTR)pmenu;
- pmenu->PMenuGadget = gad;
-
- return(pmenu);
- }
-
- void SetPMenuColor(pmenu, frontpen, backpen)
- struct PMenu *pmenu;
- USHORT frontpen, backpen;
- {
- struct Border *border;
- struct IntuiText *itext;
-
- if (pmenu)
- {
- itext = (struct IntuiText *)pmenu->PMenuGadget->GadgetText;
- border = (struct Border *)pmenu->PMenuGadget->GadgetRender;
- if (itext)
- {
- itext->FrontPen = frontpen;
- itext->BackPen = backpen;
- }
- if (border)
- {
- border->FrontPen = frontpen;
- border->BackPen = backpen;
- }
- }
- }
-
- InitPMenu(window, pmenu, x, y)
- struct Window *window;
- struct PMenu *pmenu;
- SHORT x, y;
- {
- struct RastPort *rp = window->RPort;
- struct Gadget *gad;
- ULONG flags;
-
- if (!window || !pmenu)
- return(NULL);
-
- flags = window->IDCMPFlags;
- ModifyIDCMP(window, flags | GADGETUP);
-
- pmenu->PMenuWindow = window;
-
- /* no user-set width, so find width/height of activation box */
- if (pmenu->Width == 0)
- pmenu->Width = (SHORT)find_maxpitemwidth(pmenu) + PMENU_WOFF;
-
- if (pmenu->Height == 0)
- pmenu->Height = rp->TxHeight+PITEM_VOFF;
-
- /* find out where in the window to render the window */
- if (x == -1)
- pmenu->LeftEdge = window->Width - pmenu->Width - 5;
- else if (x < -1)
- pmenu->LeftEdge = window->Width + x;
- else
- pmenu->LeftEdge = x;
-
- if (y == -1)
- pmenu->TopEdge = window->Height - pmenu->Height - 5;
- else if (y < -1)
- pmenu->TopEdge = window->Height + y;
- else
- pmenu->TopEdge = y;
-
- /* set up activation gadget attributes */
- gad = pmenu->PMenuGadget;
- gad->LeftEdge = pmenu->LeftEdge;
- gad->TopEdge = pmenu->TopEdge;
- gad->Width = pmenu->Width;
- gad->Height = pmenu->Height;
-
- calc_border(pmenu);
-
- pmenu->Flags |= MENUENABLED;
- pmenu->Flags |= MENU_INIT;
-
- AddGadget(window, pmenu->PMenuGadget, -1);
- RefreshPMenu(pmenu);
-
- return(1);
- }
-
- find_maxpitemwidth(pmenu)
- struct PMenu *pmenu;
- {
- int length, max = 0;
- struct PMenuItem *item;
-
- for (item = pmenu->FirstPItem; item; item = item->NextPItem)
- {
- if (item->Flags & ITEMTEXT)
- {
- length = IntuiTextLength((struct IntuiText *)item->ItemFill);
- if (length > max) max = length;
- }
- }
- return(max);
- }
-
- void calc_border(pmenu)
- struct PMenu *pmenu;
- {
- struct Border *b;
- SHORT *dat;
-
- if (pmenu)
- {
- b = (struct Border *)pmenu->PMenuGadget->GadgetRender;
- dat = b->XY;
-
- if (pmenu->Flags & SHADOWED)
- {
- b->Count = 8;
- dat[0] = dat[2] = pmenu->Width+1;
- dat[1] = dat[4] = 1;
- dat[3] = dat[5] = pmenu->Height+1;
- dat[6] = dat[11] = dat[12] = dat[13] = dat[14] = 0;
- dat[7] = dat[9] = dat[15] = pmenu->Height;
- dat[8] = dat[10] = pmenu->Width;
- }
- else
- {
- b->Count = 5;
- dat[0] = dat[1] = dat[3] = dat[6] = dat[8] = dat[9] = 0;
- dat[2] = dat[4] = pmenu->Width;
- dat[5] = dat[7] = pmenu->Height;
- }
- }
- }
-
- void RefreshPMenu(pmenu)
- struct PMenu *pmenu;
- {
- struct IntuiText *itext;
- struct PMenuItem *item;
- int x, y, w, h;
- UBYTE bpen;
-
- bpen = pmenu->PMenuGadget->GadgetText->BackPen;
-
- if (pmenu && (pmenu->Flags & MENU_INIT))
- {
- if (pmenu->Flags & TITLED)
- pmenu->PMenuGadget->GadgetText->IText = pmenu->MenuName;
- else
- {
- item = pmenu->ActiveItem;
- if (item->Flags & ITEMTEXT)
- {
- itext = (struct IntuiText *)pmenu->ActiveItem->ItemFill;
- pmenu->PMenuGadget->GadgetText->IText = itext->IText;
- }
- }
- itext = pmenu->PMenuGadget->GadgetText;
- itext->LeftEdge = (pmenu->Width - IntuiTextLength(itext))/2;
- itext->TopEdge = PITEM_YOFF;
- x = pmenu->LeftEdge;
- y = pmenu->TopEdge;
- w = pmenu->Width;
- h = pmenu->Height;
- SetDrMd(pmenu->PMenuWindow->RPort, JAM1);
- SetAPen(pmenu->PMenuWindow->RPort, bpen);
- RectFill(pmenu->PMenuWindow->RPort, x, y, x+w, y+h);
- RefreshGList(pmenu->PMenuGadget, pmenu->PMenuWindow, NULL, 1);
- }
- }
-
- void RemovePMenu(pmenu)
- struct PMenu *pmenu;
- {
- if (pmenu && pmenu->Flags & MENU_INIT)
- {
- pmenu->Flags &= ~MENU_INIT;
- pmenu->Flags &= ~MENUENABLED;
- RemoveGadget(pmenu->PMenuWindow, pmenu->PMenuGadget);
- }
- }
-
- void FreePMenu(pmenu)
- struct PMenu *pmenu;
- {
- struct Border *border;
-
- if (pmenu)
- {
- RemovePMenu(pmenu);
-
- FreeMem(pmenu->PMenuGadget->GadgetText, sizeof(struct IntuiText));
- FreeMem(pmenu->MenuName, 80);
-
- border = (struct Border *)pmenu->PMenuGadget->GadgetRender;
- if (border)
- {
- FreeMem(border->XY, sizeof(SHORT) * 16);
- FreeMem(border, sizeof(struct Border));
- }
- FreeMem(pmenu->PMenuGadget, sizeof(struct Gadget));
- FreeMem(pmenu, sizeof(struct PMenu));
- }
- }
-
- void SetActiveItem(pmenu, inum)
- struct PMenu *pmenu;
- SHORT inum;
- {
- struct PMenuItem *item;
-
- if (inum < 1) return;
-
- if (pmenu && (pmenu->Flags & COMMPMENU))
- {
- item = GetPItem(pmenu, inum);
- if (item)
- {
- pmenu->ActiveItem = item;
- RefreshPMenu(pmenu);
- }
- }
- }
-
- struct PMenuItem *GetPItem(pmenu, inum)
- struct PMenu *pmenu;
- SHORT inum;
- {
- struct PMenuItem *item;
- UCOUNT i = 1;
-
- for (item = pmenu->FirstPItem; item; item = item->NextPItem, i++)
- if (i == inum)
- return(item);
-
- return(NULL);
- }
-
- SHORT GetPItemNum(pmenu, item)
- struct PMenu *pmenu;
- struct PMenuItem *item;
- {
- struct PMenuItem *pitem;
- SHORT i = 0;
-
- if (item == NULL) return(0);
-
- if (pmenu->FirstPItem == item)
- return(1);
-
- for (pitem = pmenu->FirstPItem; pitem; pitem = pitem->NextPItem, i++)
- if (pitem == item)
- return((SHORT)(i+1));
-
- return(0);
- }
-
- CountPMenuItems(pmenu)
- struct PMenu *pmenu;
- {
- struct PMenuItem *item;
- UCOUNT i;
-
- if (pmenu->FirstPItem == NULL)
- return(0);
-
- for (i = 0, item = pmenu->FirstPItem; item; item = item->NextPItem, i++)
- ;
-
- return(i+1);
- }
-
- /* Sets the menu activation box of a popup menu to specified text:
- Only if an initial constant title was supplied with BuildPMenu() */
-
- void SetPMenuText(pmenu, text)
- struct PMenu *pmenu;
- UBYTE *text;
- {
- if (pmenu)
- if (pmenu->Flags & TITLED)
- {
- strcpy(pmenu->MenuName, text);
- RefreshPMenu(pmenu);
- }
- }
-
- USHORT HandlePMenu(pmenu)
- struct PMenu *pmenu;
- {
- ULONG oldflags;
- struct Window *win;
- struct BitMap *sbm;
- struct PMenuItem *item;
- struct IntuiMessage *message;
- ULONG class;
- USHORT code, inum;
- SHORT mx, my;
- SHORT lnum = 0, mousemoved = 0;
-
- if (!pmenu) return(NULL);
-
- calc_menusize(pmenu);
- sbm = savebackground(pmenu);
-
- drawpmenu(pmenu);
-
- win = pmenu->PMenuWindow;
- oldflags = win->IDCMPFlags;
- ReportMouse(win, TRUE);
- ModifyIDCMP(win, oldflags | MOUSEMOVE | MOUSEBUTTONS);
-
- lnum = GetPItemNum(pmenu, pmenu->ActiveItem);
- complement_item(pmenu, lnum);
-
- while (1)
- {
- WaitPort(win->UserPort);
- while (message = (struct IntuiMessage *)GetMsg(win->UserPort))
- {
- class = message->Class;
- code = message->Code;
- mx = message->MouseX;
- my = message->MouseY;
-
- ReplyMsg(message);
-
- switch (class)
- {
- case MOUSEMOVE:
- mousemoved = 1;
- break;
- case MOUSEBUTTONS:
- switch (code)
- {
- case SELECTUP:
- item = getmenuitem(pmenu, mx, my);
- restorebackground(pmenu, sbm);
- ModifyIDCMP(win, oldflags);
- inum = GetPItemNum(pmenu, item);
- if (!(pmenu->Flags & TITLED))
- SetActiveItem(pmenu, inum);
- return(inum);
- break;
- }
- break;
- }
- }
- if (mousemoved)
- {
- mousemoved = 0;
- handle_items(pmenu, mx, my, &lnum);
- }
- }
- }
-
- struct PMenuItem *getmenuitem(pmenu, mx, my)
- struct PMenu *pmenu;
- SHORT mx, my;
- {
- struct PMenuItem *item;
- SHORT x, y, x2, y2;
- USHORT num;
-
- if (!pmenu) return(NULL);
-
- x = pmenu->JazzX;
- y = pmenu->JazzY;
- x2 = pmenu->JazzX + pmenu->BeatX;
- y2 = pmenu->JazzY + pmenu->BeatY;
-
- if (mx > x && my > y && mx < x2 && my < y2)
- {
- num = (my - y - PITEM_YOFF) / pmenu->Height;
- item = GetPItem(pmenu, (SHORT)(num+1));
- if (item->Flags & ITEMENABLED)
- return(item);
- }
- return(NULL);
- }
-
- void calc_menusize(pmenu)
- struct PMenu *pmenu;
- {
- UCOUNT num;
-
- num = CountPMenuItems(pmenu);
-
- if (pmenu->Flags & TITLED) /* titled, so find width of largest item */
- pmenu->BeatX = find_maxpitemwidth(pmenu) + PMENU_WOFF;
- else
- pmenu->BeatX = pmenu->Width; /* otherwise width/height of menu box */
-
- pmenu->BeatY = pmenu->Height * (num-1) + PITEM_VOFF-1;
- if (pmenu->Flags & SHADOWED)
- {
- pmenu->BeatX++;
- pmenu->BeatY++;
- }
- pmenu->JazzX = pmenu->LeftEdge; /* upper-left corner of expanded */
- pmenu->JazzY = pmenu->TopEdge;
-
- /* shift menu into window if it extends out right side */
- if (pmenu->JazzX + pmenu->BeatX > pmenu->PMenuWindow->Width)
- pmenu->JazzX = pmenu->LeftEdge + pmenu->Width - pmenu->BeatX + 1;
-
- if (pmenu->Flags & COMMPMENU)
- {
- num = GetPItemNum(pmenu, pmenu->ActiveItem);
- pmenu->JazzY -= ((num-1) * pmenu->Height);
- while (pmenu->JazzY <= 0)
- pmenu->JazzY += pmenu->Height;
- }
- }
-
- struct BitMap *savebackground(pmenu)
- struct PMenu *pmenu;
- {
- int x, y, w, h;
- struct Window *win;
- struct BitMap *bm;
-
- win = pmenu->PMenuWindow;
- x = win->LeftEdge + pmenu->JazzX;
- y = win->TopEdge + pmenu->JazzY;
- w = pmenu->BeatX + 1;
- h = pmenu->BeatY + 1;
-
- bm = allocbitmap((USHORT)w, (USHORT)h, (UBYTE)win->RPort->BitMap->Depth);
- if (bm)
- BltBitMap(win->RPort->BitMap, x, y, bm, 0, 0, w, h, 0xc0, 0xff, NULL);
-
- return(bm);
- }
-
- void restorebackground(pmenu, bm)
- struct PMenu *pmenu;
- struct BitMap *bm;
- {
- int x, y, w, h;
- struct Window *win;
-
- if (!pmenu) return;
-
- win = pmenu->PMenuWindow;
- x = win->LeftEdge + pmenu->JazzX;
- y = win->TopEdge + pmenu->JazzY;
- w = pmenu->BeatX + 1;
- h = pmenu->BeatY + 1;
-
- if (bm)
- {
- BltBitMap(bm, 0, 0, win->RPort->BitMap, x, y, w, h, 0xc0, 0xff, NULL);
- freebitmap(bm);
- }
- pmenu->Flags &= ~MIDRAWN;
- }
-
- void drawpmenu(pmenu)
- struct PMenu *pmenu;
- {
- int x, y, w, h, i;
- struct RastPort *rp;
- struct PMenuItem *item;
- struct IntuiText *itext;
- UBYTE fpen, bpen;
-
- rp = pmenu->PMenuWindow->RPort;
-
- SetDrMd(rp, JAM1);
-
- fpen = pmenu->PMenuGadget->GadgetText->FrontPen;
- bpen = pmenu->PMenuGadget->GadgetText->BackPen;
-
- x = pmenu->JazzX;
- y = pmenu->JazzY;
- w = pmenu->BeatX;
- h = pmenu->BeatY;
-
- if (pmenu->Flags & SHADOWED)
- {
- w--;
- h--;
- }
-
- /* draw the menu outline */
- SetAPen(rp, fpen);
- RectFill(rp, x, y, x+w, y+h);
- SetAPen(rp, bpen);
- RectFill(rp, x+1, y+1, x+w-2, y+h-2);
-
- SetAPen(rp, fpen);
- if (pmenu->Flags & SHADOWED)
- {
- Move(rp, x+w+1, y+1);
- Draw(rp, x+w+1, y+h+1);
- Draw(rp, x+1, y+h+1);
- }
-
- for (i = 0, item = pmenu->FirstPItem; item; item = item->NextPItem, i++)
- {
- if (item->Flags & ITEMTEXT)
- {
- itext = (struct IntuiText *)item->ItemFill;
- itext->TopEdge = PITEM_YOFF;
-
- /* position item text */
- if (item->Flags & CENTERED)
- itext->LeftEdge = (w - IntuiTextLength(itext))/2;
- else
- itext->LeftEdge = PITEM_XOFF;
-
- SetAPen(rp, itext->FrontPen);
- Move(rp, x+itext->LeftEdge,
- y + itext->TopEdge + (i * pmenu->Height) + rp->TxBaseline);
- Text(rp, itext->IText, strlen(itext->IText));
- }
- }
- pmenu->Flags |= MIDRAWN;
- }
-
- void handle_items(pmenu, mx, my, lnum)
- struct PMenu *pmenu;
- SHORT mx, my, *lnum;
- {
- SHORT x, y, x2, y2;
- USHORT num;
-
- if (!pmenu) return;
-
- x = pmenu->JazzX;
- y = pmenu->JazzY;
- x2 = pmenu->JazzX + pmenu->BeatX - 1;
- y2 = pmenu->JazzY + pmenu->BeatY - 1;
- if (pmenu->Flags & SHADOWED)
- {
- x2--;
- y2--;
- }
-
- if (mx > x && my > y && mx < x2 && my < y2)
- {
- num = ((my - y - PITEM_VOFF) / pmenu->Height) + 1;
- if (num != *lnum)
- {
- if (*lnum != 0)
- complement_item(pmenu, *lnum);
-
- complement_item(pmenu, num);
- }
- *lnum = num;
- return;
- }
- if (*lnum != 0)
- complement_item(pmenu, *lnum);
- *lnum = 0;
- }
-
- void complement_item(pmenu, num)
- struct PMenu *pmenu;
- SHORT num;
- {
- int x, y, w, h;
- struct PMenuItem *item;
- struct RastPort *rp = pmenu->PMenuWindow->RPort;
- BYTE old_mode = rp->DrawMode;
-
- item = GetPItem(pmenu, num);
-
- if (pmenu == NULL || item == NULL)
- return;
-
- if (item->Flags & ITEMENABLED)
- {
- x = pmenu->JazzX+1;
- y = pmenu->JazzY + (num-1)*pmenu->Height+1;
- w = pmenu->BeatX-4;
- h = pmenu->Height-1;
-
- SetDrMd(rp, COMPLEMENT);
- SetAPen(rp, 1);
- RectFill(rp, x, y, x+w, y+h);
- SetDrMd(rp, old_mode);
- }
- }
-
- struct BitMap *allocbitmap(width, height, depth)
- USHORT width, height;
- UBYTE depth;
- {
- struct BitMap *bm;
- register int i;
-
- bm = (struct BitMap *)AllocMem(sizeof(struct BitMap), MEMF_CLEAR);
- if (bm)
- {
- InitBitMap(bm, (long)depth, (long)width, (long)height);
-
- for (i = 0; i < depth; i++)
- {
- bm->Planes[i] = (PLANEPTR)AllocRaster(width, height);
- if (!bm->Planes[i])
- {
- freebitmap(bm);
- return(NULL);
- }
- }
- }
- return(bm);
- }
-
- void freebitmap(bm)
- struct BitMap *bm;
- {
- register int i;
-
- if (bm)
- {
- for (i = 0; i < bm->Depth; i++)
- if (bm->Planes[i])
- FreeMem(bm->Planes[i], (long)(bm->BytesPerRow * bm->Rows));
- FreeMem(bm, sizeof(struct BitMap));
- }
- }
-