/***********************************************************************
 *
 * TITLE:
 *      symbol.c
 *
 * AUTHOR:
 *      Cassie Mulnix
 *
 * DESCRIPTION:
 *      This module is part of the OPPS editor, xopps.  It contains
 *      object routines to handle symbol objects.
 *
 *                              CHANGE HISTORY
 *
 * $Log: symbol.c,v $
 * Revision 1.20  1994/08/10  22:05:48  cassie
 * removed call to DialogFlagSet in verify_fun since
 * it is already set in ok_button
 *
 * Revision 1.19  1994/07/20  19:06:35  clm
 * updated TRUE, ERROR etc in cancel & ok_button functions
 * to DIALOG_ constants
 *
 * Revision 1.18  1994/06/16  21:57:27  clm
 * updated to new dialog routines - extra parameter to DialogTextCreate
 *
 * Revision 1.17  1994/06/08  18:48:45  clm
 * removed Xm library includes since they are in dialog
 *
 * Revision 1.16  1994/06/01  22:27:07  clm
 * rewrote init functions to use dialog oellib functions
 * also don't initialize popups until object called
 *
 * Revision 1.15  1994/05/20  23:31:43  clm
 * updated with HP, SGI changes
 *
 * Revision 1.14  1994/05/04  23:34:36  clm
 * ported to ANSI C
 *
 * Revision 1.13  1993/05/18  20:58:30  clm
 * added new message.c function
 *
 * Revision 1.12  1993/02/08  16:29:17  clm
 * fixed locate so that if y_gap is less than 1, symbol size does
 * not become a negative number
 *
 * Revision 1.11  1992/12/22  15:37:04  clm
 * fixed load and lim so symol cannot be moved or loaded outside chart lines
 *
 * Revision 1.10  1992/12/15  20:39:51  clm
 * changed strlen to sizeof when assigning symbols
 *
 * Revision 1.9  1992/12/10  21:45:40  clm
 * fixed new_index so chart is always object 0
 *
 * Revision 1.8  1992/11/09  21:51:57  clm
 * removed unused variables
 *
 * Revision 1.7  1992/11/09  16:33:41  clm
 * fixed dsp_marker size
 *
 * Revision 1.6  1992/10/02  20:44:22  clm
 * housekeeping
 *
 * Revision 1.5  1992/09/16  14:56:16  clm
 * fixed load function so doesn't add object if error in load
 *
 * Revision 1.4  1992/09/01  17:45:10  clm
 * added color menu
 *
 * Revision 1.3  1992/08/27  16:35:33  clm
 * fixed help callback
 *
 * Revision 1.2  1992/08/10  20:59:18  clm
 * added error checking to load routine
 *
 * Revision 1.1  1992/08/04  17:02:17  clm
 * Initial revision
 *
 *
 ***********************************************************************
 *
 * WARNINGS:
 *
 * EXTERNAL CALLABLE COMPONENTS (PUBLIC):
 *
 * GLOBALS:
 *
 * WAIVERS:
 *
 * NOTES:
 *
 * MANPAGE:
 *
 ***********************************************************************/

#ifndef lint
static char rcsid[] =
    "$Id: symbol.c,v 1.20 1994/08/10 22:05:48 cassie OEL $";
#endif

/*************************************************************************
    global functions:
        add_symbol(x, y, sym, pages, size, layer) 
	    - add object to data base
***************************************************************************/

/*
    local functions:
        dsp_symbol(i) - display symbol object
        edt_symbol(i, new) - change contents of symbol field
        rem_symbol(i) - remove symbol object
        lim_symbol(i) - limit range of motion of symbol object
        loc_symbol(i) - locate position of symbol object on screen
        mov_symbol(i) - move symbol object
        cpy_symbol(to, from) - copy symbol object
        msg_symbol(i) - display message on screen
        sav_symbol(i, file) - save symbol to file
*/

#include "xopps.h"

        /* local functions */
static void create_dialog(void);
static int load_symbol(char *);			/* load a symbol object */
static void sym_ok_button(void);		/* Callback for ok button */
static void cancel_button(void);		/* Callback for cancel */
static void change_mark(Widget, XtPointer, XtPointer);
static void change_page(Widget, XtPointer, XtPointer);
static void change_size(Widget, XtPointer, XtPointer);
static void change_drawlyr(Widget, XtPointer, XtPointer);
static void change_color(Widget, XtPointer, XtPointer);
static void dsp_symbol(int);
static void edt_symbol(int, int);
static void rem_symbol(int, int);
static void lim_symbol(int, int *, int *, int *, int *, int);
static void loc_symbol(int, int);
static void mov_symbol(int, int, int, int);
static void cpy_symbol(struct obj *, struct obj *);
static void msg_symbol(int, int);
static void sav_symbol(int, FILE *, int);
static void verify_fun(Widget, XtPointer, XtPointer);

static struct ops sym_ops = {
    dsp_symbol, edt_symbol, rem_symbol, lim_symbol, loc_symbol, mov_symbol,
    cpy_symbol, msg_symbol, sav_symbol
};

static DialogOption *marker, *page;
static DialogOption *size, *drawlyr, *color;

static Widget sym_dialog;                     /* dialog shell for popup */
static Widget parent_shell;
static int new_size;				/* new size id */
static int nmarks;				/* number of markers */
static int new_marker;				/* new marker id */
static int new_page;				/* new page id */
static int new_drawlyr;				/* new layer id */
static int new_color;				/* new color id */

/***********************************************************************
 *
 * FUNCTION:
 *      init_symbol_object() *
 *
 * INPUTS:
 *      parent  (Widget)
 *
 * OUTPUTS:
 *	none
 *
 * RETURNS:
 *	none
 *
 * EXTERNALLY READ:
 *	none
 *
 * EXTERNALLY MODIFIED:
 *	none
 *
 * DESCRIPTION:
 *      registers the symbol object and sets the parent
 */

void 
init_symbol_object(Widget parent)
{
    register_io_obj('L', load_symbol);            /* register object */
    parent_shell = parent;
}

/***********************************************************************
 *
 * FUNCTION:
 *      create_dialog()
 *
 * INPUTS:
 *	none
 *
 * OUTPUTS:
 *	none
 *
 * RETURNS:
 *	none
 *
 * EXTERNALLY READ:
 *	none
 *
 * EXTERNALLY MODIFIED:
 *	none
 *
 * DESCRIPTION:
 *      initializes the widgets for the symbol object
 */

static void 
create_dialog(void)
{
    Pixmap marks[MAX_MARKER];			/* symbol images */

    static char *page_list[] = {
	"All Pages", "Current Page"
    };

    static char *size_list[] = {
	"Normal", "Small"
    };

    static char *layer[] = {
	"0", "1", "2","3"
    };

    get_markers(marks, &nmarks);

    sym_dialog = DialogInit(parent_shell, "Symbol Dialog", "symbol", verify_fun,
	(XtPointer)DIALOG_CANCEL);

    marker = DialogOptionCreate("Symbol ", nmarks, 0, change_mark,
	DIALOG_OPT_PIX_ARY, marks, NULL);

    page = DialogOptionCreate("Page ", 2, 1, change_page, DIALOG_OPT_STR_ARY,
	page_list, NULL);

    size = DialogOptionCreate("Size ", 2, 0, change_size, DIALOG_OPT_STR_ARY,
	size_list, NULL);

    drawlyr = DialogOptionCreate("Draw Layer ", 4, 0, change_drawlyr,
	DIALOG_OPT_STR_ARY, layer, NULL);

    color = DialogOptionCreate("Color ", ncolor, 0, change_color,
	DIALOG_OPT_STR_ARY, color_name, color_index);

    DialogStdButtons(verify_fun, (XtPointer)DIALOG_UPDATE, verify_fun,
        (XtPointer)DIALOG_CANCEL, (XtCallbackProc)ShowHelp, "symbol");

}

/***********************************************************************
 *
 * FUNCTION:
 *      add_symbol()
 *
 * INPUTS:
 *      x, y, sym, page, size, layer, color  (int)
 *
 * OUTPUTS:
 *
 * RETURNS:
 *
 * EXTERNALLY READ:
 *
 * EXTERNALLY MODIFIED:
 *
 * DESCRIPTION:
 *      adds new symbol object
 */

int 
add_symbol(int x, int y, int sym, int page, int size, int layer, int color)
{
    int i;              /* index */

    i = new_index(FALSE);
    objary[i].z.symptr = (struct sym *)XtMalloc(sizeof(struct sym));
    objary[i].z.symptr->x = x;
    objary[i].z.symptr->y = y;
    objary[i].z.symptr->sym = sym;
    objary[i].z.symptr->page = page;
    objary[i].z.symptr->size = size;
    objary[i].z.symptr->color = color;
    objary[i].type = OBJ_PAG;
    objary[i].opsptr = &sym_ops;
    objary[i].layer = layer;
    return i;
}

/***********************************************************************
 *
 * FUNCTION:
 *      cpy_symbol()
 *
 * INPUTS:
 *      to, from        (obj *)
 *
 * OUTPUTS:
 *
 * RETURNS:
 *
 * EXTERNALLY READ:
 *
 * EXTERNALLY MODIFIED:
 *
 * DESCRIPTION:
 *      copies symbol object from to symbol object to
 */

static void 
cpy_symbol(struct obj *to, struct obj *from)
{

    if (from->type == OBJ_NUL) return;

    to->z.symptr = (struct sym *)XtMalloc(sizeof(struct sym));
    to->z.symptr->x = from->z.symptr->x;
    to->z.symptr->y = from->z.symptr->y;
    to->z.symptr->sym = from->z.symptr->sym;
    to->z.symptr->page = from->z.symptr->page;
    to->z.symptr->size = from->z.symptr->size;
    to->z.symptr->color = from->z.symptr->color;
    to->type = OBJ_PAG;
    to->layer = from->layer;
    to->opsptr = &sym_ops;
    to->rlist = copyRectList(from->rlist);
}

/***********************************************************************
 *
 * FUNCTION:
 *      rem_symbol()
 *
 * INPUTS:
 *      i       (int)
 *
 * OUTPUTS:
 *
 * RETURNS:
 *
 * EXTERNALLY READ:
 *
 * EXTERNALLY MODIFIED:
 *
 * DESCRIPTION:
 *      removes symbol object i
 */

static void 
rem_symbol(int i, int dir)
{
    struct obj *objptr;

    switch (i) {
    case BACK:
        objptr = &objbck;
        break;
    case TEMP:
        objptr = &objtmp;
        break;
    default: 
	objptr = &(objary[i]);
        break;
    }
    freeRectList(objptr->rlist);
    XtFree((char *)objptr->z.symptr);
    rem_object(objptr);
}

/***********************************************************************
 *
 * FUNCTION:
 *      lim_symbol()
 *
 * INPUTS:
 *      i       (int)
 *      x1, y1, x2, y2  (int *)
 *
 * OUTPUTS:
 *
 * RETURNS:
 *
 * EXTERNALLY READ:
 *
 * EXTERNALLY MODIFIED:
 *
 * DESCRIPTION:
 *      limits range of motion of symbol object
 */

static void 
lim_symbol(int i, int *x1, int *y1, int *x2, int *y2, int dir)
{
    XRectangle *(*r)[];

    r = getMoveRect(objary[i].rlist);
    *x1 = xlnary[0].z.lnptr->cord;
    *y1 = ylnary[0].z.lnptr->cord;
    *x2 = xlnary[nxln-1].z.lnptr->cord - (1 + (*r)[0]->width);
    *y2 = ylnary[nyln-1].z.lnptr->cord - (1 + (*r)[0]->height);
}

/***********************************************************************
 *
 * FUNCTION:
 *      loc_symbol()
 *
 * INPUTS:
 *      i       (int)
 *
 * OUTPUTS:
 *
 * RETURNS:
 *
 * EXTERNALLY READ:
 *
 * EXTERNALLY MODIFIED:
 *
 * DESCRIPTION:
 *      locates position of symbol object i
 */

static void 
loc_symbol(int i, int dir)
{
    struct sym *symptr;         /* local pointer */
    XRectangle r;               /* rectangle */

    symptr = objary[i].z.symptr;
    if (symptr->size == 0) {
	if (y_gap > 0) {
            r.width = y_gap - 1;
            r.height = y_gap - 1;
	} else {
	    r.width = 1;
	    r.height = 1;
	}
        r.y = symptr->y;
    } else {
	if (y_gap > 0) {
	    r.width = 2 * (y_gap - 1)/3;
            r.height = 2 * (y_gap - 1)/3;
	} else {
	    r.width = 2 * 1/3;
            r.height = 2 * 1/3;
	}
        r.y = symptr->y + r.height/4;
    }
    r.x = symptr->x;
    setRectList(objary[i].rlist, 1, &r, RL_PRIMARY);
}

/***********************************************************************
 *
 * FUNCTION:
 *      mov_symbol()
 *
 * INPUTS:
 *      i, x, y (int)
 *
 * OUTPUTS:
 *
 * RETURNS:
 *
 * EXTERNALLY READ:
 *
 * EXTERNALLY MODIFIED:
 *
 * DESCRIPTION:
 *      moves symbol object i to (x,y)
 */

static void 
mov_symbol(int i, int x, int y, int dir)
{
    objary[i].z.symptr->x += x;
    objary[i].z.symptr->y += y;
}

/***********************************************************************
 *
 * FUNCTION:
 *      dsp_symbol()
 *
 * INPUTS:
 *      i       (int)
 *
 * OUTPUTS:
 *
 * RETURNS:
 *
 * EXTERNALLY READ:
 *
 * EXTERNALLY MODIFIED:
 *
 * DESCRIPTION:
 *      displays symbol object i on screen
 */

static void 
dsp_symbol(int i)
{
    struct sym *symptr;         /* local pointer */
    XRectangle *(*r)[];		/* rectangle */

    symptr = objary[i].z.symptr;
    gr_set_color(color_name[symptr->color], color_gscale[symptr->color]);
    r = getMoveRect(objary[i].rlist);
    if ((symptr->page == current_page) || (symptr->page == 0)) {
	dsp_marker(symptr->sym,(*r)[0]->x,(*r)[0]->y + 2,(*r)[0]->height - 4,0);
    }
}

/***********************************************************************
 *
 * FUNCTION
 *      msg_symbol()
 *
 * INPUTS:
 *      i       (int)
 *
 * OUTPUTS:
 *
 * RETURNS:
 *
 * EXTERNALLY READ:
 *
 * EXTERNALLY MODIFIED:
 *
 * DESCRIPTION:
 *      displays symbol message on screen
 */

static void 
msg_symbol(int i, int dir)
{
    char buf[64];

    (void)sprintf(buf, "Symbol");
    Message(buf);
}

/***********************************************************************
 *
 * FUNCTION:
 *      sav_symbol()
 *
 * INPUTS:
 *      i       (int)
 *      fp      (FILE *)
 *
 * OUTPUTS:
 *
 * RETURNS:
 *
 * EXTERNALLY READ:
 *
 * EXTERNALLY MODIFIED:
 *
 * DESCRIPTION:
 *      saves symbol record i to fp
 */

static void 
sav_symbol(int i, FILE *fp, int dir)
{
    struct sym *symptr;
    char buf[256];

    symptr = objary[i].z.symptr;
    buf[0] = 'L';
    buf[1] = ' ';
    record_print(buf + 2, "ddddddd", symptr->x, symptr->y, symptr->sym,
	 symptr->page, symptr->size, objary[i].layer, symptr->color);
    fputs(buf, fp);
}

/***********************************************************************
 *
 * FUNCTION:
 *      load_symbol()
 *
 * INPUTS:
 *      buf     (char *)
 *
 * OUTPUTS:
 *
 * RETURNS:
 *
 * EXTERNALLY READ:
 *
 * EXTERNALLY MODIFIED:
 *
 * DESCRIPTION:
 *      loads symbol object record
 */

static int 
load_symbol(char *buf)
{
    int x, y, sym, page, size, layer, color;
    int i;

    if (record_scan(buf + 1, "ddddddd", &x, &y, &sym, &page,
	&size, &layer, &color) == 7) {
	if ((x < xlnary[0].z.lnptr->cord)||(x > xlnary[nxln-1].z.lnptr->cord)) {
	    Warning("Illegal Symbol x %d", x);
	} else if ((y < ylnary[0].z.lnptr->cord) || 
	    (y > ylnary[nyln-1].z.lnptr->cord)) {
	    Warning("Illegal Symbol y %d", y);
	} else if ((sym < 0) || (sym > 14)) {
	    Warning("Illegal Symbol symbol %d", sym);
	} else if ((page < 0) || (page > 2)) {
	    Warning("Illegal Symbol page %d", page);
	} else if ((size < 0) || (size > 1)) {
	    Warning("Illegal Symbol size %d", size);
	} else if ((layer < 0) || (layer > 3)) {
	    Warning("Illegal Symbol layer %d", layer);
	} else if ((color < 0) || (color > ncolor)) {
	    Warning("Illegal Symbol color %d", color);
   	} else {
            i = add_symbol(x, y, sym, page, size, layer, color);
            (*(objary[i].opsptr->loc))(i, OBJECT);
            return 0;
	}
        return -1;
    } else {
        return -1;
    }
}

/***********************************************************************
 *
 * FUNCTION:
 *      edt_symbol()
 *
 * INPUTS:
 *      i, new  (int)
 *
 * OUTPUTS:
 *
 * RETURNS:
 *
 * EXTERNALLY READ:
 *
 * EXTERNALLY MODIFIED:
 *
 * DESCRIPTION:
 *      edits symbol object i
 */

static void 
edt_symbol(int i, int new)
{

    if (sym_dialog == NULL) {
	create_dialog();
    }

    (*(objary[i].opsptr->cpy))(&objtmp, &objary[i]);
    new_page = objtmp.z.symptr->page;
    new_size = objtmp.z.symptr->size;
    new_marker = objtmp.z.symptr->sym;
    new_drawlyr = objtmp.layer;
    new_color = objtmp.z.symptr->color;
    if (new) {
        (*(objary[i].opsptr->rem))(i, OBJECT);
        i = -1;
    }

    DialogOptionSet(marker, (int)new_marker);
    DialogOptionSet(size, (int)new_size);
    DialogOptionSet(page, (int)new_page);
    DialogOptionSet(color, (int)new_color);
    DialogOptionSet(drawlyr, (int)new_drawlyr);
    EditObject(i, sym_dialog);
}

/***********************************************************************
 *
 * FUNCTION:
 *      sym_ok_button()
 *
 * INPUTS:
 *
 * OUTPUTS:
 *
 * RETURNS:
 *
 * EXTERNALLY READ:
 *
 * EXTERNALLY MODIFIED:
 *
 * DESCRIPTION:
 *      checks input after ok button is pressed
 */

static void 
sym_ok_button(void)
{
    int change = DIALOG_NO_CHANGE;	/* temp boolean to see if changed */

    if (new_page != objtmp.z.symptr->page) {
	change |= DIALOG_UPDATE;
    }
    objtmp.z.symptr->page = DialogOptionGet(page);

    if (new_size != objtmp.z.symptr->size) {
	change |= DIALOG_UPDATE;
    }
    objtmp.z.symptr->size = DialogOptionGet(size);

    if (new_marker != objtmp.z.symptr->sym) {
	change |= DIALOG_UPDATE;
    }
    objtmp.z.symptr->sym = DialogOptionGet(marker);

    if (new_drawlyr != objtmp.layer) {
	change |= DIALOG_UPDATE;
    }
    objtmp.layer = DialogOptionGet(drawlyr);

    if (new_color != objtmp.z.symptr->color) {
	change |= DIALOG_UPDATE;
    }
    objtmp.z.symptr->color = DialogOptionGet(color);

    if (objtmp.z.symptr->page != 0) {
	/*
	 * if not printed on all pages, set page value to current page #
    	 */
	objtmp.z.symptr->page = current_page;
	change |= DIALOG_UPDATE;
    }
    object_change = change;
    DialogFlagSet(change);
}

/***********************************************************************
 *
 * FUNCTION:
 *      cancel_button()
 *
 * INPUTS:
 *
 * OUTPUTS:
 *
 * RETURNS:
 *
 * EXTERNALLY READ:
 *
 * EXTERNALLY MODIFIED:
 *
 * DESCRIPTION:
 *      discards any edits and closes edit window
 */

static void 
cancel_button(void)
{
    object_change = DIALOG_CANCEL;
    DialogFlagSet(DIALOG_CANCEL);
}

/***********************************************************************
 *
 * FUNCTION:
 *      change_size()
 *
 * INPUTS:
 *      button  (Widget)
 *      option, any_data        (XtPointer)
 *
 * OUTPUTS:
 *
 * RETURNS:
 *
 * EXTERNALLY READ:
 *
 * EXTERNALLY MODIFIED:
 *
 * DESCRIPTION:
 *      sets new size for symbol object
 */

static void 
change_size(Widget button, XtPointer option, XtPointer any_data)
{
    new_size = (int)option;
}

/***********************************************************************
 *
 * FUNCTION:
 *      change_page()
 *
 * INPUTS:
 *      button  (Widget)
 *      option, any_data        (XtPointer)
 *
 * OUTPUTS:
 *
 * RETURNS:
 *
 * EXTERNALLY READ:
 *
 * EXTERNALLY MODIFIED:
 *
 * DESCRIPTION:
 *      sets new page for symbol object
 */

static void 
change_page(Widget button, XtPointer option, XtPointer any_data)
{
    new_page = (int)option;
}

/***********************************************************************
 *
 * FUNCTION:
 *      change_mark()
 *
 * INPUTS:
 *      button  (Widget)
 *      option, any_data        (XtPointer)
 *
 * OUTPUTS:
 *
 * RETURNS:
 *
 * EXTERNALLY READ:
 *
 * EXTERNALLY MODIFIED:
 *
 * DESCRIPTION:
 *      sets new marker for symbol object
 */

static void 
change_mark(Widget button, XtPointer option, XtPointer any_data)
{
    new_marker = (int)option;
}

/***********************************************************************
 *
 * FUNCTION:
 *      change_drawlyr()
 *
 * INPUTS:
 *      button  (Widget)
 *      option, any_data        (XtPointer)
 *
 * OUTPUTS:
 *
 * RETURNS:
 *
 * EXTERNALLY READ:
 *
 * EXTERNALLY MODIFIED:
 *
 * DESCRIPTION:
 *      sets new drawlyr for symbol object
 */

static void 
change_drawlyr(Widget button, XtPointer option, XtPointer any_data)
{
    new_drawlyr = (int)option;
}

/***********************************************************************
 *
 * FUNCTION:
 *      change_color()
 *
 * INPUTS:
 *      button  (Widget)
 *      option, any_data        (XtPointer)
 *
 * OUTPUTS:
 *
 * RETURNS:
 *
 * EXTERNALLY READ:
 *
 * EXTERNALLY MODIFIED:
 *
 * DESCRIPTION:
 *      sets new color for symbol object
 */

static void 
change_color(Widget button, XtPointer option, XtPointer any_data)
{
    new_color = (int)option;
}

/***********************************************************************
 *
 * FUNCTION:
 *      verify_fun()
 *
 * INPUTS:
 *      w       (Widget)
 *      x, y    (XtPointer)
 *
 * OUTPUTS:
 *      none
 *
 * RETURNS:
 *      none
 *
 * EXTERNALLY READ:
 *      none
 *
 * EXTERNALLY MODIFIED:
 *      none
 *
 * DESCRIPTION:
 *      validates that the popup dialog can be closed
 */

static void
verify_fun(Widget w, XtPointer x, XtPointer y)
{
    if ((int)x == DIALOG_CANCEL) {
        if (!ShellValidateClose(w)) return;
        cancel_button();
    } else if ((int)x == DIALOG_UPDATE) {
        sym_ok_button();
    }
}
