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