/*-*-C-*-
 * Colour menu processing for Misc CSE
 */

#include "resed.h"
#include "main.h"

#include "swicall.h"
#include "wimp.h"

#include "menu.h"

#include "colours.h"
#include "gui.h"



char *noneval = NULL;           /* msgtrns'd "Transparent" */
int uncolour[16];      /* which colour to use on which coloured background */

typedef struct
{
    WindowPtr dbox;
    int icon;
} ColClosRec, *ColClosPtr;

static MenuPtr coloursmenu = NULL;
static MenuPtr coloursplusmenu = NULL;
static ColClosRec colourclosure;  /* used to pass information to the colour
                                     menu callback fuction */



/*
 * Look at the palette, and decide which contrasting colours
 * to use for menu entries.  Store in uncolour[].
 */

static void set_uncolours ()
{
    unsigned int pal[20];
    int bright[16], c, d;

    if (swi (Wimp_ReadPalette,  R1, &pal,  END))
        return;
    
    for (c = 0; c < 16; c++)
    {
        int b = (pal[c] & 0xff000000) >> 24;
        int g = (pal[c] & 0x00ff0000) >> 16;
        int r = (pal[c] & 0x0000ff00) >>  8;
        bright[c] = r + g + g + b;
    }

    for (c = 0; c < 16; c++)
    {
        int maxe = -1, maxd;
        for (d = 0; d < 16; d++)
        {
            int e = abs (bright[d] - bright[c]);
            if (e > maxe)
            {
                maxe = e;
                maxd = d;
            }
        }
        uncolour[c] = maxd;
    }
}


/*
 * The two colour menus are created here; called from main.c during
 *  initialisation.
 */

error * colours_create_menus (void)

{
    int i;
    char *s;

    /* determine string to be used for "none" menu entry */
    s = message_lookup (&msgs, "None");
    noneval = malloc (strlen(s)+1);
    if (noneval == NULL)
        return error_lookup ("NoMem");
    strcpy (noneval, s);

    /* set up the "uncolour" array which defines contrasting colours */
    set_uncolours ();

    /* create the menus, setting appropriate foreground and background
       colours for each menu item */
    ER ( menu_create (16, message_lookup(&msgs, "Colour"),
                          &coloursmenu) );
    ER ( menu_create (17, message_lookup(&msgs, "Colour"),
                          &coloursplusmenu) );
    for (i = 0; i < 16; i++)
    {
        char colour[3];
        sprintf(colour, "%d", i);
        ER ( menu_entry (coloursmenu, i, colour,
                                         0, 0, -1, -1, NULL) );
        ER ( menu_alter_entry (coloursmenu, i, 0, 0, uncolour[i], i) );
        ER ( menu_entry (coloursplusmenu, i, colour,
                                         0, 0, -1, -1, NULL) );
        ER ( menu_alter_entry (coloursplusmenu, i,
                                         0, 0, uncolour[i], i) );
    } 
    ER ( menu_entry (coloursplusmenu, 16, noneval,
                                         0, 0, -1, -1, NULL) );

    /* register menus - for interactive help */
    ER ( menu_register (coloursmenu, COLOUR_MENU) );
    ER ( menu_register (coloursplusmenu, COLOUR_MENU) );

    /* use colour 0 for transparency */
    return menu_alter_entry (coloursplusmenu, 16, 0, 0, uncolour[0], 0);
}


/*
 * Colours pop-up menu callback function
 */

static error * coloursmenu_cb (MenuPtr menu, int *choice, void *closure,
                               Bool reopen)
{
    WindowPtr dbox = ((ColClosPtr) closure)->dbox;
    int icon = ((ColClosPtr) closure)->icon;

    if (choice != NULL && *choice >= 0)
    {
        gui_put_colour (dbox, icon, *choice);

        if (reopen)
            menu_tick_menu (menu, *choice);
    }

    return NULL;
}


/*
 * This function uses a colours menu to choose a colour.
 *
 * It is called from object_cm_colour(..) to choose an initial colour for a
 *  colour menu object.
 */

error * colours_choose (
    WindowPtr dbox,         /* the dialogue box containing ... */
    int icon,               /*  ... the display icon for the chosen colour */
    Bool allownone,         /* TRUE iff 'none' is an option */
    int menuicon            /* menu is to be displayed next to this icon */
)
{
    MenuPtr menu = allownone ? coloursplusmenu : coloursmenu;
    PointRec position;

    /* determine position to display menu */
    {
        IconStateRec state;

        state.windowhandle = dbox->handle;
        state.iconhandle = menuicon;

        ER ( swi (Wimp_GetIconState, R1, &state, END) );

        position.x = state.icon.bbox.maxx;
        position.y = state.icon.bbox.maxy;
        wimp_convert_point (WorkToScreen, dbox, &position, &position);
        position.x += 64;    /* because menu_post will subtract 64 */
    }

    /* tick appropriate menu item */
    {
        int item = gui_get_colour (dbox, icon);

        if (item == 0xff)   /* none is the 16th entry on the menu */
            item = 16;
        menu_tick_menu (menu, item);
    }

    /* post the menu */
    colourclosure.dbox = dbox;
    colourclosure.icon = icon;
    menu_post (menu, &position, FALSE,
                     coloursmenu_cb, (void *) &colourclosure);

    return NULL;
}
