/*-*-C-*-
 * General dialogue box processing for Misc CSE
 */

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

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

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


/*
 * Checks to see whether a length field is exactly the right size for its
 *  corresponding string field.
 *
 * This is called when loading an object, and sets the length field to -1 if
 *  an exact* match is found; this value is then displayed as "*" in the
 *  properties dbox.
 *
 *    [* or if the length field is found to be too small - eg after import]
 */

void gui_load_len_field (char *val, int *len)
{
    if (val == NULL && *len == 0 || *len <= strlen(val) + 1)
        *len = -1;

    return;
}


/*
 * Replaces any "-1" length value by one plus the length of the associated
 *  string (or by 0 if the string is NULL).
 *
 * This is called when saving an object.
 */

void gui_save_len_field (char *val, int *len)
{
    if (*len == -1)
        *len = (val == NULL) ? 0 : strlen(val) + 1;

    return;
}


/*
 * Fill in the option, text and length fields in a dialogue box for a string
 * value which may be NULL.
 *
 * If the value is NULL, the option icon is deselected and the writable icon
 *  for the value is faded.
 */

error * gui_put_len_opt_str (
    WindowPtr dbox,       /* the dialogue box */
    int opticon,          /* the option icon */
    int valicon,          /* the writable icon to contain the text value */
    int lenicon,          /* the writable icon to contain the length value */
    char *val,            /* the text value - might be NULL */
    int len               /* the length value */
)
{
    Bool isnull = (val == NULL);

    dbox_setbutton (dbox, opticon, !isnull);
    dbox_shade (dbox, valicon, isnull);
    dbox_setstring (dbox, valicon, isnull ? "" : val);
    if (len == -1)
        dbox_setstring(dbox, lenicon, "*");
    else
        dbox_setint (dbox, lenicon, len);

    return NULL;
}


/*
 * Retrieve a string value and its length from option, text and length fields
 *  in a dialogue box.
 *
 * If the option icon is deselected, a NULL value is retrieved.
 *
 * If the option icon is selected, the length retrieved will be the greater
 *  of the value in the length field, or one more than the length of the
 *  string in the value field.
 *
 * Space for any new string value is malloc'd - and space occupied by any
 *  previous value is free'd.
 */

error * gui_get_len_opt_str (
    WindowPtr dbox,       /* the dialogue box */
    int opticon,          /* the option icon */
    int valicon,          /* the writable icon containing the text value */
    int lenicon,          /* the writable icon containing the length value */
    char **val,           /* to hold the retrieved text value - maybe NULL */
    int *len              /* to hold the retrieved length value */
)
{
    Bool isnull = !dbox_getbutton (dbox, opticon);
    char *ls = dbox_getstring(dbox, lenicon);
    int max = (*ls == '*') ? -1 : dbox_getint (dbox, lenicon);

    free (*val);

    if (isnull)
        *val = NULL;
    else
    {
        char *s = dbox_getstring (dbox, valicon);
        int n = strlen (s) + 1;

        if (max >= 0 && max < n)
            max = n;

        *val = malloc (n);
        if (*val == NULL)
            return error_lookup ("NoMem");
        strcpy (*val, s);
    }
    *len = max;

    return NULL;
}


/*
 * Fill in the option and text fields in a dialogue box for a string value
 *  which may be NULL, but which has no explicit length.
 *
 * If the value is NULL, the option icon is deselected and the writable icon
 *  for the value is faded.
 */

error * gui_put_opt_str (
    WindowPtr dbox,       /* the dialogue box */
    int opticon,          /* the option icon */
    int valicon,          /* the writable icon to contain the text value */
    char *val             /* the text value - might be NULL */
)
{
    Bool isnull = (val == NULL);

    dbox_setbutton (dbox, opticon, !isnull);
    dbox_shade (dbox, valicon, isnull);
    dbox_setstring (dbox, valicon, isnull ? "" : val);

    return NULL;
}


/*
 * Retrieve a string value from option and text fields in a dialogue box.
 *
 * If the option icon is deselected, a NULL value is retrieved.
 *
 * Space for any new string value is malloc'd - and space occupied by any
 *  previous value is free'd.
 */

error * gui_get_opt_str (
    WindowPtr dbox,       /* the dialogue box */
    int opticon,          /* the option icon */
    int valicon,          /* the writable icon containing the text value */
    char **val            /* to hold the retrieved text value - maybe NULL */
)
{
    Bool isnull = !dbox_getbutton (dbox, opticon);

    free (*val);

    if (isnull)
        *val = NULL;
    else
    {
        char *s = dbox_getstring (dbox, valicon);
        int n = strlen (s) + 1;

        *val = malloc (n);
        if (*val == NULL)
            return error_lookup ("NoMem");
        strcpy (*val, s);
    }

    return NULL;
}


/*
 * Fill in the text and length fields in a dialogue box for a mandatory
 *  string.
 *
 * A NULL value is interpreted as the empty string.
 */

error * gui_put_len_str (
    WindowPtr dbox,       /* the dialogue box */
    int valicon,          /* the writable icon to contain the text value */
    int lenicon,          /* the writable icon to contain the length value */
    char *val,            /* the text value - might be NULL */
    int len               /* the length value */
)
{
    dbox_setstring (dbox, valicon, (val == NULL) ? "" : val);

    if (len == -1)
        dbox_setstring(dbox, lenicon, "*");
    else
        dbox_setint (dbox, lenicon, len);

    return NULL;
}


/*
 * Retrieve a mandatory string value and its length from text and length
 *  fields in a dialogue box.
 *
 * If the value field contains the empty string, then a NULL value is
 *  retrieved.
 *
 * The length retrieved will be the greater of the value in the length field,
 *  or one more than the length of the string in the value field.
 *
 * Space for any new string value is malloc'd - and space occupied by any
 *  previous value is free'd.
 */

error * gui_get_len_str (
    WindowPtr dbox,       /* the dialogue box */
    int valicon,          /* the writable icon containing the text value */
    int lenicon,          /* the writable icon containing the length value */
    char **val,           /* to hold the retrieved text value - maybe NULL */
    int *len              /* to hold the retrieved length value */
)
{
    char *s = dbox_getstring (dbox, valicon);
    int n = strlen (s) + 1;
    char *ls = dbox_getstring(dbox, lenicon);
    int max = (*ls == '*') ? -1 : dbox_getint (dbox, lenicon);

    if (max >= 0 && max < n)
        max = n;

    free (*val);

    if (n == 1)       /* string is empty */
        *val = NULL;
    else
    {

        *val = malloc (n);
        if (*val == NULL)
            return error_lookup ("NoMem");
        strcpy (*val, s);
    }

    *len = max;

    return NULL;
}


/*
 * Fill in the text field in a dialogue box for a mandatory string value.
 *
 * If the value is NULL, the text field is filled with the empty string.
 */

error * gui_put_str (
    WindowPtr dbox,       /* the dialogue box */
    int valicon,          /* the writable icon to contain the text value */
    char *val             /* the text value - might be NULL */
)
{
    dbox_setstring (dbox, valicon, (val == NULL) ? "" : val);

    return NULL;
}


/*
 * Retrieve a mandatory string value from a text field in a dialogue box.
 *
 * If the value field contains the empty string, a NULL value is retrieved.
 *
 * Space for any new string value is malloc'd - and space occupied by any
 *  previous value is free'd.
 */

error * gui_get_str (
    WindowPtr dbox,       /* the dialogue box */
    int valicon,          /* the writable icon containing the text value */
    char **val            /* to hold the retrieved text value - maybe NULL */
)
{
    char *s = dbox_getstring (dbox, valicon);
    int n = strlen (s) + 1;

    free (*val);

    if (n == 1)   /* string is empty */
        *val = NULL;
    else
    {
        *val = malloc (n);
        if (*val == NULL)
            return error_lookup ("NoMem");
        strcpy (*val, s);
    }

    return NULL;
}


/*
 * Updates the value of the length field in a dialogue box, subject to it
 *  remaining greater than or equal to zero.
 *
 * Note that if 'valicon' is set to -1, then the possibility that the length
 *  may have been given as "*" need not be considered.
 */

error * gui_adjust_len (
    WindowPtr dbox,         /* the dialogue box */
    int lenicon,            /* the writable icon containing the length */
    int valicon,            /* ... and the corresponding string */
    int delta,              /* change required (usually +/-1) */
    unsigned int modifiers  /* if SHIFT bit set, multiply by 10 */
)
{
    char *s = (valicon < 0) ? "" : dbox_getstring (dbox, lenicon);
    int len = (*s == '*') ? strlen (dbox_getstring (dbox, valicon)) + 1 :
                            dbox_getint (dbox, lenicon);

    /* SHIFT-click => adjust by tens */
    if (modifiers & MODIFIER_SHIFT)
        delta *= 10;

    len += delta;
    if (len < 0)
        len = 0;

    return dbox_setint (dbox, lenicon, len);
}


/*
 * Initialise the radio buttons and writable field for an optional event.
 *
 */

error * gui_put_opt_event (
    WindowPtr dbox,         /* the dialogue box */
    int dflticon,           /* the "raise default event" radio button */
    int othericon,          /* the "raise user-defined event" radio button */
    int noneicon,           /* the "do not raise any event" radio button */
    int valicon,            /* the writable icon containing the event */
    int val,                /* the event: 0 => default */
    Bool none               /* TRUE iff no event is to be raised */
)
{
    if (none)
    {
        dbox_setbutton (dbox, dflticon, FALSE);
        dbox_setbutton (dbox, noneicon, TRUE);
        dbox_setbutton (dbox, othericon, FALSE);
        dbox_shade (dbox, valicon, TRUE);
        dbox_setstring (dbox, valicon, "");
    }
    else
    {
        dbox_setbutton (dbox, dflticon, val == 0);
        dbox_setbutton (dbox, noneicon, FALSE);
        dbox_setbutton (dbox, othericon, val != 0);
        dbox_shade (dbox, valicon, val == 0);
        if (val == 0)
            dbox_setstring (dbox, valicon, "");
        else
            dbox_sethex (dbox, valicon, val);
    }

    return NULL;
}


/*
 * Retrieve details of an optional event from a dialogue box.
 */

error * gui_get_opt_event (
    WindowPtr dbox,
    int dflticon,
    int noneicon,
    int valicon,
    int *val,               /* event value stored here: 0 => default */
    unsigned *flags,        /* flags word to be updated */
    unsigned mask           /* identifies "no event" bit in flags */
)
{
    if (dbox_getbutton (dbox, noneicon))
        *flags &= ~mask;
    else
    {
        *flags |= mask;
        *val = dbox_getbutton (dbox, dflticon) ? 0 : 
                                 dbox_getint (dbox, valicon);
    }

    return NULL;
}


/*
 * Initialises a display field to decribe a filetype.
 *
 * Format is:  "aaaaaaaa (&ddd)"
 *          or "directory (&1000)"
 *          or "application (&2000)"
 */

error * gui_put_filetype (
    WindowPtr dbox,
    int valicon,            /* to contain, eg, "Text     (&fff)" */
    int filetype
)
{
    char s[16];

    if (filetype == 0x1000)
        dbox_setstring (dbox, valicon, "directory (&1000)");

    else
    if (filetype == 0x2000)
        dbox_setstring (dbox, valicon, "application (&2000)");

    else
    if (filetype < 0x1000)
    {
        /* convert filetype to string */
        ER ( swi (OS_FSControl, R0, 18, R2, filetype,
                           OUT, R2, (int *) s,       /* first 4 chars */
                                R3, ((int *) s) + 1, /* second 4 chars */
                           END) );

        sprintf(s+8, " (&%03x)", filetype);

        dbox_setstring (dbox, valicon, s);
    }

    else
        return error_lookup ("FTRange");

    return NULL;
}


/*
 * Retrieves a filetype from a display field.
 */

error * gui_get_filetype (
    WindowPtr dbox,
    int valicon,
    int *filetype
)
{
    char *s = dbox_getstring (dbox, valicon);

    s = strchr (s, '(');
    if (s == NULL)
        return error_lookup ("BadFT");
    s += 2;   /* to skip "(&" */

    sscanf (s, "%x", filetype);

    return NULL;
}


/*
 * Sets a filetype given in textual form into a display field.
 */

error * gui_put_filetype_string (
    WindowPtr dbox,
    int valicon,            /* to contain, eg, "Text     (&fff)" */
    char *type
)
{
    int filetype;

    /* force to lower case */
    {
        char *c = type;

        while (*c != 0)
        {
            *c = tolower (*c);
            c++;
        }
    }

    /* check for "special" filetypes */
    if (strcmp (type, "directory") == 0)
        filetype = 0x1000;

    else
    if (strcmp (type, "application") == 0)
        filetype = 0x2000;

    else
    {
        /* translate the text form into a filetype (if possible) */
        ER ( swi (OS_FSControl, R0, 31, R1, type, OUT, R2, &filetype, END) );
    }

    /* now call the simpler routine */
    return gui_put_filetype (dbox, valicon, filetype);
}


/*
 * Retrieves the textual form of a filetype from its display field.
 * Trailing spaces are removed.
 */

error * gui_get_filetype_string (
    WindowPtr dbox,
    int valicon,            /* contains, eg, "Unknown  (&123)" */
    char *type
)
{
    char *s = dbox_getstring (dbox, valicon);
    char *t = strchr (s, ' ');

    if (t == NULL)
        return error_lookup ("BadFT");

    *t = 0;
    strcpy (type, s);
    *t = ' ';

    return NULL;
}


/*
 * Sets the given display field according to a file type entered as a string
 *  by the user (into the Filetype dialogue box).
 *
 * Accepts any of the following:
 *  - a decimal number (starts with a digit)
 *  - a hexadecimal number (starts with '&')
 *  - a textual filetype name (anything else)
 */

error * gui_put_filetype_from_user (
    WindowPtr dbox,
    int valicon,
    char *type
)
{
    /* ignore leading spaces */
    while (*type == ' ')
        type++;

    /* digit or '&' means it's a numerical value */
    if (*type == '&' ||
        (*type >= '0' && *type <= '9'))
    {
        int filetype = 0;

        if (*type == '&')
            sscanf (type + 1, "%x", &filetype);
        else
            sscanf (type, "%d", &filetype);

        return gui_put_filetype (dbox, valicon, filetype);
    }

    /* otherwise it's the textual form */
    return gui_put_filetype_string (dbox, valicon, type);
}


/*
 * Returns integer between 0 and 15 inclusive or 255 according to the value
 * inside the display field 'icon' - which may be 0 - 15 or the string
 * 'noneval'.
 */

int gui_get_colour (WindowPtr dbox, int icon)
{
    char *s = dbox_getstring (dbox, icon);

    if (strstr (noneval, s) != NULL)    /* just in case it was truncated */
        return 255;

    return atoi (s);
}


/*
 * Set display field 'icon' in 'dbox' according to the value 'n' - which may
 *  be 0 - 16. The corresponding integer is displayed except for n = 16,
 *  which is represented by the value noneval.
 *
 * n = 255 is also interpreted as meaning "transparent".
 *
 * Appropriate foreground and background colours are also set for the icon.
 */

void gui_put_colour (WindowPtr dbox, int icon, int n)
{
    if (n == 16 || n == 255)
    {
        dbox_setstring (dbox, icon, noneval);
        n = 0;
    }
    else
        dbox_setint (dbox, icon, n);

    /* set icon colours */
    dbox_iconflag (dbox, icon,
            IF_FIELD(FG, IF_FG_MASK) | IF_FIELD(BG, IF_BG_MASK),
            IF_FIELD(FG, uncolour[n]) | IF_FIELD(BG, n));

    return;
}


/*
 * Called to retrieve an RGB colour value from a display icon.
 */

error * gui_get_rgb_colour (
    WindowPtr dbox,
    int icon,
    unsigned *rgb
)
{
    *rgb = dbox_getint (dbox, icon);

    return NULL;
}


/*
 * Called to initialise an icon to an RGB colour.
 */

error * gui_put_rgb_colour (
    WindowPtr dbox,
    int icon,
    unsigned rgb
)
{
    char s[10];

    sprintf (s, "&%08x", rgb);
    dbox_setstring (dbox, icon, s);

    return NULL;
}
