/*
 *    File edits.c
 *      Demonstrates the use of the EDIT Object
 */
#include <stdio.h>
#include <stdlib.h>
#include <string.h>

#include "mgui.h"

#define IsEven(a)	(!((a)&1))

/*
 *    Callback for closing and destroying a generic dialog
 */
extern void CloseDialogCB(MOBJECT p, void *s, void *v);

extern MTColor black, white, darkblue, cadetblue, seagreen;

/**************************************************
 * This function returns True only if characters
 * in the string pointed to by 'ps' are alternating
 * odd and even
 **************************************************/
int 
ValidateString(char *ps)
{
    int val, even, old;

    val = True;
    old = IsEven(*ps);
    if (*ps != '\0')
	for (ps++; *ps && val; ps++, old = even)
	{
	    even = IsEven(*ps);
	    val = old ^ even;
	}
    return val;
}

/*****************************************************
 *	This Callback is called by the EDIT
 *	when it is about to lose the input focus.
 *	The application can set the EDIT status to
 *	'validated' or can prevent the Object from
 *	losing the focus.
 *****************************************************/
void 
ValidateCB(MOBJECT edit, EDIT_VAL * ev, void *ii)
{
    ev->text_validated = ValidateString(ev->text);
/*
 * if the validation status is False and the Object
 * has not lost the focus, maintain the input focus
 */
    if (!ev->text_validated && !ev->focus_lost)
	ev->focus_leave = False;
}

/*****************************************************
 *	The EDIT Object calls this Callback before
 *	acting any change in the text value.
 *	The application can refuse the changes.
 *****************************************************/
void 
ValueChangeCB(MOBJECT edit, EDIT_CHANGE * ec, void *ii)
{
    char buff[128];

    if (!strcmp(ec->current_text, "1234567890"))
    {
/*
 * When the text reaches this value, every change is refused!!!
 */ ec->exec = False;
	return;
    }
/*
 * 'buff' contains the text as should be after the changes
 */
    strncpy(buff, ec->current_text, ec->pos);
    strcpy(buff + ec->pos, ec->change);
    strcat(buff, ec->current_text + ec->pos + ec->len);
/*
 * The change is permitted only if the text is validated
 * by the function 'ValidateString'
 */
    ec->exec = ValidateString(buff);
}

/*****************************************************
 *	This Callback is called by the EDIT when its
 *	text value has changed.
 *****************************************************/
void 
NewValueCB(MOBJECT edit, char *new_value, void *label)
{
/*
 * Set the new value in a LABEL Object
 */
    MObjectSetText((MOBJECT) label, new_value);
}

/*****************************************************
 *	This Callback is called by the EDIT when the
 *	'Enter' key is pressed.
 *****************************************************/
void
ActivateCB(MOBJECT edit, char *text, void *ed)
{
    static int notify;
/*
 * When 'notify' is True, the EDIT 'ed' calls
 * the 'ValueChange' and 'NewValue' Callbacks
 */
    notify ^= 1;
    MEditSetTextExt((MOBJECT) ed, text, False, notify);
}

/*****************************************************
 *	This Callback is called by the SPIN-EDIT when the
 *	the spin buttons or up/down  arrow keys are pressed.
 *	The second argument 'a' is positive if a spin-up
 *	is preformed, negative otherwise.
 *****************************************************/

void
SpinEditCB(MOBJECT ed, MVALUE a, void *b)
{
    int val = atoi(MEditValue(ed));
    char buf[32];

    if (a > 0)
	val++;
    else
	val--;
    sprintf(buf, "%d", val);
    MObjectSetText(ed, buf);
}

/*****************************************************
 *	This callback opens the dialog when the
 *	corresponding menu item is selected
 *****************************************************/
void
EditCB(MOBJECT obj, void *a, void *b)
{
    MOBJECT shell, pb, edit, edit2, list, label, cform, rform, sfile;

    shell = MCreateShell("Edit", SF_MODAL);

    cform = MCreateColForm(shell);
    rform = MCreateRowForm(cform);
/*
 * The OptionEdit is similar to a combo box
 */
    edit = MCreateOptionEdit(rform, "Optionedit", 30, 18, 4, FIXED_MEDIUM);
    MObjectSetUnsensitive(edit);
    MObjectSetColor(edit, seagreen, black);
    list = MOptionEditGetList(edit);
    MSListAddItem(list, "FIXED_MEDIUM", 0L);
    MSListAddItem(list, "MEDIUM_FONT", 0L);
    MSListAddItem(list, "LARGE_FONT", 0L);
    MSListAddItem(list, "HELV_N_FONT", 0L);
    MSListAddItem(list, "HELV_MEDIUM", 0L);
    MSListAddItem(list, "TIMES_N_FONT", 0L);
    MSListAddItem(list, "TIMES_MEDIUM", 0L);
/*
 * Hidden Edit always shows '*' in it. Useful for password entry
 * To obtain no char shown at all, use the '\0' char
 */
    MCreateHiddenEdit(rform, "hidden value", 20, FIXED_MEDIUM, '*');

    edit = MCreateEdit(rform, "", 20, FIXED_MEDIUM);
    MEditSetFilter(edit, DIGIT, "");
    MEditSetValCallback(edit, ValidateCB, 0L);
/*
 * The validated status can be highlighted using different
 * colors for the foreground and the background
 */
    MEditSetValidatedColors(edit, cadetblue, white);
    MEditSetNotValidatedColors(edit, seagreen, black);

    edit = MCreateEdit(rform, "", 20, FIXED_MEDIUM);
    MEditSetFilter(edit, DIGIT, "");
    MEditSetValueChangeCallback(edit, ValueChangeCB, 0L);
/*
 * The text of this LABEL will follow the input in the
 * EDIT created next
 */
    label = MCreateLabel(rform, "", FIXED_MEDIUM);
/*
 * This EDIT has a real length of 20 chars but a visible
 * length of 15
 */
    edit = MCreateHiddenEdit(rform, "", 20, FIXED_MEDIUM, '*');
    MEditSetNewValueCallback(edit, NewValueCB, (void *) label);

/*
 * Characters permitted in this EDIT are alpha
 * (converted to upper case) plus the character '_'
 */
    edit2 = MCreateEdit(rform, "", 20, FIXED_MEDIUM);
    MEditSetFilter(edit2, UPALPHA, "_");
    MEditSetActCallback(edit2, ActivateCB, (void *) edit); 
    edit = MCreateSpinEdit(rform, "", 3, 3, FIXED_SMALL, SpinEditCB, NULL);
/*
 * Create a SFILE Object to view this source file in the dialog
 */
    sfile = MCreateSFile(cform, __FILE__, FIXED_MEDIUM, 10, 50);
    MObjectSetColor(sfile, darkblue, white);

    cform = MCreateColForm(shell);
    edit = MCreateClippedEdit(cform, "Edit Clipped 20/60", 60, 20, FIXED_MEDIUM);
/*
 *  MEditSetReplace() selects the EDIT text for replacing
 */
    MEditSetReplace(edit);


    edit = MCreateClippedEdit(cform, "Edit Clipped 30/80 with horizontal resize enabled", 80, 30, FIXED_MEDIUM);
    MObjectSetResize(edit, True, False);
/*
 * This PUSH BUTTON closes the dialog
 */
    pb = MCreatePButton(shell, "Close", TIMES_MEDIUM);
    MPButtonSetCallback(pb, CloseDialogCB, 0L);

    MShellRealize(shell);
}
