/***********************************************************************
 *
 * TITLE:
 *      page.c
 *
 * AUTHOR:
 *      Cassie Mulnix
 *
 * DESCRIPTION:
 *      This module is part of the OPPS editor, xopps.  It contains
 *      object routines to handle page objects.
 *
 *                              CHANGE HISTORY
 *
 * $Log: page.c,v $
 * Revision 1.21  1994/08/10  22:03:27  cassie
 * updated to DIALOG_ constants for DialogFlagSet
 *
 * Revision 1.20  1994/07/20  19:06:35  clm
 * updated TRUE, ERROR etc in cancel & ok_button functions
 * to DIALOG_ constants
 *
 * Revision 1.19  1994/06/16  21:55:48  clm
 * updated to new dialog routines - extra parameter to DialogTextCreate
 *
 * Revision 1.18  1994/06/16  16:56:35  clm
 * updated to new gr_ routines using GR_ for font names
 *
 * Revision 1.17  1994/06/08  18:47:59  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/27  20:48:22  clm
 * fixed locate rectangles
 *
 * Revision 1.12  1993/05/18  20:58:30  clm
 * added new message.c function
 *
 * Revision 1.11  1992/12/22  16:00:38  clm
 * fixed lim and load so objects cannot be loaded or moved outside chart lines
 *
 * Revision 1.10  1992/12/10  21:45:40  clm
 * fixed new_index so chart is always object 0
 *
 * Revision 1.9  1992/10/02  20:27:15  clm
 * housekeeping
 *
 * Revision 1.8  1992/09/16  14:55:49  clm
 * fixed load function so doesn't add object if error in load
 *
 * Revision 1.7  1992/09/14  18:45:51  clm
 * added draw layer to object
 *
 * Revision 1.6  1992/09/14  14:22:04  clm
 * fixed error checking of font in load_page
 *
 * Revision 1.5  1992/09/01  17:14:02  clm
 * added color menu
 *
 * Revision 1.4  1992/08/13  18:09:21  clm
 * fixed error checking for load module
 *
 * Revision 1.2  1992/08/10  18:06:20  clm
 * fixed aesthetics of popup
 *
 * Revision 1.1  1992/08/04  17:02:00  clm
 * Initial revision
 *
 *
 ***********************************************************************
 *
 * WARNINGS:
 *
 * EXTERNAL CALLABLE COMPONENTS (PUBLIC):
 *
 * GLOBALS:
 *
 * WAIVERS:
 *
 * NOTES:
 *
 * MANPAGE:
 *
 ***********************************************************************/

#ifndef lint
static char rcsid[] =
    "$Id: page.c,v 1.21 1994/08/10 22:03:27 cassie OEL $";
#endif

/*************************************************************************
    global functions:
        add_page(x, y, font, point, layer) - add object to data base
***************************************************************************/

/*
    local functions:
        dsp_page(i) - display page object
        edt_page(i, new) - change contents of page field
        rem_page(i) - remove page object
        lim_page(i) - limit range of motion of page object
        loc_page(i) - locate position of page object on screen
        mov_page(i) - move page object
        cpy_page(to, from) - copy page object
        msg_page(i) - display message on screen
        sav_page(i, file) - save page to file
*/

#include "xopps.h"

static int font_values[] = {
    GR_COURIER, GR_COURIER_BOLD, GR_HELVETICA, GR_HELVETICA_BOLD, GR_TIMES, 
    GR_TIMES_BOLD
};

static int font_sizes[] = {
    8, 10, 12, 14, 18, 24
};

        /* local functions */
static void create_dialog(void);
static int load_page(char *);			/* load a page object */
static void pag_ok_button(void);            	/* Callback for ok button */
static void cancel_button(void);            	/* Callback for cancel button */
static void change_point(Widget, XtPointer, XtPointer);
static void change_font(Widget, XtPointer, XtPointer);
static void change_color(Widget, XtPointer, XtPointer);
static void change_drawlyr(Widget, XtPointer, XtPointer);
static void dsp_page(int);
static void edt_page(int, int);
static void rem_page(int, int);
static void lim_page(int, int *, int *, int *, int *, int);
static void loc_page(int, int);
static void mov_page(int, int, int, int);
static void cpy_page(struct obj *, struct obj *);
static void msg_page(int, int);
static void sav_page(int, FILE *, int);
static void verify_fun(Widget, XtPointer, XtPointer);

static struct ops pag_ops = {
    dsp_page, edt_page, rem_page, lim_page, loc_page, mov_page, cpy_page,
    msg_page, sav_page
};

static DialogOption *font, *point;
static DialogOption *color, *drawlyr;

static Widget page_dialog;                     /* dialog shell for popup */
static Widget parent_shell;
static int new_color;				/* new color id */
static int new_point;                           /* new point id */
static int new_font;                            /* new font id */
static int new_drawlyr;				/* new draw layer id */

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

void 
init_page_object(Widget parent)
{
    register_io_obj('P', load_page);            /* 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 page dialog
 */

static void 
create_dialog(void)
{
    static char *fonts[] = { "Courier", "Courier Bold", "Helvetica",
        "Helvetica Bold", "Times", "Times Bold" };
    static char *points[] = { "8", "10", "12", "14", "18", "24" };
    static char *drawlyrs[] = { "0", "1", "2", "3" };

    page_dialog = DialogInit(parent_shell, "Page Object", "page", verify_fun,
	(XtPointer)DIALOG_CANCEL);

    font = DialogOptionCreate("Font ", 6, 5, change_font, DIALOG_OPT_STR_ARY,
	fonts, font_values);

    point = DialogOptionCreate("Point ", 6, 10, change_point, 
	DIALOG_OPT_STR_ARY, points, font_sizes);

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

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

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

}

/***********************************************************************
 *
 * FUNCTION:
 *      add_page()
 *
 * INPUTS:
 *      x, y, font, point, layer, color  (int)
 *
 * OUTPUTS:
 *
 * RETURNS:
 *
 * EXTERNALLY READ:
 *
 * EXTERNALLY MODIFIED:
 *
 * DESCRIPTION:
 *      adds new page object
 */

int 
add_page(int x, int y, int font, int point, int layer, int color)
{
    int i;              /* index */

    i = new_index(FALSE);
    objary[i].z.pagptr = (struct pag *)XtMalloc(sizeof(struct pag));
    objary[i].z.pagptr->x = x;
    objary[i].z.pagptr->y = y;
    objary[i].z.pagptr->font = font;
    objary[i].z.pagptr->point = point;
    objary[i].z.pagptr->color = color;
    objary[i].type = OBJ_PAG;
    objary[i].opsptr = &pag_ops;
    objary[i].layer = layer;
    return i;
}

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

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

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

    to->z.pagptr = (struct pag *)XtMalloc(sizeof(struct pag));
    to->z.pagptr->font = from->z.pagptr->font;
    to->z.pagptr->point = from->z.pagptr->point;
    to->z.pagptr->x = from->z.pagptr->x;
    to->z.pagptr->y = from->z.pagptr->y;
    to->z.pagptr->color = from->z.pagptr->color;
    to->type = OBJ_PAG;
    to->layer = from->layer;
    to->opsptr = &pag_ops;
    to->rlist = copyRectList(from->rlist);
}

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

static void 
rem_page(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.pagptr);
    rem_object(objptr);
}

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

static void 
lim_page(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_page()
 *
 * INPUTS:
 *      i       (int)
 *
 * OUTPUTS:
 *
 * RETURNS:
 *
 * EXTERNALLY READ:
 *
 * EXTERNALLY MODIFIED:
 *
 * DESCRIPTION:
 *      locates position of page object i
 */

static void 
loc_page(int i, int dir)
{
    struct pag *pagptr;         /* local pointer */
    XRectangle r;               /* rectangle */
    char buf[20];		/* temp buffer */

    pagptr = objary[i].z.pagptr;
    (void)sprintf(buf, " Page %d of %d ", current_page, num_pages);
    r.width = gr_strwidth(buf, pagptr->font|pagptr->point);
    r.height = gr_txheight(pagptr->font|pagptr->point) + 1;
    r.x = pagptr->x;
    r.y = pagptr->y;
    setRectList(objary[i].rlist, 1, &r, RL_PRIMARY);
}

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

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

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

static void 
dsp_page(int i)
{
    struct pag *pagptr;         /* local pointer */
    char buf[20];		/* temp buffer */
    int height;			/* height of text */

    pagptr = objary[i].z.pagptr;
    (void)sprintf(buf, "Page %d of %d", current_page, num_pages);
    gr_set_color(color_name[pagptr->color], color_gscale[pagptr->color]);
    height = gr_txheight(pagptr->font|pagptr->point);
    gr_text(pagptr->x, pagptr->y + height, buf, GR_LEFT,
       (pagptr->font|pagptr->point), 0);
}

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

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

    (void)sprintf(buf, "Page Number: %d ", current_page);
    Message(buf);
}

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

static void 
sav_page(int i, FILE *fp, int dir)
{
    struct pag *pagptr;
    char buf[256];

    pagptr = objary[i].z.pagptr;
    buf[0] = 'P';
    buf[1] = ' ';
    record_print(buf + 2, "dddddd", pagptr->x, pagptr->y, pagptr->font,
	 pagptr->point, objary[i].layer, pagptr->color);
    fputs(buf, fp);
}

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

static int 
load_page(char *buf)
{
    int x, y, font, point, layer, color;
    int i;

    if (record_scan(buf + 1, "dddddd", &x, &y, &font, &point, &layer, &color)
	 == 6) {
	if ((x < xlnary[0].z.lnptr->cord) || 
	    (x > xlnary[nxln-1].z.lnptr->cord)) {
	    Warning("Illegal Page x %d", x);
	} else if ((y < ylnary[0].z.lnptr->cord) || 
	    (y > ylnary[nyln-1].z.lnptr->cord)) {
	    Warning("Illegal Page y %d", y);
	} else if ((font != GR_COURIER) && (font != GR_COURIER_BOLD) &&
		(font != GR_HELVETICA) && (font != GR_HELVETICA_BOLD) &&
		(font != GR_TIMES) && (font != GR_TIMES_BOLD)) {
	    Warning("Illegal Page font %d", font);
	} else if ((point != 8) && (point != 10) && (point != 12) &&
	    (point != 14) && (point != 18) && (point != 24)) {
	    Warning("Illegal Page point %d", point);
	} else if ((layer < 0) || (layer > 3)) {
	    Warning("Illegal Page layer %d", layer);
	} else if ((color < 0) || (color > ncolor)) {
	    Warning("Illegal Page color %d", color);
	} else {
            i = add_page(x, y, font, point, layer, color);
            (*(objary[i].opsptr->loc))(i, OBJECT);
            return 0;
	}
        return -1;
    } else {
        return -1;
    }
}

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

static void 
edt_page(int i, int new)
{

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

    (*(objary[i].opsptr->cpy))(&objtmp, &objary[i]);
    new_point =  objtmp.z.pagptr->point;
    new_font  =  objtmp.z.pagptr->font;
    new_color  =  objtmp.z.pagptr->color;
    new_drawlyr = objtmp.layer;
    if (new) {
        (*(objary[i].opsptr->rem))(i, OBJECT);
        i = -1;
    }

    DialogOptionSet(font, (int)new_font);
    DialogOptionSet(point, (int)new_point);
    DialogOptionSet(color, (int)new_color);
    DialogOptionSet(drawlyr, (int)new_drawlyr);
    EditObject(i, page_dialog);
}

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

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

    if (new_font != objtmp.z.pagptr->font) {
	change |= DIALOG_UPDATE;
    }
    objtmp.z.pagptr->font = DialogOptionGet(font);

    if (new_point != objtmp.z.pagptr->point) {
	change |= DIALOG_UPDATE;
    }
    objtmp.z.pagptr->point = DialogOptionGet(point);

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

    if (new_drawlyr != objtmp.layer) {
	change |= DIALOG_UPDATE;
    }
    objtmp.layer = DialogOptionGet(drawlyr);
    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_point()
 *
 * INPUTS:
 *      button  (Widget)
 *      option, any_data        (XtPointer)
 *
 * OUTPUTS:
 *
 * RETURNS:
 *
 * EXTERNALLY READ:
 *
 * EXTERNALLY MODIFIED:
 *
 * DESCRIPTION:
 *      sets new font point size for page object
 */

static void 
change_point(Widget button, XtPointer option, XtPointer any_data)
{
    new_point = (int)option;
}

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

static void 
change_font(Widget button, XtPointer option, XtPointer any_data)
{
    new_font = (int)option;
}

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

static void 
change_color(Widget button, XtPointer option, XtPointer any_data)
{
    new_color = (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:
 *      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) {
        pag_ok_button();
    }
}

