v04i072: xpic -- pic previewer for X11, Part07/15

Dan Heller argv at island.uu.net
Sat Jul 22 17:40:31 AEST 1989


Submitted-by: Mark Moraes <moraes at ai.toronto.edu>
Posting-number: Volume 4, Issue 72
Archive-name: xpic/part07



#! /bin/sh
# This is a shell archive.  Remove anything before this line, then unpack
# it by saving it into a file and typing "sh file".  To overwrite existing
# files, type "sh file -c".  You can also feed this as standard input via
# unshar, or by typing "sh <file", e.g..  If this archive is complete, you
# will see the following message at the end:
#		"End of archive 7 (of 15)."
# Contents:  xpic/ask.c xpic/event.c xpic/handlers.c xpic/obj_block.c
#   xpic/obj_line.c
# Wrapped by moraes at neat.ai on Thu Jul 13 22:36:08 1989
PATH=/bin:/usr/bin:/usr/ucb ; export PATH
if test -f 'xpic/ask.c' -a "${1}" != "-c" ; then 
  echo shar: Will not clobber existing file \"'xpic/ask.c'\"
else
echo shar: Extracting \"'xpic/ask.c'\" \(9084 characters\)
sed "s/^X//" >'xpic/ask.c' <<'END_OF_FILE'
X/* This file contains code from the JOVE screen editor */
X
X/************************************************************************
X * JOVE is Copyright (C) 1986 by Jonathan Payne.  JOVE is               *
X * provided to you without charge, and with no warranty.  You may give  *
X * away copies of JOVE, including sources, provided that this notice is *
X * included in all the files.                                           *
X ************************************************************************/
X
X/*
X *  Modified by Mark Moraes for use in a widget for the X Windows System
X *  Version 11. This file is still independent of the X Windows System.
X */
X
X/* The routines in this file perform Tenex-style filename completion. 
X   The routine to be called is 
X	f_complete(buf, cursorposition, cols, c)
X	char *buf;
X
X   where 'buf' contains the filename so far. 'cursorposition' is the 
X   location of the cursor in 'buf' - it should be at the end of the 'buf'.
X   'cols' is the width of the screen used for typeout, (the listing of files)
X   and 'c' is one of ' ', '\t', and '?'. For the former two, f_complete
X   attempts to complete the name in 'buf', and for the latter, it
X   lists out the files which match the name so far using the typeout
X   routines.
X
X   It requires two sets of external routines to do this - insert_s(), 
X   add_mess() and rbell() are used for completion, and TOstart(), 
X   Typeout(), and TOstop() are used for typeout. These are described 
X   below 
X */
X#include <ctype.h>
X#include <signal.h>
X#include <varargs.h>
X#include <stdio.h>
X#ifdef XWINDOWS
X# include <X11/Xos.h>
X#else
X# include <strings.h>
X# include <sys/types.h>
X#endif
X#include <sys/stat.h>
X#ifdef DIRENT
X# include <sys/param.h>
X# include <dirent.h>
X# ifndef DIRSIZE
X#  define DIRSIZE(entry)	DIRSIZ
X# endif
X# ifndef direct
X#  define direct	dirent
X# endif
X#else
X# include <sys/dir.h>
X# define DIRSIZE(entry)	DIRSIZ(entry)
X#endif DIRENT
X
X#define FILESIZE	128
X#define TRUE		1
X#define FALSE		0
X#define min(x, y)	((x) < (y) ? (x) : (y))
X#define max(x, y)	((x) > (y) ? (x) : (y))
X
Xstatic char *linebuf;
Xstatic int curchar;
Xstatic int maxCols;
X
Xextern char *malloc();
Xextern char *realloc();
X
X/**********************External functions **********************************/
X/* insert_s(at, s, len, curpos) char *at, *s; int len; int *curpos;
X *	deletes from 'at' to the end of the line, and inserts the first len
X *	characters of 's' there. It returns 'curpos' as the new end of the
X *	string being edited - the cursor should now be there
X */
Xextern void insert_s();
X
X/* add_mess(s) char *s;
X *	inserts 's' at the end of the buffer, then waits a respectable
X *	interval, deletes 's', and returns
X */
Xextern void add_mess();
X
X/* rbell()
X *	Rings a bell or attracts the user's attention in some other way 
X */
Xextern void rbell();
X
X/* TOstart(s) char *s;
X *	Starts the typeout, and prints 's' as a title. Typeout is some 
X *	sort of overlay 'window' or something, for temporary output, 
X *	which can popup, and vanish after the user has read it. 
X */
Xextern TOstart();
X
X/* Typeout(fmt, args) char *fmt; va_dcl args;
X *	Is like printf() - prints args according to format 'fmt'. 
X *	Is a <varargs> routine
X */
Xextern Typeout();
X
X/* TOstop()
X *	End of typeout - this performs some sort of wait()
X *	- like for a keypress or a mouse click. It then cleans up
X *	the typeout and returns.
X */
Xextern TOstop();
X
Xchar *xmalloc(n)
X{
X	extern char *malloc();
X	char *p = malloc((unsigned) n);
X
X	if (!p) {
X		(void) fprintf(stderr, "out of memory in malloc\n");
X		exit(-1);
X	}
X	return p;
X}
X
Xchar *xrealloc(s, n)
Xchar *s;
X{
X	extern char *realloc();
X	char *p = realloc(s, (unsigned) n);
X
X	if (!p) {
X		(void) fprintf(stderr, "out of memory in realloc\n");
X		exit(-1);
X	}
X	return p;
X}
X
X/* Scandir returns the number of entries or -1 if the directory cannoot
X   be opened or malloc fails. */
X
Xint
Xmyscandir(dir, nmptr, qualify, sorter)
Xchar	*dir;
Xchar	***nmptr;
Xint	(*qualify)();
Xint	(*sorter)();
X{
X	DIR	*dirp;
X	struct direct	*entry;
X	char	**ourarray;
X	int	nalloc = 10;
X	int	nentries = 0;
X
X	if ((dirp = opendir(dir)) == 0)
X		return -1;
X	ourarray = (char **) xmalloc(nalloc * sizeof (char *));
X	while ((entry = readdir(dirp)) != 0) {
X		if (qualify != 0 && (*qualify)(entry->d_name) == 0)
X			continue;
X		if (nentries == nalloc) {
X			ourarray = (char **) xrealloc((char *) ourarray, (nalloc += 10) * sizeof (char *));
X		}
X		ourarray[nentries] = (char *) xmalloc((int) DIRSIZE(entry) + 1);
X		null_ncpy(ourarray[nentries], entry->d_name, (int) DIRSIZE(entry));
X		nentries++;
X	}
X	closedir(dirp);
X	if ((nentries + 1) != nalloc)
X		ourarray = (char **) xrealloc((char *) ourarray,
X					((nentries + 1) * sizeof (char *)));
X	if (sorter != 0)
X		qsort((char *) ourarray, nentries, sizeof (char **), sorter);
X	*nmptr = ourarray;
X	ourarray[nentries] = 0;		/* guaranteed 0 pointer */
X
X	return nentries;
X}
X
Xfreedir(nmptr, nentries)
Xchar	***nmptr;
X{
X	char	**ourarray = *nmptr;
X
X	while (--nentries >= 0)
X		free(*ourarray++);
X	free((char *) *nmptr);
X	*nmptr = 0;
X}
X
Xalphacomp(a, b)
Xchar	**a,
X	**b;
X{
X	return strcmp(*a, *b);
X}
X
Xnumcomp(s1, s2)
Xregister char	*s1,
X		*s2;
X{
X	register int	count = 0;
X
X	while (*s1 != 0 && *s1++ == *s2++)
X		count++;
X	return count;
X}
X
Xstatic char	*fc_filebase;
Xchar	BadExtensions[128] = ".o";
X
Xstatic
Xbad_extension(name, bads)
Xchar	*name,
X	*bads;
X{
X	char	*ip;
X	int	namelen = strlen(name),
X		ext_len,
X		stop = 0;
X
X	do {
X		if (ip = index(bads, ' '))
X			*ip = 0;
X		else {
X			ip = bads + strlen(bads);
X			stop++;
X		}
X		if ((ext_len = ip - bads) == 0)
X			continue;
X		if ((ext_len < namelen) &&
X		    (strcmp(&name[namelen - ext_len], bads) == 0))
X			return TRUE;
X	} while ((bads = ip + 1), !stop);
X	return FALSE;
X}
X
Xf_match(file)
Xchar	*file;
X{
X	int	len = strlen(fc_filebase);
X
X	return ((len == 0) ||
X		(strncmp(file, fc_filebase, strlen(fc_filebase)) == 0));
X}
X
Xstatic
Xisdir(name)
Xchar	*name;
X{
X	struct stat	stbuf;
X	char	filebuf[FILESIZE];
X
X	PathParse(name, filebuf);
X	return ((stat(filebuf, &stbuf) != -1) &&
X		(stbuf.st_mode & S_IFDIR) == S_IFDIR);
X}
X
Xstatic
Xfill_in(dir_vec, n)
Xregister char	**dir_vec;
X{
X	int	minmatch = 0,
X    		numfound = 0,
X    		lastmatch = -1,
X		i,
X		the_same = TRUE, /* After filling in, are we the same
X				    as when we were called? */
X		is_ntdir;	/* Is Newly Typed Directory name */
X	char	bads[128];
X
X	for (i = 0; i < n; i++) {
X		(void) strcpy(bads, BadExtensions);
X		/* bad_extension() is destructive */
X		if (bad_extension(dir_vec[i], bads))
X			continue;
X		if (numfound)
X			minmatch = min(minmatch,
X				       numcomp(dir_vec[lastmatch], dir_vec[i]));
X		else
X			minmatch = strlen(dir_vec[i]);
X		lastmatch = i;
X		numfound++;
X	}
X	/* Ugh.  Beware--this is hard to get right in a reasonable
X	   manner.  Please excuse this code--it's past my bedtime. */
X	if (numfound == 0) {
X		rbell();
X		return;
X	}
X	if (minmatch > strlen(fc_filebase)) {
X		the_same = FALSE;
X		insert_s(fc_filebase, dir_vec[lastmatch], minmatch, &curchar);
X	}
X	is_ntdir = ((numfound == 1) &&
X		    (curchar > 0) &&
X		    (linebuf[curchar - 1] != '/') &&
X		    (isdir(linebuf)));
X	if (the_same && !is_ntdir) {
X		add_mess((n == 1) ? " [Unique]" : " [Ambiguous]");
X	}
X	if (is_ntdir)
X		insert_s(&linebuf[curchar], "/", 1, &curchar);
X}
X
X/*
X *  called when one of "\t ?" is typed.  Does the right thing,
X *  depending on which.
X */
X
Xf_complete(sbuf, curpos, cols, c)
Xchar *sbuf;
X{
X	char	dir[FILESIZE],
X		**dir_vec;
X	int	nentries;
X#ifdef TYPEOUT
X	int	i;
X#endif
X
X	linebuf = sbuf;
X	curchar = curpos;
X	maxCols = cols;
X	
X	if (linebuf[curpos] != '\0')
X		linebuf[curpos] = '\0';
X		
X	if ((fc_filebase = rindex(linebuf, '/')) != 0) {
X		char	tmp[FILESIZE];
X
X		null_ncpy(tmp, linebuf, (++fc_filebase - linebuf));
X		if (tmp[0] == '\0')
X			(void) strcpy(tmp, "/");
X		PathParse(tmp, dir);
X	} else {		
X		fc_filebase = linebuf;
X		(void) strcpy(dir, ".");
X	}
X	if ((nentries = myscandir(dir, &dir_vec, f_match, alphacomp)) == -1) {
X		char err[FILESIZE];
X		
X		(void) sprintf(err, " [Unknown directory: %s]", dir);
X		add_mess(err);
X		return 1;
X	}
X	if (nentries == 0) {
X		add_mess(" [No match]");
X	} else if (c == ' ' || c == '\t')
X		fill_in(dir_vec, nentries);
X	else {
X		/* we're a '?' */
X#ifdef TYPEOUT
X		int	maxlen = 0,
X			ncols,
X			col,
X			lines,
X			linespercol;
X
X		TOstart("Completion");
X		Typeout("(! means file will not be chosen unless typed explicitly)");
X		Typeout((char *) 0);
X		Typeout("Possible completions (in %s):", dir);
X		Typeout((char *) 0);
X
X		for (i = 0; i < nentries; i++)
X			maxlen = max(strlen(dir_vec[i]), maxlen);
X		maxlen += 4;	/* pad each column with at least 4 spaces */
X		ncols = (maxCols - 2) / maxlen;
X		linespercol = 1 + (nentries / ncols);
X
X		for (lines = 0; lines < linespercol; lines++) {
X			for (col = 0; col < ncols; col++) {
X				int	isbad,
X					which;
X				char	bads[128];
X
X				which = (col * linespercol) + lines;
X				if (which >= nentries)
X					break;
X				(void) strcpy(bads, BadExtensions);
X				isbad = bad_extension(dir_vec[which], bads);
X				Typeout("%s%-*s", isbad ? "!" : "",
X					maxlen - isbad, dir_vec[which]);
X			}
X			Typeout((char *) 0);
X		}
X		TOstop();
X#endif
X	}
X	freedir(&dir_vec, nentries);
X	return 1;
X}
END_OF_FILE
if test 9084 -ne `wc -c <'xpic/ask.c'`; then
    echo shar: \"'xpic/ask.c'\" unpacked with wrong size!
fi
# end of 'xpic/ask.c'
fi
if test -f 'xpic/event.c' -a "${1}" != "-c" ; then 
  echo shar: Will not clobber existing file \"'xpic/event.c'\"
else
echo shar: Extracting \"'xpic/event.c'\" \(10071 characters\)
sed "s/^X//" >'xpic/event.c' <<'END_OF_FILE'
X/* $Header: event.c,v 1.4 89/04/21 03:30:34 xwindows Exp $ */
X/* 
X *  The event handler determines which object's event processor to call,
X *  and passes it the event type, and object mode. Each object module
X *  must provide a procedure called xxx_event, where xxx is the object
X *  name, which takes the event code, and returns the new editing state.
X *  The event code consistes of the current drawingMode (START_MODE, END_MODE,
X *  DRAG_MODE, ASK_MODE), or'ed with the event type (REDRAW, MOTION, LEFT,
X *  MIDDLE, RIGHT). The object event routine will usually take some
X *  appropriate action, and return the new drawingMode. The object
X *  module must also provide a xxx_abort routine, which can be invoked
X *  by the CleanUpMode routine if the user hits a menu button whil estill
X *  editing something.
X */
X
X#include <values.h>
X#include "xpic.h"
X#include "windows.h"
X#include "newfonts.h"
X#include "gels.h"
X#include "draw.h"
X#include "spline.h"
X
Xstatic int mx, my;					/* Mouse coordinates after snap */
X
X/*
X *  processes events in the pic window
X */
X/*ARGSUSED*/
Xvoid picEventHandle(w, data, event)
XWidget w;
Xcaddr_t data;
XXEvent *event;
X{
X	int event_mode = drawingMode;
X
X	switch (event->type) {
X	case Expose:
X		event_mode |= REDRAW;
X		/*
X		 *  mx, my not important in Expose - all the object event
X		 *  processor will do is redraw the last rubber banded object if
X		 *  any, at the last position.
X		 */
X		/* Can do selective redraw, but it is hardly  necessary */
X		PicRedraw(CurrentCell->gelList, &picBox);
X		break;
X	case MotionNotify:
X		event_mode |= MOTION;
X		/*
X		 *  We use the MotionNotify event as a hint, and ask for the
X		 *  mouse position. We use the mouse position to rubber badn -
X		 *  this is essentially "jump" rubber banding, and is possible
X		 *  because we have the compress_motion flag on the Window
X		 *  widget set to TRUE to make sure the MotionNotify events are
X		 *  hints, and not a stream of actual mouse movements.
X		 */
X		{
X			Window root_return, child_return;
X			int root_x_return, root_y_return, win_x_return, win_y_return;
X			unsigned int mask_return;
X			
X			(void) XQueryPointer(picDpy, picWin, &root_return, &child_return, 
X			 &root_x_return, &root_y_return, &win_x_return, &win_y_return, 
X			 &mask_return);
X			mx = snap(win_x_return, mouseResolution);
X			my = snap(win_y_return, mouseResolution);
X		}
X		/* Usually, if in start, then ignore, else rubber_band or drag */
X		break;
X	case ButtonPress:
X		mx = snap(event->xbutton.x, mouseResolution);
X		my = snap(event->xbutton.y, mouseResolution);
X		switch (event->xbutton.button) {
X		case Button1:
X			event_mode |= LEFT;
X			/* Decision button */
X			break;
X		case Button3:
X			event_mode |= RIGHT;
X			/* termination button for lines, splines, editing actions */
X			break;
X		case Button2:
X			event_mode |= MIDDLE;
X			/* Abort current action */
X			break;
X		default:
X#ifdef DEBUG
X			(void) sprintf(errstring, "unknown button in picEventhandle - %d",
X			 event->xbutton.button);
X			message(errstring);
X#endif
X			break;
X		}
X		break;
X	case ConfigureNotify:
X		event_mode |= REDRAW;
X		if ((event->xconfigure.width != picWinWidth) 
X		 || (event->xconfigure.height != picWinHeight)) {
X#ifdef DEBUG
X			(void) fprintf(stderr, "Window Size changed to %dx%d\n", 
X			 event->xconfigure.width, event->xconfigure.height);
X#endif
X			picWinWidth = picBox.ur.x = event->xconfigure.width;
X			picWinHeight = picBox.ur.y = event->xconfigure.height;
X			pageWidth = picWinWidth / gridSpacing + 0.5;
X			pageHeight = picWinHeight / gridSpacing + 0.5;
X		}
X		/* Can do selective redraw, but it is hardly  necessary */
X		XClearWindow(picDpy, picWin);
X		PicRedraw(CurrentCell->gelList, &picBox);
X		break;
X	default:
X		/* Various other Notify types will end up here. */
X#ifdef DEBUG
X		(void) sprintf(errstring,
X		 "picEventHandle: Unknown event %d", event->type);
X		message(errstring);
X#endif
X		return;
X	}
X
X	/* Now call the object event handler  - wouldn't this be easy in C++*/
X	switch (objectType) {
X	case LINE:
X		line_event(event_mode, mx, my);
X		break;
X	case SPLINE:
X		spline_event(event_mode, mx, my);
X		break;
X	case BOX:
X		box_event(event_mode, mx, my);
X		break;
X	case CIRCLE:
X		circle_event(event_mode, mx, my);
X		break;
X	case ELLIPSE:
X		ellipse_event(event_mode, mx, my);
X		break;
X	case TEXT:
X		text_event(event_mode, mx, my);
X		break;
X	case BLOCK:
X		block_event(event_mode, mx, my);
X		break;
X	case ELEMENT:
X		element_event(event_mode, mx, my);
X		break;
X	default:
X#ifdef DEBUG
X		(void) sprintf(errstring, "Unknown object %d", objectType);
X		message(errstring);
X#endif
X		break;
X	}
X}
X
X
X/*
X *  This gets called when the user presses a button to change a
X *  selection - it cleans up any rubber bands appropriately, by calling
X *  the object procedure xxx_abort, where xxx is the object name.
X */
X/* !! remove the xxx_abort procedures by calling xxx_event() directly */
Xvoid CleanUpMode()
X{
X	switch(objectType) {
X	case LINE:
X		line_abort();
X		break;
X	case SPLINE:
X		spline_abort();
X		break;
X	case BOX:
X		box_abort();
X		break;
X	case ELLIPSE:
X		ellipse_abort();
X		break;
X	case CIRCLE:
X		circle_abort();
X		break;
X	case TEXT:
X		text_abort();
X		break;
X	case BLOCK:
X		block_abort();
X		break;
X	case ELEMENT:
X		element_abort();
X		break;
X	default:
X#ifdef DEBUG
X		(void) sprintf(errstring, "Unknown object in cleanup? %d", 
X		 objectType);
X		message(errstring);
X#endif
X		break;
X	}
X}
X
X
X/* 
X *  The routine GelDraw to draw an element takes a pointer to a Gel and
X *  depending on the type, invokes different drawing methods
X */
Xvoid GelDraw(g, func)
XGel *g;
Xint func;
X{
X	XFontStruct *font;
X	int pad, n;
X	PointList *pt;
X	Conic *conic;
X	TextString *text;
X	GC gc;
X	
X	switch (func) {
X	case DRAW:
X		gc = tmpGcNormal;
X		break;
X	case ERASE:
X		gc = tmpGcErase;
X		break;
X	case INVERT:
X	case HILITE:
X		gc = tmpGcInvert;
X		break;
X	}
X
X	SETDASHES(gc, getlinestyle(g->attributes))
X	if (func == HILITE) 
X		setwidth(gc, g->linewidth + 2);
X	else
X		setwidth(gc, g->linewidth);
X
X#ifdef DRAWBBOX
X	/* Draw bounding boxes for all stuff except Boxes */
X	if (g->type != BOX)
X		box(picWin, g->b_box.ll.x, g->b_box.ll.y, 
X		 g->b_box.ur.x, g->b_box.ur.y, gcBlock);
X#endif
X
X	switch (g->type) {
X	case LINE:
X		pt = (PointList *) g->data;
X		drawlines(picDpy, picWin, gc, pt->v, pt->nVerts, CoordModeOrigin);
X		if (pt->nVerts == 1)
X			break;
X		if (g->attributes & ST_ARROW)
X			Arrow(picDpy, picWin, pt->v[1].x, pt->v[1].y, 
X			 pt->v[0].x, pt->v[0].y, gc);
X		if (g->attributes & EN_ARROW)
X			Arrow(picDpy, picWin, 
X			 pt->v[pt->nVerts - 2].x, pt->v[pt->nVerts - 2].y, 
X			 pt->v[pt->nVerts - 1].x, pt->v[pt->nVerts - 1].y, gc);
X		break;
X	case SPLINE:
X		pt = (PointList *) g->data;
X		FlattenSpline(pt->v, pt->nVerts-1, &flatVerts2, &n, &flatSize2);
X		drawlines(picDpy, picWin, gc, flatVerts2, n, CoordModePrevious);
X		if (pt->nVerts == 1)
X			break;
X		if (g->attributes & ST_ARROW)
X			Arrow(picDpy, picWin, pt->v[2].x, pt->v[2].y, 
X			 pt->v[1].x, pt->v[1].y, gc);
X		if (g->attributes & EN_ARROW)
X			Arrow(picDpy, picWin, 
X			 pt->v[pt->nVerts - 3].x, pt->v[pt->nVerts - 3].y,
X			 pt->v[pt->nVerts - 2].x, pt->v[pt->nVerts - 2].y, gc);
X		break;
X	case BOX:
X		box(picWin, g->b_box.ll.x, g->b_box.ll.y, g->b_box.ur.x, 
X		 g->b_box.ur.y, gc);
X		break;
X	case CIRCLE:
X		conic = (Conic *) g->data;
X		ellipse(picWin, conic->centre.x, conic->centre.y, 
X		 conic->xrad, conic->xrad, gc);
X		break;
X	case ELLIPSE:
X		conic = (Conic *) g->data;
X		ellipse(picWin, conic->centre.x, conic->centre.y, 
X		 conic->xrad, conic->yrad, gc);
X		break;
X	case TEXT:
X		text = (TextString *) g->data;
X		font = ChangeFont(&text->font->sizes[text->sizeindex], &pad);
X		setfont(gc, font->fid);
X		/*
X		 *  This weird location for drawing text is a result of the
X		 *  sloppy bounding box calculation, which is teh X10 heritage -
X		 *  using the bounding box lower left corner as the control
X		 *  point for text. Since text in X11 uses the baseline as the y
X		 *  coordinate, this code is crude. The text drawing needs
X		 *  cleaning up, especially for proper space padding
X		 */
X		drawtext(picWin, g->b_box.ll.x, g->b_box.ur.y, text->str,
X		 text->length, gc, pad);
X		break;
X	default:
X#ifdef DEBUG
X		(void) sprintf(errstring, "GelDraw: Unknown Gel type - %d", g->type);
X		message(errstring);
X#endif
X		break;
X	}
X}
X
X
X/* These are rather sloppy - need to be cleaned up a bit */
Xvoid GelHilite(g)
XGel *g;
X{
X	extern void SetWorkingCursor(), SetWaitCursor();
X
X	/* !! Should do something interesting for color */
X	SetWaitCursor();
X	for (; g != NULL; g = g->next) {
X		if (!(g->int_flags & HILITED)) {
X			g->int_flags |= HILITED;
X			if (g->type != TEXT) {
X				GelDraw(g, HILITE);
X			} else {
X				XFillRectangle(picDpy, picWin, gcGray,
X				 g->b_box.ll.x, g->b_box.ll.y,
X				 (unsigned) (g->b_box.ur.x - g->b_box.ll.x),
X				 (unsigned) (g->b_box.ur.y - g->b_box.ll.y));
X				GelDraw(g, INVERT);
X			}
X		}
X	}
X	SetWorkingCursor();
X}
X
X
Xvoid GelUnHilite(g)
XGel *g;
X{
X	extern void SetWorkingCursor(), SetWaitCursor();
X
X	/* !! Should do something interesting for color */
X	SetWaitCursor();
X	for (; g != NULL; g = g->next) {
X		if (g->int_flags & HILITED) {
X			g->int_flags &= ~HILITED;
X			if (g->type != TEXT) {
X				GelDraw(g, HILITE);
X			} else {
X				/* Make sure we have a correct bounding box */
X				GelDraw(g, INVERT);
X				XFillRectangle(picDpy, picWin, gcGray,
X				 g->b_box.ll.x, g->b_box.ll.y,
X				 (unsigned) (g->b_box.ur.x - g->b_box.ll.x),
X				 (unsigned) (g->b_box.ur.y - g->b_box.ll.y));
X			}
X		}
X	}
X	SetWorkingCursor();
X}
X
X
X/*
X *  The routine PicRedraw takes three parameters - a pointer to a Gel,
X *  and a Box which defines the Clip area needed to be drawn. */
X/*
X *  Ideally, any Gel whose bbox intersects the Box passed in is redrawn.
X *  This allows the efficient use of ExposeRegion events to redraw small
X *  sections quickly. For now, we just redraw the whole thing.
X */
X/* !! proper clipped redraw - note that the rubber banded stuff
X will pose problems */
X/*ARGSUSED*/
Xvoid PicRedraw(g, clip)
XGel *g;
XBox *clip;
X{
X	extern void SetWorkingCursor(), SetWaitCursor();
X
X	SetWaitCursor();
X	CalcBBox(g, MAXINT);
X	for(; g != NULL; g = g->next)
X		GelDraw(g, DRAW);
X	SetWorkingCursor();
X}
X
X
END_OF_FILE
if test 10071 -ne `wc -c <'xpic/event.c'`; then
    echo shar: \"'xpic/event.c'\" unpacked with wrong size!
fi
# end of 'xpic/event.c'
fi
if test -f 'xpic/handlers.c' -a "${1}" != "-c" ; then 
  echo shar: Will not clobber existing file \"'xpic/handlers.c'\"
else
echo shar: Extracting \"'xpic/handlers.c'\" \(9120 characters\)
sed "s/^X//" >'xpic/handlers.c' <<'END_OF_FILE'
X/* $Header: handlers.c,v 1.4 89/04/21 03:30:43 xwindows Exp $ */
X#include "xpic.h"
X#include "windows.h"
X#include "newfonts.h"
X#include "input.h"
X#include "version.h"
X#include "gels.h"
X#include "patchlevel.h"
X#include "draw.h"
X
Xextern void RedrawPicWin();
Xextern void CleanUpMode();
X
X/*
X *  If a PushButton has been pressed in a mode other than START_MODE,
X *  there's probably rubber-banded stuff on teh screen that we'll have
X *  to clean up
X */
X#define RESETMODE()	if(drawingMode != START_MODE) CleanUpMode(); else
X
X/*ARGSUSED*/
Xvoid copy(w, tag, calldata)
XWidget w;
Xcaddr_t tag;
Xcaddr_t calldata;
X{
X	RESETMODE();
X
X	editType = COPY;
X	objectType = editMode;
X}
X
X/*ARGSUSED*/
Xvoid cut(w, tag, calldata)
XWidget w;
Xcaddr_t tag;
Xcaddr_t calldata;
X{
X	RESETMODE();
X
X	editType = DELETE;
X	objectType = editMode;
X}
X
X
X/*ARGSUSED*/
Xvoid paste(w, tag, calldata)
XWidget w;
Xcaddr_t tag;
Xcaddr_t calldata;
X{
X	RESETMODE();
X
X	editType = PASTE;
X	objectType = editMode;
X}
X
X
X/*ARGSUSED*/
Xvoid move(w, tag, calldata)
XWidget w;
Xcaddr_t tag;
Xcaddr_t calldata;
X{
X	RESETMODE();
X
X	editType = MOVE;
X	objectType = editMode;
X}
X
X
X
X/*ARGSUSED*/
Xvoid change(w, tag, calldata)
XWidget w;
Xcaddr_t tag;
Xcaddr_t calldata;
X{
X	RESETMODE();
X
X	editType = CHANGE_ATTRIBUTE;
X	objectType = editMode;
X}
X
X
X
X/*ARGSUSED*/
Xvoid adjust(w, tag, calldata)
XWidget w;
Xcaddr_t tag;
Xcaddr_t calldata;
X{
X	RESETMODE();
X
X	editType = ADJUST;
X	objectType = editMode;
X}
X
X
X
X/*ARGSUSED*/
Xvoid rotate(w, tag, calldata)
XWidget w;
Xcaddr_t tag;
Xcaddr_t calldata;
X{
X	RESETMODE();
X
X	message("rotate: Not implemented yet. Sorry.");
X}
X
X
X/*ARGSUSED*/
Xvoid scale(w, tag, calldata)
XWidget w;
Xcaddr_t tag;
Xcaddr_t calldata;
X{
X	RESETMODE();
X
X	message("scale: Not implemented yet. Sorry.");
X}
X
X
X
X/*ARGSUSED*/
Xvoid getcell(w, tag, calldata)
XWidget w;
Xcaddr_t tag;
Xcaddr_t calldata;
X{
X	RESETMODE();
X
X	editType = GET;
X	objectType = editMode;
X}
X
X
X/*ARGSUSED*/
Xvoid putcell(w, tag, calldata)
XWidget w;
Xcaddr_t tag;
Xcaddr_t calldata;
X{
X	RESETMODE();
X
X	editType = PUT;
X	objectType = editMode;
X}
X
X
X/*ARGSUSED*/
Xvoid element(w, tag, calldata)
XWidget w;
Xcaddr_t tag;
Xcaddr_t calldata;
X{
X	RESETMODE();
X
X	/* Make sure everything is selectable - should be, but you never know! */
X	ClearGelFlags(CurrentCell->gelList);
X	
X	if (STREQ(tag, "Line"))
X		objectType = LINE;
X	else if (STREQ(tag, "Box"))
X		objectType = BOX;
X	else if (STREQ(tag, "Ellipse"))
X		objectType = ELLIPSE;
X	else if (STREQ(tag, "Circle"))
X		objectType = CIRCLE;
X	else if (STREQ(tag, "Spline"))
X		objectType = SPLINE;
X	else if (STREQ(tag, "Text"))
X		objectType = TEXT;
X	else {
X		(void) sprintf("Unknown element - %s", errstring);
X		message(errstring);
X	}
X}
X
X
X/*ARGSUSED*/
Xvoid editattrib(w, tag, calldata)
XWidget w;
Xcaddr_t tag;
Xcaddr_t calldata;
X{
X	RESETMODE();
X
X	if (STREQ(tag, "Block")) {
X		editMode = BLOCK;
X		if (objectType == ELEMENT)
X			objectType = BLOCK;
X	} else if (STREQ(tag, "Element")) {
X		editMode = ELEMENT;
X		if (objectType == BLOCK)
X			objectType = ELEMENT;
X	} else {
X		(void) sprintf(errstring,
X		 "editattrib: Unknown editing mode - Tag = %s", tag);
X		message(errstring);
X	}
X}
X
X
X/*ARGSUSED*/
Xvoid linepattern(w, tag, calldata)
XWidget w;
Xcaddr_t tag;
Xcaddr_t calldata;
X{
X	RESETMODE();
X
X	if (STREQ(tag, "Solid"))
X		line_type = SOLID;
X	else if (STREQ(tag, "Dotted"))
X		line_type = DOTTED;
X	else if (STREQ(tag, "Short-Dashed"))
X		line_type = SDASH;
X	else if (STREQ(tag, "Long-Dashed"))
X		line_type = LDASH;
X	else if (STREQ(tag, "Dot-Dashed"))
X		line_type = DDASH;
X	else {
X		(void) sprintf(errstring,
X		 "linepattern: Unknown line pattern - Tag = %s",tag);
X		message(errstring);
X	}
X	SETDASHES(gcNormal, line_type)
X	SETDASHES(gcInvert, line_type)
X}
X
X
X/*ARGSUSED*/
Xvoid linearrow(w, tag, calldata)
XWidget w;
Xcaddr_t tag;
Xcaddr_t calldata;
X{
X	RESETMODE();
X	
X	if (STREQ(tag, "None"))
X		line_arrow = NO_ARROW;
X	else if (STREQ(tag, "Start"))
X		line_arrow = ST_ARROW;
X	else if (STREQ(tag, "End"))
X		line_arrow = EN_ARROW;
X	else if (STREQ(tag, "Both"))
X		line_arrow = ST_ARROW | EN_ARROW;
X	else {
X#ifdef DEBUG
X		(void) sprintf(errstring,
X		 "linearrow: Unknown line arrow - Tag = %s", tag);
X		message(errstring);
X#endif
X	}
X}
X
X
X/*ARGSUSED*/
Xvoid linethickness(w, tag, calldata)
XWidget w;
Xcaddr_t tag;
Xcaddr_t calldata;
X{
X	RESETMODE();
X	lineThickness = atoi(tag);
X	if (lineThickness< 0) {
X		message("Line Thickness must be positive");
X		lineThickness = 0;
X	}
X	setwidth(gcNormal, lineThickness);
X	setwidth(gcInvert, lineThickness);
X}
X
X
X/*ARGSUSED*/
Xvoid textvalign(w, tag, calldata)
XWidget w;
Xcaddr_t tag;
Xcaddr_t calldata;
X{
X	RESETMODE();
X	if (STREQ(tag, "Top"))
X		textVertAlign = TOPLINE;
X	else if (STREQ(tag, "Middle"))
X		textVertAlign = MIDLINE;
X	else if (STREQ(tag, "Bottom"))
X		textVertAlign = BOTLINE;
X}
X
X
X/*ARGSUSED*/
Xvoid texthalign(w, tag, calldata)
XWidget w;
Xcaddr_t tag;
Xcaddr_t calldata;
X{
X	RESETMODE();
X	if (STREQ(tag, "Centred"))
X		textHorizAlign = CENTRE;
X	else if (STREQ(tag, "Left Just."))
X		textHorizAlign = LJUST;
X	else if (STREQ(tag, "Right Just."))
X		textHorizAlign = RJUST;
X}
X
X
X/*ARGSUSED*/
Xvoid setsnap(w, tag, calldata)
XWidget w;
Xcaddr_t tag;
Xcaddr_t calldata;
X{
X	RESETMODE();
X	mouseResolution = atoi(tag);
X	if (mouseResolution < 0) 
X		message("Mouse resolution must be positive");
X}
X
X
X/*
X *  Status is printed on the message line - it prints certain global
X *  variables, like the program name, version number, buffername, the
X *  filename associated with the buffer, the * to show if the buffer was
X *  saved or not, and the present drawing mode
X */
Xvoid DisplayStatus()
X{
X
X	char *modified = " ";
X	
X	if (CurrentCell->saved & MODIFIED)
X		modified = "[Modified]";
X	(void) sprintf(errstring, "XPIC %d.%d%s   Buffer: %s    File: %s  %s", 
X	 progVersion, PATCHLEVEL, progStatus, CurrentCell->name, 
X	 CurrentCell->filename, modified);
X	message(errstring);
X}
X
X
X/* Callback entry point */
X/*ARGSUSED*/
Xvoid status(w, tag, calldata)
XWidget w;
Xcaddr_t tag;
Xcaddr_t calldata;
X{
X	RESETMODE();
X
X	DisplayStatus();
X}
X
X
X
X/*ARGSUSED*/
Xvoid readcell(w, tag, calldata)
XWidget w;
Xcaddr_t tag;
Xcaddr_t calldata;
X{
X	Cell *cell;
X	
X	RESETMODE();
X
X	/* This will not be necessary when multiple buffers become available */
X	if (CurrentCell->saved & MODIFIED) {
X		message("You must first save the current cell");
X		return;
X	}
X	
X	if ((cell = ReadCell("Read file name ? ", (char *) NULL)) == NULL)
X		return;
X
X	cell->next = MainCell;
X	MainCell = cell;
X	LastCell = CurrentCell;
X	CurrentCell = MainCell;
X	RedrawPicWin();
X	DisplayStatus();
X}
X
X
X/*ARGSUSED*/
Xvoid lprintcell(w, tag, calldata)
XWidget w;
Xcaddr_t tag;
Xcaddr_t calldata;
X{
X	RESETMODE();
X	LPrintCell(CurrentCell);
X}
X
X
X/*ARGSUSED*/
Xvoid savecell(w, tag, calldata)
XWidget w;
Xcaddr_t tag;
Xcaddr_t calldata;
X{
X	char *fname;
X	
X	RESETMODE();
X
X	if(STREQ(tag, "Save As")) {
X		fname = get_input("Save file name ? ", CurrentCell->filename, TRUE);
X		if (fname == NULL)
X			return;
X		if (CurrentCell->filename && !(STREQ(CurrentCell->filename, nullfile)))
X			free(CurrentCell->filename);
X		CurrentCell->filename = fname;
X		/* Force a save */
X		CurrentCell->saved = MODIFIED | NEWFILE;
X	}
X	(void) WriteCell(CurrentCell, backupOnWrite);
X}
X
X
X/*ARGSUSED*/
Xvoid redisplay(w, tag, calldata)
XWidget w;
Xcaddr_t tag;
Xcaddr_t calldata;
X{
X	RESETMODE();
X	RedrawPicWin();
X	DisplayStatus();
X}
X
X
X/*ARGSUSED*/
Xvoid setgrid(w, tag, calldata)
XWidget w;
Xcaddr_t tag;
Xcaddr_t calldata;
X{
X	Arg args[1];
X	
X	RESETMODE();
X	gridOn = !gridOn;
X	if (gridOn) {
X		XtSetArg(args[0], XtNbackgroundPixmap, gridTile);
X		XtSetValues(picWidget, args, 1);
X	} else {
X		XtSetArg(args[0], XtNbackgroundPixmap, blankTile);
X		XtSetValues(picWidget, args, 1);
X	}
X}
X
X
X/*ARGSUSED*/
Xvoid undo(w, tag, calldata)
XWidget w;
Xcaddr_t tag;
Xcaddr_t calldata;
X{
X	Gel *g;
X 	register Gel *tmp;
X	int i;
X	
X	RESETMODE();
X
X	g = PopGel(&(CurrentCell->gelList), CurrentCell->undo);
X	for(tmp = g; tmp != NULL; tmp = tmp->next)
X		GelDraw(tmp, ERASE);
X	for(tmp = CurrentCell->undoList; tmp != NULL; tmp = tmp->next)
X		GelDraw(tmp, DRAW);
X	ClearGelFlags(CurrentCell->undoList);
X	i = PushGel(&(CurrentCell->gelList), CurrentCell->undoList);
X	CurrentCell->undo = i;
X	CurrentCell->undoList = g;
X	CurrentCell->saved |= MODIFIED;
X	
X}
X
X	
X
X/*ARGSUSED*/
Xvoid quit(w, tag, calldata)
XWidget w;
Xcaddr_t tag;
Xcaddr_t calldata;
X{
X	Cell *cell;
X	
X	RESETMODE();
X	/* Check all the buffers to make sure they're saved */
X	for (cell = MainCell; cell != NULL; cell = cell->next) {
X		if (cell->saved & MODIFIED) {
X			(void) sprintf(errstring, "Buffer \"%s\" not saved. Save (y/n) ?",
X			 cell->name);
X			switch ( confirm(errstring, "y")) {
X				case ABORT:
X					return;
X				case YES:
X					if (WriteCell(cell, backupOnWrite))
X						break;
X					else
X						return;
X				case NO:
X					break;
X			}
X		}
X	}
X	exit(0);
X}
X
X/*ARGSUSED*/
Xvoid change_buffer(w, tag, calldata)
XWidget w;
Xcaddr_t tag;
Xcaddr_t calldata;
X{
X	RESETMODE();
X	message("change_buffer: Not implemented yet. Sorry.");
X}
X
X
X/*ARGSUSED*/
Xvoid kill_buffer(w, tag, calldata)
XWidget w;
Xcaddr_t tag;
Xcaddr_t calldata;
X{
X	RESETMODE();
X	message("kill_buffer: Not implemented yet. Sorry.");
X}
X
X
X#ifdef DEBUG
X/*ARGSUSED*/
Xvoid printcell(w, tag, calldata)
XWidget w;
Xcaddr_t tag;
Xcaddr_t calldata;
X{
X	RESETMODE();
X	PrintCell(CurrentCell);
X}
X#endif
END_OF_FILE
if test 9120 -ne `wc -c <'xpic/handlers.c'`; then
    echo shar: \"'xpic/handlers.c'\" unpacked with wrong size!
fi
# end of 'xpic/handlers.c'
fi
if test -f 'xpic/obj_block.c' -a "${1}" != "-c" ; then 
  echo shar: Will not clobber existing file \"'xpic/obj_block.c'\"
else
echo shar: Extracting \"'xpic/obj_block.c'\" \(10281 characters\)
sed "s/^X//" >'xpic/obj_block.c' <<'END_OF_FILE'
X/* $Header: obj_block.c,v 1.7 89/04/21 03:31:08 xwindows Exp $ */
X/* 
X *  The block edit routines - treated as a separate pseudo-object
X *  because they are so similar. The code is somewhat intricate - the
X *  result of trying to cram as many operations into as little code as
X *  possible, so that the code to do something stayed in the one place.
X *  Sigh! macros might have been nicer.
X */
X#include <values.h>
X
X#include "xpic.h"
X#include "windows.h"
X#include "spline.h"
X#include "gels.h"
X#include "draw.h"
X#include "input.h"
X#include "newfonts.h"
X#include "assert.h"
X
Xstatic int x_1, y_1, x_2, y_2;			/* Corners of box, ellipse, ends of line */
Xstatic int xmin, xmax, ymin, ymax;	/* Bounding box */
Xstatic Gel *gel;
Xstatic Gel *oldgel;
Xstatic Cell *cell;
Xstatic Box *bp;
Xstatic Box adjbox;
Xstatic int lastX, lastY;
Xstatic int first_time = FALSE;
X
X/*
X *  For the editing constructs, we also may have a DRAG_MODE (where the
X *  object is dragged around, or an ASK_MODE where the user is asked to
X *  confirm the operation (usually a delete, with a click
X */
Xblock_event(evtype, mx, my)
X{
X	char *err;
X	register Gel *tmp;
X	
X	switch(evtype) {
X	case MOTION | START_MODE:
X	case MOTION | ASK_MODE:
X	case RIGHT  | START_MODE:
X	case MIDDLE | START_MODE:
X	case REDRAW | START_MODE:
X	case REDRAW | ASK_MODE:
X		break;
X	case MOTION | END_MODE:
X		/* rubber band the box corner */
X		box(picWin, x_1, y_1, x_2, y_2, gcBlock);
X		x_2 = mx;
X		y_2 = my;
X		box(picWin, x_1, y_1, x_2, y_2, gcBlock);
X		break;
X	case MOTION | DRAG_MODE:  
X		/*
X		 *  move the box around on the cursor - use the second corner as
X		 *  the mouse corner
X		 */
X		box(picWin, x_1, y_1, x_2, y_2, gcBlock);
X		x_1 += mx - x_2;
X		y_1 += my - y_2;
X		x_2 = mx;
X		y_2 = my;
X		box(picWin, x_1, y_1, x_2, y_2, gcBlock);
X		break;
X	case LEFT | START_MODE:
X		/* start the box */
X		first_time = TRUE;
X		if (editType == PASTE) {
X			if (KillBuffer == NULL) {
X				message("Nothing to paste. Delete something first");
X				break;
X			}
X			gel = CopyGel(KillBuffer, MAXINT);
X			MoveGel(gel, mx - KillX, my - KillY);
X			bp = GetBBox(gel);
X			x_1 = bp->ll.x;
X			y_1 = bp->ll.y;
X			lastX = x_2 = bp->ur.x;
X			lastY = y_2 = bp->ur.y;
X			drawingMode = DRAG_MODE;
X		} else if (editType == GET) {
X			if (cell)
X				FreeCell(cell);
X			cell = ReadCell("Get from file ? ", (char *) NULL);
X			if ( cell == NULL) 
X				break;
X			else if (cell->gelList == NULL) {
X				message("Can't paste an empty cell!");
X				FreeCell(cell);
X				cell = NULL;
X				break;
X			}
X			gel = cell->gelList;
X			cell->gelList = NULL;
X			bp = GetBBox(gel);
X			x_1 = bp->ll.x;
X			y_1 = bp->ll.y;
X			lastX = x_2 = bp->ur.x;
X			lastY = y_2 = bp->ur.y;
X			drawingMode = DRAG_MODE;
X		} else if (editType == SCALE || editType == ROTATE) {
X			message("SCALE/ROTATE not yet implemented");
X			break;
X		} else {
X			x_1 = x_2 = mx;
X			y_1 = y_2 = my;
X			drawingMode = END_MODE;
X		}
X		box(picWin, x_1, y_1, x_2, y_2, gcBlock);
X		break;
X	case LEFT | END_MODE:
X		/* Won't get here for GET, PASTE - they go straight to DRAG */
X		/* End the box, find the contained gels, highlight them */
X		box(picWin, x_1, y_1, x_2, y_2, gcBlock);
X		lastX = x_2 = mx;
X		lastY = y_2 = my;
X		xmin = MIN(x_1, mx);
X		xmax = MAX(x_1, mx);
X		ymin = MIN(y_1, my);
X		ymax = MAX(y_1, my);
X		/*
X		 *  The very nature of ADJUST means that we want
X		 *  intersecting Gels - for the others, we want only
X		 *  those that are strictly contained within the box
X		 */
X		if (editType == ADJUST) {
X			oldgel = FindIntersectingGels(&(CurrentCell->gelList), 
X			 xmin, ymin, xmax, ymax);
X			gel = CopyGel(oldgel, MAXINT);
X			adjbox.ll.x = xmin;
X			adjbox.ll.y = ymin;
X			adjbox.ur.x = xmax;
X			adjbox.ur.y = ymax;
X			err = "No intersecting elements";
X		} else {
X			oldgel = FindContainedGels(&(CurrentCell->gelList), 
X			 xmin, ymin, xmax, ymax);
X			gel = CopyGel(oldgel, MAXINT);
X			err = "No contained elements";
X		}
X		if (oldgel == NULL) {
X			message(err);
X			drawingMode = START_MODE;
X			break;
X		}
X		for (tmp = gel; tmp != NULL; tmp = tmp->next)
X			GelDraw(tmp, ERASE);
X		GelHilite(gel);
X		if (editType == DELETE || editType == CHANGE_ATTRIBUTE) {
X			drawingMode = ASK_MODE;
X			(void) sprintf(errstring, "Click Left button to confirm %s",
X			 (editType == DELETE) ? "Delete" : "Change");
X			message(errstring);
X		} else if (editType == COPY || editType == MOVE || 
X		 editType  == ADJUST) {
X		 	if (editType == COPY) {
X				/* 'gel' must be a copy of the gels selected */
X				(void) PushUnderUndo(&(CurrentCell->gelList), oldgel, 
X				 CurrentCell->undo);
X				oldgel = NULL;
X			}
X			drawingMode = DRAG_MODE;
X			/* Draw the rubber banded box for drag */
X			box(picWin, x_1, y_1, x_2, y_2, gcBlock);
X		} else if (editType == PUT) {
X			if (cell)
X				FreeCell(cell);
X			(void) PushGel(&(CurrentCell->gelList), oldgel);
X			if ((cell = NewCell((char *) NULL, nullfile)) != NULL) {
X				cell->gelList = gel;
X				cell->saved |= MODIFIED;
X				/* 
X				 *  If we try to write out a cell with a name of
X				 *  nullfile, it will ask for the name
X				 */
X				(void) WriteCell(cell, backupOnWrite);
X				cell->gelList = NULL;
X			}
X			GelUnHilite(gel);
X			for (tmp = gel; tmp != NULL; tmp = tmp->next)
X				GelDraw(tmp, DRAW);
X			FreeGel(gel);
X			gel = NULL;
X			drawingMode = START_MODE;
X		} else { /* shouldn't get here, since SCALE, ROTATE aren't working! */ 
X			(void) sprintf(errstring,
X			 "Unknown editType %d in block_event - LEFT", editType);
X			message(errstring);
X			(void) PushGel(&(CurrentCell->gelList), oldgel);
X			GelUnHilite(gel);
X			FreeGel(gel);
X			gel = NULL;
X			drawingMode = START_MODE;
X		}
X		break;
X	case LEFT | DRAG_MODE:
X		/* 
X		 *  Every time LEFT is clicked in DRAG mode, we move all
X		 *  the objects in the gel list here, highlight them,
X		 *  and stay in this mode - gives the users multiple
X		 *  tries at adjusting the block since it isn't
X		 *  completely WYSIWYG. PUT doesn't get here since it
X		 *  ends in END_MODE, DELETE and CHANGE_ATTRIB go via
X		 *  ASK_MODE
X		 */
X		box(picWin, x_1, y_1, x_2, y_2, gcBlock);
X		x_1 += mx - x_2;
X		y_1 += my - y_2;
X		x_2 = mx;
X		y_2 = my;
X		if (first_time) {
X			first_time = FALSE;
X		 	if (editType == COPY) {
X				GelUnHilite(gel);
X				for (tmp = gel; tmp != NULL; tmp = tmp->next) 
X					GelDraw(tmp, DRAW);
X			} else if (editType == MOVE || editType == ADJUST) {
X				GelUnHilite(gel);
X				for (tmp = gel; tmp != NULL; tmp = tmp->next) 
X					GelDraw(tmp, ERASE);
X			} else { /* GET, PASTE */
X				/* Do nothing */
X			}
X		} else { /* Not first time, so we zonk the last position */
X			GelUnHilite(gel);
X		}
X		if (editType == ADJUST) {
X			AdjustGel(gel, &adjbox, mx - lastX, my - lastY);
X			adjbox.ll.x = MIN(x_1, x_2);
X			adjbox.ll.y = MIN(y_1, y_2);
X			adjbox.ur.x = MAX(x_1, x_2);
X			adjbox.ur.y = MAX(y_1, y_2);
X		} else
X			MoveGel(gel, mx - lastX, my - lastY);
X		lastX = mx;
X		lastY = my;
X		GelHilite(gel);
X		box(picWin, x_1, y_1, x_2, y_2, gcBlock);
X		break;
X	case RIGHT | DRAG_MODE:
X		box(picWin, x_1, y_1, x_2, y_2, gcBlock);
X		if ((!first_time) || editType == COPY || editType == MOVE || 
X		 editType == ADJUST) {
X			GelUnHilite(gel);
X		}
X		if (!(first_time && (editType == GET || editType == PASTE))) {
X			for (tmp = gel; tmp != NULL; tmp = tmp->next) 
X				GelDraw(tmp, DRAW);
X			FreeGel(CurrentCell->undoList);
X			CurrentCell->undoList = NULL;
X			if (editType != GET && editType != PASTE) {
X				CurrentCell->undoList = oldgel;
X				oldgel = NULL;
X			}
X			FreeGel(KillBuffer);
X			KillBuffer = CopyGel(gel, MAXINT);
X			KillX = mx;
X			KillY = my;
X			CurrentCell->undo = PushGel(&(CurrentCell->gelList), 
X			 gel);
X			CurrentCell->saved |= MODIFIED;
X		}
X		gel = NULL;
X		drawingMode = START_MODE;
X		break;		
X	case LEFT  | ASK_MODE:
X		/* Delete, change the gels */
X		GelUnHilite(gel);
X		FreeGel(CurrentCell->undoList);
X		CurrentCell->undoList = oldgel;
X		oldgel = NULL;
X		if (editType == DELETE) {
X			CurrentCell->undo = 0;
X			FreeGel(KillBuffer);
X			KillBuffer = gel;
X			KillX = mx;
X			KillY = my;
X		} else { /* CHANGE_ATTRIB */
X			ChangeAttrib(gel, line_type, line_arrow, lineThickness, 
X			 fill_type, 
X			 textVertAlign | textHorizAlign, fontType, textSize);
X			for (tmp = gel; tmp != NULL; tmp = tmp->next) 
X				GelDraw(tmp, DRAW);
X			CurrentCell->undo = PushGel(&(CurrentCell->gelList), gel);
X		}
X		gel = NULL;
X		CurrentCell->saved |= MODIFIED;
X		drawingMode = START_MODE;
X		break;
X	case RIGHT | ASK_MODE:
X	case MIDDLE | ASK_MODE:
X		/* Abort */
X		GelUnHilite(gel);
X		for (tmp = gel; tmp != NULL; tmp = tmp->next) 
X			GelDraw(tmp, DRAW);
X		(void) PushUnderUndo(&(CurrentCell->gelList), gel, CurrentCell->undo);
X		gel = NULL;
X		drawingMode = START_MODE;
X		break;
X	case MIDDLE | DRAG_MODE:
X		/* Abort, unhilite the gels - delete any copies */
X		box(picWin, x_1, y_1, x_2, y_2, gcBlock);
X		/* PUT only gets as far as END_MODE - won't get here */
X		if ((!first_time) || editType == COPY || editType == MOVE || 
X		 editType == ADJUST) {
X			GelUnHilite(gel);
X		}
X		if (editType == COPY || editType == PASTE || editType == GET) {
X			FreeGel(gel);
X			if (cell)
X				FreeCell(cell);
X			cell = NULL;
X		} else if (editType == MOVE || editType == ADJUST) {
X			FreeGel(gel);
X			gel = oldgel;
X			for (tmp = gel; tmp != NULL; tmp = tmp->next) 
X				GelDraw(tmp, DRAW);
X			(void) PushUnderUndo(&(CurrentCell->gelList), gel,
X			 CurrentCell->undo);
X		} else { /* can't happen, since we don't have SCALE/ROTATE */
X			(void) sprintf(errstring,
X			 "Unknown editType %d in block_event - MIDDLE", editType);
X			message(errstring);
X		}
X		gel = NULL;
X		drawingMode = START_MODE;
X		break;
X	case RIGHT | END_MODE:
X	case MIDDLE | END_MODE:
X		/* Abort - stop rubber banding */
X		box(picWin, x_1, y_1, x_2, y_2, gcBlock);
X		drawingMode = START_MODE;
X		break;
X	case REDRAW | END_MODE:
X		/* redraw the rubber band */
X		box(picWin, x_1, y_1, x_2, y_2, gcBlock);
X		break;
X	case REDRAW | DRAG_MODE:
X		/* highlight the gels, redraw the drag box */
X		box(picWin, x_1, y_1, x_2, y_2, gcBlock);
X		if (!first_time || (editType == COPY || editType == MOVE 
X		 || editType == ADJUST)) 
X			GelHilite(gel);
X		break;
X	default:
X#ifdef DEBUG
X		(void) sprintf(errstring, "Hey! Unknown BLOCK mode %d", drawingMode);
X		message(errstring);
X#endif
X		break;
X	}
X	ASSERT(allock(), "block_event");
X}
X
Xblock_abort()
X{
X	/* Fudge up a RIGHT button pressed event - safer thing to do */
X	block_event((RIGHT | drawingMode), 0, 0);
X}
X	
END_OF_FILE
if test 10281 -ne `wc -c <'xpic/obj_block.c'`; then
    echo shar: \"'xpic/obj_block.c'\" unpacked with wrong size!
fi
# end of 'xpic/obj_block.c'
fi
if test -f 'xpic/obj_line.c' -a "${1}" != "-c" ; then 
  echo shar: Will not clobber existing file \"'xpic/obj_line.c'\"
else
echo shar: Extracting \"'xpic/obj_line.c'\" \(10261 characters\)
sed "s/^X//" >'xpic/obj_line.c' <<'END_OF_FILE'
X/* $Header: obj_line.c,v 1.5 89/04/21 03:31:18 xwindows Exp $ */
X/* Procedures for the line object */
X
X#include <values.h>
X#include <math.h>
X
X#include "xpic.h"
X#include "windows.h"
X#include "gels.h"
X#include "draw.h"
X#include "assert.h"
X
Xstatic int x_1, y_1, x_2, y_2;			/* Corners of box, ellipse, ends of line */
Xstatic int xmin, xmax, ymin, ymax;	/* Bounding box */
Xstatic PointList *ptList;
X
X/* Handles events for LINE mode */
Xline_event(evtype, mx, my)
Xint evtype;		/* One of MOUSE, LEFT, MIDDLE, RIGHT */
Xint mx, my;		/* Snapped position of the mouse */
X{
X	switch (evtype) {
X	case MOTION | START_MODE:
X	case RIGHT  | START_MODE:
X	case MIDDLE | START_MODE:
X	case REDRAW | START_MODE:
X		break;
X	case MOTION | END_MODE:
X		if (((line_arrow & ST_ARROW) != 0) && (nVerts == 1))
X			Arrow(picDpy, picWin, x_2, y_2, x_1, y_1, gcInvert);
X		if ((line_arrow & EN_ARROW) != 0)
X			Arrow(picDpy, picWin, x_1, y_1, x_2, y_2, gcInvert);
X		line(picWin, x_1, y_1, x_2, y_2, gcInvert);
X		x_2 = mx;
X		y_2 = my;
X		line(picWin, x_1, y_1, x_2, y_2, gcInvert);
X		if (((line_arrow & ST_ARROW) != 0) && (nVerts == 1))
X			Arrow(picDpy, picWin, x_2, y_2, x_1, y_1, gcInvert);
X		if ((line_arrow & EN_ARROW) != 0)
X			Arrow(picDpy, picWin, x_1, y_1, x_2, y_2, gcInvert);
X		break;
X	case LEFT | START_MODE:
X		xmin = xmax = x_1 = x_2 = verts[0].x = mx;
X		ymin = ymax = y_1 = y_2 = verts[0].y = my;
X		nVerts = 1;
X		drawingMode = END_MODE;
X		break;
X	case LEFT | END_MODE:
X		if (nVerts + 1 >= maxVerts) {
X			maxVerts += INC_VERTS;
X#ifdef DEBUG
X			(void) fprintf(stderr, "Reallocing verts to %d\n", maxVerts);
X#endif
X			if ((verts = (XPoint *) realloc((char *) verts, 
X			 (unsigned) (maxVerts * sizeof(XPoint)))) == NULL) {
X				message("No more memory for vertices");
X				break;
X			}
X		}
X		if (((line_arrow & ST_ARROW) != 0) && (nVerts == 1))
X			Arrow(picDpy, picWin, x_2, y_2, x_1, y_1, gcInvert);
X		if ((line_arrow & EN_ARROW) != 0)
X			Arrow(picDpy, picWin, x_1, y_1, x_2, y_2, gcInvert);
X		line(picWin, x_1, y_1, x_2, y_2, gcInvert);
X		verts[nVerts].x = x_2 = mx;
X		verts[nVerts].y = y_2 = my;
X		xmin = MIN(xmin, mx);
X		xmax = MAX(xmax, mx);
X		ymin = MIN(ymin, my);
X		ymax = MAX(ymax, my);
X		line(picWin, x_1, y_1, x_2, y_2, gcInvert);
X		if (((line_arrow & ST_ARROW) != 0) && (nVerts == 1))
X			Arrow(picDpy, picWin, x_2, y_2, x_1, y_1, gcNormal);
X		nVerts++;
X		x_1 = x_2;
X		y_1 = y_2;
X		break;
X	case RIGHT | END_MODE:
X		if (((line_arrow & ST_ARROW) != 0) && (nVerts == 1))
X			Arrow(picDpy, picWin, x_2, y_2, x_1, y_1, gcInvert);
X		if ((line_arrow & EN_ARROW) != 0)
X			Arrow(picDpy, picWin, x_1, y_1, x_2, y_2, gcInvert);
X		line(picWin, x_1, y_1, x_2, y_2, gcInvert);
X		drawingMode = START_MODE;
X		if (nVerts <= 1)
X			break;
X		if ((ptList = NewPtList(verts, nVerts)) == NULL)
X			message("No more memory for line/spline");
X		else {
X			int i;
X			/*
X			 * erase the whole line - we must do it a segment at a time,
X			 * because that's the way we drew it when rubber banding. If we
X			 * draw the entire polyline at one go, then the dashes don't
X			 * match. Then we redraw the polyline at one go.
X			 */
X			for (i = nVerts - 1; i > 0; i--) {
X				line(picWin, verts[i-1].x, verts[i-1].y,
X				 verts[i].x, verts[i].y, gcInvert);
X			}
X			drawlines(picDpy,picWin, gcNormal, verts, nVerts, CoordModeOrigin);
X			if (((line_arrow & EN_ARROW) != 0) && (nVerts > 1))
X				Arrow(picDpy, picWin, verts[nVerts - 2].x, verts[nVerts - 2].y,
X				 x_1, y_1, gcNormal);
X			AddLineGel(&(CurrentCell->gelList), LINE, ptList,
X			 line_type | line_arrow, xmin, ymin, xmax, ymax, lineThickness);
X			FreeGel(CurrentCell->undoList);
X			CurrentCell->undoList = NULL;
X			CurrentCell->undo = 1;
X			CurrentCell->saved |= MODIFIED;
X		}
X		break;
X	case MIDDLE | END_MODE:
X		if ((line_arrow & ST_ARROW) != 0)
X			Arrow(picDpy, picWin, verts[1].x, verts[1].y, verts[0].x, 
X			 verts[0].y, gcInvert);
X		if ((line_arrow & EN_ARROW) != 0)
X			Arrow(picDpy, picWin, x_1, y_1, x_2, y_2, gcInvert);
X		verts[nVerts].x = mx;
X		verts[nVerts].y = my;
X		/*
X		 * erase the whole line - we must do it a segment at a time, because
X		 * that's the way we drew it when rubber banding. If we draw the
X		 * entire polyline at one go, then the dashes don't match
X		 */
X		for (; nVerts > 0; nVerts--) {
X				line(picWin, verts[nVerts-1].x, verts[nVerts-1].y,
X				 verts[nVerts].x, verts[nVerts].y, gcInvert);
X		}
X		drawingMode = START_MODE;
X		break;
X	case REDRAW | END_MODE:
X		drawlines(picDpy, picWin, gcInvert, verts, nVerts, CoordModeOrigin);
X		line(picWin, x_1, y_1, x_2, y_2, gcInvert);
X		if (((line_arrow & ST_ARROW) != 0) && (nVerts == 1))
X			Arrow(picDpy, picWin, x_2, y_2, x_1, y_1, gcInvert);
X		if ((line_arrow & EN_ARROW) != 0)
X			Arrow(picDpy, picWin, x_1, y_1, x_2, y_2, gcInvert);
X		break;
X	default:
X#ifdef DEBUG
X		(void) sprintf(errstring, "Hey! Unknown LINE mode %d", drawingMode);
X		message(errstring);
X#endif
X		break;
X	}
X	ASSERT(allock(), "line_event");
X}
X	
X
Xline_abort()
X{
X	line_event((RIGHT | drawingMode), 0, 0);
X}
X
X
Xline_adj(evtype, gel, mx, my)
Xint evtype;
XGel *gel;
Xint mx, my;
X{
X	static XPoint *v;
X	static XPoint *adjusted;
X	static int arrowstyle, start, end, npts;
X	static Gel *linegel, *oldlinegel;
X	/*
X	 *  Will not need to process MOTION|START_MODE, RIGHT|START_MODE,
X	 *  REDRAW|START_MODE - these are taken care of in
X	 *  the adj_element routine.
X	 */
X	switch(evtype) {
X	case MOTION | END_MODE:
X		DrawLineSection(v, npts, tmpGcInvert, start, end);
X		adjusted->x = mx;
X		adjusted->y = my;
X		DrawLineSection(v, npts, tmpGcInvert, start, end);
X		break;
X	case LEFT | START_MODE:
X		linegel = CopyGel(gel, 1);
X		oldlinegel = gel;
X		gel = NULL;
X		GetClosestLinePoint(linegel, mx, my, &v, &npts, &adjusted, 
X		 &start, &end);
X		/* Line has been erased in element_adjust, so we redraw inverted */
X		GelDraw(linegel, INVERT);
X		drawingMode = END_MODE;
X		setwidth(tmpGcNormal, linegel->linewidth);
X		setwidth(tmpGcInvert, linegel->linewidth);
X		SETDASHES(tmpGcNormal, getlinestyle(linegel->attributes))
X		SETDASHES(tmpGcInvert, getlinestyle(linegel->attributes))
X		arrowstyle = getlinearrow(linegel->attributes);
X		start = start && (arrowstyle & ST_ARROW);
X		end = end && (arrowstyle & EN_ARROW);
X		break;
X	case LEFT | END_MODE:
X		DrawLineSection(v, npts, tmpGcInvert, start, end);
X		adjusted->x = mx;
X		adjusted->y = my;
X		update_box(linegel->b_box, mx, my);
X		GelDraw(linegel, DRAW);
X		(void) PushGel(&(CurrentCell->gelList), linegel);
X		linegel = NULL;
X		FreeGel(CurrentCell->undoList);
X		CurrentCell->undoList = oldlinegel;
X		CurrentCell->undo = 1;
X		CurrentCell->saved |= MODIFIED;
X		drawingMode = START_MODE;
X		break;
X	case RIGHT | END_MODE:
X	case MIDDLE | END_MODE:
X		DrawLineSection(v, npts, tmpGcInvert, start, end);
X		GelDraw(oldlinegel, DRAW);
X		(void) PushUnderUndo(&(CurrentCell->gelList), oldlinegel,
X		 CurrentCell->undo);
X		oldlinegel = NULL;
X		FreeGel(linegel);
X		linegel = NULL;
X		if (evtype == (MIDDLE | END_MODE))
X			ClearGelFlags(CurrentCell->gelList);
X		drawingMode = START_MODE;
X		break;
X	case MIDDLE | START_MODE:
X		ClearGelFlags(CurrentCell->gelList);
X		break;
X	case REDRAW | END_MODE:
X		DrawLineSection(v, npts, tmpGcInvert, start, end);
X		break;
X	default:
X#ifdef DEBUG
X		(void) sprintf(errstring, "Hey! Unknown mode %d in line_adj", 
X		 evtype);
X		message(errstring);
X#endif
X		break;
X	}
X	ASSERT(allock(), "line_adj");
X}
X
X
XDrawLineSection(v, npts, gc, start, end)
XXPoint *v;
XGC gc;
Xint start, end, npts;
X{
X	drawlines(picDpy, picWin, gc, v, npts, CoordModeOrigin);
X
X	if (start)
X		Arrow(picDpy, picWin, v[1].x, v[1].y, v[0].x, v[0].y, gc);
X	if (end)
X		Arrow(picDpy, picWin, v[0].x, v[0].y, v[1].x, v[1].y, gc);
X}
X
X
X/*
X *  Finds the closest point in the line gel 'g' to mx, my and
X *  puts the points in 'v'. Caller must allocate space for v. 'adjusted'
X *  will point to the closest point in the gel pointlist, and start and
X *  end will be set depending on whether the point is the start or end
X *  point. 'npts' is the number of points in v, usually 3, but 2 if one
X *  of the points is an endpoint.
X */
XGetClosestLinePoint(g, mx, my, v, npts, adjusted, start, end)
XGel *g;
XXPoint **v;
XXPoint **adjusted;
Xint *start, *end, *npts;
Xint mx, my;
X{
X	register int i;
X	int mindist = MAXINT;
X	int dist;
X	int closest;
X	int n = ((PointList *) g->data)->nVerts;
X	XPoint *vertices = ((PointList *) g->data)->v;
X
X	*adjusted = vertices;
X	for (i = 0; i < n; i++, vertices++) {
X		dist = (vertices->x - mx)*(vertices->x - mx) + 
X		 (vertices->y - my)*(vertices->y - my);
X		if (dist < mindist) {
X			closest = i;
X			*adjusted = vertices;
X			mindist = dist;
X		}
X	}
X	*npts = 3;
X	if (closest == 0) {
X		*start = TRUE;
X		*v = *adjusted;
X		(*npts)--;
X	} else {
X		*start = FALSE;
X		*v = *adjusted - 1;
X	}
X	if (closest == n - 1) {
X		*end = TRUE;
X		(*npts)--;
X	} else {
X		*end = FALSE;
X	}
X	ASSERT((*npts != 1), "One point line");
X}
X
X
X/*
X * Finds distance of point from a line. This is the distance of the closest
X * segment of the line from the point. The distance of a segment from the
X * point is the perpendicular distance of the point from the segment, if the
X * perpendicular intersects the segment, else it is the distance of the
X * closest endpoint. All distances are integer distances, good enough for us.
X */
Xint
Xline_distance(gel, xp, yp)
XGel *gel;
Xint xp, yp;
X{
X	int n = ((PointList *) gel->data)->nVerts;
X	XPoint *v1 = ((PointList *) gel->data)->v;
X	XPoint *v2 = v1;
X	int dx;
X	int dy;
X	double t;
X	int distsqr;
X	int closest = MAXINT;
X	int xm, ym;
X
X	for(v2++; --n > 0; v1++, v2++) {
X		/* Compute intersection of perpendicular with line segment */
X		dx = v2->x - v1->x;
X		dy = v2->y - v1->y;
X		if (dx == 0) {
X			xm = v1->x;
X			ym = yp;
X			t = ym - v1->y;
X			t /= dy;
X		} else if (dy == 0) {
X			xm = xp;
X			ym = v1->y;
X			t = xm - v1->x;
X			t /= dx;
X		} else {
X			double slope = dy;
X			double c = (v2->x * v1->y - v1->x * v2->y);
X
X			slope /= dx;
X			c /= dx;
X
X			xm = (yp + xp / slope - c) / (slope + 1.0 / slope);
X			ym = slope * xm + c;
X			t = xm - v1->x;
X			t /= dx;
X		}
X		/*
X		 * If perpendicular intersects an extension of the segment, then use
X		 * the closer endpoint
X		 */
X		if (t < 0.0) {
X			xm = v1->x;
X			ym = v1->y;
X		} else if (t > 1.0) {
X			xm = v2->x;
X			ym = v2->y;
X		}
X		distsqr = (xp - xm) * (xp - xm) + (yp - ym) * (yp - ym);
X		closest = MIN(distsqr, closest);
X	}
X	return((int) sqrt((double) closest));
X}
END_OF_FILE
if test 10261 -ne `wc -c <'xpic/obj_line.c'`; then
    echo shar: \"'xpic/obj_line.c'\" unpacked with wrong size!
fi
# end of 'xpic/obj_line.c'
fi
echo shar: End of archive 7 \(of 15\).
cp /dev/null ark7isdone
MISSING=""
for I in 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 ; do
    if test ! -f ark${I}isdone ; then
	MISSING="${MISSING} ${I}"
    fi
done
if test "${MISSING}" = "" ; then
    echo You have unpacked all 15 archives.
    rm -f ark[1-9]isdone ark[1-9][0-9]isdone
else
    echo You still need to unpack the following archives:
    echo "        " ${MISSING}
fi
##  End of shell archive.
exit 0



More information about the Comp.sources.x mailing list