/* ======================================================================== *
                      example2.c - Using GadTools menus
                                   By Talin.
 * ======================================================================== */

#include <exec/types.h>
#include <exec/memory.h>
#include <exec/libraries.h>
#include <graphics/gfxmacros.h>
#include <graphics/gfxbase.h>
#include <intuition/intuition.h>
#include <libraries/gadtools.h>

    /* this include file is my special file which includes all prototypes
        and pragmas -- replace with whatever is appropriate in your environment.
    */

#include <functions20.h>

/* =============== These are a few of my favorite macros ================= */

#define LEAVE           goto exitit
#define unless(test)    if (!(test))

    /* declare the library bases. Most are declared simply as Library
        structures, by we need to look in GfxBase so we declare that
        as what it really is.
    */

struct Library          *IntuitionBase=NULL,
                        *GadToolsBase=NULL;
struct GfxBase          *GfxBase=NULL;

    /* some pointers we will use */

struct Screen           *screen;            /* pointer to WorkBench screen  */
struct Window           *Window=NULL;       /* pointer to our window        */
struct RastPort         *rp;                /* our window's rast port       */

    /* define what the window is going to look like */

struct NewWindow new_window =
{   0,0,320,115,                            /* window size                  */
    0,1,                                    /* DetailPen and BlockPen       */
    MENUPICK | CLOSEWINDOW,                 /* IDCMP flags                  */
    NOCAREREFRESH|ACTIVATE|SMART_REFRESH|   /* other flags                  */
        WINDOWDRAG|WINDOWDEPTH|WINDOWCLOSE,
    NULL,NULL,"GadTools Menu Demo",NULL,NULL,
    320,200,320,200,                        /* Window Limits                */
    CUSTOMSCREEN,                           /* FORCE it to WorkBench        */
};

    /* Next we are going to define the array of NewMenu structures. However,
        since each menu is going to point to a function, then we have to
        declare all the functions first.
    */

int do_new(void),       do_quit(void),      do_open(void),  do_save(void),
    do_saveas(void),    do_revert(void),    do_print(void), do_info(void), 
    do_undo(void),      do_add(void),       do_delete(void),do_erase(void),
    do_copy(void),      do_cut(void),       do_paste(void), do_prev(void),
    do_next(void),      do_first(void),     do_last(void),  do_find(void),
    do_findnext(void),  do_findprev(void);

struct NewMenu doc_menus[] = {
    { NM_TITLE, "Project",      NULL,   NULL,   0L              },
    { NM_ITEM,  "New",          "N",    NULL,   0L, do_new      },
    { NM_ITEM,  "Open...",      "O",    NULL,   0L, do_open     },
    { NM_ITEM,  NM_BARLABEL,    NULL,   NULL,   0L              },
    { NM_ITEM,  "Save",         "S",    NULL,   0L, do_save     },
    { NM_ITEM,  "Save As...",   "A",    NULL,   0L, do_saveas   },
    { NM_ITEM,  "Revert...",    NULL,   NULL,   0L, do_revert   },
    { NM_ITEM,  NM_BARLABEL,    NULL,   NULL,   0L              },
    { NM_ITEM,  "Print...",     "P",    NULL,   0L, do_print    },
    { NM_ITEM,  "Program Info...",NULL, NULL,   0L, do_info     },
    { NM_ITEM,  "Quit",         "Q",    NULL,   0L, do_quit     },
    { NM_TITLE, "Edit",         NULL,   NULL,   0L              },
    { NM_ITEM,  "Undo",         "Z",    NULL,   0L, do_undo     },
    { NM_ITEM,  NM_BARLABEL,    NULL,   NULL,   0L              },
    { NM_ITEM,  "Cut",          "X",    NULL,   0L, do_cut      },
    { NM_ITEM,  "Copy",         "C",    NULL,   0L, do_copy     },
    { NM_ITEM,  "Paste",        "V",    NULL,   0L, do_paste    },
    { NM_ITEM,  "Erase",        "D",    NULL,   0L, do_erase    },
    { NM_ITEM,  NM_BARLABEL,    NULL,   NULL,   0L              },
    { NM_ITEM,  "Add Record",   "R",    NULL,   0L, do_add      },
    { NM_ITEM,  "Delete Record","K",    NULL,   0L, do_delete   },
    { NM_TITLE, "Move",          NULL,  NULL,   0L              },
    { NM_ITEM,  "Prev Record",  ";",    NULL,   0L, do_prev     },
    { NM_ITEM,  "Next Record",  "'",    NULL,   0L, do_next     },
    { NM_ITEM,  "First Record", "<",    NULL,   0L, do_first    },
    { NM_ITEM,  "Last Record",  ">",    NULL,   0L, do_last     },
    { NM_ITEM,  NM_BARLABEL,    NULL,   NULL,   0L              },
    { NM_ITEM,  "Find...",      "F",    NULL,   0L, do_find     },
    { NM_ITEM,  "Find Next",    "]",    NULL,   0L, do_findnext },
    { NM_ITEM,"Find Previous",  "[",    NULL,   0L, do_findprev },
    { NM_END }
};

    /* taglist used for GetVisualInfo */

struct TagItem null_tags[] = {
    TAG_END,        NULL
};

    /* taglist used for menu creation */

struct TagItem menu_tags[] = {
    GTMN_FrontPen,  2,                      /* which pen color to use       */
    TAG_END,        NULL
};

struct Menu             *main_menus;        /* pointer to created menus     */
struct VisualInfo       *vi;                /* visual info for gadtools     */
int                     quit_flag = FALSE;  /* set TRUE to quit             */

main(int argc, char **argv)
{
        /* open the libraries. If gadtools is not present, just return don't
            even bother to clean up, because the cleanup code won't work
            under 1.3.
        */

    unless (GadToolsBase = OpenLibrary("gadtools.library",0L)) return 0L;
    unless (IntuitionBase = OpenLibrary("intuition.library",0)) LEAVE;
    unless (GfxBase = (struct GfxBase *)OpenLibrary("graphics.library",0)) LEAVE;

        /* lock the default public screen and get the visual info so
            that gadtools will know what the font and colors are.
        */

    unless (screen = LockPubScreen(NULL)) LEAVE;
    unless (vi = GetVisualInfoA(screen,null_tags)) LEAVE;

        /* open the window on that screen, and then unlock it. It's best to
            unlock as soon as possible.
        */

    new_window.Screen = screen;
    unless (Window = OpenWindow(&new_window)) LEAVE;
    UnlockPubScreen(NULL,screen);           /* once window is open          */
    screen = NULL;                          /*  lock on screen isn't needed */

    rp = Window->RPort;

        /* create the menus and then lay them out. */

    unless (main_menus = CreateMenusA(doc_menus,menu_tags)) LEAVE;
    unless (LayoutMenusA(main_menus,vi,null_tags)) LEAVE;
    SetMenuStrip(Window,main_menus);

        /* main loop */

    while (!quit_flag)
    {   ULONG           class;              /* message class                */
        USHORT          code;               /* message subclass             */
        struct IntuiMessage *message;       /* pointer to message           */
        struct Window   *msg_window;        /* the window that msg is from  */

            /* wait for the message port signal */

        Wait(1 << Window->UserPort->mp_SigBit);

            /* get the messages */

        while (message = (struct IntuiMessage *)GetMsg(Window->UserPort))
        {   class = message->Class;
            code = message->Code;
            msg_window = message->IDCMPWindow;
            ReplyMsg(&message->ExecMessage);    /* makes ANSI happy :-)     */

            switch (class) {
            case MENUPICK:

                    /* here's how we handle the NextSelect chain */

                while (code != MENUNULL)
                {   struct MenuItem *menuitem;

                        /* get the menu address */

                    if (menuitem = ItemAddress(msg_window->MenuStrip,code))
                    {   void (*userfunc)(void);

                            /* get the function pointer using the supplied
                                macro from libraries/gadtools.h and call
                                the function.
                            */

                        if (userfunc = GTMENUITEM_USERDATA(menuitem))
                        {   (userfunc)();
                        }
                        code = menuitem->NextSelect;
                    }
                    else break;
                }
                break;

            case CLOSEWINDOW:
                quit_flag = TRUE;
                break;
            }
        }
    }
exitit:

        /* clean up everything */

    if (Window) { ClearMenuStrip(Window); CloseWindow(Window); }
    if (screen) UnlockPubScreen(NULL,screen);
    if (main_menus) FreeMenus(main_menus);
    if (vi) FreeVisualInfo(vi);
    CloseLibrary(GadToolsBase);             /* note no check -- unsafe under 1.3 */
    CloseLibrary((struct Library *)GfxBase);
    CloseLibrary(IntuitionBase);
}

/* ========================= Dispatch Functions ============================= */

    /*  These functions are called whever a menu is hit (and could be called
            by actions other than a menu hit, such as a keyboard sequence or
            an ARexx message coming in from an ARexx port.
        For the demo, the functions simply print the name of the function,
            except for quit which actualyy quits the program.
    */

do_quit(void)   {   quit_flag = TRUE; }
do_new(void)    {   printf("New\n"); }
do_next(void)   {   printf("Next\n"); }
do_prev(void)   {   printf("Previous\n"); }
do_first(void)  {   printf("First\n"); }
do_last(void)   {   printf("Last\n"); }
do_add(void)    {   printf("Add\n"); }
do_delete(void) {   printf("Delete\n"); }
do_paste(void)  {   printf("Paste\n"); }
do_copy(void)   {   printf("Copy\n"); }
do_cut(void)    {   printf("Cut\n"); }
do_erase(void)  {   printf("Erase\n"); }
do_undo(void)   {   printf("Undo\n"); }
do_open()       {   printf("Open\n"); }
do_revert()     {   printf("Revert\n"); }
do_save(void)   {   printf("Save\n"); }
do_saveas(void) {   printf("Save As\n"); }
do_print()      {   printf("Print\n"); }
do_info()       {   printf("Info\n"); }
do_find(void)   {   printf("Find\n"); }
do_findnext(void) { printf("Find Next\n"); }
do_findprev(void) { printf("FindPrev\n"); }

