/***********************************************************************
 *
 * TITLE:	marker.c
 *
 * AUTHOR:	Cassie Mulnix
 *
 * DESCRIPTION:	This module is part of the OPPS editor, xopps.  It contains
 *		event markers symbol functions.
 *
 *                              CHANGE HISTORY
 *
 * $Log: marker.c,v $
 * Revision 1.12  1995/02/01  03:19:21  kevin
 * fixed marker colors in popup
 *
 * Revision 1.11  1994/06/16  16:56:35  clm
 * updated to new gr_ routines using GR_ for font names
 *
 * Revision 1.10  1994/05/04  23:34:36  clm
 * ported to ANSI C
 *
 * Revision 1.9  1993/05/18  20:58:30  clm
 * added new message.c function
 *
 * Revision 1.8  1992/12/15  20:40:34  clm
 * changed MAX_MARKER to global declaration
 *
 * Revision 1.7  1992/10/02  20:24:27  clm
 * housekeeping
 *
 * Revision 1.6  1992/09/10  17:13:05  clm
 * added add_marker calls to init_markers
 * removing xopps_init
 *
 * Revision 1.5  1992/08/27  20:57:19  clm
 * changed marker size if needed in dsp_marker so they always look right
 *
 * Revision 1.4  1992/08/03  21:34:20  clm
 * added gr_poly_clear
 *
 * Revision 1.3  1992/05/20  22:28:51  clm
 * *** empty log message ***
 *
 * Revision 1.2  1992/05/20  19:50:57  clm
 * cleaned up file and help format
 *
 * Revision 1.1  1991/06/04  00:32:22  chester
 * Initial revision
 *
 ***********************************************************************
 *
 * WARNINGS:
 *
 * EXTERNAL CALLABLE COMPONENTS (PUBLIC):
 *
 * GLOBALS:
 *
 * WAIVERS:
 *
 * NOTES:
 *
 * MANPAGE:
 *
 ***********************************************************************/

#ifndef lint
static char rcsid[] =
    "$Id: marker.c,v 1.12 1995/02/01 03:19:21 kevin OEL $";
#endif

/*
    marker.c - an sfos module containing routines for drawing markers

    global functions:
	add_marker(n, name, cmd) - add marker to database
	draw_marker(n, x, y) - place marker on screen at (x, y)
*/

#include "xopps.h"

#include <X11/StringDefs.h>

                              /* define marker objects */
/****************************************************************************/
#define MAX_SYM_COORD 99
#define DRAW_MEMORY 1
#define DRAW_SCREEN 0

struct mark {
    char * command;
    Pixmap pixdata;
};

static struct mark marker[MAX_MARKER];

/*
static char *marker[MAX_MARKER];
*/
static int nmarks;
static GC pmgc;			/* temporary GC for Pixmaps */

static void create_marker_pixmap(int, Pixel, Pixel);
static int get_coordinates(char **, int *, int *);
static void draw_poly(Pixmap, XPoint *, int);

/***********************************************************************
 *
 * FUNCTION:
 *	init_markers()
 *
 * INPUTS:
 *
 * OUTPUTS:
 *
 * RETURNS:
 *
 * EXTERNALLY READ:
 *
 * EXTERNALLY MODIFIED:
 *
 * DESCRIPTION:	registers load_markers
 *
 */

void 
init_markers(void)
{
    int i;
    XrmDatabase db;
    Pixel fg, bg;
    char *type;
    XrmValue value;
    Colormap cmap;
    XColor color;

    nmarks = 0;
    add_marker(0, "M 0 50 D 50 99 D 99 50 D 50 0 C");
    add_marker(1, "M 0 50 D 50 99 D 99 50 D 50 0 C F"); 
    add_marker(2, "M 50 99 D 99  0 D  0  0 C");
    add_marker(3, "M  0  0 D 99  0 D 50 99 C F");
    add_marker(4, "M  0 99 D 99 99 D 50  0 C");
    add_marker(5, "M  0 99 D 99 99 D 50  0 C F");
    add_marker(6, "M 50 99 D 50  0 M  0 30 D 50 0 M 99 30 D 50 0 C");
    add_marker(7, "M 50  0 D 50 99 M  0 70 D 50 99 M 99 70 D 50 99 C");
    add_marker(8,
	"M 50  0 D 50 99 M  0 50 D 99 50 M 15 15 D 85 85 M 15 85 D 85 15 C");
    add_marker(9, "M 45  0 D 45 99 D 55 99 D 55  0 C F");
    add_marker(10, "M 50 18 D 99 50 D 50 78 D  0 50 C");
    add_marker(11, "M 50 18 D 99 50 D 50 78 D  0 50 C F");
    add_marker(12, "");
    add_marker(13, "M  0  0 D  0 99 D 99 99 D 99  0 C F");
    add_marker(14,
	"M  0  0 D  0 99 D 99 99 D 99  0 C M  0  0 D 99 99 M 99 0 D  0 99 C ");

    db = XrmGetDatabase(dw.display);
    if (db != NULL) {
	cmap = DefaultColormap(dw.display, dw.screen);
	/*
	 * DITKA - the resource name strings should be extended to the
	 * full names for the event symbols, but this works well enough
	 * for now
	 */
	if (XrmGetResource(db,
		"xopps.event_popup.event.background",
		"XOpps.XmDialogShell.XmBulletinBoard.Background",
		&type, &value) && (!strcmp(type, XtRString))) {
	    bg = (dw.iscolor && XParseColor(dw.display, cmap, value.addr,
		&color) && XAllocColor(dw.display, cmap, &color)) ?
		color.pixel : WhitePixel(dw.display, dw.screen);
	} else {
	    bg = WhitePixel(dw.display, dw.screen);
	}
	if (XrmGetResource(db,
		"xopps.event_popup.event.foreground",
		"XOpps.XmDialogShell.XmBulletinBoard.Foreground",
		&type, &value) && (!strcmp(type, XtRString))) {
	    fg = (dw.iscolor && XParseColor(dw.display, cmap, value.addr,
		&color) && XAllocColor(dw.display, cmap, &color)) ?
		color.pixel : BlackPixel(dw.display, dw.screen);
	} else {
	    fg = BlackPixel(dw.display, dw.screen);
	}
    } else {
	bg = WhitePixel(dw.display, dw.screen);
	fg = BlackPixel(dw.display, dw.screen);
    }
    pmgc = XCreateGC(dw.display, dw.win, 0, NULL);
    for (i = 0; i < 15; i++) {
        gr_screen_on(&dw);
	create_marker_pixmap(i, bg, fg);
        gr_screen_off();
    }
    XFreeGC(dw.display, pmgc);
}

/***********************************************************************
 *
 * FUNCTION:
 *	add_marker()
 *
 * INPUTS:
 *	n	- (int)
 *	cmd	- (char *)
 *
 * OUTPUTS:
 *
 * RETURNS:
 *
 * EXTERNALLY READ:
 *
 * EXTERNALLY MODIFIED:
 *
 * DESCRIPTION:	adds a marker to the database
 *
 */

void 
add_marker(int n, char *cmd)
{
    if (marker[n].command == NULL) {
	marker[n].command = (char *)XtNewString(cmd);
    } else {
	marker[n].command =
             (char *)XtRealloc(marker[n].command, strlen(cmd) + 1);
        (void)strcpy(marker[n].command, cmd);
    }
    nmarks++;
}

/***********************************************************************
 *
 * FUNCTION:
 *	create_marker_pixmap()
 *
 * INPUTS:
 *	i	- (int)
 *
 * OUTPUTS:
 *
 * RETURNS:
 *
 * EXTERNALLY READ:
 *
 * EXTERNALLY MODIFIED:
 *
 * DESCRIPTION:	creates a marker image in memory
 *
 */

static void 
create_marker_pixmap(int i, Pixel bg, Pixel fg)
{
    int icon_width;

    if ( ((icon_width = gr_txheight(GR_HELVETICA|10)) % 2) == 0) {
        icon_width--;
    }
    
    marker[i].pixdata = XCreatePixmap(dw.display, dw.win, (unsigned)icon_width,
	(unsigned)icon_width, (unsigned)(DefaultDepth(dw.display, dw.screen)));

    XSetForeground(dw.display, pmgc, bg);
    XFillRectangle(dw.display, marker[i].pixdata, pmgc, 0, 0, 
	(unsigned)(icon_width+1), (unsigned)(icon_width+1));
    
    XSetForeground(dw.display, pmgc, fg);
    dsp_marker(i, 0, 0, icon_width, DRAW_MEMORY);
}

/***********************************************************************
 *
 * FUNCTION:
 *	get_markers()
 *
 * INPUTS:
 *	symbols[]	- (Pixmap)
 *	num		- (int *)
 *
 * OUTPUTS:
 *
 * RETURNS:
 *
 * EXTERNALLY READ:
 *
 * EXTERNALLY MODIFIED:
 *
 * DESCRIPTION:	copies marker information to other programs
 *
 */

void 
get_markers(Pixmap symbols[], int *num)
{
    int i;

    *num = nmarks;
    for (i = 0; i < nmarks; i++) {
        symbols[i] = marker[i].pixdata;
    }
}

/***********************************************************************
 *
 * FUNCTION:
 *	clear_all_markers()
 *
 * INPUTS:
 *
 * OUTPUTS:
 *
 * RETURNS:
 *
 * EXTERNALLY READ:
 *
 * EXTERNALLY MODIFIED:
 *
 * DESCRIPTION:	clears all marker information from array
 *
 */

void 
clear_all_markers(void)
{
    int i;

    for (i = 0; i < nmarks; i++) {
        marker[i].pixdata = 0;
    }
    nmarks = 0;
}

/***********************************************************************
 *
 * FUNCTION:
 *	get_coordinates()
 *
 * INPUTS:
 *	ptr	- (char **)
 *	x	- (int *)
 *	y	- (int *)
 *
 * OUTPUTS:
 *
 * RETURNS:
 *
 * EXTERNALLY READ:
 *
 * EXTERNALLY MODIFIED:
 *
 * DESCRIPTION:	gets the coordinates of a marker
 *
 */

static int 
get_coordinates(char **ptr, int *x, int *y)
{
    *x = 0;
    *y = 0;

    skip_blanks(ptr);
    if ( get_number(ptr, x) == -1 ) {
        return -1;
    } else if ( abs(*x) > MAX_SYM_COORD ) {
        return -2;
    }
    skip_blanks(ptr);
    if ( get_number(ptr, y) == -1 ) {
        return -1;
    } else if ( abs(*y) > MAX_SYM_COORD ) {
        return -2;
    }
    return 0;
}

/***********************************************************************
 *
 * FUNCTION:
 *	dsp_marker()
 *
 * INPUTS:
 *	n	- (int)
 *	x	- (int)
 *	y	- (int)
 *	len	- (int)
 *	mode	- (int)
 *
 * OUTPUTS:
 *
 * RETURNS:
 *
 * EXTERNALLY READ:
 *
 * EXTERNALLY MODIFIED:
 *
 * DESCRIPTION:	places a marker on the screen
 *
 */

void 
dsp_marker(int n, int x, int y, int len, int mode)
{
    int pdx, pdy;                     /* percentage positions */
    int dx, dy;                       /* relative positions */
    int draw_pts;                     /* flag to detect points to be drawn */
    int i;                            /* index for drawing points */
    char *cmdptr;                     /* command string pointer */
    Pixmap pixdata;                   /* marker pixmap representation */
    XPoint points[64];                /* points to plot the marker symbol */
    int npoints = 0;                  /* number of points to plot */
    int status = 0;                   /* status of valid points */

    /*
     * markers only look right if they have odd length, so make len odd
     */
    if (len % 2 == 0) {
	len = len - 1;
    }

    cmdptr = marker[n].command;
    pixdata = marker[n].pixdata;
    draw_pts = FALSE;
    while (*cmdptr) {
        switch (*cmdptr) {
        case 'C':
            cmdptr++;
            if (mode == DRAW_MEMORY) {
                draw_poly(pixdata, points, npoints);
            } else {
		gr_poly_clear(points, npoints);
                gr_poly(points, npoints);
            }
            draw_pts = FALSE;
            break;
        case 'F':
            cmdptr++;
            if (mode == DRAW_MEMORY) {
                XFillPolygon(dw.display, pixdata, pmgc, points, npoints,
                             Complex, CoordModeOrigin);
            } else {
                gr_poly_fill(points, npoints, "", 100);
            }
            draw_pts = FALSE;
            break;
        case 'M':
            cmdptr++;
            skip_blanks(&cmdptr);
            if ((status = get_coordinates(&cmdptr, &pdx, &pdy)) < 0 ) {
                if (status == -1) {
                    Warning("ERROR: Marker %d, Invalid Format", n);
		    return;
                } else if (status == -2) {
                    Warning("ERROR: Marker %d, Bad Coordinate", n);
		    return;
                }
            }
            /* convert from symbol coordinates to screen coordinates */
            pdy = MAX_SYM_COORD - pdy;
            dx = (int) ( (float)len * ((float)pdx / 100) );
            dy = (int) ( (float)len * ((float)pdy / 100) );
            if (draw_pts == TRUE) {
                if (mode == DRAW_MEMORY) {
                    XDrawLines(dw.display, pixdata, pmgc, points,
                               npoints, CoordModeOrigin);
                } else {
                    gr_move(points[0].x, points[0].y);
                    for (i = 1; i < npoints; i++) {
                        gr_draw(points[i].x, points[i].y);
                    }
                }
                draw_pts = FALSE;
            }
            points[0].x = x + dx;
            points[0].y = y + dy;
            npoints = 1;
            cmdptr++;
            break;
        case 'D':
            cmdptr++;
            if ((status = get_coordinates(&cmdptr, &pdx, &pdy)) < 0 ) {
                if (status == -1) {
                    Warning("ERROR: Marker %d, Invalid Format", n);
		    return;
                } else if (status == -2) {
                    Warning("ERROR: Marker %d, Bad Coordinate", n);
		    return;
                }
            }
            /* convert from symbol coordinates to screen coordinates */
            pdy = MAX_SYM_COORD - pdy;
            dx = (int) ((float)len * ((float)pdx / 100));
            dy = (int) ((float)len * ((float)pdy / 100));
            draw_pts = TRUE;
            points[npoints].x = x + dx;
            points[npoints].y = y + dy;
            npoints++;
            cmdptr++;
            break;
        default:
            Warning("ERROR: On marker %d", n);
	    return;
        }
        skip_blanks(&cmdptr);
    }
}

/***********************************************************************
 *
 * FUNCTION:
 *	draw_poly()
 *
 * INPUTS:
 *	pixdata	- (pixdata)
 *	pts	- (XPoint *)
 *	npts	- (int)
 *
 * OUTPUTS:
 *
 * RETURNS:
 *
 * EXTERNALLY READ:
 *
 * EXTERNALLY MODIFIED:
 *
 * DESCRIPTION:	plots out a polygon in memory
 *
 */

static void 
draw_poly(Pixmap pixdata, XPoint *pts, int npts)
{
    XDrawLines(dw.display, pixdata, pmgc, pts, npts, CoordModeOrigin);
    if ( (pts[0].x != pts[npts-1].x) || (pts[0].y != pts[npts-1].y) ) {
        XDrawLine(dw.display, pixdata, pmgc , pts[0].x, pts[0].y,
                  pts[npts-1].x, pts[npts-1].y);
     }
}
