/*********************************************************************** * * TITLE: * line.c * * AUTHOR: * Cassie Mulnix * * DESCRIPTION: * This module is part of the OPPS editor, xopps. It contains * object routines to handle chart line objects. * * CHANGE HISTORY * * $Log: line.c,v $ * Revision 1.20 1994/06/16 21:55:48 clm * updated to new dialog routines - extra parameter to DialogTextCreate * * Revision 1.19 1994/06/01 22:28:54 clm * cleaned up init arguments * changed color from structure to 3 arrays * * Revision 1.18 1994/05/20 23:31:43 clm * updated with HP, SGI changes * * Revision 1.17 1994/05/04 23:34:36 clm * ported to ANSI C * * Revision 1.16 1993/05/18 20:58:30 clm * added new message.c function * * Revision 1.15 1993/03/04 17:49:11 clm * line_init in load_line if any lines are missing * set default line dir if direction is off * * Revision 1.14 1993/03/03 18:12:11 clm * added error checking of Y_LINE 3 to Y_LINE 2 * * Revision 1.13 1993/02/08 16:08:59 clm * check for minimum gap for chart lines * * Revision 1.12 1992/12/17 18:50:07 clm * fixed error checking for mov_line * * Revision 1.11 1992/10/02 20:44:33 clm * `housekeeping * * Revision 1.10 1992/10/02 18:44:34 clm * fixed mov_line routine for y_line 3 * * Revision 1.9 1992/09/14 14:48:55 clm * fixed mov function so that text will always fit in chart area * * Revision 1.8 1992/09/11 22:59:49 clm * changed line coordinates to fit in new drawing size * changed mode to GR_EXPAND * * Revision 1.7 1992/09/10 20:56:55 clm * fix cord of ylnary[3] to correspond to y_gap value * * Revision 1.6 1992/09/09 22:55:13 clm * added line_init function to hard code line coordinates * removing xopps_init file * * Revision 1.4 1992/08/27 16:19:40 clm * took out unused functions * * Revision 1.3 1992/08/26 15:05:21 clm * fixed lim function * * Revision 1.2 1992/08/25 20:07:24 clm * added modified boolean for beware message * * Revision 1.1 1992/08/25 18:01:21 clm * Initial revision * *********************************************************************** * * WARNINGS: * * EXTERNAL CALLABLE COMPONENTS (PUBLIC): * * GLOBALS: * * WAIVERS: * * NOTES: * * MANPAGE: * ***********************************************************************/ #ifndef lint static char rcsid[] = "$Id: line.c,v 1.20 1994/06/16 21:55:48 clm OEL $"; #endif #include "xopps.h" #define LINE_SENSE 5 /* line sensitivity: how close the mouse has to be */ static int load_line(char *); static void edt_line(int, int); static void rem_line(int, int); static void lim_line(int, int *, int *, int *, int *, int); static void loc_line(int, int); static void mov_line(int, int, int, int); static void dsp_line(int); static void cpy_line(struct obj *, struct obj *); static void msg_line(int, int); static void sav_line(int, FILE *, int); static struct ops line_ops = { dsp_line, edt_line, rem_line, lim_line, loc_line, mov_line, cpy_line, msg_line, sav_line }; enum dialog_type { DONE_BUTTON, CANCEL_BUTTON, HELP_BUTTON, COORD_LABEL, COORD, S_OFF_LABEL, S_OFF, E_OFF_LABEL, E_OFF, TIMELINE_SEPARATOR, PAGE_INFO, LINE, N_ITEMS }; /*********************************************************************** * * FUNCTION: * line_init() * * INPUTS: * * OUTPUTS: * * RETURNS: * * EXTERNALLY READ: * * EXTERNALLY MODIFIED: * * DESCRIPTION: * hard code values of xlnary and ylnary * */ void line_init(void) { /* set values of vertical lines */ add_line(0, 0, 2, 0, 4, 0, 0); add_line(1, 0, 264, 1, 3, 0, 0); add_line(2, 0, 296, 0, 1, 0, 0); add_line(3, 0, 725, 0, 1, 0, 0); add_line(4, 0, 997, 0, 4, 0, 0); nxln = 5; /* set values of horizontal lines */ add_line(0, 1, 2, 0, 4, 0, 0); add_line(1, 1, 70, 0, 4, 0, 0); add_line(2, 1, 138, 0, 4, 0, 0); add_line(3, 1, 667, 0, 4, 0, 0); add_line(4, 1, 736, 0, 4, 0, 0); nyln = 5; } /*********************************************************************** * * FUNCTION: * init_line_object() * * INPUTS: * none * * OUTPUTS: * none * * RETURNS: * none * * EXTERNALLY READ: * none * * EXTERNALLY MODIFIED: * none * * DESCRIPTION: * registers the line object * */ void init_line_object(void) { register_io_obj('A', load_line); } /*********************************************************************** * * FUNCTION: * load_line() * * INPUTS: * buf - (char *) * * OUTPUTS: * * RETURNS: * * EXTERNALLY READ: * * EXTERNALLY MODIFIED: * * DESCRIPTION: * */ static int load_line(char *buf) { static int new_lines = FALSE; int num, dir, cord, startln, endln, start_offset, end_offset; if (record_scan(buf + 1, "ddddddd", &num, &dir, &cord, &startln, &endln, &start_offset, &end_offset) == 7) { if ((dir != 0) && (dir != 1)) { if (nxln != MAX_XLINES) { Warning("Error - Illegal direction of line %d, %d used", num,0); dir = 0; } else { Warning("Error - Illegal direction of line %d, %d used", num,1); dir = 1; } } if (dir == 0) { /* vertical line */ if ( (num < 0 ) || (num >= MAX_XLINES) ) { Warning("Error - Illegal Vertical Line Index (%d)", num); return -1; } if ( (cord < 0) || (cord > page_width) ) { Warning("Page Limit Coordinate (%d) Error", cord); return -1; } } else if (dir == 1) { /* horizontal line */ if ((num < 0 ) || (num >= MAX_YLINES)) { Warning("Error - Illegal Horizontal Line Index (%d)", num); return -1; } if ( (cord < 0) || (cord > page_height) ) { Warning("Page Limit Coordinate (%d) Error - Line %d",cord); return -1; } } if (!new_lines) { new_lines = TRUE; nxln = 0; nyln = 0; } add_line(num, dir, cord, startln, endln, start_offset, end_offset); return 0; } else { return -1; } } /*********************************************************************** * * FUNCTION: * add_line() * * INPUTS: * num - (int) * dir - (int) * coord - (int) * sline - (int) * eline - (int) * soff - (int) * eoff - (int) * * OUTPUTS: * * RETURNS: * * EXTERNALLY READ: * * EXTERNALLY MODIFIED: * * DESCRIPTION: * */ void add_line(int num, int dir, int cord, int sline, int eline, int soff, int eoff) { if (dir) { ylnary[num].rlist = newRectList(0); ylnary[num].z.lnptr = (struct line *)XtMalloc(sizeof(struct line)); ylnary[num].z.lnptr->dir = dir; ylnary[num].z.lnptr->cord = cord; ylnary[num].z.lnptr->startln = sline; ylnary[num].z.lnptr->endln = eline; ylnary[num].z.lnptr->start_offset = soff; ylnary[num].z.lnptr->end_offset = eoff; ylnary[num].type = OBJ_LNY; ylnary[num].opsptr = &line_ops; nyln++; } else { xlnary[num].rlist = newRectList(0); xlnary[num].z.lnptr = (struct line *)XtMalloc(sizeof(struct line)); xlnary[num].z.lnptr->dir = dir; xlnary[num].z.lnptr->cord = cord; xlnary[num].z.lnptr->startln = sline; xlnary[num].z.lnptr->endln = eline; xlnary[num].z.lnptr->start_offset = soff; xlnary[num].z.lnptr->end_offset = eoff; xlnary[num].type = OBJ_LNX; xlnary[num].opsptr = &line_ops; nxln++; } } /*********************************************************************** * * FUNCTION: * cpy_line() * * INPUTS: * * OUTPUTS: * * RETURNS: * * EXTERNALLY READ: * * EXTERNALLY MODIFIED: * * DESCRIPTION: * */ static void cpy_line(struct obj *to, struct obj *from) { if (from->type == OBJ_NUL) return; to->z.lnptr = (struct line *)XtMalloc(sizeof(struct line)); to->z.lnptr->dir = from->z.lnptr->dir; to->z.lnptr->cord = from->z.lnptr->cord; to->z.lnptr->startln = from->z.lnptr->startln; to->z.lnptr->endln = from->z.lnptr->endln; to->z.lnptr->start_offset = from->z.lnptr->start_offset; to->z.lnptr->end_offset = from->z.lnptr->end_offset; to->type = from->type; to->opsptr = &line_ops; to->rlist = copyRectList(from->rlist); } /*********************************************************************** * * FUNCTION: * rem_line() * * INPUTS: * num - (int) * dir - (int) * * OUTPUTS: * * RETURNS: * * EXTERNALLY READ: * * EXTERNALLY MODIFIED: * * DESCRIPTION: * */ static void rem_line(int num, int dir) { struct obj *objptr; switch (num) { case BACK: objptr = &objbck; break; case TEMP: objptr = &objtmp; break; default: if (dir == LINE_X) { objptr = &(xlnary[num]); } else { objptr = &(ylnary[num]); } break; } freeRectList(objptr->rlist); XtFree((char *)objptr->z.lnptr); rem_object(objptr); } /*********************************************************************** * * FUNCTION: * lim_line() * * INPUTS: * num - (int) * start_horz - (int *) * start_vert - (int *) * end_horz - (int *) * end_vert - (int *) * lndir - (int) * * OUTPUTS: * * RETURNS: * * EXTERNALLY READ: * * EXTERNALLY MODIFIED: * * DESCRIPTION: * */ static void lim_line(int co, int *x1, int *y1, int *x2, int *y2, int lndir) { XRectangle *(*r)[]; /* move Rectangle */ switch (lndir) { case LINE_X: /* vertical line */ r = getMoveRect(xlnary[co].rlist); (*x1) = 0; (*y1) = (*r)[0]->y; (*x2) = page_width - 1; (*y2) = (*r)[0]->y; break; case LINE_Y: /* horizontal line */ r = getMoveRect(ylnary[co].rlist); (*x1) = (*r)[0]->x; (*y1) = 0; (*x2) = (*r)[0]->x; (*y2) = page_height - 1; break; } } /*********************************************************************** * * FUNCTION: * loc_line() * * INPUTS: * i - (int) * dir - (int) * * OUTPUTS: * * RETURNS: * * EXTERNALLY READ: * * EXTERNALLY MODIFIED: * * DESCRIPTION: * */ static void loc_line(int i, int dir) { struct line *lineptr; XRectangle rpri; /* Rectangles */ switch (dir) { case LINE_X: lineptr = xlnary[i].z.lnptr; rpri.x = lineptr->cord; rpri.y = ylnary[lineptr->startln].z.lnptr->cord; rpri.width = 1; rpri.height = ylnary[lineptr->endln].z.lnptr->cord - ylnary[lineptr->startln].z.lnptr->cord; setRectList(xlnary[i].rlist, 1, &rpri, RL_PRIMARY); break; case LINE_Y: lineptr = ylnary[i].z.lnptr; rpri.x = xlnary[lineptr->startln].z.lnptr->cord; rpri.y = lineptr->cord; rpri.width = xlnary[lineptr->endln].z.lnptr->cord - xlnary[lineptr->startln].z.lnptr->cord; rpri.height = 1; setRectList(ylnary[i].rlist, 1, &rpri, RL_PRIMARY); break; } } /*********************************************************************** * * FUNCTION: * mov_line() * * INPUTS: * i - (int) * x - (int) * y - (int) * lndir - (int) * * OUTPUTS: * * RETURNS: * * EXTERNALLY READ: * * EXTERNALLY MODIFIED: * * DESCRIPTION: * */ static void mov_line(int i, int x, int y, int lndir) { int temp_y_gap; switch (lndir) { case LINE_X: /* * check new coordinate with limit value on right */ if ((i == 1) || (i == 3)) { if (xlnary[i].z.lnptr->cord+x > xlnary[nxln-1].z.lnptr->cord) { Warning("Can't pass border lines"); break; } } else if (i == 0) { /* header vertical line may be left of horizontal line area vertical line, so need to check against furthest left vertical line */ if (xlnary[1].z.lnptr->cord > xlnary[2].z.lnptr->cord) { if (xlnary[i].z.lnptr->cord+x > xlnary[2].z.lnptr->cord) { Warning("Can't pass next line"); break; } } else { if (xlnary[i].z.lnptr->cord+x > xlnary[i+1].z.lnptr->cord) { Warning("Can't pass next line"); break; } } } else if (i == 2) { if (xlnary[i].z.lnptr->cord+x > xlnary[i+1].z.lnptr->cord) { Warning("Can't pass next line"); break; } } /* * check new coordinate with limit value on left */ if ((i == 1) || (i == 3)) { if (xlnary[i].z.lnptr->cord+x < xlnary[i-1].z.lnptr->cord) { Warning("Can't pass previous line"); break; } } else if (i == nxln - 1) { /* header vertical line may be right of horizontal line area vertical line, so need to check against furthest right vertical line */ if (xlnary[i-1].z.lnptr->cord > xlnary[1].z.lnptr->cord) { if (xlnary[i].z.lnptr->cord+x < xlnary[i-1].z.lnptr->cord) { Warning("Can't pass previous line"); break; } } else if (xlnary[i].z.lnptr->cord+x < xlnary[1].z.lnptr->cord) { Warning("Can't pass chart line"); break; } } else if (i == 2) { if (xlnary[i].z.lnptr->cord+x < xlnary[0].z.lnptr->cord) { Warning("Can't pass border lines"); break; } } xlnary[i].z.lnptr->cord += x; break; case LINE_Y: if (i != 0) { if (ylnary[i].z.lnptr->cord+y <= ylnary[i-1].z.lnptr->cord) { Warning("Can`t pass previous line"); break; } } if (i != nyln-1) { if (ylnary[i].z.lnptr->cord+y >= ylnary[i+1].z.lnptr->cord) { Warning("Can't pass next line"); break; } } if (i == 1) { if ((ylnary[2].z.lnptr->cord - (ylnary[1].z.lnptr->cord + y))< 45) { Warning("Must have width of 45 for chart dates"); break; } } if (i == 2) { temp_y_gap = (int)((ylnary[2].z.lnptr->cord + y - y_act_bottom) / pg_lines); if (((ylnary[2].z.lnptr->cord + y) - ylnary[1].z.lnptr->cord)< 45) { Warning("Must have width of 45 for chart dates"); break; } if (((ylnary[3].z.lnptr->cord - (ylnary[2].z.lnptr->cord + y)) < pg_lines) || ((temp_y_gap * pg_lines + y_act_bottom) < pg_lines)) { Warning("Must have width of at least 1 for each line on chart"); break; } } if (i == 3) { temp_y_gap = (int)((ylnary[3].z.lnptr->cord + y - y_act_bottom) / pg_lines); if ((((ylnary[3].z.lnptr->cord + y) - ylnary[2].z.lnptr->cord) < pg_lines) || ((temp_y_gap * pg_lines + y_act_bottom) < pg_lines)) { Warning("Must have width of at least 1 for each line on chart"); break; } } ylnary[i].z.lnptr->cord += y; break; } } /*********************************************************************** * * FUNCTION: * dsp_line() * * INPUTS: * i - (int) * lndir - (int) * * OUTPUTS: * * RETURNS: * * EXTERNALLY READ: * * EXTERNALLY MODIFIED: * * DESCRIPTION: * */ static void dsp_line(int i) { #ifdef BOZO struct line *lptr; int x1, y1, x2, y2; switch (lndir) { case LINE_X: lptr = xlnary[i].z.lnptr; gr_set_color(color_name[objary[0].z.chtptr->color], color_gscale[objary[0].z.chtptr->color]); x1 = lptr->cord; y1 = ylnary[lptr->startln].z.lnptr->cord + lptr->start_offset; x2 = lptr->cord; y2 = ylnary[lptr->endln].z.lnptr->cord + lptr->end_offset; gr_line(x1, y1, x2, y2); break; case LINE_Y: lptr = ylnary[i].z.lnptr; gr_set_color(color_name[objary[0].z.chtptr->color], color_gscale[objary[0].z.chtptr->color]); x1 = xlnary[lptr->startln].z.lnptr->cord + lptr->start_offset; y1 = lptr->cord; x2 = xlnary[lptr->endln].z.lnptr->cord + lptr->end_offset; y2 = lptr->cord; gr_line(x1, y1, x2, y2); break; } #endif } /*********************************************************************** * * FUNCTION: * msg_line() * * INPUTS: * i - (int) * lndir - (int) * * OUTPUTS: * * RETURNS: * * EXTERNALLY READ: * * EXTERNALLY MODIFIED: * * DESCRIPTION: * */ static void msg_line(int i, int lndir) { switch (lndir) { case LINE_X: Message("Vertical Line at %d", xlnary[i].z.lnptr->cord); break; case LINE_Y: Message("Horizontal Line at %d", ylnary[i].z.lnptr->cord); break; } } /*********************************************************************** * * FUNCTION: * sav_line() * * INPUTS: * i - (int) * dir - (int) * fp - (FILE *) * * OUTPUTS: * * RETURNS: * * EXTERNALLY READ: * * EXTERNALLY MODIFIED: * * DESCRIPTION: * */ static void sav_line(int i, FILE *fp, int dir) { struct line *lnptr; char buf[256]; if (dir == LINE_X) { lnptr = xlnary[i].z.lnptr; } else if (dir == LINE_Y) { lnptr = ylnary[i].z.lnptr; } buf[0] = 'A'; buf[1] = ' '; (void)record_print(buf + 2, "ddddddd", i, lnptr->dir, lnptr->cord, lnptr->startln, lnptr->endln, lnptr->start_offset, lnptr->end_offset); (void)fputs(buf, fp); } /*********************************************************************** * * FUNCTION: * edt_line() * * INPUTS: * * OUTPUTS: * * RETURNS: * * EXTERNALLY READ: * * EXTERNALLY MODIFIED: * * DESCRIPTION: * */ static void edt_line(int i, int ltype) { /* can't edit the line, only move it */ } /*********************************************************************** * * FUNCTION: * locate_lines() * * INPUTS: * * OUTPUTS: * * RETURNS: * * EXTERNALLY READ: * * EXTERNALLY MODIFIED: * * DESCRIPTION: * locate the lines on screen usually after a file has been loaded. * */ void locate_lines(void) { int i; for (i = 0; i < nxln; i++) { (*(xlnary[i].opsptr->loc))(i, LINE_X); } for (i = 0; i < nyln; i++) { (*(ylnary[i].opsptr->loc))(i, LINE_Y); } } /*********************************************************************** * * FUNCTION: * clear_all_lines() * * INPUTS: * * OUTPUTS: * * RETURNS: * * EXTERNALLY READ: * * EXTERNALLY MODIFIED: * * DESCRIPTION: * */ void clear_all_lines(void) { int i; /* temp index */ for (i = 0; i < nxln; i++) { (*(xlnary[i].opsptr->rem))(i, LINE_X); } for (i = 0; i < nyln; i++) { (*(ylnary[i].opsptr->rem))(i, LINE_Y); } nxln = 0; nyln = 0; } /*********************************************************************** * * FUNCTION: * find_line() * * INPUTS: * x - (int) * y - (int) * lndir - (int *) * * OUTPUTS: * * RETURNS: * * EXTERNALLY READ: * * EXTERNALLY MODIFIED: * * DESCRIPTION: * */ int find_line(int x, int y, int *lndir) { int i; /* index */ static int lastln = -1; /* array index of line array */ i = 0; if ( ((*lndir) == LINE_X) || ((*lndir) == LINE_Y) ){ i = lastln + 1; } if ((*lndir) != LINE_Y) { /* * Rotate between a vertical line to a horizontal line and back * to a vertical line. */ if ( (lastln = find_line2(i, x, y, xlnary, ylnary, nxln)) >= 0) { (*lndir) = LINE_X; } else if ( (lastln = find_line2(0, y, x, ylnary, xlnary, nyln)) >= 0) { (*lndir) = LINE_Y; } else if (i > 0) { if ( (lastln = find_line2(0, x, y, xlnary, ylnary, nxln)) >= 0) { (*lndir) = LINE_X; } } } else { /* * Rotate between a horizontal line to a vertical line and back * to a horizontal line. */ if ( (lastln = find_line2(i, y, x, ylnary, xlnary, nyln)) >= 0) { (*lndir) = LINE_Y; } else if ( (lastln = find_line2(0, x, y, xlnary, ylnary, nxln)) >= 0) { (*lndir) = LINE_X; } else if (i > 0) { if ( (lastln = find_line2(0, y, x, ylnary, xlnary, nyln)) >= 0) { (*lndir) = LINE_Y; } } } return (lastln); } /*********************************************************************** * * FUNCTION: * find_line2() * * INPUTS: * curr - (int) * cord - (int) * pt2 - (int) * ln1 - (struct obj *) * ln2 - (struct obj *) * nlines - (int) * * OUTPUTS: * * RETURNS: * * EXTERNALLY READ: * * EXTERNALLY MODIFIED: * * DESCRIPTION: * */ int find_line2(int curr, int cord, int pt2, struct obj *ln1, struct obj *ln2, int nlines) { int lastline = -1; /* return -1 if no line is found */ int i; int ln_start; int ln_end; /* * With the assumption that the lines are placed in sequential order, * this function will check the following line(s) in the line array to * determine out if another line falls under the mouse's sphere of influence * If there is one, it will return the index of that line, otherwise it will * return a -1. */ for (i = 0; i < nlines; i++) { if ( (curr + i) >= nlines ) { break; } ln_start = ln2[ln1[curr+i].z.lnptr->startln].z.lnptr->cord + ln1[curr+i].z.lnptr->start_offset; ln_end = ln2[ln1[curr+i].z.lnptr->endln].z.lnptr->cord + ln1[curr+i].z.lnptr->end_offset; if ( (abs(cord - ln1[curr+i].z.lnptr->cord) < LINE_SENSE) && (ln_start < pt2) && (pt2 < ln_end) ) { lastline = curr + i; return (lastline); } } return (lastline); } void check_lines(void) { if ((nxln != MAX_XLINES) || (nyln != MAX_YLINES)) { Warning("Error in chart lines - default lines being loaded"); line_init(); } }