/************************************************************************** * M E N U E X A M P L E P R O G R A M - JOHN DRAPER * * This program demonstrates the use of menus. It is constructed so * pieces can me "Plucked out" and used in other programs. * * The menu structures are declared and initialized much like the * existing Amiga demo programs, however, the MenuItem structures * are initialized by a function from easily changed arrays. This * combines "Best of both worlds". Only a single routine is needed to * initialize the MenuItem structures, and yet the source code won't * be un-necessarily cluttered by having each of the MenuItem structures * declared and initialized, thus keeping the program size to within * reasonable limits. This program will compile on Both Lattice C * and Aztec C (Soon to be released). Remove the #define AZTEC * * This isn't the most efficient piece of C code I've written, as if * I write a lot of C code, It only shows what is involved in creating * menus, and taking menu actions. ***************************************************************************/ #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include /*************************************************************************** * Early beta-test versions of Manx C had a bug which caused a system * crash with certain void constructs. This same compiler does NOT * predefine "AMIGA", so we use this def to remap voids to int. * Also note that "VOID" is defined in . ***************************************************************************/ #ifndef AMIGA #undef VOID /** Get rid of old definition **/ #define VOID int /** Make void's int's instead **/ #endif /*************************************************************************** * I M P O R T A N T C O N S T A N T S ***************************************************************************/ #define MAXPLANES 6 /** Max number of bitplanes we will need ***/ #define MAX_WIDTH 128 /** Max number of Pixels wide for sprite */ #define MAX_HEIGHT 128 /** Max number of pixels high for sprite */ #define NL 0 #define REDP 3 #define BLKP 2 #define WHTP 1 #define BLUP 0 /*** CLOSE FLAGS FOR VARIOUS THINGS ***/ long mask = 0; #define INTUITION 0x00000001 #define GRAPHICS 0x00000002 #define SCREEN 0x00000004 #define WINDOW 0x00000008 #define COLORMAP 0x00000010 #define MENU 0x00000020 int we_add = TRUE; /* We add a proportional gadget for first time */ /*************************************************************************** F U N C T I O N D E C L A R A T I O N S ***************************************************************************/ extern VOID *OpenLibrary(); extern struct Window *OpenWindow(); extern struct IntuiMessage *GetMsg(); extern VOID exit(); static VOID close_things(); static VOID NewMenu(); static VOID domenu(); static VOID auto_req(); static VOID do_req(); /* * For portability between compilers with 32 bit ints and thoses with * 16 bit ints, the following referenced functions are declared as returning * long, which is 32 bits for most compilers with 16 bit ints. * * Actually, I have not really checked the library documentation to find * out if any of these actually return pointers. * */ extern long RefreshGadgets(); extern long SetMenuStrip(); extern long AddGadget(); extern long AutoRequest(); extern long OpenWorkBench(); extern long ClearMenuStrip(); extern long ReplyMsg(); extern long Wait(); extern long InitRequester(); extern long Request(); extern long CloseLibrary(); extern long DrawImage(); extern long CloseWindow(); extern long printf(); /*************************************************************************** * I N T U I T I O N G L O B A L V A R S ***************************************************************************/ struct IntuitionBase *IntuitionBase; struct GfxBase *GfxBase; struct IntuiMessage *message; struct RastPort *rp; struct Window *w; /*************************************************************************** * M I S C G L O B A L V A R I A B L E S ***************************************************************************/ /*************************************************************************** M E N U D E F I N I T I O N S ***************************************************************************/ #define NUM_MENUS 3 /* Copies of this structure will get "stamped" into many more */ /* Allocated later */ struct IntuiText generic = { 0, 1, /* Bluepen, Whitepen */ JAM2, 5, /* mode, LeftEdge */ 0, NL, /* Top (to be filled later), Font */ NL, /* Name (to be filled later) */ NL /* Next one */ }; /* Menu numbers */ #define FILE_MENU 0 #define WIND_MENU 1 #define REQS_MENU 2 /* Menu Widths */ #define FIL_WIDTH 60 #define ITEM_WIDTH 70 #define REQ_WIDTH 100 int item_widths[ NUM_MENUS ] = { 80, 96, 198 }; /* All items in these menus has the following flags set */ #define BOX_FILL ITEMTEXT | ITEMENABLED | HIGHBOX /* File */ #define BLACK_FILL ITEMTEXT | ITEMENABLED | HIGHCOMP /* Wind */ #define HAS_CHECKS ITEMTEXT | ITEMENABLED | HIGHBOX | CHECKIT /* Reqs */ /** BITPLANE MENU ITEM NAME POINTERS **/ #define NUM_REQUESTS 6 #define REQS1 0 #define REQS2 1 #define REQS3 2 #define GAD_REQS 3 #define TEX_REQS 4 #define IMG_REQS 5 struct MenuItem req_items[NUM_REQUESTS]; struct IntuiText req_names[NUM_REQUESTS]; char *rqs_names[] = { " Auto Request 1", " Auto Request 2", " Auto Request 3", " Create Joystick gadget", " Custom Requester", " Requester with Images" }; struct Menu req_menu = { NL, /* NO Next menu */ FIL_WIDTH + ITEM_WIDTH, /* LeftEdge */ 0, REQ_WIDTH, 10, /* TopEdge, Width, Height */ MENUENABLED, /* Flags */ "Requestors", /* Menu name */ req_items /* Pointer to items list */ }; /** OPTIONS MENU ITEM NAME POINTERS ***/ #define NUM_WINDOWS 2 #define INFO_ITEM 0 #define GRA_ITEM 1 static struct MenuItem win_items[NUM_WINDOWS]; static struct IntuiText win_text[NUM_WINDOWS]; char *wind_names[] = { "Information", /* Write text into window, then close it */ "Graphics" /* Draw various graphics images into window */ }; struct Menu win_menu = { &req_menu, /* Pointer to next menu */ FIL_WIDTH, /* LeftEdge */ 0, ITEM_WIDTH, 10, /* TopEdge, Width, Height */ MENUENABLED, /* FLAGS */ "Windows", /* Name of menu */ win_items /* First item structure */ }; /** FILE MENU ITEMS **/ #define NUM_FILE_ITEMS 5 #define NEW_ITEM 0 #define OPEN_ITEM 1 #define SAVE_ITEM 2 #define SAVAS_ITEM 3 #define QUIT_ITEM 4 struct MenuItem file_items[NUM_FILE_ITEMS]; struct IntuiText file_names[NUM_FILE_ITEMS]; char *filemenu_names[] = { "New", "Open", "Save", "Save as..", "Quit" }; struct Menu fmenu = { &win_menu, /* Pointer to next menu */ 0, 0, FIL_WIDTH, 10, /* LeftEdge, TopEdge, Width, Height */ MENUENABLED, /* FLAGS */ "File", /* Menu name */ file_items /* First item structure */ }; /*************************************************************************** AUTO REQUEST INTUITEXT STRUCTURES ***************************************************************************/ struct IntuiText AutoText = { REDP, WHTP, JAM2, 5, 5, NL, /* A function puts string in this one */ (UBYTE *) "Simple AutoRequest", NL }; /** TRUE TEXT **/ struct IntuiText TRUEtext = { BLUP, WHTP, JAM2, 7, /* LeftEdge */ 3, /* TopEdge */ NL, /* Default font */ (UBYTE *) "TRUE", /* Text */ NL /* No pointer to next text */ }; /** FALSE TEXT **/ struct IntuiText FALSEtext = { REDP, WHTP, JAM2, 7, /* LeftEdge */ 3, /* TopEdge */ NL, /* Default font */ (UBYTE *) "FALSE", /* Text */ NL }; /*************************************************************************** CUSTOM REQUEST WITH TEXT, BORDERS, AND GADGETS ***************************************************************************/ /* Border for buttons */ SHORT Pairs[] = { 0, 0, 51, 0, 51, 12, 0, 12, 0, 0 }; #define NUM_PAIRS 5 struct Border butt_border = { -1, -1, BLUP, 0, JAM1, NUM_PAIRS, (SHORT *) Pairs, NULL }; /* FALSE BUTTON TEXT AND GADGET */ struct IntuiText negtext = { REDP, WHTP, JAM2, 6, 2, NL, (UBYTE *) "FALSE", NL }; #define FALSE_BUTT 1 /** GadgetID used to identify the action ***/ struct Gadget offgad = { NULL, 158, 46, /* LeftEdge, TopEdge */ 50, 11, /* Width, Height */ GADGHCOMP, /* Flag */ RELVERIFY | ENDGADGET, /* Activation */ BOOLGADGET | REQGADGET, /* GadgetType */ (APTR)&butt_border, /* GadgetRender - Border */ NULL, /* SelectRender */ &negtext, /* "OK" text */ NL, NL, FALSE_BUTT, NL /* Mut Excl, Spec Info, */ }; /* "TRUE" TEXT AND GADGET */ struct IntuiText postext = { BLKP, WHTP, JAM2, 6, 2, NL, (UBYTE *) "TRUE", NL }; #define TRUE_BUTT 2 struct Gadget ongad = { &offgad, 30, 46, /* LeftEdge, TopEdge */ 50, 11, /* Width, Height */ GADGHCOMP, /* Flag */ RELVERIFY | GADGIMMEDIATE, /* Activation */ BOOLGADGET | REQGADGET, /* GadgetType */ (APTR)&butt_border, /* GadgetRender - Border */ NULL, /* SelectRender */ &postext, /* "OK" text */ NL, NL, TRUE_BUTT, NL /* Mut Excl, Spec Info, */ }; /* Outside Border of Requester */ SHORT ReqPairs[] = { 5, 3, 247, 3, 247, 78, 5, 78, 5, 3 }; struct Border out_border = { -1, -1, BLKP, 0, JAM1, NUM_PAIRS, (SHORT *) ReqPairs, NULL }; /* Text structures for a regular SysRequest structure */ struct IntuiText text = { BLUP, WHTP, JAM2, 58, 5, NL, (UBYTE *) "Regular requestor", NL }; struct Requester req; /* Custom Requester structure */ /*************************************************************************** CUSTOM REQUEST IMAGE BOOLEAN GADGETS BIT IMAGES FOR THE IMAGE REQUESTER ***************************************************************************/ /** Image for the smiley face **/ UWORD smile[] = { 0x0000, 0x0000, 0x001f, 0xf100, 0x0060, 0x0600, 0x0180, 0x0180, 0x0218, 0x1840, 0x0424, 0x2420, 0x0418, 0x1820, 0x0800, 0x0010, 0x0801, 0x8010, 0x0801, 0x8010, 0x0803, 0xc010, 0x0800, 0x0010, 0x0420, 0x0420, 0x0418, 0x1820, 0x0207, 0xe040, 0x0180, 0x0180, 0x0060, 0x0600, 0x001f, 0xf800, 0x0000, 0x0000, 0x0000, 0x0000 }; struct Image smil_face = { 0, 0, /* Left, Top */ 32, 20, 1, /* Width, Height, Depth */ &smile[0], /* Pointer to data above */ 1, 0, /* PlanePick, PlaneOnOff */ NULL /* Next Image */ }; /** Image for the face with the tongue **/ UWORD tonge[] = { 0x0000, 0x0000, 0x001f, 0xf100, 0x0060, 0x0600, 0x0180, 0x0180, 0x0218, 0x1840, 0x0424, 0x2420, 0x0418, 0x1820, 0x0800, 0x0010, 0x0801, 0x8010, 0x0801, 0x8010, 0x0803, 0xc010, 0x0800, 0x0010, 0x040f, 0xf020, 0x0410, 0x0120, 0x0214, 0x2860, 0x018c, 0x3180, 0x0064, 0x2600, 0x001e, 0x7100, 0x0002, 0x6000, 0x0001, 0x8000 }; struct Image tong_face = { 0, 0, /* Left, Top */ 32, 20, 1, /* Width, Height, Depth */ &tonge[0], /* Pointer to data above */ 1, 0, /* PlanePick, PlaneOnOff */ NULL /* Next Image */ }; struct IntuiText gag_me = { BLKP, WHTP, JAM2, -1, 21, NL, (UBYTE *) "Click me", NL }; #define FACE 3 struct Gadget face_gad = { NULL, 30, 18, /* LeftEdge, TopEdge */ 32, 20, /* Width, Height */ GADGHIMAGE | GADGIMAGE | GADGHIMAGE, /* Flag */ RELVERIFY | GADGIMMEDIATE, /* Activation */ BOOLGADGET | REQGADGET, /* GadgetType */ (APTR)&smil_face, /* GadgetRender - Border */ (APTR)&tong_face, /* SelectRender */ &gag_me, /* "Gag me" */ NL, NL, FACE, NL /* Mut Excl, Spec Info, */ }; struct IntuiText stab_here = { BLUP, WHTP, JAM2, 6, 2, NL, (UBYTE *) "Stab here", NL }; /* Border to the button */ SHORT gag_pairs[] = { 0, 0, 80, 0, 80, 12, 0, 12, 0, 0 }; struct Border gag_border = { -1, -1, BLKP, WHTP, JAM1, NUM_PAIRS, (SHORT *) gag_pairs, NULL }; #define STAB_BUTT 4 struct Gadget stab = { &face_gad, 130, 20, /* LeftEdge, TopEdge */ 78, 11, /* Width, Height */ GADGHCOMP, /* Flag */ RELVERIFY | ENDGADGET, /* Activation */ BOOLGADGET | REQGADGET, /* GadgetType */ (APTR)&gag_border, /* GadgetRender - Border */ NULL, /* SelectRender */ &stab_here, /* "Stab me" */ NL, NL, STAB_BUTT, NL /* Mut Excl, Spec Info, */ }; /*** Text which goes in the main requester ***/ struct IntuiText imag_text = { BLUP, WHTP, JAM2, 38, 7, NL, (UBYTE *) "Gag me with the mouse", NL }; struct Requester gag; /*************************************************************************** * J O Y S T I C K G A D G E T ***************************************************************************/ /* Image for a custom proportional gadget */ UWORD joyimage[] = { 0x0000, 0x0000, 0x0180, 0x0660, 0x1818, 0x2004, 0x4002, 0x4002, 0x4002, 0x4002, 0x2004, 0x1818, 0x0660, 0x0180, 0x0000, 0x0000 }; struct Image joy_image = { 0, 0, /* LeftEdge, TopEdge */ 16, 16, 1, /* Width, Height, Depth */ &joyimage[0], /* Pointer to bit image */ 1, 0, /* PlanePick, Planeonoff */ NULL /* No other images */ }; struct PropInfo joy_prop = { FREEHORIZ | FREEVERT, /* Want knob to go both vert and horiz */ 0x8000, 0x8000, /* Want knob to be centered initially */ 0x800, 0x800, /* Smallest increment the knob can move */ 150, 50, /* cWidth, cHeight - Container w & h */ 1, 1, /* HPosres, VPotres - Pot increments */ 0, 0 /* Container borders */ }; #define CUST_KNOB 5 struct Gadget JoyGadget = { NL, 17, 140, 150, 50, GADGHCOMP, GADGIMMEDIATE | RELVERIFY, PROPGADGET, (APTR)&joy_image, NL, NL, NL, (APTR)&joy_prop, CUST_KNOB, NL }; /*************************************************************************** * N E W W I N D O W S T R U C T U R E ***************************************************************************/ struct NewWindow nw = { 0, 0, /* Start position */ 320, 200, /* width, height, depth */ 0, 1, /* detail, block pens */ CLOSEWINDOW /* IDCMP flags */ | REFRESHWINDOW | MOUSEBUTTONS | MENUPICK | REQCLEAR | GADGETDOWN | SELECTDOWN | SELECTUP, /* Regular flags for gadgets and such */ WINDOWDEPTH | WINDOWDRAG | REPORTMOUSE | WINDOWCLOSE | SMART_REFRESH, NULL, /* No gadgets for now */ NULL, /* User checkmark */ (UBYTE *) "Sprite Editor", /* Window Title */ NULL, /* Pointer to screen (Set later) */ NULL, /* Pointer to superbitmap */ 0, 0, 320, 186, /* Ignored because not sizeable */ WBENCHSCREEN, /* Using the Workbench screen */ }; /*************************************************************************** M A I N P R O G R A M M O D U L E ***************************************************************************/ VOID main() { ULONG class; /* Message class from Intuition */ USHORT code; /* Menu code info from Intuition */ /*************************************************************************** Read in the libraries, and set each "read" mask bit. ***************************************************************************/ if(!(GfxBase = (struct GfxBase *)OpenLibrary("graphics.library",0))) { (VOID) printf("no graphics library!!!\n"); close_things(); exit(1); } mask |= GRAPHICS; if(!(IntuitionBase = (struct IntuitionBase *) OpenLibrary("intuition.library",0))) { (VOID) printf("no intuition here!!\n"); close_things(); exit(2); } mask |= INTUITION; /*************************************************************************** OPEN UP THE WINDOW ON TOP OF WORKBENCH SCREEN ***************************************************************************/ if (!(w = (struct Window *)OpenWindow(&nw) )) { (VOID) printf("could not open the window\n"); close_things(); exit(3); } mask |= WINDOW; /*************************************************************************** CREATE THE THREE MENUS ***************************************************************************/ NewMenu( &fmenu, filemenu_names, file_items, file_names, NUM_FILE_ITEMS, item_widths[0], BOX_FILL); NewMenu( &win_menu, wind_names, win_items, win_text, NUM_WINDOWS, item_widths[1], BLACK_FILL); NewMenu( &req_menu, rqs_names, req_items, req_names, NUM_REQUESTS, item_widths[2], HAS_CHECKS); mask |= MENU; /*************************************************************************** INITIALIZATION CODE HERE ***************************************************************************/ (VOID) SetMenuStrip(w, &fmenu); /* Set up the menu here */ (VOID) InitRequester(&req); /* Init the requestor */ (VOID) InitRequester(&gag); /* Init Bit imaage requester */ rp = w->RPort; /* Init the fields in the Requester structure */ req.LeftEdge = 20; req.TopEdge = 20; req.Width = 250; req.Height = 80; req.ReqGadget = &ongad; /* First gadget */ req.ReqText = &text; /* Text for requester */ req.BackFill = 1; /* BackGnd color to window */ req.Flags = 0; req.ReqBorder = &out_border; /* Must have at least one */ /* Init the fields in the Bit Image structure */ gag.LeftEdge = 20; gag.TopEdge = 20; gag.Width = 250; gag.Height = 80; gag.ReqGadget = &stab; /* First gadget */ gag.ReqText = &imag_text; /* Text for requester */ gag.BackFill = 1; /* BackGnd color to window */ gag.Flags = 0; gag.ReqBorder = &out_border; /* Must have at least one */ /*************************************************************************** MAIN PROGRAM LOOP HERE ***************************************************************************/ for (;;) { if ((message = (struct IntuiMessage *)GetMsg(w->UserPort)) == 0L) { (VOID) Wait(1L<UserPort->mp_SigBit); continue; } class = message->Class; code = message->Code; (VOID) ReplyMsg(message); switch (class) { case CLOSEWINDOW : close_things(); exit(0); break; case MENUPICK : if (MENUNUM(code) != MENUNULL) domenu(MENUNUM(code), ITEMNUM(code)); break; case MOUSEBUTTONS: break; } /* Case */ } /* for */ } /* End of Main */ /*************************************************************************** C R E A T E A N E W M E N U ***************************************************************************/ static VOID NewMenu ( menu, item_names, menu_items, menu_text, num_items, Mwidth, flag) struct Menu *menu; /* Menu structure */ char *item_names[]; /* Pointer to array of item names */ struct MenuItem menu_items[]; /* pointer to array of structures */ struct IntuiText menu_text[]; /* Pointer to array of text structures */ int num_items; /* Number of items */ int Mwidth; /* Menu Width */ int flag; /* Special Item flag for ALL items */ { int i; int height = 0; for (i=0; i< num_items; i++) { menu_text[i] = generic; /* stamp generic template */ menu_text[i].IText = (UBYTE *) item_names[i]; /* mv string ptrs */ menu_items[i].NextItem = &menu_items[i+1]; /* Lnk to nxt item */ menu_items[i].TopEdge = 10 * i; /* Top rect of item */ menu_items[i].LeftEdge = 0; menu_items[i].Height = 8; menu_items[i].ItemFill = (APTR)&menu_text[i]; menu_items[i].Flags = flag; menu_items[i].Width = Mwidth; menu_items[i].MutualExclude = 0x0000; menu_items[i].Command = 0; menu_items[i].SubItem = NL; menu_items[i].NextSelect = NL; height += 10; } menu_items[num_items-1].NextItem = NULL; menu->Height = height; } /*************************************************************************** DO THE MENU SELECTIONS ***************************************************************************/ static VOID domenu(menu, item) USHORT menu, item; { switch (menu) { case FILE_MENU: switch (item) { case NEW_ITEM: (VOID) printf("Opening new file\n"); break; case OPEN_ITEM: (VOID) printf("Opening file\n"); break; case SAVE_ITEM: (VOID) printf("Saving file\n"); break; case SAVAS_ITEM: (VOID) printf("Saving as..\n"); break; case QUIT_ITEM: close_things(); exit(0); break; } break; case WIND_MENU: switch (item) { case INFO_ITEM: (VOID) printf("Information window\n"); break; case GRA_ITEM: (VOID) DrawImage (rp, &tong_face, 30L, 30L); (VOID) DrawImage (rp, &smil_face, 64L, 30L); break; } break; case REQS_MENU: switch (item) { case REQS1: auto_req ( "Here is an Auto requestor"); break; case REQS2: auto_req ( "And yet another one" ); break; case REQS3: auto_req ( "How about one more" ); break; case GAD_REQS: if (we_add) { (VOID) AddGadget(w, &JoyGadget, -1 ); (VOID) RefreshGadgets(&JoyGadget,w,NULL); we_add = FALSE; } break; case TEX_REQS: if (Request(&req, w) == 1) do_req(); break; case IMG_REQS: if (Request(&gag, w) == 1) do_req(); break; } break; } } /*************************************************************************** HANDLE AUTO-REQUESTS ***************************************************************************/ static VOID auto_req (textp) char *textp; /* Pointer to the text */ { int val; AutoText.IText = (UBYTE *) textp; /* Text pointer */ val = AutoRequest(w, &AutoText, &TRUEtext, &FALSEtext, 0L, 0L, 319L, 60L ); if (val) (VOID) printf("TRUE\n"); else (VOID) printf("FALSE\n"); } /*************************************************************************** D O C U S T O M R E Q U E S T ***************************************************************************/ static VOID do_req() { int looping = TRUE; struct IntuiMessage *mes; struct Gadget *gad; /* Gadget chosen */ ULONG class; while (looping) { if ((mes = (struct IntuiMessage *)GetMsg(w->UserPort)) == 0L) { (VOID) Wait(1L<UserPort->mp_SigBit); continue; } class = mes->Class; gad = (struct Gadget *)mes->IAddress; (VOID) ReplyMsg(mes); if (class == REQCLEAR) { looping = FALSE; } if (class == GADGETDOWN) { switch (gad->GadgetID) { case TRUE_BUTT: (VOID) printf("true button ...\n"); break; case FALSE_BUTT: (VOID) printf("false button...\n"); break; case FACE: (VOID) printf("Ouch!!..That hurt!!\n"); break; } } } } /*************************************************************************** C L O S E T H I N G S ***************************************************************************/ static VOID close_things() { if (mask & MENU) (VOID) ClearMenuStrip(w, &fmenu); if (mask & WINDOW) (VOID) CloseWindow(w); if (mask & GRAPHICS) (VOID) CloseLibrary((VOID *)GfxBase); (VOID) OpenWorkBench(); if (mask & INTUITION) (VOID) CloseLibrary((VOID *)IntuitionBase); } /*************************************************************************** DIAGNOSTIC DUMP ROUTINE ***************************************************************************/ #ifdef DEADCODE /* Currently not used for anything */ #define BPL 16 static VOID dump(adr,len) long adr, len; { unsigned char *strtchr,*endchr,*cnt; endchr = (unsigned char *) (adr + len -1); for (strtchr = (unsigned char *) adr; strtchr <= endchr; strtchr += BPL) { (VOID) printf("%06lx: ",(long) strtchr); for (cnt = strtchr; cnt < strtchr + BPL; cnt++) (VOID) printf(" %02x",(int) *cnt); (VOID) printf(" "); for (cnt = strtchr; cnt < strtchr + BPL; cnt++) if ((*cnt & 0x7f) < 32) (VOID) printf("."); else (VOID) printf("%c", *cnt); (VOID) printf("\n"); } } #endif /* DEADCODE */