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

#include "mguipp.h"

#include "mguitest.hpp"

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

class EditsDialog : public CmCallback
{
    CmShell *shell;
public:
    EditsDialog();
    void closeDialog(void) { delete shell; delete this; };
};

class CaChangingEditField:public CmEditField
{
public:
      CaChangingEditField(CmContainer * p, char *text, int len, int clen = -1, MTFont f = DEFAULT_FONT)
    : CmEditField(p, text, len, clen, f)
    {
    };
    void onChanging(EDIT_CHANGE * ec);
};

class CaValEditField:public CmEditField
{
public:
      CaValEditField(CmContainer * p, char *text, int len, int clen = -1, MTFont f = DEFAULT_FONT)
    : CmEditField(p, text, len, clen, f)
    {
    };
    void onValidating(EDIT_VAL * ev);
};

class CaChangeHiddenEditField:public CmHiddenEditField
{
public:
    CmLabel * label;
    void onChange(char *text);

      CaChangeHiddenEditField(CmContainer * p, char *text, int len, int clen = -1, MTFont f = DEFAULT_FONT)
    : CmHiddenEditField(p, text, len, clen, f)
    {
    };
};

class CaReturnKeyEditField:public CmEditField
{
public:
    int notify;
    CmEditField *ed;
    void onReturnKey(char *text);

      CaReturnKeyEditField(CmContainer * p, char *text, int len, int clen = -1, MTFont f = DEFAULT_FONT)
    : CmEditField(p, text, len, clen, f)
    {
	notify = 0;
    };
};

/**************************************************
 * 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 function 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 CaValEditField::
onValidating(EDIT_VAL * ev)
{
    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 CaChangingEditField::
onChanging(EDIT_CHANGE * ec)
{
    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 CaChangeHiddenEditField::
onChange(char *new_value)
{
/*
 * Set the new value in a LABEL Object
 */
    label->setText(new_value);
}

/*****************************************************
 *	This Callback is called by the EDIT when the
 *	'Enter' key is pressed.
 *****************************************************/
void CaReturnKeyEditField::
onReturnKey(char *text)
{
/*
 * When 'notify' is True, the EDIT 'ed' calls
 * the 'ValueChange' and 'NewValue' Callbacks
 */
    notify ^= 1;
    ed->setTextExt(text, False, notify);
}

EditsDialog::EditsDialog(void)
{
    CmOptionEdit *opedit;
    CmEditField *edit;
    CaReturnKeyEditField *edit2;
    CaChangeHiddenEditField *hedit;
    CmLabel *label;
    CmColForm *cform;
    CmRowForm *rform;
    CmSFile *sfile;
    CmAbsList *slist;
    CmPushButton *pb;

    shell = new CmShell("Edit", SF_MODAL);

    cform = new CmColForm(shell);
    rform = new CmRowForm(cform);
/*
 * The OptionEdit is similar to a combo box
 */
    opedit = new CmOptionEdit(rform, "Optionedit", 30, 18, 4, FIXED_MEDIUM);
    opedit->setUnsensitive();
    opedit->setColor(seagreen, black);
    slist = opedit->getSList();
    slist->addItem("FIXED_MEDIUM", 0L);
    slist->addItem("MEDIUM_FONT", 0L);
    slist->addItem("LARGE_FONT", 0L);
    slist->addItem("HELV_N_FONT", 0L);
    slist->addItem("HELV_MEDIUM", 0L);
    slist->addItem("TIMES_N_FONT", 0L);
    slist->addItem("TIMES_MEDIUM", 0L);
/*
 * Hidden Edit always shows '*' in it. Useful for password entry
 * To obtain no char shown at all, use the '\0' char
 */
    new CmHiddenEditField(rform, "hidden value", 20);

    edit = new CaValEditField(rform, "", 20);
    edit->setFilter(DIGIT, "");
    edit->setValidateCallback(edit, (EDITVAL_CB)&CaValEditField::onValidating);
/*
 * The validated status can be highlighted using different
 * colors for the foreground and the background
 */
    edit->setValidatedColors(cadetblue, white);
    edit->setInvalidatedColors(seagreen, black);

    edit = new CaChangingEditField(rform, "", 20);
    edit->setFilter(DIGIT, "");
    edit->setValueChangeCallback(edit, (EDITCHANGE_CB)&CaChangingEditField::onChanging);
/*
 * The text of this LABEL will follow the input in the
 * EDIT created next
 */
    label = new CmLabel(rform, "", FIXED_MEDIUM);
/*
 * This EDIT has a real length of 20 chars but a visible
 * length of 15
 */
    hedit = new CaChangeHiddenEditField(rform, "", 20);
    hedit->label = label;
    hedit->setNewValueCallback(hedit, (STRING_CB)&CaChangeHiddenEditField::onChange);
/*
 * Characters permitted in this EDIT are alpha
 * (converted to upper case) plus the character '_'
 */
    edit2 = new CaReturnKeyEditField(rform, "", 20);
    edit2->setFilter(UPALPHA, "_");
    edit2->setActivateCallback(edit2, (STRING_CB)&CaReturnKeyEditField::onReturnKey);
    edit2->ed = edit;
/*
 * Create a SFILE Object to view this source file in the dialog
 */
    sfile = new CmSFile(cform, __FILE__, FIXED_MEDIUM, 10, 50);
    sfile->setColor(darkblue, white);

    cform = new CmColForm(shell);
    edit = new CmEditField(cform, "Edit Clipped 20/60", 60, 20, FIXED_MEDIUM);
/*
 *  MEditSetReplace() selects the EDIT text for replacing
 */
    edit->selectForReplace();

    edit = new CmEditField(cform, "Edit Clipped 30/80 with horizontal resize enabled", 80, 30, FIXED_MEDIUM);
    edit->setResize(True, False);
/*
 * This PUSH BUTTON closes the dialog
 */
    pb = new CmPushButton(shell, "Close", TIMES_MEDIUM);
    pb->setCallback(this, (VOID_CB)&EditsDialog::closeDialog);

    shell->realize();
}

/*****************************************************
 *	This function opens the dialog when the
 *	corresponding menu item is selected
 *****************************************************/
void
EditFieldDemo(void)
{
	new EditsDialog;
}
