/***********************************************************************
 *
 * TITLE:
 *	hline.c
 *
 * AUTHOR:
 *	Cassie Mulnix
 *
 * DESCRIPTION:	
 *	This module is part of the OPPS editor: xopps.  It contains
 *	routines for horizontal line objects.
 *
 *                              CHANGE HISTORY
 *
 * $Log: hline.c,v $
 * Revision 1.58  1994/12/31  04:01:53  kevin
 * fixed memory allocation problem after DialogTextGet
 *
 * Revision 1.57  1994/10/12  23:45:11  cassie
 * declared new variable
 *
 * Revision 1.56  1994/10/12  23:43:44  cassie
 * fixed load_hline to reset to default values
 *
 * Revision 1.55  1994/10/12  23:24:58  cassie
 * check length of text in load_hline
 *
 * Revision 1.54  1994/09/12  21:40:48  cassie
 * added case in add_hline if text is NULL
 *
 * Revision 1.53  1994/08/10  22:02:18  cassie
 * fixed DialogFlagSet calls
 *
 * Revision 1.52  1994/07/20  19:06:35  clm
 * updated TRUE, ERROR etc in cancel & ok_button functions
 * to DIALOG_ constants
 *
 * Revision 1.51  1994/06/16  21:55:48  clm
 * updated to new dialog routines - extra parameter to DialogTextCreate
 *
 * Revision 1.50  1994/06/16  16:56:35  clm
 * updated to new gr_ routines using GR_ for font names
 *
 * Revision 1.49  1994/06/08  18:47:59  clm
 * removed Xm library includes since they are in dialog
 *
 * Revision 1.48  1994/06/07  16:36:33  clm
 * fixed ok button, testing change on last text value
 *
 * Revision 1.47  1994/06/07  00:04:01  clm
 * malloc correction in edt_hline
 *
 * Revision 1.46  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.45  1994/05/20  23:31:43  clm
 * updated with HP, SGI changes
 *
 * Revision 1.44  1994/05/04  23:34:36  clm
 * ported to ANSI C
 *
 * Revision 1.43  1993/09/13  22:04:17  clm
 * increased buffer length for text in load_hline
 *
 * Revision 1.42  1993/05/21  16:01:58  clm
 * fixed buffer size for sav function
 *
 * Revision 1.41  1993/05/18  22:39:41  clm
 * added meaningful error messages for check_num and check_day
 *
 * Revision 1.40  1993/05/18  20:58:30  clm
 * added new message.c function
 *
 * Revision 1.39  1993/02/08  16:06:32  clm
 * fixed loc_function for y2
 *
 * Revision 1.38  1992/12/11  21:29:08  clm
 * add hlines with RSRC FONT and POINT
 *
 * Revision 1.37  1992/12/08  23:22:04  clm
 * made number display same font and point as hline text
 *
 * Revision 1.36  1992/11/24  18:37:52  clm
 * changed loc_pline loop from MAX_PLN to npln
 *
 * Revision 1.35  1992/11/09  16:29:40  clm
 * added precedence lines.
 *
 * Revision 1.34  1992/10/22  21:52:03  clm
 * housekeeping
 *
 * Revision 1.33  1992/10/19  19:34:46  clm
 * fixed refresh for all pages
 *
 * Revision 1.32  1992/10/16  14:47:12  clm
 * changed free, realloc, and malloc to Xt functions
 *
 * Revision 1.31  1992/10/02  20:16:06  clm
 * housekeeping
 *
 * Revision 1.30  1992/09/24  15:42:51  clm
 * fixed comments of file
 *
 * Revision 1.29  1992/09/16  14:55:21  clm
 * fixed load function so doesn't add object if error in load
 *
 * Revision 1.28  1992/09/02  15:32:50  clm
 * fixed ren_hline
 *
 * Revision 1.25  1992/08/28  18:58:18  clm
 * removed unused variables
 *
 * Revision 1.24  1992/08/26  19:50:29  clm
 * changed color of hline text display
 *
 * Revision 1.23  1992/08/26  19:48:03  clm
 * changed message call to warning
 *
 * Revision 1.22  1992/08/26  16:41:19  clm
 * fixed error checking for font
 *
 * Revision 1.21  1992/08/25  15:46:36  clm
 * edited to reflect addition of xlnary and ylnary
 *
 * Revision 1.20  1992/08/20  20:18:50  clm
 * changed hline grid options to use gr_routines
 *
 * Revision 1.18  1992/08/13  18:07:00  clm
 * fixed bug in ins_hline
 *
 * Revision 1.16  1992/08/04  17:01:10  clm
 * changed malloc and free to XtMalloc and XtFree
 *
 * Revision 1.15  1992/08/03  21:33:52  clm
 * set font for displaying line numbers
 *
 * Revision 1.14  1992/07/13  20:49:32  clm
 * added color pointer
 * added load and sav functions
 *
 * Revision 1.13  1992/07/08  19:48:57  clm
 * changed add_hline call to reflect color value
 *
 * Revision 1.12  1992/07/06  17:47:27  clm
 * got all functions working
 *
 * Revision 1.11  1992/06/24  17:12:33  clm
 * complete move, delete, insert, and edit callbacks
 * filled in all functions
 *
 * Revision 1.10  1992/06/03  16:40:35  clm
 * updated dialog shell
 *
 * Revision 1.9  1992/05/22  17:02:18  clm
 * fixed dsp_hline routine
 *
 * Revision 1.5  1992/05/21  19:44:08  clm
 * changed to incorporate rectangle routines
 *
 ***********************************************************************
 *
 * WARNINGS:
 *
 * EXTERNAL CALLABLE COMPONENTS (PUBLIC):
 *
 * GLOBALS:
 *
 * WAIVERS:
 *
 * NOTES:
 *
 * MANPAGE:
 *
 ***********************************************************************/

#ifndef lint
static char rcsid[] = "$Id: hline.c 1.4 1/25/90 JPL";
#endif

/*
    hline.c - an XOPPS module to handle horizontal line objects
*/

/*************************************************************************
    global functions:
        init_hline_object()	-- initialize static number of lines (MAX_LINE) 
        tog_hline(i)	-- toggle to draw grapical line 
        ins_hline(i)	-- insert new line
        add_hline()	-- add values to a horizontal line
***************************************************************************/

/*
    local functions:
        dsp_hline(i) - dsp_lin hline object
        rem_hline(i) - turn off hline object
        mov_hline(i) - move hline object
        msg_hline(i) - dsp_lin message on screen
	edt_hline(i) - edit the hline object
	lim_hline(i) - limits hline object movement
	loc_hline(i) - locates the hline object
	cpy_hline(i) - copies hline object values
	sav_hline(i) - saves hline object
	ren_hline(i) - renumber input_number 
*/

#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 void hline_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_ldisp(Widget, XtPointer, XtPointer);
static void change_grid(Widget, XtPointer, XtPointer);
static void change_ndisp(Widget, XtPointer, XtPointer);
static void dsp_hline(int);
static void edt_hline(int, int);
static void rem_hline(int, int);
static void lim_hline(int, int *, int *, int *, int *, int);
static void loc_hline(int, int);
static void mov_hline(int, int, int, int);
static void cpy_hline(struct obj *, struct obj *);
static void msg_hline(int, int);
static void sav_hline(int, FILE *, int);
static int load_hline(char *);
void ren_hline(void);			/* renumber horiz. lines */
void mov_lines(int, int);		/* moves lines */
void delete_hline(int);			/* deletes line */
static void verify_fun(Widget, XtPointer, XtPointer);

static struct ops hln_ops = {
    dsp_hline, edt_hline, rem_hline, lim_hline, loc_hline, mov_hline, 
    cpy_hline, msg_hline, sav_hline
    };

static DialogOption *numdisp;
static DialogText *ntd, *text;
static DialogOption *line, *grid;
static DialogOption *font, *point;

static Widget hline_dialog;			/* dialog shell for popup */
static int new_point;                             /* new point id */
static int new_font;                              /* new font id */
static int new_ldisp;
static int new_grid;
static int new_ndisp;
static Widget parent_shell;

/***********************************************************************
 *
 * FUNCTION:
 *	init_hline_object()
 *
 * INPUTS:
 *	parent	(Widget)
 *
 * OUTPUTS:
 *	none
 *
 * RETURNS:
 *	none
 *
 * EXTERNALLY READ:
 *	none
 *
 * EXTERNALLY MODIFIED:
 *	none
 *
 * DESCRIPTION:
 *	register the horizontal line object and set the parent
 */

void 
init_hline_object(Widget parent)
{

    register_io_obj('H', load_hline);		/* register object */
    parent_shell = parent;
}

/***********************************************************************
 *
 * FUNCTION:
 *	create_dialog()
 *
 * INPUTS:
 *	none
 *
 * OUTPUTS:
 *	none
 *
 * RETURNS:
 *	none
 *
 * EXTERNALLY READ:
 *	none
 *
 * EXTERNALLY MODIFIED:
 *	none
 *
 * DESCRIPTION:
 *	allocate all hln objects initially and set up widgets for edit
 *	popup 
 */

static void 
create_dialog(void)
{
    static char *nums[] = { "Number Off", "Number On" };
    static char *lines[] = { "Line Off", "Line On" };
    static char *grids[] = { "Solid", "Thick", "Dotted", "Short Dash",
	"Long Dash" };
    static char *fonts[] = { "Courier", "Courier Bold", "Helvetica",
        "Helvetica Bold", "Times", "Times Bold" };
    static char *points[] = { "8", "10", "12", "14", "18", "24" };

    register_io_obj('H', load_hline);		/* register object */

    hline_dialog = DialogInit(parent_shell, "Horizontal Line Dialog", "hline",
	verify_fun, (XtPointer)DIALOG_CANCEL);

    DialogAddRow(2);
    numdisp = DialogOptionCreate("Number Display ", 2, 1, change_ndisp, 
	DIALOG_OPT_STR_ARY, nums, NULL);
    ntd = DialogTextCreate("Number To Display ", 3, 3);

    text = DialogTextCreate("Text ", 50, 100);

    line = DialogOptionCreate("Line Display ", 2, 1, change_ldisp, 
	DIALOG_OPT_STR_ARY, lines, NULL);

    grid = DialogOptionCreate("Line Grid Type ", 5, 0, change_grid, 
	DIALOG_OPT_STR_ARY, grids, NULL);

    DialogAddRow(2);
    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);

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

}

/***********************************************************************
 *
 * FUNCTION:
 *      hline_init()
 *
 * INPUTS:
 *
 * OUTPUTS:
 *
 * RETURNS:
 *
 * EXTERNALLY READ:
 *
 * EXTERNALLY MODIFIED:
 *
 * DESCRIPTION:
 *      allocate all hln objects initially
 */

void 
hline_init(void)
{
    int our_num;			/* "actual" line number */
    int co;				/* current object index */

    for (our_num=1; our_num <= MAX_LINE; our_num++) {
	co = new_H_index();
        Hobjary[co].z.hlnptr = XtNew(struct hln);
        hln_objary[our_num] = co;
        Hobjary[co].z.hlnptr->text = XtNewString("");
	add_hline(our_num,our_num,all_line_dsp,all_num_dsp,
	    2, RSRC_FONT, RSRC_POINT, all_grid_dsp,"");
	(*(Hobjary[co].opsptr->loc))(co, OBJECT);
    }
	/* last MAX_LINE position is for swap area in mov_lines */
}

/***********************************************************************
 *
 * FUNCTION:
 *	add_hline
 *
 * INPUTS:
 *	our_num, input_num	(int)
 *	dsp_lin, dsp_num	(enum tog)
 *	color, font, point	(int)
 *	grid	(enum grid_typ)
 *	text	(char *)
 *
 * OUTPUTS:
 *
 * RETURNS:
 *
 * EXTERNALLY READ:
 *
 * EXTERNALLY MODIFIED:
 *
 * DESCRIPTION:
 *	adds a horizontal line during init_hline, each later call changes
 *	the values only since the horizontal lines always exist
 */

int 
add_hline(int our_num, int input_num, enum tog dsp_lin, enum tog dsp_num, int color, int font, int point, enum grid_typ grid, char *text)
{
    int co;              /* object array index */

    co = hln_objary[our_num];
    Hobjary[co].z.hlnptr->our_num = our_num;
    Hobjary[co].z.hlnptr->input_num = input_num;
    Hobjary[co].z.hlnptr->dsp_lin = dsp_lin;
    Hobjary[co].z.hlnptr->dsp_num = dsp_num;
    Hobjary[co].z.hlnptr->color = color;
    Hobjary[co].z.hlnptr->font = font;
    Hobjary[co].z.hlnptr->point = point;
    Hobjary[co].z.hlnptr->grid = grid;
    if (Hobjary[co].z.hlnptr->text != NULL) {
	XtFree(Hobjary[co].z.hlnptr->text);
    }
    Hobjary[co].z.hlnptr->text = XtNewString(text);
    Hobjary[co].type = OBJ_HLN;
    Hobjary[co].layer = 0;
    Hobjary[co].opsptr = &hln_ops;
    return co;
}

/***********************************************************************
 *
 * FUNCTION:
 *	ren_hline()
 *
 * INPUTS:	
 *
 * OUTPUTS:
 *
 * RETURNS:
 *
 * EXTERNALLY READ:
 *
 * EXTERNALLY MODIFIED:
 *
 * DESCRIPTION:	
 *	renumber the input numbers of all lines with number toggle ON
 */

void 
ren_hline(void)		
{
    int new_num = 1;			/* renumbering value */
    int i, co;				/* temp indices */

    for (i = 1; i <= MAX_LINE; i++) {
	co = hln_objary[i];
	if (Hobjary[co].z.hlnptr->dsp_num == TOG_ON) {
	    Hobjary[co].z.hlnptr->input_num = new_num++;
	}
    }
    num_mode = L_NONE;    		/* for display routine */
}

/***********************************************************************
 *
 * FUNCTION:
 *	mov_lines()
 *
 * INPUTS:
 *	old_num, new_num	(int)
 *
 * OUTPUTS:
 *
 * RETURNS:
 *
 * EXTERNALLY READ:
 *
 * EXTERNALLY MODIFIED:
 *
 * DESCRIPTION:	
 *	adjust lines to make room for an inserted or deleted line
 *	and place the selected line. All objects on the line are
 *	also moved.  old_num is moving to new_num and all the
 *	lines in between are moved one location in the direction
 *	of the move
 */

void 
mov_lines(int old_num, int new_num)
{
    int i, tempco, co;			/* general indices */
	
    tempco = hln_objary[old_num];   	/* temporary save of the selected line*/
    if (new_num < old_num) {
      /* 
       * shift down Lines[new_num] .. Lines[old_num] for an insert
       * the inserted line will appear above the line that the
       * cursor was on when insert line was selected 
       * the line is moved from the last location onto the selected
       * line and everything else is moved down
       * 
       * new_num+1 is the line the cursor was on when insert was selected
       * new_num+1 is also equal to new_num
       *
       * Old Screen			New Screen
       * 
       *  [new_num-1]			  [new_num-1]
       *  [new_num+1]		          [old_num]
       *  [new_num+2]			  [new_num]
       *  [ ... ]			  [new_num+1]
       *  [MAX_LINE-1]			  [...]
       *  [old_num]			  [MAX_LINE]
       *
       * used similarly for moving a line up on the screen
       */
	for (i=old_num-1; i>=new_num; i--) {
	   /*
	    * moves all objects down
            */
	    co = hln_objary[i];
	    Hobjary[co].z.hlnptr->our_num++;
	    hln_objary[i+1] = hln_objary[i];
	    if (co != MAX_LINE) {     
       		/* since MAX_LINE indexes a buffer */
	    	(*(Hobjary[co].opsptr->loc))(co, OBJECT);	
	    }
	}

    } else if (new_num > old_num) {

      /* 
       * shift up Lines[old_num] .. Lines[new_num] for an delete 
       * the line is moved to the end of the list and all of
       * the lines are shifted upwards
       * 
       * Old Screen			New Screen
       * 
       *  [old_num-1]			  [old_num-1]
       *  [old_num]	 		  [old_num+1]
       *  [old_num+1]		          [old_num+2]
       *  [old_num+2]			  [ ... ]
       *  [ ... ]			  [MAX_LINE-1]
       *  [MAX_LINE]			  [new_num]
       *
       * used similarly for moving a line down on the screen
       */

	for (i=old_num+1; i<=new_num; i++) { 
	   /*
	    * moves all objects up
            */
            co = hln_objary[i]; 
            Hobjary[co].z.hlnptr->our_num--; 
            hln_objary[i-1] = hln_objary[i]; 
    	    if (Hobjary[co].rlist == NULL) {	/* so can be exposed*/
		Hobjary[co].rlist = newRectList(0);
    	    }
	   (*(Hobjary[co].opsptr->loc))(co, OBJECT);	
	}

    } else {
	return;		/* no change */
    }	

    /*
     * places deleted line
     */

    hln_objary[new_num] = tempco;
    Hobjary[tempco].z.hlnptr->our_num = new_num;
    (*(Hobjary[tempco].opsptr->loc))(tempco, OBJECT);

    /*
     * dated objects move with their line so 
     * move objects on line to new line position 
     * i > 1 is checked since i = 0 is always the chart object
     */
    for (co = 0; co < nobj; co++) {
	    switch (objary[co].type) {
	    case OBJ_EVT:
		i= objary[co].z.evtptr->line; 
		if ((i <= new_num) && (i > old_num) && (i > 1)) {
		    objary[co].z.evtptr->line--;
        	} else if ((i >= new_num) && (i < old_num) && (i < MAX_LINE)) {
                    objary[co].z.evtptr->line++; 
		} else if (i == old_num) {
		    objary[co].z.evtptr->line = new_num;
		}
	 	(*(objary[co].opsptr->loc))(co, OBJECT);
		for (i = 0; i < npln; i++) {
		    loc_pline(i, OBJECT);
 		}
	 	break;
	    case OBJ_ACT:
		i = objary[co].z.actptr->line;
		if ((i <= new_num) && (i > old_num) && (i > 1)) {
	    	    objary[co].z.actptr->line--;
        	} else if ((i >= new_num) && (i < old_num) && (i < MAX_LINE)) {
                    objary[co].z.actptr->line++; 
		} else if (i == old_num) {
		    objary[co].z.actptr->line = new_num;
		}
	 	(*(objary[co].opsptr->loc))(co, OBJECT);
		for (i = 0; i < npln; i++) {
		    loc_pline(i, OBJECT);
 		}
		break;
	    case OBJ_SACT:
		i = objary[co].z.sactptr->line;
		if ((i <= new_num) && (i > old_num) && (i > 1)) {
		    objary[co].z.sactptr->line--;
        	} else if ((i >= new_num) && (i < old_num) && (i < MAX_LINE)) {
                    objary[co].z.sactptr->line++; 
		} else if (i == old_num) {
		    objary[co].z.sactptr->line = new_num;
		}
	 	(*(objary[co].opsptr->loc))(co, OBJECT);
		for (i = 0; i < npln; i++) {
		    loc_pline(i, OBJECT);
 		}
		break;
	    case OBJ_SEQ:
		i = objary[co].z.seqptr->line;
		if ((i <= new_num) && (i > old_num) && (i > 1)) {
		    objary[co].z.seqptr->line--;
        	} else if ((i >= new_num) && (i < old_num) && (i < MAX_LINE)) {
                    objary[co].z.seqptr->line++; 
		} else if (i == old_num) {
		    objary[co].z.seqptr->line = new_num;
		}
	 	(*(objary[co].opsptr->loc))(co, OBJECT);
		for (i = 0; i < npln; i++) {
		    loc_pline(i, OBJECT);
 		}
		break;
	    case OBJ_SLP:
		i = objary[co].z.slpptr->line;
		if ((i <= new_num) && (i > old_num) && (i > 1)) {
	   	    objary[co].z.slpptr->line--;
        	} else if ((i >= new_num) && (i < old_num) && (i < MAX_LINE)) {
                    objary[co].z.slpptr->line++; 
		} else if (i == old_num) {
		    objary[co].z.slpptr->line = new_num;
		}
	 	(*(objary[co].opsptr->loc))(co, OBJECT);
		for (i = 0; i < npln; i++) {
		    loc_pline(i, OBJECT);
 		}
		break;
	    default:
		break;	
	    }
    }
	
    /* 
     * renumber lines 
     */
    if (auto_renum == TOG_ON) {
    	ren_hline();
    }
}

/***********************************************************************
 *
 * FUNCTION:
 *	rem_hline()
 *
 * INPUTS:
 *	i	(int)
 *
 * OUTPUTS:
 *
 * RETURNS:
 *
 * EXTERNALLY READ:
 *
 * EXTERNALLY MODIFIED:
 *
 * DESCRIPTION:	
 *	removes horizontal line object i from being displayed, line
 *	always exists
 */

static void 
rem_hline(int i, int dir)
{
    int del_line;				/* temporary line number */
    int tempco;					/* temporary object index */
    XRectangle r;				/* expose rectangle */
 
    del_line = Hobjary[i].z.hlnptr->our_num; 	/* deleted line */
    exposeRectList(1, Hobjary[del_line].rlist);

    /* remove objects on deleted line */
    for (tempco = 0; tempco < nobj; tempco++) {
	switch (objary[tempco].type) {
        case OBJ_EVT:
   	    if (objary[tempco].z.evtptr->line == del_line) {
		(*(objary[tempco].opsptr->rem))(tempco, OBJECT);
	    }
	    break;
	case OBJ_ACT:
            if (objary[tempco].z.actptr->line == del_line) {
	        (*(objary[tempco].opsptr->rem))(tempco, OBJECT);
	    }
	    break;
	case OBJ_SACT:
            if (objary[tempco].z.sactptr->line == del_line) {
	        (*(objary[tempco].opsptr->rem))(tempco, OBJECT);
	    }
	    break;
	case OBJ_SEQ:
            if (objary[tempco].z.seqptr->line == del_line) {
	        (*(objary[tempco].opsptr->rem))(tempco, OBJECT);
	    }
	    break;
	case OBJ_SLP:
            if (objary[tempco].z.slpptr->line == del_line) {
	        (*(objary[tempco].opsptr->rem))(tempco, OBJECT);
	    }
	    break;
	default:
	    break;
	}
    }

    /* reset hline object for swap area */
    add_hline(del_line, del_line, all_line_dsp, all_num_dsp, 
	objary[0].z.chtptr->color, RSRC_FONT, RSRC_POINT, all_grid_dsp, "");
    mov_lines(del_line, MAX_LINE);

    /* since you are deleting it, it is
     * no longer on screen.  So you must
     * expose one that is 
     */
    for (tempco = 0; tempco < Hnobj; tempco++) {
	if (Hobjary[tempco].z.hlnptr->our_num == 1) {
	    break;
	}
    }
    r.x = 0;
    r.y = 0;
    r.width = page_width;
    r.height = page_height;
    AddExposeEvent(0, &r);
}

/***********************************************************************
 *
 * FUNCTION:
 *      delete_hline()
 *
 * INPUTS:
 *      i       (int)
 *
 * OUTPUTS:
 *
 * RETURNS:
 *
 * EXTERNALLY READ:
 *
 * EXTERNALLY MODIFIED:
 *
 * DESCRIPTION:
 *      deletes horizontal line object i for setting up new screen 
 */

void 
delete_hline(int i)
{
    freeRectList(Hobjary[i].rlist);
    XtFree(Hobjary[i].z.hlnptr->text);
    Hobjary[i].z.hlnptr->text = NULL;
    XtFree((char *)Hobjary[i].z.hlnptr);
    rem_H_object(i);
}

/***********************************************************************
 *
 * FUNCTION:
 *	ins_hline()
 *
 * INPUTS:
 *	co	(int)
 *
 * OUTPUTS:
 *
 * RETURNS:
 *
 * EXTERNALLY READ:
 *
 * EXTERNALLY MODIFIED:
 *
 * DESCRIPTION:	
 *	inserts new line at co line object and move all other lines down
 */

void 
ins_hline(int co)
{
    int line;              /* line number for insert  */
    int tempco;		   /* must expose line that is on the page */
    XRectangle r;	   /* expose rectangle */

    line = Hobjary[co].z.hlnptr->our_num; 
    exposeRectList(1, Hobjary[line].rlist);
    /*
     * call add to change the display values only
     */
    add_hline(MAX_LINE, MAX_LINE, all_line_dsp, all_num_dsp,
	objary[0].z.chtptr->color, RSRC_FONT, RSRC_POINT, all_grid_dsp, "");
    /* 
     * move MAX_LINE to line position 
     */
    mov_lines(MAX_LINE, line);
    for (tempco = 0; tempco < Hnobj; tempco++) {
	if (Hobjary[tempco].z.hlnptr->our_num == 1) {
	    break;
	}
    }
    r.x = 0;
    r.y = 0;
    r.width = page_width;
    r.height = page_height;
    AddExposeEvent(0, &r);
}

/***********************************************************************
 *
 * FUNCTION:
 *	dsp_hline()
 *
 * INPUTS:
 *	i	(int)
 *
 * OUTPUTS:
 *
 * RETURNS:
 *
 * EXTERNALLY READ:
 *
 * EXTERNALLY MODIFIED:
 *
 * DESCRIPTION:
 *	display horizontal line object i from the data base
 */

static void 
dsp_hline(int i)
{
    struct hln *hlnptr;         /* local pointer */
    XRectangle *(*r)[];		/* rectangle */
    char buffer[5];             /* line number to print */
    int ln_pos;                 /* line position */
    int htpos;                  /* text height position */

    hlnptr = Hobjary[i].z.hlnptr;
    gr_set_color(color_name[hlnptr->color], color_gscale[hlnptr->color]);
    ln_pos = hlnptr->our_num;
    if ((ln_pos >= page_begin) && (ln_pos <= page_end)) {
    	r = getMoveRect(Hobjary[i].rlist);

    	/*
     	* if the display line toggle is on, draw the line
     	*/
    	if (hlnptr->dsp_lin == TOG_ON) {
            if ((hlnptr->grid == G_THICK) || (hlnptr->grid == G_SOLID)) {
                gr_line((*r)[0]->x, (*r)[0]->y +(*r)[0]->height,
                    x_right_margin, (*r)[0]->y+(*r)[0]->height);
            } else if (hlnptr->grid == G_DOT_LINE) {
		gr_set_line(GR_DOT_LINE);
		gr_line((*r)[0]->x, (*r)[0]->y + (*r)[0]->height,
		     x_right_margin, (*r)[0]->y+(*r)[0]->height);
		gr_set_line(GR_SOLID_LINE);
            } else if (hlnptr->grid == G_SHORT_DASH) {
		gr_set_line(GR_SHORT_DASH);
		gr_line((*r)[0]->x, (*r)[0]->y + (*r)[0]->height,
                     x_right_margin, (*r)[0]->y+(*r)[0]->height);
                gr_set_line(GR_SOLID_LINE);
	    } else {
		gr_set_line(GR_LONG_DASH);
		 gr_line((*r)[0]->x, (*r)[0]->y + (*r)[0]->height,
                     x_right_margin, (*r)[0]->y+(*r)[0]->height);
                gr_set_line(GR_SOLID_LINE);
	    }
            if (hlnptr->grid == G_THICK) {
                gr_line((*r)[0]->x,(*r)[0]->y+(*r)[0]->height+1,x_right_margin, 
		    (*r)[0]->y+(*r)[0]->height+1);
            }
        }
        htpos = (*r)[0]->y + y_gap/2 + (gr_txheight(hlnptr->font|
           hlnptr->point))/2 + 2;
        /*
         * if the display number toggle is on, display the line number 
         */
        if (hlnptr->dsp_num == TOG_ON) {
             (void)sprintf(buffer, "%d", hlnptr->input_num);
             gr_text(x_num_offset-7, htpos, buffer, GR_CENTER,
		hlnptr->font|hlnptr->point, 0);
        }
        /*
         * print the text that appears on the line
         */
	gr_set_color(color_name[0], color_gscale[0]);
        gr_text((*r)[0]->x + 28, htpos, hlnptr->text, GR_LEFT, (hlnptr->font|
             hlnptr->point), 0);
   }
}

/***********************************************************************
 *
 * FUNCTION:
 *	msg_hline()
 *
 * INPUTS:
 *	i	(int)
 *
 * OUTPUTS:
 *
 * RETURNS:
 *
 * EXTERNALLY READ:
 *
 * EXTERNALLY MODIFIED:
 *
 * DESCRIPTION:
 *	displays horizontal line message on the screen	
 */

static void 
msg_hline(int i, int dir)
{
    Message("Move Horizontal Line");
}
/***********************************************************************
 *
 * FUNCTION:
 *	mov_hline()
 *
 * INPUTS:
 *	i 			(int)
 *	our_num, input_num	(int)
 *
 * OUTPUTS:
 *
 * RETURNS:
 *
 * EXTERNALLY READ:
 *
 * EXTERNALLY MODIFIED:
 *
 * DESCRIPTION: 
 *	moves horizontal lines on the screen
 */

static void 
mov_hline(int i, int x, int y, int dir)
{
    int line;			/* temp line index */
    int top_of_page;		/* index of line at top of page */
    struct hln *hlnptr;		/* Horiz. line pointer */
 
    hlnptr = Hobjary[i].z.hlnptr;
    if ((y >= y_act_bottom) && (y < y_lines_end)) {
	top_of_page = (current_page - 1) * pg_lines + 1;
	line = ((y + 1 - y_act_bottom) / y_gap) + top_of_page;
	mov_lines(hlnptr->our_num, line);
    } else {
	Warning("Cannot move line into that area");
    }
}

/***********************************************************************
 *
 * FUNCTION:
 *	tog_hline()
 *
 * INPUTS:
 *	i	(int)
 *
 * OUTPUTS:
 *
 * RETURNS:
 *
 * EXTERNALLY READ:
 *
 * EXTERNALLY MODIFIED:
 *
 * DESCRIPTION:
 *	toggles value of display line
 */

void 
tog_hline(int i)
{
    char buf[40];

    if (Hobjary[i].z.hlnptr->dsp_lin == TOG_OFF) {
	(void)sprintf(buf, "Horizontal line %d display is ON", i+1);
   	Message(buf);
	Hobjary[i].z.hlnptr->dsp_lin = TOG_ON;
    } else {
	(void)sprintf(buf, "Horizontal line %d display is OFF", i+1);
   	Message(buf);
	Hobjary[i].z.hlnptr->dsp_lin = TOG_OFF;
    }
    exposeRectList(0, Hobjary[i].rlist);
}
/***********************************************************************
 *
 * FUNCTION:
 *	tog_hnum()
 *
 * INPUTS:
 *	i	(int)
 *
 * OUTPUTS:
 *
 * RETURNS:
 *
 * EXTERNALLY READ:
 *
 * EXTERNALLY MODIFIED:
 *
 * DESCRIPTION:
 *	toggle number display on line
 */

void 
tog_hnum(int i)
{
    char buf[40];

    if (Hobjary[i].z.hlnptr->dsp_num == TOG_OFF) {
	(void)sprintf(buf, "Horizontal line %d number is ON", i+1);
   	Message(buf);
    	Hobjary[i].z.hlnptr->dsp_num = TOG_ON;
    } else {
	(void)sprintf(buf, "Horizontal line %d number is OFF", i+1);
   	Message(buf);
    	Hobjary[i].z.hlnptr->dsp_num = TOG_OFF;
    }
    if (auto_renum == TOG_ON)
    	ren_hline();
    exposeRectList(0, Hobjary[i].rlist);
}

/***********************************************************************
 *
 * FUNCTION:
 *	all_numbers()
 *
 * INPUTS:
 *	num_tog	(enum tog)
 *
 * OUTPUTS:
 *
 * RETURNS:
 *
 * EXTERNALLY READ:
 *
 * EXTERNALLY MODIFIED:
 *
 * DESCRIPTION:
 *	turn all numbers on with our numbers or turn all off
 */

void 
all_numbers(enum tog num_tog)
{
    int i, co, new_num;

    new_num = 1;	
    for (i=1; i < MAX_LINE; i++) {
	co = hln_objary[i];
	Hobjary[co].z.hlnptr->dsp_num = num_tog;
	if (num_tog == TOG_ON)
           Hobjary[co].z.hlnptr->input_num = new_num++;
    }
    num_mode = L_NONE;    /* for display routine */
}

/***********************************************************************
 *
 * FUNCTION:
 *	all_lins()
 *
 * INPUTS:
 *	lin_tog	(enum tog)
 *
 * OUTPUTS:
 *
 * RETURNS:
 *
 * EXTERNALLY READ:
 *
 * EXTERNALLY MODIFIED:
 *
 * DESCRIPTION:	
 *	turn all numbers/lines on/off with our numbers
 */

void 
all_lins(enum tog lin_tog)
{
    int i, co;

    for (i=1; i < MAX_LINE; i++) {
	co = hln_objary[i];
	Hobjary[co].z.hlnptr->dsp_lin = lin_tog;
    }
    num_mode = L_NONE;    /* for display routine */
}
 
/***********************************************************************
 *
 * FUNCTION:
 *	all_grids()
 *
 * INPUTS:
 *	grid_mode	(enum grid_typ)
 *
 * OUTPUTS:
 *
 * RETURNS:
 *
 * EXTERNALLY READ:
 *
 * EXTERNALLY MODIFIED:
 *
 * DESCRIPTION:	
 *	change grid of all lines
 */

void 
all_grids(enum grid_typ grid_mode)
{
    int i, co;	/* line index */

    for (i=1; i < MAX_LINE; i++) {
	co = hln_objary[i];
   	Hobjary[co].z.hlnptr->grid = grid_mode;
    }
    all_grid_dsp = grid_mode;
}

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

static void 
lim_hline(int i, int *x1, int *y1, int *x2, int *y2, int dir)
{
    *x1 = 0;
    *y1 = y_act_bottom;
    *x2 = 0; 
    *y2 = y_lines_end - y_gap;
}

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

static void 
loc_hline(int i, int dir)
{
    struct hln *hlnptr;		/* local pointer */
    int ln_pos;			/* line position */
    XRectangle r1,r2;		/* rectangle */

    hlnptr = Hobjary[i].z.hlnptr;
    ln_pos = hlnptr->our_num;
    if ((ln_pos > page_end) || (ln_pos < page_begin)) {
	setRectList(Hobjary[i].rlist,0);
	return;
    }

    ln_pos = ln_pos % pg_lines;
    if (ln_pos == 0) {
	ln_pos = pg_lines;
    }

    /* rectangle for one horizontal line */
    r1.width = x_right_margin - x_left_margin - 3;
    r1.height = y_gap;
    r1.x = x_left_margin;
    r1.y = y_act_bottom + (ln_pos - 1)*r1.height; 

    r2.x = x_left_margin;
    r2.y = y_act_bottom + 1;
    r2.height = page_height - r2.y;
    r2.width = x_right_margin - x_left_margin - 3;

    setRectList(Hobjary[i].rlist, 2, &r1, RL_PRIMARY, &r2, RL_EXPOSE);
}

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

static void 
cpy_hline(struct obj *to, struct obj *from)
{
    if (from->type == OBJ_NUL) {
	return;
    }
    to->z.hlnptr = (struct hln *)XtMalloc(sizeof(struct hln));
    to->z.hlnptr->font = from->z.hlnptr->font;
    to->z.hlnptr->point = from->z.hlnptr->point;
    to->z.hlnptr->color = from->z.hlnptr->color;
    to->z.hlnptr->our_num = from->z.hlnptr->our_num;
    to->z.hlnptr->input_num = from->z.hlnptr->input_num;
    to->z.hlnptr->dsp_lin = from->z.hlnptr->dsp_lin;
    to->z.hlnptr->dsp_num = from->z.hlnptr->dsp_num;
    to->z.hlnptr->grid = from->z.hlnptr->grid;
    to->z.hlnptr->text = XtNewString(from->z.hlnptr->text);
    to->type = OBJ_HLN;
    to->opsptr = &hln_ops;
    to->rlist = copyRectList(from->rlist);
}

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

static void 
sav_hline(int i, FILE *fp, int dir)
{
    struct hln *hlnptr;
    char buf[1024];

    hlnptr = Hobjary[i].z.hlnptr;
    buf[0] = 'H';
    buf[1] = ' ';
    record_print(buf+2, "ddddddddq", hlnptr->our_num, hlnptr->input_num,
	hlnptr->dsp_lin, hlnptr->dsp_num, hlnptr->color, hlnptr->font,
	hlnptr->point, hlnptr->grid, hlnptr->text);
    fputs(buf, fp);
}

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

static int 
load_hline(char *buf)
{
    int our_num, input_num;
    enum tog dsp_lin, dsp_num;
    int color, font, point;
    enum grid_typ grid;
    char text[512];
    int i;
    int use_default;

    if (record_scan(buf + 1, "ddddddddq", &our_num, &input_num, &dsp_lin,
	&dsp_num, &color, &font, &point, &grid, text) == 9) {
	if ((our_num < 0) || (our_num  > MAX_LINE)) {
	    Warning("Illegal HLine our_num %d", our_num);
	    use_default = 0;
	} else if ((input_num < 0) || (input_num > MAX_LINE)) {
	    Warning("Illegal HLine input_num %d", input_num);
	    use_default = 0;
	} else if (((int)dsp_lin < 0) || ((int)dsp_lin > 1)) {
	    Warning("Illegal HLine display line %d", dsp_lin);
	    use_default = 1;
	} else if (((int)dsp_num < 0) || ((int)dsp_num > 1)) {
            Warning("Illegal HLine display number %d", dsp_num);
	    use_default = 1;
	} else if ((color < 0) || (color > ncolor)) {
	    Warning("Illegal HLine color %d", color);
	    use_default = 1;
	} 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 HLine font %d", font);
	    use_default = 1;
        } else if ((point != 8) && (point != 10) && (point != 12) &&
            (point != 14) && (point != 18) && (point != 24)) {
            Warning("Illegal HLine point %d", point);
	    use_default = 1;
        } else if (((int)grid < 0) || ((int)grid > 4)) {
	    Warning("Illegal HLine grid %d", grid);
	    use_default = 1;
	} else if (strlen(text) > 100) {
	    Warning("Hline text string is too long %s", text);
	    use_default = 1;
	} else {
            i = add_hline(our_num, input_num, dsp_lin, dsp_num, color, font,
	  	 point, grid, text);
            (*(Hobjary[i].opsptr->loc))(i, OBJECT);
            return 0;
	}
	if (use_default) {
	    /*
	     * reset line to default values only if you know line number
	     */
	    i = add_hline(our_num, input_num, all_line_dsp, all_num_dsp, 
		objary[0].z.chtptr->color, 0, 10, all_grid_dsp, "");
	    (*(Hobjary[i].opsptr->loc))(i, OBJECT);
	}
        return -1;
    } else {
        return -1;
    }
}

/***********************************************************************
 *
 * FUNCTION:
 *	edt_hline()
 *
 * INPUTS:
 *	i, new	(int)
 *
 * OUTPUTS:
 *
 * RETURNS:
 *
 * EXTERNALLY READ:
 *
 * EXTERNALLY MODIFIED:
 *
 * DESCRIPTION:	
 *	edits horizontal line object i
 */

static void 
edt_hline(int i, int new)
{
    char *buf;

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

    (*(Hobjary[i].opsptr->cpy))(&objtmp, &Hobjary[i]);
    new_point = objtmp.z.hlnptr->point;
    new_font = objtmp.z.hlnptr->font;
    new_ldisp = objtmp.z.hlnptr->dsp_lin;
    new_ndisp = objtmp.z.hlnptr->dsp_num;
    new_grid = objtmp.z.hlnptr->grid;
    if (new) {
	(*(Hobjary[i].opsptr->rem))(i, OBJECT);
	i = -1;
    }

    buf = (char *)XtMalloc(4 * sizeof(char));
    sprintf(buf, "%d", objtmp.z.hlnptr->input_num);
    DialogTextSet(ntd, buf);
    XtFree(buf);

    DialogOptionSet(font, (int)new_font);
    DialogOptionSet(point, (int)new_point);
    DialogOptionSet(line, (int)new_ldisp);
    DialogOptionSet(numdisp, (int)new_ndisp);
    DialogOptionSet(grid, (int)new_grid);

    DialogTextSet(text, objtmp.z.hlnptr->text);
    EditHObject(i, hline_dialog);
}

/***********************************************************************
 *
 * FUNCTION:
 *      change_point()
 *
 * INPUTS:
 *      button          - (Widget)
 *      option          - (XtPointer)
 *      any_data        - (XtPointer)
 *
 * OUTPUTS:
 *
 * RETURNS:
 *
 * EXTERNALLY READ:
 *
 * EXTERNALLY MODIFIED:
 *
 * DESCRIPTION:
 *	changes the point size to the option selected
 */

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

/***********************************************************************
 *
 * FUNCTION:
 *      change_font()
 *
 * INPUTS:
 *      button          - (Widget)
 *      option          - (XtPointer)
 *      any_data        - (XtPointer)
 *
 * OUTPUTS:
 *
 * RETURNS:
 *
 * EXTERNALLY READ:
 *
 * EXTERNALLY MODIFIED:
 *
 * DESCRIPTION:
 *	changes the selected font
 */

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

/***********************************************************************
 *
 * FUNCTION:
 *	change_ndisp()
 *
 * INPUTS:
 *	button		- (Widget)
 *	option		- (XtPointer)
 *	any_data	- (XtPointer)
 *
 * OUTPUTS:
 *
 * RETURNS:
 *
 * EXTERNALLY READ:
 *
 * EXTERNALLY MODIFIED:
 *
 * DESCRIPTION:	
 *	changes the number display option
 */

static void 
change_ndisp(Widget button, XtPointer option, XtPointer any_data)
{
    new_ndisp = (int)option;
}

/***********************************************************************
 *
 * FUNCTION:
 *	change_ldisp()
 *
 * INPUTS:
 *	button		- (Widget)
 *	option		- (XtPointer)
 *	any_data	- (XtPointer)
 *
 * OUTPUTS:
 *
 * RETURNS:
 *
 * EXTERNALLY READ:
 *
 * EXTERNALLY MODIFIED:
 *
 * DESCRIPTION:	
 *	changes the line display option
 */

static void 
change_ldisp(Widget button, XtPointer option, XtPointer any_data)
{
    new_ldisp = (int)option;
}

/***********************************************************************
 *
 * FUNCTION:
 *	change_grid()	
 *
 * INPUTS:
 *	button		- (Widget)
 *	option		- (XtPointer)
 *	any_data	- (XtPointer)
 *
 * OUTPUTS:
 *
 * RETURNS:
 *
 * EXTERNALLY READ:
 *
 * EXTERNALLY MODIFIED:
 *
 * DESCRIPTION:	
 *	changes the grid option
 */

static void 
change_grid(Widget button, XtPointer option, XtPointer any_data)
{
    new_grid = (int)option;
}

/***********************************************************************
 *
 * FUNCTION:
 *	hline_ok_button()
 *
 * INPUTS:
 *
 * OUTPUTS:
 *
 * RETURNS:
 *
 * EXTERNALLY READ:
 *
 * EXTERNALLY MODIFIED:
 *
 * DESCRIPTION:	
 *	sets the new values when ok is set and unmanages the window
 */

static void 
hline_ok_button(void)
{
    int change = DIALOG_NO_CHANGE;
    char *buf;
    int val;

    if (new_ndisp != (int)objtmp.z.hlnptr->dsp_num) {
	change |= DIALOG_UPDATE;
    }
    objtmp.z.hlnptr->dsp_num = DialogOptionGet(numdisp);

    if (new_ldisp != (int)objtmp.z.hlnptr->dsp_lin) {
	change |= DIALOG_UPDATE;
    }
    objtmp.z.hlnptr->dsp_lin = DialogOptionGet(line);

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

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

    if (new_grid != (int)objtmp.z.hlnptr->grid) {
	change |= DIALOG_UPDATE;
    }
    objtmp.z.hlnptr->grid = DialogOptionGet(grid);

    buf = DialogTextGet(text);
    if (strcmp(buf, objtmp.z.hlnptr->text)) {
	change |= DIALOG_UPDATE;
	XtFree(objtmp.z.hlnptr->text);
	objtmp.z.hlnptr->text = buf;
    } else {
	XtFree(buf);
    }

    val = DialogTextGetInt(ntd);
    if ((val < 0) || (val >= MAX_LINE)) {
	Warning("Invalid Number to Display");
	change |= DIALOG_ERROR;
    } else if (val != objtmp.z.hlnptr->input_num) {
	change |= DIALOG_UPDATE;
	objtmp.z.hlnptr->input_num = val;
    }

    hobject_change = change;
    if ((hobject_change) && (auto_renum)) {
	ren_hline();
    }
    DialogFlagSet(change);
}

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

/* ARGSUSED */
static void 
cancel_button(void)
{
    hobject_change = DIALOG_CANCEL;
    DialogFlagSet(DIALOG_CANCEL);
}

/***********************************************************************
 *
 * 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) {
        hline_ok_button();
    }
}

