/*
 * FIG : Facility for Interactive Generation of figures
 * Copyright (c) 1985 by Supoj Sutanthavibul
 * Copyright (c) 1992 by Brian V. Smith
 *
 * "Permission to use, copy, modify, distribute, and sell this software and its
 * documentation for any purpose is hereby granted without fee, provided that
 * the above copyright notice appear in all copies and that both the copyright
 * notice and this permission notice appear in supporting documentation. 
 * No representations are made about the suitability of this software for 
 * any purpose.  It is provided "as is" without express or implied warranty."
 */

/*
 * This file provides some drawing primitives which make use of the
 * underlying low-level windowing system operations.
 *
 * The file is divided into routines for:
 *
 * GRAPHICS CONTEXTS (which are used by all the following)
 * FONTS
 * LINES
 * SHADING
 */

/* IMPORTS */

#include "fig.h"
#include "figx.h"
#include "resources.h"
#include "paintop.h"
#include "mode.h"
#include "object.h"
#include "u_fonts.h"
#include "w_canvas.h"
#include "w_drawprim.h"
#include "w_icons.h"		/* for none_ic in init_fill_pm */
#include "w_indpanel.h"
#include "w_setup.h"
#include "w_util.h"
#include "w_zoom.h"

extern struct _xfstruct x_fontinfo[NUM_X_FONTS];
extern struct _fstruct ps_fontinfo[];	/* font names */
extern choice_info fillstyle_choices[];

/* EXPORTS */

PIX_FONT	bold_font;
PIX_FONT	roman_font;
PIX_FONT	button_font;
PIX_ROT_FONT	canvas_font;

/* LOCAL */

static Pixel	gc_color[NUMOPS];
static XRectangle clip[1];
static pr_size	pfx_textwidth();
static int	parsesize();

#define MAXNAMES 35

static struct {
    char	   *fn;
    int		    s;
}		flist[MAXNAMES];

init_font()
{
    struct xfont   *newfont, *nf;
    int		    f, count, i, p, ss;
    char	    template[200];
    char	  **fontlist, **fname;

    if (appres.boldFont == NULL || *appres.boldFont == '\0')
	appres.boldFont = BOLD_FONT;
    if (appres.normalFont == NULL || *appres.normalFont == '\0')
	appres.normalFont = NORMAL_FONT;
    if (appres.buttonFont == NULL || *appres.buttonFont == '\0')
	appres.buttonFont = BUTTON_FONT;

    roman_font = XLoadQueryFont(tool_d, appres.normalFont);
    hidden_text_length = 4 * roman_font->max_bounds.width;
    if ((bold_font = XLoadQueryFont(tool_d, appres.boldFont)) == 0) {
	fprintf(stderr, "Can't load font: %s, using %s\n",
		appres.boldFont, appres.normalFont);
	bold_font = XLoadQueryFont(tool_d, appres.normalFont);
    }
    if ((button_font = XLoadQueryFont(tool_d, appres.buttonFont)) == 0) {
	fprintf(stderr, "Can't load font: %s, using %s\n",
		appres.buttonFont, appres.normalFont);
	button_font = XLoadQueryFont(tool_d, appres.normalFont);
    }
    /*
     * Now initialize the font structure for the X fonts corresponding to the
     * Postscript fonts for the canvas.	 OpenWindows can use any LaserWriter
     * fonts at any size, so we don't need to load anything if we are using
     * it.
     */

#ifndef OPENWIN
    /* if the user asked for scalable fonts, check that the server 
       really has them by checking for font of 0-0 size */
    if (appres.SCALABLEFONTS) {
	strcpy(template,x_fontinfo[0].template);  /* just check the first font */
	strcat(template,"0-0-*-*-*-*-*-*");
	if ((fontlist = XListFonts(tool_d, template, 1, &count))==0)
	    appres.SCALABLEFONTS = False;	/* none, turn off request for them */
    }

    /* X11R5 has scalable fonts - skip next section in that case */
    if (!appres.SCALABLEFONTS) {
	for (f = 0; f < NUM_X_FONTS; f++) {
	    nf = NULL;
	    strcpy(template,x_fontinfo[f].template);
	    strcat(template,"*-*-*-*-*-*-");
	    /* add ISO8859 (if not Symbol font or ZapfDingbats) to font name */
	    if (strstr(template,"symbol") == NULL && 
		strstr(template,"zapfdingbats") == NULL)
		    strcat(template,"ISO8859-*");
	    else
		strcat(template,"*-*");
	    /* don't free the Fontlist because we keep pointers into it */
	    p = 0;
	    if ((fontlist = XListFonts(tool_d, template, MAXNAMES, &count))==0) {
		/* no fonts by that name found, substitute the -normal font name */
		flist[p].fn = appres.normalFont;
		flist[p++].s = 12;	/* just set the size to 12 */
	    } else {
		fname = fontlist; /* go through the list finding point
				   * sizes */
		while (count--) {
		ss = parsesize(*fname);	/* get the point size from
					 * the name */
		flist[p].fn = *fname++;	/* save name of this size
					 * font */
		flist[p++].s = ss;	/* and save size */
		}
	    }
	    for (ss = 4; ss <= 50; ss++) {
		for (i = 0; i < p; i++)
			if (flist[i].s == ss)
			    break;
		if (i < p && flist[i].s == ss) {
			newfont = (struct xfont *) malloc(sizeof(struct xfont));
			if (nf == NULL)
			    x_fontinfo[f].xfontlist = newfont;
			else
			    nf->next = newfont;
			nf = newfont;	/* keep current ptr */
			nf->size = ss;	/* store the size here */
			nf->fname = flist[i].fn;	/* keep actual name */
			nf->list = NULL;
			nf->next = NULL;
		    }
	    } /* next size */
	} /* next font, f */
    } /* !appres.SCALABLEFONTS */
#endif /* OPENWIN */
}

/* parse the point size of font 'name' */
/* e.g. -adobe-courier-bold-o-normal--10-100-75-75-m-60-ISO8859-1 */

static int
parsesize(name)
    char	   *name;
{
    int		    s;
    char	   *np;

    for (np = name; *(np + 1); np++)
	if (*np == '-' && *(np + 1) == '-')	/* look for the -- */
	    break;
    s = 0;
    if (*(np + 1)) {
	np += 2;		/* point past the -- */
	s = atoi(np);		/* get the point size */
    } else
	fprintf(stderr, "Can't parse '%s'\n", name);
    return s;
}

/*
 * Lookup an X font corresponding to a Postscript font style that is close in
 * size and with angle "angle"
 */

PIX_ROT_FONT
lookfont(f, s, angle)
    int		    f, s;
    float	    angle;
{
    struct xfont   *xf;
    PIX_ROT_FONT   fontst;
    int		   dir;

    /*** Must fix the following to actually return the "-normal font" ROTATED font */
    if (f == DEFAULT)
	f = 0;		/* pass back the -normal font font */
    if (s < 0)
	s = DEF_FONTSIZE;	/* default font size */

#ifdef OPENWIN
  {
    /* to search for OpenWindows font - see below */
    char	    fn[128];
    int		    i;

    for (i = 1; i < NUM_PS_FONTS + 1; i++)
	if (ps_fontinfo[i].xfontnum == f)
	    {
	    sprintf(fn, "%s-%d", ps_fontinfo[i].name, s);
	    break;
	    }

    for (i = strlen(fn) - 1; i >= 0; i--)
	if (isupper(fn[i]))
	    fn[i] = tolower(fn[i]);
    if (appres.DEBUG)
	fprintf(stderr, "Loading font %s\n", fn);
    set_temp_cursor(wait_cursor);
    app_flush();
    fontst = XRotLoadFont(tool_d, fn, angle);
    if (fontst == NULL) {
	fprintf(stderr, "xfig: Can't load font %s ?!, using %s\n",
		fn, appres.normalFont);
	fontst = XRotLoadFont(tool_d, appres.normalFont, angle);
    }
    reset_cursor();
    return (fontst);
  }

#else
  {
	char		fn[128];
	char		template[200];
	Boolean		found;
	struct xfont   *newfont, *nf, *oldnf;
	struct flist   *lp, *nlp, *oldlp;

	/* see if we've already loaded that font size 's' at angle 'angle' 
	   from the font family 'f' */
	/* actually, we've reduced the number of angles to four - 0, 90, 180 and 270 */
	if (angle < 0.0)
		angle += 2.0*M_PI;
	dir = (int)(angle/M_PI_2+0.0001);
	if (dir > 3)
		dir -= 4;
	found = False;
	/* start with the basic font name (e.g. adobe-times-medium-r-normal-...) */
	nf = x_fontinfo[f].xfontlist;
	oldnf = nf;
	if (nf != NULL) {
	    if (nf->size > s && !appres.SCALABLEFONTS)
		found = True;
	    else while (nf != NULL){
	    if (nf->size == s || (!appres.SCALABLEFONTS &&
		     (nf->size >= s && oldnf->size <= s ))) {
		found = True;
		break;
	    }
	    oldnf = nf;
	    nf = nf->next;
	    }
	}
	if (found) {		/* found exact size (or only larger available) */
	    strcpy(fn,nf->fname);  /* put the name in fn */
	    if (s < nf->size)
		put_msg("Font size %d not found, using larger %d point",s,nf->size);
	} else if (!appres.SCALABLEFONTS) {	/* not found, use largest available */
	    nf = oldnf;
	    strcpy(fn,nf->fname);  /* put the name in fn */
	    if (s > nf->size)
		put_msg("Font size %d not found, using smaller %d point",s,nf->size);
	} else { /* SCALABLE; none yet of that size, alloc one and put it in the list */
	    newfont = (struct xfont *) malloc(sizeof(struct xfont));
	    /* add it on to the end of the list */
	    if (x_fontinfo[f].xfontlist == NULL)
	        x_fontinfo[f].xfontlist = newfont;
	    else
	        oldnf->next = newfont;
	    nf = newfont;		/* keep current ptr */
	    nf->size = s;		/* store the size here */
	    nf->list = NULL;
	    nf->next = NULL;

	    /* create a full XLFD font name */
	    strcpy(template,x_fontinfo[f].template);
	    /* attach pointsize to font name */
	    strcat(template,"%d-*-*-*-*-*-");
	    /* add ISO8859 (if not Symbol font or ZapfDingbats) to font name */
	    if (strstr(template,"symbol") == NULL && 
		strstr(template,"zapfdingbats") == NULL)
		    strcat(template,"ISO8859-*");
	    else
		strcat(template,"*-*");
	    /* use the pixel field instead of points in the fontname so that the
		font scales with screen size */
	    sprintf(fn, template, s);
	    /* allocate space for the name and put it in the structure */
	    nf->fname = (char *) malloc(strlen(fn));
	    strcpy(nf->fname, fn);
	} /* if (!found) */
	if (appres.DEBUG)
	    fprintf(stderr, "Loading font %s at angle %f (%f)\n", 
			fn, (float) dir*90.0, angle);
	lp = nf->list;
	oldlp = lp;
	found = False;
	while (lp) {
		if (lp->dir == dir) {
		    found = True;
		    break;
		}
		oldlp = lp;
		lp = lp->next;
	} /* while (lp) */
	if (!found) {
		nlp = (struct flist *) malloc(sizeof(struct flist));
		nlp->next = NULL;
		if (oldlp)
			oldlp->next = nlp;	/* add this to the list */
		else
			nf->list = nlp;		/* first on the list */
		nlp->dir = dir;
		set_temp_cursor(wait_cursor);
		app_flush();
		fontst = XRotLoadFont(tool_d, fn, (float) dir*90.0);
		reset_cursor();
		if (fontst == NULL) {
		    fprintf(stderr, "xfig: Can't load font %s ?!, using %s\n",
			fn, appres.normalFont);
		    fontst = XRotLoadFont(tool_d, appres.normalFont, (float) dir*90.0);
		    nf->fname = fn;	/* keep actual name */
		}
		/* put the structure in the list */
		nlp->fstruct = fontst;
		lp = nlp;
	} /* if (!found) */
	fontst = lp->fstruct;
	return (fontst);
  }

#endif				/* !OPENWIN */

}

/* print "string" in window "w" using font specified in fstruct at (x,y) */

pw_text(w, x, y, op, fstruct, string, color)
    Window	    w;
    int		    x, y, op;
    PIX_ROT_FONT    fstruct;
    char	   *string;
    Color	    color;
{
    if (fstruct == NULL)
	fprintf(stderr,"Error, in pw_text, fstruct==NULL\n");
    pwx_text(w, x, y, op, fstruct, string, color);
}

pwx_text(w, x, y, op, fstruct, string, color)
    Window	    w;
    int		    x, y, op;
    PIX_ROT_FONT    fstruct;
    char	   *string;
    Color	    color;
{
    /* if we're drawing to the bitmap instead of the canvas
       map colors white => white, all others => black */
    if (writing_bitmap)
	{
	if (color == WHITE)
		color = 0;
	else
		color = 1;
	}
    if (writing_bitmap? color != gc_color[op] : x_color(color) != gc_color[op]) {
	    if (op == PAINT) {
		if (writing_bitmap)
		    XSetForeground(tool_d,gccache[op],color);
		else
		    set_x_color(gccache[op], color);
		gc_color[op] = writing_bitmap? color : x_color(color);
	    }
    }
    zXRotDrawString(tool_d, w, fstruct, gccache[op], x, y, 
		    string, strlen(string));
}

pr_size
pf_textwidth(fstruct, n, s)
    PIX_ROT_FONT    fstruct;
    int		    n;
    char	   *s;
{
    pr_size	    ret;

    ret.x = XRotTextWidth(fstruct, s, n);
    ret.y = XRotTextHeight(fstruct, s, n);
    return (ret);
}

/* LINES */

static int	gc_thickness[NUMOPS], gc_line_style[NUMOPS];

static		GC
makegc(op, fg, bg)
    int		    op;
    Pixel	    fg;
    Pixel	    bg;
{
    register GC	    ngc;
    XGCValues	    gcv;
    unsigned long   gcmask;

    gcv.font = roman_font->fid;
    gcv.join_style = JoinMiter;
    gcmask = GCJoinStyle | GCFunction | GCForeground | GCBackground | GCFont;
    switch (op) {
    case PAINT:
	gcv.foreground = fg;
	gcv.background = bg;
	gcv.function = GXcopy;
	break;
    case ERASE:
	gcv.foreground = bg;
	gcv.background = bg;
	gcv.function = GXcopy;
	break;
    case INV_PAINT:
	gcv.foreground = fg ^ bg;
	gcv.background = bg;
	gcv.function = GXxor;
	break;
    case MERGE:
	gcv.foreground = fg;
	gcv.background = bg;
	gcv.function = GXor;
	break;
    }

    ngc = XCreateGC(tool_d, XtWindow(canvas_sw), gcmask, &gcv);
    XCopyGC(tool_d, gc, ~(gcmask), ngc);	/* add main gc's values to
						 * the new one */
    return (ngc);
}

init_gc()
{
    int		    i;

    gccache[PAINT] = makegc(PAINT, x_fg_color.pixel, x_bg_color.pixel);
    gccache[ERASE] = makegc(ERASE, x_fg_color.pixel, x_bg_color.pixel);
    gccache[INV_PAINT] = makegc(INV_PAINT, x_fg_color.pixel, x_bg_color.pixel);
    gccache[MERGE] = makegc(MERGE, x_fg_color.pixel, x_bg_color.pixel);

    for (i = 0; i < NUMOPS; i++) {
	gc_color[i] = -1;
	gc_thickness[i] = -1;
	gc_line_style[i] = -1;
    }
}

/* create the gc's for fill style (PAINT and ERASE) */
/* the fill_pm[] and unfill_pm[] must already be created */

init_fill_gc()
{
    XGCValues	    gcv;
    int		    i;

    gcv.fill_style = FillOpaqueStippled;
    gcv.arc_mode = ArcPieSlice; /* fill mode for arcs */
    gcv.fill_rule = EvenOddRule /* WindingRule */ ;
    for (i = 0; i < NUMFILLPATS; i++) {
	/* make color fill pattern with black bg (fg is set later in set_x_color() */
	fill_gc[i] = makegc(PAINT, x_fg_color.pixel, x_color(BLACK));
	un_fill_gc[i] = makegc(ERASE, x_fg_color.pixel, x_color(BLACK));
	/* make black fill pattern with default background */
	black_fill_gc[i] = makegc(PAINT, x_fg_color.pixel, x_bg_color.pixel);
	black_un_fill_gc[i] = makegc(ERASE, x_fg_color.pixel, x_bg_color.pixel);
	gcv.stipple = fill_pm[i];
	XChangeGC(tool_d, fill_gc[i],
		  GCStipple | GCFillStyle | GCFillRule | GCArcMode, &gcv);
	XChangeGC(tool_d, black_fill_gc[i],
		  GCStipple | GCFillStyle | GCFillRule | GCArcMode, &gcv);
	XChangeGC(tool_d, un_fill_gc[i],
		  GCStipple | GCFillStyle | GCArcMode, &gcv);
	XChangeGC(tool_d, black_un_fill_gc[i],
		  GCStipple | GCFillStyle | GCArcMode, &gcv);
    }
}

/* SHADING */

/* grey images for fill patterns (32x32) */

static unsigned char fill_images[NUMFILLPATS][128] = {
 {0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00},
 {0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x88,0x88,0x88,
 0x88,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x08,0x08,
 0x08,0x08,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x88,
 0x88,0x88,0x88,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
 0x08,0x08,0x08,0x08,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
 0x00,0x88,0x88,0x88,0x88,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
 0x00,0x00,0x08,0x08,0x08,0x08,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
 0x00,0x00,0x00,0x88,0x88,0x88,0x88,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
 0x00,0x00,0x00,0x00,0x08,0x08,0x08,0x08},
 {0x10,0x10,0x10,0x10,0x00,0x00,0x00,0x00,0x44,0x44,0x44,0x44,0x00,0x00,0x00,
 0x00,0x01,0x11,0x01,0x11,0x00,0x00,0x00,0x00,0x44,0x44,0x44,0x44,0x00,0x00,
 0x00,0x00,0x10,0x10,0x10,0x10,0x00,0x00,0x00,0x00,0x44,0x44,0x44,0x44,0x00,
 0x00,0x00,0x00,0x01,0x01,0x01,0x01,0x00,0x00,0x00,0x00,0x44,0x44,0x44,0x44,
 0x00,0x00,0x00,0x00,0x10,0x10,0x10,0x10,0x00,0x00,0x00,0x00,0x44,0x44,0x44,
 0x44,0x00,0x00,0x00,0x00,0x01,0x11,0x01,0x11,0x00,0x00,0x00,0x00,0x44,0x44,
 0x44,0x44,0x00,0x00,0x00,0x00,0x10,0x10,0x10,0x10,0x00,0x00,0x00,0x00,0x44,
 0x44,0x44,0x44,0x00,0x00,0x00,0x00,0x01,0x01,0x01,0x01,0x00,0x00,0x00,0x00,
 0x44,0x44,0x44,0x44,0x00,0x00,0x00,0x00},
 {0x00,0x00,0x00,0x00,0x11,0x51,0x11,0x51,0x00,0x00,0x00,0x00,0x44,0x44,0x44,
 0x44,0x00,0x00,0x00,0x00,0x15,0x15,0x15,0x15,0x00,0x00,0x00,0x00,0x44,0x44,
 0x44,0x44,0x00,0x00,0x00,0x00,0x51,0x11,0x51,0x11,0x00,0x00,0x00,0x00,0x44,
 0x44,0x44,0x44,0x00,0x00,0x00,0x00,0x15,0x15,0x15,0x15,0x00,0x00,0x00,0x00,
 0x44,0x44,0x44,0x44,0x00,0x00,0x00,0x00,0x11,0x51,0x11,0x51,0x00,0x00,0x00,
 0x00,0x44,0x44,0x44,0x44,0x00,0x00,0x00,0x00,0x15,0x15,0x15,0x15,0x00,0x00,
 0x00,0x00,0x44,0x44,0x44,0x44,0x00,0x00,0x00,0x00,0x51,0x11,0x51,0x11,0x00,
 0x00,0x00,0x00,0x44,0x44,0x44,0x44,0x00,0x00,0x00,0x00,0x15,0x15,0x15,0x15,
 0x00,0x00,0x00,0x00,0x44,0x44,0x44,0x44},
 {0x00,0x00,0x00,0x00,0xaa,0xaa,0xaa,0xaa,0x00,0x00,0x00,0x00,0x8a,0x88,0x8a,
 0x88,0x00,0x00,0x00,0x00,0xaa,0xaa,0xaa,0xaa,0x00,0x00,0x00,0x00,0x88,0x88,
 0x88,0x88,0x00,0x00,0x00,0x00,0xaa,0xaa,0xaa,0xaa,0x00,0x00,0x00,0x00,0x8a,
 0x8a,0x8a,0x8a,0x00,0x00,0x00,0x00,0xaa,0xaa,0xaa,0xaa,0x00,0x00,0x00,0x00,
 0x88,0x88,0x88,0x88,0x00,0x00,0x00,0x00,0xaa,0xaa,0xaa,0xaa,0x00,0x00,0x00,
 0x00,0x8a,0x88,0x8a,0x88,0x00,0x00,0x00,0x00,0xaa,0xaa,0xaa,0xaa,0x00,0x00,
 0x00,0x00,0x88,0x88,0x88,0x88,0x00,0x00,0x00,0x00,0xaa,0xaa,0xaa,0xaa,0x00,
 0x00,0x00,0x00,0x8a,0x8a,0x8a,0x8a,0x00,0x00,0x00,0x00,0xaa,0xaa,0xaa,0xaa,
 0x00,0x00,0x00,0x00,0x88,0x88,0x88,0x88},
 {0x55,0x55,0x55,0x55,0x00,0x00,0x00,0x00,0x55,0x55,0x55,0x55,0x00,0x00,0x00,
 0x00,0x55,0x55,0x55,0x55,0x00,0x00,0x00,0x00,0x55,0x55,0x55,0x55,0x00,0x00,
 0x00,0x00,0x55,0x55,0x55,0x55,0x00,0x00,0x00,0x00,0x55,0x55,0x55,0x55,0x00,
 0x00,0x00,0x00,0x55,0x55,0x55,0x55,0x00,0x00,0x00,0x00,0x55,0x55,0x55,0x55,
 0x00,0x00,0x00,0x00,0x55,0x55,0x55,0x55,0x00,0x00,0x00,0x00,0x55,0x55,0x55,
 0x55,0x00,0x00,0x00,0x00,0x55,0x55,0x55,0x55,0x00,0x00,0x00,0x00,0x55,0x55,
 0x55,0x55,0x00,0x00,0x00,0x00,0x55,0x55,0x55,0x55,0x00,0x00,0x00,0x00,0x55,
 0x55,0x55,0x55,0x00,0x00,0x00,0x00,0x55,0x55,0x55,0x55,0x00,0x00,0x00,0x00,
 0x55,0x55,0x55,0x55,0x00,0x00,0x00,0x00},
 {0x55,0x55,0x55,0x55,0x00,0x00,0x00,0x00,0x55,0x55,0x55,0x55,0x88,0x88,0x88,
 0x88,0x55,0x55,0x55,0x55,0x00,0x00,0x00,0x00,0x55,0x55,0x55,0x55,0x80,0x80,
 0x80,0x80,0x55,0x55,0x55,0x55,0x00,0x00,0x00,0x00,0x55,0x55,0x55,0x55,0x88,
 0x88,0x88,0x88,0x55,0x55,0x55,0x55,0x00,0x00,0x00,0x00,0x55,0x55,0x55,0x55,
 0x88,0x80,0x88,0x80,0x55,0x55,0x55,0x55,0x00,0x00,0x00,0x00,0x55,0x55,0x55,
 0x55,0x88,0x88,0x88,0x88,0x55,0x55,0x55,0x55,0x00,0x00,0x00,0x00,0x55,0x55,
 0x55,0x55,0x80,0x80,0x80,0x80,0x55,0x55,0x55,0x55,0x00,0x00,0x00,0x00,0x55,
 0x55,0x55,0x55,0x88,0x88,0x88,0x88,0x55,0x55,0x55,0x55,0x00,0x00,0x00,0x00,
 0x55,0x55,0x55,0x55,0x88,0x80,0x88,0x80},
 {0x22,0x22,0x22,0x22,0x55,0x55,0x55,0x55,0x80,0x80,0x80,0x80,0x55,0x55,0x55,
 0x55,0x22,0x22,0x22,0x22,0x55,0x55,0x55,0x55,0x88,0x08,0x88,0x08,0x55,0x55,
 0x55,0x55,0x22,0x22,0x22,0x22,0x55,0x55,0x55,0x55,0x80,0x80,0x80,0x80,0x55,
 0x55,0x55,0x55,0x22,0x22,0x22,0x22,0x55,0x55,0x55,0x55,0x08,0x08,0x08,0x08,
 0x55,0x55,0x55,0x55,0x22,0x22,0x22,0x22,0x55,0x55,0x55,0x55,0x80,0x80,0x80,
 0x80,0x55,0x55,0x55,0x55,0x22,0x22,0x22,0x22,0x55,0x55,0x55,0x55,0x88,0x08,
 0x88,0x08,0x55,0x55,0x55,0x55,0x22,0x22,0x22,0x22,0x55,0x55,0x55,0x55,0x80,
 0x80,0x80,0x80,0x55,0x55,0x55,0x55,0x22,0x22,0x22,0x22,0x55,0x55,0x55,0x55,
 0x08,0x08,0x08,0x08,0x55,0x55,0x55,0x55},
 {0x88,0x88,0x88,0x88,0x55,0x55,0x55,0x55,0x22,0xa2,0x22,0xa2,0x55,0x55,0x55,
 0x55,0x88,0x88,0x88,0x88,0x55,0x55,0x55,0x55,0x2a,0x2a,0x2a,0x2a,0x55,0x55,
 0x55,0x55,0x88,0x88,0x88,0x88,0x55,0x55,0x55,0x55,0xa2,0x22,0xa2,0x22,0x55,
 0x55,0x55,0x55,0x88,0x88,0x88,0x88,0x55,0x55,0x55,0x55,0x2a,0x2a,0x2a,0x2a,
 0x55,0x55,0x55,0x55,0x88,0x88,0x88,0x88,0x55,0x55,0x55,0x55,0x22,0xa2,0x22,
 0xa2,0x55,0x55,0x55,0x55,0x88,0x88,0x88,0x88,0x55,0x55,0x55,0x55,0x2a,0x2a,
 0x2a,0x2a,0x55,0x55,0x55,0x55,0x88,0x88,0x88,0x88,0x55,0x55,0x55,0x55,0xa2,
 0x22,0xa2,0x22,0x55,0x55,0x55,0x55,0x88,0x88,0x88,0x88,0x55,0x55,0x55,0x55,
 0x2a,0x2a,0x2a,0x2a,0x55,0x55,0x55,0x55},
 {0xaa,0xaa,0xaa,0xaa,0x55,0x55,0x55,0x55,0xaa,0xaa,0xaa,0xaa,0x54,0x54,0x54,
 0x54,0xaa,0xaa,0xaa,0xaa,0x55,0x55,0x55,0x55,0xaa,0xaa,0xaa,0xaa,0x44,0x44,
 0x44,0x44,0xaa,0xaa,0xaa,0xaa,0x55,0x55,0x55,0x55,0xaa,0xaa,0xaa,0xaa,0x44,
 0x54,0x44,0x54,0xaa,0xaa,0xaa,0xaa,0x55,0x55,0x55,0x55,0xaa,0xaa,0xaa,0xaa,
 0x44,0x44,0x44,0x44,0xaa,0xaa,0xaa,0xaa,0x55,0x55,0x55,0x55,0xaa,0xaa,0xaa,
 0xaa,0x54,0x54,0x54,0x54,0xaa,0xaa,0xaa,0xaa,0x55,0x55,0x55,0x55,0xaa,0xaa,
 0xaa,0xaa,0x44,0x44,0x44,0x44,0xaa,0xaa,0xaa,0xaa,0x55,0x55,0x55,0x55,0xaa,
 0xaa,0xaa,0xaa,0x44,0x54,0x44,0x54,0xaa,0xaa,0xaa,0xaa,0x55,0x55,0x55,0x55,
 0xaa,0xaa,0xaa,0xaa,0x44,0x44,0x44,0x44},
 {0x55,0x55,0x55,0x55,0xaa,0xaa,0xaa,0xaa,0x55,0x55,0x55,0x55,0xaa,0xaa,0xaa,
 0xaa,0x55,0x55,0x55,0x55,0xaa,0xaa,0xaa,0xaa,0x55,0x55,0x55,0x55,0xaa,0xaa,
 0xaa,0xaa,0x55,0x55,0x55,0x55,0xaa,0xaa,0xaa,0xaa,0x55,0x55,0x55,0x55,0xaa,
 0xaa,0xaa,0xaa,0x55,0x55,0x55,0x55,0xaa,0xaa,0xaa,0xaa,0x55,0x55,0x55,0x55,
 0xaa,0xaa,0xaa,0xaa,0x55,0x55,0x55,0x55,0xaa,0xaa,0xaa,0xaa,0x55,0x55,0x55,
 0x55,0xaa,0xaa,0xaa,0xaa,0x55,0x55,0x55,0x55,0xaa,0xaa,0xaa,0xaa,0x55,0x55,
 0x55,0x55,0xaa,0xaa,0xaa,0xaa,0x55,0x55,0x55,0x55,0xaa,0xaa,0xaa,0xaa,0x55,
 0x55,0x55,0x55,0xaa,0xaa,0xaa,0xaa,0x55,0x55,0x55,0x55,0xaa,0xaa,0xaa,0xaa,
 0x55,0x55,0x55,0x55,0xaa,0xaa,0xaa,0xaa},
 {0xdd,0xdd,0xdd,0xdd,0xaa,0xaa,0xaa,0xaa,0x55,0x55,0x55,0x55,0xaa,0xaa,0xaa,
 0xaa,0xd5,0xd5,0xd5,0xd5,0xaa,0xaa,0xaa,0xaa,0x55,0x55,0x55,0x55,0xaa,0xaa,
 0xaa,0xaa,0xdd,0xdd,0xdd,0xdd,0xaa,0xaa,0xaa,0xaa,0x55,0x55,0x55,0x55,0xaa,
 0xaa,0xaa,0xaa,0xdd,0xd5,0xdd,0xd5,0xaa,0xaa,0xaa,0xaa,0x55,0x55,0x55,0x55,
 0xaa,0xaa,0xaa,0xaa,0xdd,0xdd,0xdd,0xdd,0xaa,0xaa,0xaa,0xaa,0x55,0x55,0x55,
 0x55,0xaa,0xaa,0xaa,0xaa,0xd5,0xd5,0xd5,0xd5,0xaa,0xaa,0xaa,0xaa,0x55,0x55,
 0x55,0x55,0xaa,0xaa,0xaa,0xaa,0xdd,0xdd,0xdd,0xdd,0xaa,0xaa,0xaa,0xaa,0x55,
 0x55,0x55,0x55,0xaa,0xaa,0xaa,0xaa,0xdd,0xd5,0xdd,0xd5,0xaa,0xaa,0xaa,0xaa,
 0x55,0x55,0x55,0x55,0xaa,0xaa,0xaa,0xaa},
 {0x77,0x77,0x77,0x77,0xaa,0xaa,0xaa,0xaa,0xd5,0xd5,0xd5,0xd5,0xaa,0xaa,0xaa,
 0xaa,0x77,0x77,0x77,0x77,0xaa,0xaa,0xaa,0xaa,0xdd,0x5d,0xdd,0x5d,0xaa,0xaa,
 0xaa,0xaa,0x77,0x77,0x77,0x77,0xaa,0xaa,0xaa,0xaa,0xd5,0xd5,0xd5,0xd5,0xaa,
 0xaa,0xaa,0xaa,0x77,0x77,0x77,0x77,0xaa,0xaa,0xaa,0xaa,0x5d,0xdd,0x5d,0xdd,
 0xaa,0xaa,0xaa,0xaa,0x77,0x77,0x77,0x77,0xaa,0xaa,0xaa,0xaa,0xd5,0xd5,0xd5,
 0xd5,0xaa,0xaa,0xaa,0xaa,0x77,0x77,0x77,0x77,0xaa,0xaa,0xaa,0xaa,0xdd,0x5d,
 0xdd,0x5d,0xaa,0xaa,0xaa,0xaa,0x77,0x77,0x77,0x77,0xaa,0xaa,0xaa,0xaa,0xd5,
 0xd5,0xd5,0xd5,0xaa,0xaa,0xaa,0xaa,0x77,0x77,0x77,0x77,0xaa,0xaa,0xaa,0xaa,
 0x5d,0xdd,0x5d,0xdd,0xaa,0xaa,0xaa,0xaa},
 {0x55,0x55,0x55,0x55,0xbb,0xbb,0xbb,0xbb,0x55,0x55,0x55,0x55,0xfe,0xfe,0xfe,
 0xfe,0x55,0x55,0x55,0x55,0xbb,0xbb,0xbb,0xbb,0x55,0x55,0x55,0x55,0xee,0xef,
 0xee,0xef,0x55,0x55,0x55,0x55,0xbb,0xbb,0xbb,0xbb,0x55,0x55,0x55,0x55,0xfe,
 0xfe,0xfe,0xfe,0x55,0x55,0x55,0x55,0xbb,0xbb,0xbb,0xbb,0x55,0x55,0x55,0x55,
 0xef,0xef,0xef,0xef,0x55,0x55,0x55,0x55,0xbb,0xbb,0xbb,0xbb,0x55,0x55,0x55,
 0x55,0xfe,0xfe,0xfe,0xfe,0x55,0x55,0x55,0x55,0xbb,0xbb,0xbb,0xbb,0x55,0x55,
 0x55,0x55,0xee,0xef,0xee,0xef,0x55,0x55,0x55,0x55,0xbb,0xbb,0xbb,0xbb,0x55,
 0x55,0x55,0x55,0xfe,0xfe,0xfe,0xfe,0x55,0x55,0x55,0x55,0xbb,0xbb,0xbb,0xbb,
 0x55,0x55,0x55,0x55,0xef,0xef,0xef,0xef},
 {0xff,0xff,0xff,0xff,0xaa,0xaa,0xaa,0xaa,0x77,0x77,0x77,0x77,0xaa,0xaa,0xaa,
 0xaa,0xff,0xff,0xff,0xff,0xaa,0xaa,0xaa,0xaa,0x77,0x7f,0x77,0x7f,0xaa,0xaa,
 0xaa,0xaa,0xff,0xff,0xff,0xff,0xaa,0xaa,0xaa,0xaa,0x77,0x77,0x77,0x77,0xaa,
 0xaa,0xaa,0xaa,0xff,0xff,0xff,0xff,0xaa,0xaa,0xaa,0xaa,0x7f,0x7f,0x7f,0x7f,
 0xaa,0xaa,0xaa,0xaa,0xff,0xff,0xff,0xff,0xaa,0xaa,0xaa,0xaa,0x77,0x77,0x77,
 0x77,0xaa,0xaa,0xaa,0xaa,0xff,0xff,0xff,0xff,0xaa,0xaa,0xaa,0xaa,0x77,0x7f,
 0x77,0x7f,0xaa,0xaa,0xaa,0xaa,0xff,0xff,0xff,0xff,0xaa,0xaa,0xaa,0xaa,0x77,
 0x77,0x77,0x77,0xaa,0xaa,0xaa,0xaa,0xff,0xff,0xff,0xff,0xaa,0xaa,0xaa,0xaa,
 0x7f,0x7f,0x7f,0x7f,0xaa,0xaa,0xaa,0xaa},
 {0xff,0xff,0xff,0xff,0xaa,0xaa,0xaa,0xaa,0xff,0xff,0xff,0xff,0xaa,0xaa,0xaa,
 0xaa,0xff,0xff,0xff,0xff,0xaa,0xaa,0xaa,0xaa,0xff,0xff,0xff,0xff,0xaa,0xaa,
 0xaa,0xaa,0xff,0xff,0xff,0xff,0xaa,0xaa,0xaa,0xaa,0xff,0xff,0xff,0xff,0xaa,
 0xaa,0xaa,0xaa,0xff,0xff,0xff,0xff,0xaa,0xaa,0xaa,0xaa,0xff,0xff,0xff,0xff,
 0xaa,0xaa,0xaa,0xaa,0xff,0xff,0xff,0xff,0xaa,0xaa,0xaa,0xaa,0xff,0xff,0xff,
 0xff,0xaa,0xaa,0xaa,0xaa,0xff,0xff,0xff,0xff,0xaa,0xaa,0xaa,0xaa,0xff,0xff,
 0xff,0xff,0xaa,0xaa,0xaa,0xaa,0xff,0xff,0xff,0xff,0xaa,0xaa,0xaa,0xaa,0xff,
 0xff,0xff,0xff,0xaa,0xaa,0xaa,0xaa,0xff,0xff,0xff,0xff,0xaa,0xaa,0xaa,0xaa,
 0xff,0xff,0xff,0xff,0xaa,0xaa,0xaa,0xaa},
 {0x55,0x55,0x55,0x55,0xff,0xff,0xff,0xff,0xdd,0xdd,0xdd,0xdd,0xff,0xff,0xff,
 0xff,0x55,0x55,0x55,0x55,0xff,0xff,0xff,0xff,0x5d,0xdd,0x5d,0xdd,0xff,0xff,
 0xff,0xff,0x55,0x55,0x55,0x55,0xff,0xff,0xff,0xff,0xdd,0xdd,0xdd,0xdd,0xff,
 0xff,0xff,0xff,0x55,0x55,0x55,0x55,0xff,0xff,0xff,0xff,0x5d,0x5d,0x5d,0x5d,
 0xff,0xff,0xff,0xff,0x55,0x55,0x55,0x55,0xff,0xff,0xff,0xff,0xdd,0xdd,0xdd,
 0xdd,0xff,0xff,0xff,0xff,0x55,0x55,0x55,0x55,0xff,0xff,0xff,0xff,0x5d,0xdd,
 0x5d,0xdd,0xff,0xff,0xff,0xff,0x55,0x55,0x55,0x55,0xff,0xff,0xff,0xff,0xdd,
 0xdd,0xdd,0xdd,0xff,0xff,0xff,0xff,0x55,0x55,0x55,0x55,0xff,0xff,0xff,0xff,
 0x5d,0x5d,0x5d,0x5d,0xff,0xff,0xff,0xff},
 {0xee,0xee,0xee,0xee,0xff,0xff,0xff,0xff,0xbb,0xba,0xba,0xba,0xff,0xff,0xff,
 0xff,0xee,0xee,0xee,0xee,0xff,0xff,0xff,0xff,0xab,0xbb,0xab,0xbb,0xff,0xff,
 0xff,0xff,0xee,0xee,0xee,0xee,0xff,0xff,0xff,0xff,0xbb,0xba,0xba,0xba,0xff,
 0xff,0xff,0xff,0xee,0xee,0xee,0xee,0xff,0xff,0xff,0xff,0xbb,0xab,0xbb,0xab,
 0xff,0xff,0xff,0xff,0xee,0xee,0xee,0xee,0xff,0xff,0xff,0xff,0xbb,0xba,0xba,
 0xba,0xff,0xff,0xff,0xff,0xee,0xee,0xee,0xee,0xff,0xff,0xff,0xff,0xab,0xbb,
 0xab,0xbb,0xff,0xff,0xff,0xff,0xee,0xee,0xee,0xee,0xff,0xff,0xff,0xff,0xbb,
 0xba,0xba,0xba,0xff,0xff,0xff,0xff,0xee,0xee,0xee,0xee,0xff,0xff,0xff,0xff,
 0xbb,0xab,0xbb,0xab,0xff,0xff,0xff,0xff},
 {0xff,0xff,0xff,0xff,0xee,0xee,0xee,0xee,0xff,0xff,0xff,0xff,0xfb,0xfb,0xfb,
 0xfb,0xff,0xff,0xff,0xff,0xee,0xee,0xee,0xee,0xff,0xff,0xff,0xff,0xbf,0xbb,
 0xbf,0xbb,0xff,0xff,0xff,0xff,0xee,0xee,0xee,0xee,0xff,0xff,0xff,0xff,0xfb,
 0xfb,0xfb,0xfb,0xff,0xff,0xff,0xff,0xee,0xee,0xee,0xee,0xff,0xff,0xff,0xff,
 0xbf,0xbf,0xbf,0xbf,0xff,0xff,0xff,0xff,0xee,0xee,0xee,0xee,0xff,0xff,0xff,
 0xff,0xfb,0xfb,0xfb,0xfb,0xff,0xff,0xff,0xff,0xee,0xee,0xee,0xee,0xff,0xff,
 0xff,0xff,0xbf,0xbb,0xbf,0xbb,0xff,0xff,0xff,0xff,0xee,0xee,0xee,0xee,0xff,
 0xff,0xff,0xff,0xfb,0xfb,0xfb,0xfb,0xff,0xff,0xff,0xff,0xee,0xee,0xee,0xee,
 0xff,0xff,0xff,0xff,0xbf,0xbf,0xbf,0xbf},
 {0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xbb,0xbb,0xbb,
 0xbb,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xfb,0xfb,
 0xfb,0xfb,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xbb,
 0xbb,0xbb,0xbb,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,
 0xfb,0xfb,0xfb,0xfb,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,
 0xff,0xbb,0xbb,0xbb,0xbb,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,
 0xff,0xff,0xfb,0xfb,0xfb,0xfb,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,
 0xff,0xff,0xff,0xbb,0xbb,0xbb,0xbb,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,
 0xff,0xff,0xff,0xff,0xfb,0xfb,0xfb,0xfb},
 {0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,
 0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,
 0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,
 0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,
 0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,
 0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,
 0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,
 0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,
 0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff},
};

/* generate the fill pixmaps */

init_fill_pm()
{
    int		    i;

    for (i = 0; i < NUMFILLPATS + 1; i++) {
	fillstyle_choices[i].value = i;
	fillstyle_choices[i].icon = &none_ic;
    }
    /* use same colors for "NONE" indicator for black and color */
    fillstyle_choices[0].normalPM = 
	fillstyle_choices[0].blackPM = XCreatePixmapFromBitmapData(tool_d,
			XtWindow(ind_panel), (char *) none_ic.data, none_ic.width,
			none_ic.height, x_fg_color.pixel, x_bg_color.pixel,
			DefaultDepthOfScreen(tool_s));

    for (i = 0; i < NUMFILLPATS; i++) {
	fill_pm[i] = XCreateBitmapFromData(tool_d, XtWindow(canvas_sw),
					   (char *) fill_images[i], 32, 32);
	/* create fill style pixmaps for indicator button */
	fillstyle_choices[i + 1].normalPM = XCreatePixmapFromBitmapData(tool_d,
		 XtWindow(canvas_sw), (char *) fill_images[i], 32, 32, 
		 x_bg_color.pixel,x_fg_color.pixel,DefaultDepthOfScreen(tool_s));
	fillstyle_choices[i + 1].blackPM = XCreatePixmapFromBitmapData(tool_d,
		 XtWindow(canvas_sw), (char *) fill_images[i], 32, 32, 
		 x_fg_color.pixel,x_bg_color.pixel,DefaultDepthOfScreen(tool_s));
    }
}

pw_vector(w, x1, y1, x2, y2, op, line_width, line_style, style_val, color)
    Window	    w;
    int		    x1, y1, x2, y2, op, line_width, line_style;
    float	    style_val;
    Color	    color;
{
    if (line_width == 0)
	return;
    set_line_stuff(line_width, line_style, style_val, op, color);
    if (line_style == PANEL_LINE)
	XDrawLine(tool_d, w, gccache[op], x1, y1, x2, y2);
    else
	zXDrawLine(tool_d, w, gccache[op], x1, y1, x2, y2);
}

pw_curve(w, xstart, ystart, xend, yend,
	 op, linewidth, style, style_val, fill_style, color)
    Window	    w;
    int		    xstart, ystart, xend, yend;
    int		    op, linewidth, style, fill_style;
    float	    style_val;
    Color	    color;
{
    short	    xmin, ymin;
    unsigned short  wd, ht;

    xmin = (short) min2(xstart, xend);
    ymin = (short) min2(ystart, yend);
    wd = (unsigned short) abs(xstart - xend);
    ht = (unsigned short) abs(ystart - yend);

    /* if it's a fill pat we know about */
    if (fill_style >= 1 && fill_style <= NUMFILLPATS) {
	set_fillgc(fill_style, op, color);
	zXFillArc(tool_d, w, fillgc, xmin, ymin, wd, ht, 0, 360 * 64);
    }
    if (linewidth == 0)
	return;
    if (op == ERASE) {
	/* kludge - to speed things up we erase with thick solid lines */
	set_line_stuff(linewidth + 3, SOLID_LINE, 0.0, op, color);	/* +2 or +3 ok */
	zXDrawArc(tool_d, w, gccache[op], xmin, ymin, wd, ht, 0, 360 * 64);
    } else {
	set_line_stuff(linewidth, style, style_val, op, color);
	zXDrawArc(tool_d, w, gccache[op], xmin, ymin, wd, ht, 0, 360 * 64);
    }
}

pw_point(w, x, y, line_width, op, color)
    Window	    w;
    int		    x, y;
    int		    op, line_width;
    Color	    color;
{
    /* pw_point doesn't use line_style or fill_style - maybe not needed */
    /* (needs color though - hns) */
    set_line_stuff(line_width, SOLID_LINE, 0.0, op, color);
    zXDrawPoint(tool_d, w, gccache[op], x, y);
}

pw_arcbox(w, xmin, ymin, xmax, ymax, radius, op,
	  line_width, line_style, style_val, fill_style, color)
    Window	    w;
    int		    xmin, ymin, xmax, ymax, radius;
    int		    op, line_width, line_style, fill_style;
    float	    style_val;
    Color	    color;
{
    GC		    gc;
    int		    diam = 2 * radius;

    /* if it's a fill pat we know about */
    if (fill_style >= 1 && fill_style <= NUMFILLPATS) {
	set_fillgc(fill_style, op, color);
	/* upper left */
	zXFillArc(tool_d, w, fillgc, xmin, ymin, diam, diam, 90 * 64, 90 * 64);
	/* lower left */
	zXFillArc(tool_d, w, fillgc, xmin, ymax - diam, diam, diam,
		  180 * 64, 90 * 64);
	/* lower right */
	zXFillArc(tool_d, w, fillgc, xmax - diam, ymax - diam, diam, diam,
		  270 * 64, 90 * 64);
	/* upper right */
	zXFillArc(tool_d, w, fillgc, xmax - diam, ymin, diam, diam,
		  0 * 64, 90 * 64);
	/* fill strip on left side between upper and lower arcs */
	if (ymax - ymin - diam > 0)
	    zXFillRectangle(tool_d, w, fillgc, xmin, ymin + radius, radius,
			    ymax - ymin - diam);
	/* fill middle section */
	if (xmax - xmin - diam > 0)
	    zXFillRectangle(tool_d, w, fillgc, xmin + radius, ymin,
			    xmax - xmin - diam, ymax - ymin);
	/* fill strip on right side between upper and lower arcs */
	if (ymax - ymin - diam > 0)
	    zXFillRectangle(tool_d, w, fillgc, xmax - radius, ymin + radius,
			    radius, ymax - ymin - diam);
    }
    if (line_width == 0)
	return;

    set_line_stuff(line_width, line_style, style_val, op, color);
    gc = gccache[op];
    zXDrawArc(tool_d, w, gc, xmin, ymin, diam, diam, 90 * 64, 90 * 64);
    zXDrawLine(tool_d, w, gc, xmin, ymin + radius, xmin, ymax - radius + 1);
    zXDrawArc(tool_d, w, gc, xmin, ymax - diam, diam, diam, 180 * 64, 90 * 64);
    zXDrawLine(tool_d, w, gc, xmin + radius, ymax, xmax - radius + 1, ymax);
    zXDrawArc(tool_d, w, gc, xmax - diam, ymax - diam,
	      diam, diam, 270 * 64, 90 * 64);
    zXDrawLine(tool_d, w, gc, xmax, ymax - radius, xmax, ymin + radius - 1);
    zXDrawArc(tool_d, w, gc, xmax - diam, ymin, diam, diam, 0 * 64, 90 * 64);
    zXDrawLine(tool_d, w, gc, xmax - radius, ymin, xmin + radius - 1, ymin);
}

pw_lines(w, points, npoints, op, line_width, line_style, style_val, fill_style, color)
    Window	    w;
    int		    npoints;
    XPoint	   *points;
    int		    op, line_width, line_style, fill_style;
    float	    style_val;
    Color	    color;
{
    /* if it's a fill pat we know about */
    if (fill_style >= 1 && fill_style <= NUMFILLPATS) {
	set_fillgc(fill_style, op, color);
	if (line_style == PANEL_LINE)
	    XFillPolygon(tool_d, w, fillgc, points, npoints,
			 Complex, CoordModeOrigin);
	else
	    zXFillPolygon(tool_d, w, fillgc, points, npoints,
			  Complex, CoordModeOrigin);
    }
    if (line_width == 0)
	return;
    set_line_stuff(line_width, line_style, style_val, op, color);
    if (line_style == PANEL_LINE)
	XDrawLines(tool_d, w, gccache[op], points, npoints, CoordModeOrigin);
    else
	zXDrawLines(tool_d, w, gccache[op], points, npoints, CoordModeOrigin);
}

set_clip_window(xmin, ymin, xmax, ymax)
    int		    xmin, ymin, xmax, ymax;
{
    clip_xmin = clip[0].x = xmin;
    clip_ymin = clip[0].y = ymin;
    clip_xmax = xmax;
    clip_ymax = ymax;
    clip_width = clip[0].width = xmax - xmin;
    clip_height = clip[0].height = ymax - ymin;
    XSetClipRectangles(tool_d, gccache[PAINT], 0, 0, clip, 1, YXBanded);
    XSetClipRectangles(tool_d, gccache[INV_PAINT], 0, 0, clip, 1, YXBanded);
}

set_zoomed_clip_window(xmin, ymin, xmax, ymax)
    int		    xmin, ymin, xmax, ymax;
{
    set_clip_window(ZOOMX(xmin), ZOOMY(ymin), ZOOMX(xmax), ZOOMY(ymax));
}

reset_clip_window()
{
    set_clip_window(0, 0, CANVAS_WD, CANVAS_HT);
}

set_fillgc(fill_style, op, color)
    int		    fill_style;
    int		    op;
    Color	    color;
{
    if (op == PAINT) {
	fillgc = ((color==BLACK || 
	     (color==DEFAULT_COLOR && x_fg_color.pixel==appres.color[BLACK]) ||
	     (!all_colors_available && color!=WHITE))? 
		black_fill_gc[fill_style - 1]: fill_gc[fill_style - 1]);
	if (writing_bitmap)
	    {
	    if (color == WHITE)
		color = 0;
	    else
		color = 1;
	    XSetForeground(tool_d,fillgc,color);
	    }
	else
	    set_x_color(fillgc, color);
    } else
	fillgc = ((color==BLACK || 
	     (color==DEFAULT_COLOR && x_fg_color.pixel==appres.color[BLACK]) ||
	     (!all_colors_available && color!=WHITE))? 
		black_un_fill_gc[fill_style - 1]: un_fill_gc[fill_style - 1]);
    XSetClipRectangles(tool_d, fillgc, 0, 0, clip, 1, YXBanded);
}

set_line_stuff(width, style, style_val, op, color)
    int		    width, style, op;
    float	    style_val;
    Color	    color;
{
    XGCValues	    gcv;
    unsigned long   mask;
    static unsigned char dash_list[2] = {-1, -1};

    switch (style) {
    case RUBBER_LINE:
	width = 0;
	break;
    case PANEL_LINE:
	break;
    default:
	width = round(zoomscale * width);
	break;
    }

    /* user zero-width lines for speed with SOLID lines */
    /* can't do this for dashed lines because server isn't */
    /* required to draw dashes for zero-width lines */
    if (width == 1 && style == SOLID_LINE)
	width = 0;

    /* if we're drawing to the bitmap instead of the canvas
       map colors white => white, all others => black */
    if (writing_bitmap)
	{
	if (color == WHITE)
		color = 0;
	else
		color = 1;
	}
    /* see if all gc stuff is already correct */

    if (width == gc_thickness[op] && style == gc_line_style[op] &&
	(writing_bitmap? color == gc_color[op] : x_color(color) == gc_color[op]) &&
	(style != DASH_LINE && style != DOTTED_LINE ||
	 dash_list[1] == (char) round(style_val * zoomscale)))
	return;			/* no need to change anything */

    gcv.line_width = width;
    mask = GCLineWidth | GCLineStyle | GCCapStyle;
    if (op == PAINT)
	mask |= GCForeground;
    gcv.line_style = (style == DASH_LINE || style == DOTTED_LINE) ?
	LineOnOffDash : LineSolid;
    gcv.cap_style = (style == DOTTED_LINE) ? CapRound : CapButt;
    gcv.foreground = (writing_bitmap? color : x_color(color));

    XChangeGC(tool_d, gccache[op], mask, &gcv);
    if (style == DASH_LINE || style == DOTTED_LINE) {
	if (style_val > 0.0) {	/* style_val of 0.0 causes problems */
	    /* length of ON/OFF pixels */
	    dash_list[0] = dash_list[1] = (char) round(style_val *zoomscale);
	    if (dash_list[0]==0)		/* take care for rounding to zero ! */
		dash_list[0]=dash_list[1]=1;

	    if (style == DOTTED_LINE)
		dash_list[0] = 1;	/* length of ON pixels for dotted */
	    XSetDashes(tool_d, gccache[op], 0, (char *) dash_list, 2);
	}
    }
    gc_thickness[op] = width;
    gc_line_style[op] = style;
    gc_color[op] = writing_bitmap? color : x_color(color);
}
