/*
 * pin_menu.c -
 *  Demonstrate how to generate your own pinup menu.
 *  Use of MENU_GEN_PIN_WINDOW is for static menus only.
 *  This demo uses menus whose items may change, so we
 *  need to reflect those changes in our own command frame.
 */
#include <xview/xview.h>
#include <xview/canvas.h>
#include <xview/panel.h>

Frame   frame;

/*
 * main -
 *  Create a frame, canvas and menu.
 *  A canvas receives input in its canvas_paint_window().
 *  Specify creation of an Open Look Menu and transformation of
 *  the menu to a pinned command window.
 *  Each menu item specifies an action proc to be called when the
 *  item is chosen, regardless of whether or not menu is pinned.
 */
main(argc, argv)
int argc;
char    *argv[];
{
    Canvas  canvas;
    Menu    menu;
    int     my_notify_proc();
    void    my_event_proc(), my_menu_done();
    extern void exit();

    xv_init(XV_INIT_ARGC_PTR_ARGV, &argc, argv, NULL);

    frame = (Frame)xv_create(NULL, FRAME,
                             FRAME_LABEL,    argv[0],
                             NULL);
    canvas = (Canvas)xv_create(frame, CANVAS,
                               XV_WIDTH,   300,
                               XV_HEIGHT,  200,
                               NULL);
    menu = (Menu)xv_create(NULL, MENU,
                           MENU_GEN_PIN_WINDOW,    frame, "Junk",
                           MENU_DONE_PROC,     my_menu_done,
                           /*
                           MENU_STRINGS,       "Yes", "No", "Maybe", NULL,
                           MENU_NOTIFY_PROC,   my_notify_proc,
                           */
                           MENU_ITEM, MENU_STRING, "No", MENU_NOTIFY_PROC, my_notify_proc, NULL,
                           MENU_ITEM, MENU_STRING, "Yes", MENU_NOTIFY_PROC, my_notify_proc, NULL,
                           MENU_ITEM, MENU_STRING, "Maybe", MENU_NOTIFY_PROC, my_notify_proc, NULL,
                           MENU_ITEM,
                           MENU_STRING,    "Save",
                           MENU_NOTIFY_PROC,   my_notify_proc,
                           MENU_PULLRIGHT,
                           xv_create(canvas, MENU,
                                     MENU_ITEM,
                                     MENU_STRING,        "Update Changes",
                                     MENU_NOTIFY_PROC,   my_notify_proc,
                                     NULL,
                                     NULL),
                           NULL,
                           MENU_ITEM,
                           MENU_STRING,    "Quit",
                           MENU_NOTIFY_PROC,   exit,
                           NULL,
                           NULL);

    xv_set(canvas_paint_window(canvas),
           WIN_CONSUME_EVENTS, WIN_MOUSE_BUTTONS, NULL,
           WIN_EVENT_PROC,     my_event_proc,
           /* associate the menu to the canvas win so we can retreive it easily */
           WIN_CLIENT_DATA,    menu,
           NULL);

    window_fit(frame);
    window_main_loop(frame);
}

/*
 * my_menu_done - menu has been popped-down.  Make sure the command frame panel
 * matches the menu.
 */
void
my_menu_done(menu, result)
Menu menu;
Xv_opaque result;
{
    int default_item, i;
    Frame pin_frame;
    Panel panel;
    Panel_item pi;

    printf("result = %x\n", result);

    if(!(pin_frame = (Frame)xv_get(menu, MENU_PIN_WINDOW)))
    {
        puts("menu has no pin frame");
        return;
    }

    panel = (Panel)xv_get(pin_frame, FRAME_CMD_PANEL);
    /* get the ordinal number of the default menu item */
    default_item = (int)xv_get(menu, MENU_DEFAULT);

    /* search for the <default>-th item in the panel and... */
    pi = (Panel_item)xv_get(panel, PANEL_FIRST_ITEM);

    for(i = 1 /*menu items offset at 1*/; i < default_item && pi; i++)
        pi = (Panel_item)xv_get(pi, PANEL_NEXT_ITEM);

    /* set that panel item to be the default item */
    xv_set(panel, PANEL_DEFAULT_ITEM, pi, NULL);
}

/*
 * my_notify_proc - Display menu selection in frame header.
 */
/*ARGSUSED*/
int
my_notify_proc(menu, menu_item)
Menu menu;
Menu_item menu_item;
{
    xv_set(frame,
           FRAME_LABEL,    xv_get(menu_item, MENU_STRING),
           NULL);
    return (XV_OK);
}

/*
 * my_event_proc - Call menu_show() to display menu on right mouse button push.
 */
void
my_event_proc(window, event)
Xv_Window window;
Event *event;
{
    if(event_action(event) == ACTION_MENU && event_is_down(event))
    {
        Menu menu = (Menu)xv_get(window, WIN_CLIENT_DATA);

        if(!xv_get(menu, MENU_PIN_WINDOW))
            create_pin_win(menu);

        menu_show(menu, window, event, NULL);
    }
}

#define MENU_KEY    100
#define MENU_ITEM_KEY   101
#define ACTION_KEY  102

#define nullstr "(null)"

create_pin_win(menu)
Menu menu;
{
    int i;
    void pin_btn_notify();
    Frame cmd_frame = (Frame)xv_create(frame, FRAME_CMD, XV_SHOW, FALSE, NULL);
    Panel panel = (Panel)xv_get(cmd_frame, FRAME_CMD_PANEL);
    Menu_item mi;
    char *ms;

    xv_set(panel, PANEL_LAYOUT, PANEL_VERTICAL, 0);
    printf("frame = %x, panel = %x\n", cmd_frame, panel);

    for(i = (int)xv_get(menu, MENU_NITEMS); i > 0; i--)
    {
        mi = (Menu_item)xv_get(menu, MENU_NTH_ITEM, i);

        if((ms = (char *)xv_get(mi, MENU_STRING)) == 0)
            ms = nullstr;

        printf("adding panel item: %s\n", ms);
        xv_create(panel, PANEL_BUTTON,
                  /* PANEL_MENU_ITEM,     TRUE, */
                  PANEL_LABEL_STRING,     xv_get(mi, MENU_STRING),
                  PANEL_NOTIFY_PROC,      pin_btn_notify,
                  XV_KEY_DATA, MENU_KEY,  menu,
                  XV_KEY_DATA, MENU_ITEM_KEY, mi,
                  XV_KEY_DATA, ACTION_KEY,    xv_get(mi, MENU_NOTIFY_PROC),
                  NULL);
    }

    window_fit(panel);
    window_fit(cmd_frame);
    xv_set(menu, MENU_PIN_WINDOW, cmd_frame, NULL);
}

/*ARGSUSED*/
void
pin_btn_notify(item, event)
Panel_item item;
Event *event;
{
    Menu    menu = (Menu)xv_get(item, XV_KEY_DATA, MENU_KEY);
    Menu_item   mi = (Menu)xv_get(item, XV_KEY_DATA, MENU_ITEM_KEY);
    void (*action)() = (void (*)())xv_get(item, XV_KEY_DATA, ACTION_KEY);

    (*action)(menu, mi);
}
