home
***
CD-ROM
|
disk
|
FTP
|
other
***
search
/
Frozen Fish 2: PC
/
frozenfish_august_1995.bin
/
bbs
/
d03xx
/
d0368.lha
/
PopMenu
/
popmenu_pak.c
< prev
next >
Wrap
C/C++ Source or Header
|
1990-08-15
|
18KB
|
745 lines
/***************************************************************************
* 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));
}
}