home
***
CD-ROM
|
disk
|
FTP
|
other
***
search
/
The Fred Fish Collection 1.5
/
ffcollection-1-5-1992-11.iso
/
ff_progs
/
educ
/
splines.lzh
/
SPLINES
/
POPMENU.C
< prev
next >
Wrap
C/C++ Source or Header
|
1991-08-16
|
9KB
|
259 lines
/* The routines in this file are copyright (c) 1987 by Helene (Lee) Taran.
* Permission is granted for use and free distribution as long as the
* original author's name is included with the code.
*/
#include "popmenu.h"
struct Layer_Info *PopUp_LayerInfo;
struct TextFont *menufont;
/* User should call Init_MenuPackage() before trying to pop up any
* menus. Will return TRUE if the package has been initialized correctly.
* Do not attempt to use this package if this initialization routine
* returns FALSE.
*/
Init_MenuPackage()
{
void *NewLayerInfo(), *OpenFont();
static struct TextAttr MenuFont = {(UBYTE *)"topaz.font",8,0,0};
if (!(menufont = OpenFont(&MenuFont))) {
fprintf(stderr,"sorry couldn't find topaz eight for menu font]\n");
return(FALSE);
}
if (!(PopUp_LayerInfo = (struct Layer_Info *)NewLayerInfo())) {
fprintf(stderr,"sorry, couldn't allocate a layer info structure\n");
return(FALSE);
}
return(TRUE);
}
/* The user should call Close_MenuPackage before exiting their program
* to ensure that the menu package releases any memory that it
* has allocated for its own use.
*/
Close_MenuPackage()
{
CloseFont(menufont);
if (PopUp_LayerInfo != NULL)
DisposeLayerInfo(PopUp_LayerInfo);
}
Init_PopUp_Menu (menu)
struct PopUp_Menu *menu;
{
void *AllocRaster();
struct PopUp_Item *item;
int longest = 0;
int total_height = 0;
int i;
if (menu == NULL) return(FALSE);
item = menu->first_item;
while (item != NULL) {
/* note: bad things may happen if you allocate an empty string for
* your item text.
*/
item->width = MAX(item->width, FONT_WIDTH * strlen(item->text));
item->left = MAX(0,item->left);
longest = MAX(longest, (item->width + item->left));
item->height = MAX(item->height, FONT_HEIGHT);
item->top = MAX(0,item->top);
total_height += (item->height + item->top);
/* re-initialize item-top to be the top relative to the menu top */
item->top = (total_height - item->height);
item = item->next;
}
menu->height = total_height+1;
menu->width = MAX(menu->width, longest);
/* initialize a bitmap the same size as the required menu image */
/* initialize a raster port to facillitate drawing into the bitmap */
InitBitMap(&(menu->bitmap),menu->depth,menu->width,menu->height);
InitRastPort(&(menu->rp));
SetFont(menu->rp,menufont);
for (i = 0; i < menu->depth; i++)
if (!(menu->bitmap.Planes[i] = (PLANEPTR)
AllocRaster(menu->width, menu->height))) {
Dispose_PopUp(menu);
return(FALSE);
}
menu->rp.BitMap = &(menu->bitmap);
menu->cr.BitMap = &(menu->bitmap);
/* draw the menu outline and background color into its own bitmap */
SetDrMd(&(menu->rp),JAM1);
SetAPen(&(menu->rp),menu->area_color);
SetOPen(&(menu->rp),menu->outline_color);
RectFill(&(menu->rp),0,0,menu->width -1,menu->height -1);
BNDRYOFF(&(menu->rp)); /* turn off the raster port outlining */
item = menu->first_item;
/* Now, draw each menu item */
while (item != NULL) {
SetAPen(&(menu->rp),item->color);
Move(&(menu->rp),item->left, item->top + FONT_BASELINE);
Text(&(menu->rp),item->text, strlen(item->text));
item = item->next;
}
return(TRUE);
}
/* SelectItem : activates the item located at <x,y>. Assumes the <menu>
* is currently active and thus, menu->left and menu->top should represent
* the menu's current top,left corner. If there is an item located
* at <x,y> within the menu, then it is made 'active' ...this means
* that the item becomes menu->active_item and is highlighted. The
* old menu->active_item, if any, is deselected. Note: if you're using
* a GIMMEZEROZERO window you'll have to fiddle with the x,y coordinates.
*/
SelectItem(menu,Window)
struct PopUp_Menu *menu;
struct Window *Window;
{ struct PopUp_Item *item;
SHORT x = Window->MouseX + Window->LeftEdge;
SHORT y = Window->MouseY + Window->TopEdge;
item = menu->first_item;
x -= menu->left; y -= menu->top;
if ((x >= 0) && (x < menu->width) && (y >= 0) && (y < menu->height))
while (item != NULL) {
if ((y >= item->top -1) && (y < item->top -1 + item->height))
break; /* we found an active item {yeah yeah...bad style, i know...} */
else item = item->next;
}
else item = NULL; /* mouse isn't on menu */
if (menu->active_item != item) { /* deselect previously active item */
ComplementItem(menu,menu->active_item,Window);
ComplementItem(menu,item,Window);
}
menu->active_item = item;
}
/* ComplementItem : complements the given menu item area. Assumes that
* the <menu> is currently being displayed and thus,the current menu->left
* and menu->top represent the current coordinates of the menu's top,left
* corner. Assumes the <item> is an popup_item that belongs to <menu>
* and that its left/top offsets have been initialized.
*/
ComplementItem(menu,item,Window)
struct PopUp_Menu *menu;
struct PopUp_Item *item;
struct Window *Window;
{ BYTE old_mode = Window->WScreen->RastPort.DrawMode;
if (item == NULL) return; /* do nothing */
SetDrMd(&(Window->WScreen->RastPort), COMPLEMENT);
RectFill(&(Window->WScreen->RastPort), menu->left,
menu->top + item->top -1,
menu->left + menu->width -1,
menu->top + item->top + item->height -2);
SetDrMd(&(Window->WScreen->RastPort), (int)old_mode);
}
/* PopUp : this is one of those 'do everything' type of functions. It
* displays the <menu> in the window given its upper left hand
* coordinates <left,top>. It tracks the user's mouse movements,
* highlighting the currently active item until the user deselects
* the menu by releasing the mouse's select button, at which time,
* this function will remove the menu from the display. Returns the
* selection_id of the item that was active when the user releases
* the select button. Returns 0 if nothing was selected.
* Assumes that the <menu> has been initialized by a call to
* Init_PopUp_Menu and that the user has requested ReportMouse for the
* Window in question (ReportMouse makes sure that the Window's MouseX and
* MouseY coordinates are kept up to date).
*/
int PopUp(menu,Window)
struct PopUp_Menu *menu;
struct Window *Window;
{ ULONG oldflags;
SHORT left, top;
left = Window->MouseX;
top = Window->MouseY;
if (!Inside_Window(left,top,Window)) return(OUTSIDE_WINDOW);
if ((menu->width <= Window->Width) && (left + menu->width > Window->Width))
left += Window->Width - (left + menu->width);
if ((menu->height <= Window->Height) && (top + menu->height > Window->Height))
top += Window->Height - (top + menu->height);
LockLayers(PopUp_LayerInfo);
/* SwapBits...() requires that the clipping rectangle's bounds are given
* with respect to the screen's 0,0 coordinate but mouse movements
* are reported to the Window and are given in terms of the window's
* coordinate system so...sLeft and sTop represent the adjustment of
* the Window's coordinates to match the screen's coordinates.
* Note: if you're using a GIMMEZEROZERO window, you'll have to muck
* with the left,top coordinates to get the complementing to work.
*/
left = (left + Window->LeftEdge) & 0xfff0;
top = top + Window->TopEdge;
menu->cr.bounds.MinX = left;
menu->cr.bounds.MinY = top;
menu->cr.bounds.MaxX = left + menu->width -1;
menu->cr.bounds.MaxY = top + menu->height -1;
SwapBitsRastPortClipRect(Window->RPort,&(menu->cr));
menu->left = left;
menu->top = top;
SelectItem(menu,Window);
oldflags = Window->IDCMPFlags;
ModifyIDCMP(Window,oldflags | MOUSEMOVE);
while (1) /* wait for the user to select an item and deselect the menu */
{ struct IntuiMessage msg, *message, *GetMsg();
int MouseMoved = FALSE;
Wait(1 << Window->UserPort->mp_SigBit);
while (message = GetMsg(Window->UserPort)) {
msg = *message; /* make a backup copy of message */
ReplyMsg(message); /* reply immediately to prevent deadlock */
if (msg.Class == MOUSEMOVE)
/* just keep track of the fact that the mouse moved */
MouseMoved = TRUE;
else if ((msg.Class == MOUSEBUTTONS) && (msg.Code == menu->deactivate)) {
/* user has deselected the menu */
ModifyIDCMP(Window,oldflags); /* restore idcmp flags */
SelectItem(menu,Window);
SwapBitsRastPortClipRect(Window->RPort,&(menu->cr));
UnlockLayers(PopUp_LayerInfo);
if (menu->active_item != NULL)
return(menu->active_item->selection_id);
else return(NOITEM_SELECTED);
} /* end of deselection routine */
}
/*
* at this point the message queue should be empty so the mouse
* has stopped for the moment.
*/
if (MouseMoved)
SelectItem(menu,Window);
}
}
Dispose_PopUp(menu)
struct PopUp_Menu *menu;
{
int i;
for (i = 0; i < menu->depth; i++)
if (menu->bitmap.Planes[i] != NULL)
FreeRaster(menu->bitmap.Planes[i], menu->width, menu->height);
}