Programming AmigaOS in C

22. Processing Menus

The following example, adds processing of menus, its different from the previous example, as the menus have been defined so that they are correctly numbered. Menus are always numbered from zero onwards, so the first menu (File) is 0, Open is 0, Save is 1, Print is 2 and Quit is 3. The menu number is retrieved from the IntuiMessage Code value and split into menu, item and subitem using the MENUNUM, ITEMNUM and SUBNUM functions. For a Window to detect menu events, the IDCMP_MENUPICK flag has to be added to the Window's properties and checked for in the main program code. I have also added the PrintIText command which allows you to write text to the window (normal printf type statements will only print to a console, not a window).

/* Menu Example 2 */

#include <proto/intuition.h>
#include <proto/gadtools.h>
#include <proto/exec.h>
#include <proto/dos.h>
#include <intuition/intuition.h>
#include <stdio.h>
#include <string.h>

/* Menu definition */

struct IntuiText text1 =
{ 0, 1, JAM2, 4, 2, NULL, "Open", NULL };
struct IntuiText text2 =
{ 0, 1, JAM2, 4, 2, NULL, "Save", NULL };
struct IntuiText text3 =
{ 0, 1, JAM2, 4, 2, NULL, "Print", NULL };
struct IntuiText text4 =
{ 0, 1, JAM2, 4, 2, NULL, "Quit", NULL };

struct MenuItem item4 =
{ NULL, 0, 36, 48, 12, ITEMTEXT|ITEMENABLED|HIGHCOMP, 0, &text4, &text4, NULL, NULL, 0 };
struct MenuItem item3 =
{ &item4, 0, 24, 48, 12, ITEMTEXT|ITEMENABLED|HIGHCOMP, 0, &text3, &text3, NULL, NULL, 0 };
struct MenuItem item2 =
{ &item3, 0, 12, 48, 12, ITEMTEXT|ITEMENABLED|HIGHCOMP, 0, &text2, &text2, NULL, NULL, 0 };
struct MenuItem item1 =
{ &item2, 0, 0, 48, 12, ITEMTEXT|ITEMENABLED|HIGHCOMP, 0, &text1, &text1, NULL, NULL, 0 };

struct Menu menu1 =
{ NULL, 0, 0, 48, 12, MENUENABLED, "File", &item1, 0, 0, 0, 0 };

/* For printing in Window */
UBYTE result[255];

struct IntuiText WinText =
{1, 0, JAM1, 0, 0, NULL, &result[0], NULL};

/* Main program */
int main() {
   struct Window *myWindow;
   int closewin = FALSE;
   struct IntuiMessage *msg;
   UWORD menuNumber, menuNum, itemNum, subNum;
   ULONG msgClass, line=12;

   myWindow = OpenWindowTags(NULL,
      WA_Left, 20, WA_Top, 20,
      WA_Width, 300, WA_Height, 200,
      WA_IDCMP, IDCMP_CLOSEWINDOW | IDCMP_MENUPICK, /* Test for menus */
      WA_Flags, WFLG_SIZEGADGET | WFLG_DRAGBAR | WFLG_DEPTHGADGET | WFLG_CLOSEGADGET | WFLG_ACTIVATE,
      WA_Title, "My Window",
      WA_PubScreenName, "Workbench",
      TAG_DONE);

   /* Attach menu to window */
   SetMenuStrip (myWindow, &menu1);

   while (closewin == FALSE) {
      Wait(1L << myWindow->UserPort->mp_SigBit);
      msg = GT_GetIMsg(myWindow->UserPort);
      msgClass = msg->Class;
      menuNumber = msg->Code; /* Get menu number */
      GT_ReplyIMsg(msg);

      switch (msgClass) {
         case IDCMP_CLOSEWINDOW: /* Close window? */
               closewin = TRUE;
               break;
          case IDCMP_MENUPICK: /* Menu selected? */
               menuNum = MENUNUM(menuNumber); /* Split code into menus, items, subitems */
               itemNum = ITEMNUM(menuNumber);
               subNum = SUBNUM(menuNumber);
               /* Print selection in window */
               sprintf(result, "Menu %d Item %d", menuNum, itemNum);
               PrintIText(myWindow->RPort, &WinText, 5, line);
               line += 10; /* Next line */
               if (menuNum == 0 && itemNum == 3) /* Test for quit */
                   closewin = TRUE;
               break;

        }
   }
   Delay(50);
   ClearMenuStrip(myWindow); /* remove menu */
   CloseWindow(myWindow);
   return(0);
}

Note that the text and menuitems have been re-ordered so that the menu numbers go up in value as you go down them. The IDCMP_MENUPICK has been added to the OpenWindowTags function so that in the while loop it can be detected by IntuiMessages. The if statement has been replaced with a standard switch statement. The menuNumber is retrieved from the msg->Code value, which is a combination of the menu, item and subitems and is split later. When a menu item is picked, the program will get the menu numbers and print it out on the screen using combination of sprintf to format the string and PrintIText to print it out using the result string buffer an WinText IntuiText structure (defined before the main program). The program then checks to see if the Quit option is selected, if so, the closewin flag is set to True and the while loop exists, a slight delay is given before the menu is removed, window closed and the program ends.

If programming more complex menus, then the menu processing could be done in another function and then other functions called to do the other processes such as Open, Save and Print, for example.

23. Printing Text in Windows

In C, you would normally use the standard I/O functions such as printf() to print text to the console. For intuition and printing in Windows, this will not work. Instead the PrintIText statement can be used to print text in Intuition Windows. The format of the command is:

void PrintIText(struct RaspPort *rp, struct IntuiText *i, long x, long y)

where the Rastport is a pointer to the Window's RaspPort (the writable area within the window's borders), a pointer to an IntuiText structure (you cannot just use a string constant here) and the horizontal and vertical position in the window. The RastPort can be retreived by a pointer from the Window structure e.g. myWindow->RPort. The IntuiText structure needs to be set up for formatting text, and can contain a pointer to a string buffer where the output is placed. If printing strings and numbers, use the sprintf function to make it easier to format the output. Finally, provide the x and y values to place the text on screen. Note that the window title can be overwritten if using low values (<12), so take that into consideration. If you wish to print lines, one after the other, use a y counter to count number of pixels to move to place text under one another (see menu example above). When using this function, make sure that you consider the size of the font used, by default topaz 8 is used. If using different sized fonts, you need to modify your program to take different font sizes into account.

Next page