Article View: comp.windows.x.apps
Article #764BETA Version of XPaint 2.0 -- Part 3 / 5
From: David Koblas
Date: Thu, 09 Jul 1992 21:07
Date: Thu, 09 Jul 1992 21:07
2028 lines
59609 bytes
59609 bytes
#! /bin/sh
# This is a shell archive. Remove anything before this line, then feed it
# into a shell via "sh file" or similar. To overwrite existing files,
# type "sh file -c".
# The tool that generated this appeared in the comp.sources.unix newsgroup;
# send mail to comp-sources-unix@uunet.uu.net if you want that tool.
# If this archive is complete, you will see the following message at the end:
# "End of archive 3 (of 5)."
# Contents: BoxOp.c CircleOp.c Event.c FillOp.c Hash.c Menu.c
# Pattern.c ReadWritePNM.c SelectAreaOp.c SelectBoxOp.c
# Wrapped by koblas@bananajr on Thu Jul 9 14:00:22 1992
PATH=/bin:/usr/bin:/usr/ucb ; export PATH
if test -f 'BoxOp.c' -a "${1}" != "-c" ; then
echo shar: Will not clobber existing file \"'BoxOp.c'\"
else
echo shar: Extracting \"'BoxOp.c'\" \(4320 characters\)
sed "s/^X//" >'BoxOp.c' <<'END_OF_FILE'
X/* +-------------------------------------------------------------------+ */
X/* | Copyright 1992, David Koblas. | */
X/* | Permission to use, copy, modify, and distribute this software | */
X/* | and its documentation for any purpose and without fee is hereby | */
X/* | granted, provided that the above copyright notice appear in all | */
X/* | copies and that both that copyright notice and this permission | */
X/* | notice appear in supporting documentation. This software is | */
X/* | provided "as is" without express or implied warranty. | */
X/* +-------------------------------------------------------------------+ */
X
X#include <X11/Intrinsic.h>
X#include <X11/StringDefs.h>
X#include "xpaint.h"
X
Xtypedef struct {
X int rx, ry;
X int startX, startY, endX, endY;
X int drawn;
X Boolean type; /* Is is a rectangle or square? */
X Boolean fill; /* Filled rectangle? */
X} LocalInfo;
X
X#define MKRECT(rect, sx, sy, ex, ey, typeFlag) do { \
X if (typeFlag) { \
X (rect)->width = MIN(ABS(sx - ex),ABS(sy - ey)); \
X (rect)->height = (rect)->width; \
X (rect)->x = (ex - sx < 0) ? sx - (rect)->width : sx; \
X (rect)->y = (ey - sy < 0) ? sy - (rect)->height : sy; \
X } else { \
X (rect)->x = MIN(sx, ex); \
X (rect)->y = MIN(sy, ey); \
X (rect)->width = MAX(sx, ex) - (rect)->x; \
X (rect)->height = MAX(sy, ey) - (rect)->y; \
X } \
X} while (0)
X
X
Xstatic void press(Widget w, LocalInfo *l,
X XButtonEvent *event, OpInfo *info)
X{
X l->rx = info->x;
X l->ry = info->y;
X l->endX = l->startX = event->x;
X l->endY = l->startY = event->y;
X
X l->type = (event->state & ShiftMask);
X
X l->drawn = False;
X}
X
Xstatic void motion(Widget w, LocalInfo *l,
X XMotionEvent *event, OpInfo *info)
X{
X XRectangle rect;
X
X if (l->drawn) {
X MKRECT(&rect, l->startX, l->startY, l->endX, l->endY, l->type);
X
X XDrawRectangles(XtDisplay(w), XtWindow(w), Global.gcx, &rect,1);
X }
X
X l->endX = event->x;
X l->endY = event->y;
X
X /*
X ** Really set this flag in the if statement
X */
X if (l->drawn = (l->startX != l->endX && l->startY != l->endY)) {
X MKRECT(&rect, l->startX, l->startY, l->endX, l->endY, l->type);
X
X XDrawRectangles(XtDisplay(w), XtWindow(w), Global.gcx,&rect, 1);
X }
X}
X
Xstatic void release(Widget w, LocalInfo *l,
X XButtonEvent *event, OpInfo *info)
X{
X XRectangle rect;
X
X if (l->drawn && info->surface == opWindow) {
X MKRECT(&rect, l->startX, l->startY, l->endX, l->endY, l->type);
X
X XDrawRectangles(XtDisplay(w), XtWindow(w), Global.gcx,&rect, 1);
X }
X
X if (info->isFat && info->surface == opWindow)
X return;
X
X MKRECT(&rect, l->rx, l->ry, event->x, event->y, l->type);
X
X UndoStart(w, info);
X
X if (l->fill) {
X XFillRectangles(XtDisplay(w), info->drawable,
X info->filled_gc, &rect, 1);
X } else {
X XDrawRectangles(XtDisplay(w), info->drawable,
X info->filled_gc, &rect, 1);
X }
X
X if (info->surface == opPixmap) {
X rect.width++;
X rect.height++;
X UndoSetRectangle(w, &rect);
X PwUpdate(w, &rect, False);
X }
X}
X
X/*
X** Public routines
X*/
X
Xvoid *BoxAdd(Widget w)
X{
X LocalInfo *l = (LocalInfo *)XtMalloc(sizeof(LocalInfo));
X
X l->fill = False;
X
X OpAddEventHandler(w, opWindow, ButtonPressMask, FALSE, press, l);
X OpAddEventHandler(w, opWindow, ButtonMotionMask, FALSE, motion, l);
X OpAddEventHandler(w, opWindow|opPixmap, ButtonReleaseMask, FALSE, release, l);
X SetCrossHairCursor(w);
X
X return l;
X}
Xvoid BoxRemove(Widget w, LocalInfo *l)
X{
X OpRemoveEventHandler(w, opWindow, ButtonPressMask, FALSE, press, l);
X OpRemoveEventHandler(w, opWindow, ButtonMotionMask, FALSE, motion, l);
X OpRemoveEventHandler(w, opWindow|opPixmap, ButtonReleaseMask, FALSE, release, l);
X
X XtFree(l);
X}
X
Xvoid *FBoxAdd(Widget w)
X{
X LocalInfo *l = (LocalInfo *)XtMalloc(sizeof(LocalInfo));
X
X l->fill = True;
X
X OpAddEventHandler(w, opWindow, ButtonPressMask, FALSE, press, l);
X OpAddEventHandler(w, opWindow, ButtonMotionMask, FALSE, motion, l);
X OpAddEventHandler(w, opWindow|opPixmap, ButtonReleaseMask, FALSE, release, l);
X SetCrossHairCursor(w);
X
X return l;
X}
Xvoid FBoxRemove(Widget w, LocalInfo *l)
X{
X OpRemoveEventHandler(w, opWindow, ButtonPressMask, FALSE, press, l);
X OpRemoveEventHandler(w, opWindow, ButtonMotionMask, FALSE, motion, l);
X OpRemoveEventHandler(w, opWindow|opPixmap, ButtonReleaseMask, FALSE, release, l);
X
X XtFree(l);
X}
END_OF_FILE
echo shar: NEWLINE appended to \"'BoxOp.c'\"
if test 4321 -ne `wc -c <'BoxOp.c'`; then
echo shar: \"'BoxOp.c'\" unpacked with wrong size!
fi
# end of 'BoxOp.c'
fi
if test -f 'CircleOp.c' -a "${1}" != "-c" ; then
echo shar: Will not clobber existing file \"'CircleOp.c'\"
else
echo shar: Extracting \"'CircleOp.c'\" \(5758 characters\)
sed "s/^X//" >'CircleOp.c' <<'END_OF_FILE'
X/* +-------------------------------------------------------------------+ */
X/* | Copyright 1992, David Koblas. | */
X/* | Permission to use, copy, modify, and distribute this software | */
X/* | and its documentation for any purpose and without fee is hereby | */
X/* | granted, provided that the above copyright notice appear in all | */
X/* | copies and that both that copyright notice and this permission | */
X/* | notice appear in supporting documentation. This software is | */
X/* | provided "as is" without express or implied warranty. | */
X/* +-------------------------------------------------------------------+ */
X
X#include <X11/Intrinsic.h>
X#include <X11/StringDefs.h>
X#include "xpaint.h"
X
X#define FILL 0x02
X#define CIRCLE 0x01
X#define ISFILL(x) ((x) & FILL)
X#define ISCIRCLE(x) ((x) & CIRCLE)
X
Xtypedef struct {
X int rx, ry, startX, startY, endX, endY, drawn, typeFlag, flag;
X} LocalInfo;
X
X/*
X** Warning this define picks up "flag" from scope
X*/
X#define MKRECT(rect, sx, sy, ex, ey, flag) do { \
X (rect)->x = MIN(sx, ex); \
X (rect)->y = MIN(sy, ey); \
X (rect)->width = MAX(sx, ex) - (rect)->x; \
X (rect)->height = MAX(sy, ey) - (rect)->y; \
X if (ISCIRCLE(flag)) { \
X (rect)->width = MIN((rect)->width, (rect)->height); \
X (rect)->height = (rect)->width; \
X } \
X if ((rect)->x != sx) (rect)->x = sx - (rect)->width; \
X if ((rect)->y != sy) (rect)->y = sy - (rect)->height; \
X (rect)->angle1 = 0; \
X (rect)->angle2 = 360*64; \
X } while (0)
X
Xstatic void press(Widget w, LocalInfo *l,
X XButtonEvent *event, OpInfo *info)
X{
X l->rx = info->x;
X l->ry = info->y;
X l->endX = l->startX = event->x;
X l->endY = l->startY = event->y;
X
X l->typeFlag = (event->state & ShiftMask) ? CIRCLE : 0;
X
X l->drawn = False;
X}
X
Xstatic void motion(Widget w, LocalInfo *l,
X XMotionEvent *event, OpInfo *info)
X{
X XArc rect;
X
X if (l->drawn) {
X MKRECT(&rect, l->startX,l->startY,l->endX,l->endY,l->typeFlag);
X XDrawArcs(XtDisplay(w), info->drawable, Global.gcx, &rect, 1);
X }
X
X l->endX = event->x;
X l->endY = event->y;
X
X /*
X ** Really set this flag in the if statement
X */
X if (l->drawn = (l->startX != l->endX && l->startY != l->endY)) {
X MKRECT(&rect, l->startX,l->startY,l->endX,l->endY,l->typeFlag);
X XDrawArcs(XtDisplay(w), info->drawable, Global.gcx, &rect, 1);
X }
X}
X
Xstatic void release(Widget w, LocalInfo *l,
X XButtonEvent *event, OpInfo *info)
X{
X XArc rect;
X XRectangle undo;
X
X if (l->drawn && info->surface == opWindow) {
X MKRECT(&rect, l->startX,l->startY,l->endX,l->endY,l->typeFlag);
X XDrawArcs(XtDisplay(w), info->drawable, Global.gcx, &rect, 1);
X }
X
X if (info->surface == opWindow && info->isFat)
X return;
X
X MKRECT(&rect, l->rx, l->ry, event->x, event->y, l->typeFlag);
X
X UndoStart(w, info);
X
X if (ISFILL(l->flag)) {
X XFillArcs(XtDisplay(w), info->drawable,
X info->filled_gc, &rect, 1);
X } else {
X XDrawArcs(XtDisplay(w), info->drawable,
X info->filled_gc, &rect, 1);
X }
X
X if (info->surface == opPixmap) {
X XYtoRECT(l->rx, l->ry, event->x, event->y, &undo);
X UndoSetRectangle(w, &undo);
X PwUpdate(w, &undo, False);
X }
X}
X
X/*
X** Those public functions
X*/
Xvoid *CircleAdd(Widget w)
X{
X LocalInfo *l = (LocalInfo*)XtMalloc(sizeof(LocalInfo));
X l->flag = CIRCLE;
X OpAddEventHandler(w, opWindow, ButtonPressMask, FALSE, press, l);
X OpAddEventHandler(w, opWindow, ButtonMotionMask, FALSE, motion, l);
X OpAddEventHandler(w, opWindow|opPixmap, ButtonReleaseMask, FALSE, release, l);
X SetCrossHairCursor(w);
X return l;
X}
Xvoid CircleRemove(Widget w, LocalInfo *l)
X{
X OpRemoveEventHandler(w, opWindow, ButtonPressMask, FALSE, press, l);
X OpRemoveEventHandler(w, opWindow, ButtonMotionMask, FALSE, motion, l);
X OpRemoveEventHandler(w, opWindow|opPixmap, ButtonReleaseMask, FALSE, release, l);
X XtFree(l);
X}
Xvoid *FCircleAdd(Widget w)
X{
X LocalInfo *l = (LocalInfo*)XtMalloc(sizeof(LocalInfo));
X l->flag = CIRCLE|FILL;
X OpAddEventHandler(w, opWindow, ButtonPressMask, FALSE, press, l);
X OpAddEventHandler(w, opWindow, ButtonMotionMask, FALSE, motion, l);
X OpAddEventHandler(w, opWindow|opPixmap, ButtonReleaseMask, FALSE, release, l);
X SetCrossHairCursor(w);
X return l;
X}
Xvoid FCircleRemove(Widget w, LocalInfo *l)
X{
X OpRemoveEventHandler(w, opWindow, ButtonPressMask, FALSE, press, l);
X OpRemoveEventHandler(w, opWindow, ButtonMotionMask, FALSE, motion, l);
X OpRemoveEventHandler(w, opWindow|opPixmap, ButtonReleaseMask, FALSE, release, l);
X XtFree(l);
X}
Xvoid *OvalAdd(Widget w)
X{
X LocalInfo *l = (LocalInfo*)XtMalloc(sizeof(LocalInfo));
X l->flag = 0;
X OpAddEventHandler(w, opWindow, ButtonPressMask, FALSE, press, l);
X OpAddEventHandler(w, opWindow, ButtonMotionMask, FALSE, motion, l);
X OpAddEventHandler(w, opWindow|opPixmap, ButtonReleaseMask, FALSE, release, l);
X SetCrossHairCursor(w);
X return l;
X}
Xvoid OvalRemove(Widget w, LocalInfo *l)
X{
X OpRemoveEventHandler(w, opWindow, ButtonPressMask, FALSE, press, l);
X OpRemoveEventHandler(w, opWindow, ButtonMotionMask, FALSE, motion, l);
X OpRemoveEventHandler(w, opWindow|opPixmap, ButtonReleaseMask, FALSE, release, l);
X XtFree(l);
X}
Xvoid *FOvalAdd(Widget w)
X{
X LocalInfo *l = (LocalInfo*)XtMalloc(sizeof(LocalInfo));
X l->flag = FILL;
X OpAddEventHandler(w, opWindow, ButtonPressMask, FALSE, press, l);
X OpAddEventHandler(w, opWindow, ButtonMotionMask, FALSE, motion, l);
X OpAddEventHandler(w, opWindow|opPixmap, ButtonReleaseMask, FALSE, release, l);
X SetCrossHairCursor(w);
X return l;
X}
Xvoid FOvalRemove(Widget w, LocalInfo *l)
X{
X OpRemoveEventHandler(w, opWindow, ButtonPressMask, FALSE, press, l);
X OpRemoveEventHandler(w, opWindow, ButtonMotionMask, FALSE, motion, l);
X OpRemoveEventHandler(w, opWindow|opPixmap, ButtonReleaseMask, FALSE, release, l);
X XtFree(l);
X}
END_OF_FILE
echo shar: NEWLINE appended to \"'CircleOp.c'\"
if test 5759 -ne `wc -c <'CircleOp.c'`; then
echo shar: \"'CircleOp.c'\" unpacked with wrong size!
fi
# end of 'CircleOp.c'
fi
if test -f 'Event.c' -a "${1}" != "-c" ; then
echo shar: Will not clobber existing file \"'Event.c'\"
else
echo shar: Extracting \"'Event.c'\" \(5686 characters\)
sed "s/^X//" >'Event.c' <<'END_OF_FILE'
X/* +-------------------------------------------------------------------+ */
X/* | Copyright 1992, David Koblas. | */
X/* | Permission to use, copy, modify, and distribute this software | */
X/* | and its documentation for any purpose and without fee is hereby | */
X/* | granted, provided that the above copyright notice appear in all | */
X/* | copies and that both that copyright notice and this permission | */
X/* | notice appear in supporting documentation. This software is | */
X/* | provided "as is" without express or implied warranty. | */
X/* +-------------------------------------------------------------------+ */
X
X#include <X11/IntrinsicP.h>
X#include "PaintP.h"
X#include "xpaint.h"
X
Xtypedef struct data_s {
X Widget w;
X void (*func)(Widget, void *, XEvent *, OpInfo *);
X void *data;
X int mask, flag;
X int surfMask;
X struct data_s *next;
X OpInfo *info;
X} data_t;
X
Xstatic data_t *list = NULL;
X
Xstatic data_t **widgetEvent(Widget w, data_t *look)
X{
X static data_t *d[10];
X data_t *cur = list;
X int n = 0;
X
X while (cur != NULL) {
X if (cur->mask == look->mask &&
X cur->flag == look->flag &&
X cur->func == look->func &&
X cur->w == w)
X d[n++] = cur;
X cur = cur->next;
X }
X
X d[n] = NULL;
X
X return n == 0 ? NULL : d;
X}
X
Xstatic void opHandleEvent(Widget w, data_t *data, XEvent *event)
X{
X int grid;
X PaintWidget paint = (PaintWidget)w;
X OpInfo *info = data->info;
X static Window lastWindow = None;
X static Display *lastDisplay = None;
X static int lastType;
X static int lastX, lastY;
X Boolean same;
X int zoom;
X
X /*
X ** Figure out if there is a grid, either by
X ** choice or by zooming
X */
X if (info->isFat = ((zoom = paint->paint.zoom) > 1))
X grid = paint->paint.zoom;
X else if (paint->paint.gridOn)
X grid = paint->paint.grid;
X else
X grid = 1;
X
X same = (event->xany.window == lastWindow) &&
X (event->xany.display == lastDisplay) &&
X (event->xany.type == lastType);
X lastWindow = event->xany.window;
X lastDisplay = event->xany.display;
X lastType = event->xany.type;
X
X /*
X ** Snap events to the grid
X */
X if (((event->type == ButtonPress) ||
X (event->type == ButtonRelease) ||
X (event->type == MotionNotify)) && grid > 1) {
X switch (event->type) {
X case ButtonPress:
X case ButtonRelease:
X event->xbutton.x = event->xbutton.x -
X (event->xbutton.x % grid);
X event->xbutton.y = event->xbutton.y -
X (event->xbutton.y % grid);
X if (same && lastX == event->xbutton.x && lastY == event->xbutton.y)
X return;
X break;
X case MotionNotify:
X event->xmotion.x = event->xmotion.x -
X (event->xmotion.x % grid);
X event->xmotion.y = event->xmotion.y -
X (event->xmotion.y % grid);
X if (same && lastX == event->xmotion.x && lastY == event->xmotion.y)
X return;
X break;
X }
X lastX = event->xmotion.x;
X lastY = event->xmotion.y;
X } else {
X lastX = lastY = -1;
X }
X
X if (event->type == MotionNotify) {
X info->x = (event->xmotion.x / zoom) + paint->paint.zoomX;
X info->y = (event->xmotion.y / zoom) + paint->paint.zoomY;
X } else if (event->type == ButtonPress || event->type == ButtonRelease) {
X info->x = (event->xbutton.x / zoom) + paint->paint.zoomX;
X info->y = (event->xbutton.y / zoom) + paint->paint.zoomY;
X }
X
X if (data->surfMask & opWindow) {
X info->surface = opWindow;
X info->drawable = event->xany.window;
X data->func(w, data->data, event, info);
X }
X if (event->type == MotionNotify) {
X event->xmotion.x = info->x;
X event->xmotion.y = info->y;
X } else if (event->type == ButtonPress || event->type == ButtonRelease) {
X event->xbutton.x = info->x;
X event->xbutton.y = info->y;
X }
X
X if (data->surfMask & opPixmap) {
X info->surface = opPixmap;
X info->drawable = paint->paint.undo ? paint->paint.undo->pixmap : None;
X data->func(w, data->data, event, info);
X }
X}
X
Xvoid OpAddEventHandler(Widget w, int surfMask, int mask, Boolean flag,
X void (*func)(Widget,void *, XEvent*, OpInfo *), void *data)
X{
X PaintWidget paint = (PaintWidget)w;
X data_t *new = (data_t *)XtMalloc(sizeof(data_t));
X OpInfo *info;
X data_t *cur;
X
X if (new == NULL)
X return;
X
X new->w = w;
X new->func = func;
X new->data = data;
X new->mask = mask;
X new->flag = flag;
X new->surfMask = surfMask;
X
X info = new->info = (OpInfo*)XtMalloc(sizeof(OpInfo));
X
X /*
X ** Now build the approprate info structure
X */
X if (paint->paint.paint == None) {
X /*
X ** If this is a paint widget, this is easy
X */
X info->filled_gc = paint->paint.fgc;
X info->solid_gc = paint->paint.sgc;
X info->base_gc = paint->paint.igc;
X } else {
X /*
X ** For a fatbits paint widget get paint information
X */
X info->filled_gc = ((PaintWidget)paint->paint.paint)->paint.fgc;
X info->solid_gc = ((PaintWidget)paint->paint.paint)->paint.sgc;
X info->base_gc = ((PaintWidget)paint->paint.paint)->paint.igc;
X }
X
X new->next = list;
X list = new;
X
X XtAddEventHandler(w, mask, flag, opHandleEvent, new);
X}
X
Xvoid OpRemoveEventHandler(Widget w, int surfMask, int mask, Boolean flag,
X void (*func)(Widget, void *, XEvent*, OpInfo *), void *data)
X{
X data_t *cur = list;
X data_t **prev = &list;
X
X while (cur != NULL) {
X if (cur->w == w &&
X cur->data == data &&
X cur->mask == mask &&
X cur->flag == flag &&
X cur->surfMask == surfMask &&
X cur->func == func)
X break;
X prev = &cur->next;
X cur = cur->next;
X }
X
X if (cur == NULL)
X return;
X
X XtRemoveEventHandler(w, mask, flag, opHandleEvent, cur);
X
X *prev = cur->next;
X
X cur->info->refCount--;
X if (cur->info->refCount == 0)
X XtFree(cur->info);
X
X XtFree(cur);
X}
END_OF_FILE
echo shar: NEWLINE appended to \"'Event.c'\"
if test 5687 -ne `wc -c <'Event.c'`; then
echo shar: \"'Event.c'\" unpacked with wrong size!
fi
# end of 'Event.c'
fi
if test -f 'FillOp.c' -a "${1}" != "-c" ; then
echo shar: Will not clobber existing file \"'FillOp.c'\"
else
echo shar: Extracting \"'FillOp.c'\" \(5656 characters\)
sed "s/^X//" >'FillOp.c' <<'END_OF_FILE'
X/* +-------------------------------------------------------------------+ */
X/* | Copyright 1992, David Koblas. | */
X/* | Permission to use, copy, modify, and distribute this software | */
X/* | and its documentation for any purpose and without fee is hereby | */
X/* | granted, provided that the above copyright notice appear in all | */
X/* | copies and that both that copyright notice and this permission | */
X/* | notice appear in supporting documentation. This software is | */
X/* | provided "as is" without express or implied warranty. | */
X/* +-------------------------------------------------------------------+ */
X
X#include <X11/Intrinsic.h>
X#include <X11/StringDefs.h>
X#include <X11/cursorfont.h>
X#include "Paint.h"
X#include "xpaint.h"
X
Xtypedef struct {
X Boolean done;
X Pixmap pix;
X} LocalInfo;
X
Xstatic XImage *source, *mask;
Xstatic int xMin, yMin, xMax, yMax;
X
X/*
X * A Seed Fill Algorithm
X * by Paul Heckbert
X * from "Graphics Gems", Academic Press, 1990
X */
X
X/*
X * fill.c : simple seed fill program
X * Calls pixelread() to read pixels, pixelwrite() to write pixels.
X *
X * Paul Heckbert 13 Sept 1982, 28 Jan 1987
X */
X
X#define pixelwrite(x,y) { \
X XPutPixel(mask, x, y, True); \
X xMin = MIN(xMin, x); \
X yMin = MIN(yMin, y); \
X xMax = MAX(xMax, x); \
X yMax = MAX(yMax, y); \
X }
X#define pixelread(x,y) (XGetPixel(mask, x, y) ? ~ov : XGetPixel(source, x, y))
X
Xtypedef struct {int y, xl, xr, dy;} Segment;
X/*
X * Filled horizontal segment of scanline y for xl<=x<=xr.
X * Parent segment was on line y-dy. dy=1 or -1
X */
X
X#define STACKSIZE 10000 /* max depth of stack */
X
X#define PUSH(Y, XL, XR, DY) /* push new segment on stack */ \
X if (sp<stack+STACKSIZE && Y+(DY)>=0 && Y+(DY)<=height) \
X {sp->y = Y; sp->xl = XL; sp->xr = XR; sp->dy = DY; sp++;}
X
X#define POP(Y, XL, XR, DY) /* pop segment off stack */ \
X {sp--; Y = sp->y+(DY = sp->dy); XL = sp->xl; XR = sp->xr;}
X
X/*
X * fill: set the pixel at (x,y) and all of its 4-connected neighbors
X * with the same pixel value to the new pixel value nv.
X * A 4-connected neighbor is a pixel above, below, left, or right of a pixel.
X */
X
Xstatic void fill(int x, int y, int width, int height)
X{
X int start, x1, x2, dy = 0;
X Pixel ov; /* old pixel value */
X Segment stack[STACKSIZE], *sp = stack; /* stack of filled segments */
X
X ov = pixelread(x, y); /* read pv at seed point */
X PUSH(y, x, x, 1); /* needed in some cases */
X PUSH(y+1, x, x, -1); /* seed segment (popped 1st) */
X
X while (sp>stack) {
X /* pop segment off stack and fill a neighboring scan line */
X POP(y, x1, x2, dy);
X /*
X * segment of scan line y-dy for x1<=x<=x2 was previously filled,
X */
X for (x = x1; x >= 0 && pixelread(x, y) == ov; x--)
X pixelwrite(x, y);
X if (x >= x1) {
X for (x++; x<=x2 && pixelread(x, y)!=ov; x++);
X start = x;
X if (x > x2)
X continue;
X } else {
X start = x+1;
X if (start<x1) PUSH(y, start, x1-1, -dy); /* leak on left? */
X x = x1+1;
X }
X do {
X for (; x<=width && pixelread(x, y)==ov; x++)
X pixelwrite(x, y);
X PUSH(y, start, x-1, dy);
X if (x>x2+1) PUSH(y, x2+1, x-1, -dy); /* leak on right? */
X for (x++; x<=x2 && pixelread(x, y)!=ov; x++);
X start = x;
X } while (x<=x2);
X }
X}
X
Xstatic void press(Widget w, LocalInfo *l, XButtonEvent *event, OpInfo *info)
X{
X XRectangle undo;
X char *mData;
X int width, height;
X GC gc;
X int fillWidth, fillHeight;
X XGCValues values;
X
X UndoStart(w, info);
X
X SetWatchCursor(w);
X
X XtVaGetValues(w, XtNdrawWidth, &width, XtNdrawHeight, &height, NULL);
X
X if ((mData = XtMalloc(width * height * sizeof(char))) == NULL)
X return;
X
X bzero(mData, width * height * sizeof(char));
X
X if ((mask = XCreateImage(XtDisplay(w), NULL,
X 1, XYBitmap, 0, mData,
X width, height, 8, 0)) == NULL) {
X XtFree(mData);
X return;
X }
X
X if ((source = XGetImage(XtDisplay(w), info->drawable, 0, 0,
X width, height, ~0, ZPixmap)) == NULL) {
X XDestroyImage(mask);
X return;
X }
X
X xMin = xMax = event->x;
X yMin = yMax = event->y;
X
X fill(event->x, event->y, width, height);
X
X XDestroyImage(source);
X
X fillWidth = (xMax - xMin) + 1;
X fillHeight = (yMax - yMin) + 1;
X
X l->pix = XCreatePixmap(XtDisplay(w), XtWindow(w), fillWidth,fillHeight,1);
X
X values.foreground = True;
X values.background = False;
X gc = XCreateGC(XtDisplay(w), l->pix, GCForeground|GCBackground, &values);
X XPutImage(XtDisplay(w), l->pix, gc, mask, xMin, yMin,
X 0, 0, fillWidth, fillHeight);
X XFreeGC(XtDisplay(w),gc);
X
X XDestroyImage(mask);
X
X XSetClipOrigin(XtDisplay(w), info->filled_gc, xMin, yMin);
X XSetClipMask(XtDisplay(w), info->filled_gc, l->pix);
X
X XFillRectangle(XtDisplay(w), info->drawable, info->filled_gc,
X xMin, yMin, fillWidth, fillHeight);
X if (!info->isFat)
X XFillRectangle(XtDisplay(w), XtWindow(w), info->filled_gc,
X xMin, yMin, fillWidth, fillHeight);
X
X XSetClipMask(XtDisplay(w), info->filled_gc, None);
X XFreePixmap(XtDisplay(w), l->pix);
X
X XYtoRECT(xMin, yMin, xMax + 1, yMax + 1, &undo);
X UndoSetRectangle(w, &undo);
X PwUpdate(w, &undo, False);
X
X SetCrossHairCursor(w);
X}
X
Xvoid *FillAdd(Widget w)
X{
X LocalInfo *l = (LocalInfo*)XtMalloc(sizeof(LocalInfo));
X l->done = False;
X OpAddEventHandler(w, opPixmap, ButtonPressMask, FALSE, press, l);
X SetCrossHairCursor(w);
X return l;
X}
Xvoid FillRemove(Widget w, LocalInfo *l)
X{
X OpRemoveEventHandler(w, opPixmap, ButtonPressMask, FALSE, press, l);
X XtFree(l);
X}
END_OF_FILE
echo shar: NEWLINE appended to \"'FillOp.c'\"
if test 5657 -ne `wc -c <'FillOp.c'`; then
echo shar: \"'FillOp.c'\" unpacked with wrong size!
fi
# end of 'FillOp.c'
fi
if test -f 'Hash.c' -a "${1}" != "-c" ; then
echo shar: Will not clobber existing file \"'Hash.c'\"
else
echo shar: Extracting \"'Hash.c'\" \(5404 characters\)
sed "s/^X//" >'Hash.c' <<'END_OF_FILE'
X/* +-------------------------------------------------------------------+ */
X/* | Copyright 1992, David Koblas. | */
X/* | Permission to use, copy, modify, and distribute this software | */
X/* | and its documentation for any purpose and without fee is hereby | */
X/* | granted, provided that the above copyright notice appear in all | */
X/* | copies and that both that copyright notice and this permission | */
X/* | notice appear in supporting documentation. This software is | */
X/* | provided "as is" without express or implied warranty. | */
X/* +-------------------------------------------------------------------+ */
X
X/*
X** A Simple useful set of hash routines:
X**
X** void *HashCreate(int (*cmp)(void *, void*), void (*free)(void *), int nelem)
X** -- Create a hash table with cmp() function, and optional free() function.
X** void HashDestroy(HashTable *tbl)
X** -- Destroy the whole hash table
X** void *HashFind(HashTable *tbl, int value, void *val)
X** -- Find an element in the hash table, returns NULL if not found
X** int HashAdd(HashTable *tbl, int value, void *val)
X** -- Add an element to the table, returns non-zero on failure
X** int HashRemove(HashTable *tbl, int value, void *elem)
X** -- Remove a particular hash entry from the table, pointer compairson
X** int HashAll(HashTable *tbl, int (*func)(void *))
X** -- Apply function to all elements of the table, until func() returns non-zero
X*/
X
X
X#include <stdio.h>
X#if 0
X#include <malloc.h>
X#else
Xextern void free(void *);
Xextern void *malloc(unsigned int);
X#endif
X
Xtypedef struct hash_s {
X int *val;
X struct hash_s *left, *right, **parentp;
X} HashElement;
X
Xtypedef struct {
X int (*cmp)(void *, void *);
X void (*free)(void *);
X HashElement **table;
X int nelem;
X} HashTable;
X
X/*
X** Create a hashtable, with cmp() compare function, and free() free function
X** with a hash table width of nelem, free can be null in which case the
X** system free function will be used.
X*/
Xvoid *HashCreate(int (*cmp)(void *, void *), void (*free)(void *), int nelem)
X{
X HashTable *new;
X int i;
X
X new = (HashTable*)malloc(sizeof(HashTable));
X new->nelem = nelem;
X new->cmp = cmp;
X new->free = free;
X new->table = (HashElement **)malloc(nelem * sizeof(HashElement*));
X
X for (i = 0; i < nelem; i++)
X new->table[i] = NULL;
X
X return (void*)new;
X}
X
Xstatic void hashDestory(void (*func)(void *), HashElement *entry)
X{
X if (entry->left != NULL) {
X hashDestory(func, entry->left);
X free(entry->left);
X }
X if (entry->right != NULL) {
X hashDestory(func, entry->right);
X free(entry->right);
X }
X
X if (entry->val)
X func(entry->val);
X}
X
X/*
X** Free the entire hash table, and all elements
X*/
Xvoid HashDestroy(HashTable *tbl)
X{
X int i;
X HashElement *cur;
X
X for (i = 0; i < tbl->nelem; i++) {
X if (tbl->table[i] != NULL) {
X hashDestory(tbl->free ? tbl->free : free, tbl->table[i]);
X free(tbl->table[i]);
X }
X }
X free(tbl);
X}
X
X/*
X** Find a particular element in the hash table, returns NULL if it isn't found
X*/
Xvoid *HashFind(HashTable *tbl, int value, void *val)
X{
X HashElement *cur = tbl->table[value];
X int v;
X
X while (cur != NULL) {
X if ((v = tbl->cmp(cur->val, val)) == 0)
X return cur->val;
X
X if (v < 0)
X cur = cur->left;
X else
X cur = cur->right;
X }
X
X return NULL;
X}
X
X/*
X** And a new element to the has table, returns non-zero on failure
X*/
Xint HashAdd(HashTable *tbl, int value, void *val)
X{
X HashElement *new = (HashElement*)malloc(sizeof(HashElement));
X HashElement *cur = tbl->table[value];
X HashElement **prev;
X
X if (new == NULL)
X return 1;
X
X new->left = NULL;
X new->right = NULL;
X new->val = val;
X new->parentp = NULL;
X
X prev = &tbl->table[value];
X while (cur != NULL) {
X if (tbl->cmp(cur->val, val) < 0) {
X prev = &cur->left;
X cur = cur->left;
X } else {
X prev = &cur->right;
X cur = cur->right;
X }
X }
X *prev = new;
X new->parentp = prev;
X
X return 0;
X}
X
Xstatic HashElement *find(HashElement *pos, void *elem)
X{
X HashElement *v;
X
X if (pos->val == elem)
X return pos;
X if (pos->left != NULL && (v = find(pos->left, elem)) != NULL)
X return v;
X if (pos->right != NULL && (v = find(pos->right, elem)) != NULL)
X return v;
X return NULL;
X}
X
X/*
X** Remove a particular element from the hash table, done using pointer compares
X*/
Xint HashRemove(HashTable *tbl, int value, void *elem)
X{
X HashElement *v;
X
X if (elem == NULL)
X return 1;
X
X if ((v = find(tbl->table[value], elem)) == NULL)
X return 0;
X
X if (v->left != NULL) {
X *v->parentp = v->left;
X v->left->parentp = v->parentp;
X if (v->right != NULL) {
X HashElement *cur = v->left, **prev;
X while (cur != NULL) {
X if (tbl->cmp(cur->val, v->right->val) < 0) {
X prev = &cur->left;
X cur = cur->left;
X } else {
X prev = &cur->right;
X cur = cur->right;
X }
X }
X *prev = v->right;
X v->right->parentp = prev;
X }
X } else {
X /* no left side, just attach the right */
X *v->parentp = v->right;
X if (v->right != NULL)
X v->right->parentp = v->parentp;
X }
X free(v);
X
X return 1;
X}
X
Xstatic int overAll(HashElement *elem, int (*func)(void *))
X{
X if (elem == NULL)
X return 0;
X if (elem->val != NULL)
X func(elem->val);
X
X return overAll(elem->left, func) || overAll(elem->right, func);
X}
X
Xint HashAll(HashTable *tbl, int (*func)(void *))
X{
X int i;
X
X for (i = 0; i < tbl->nelem; i++)
X if (overAll(tbl->table[i], func))
X return 1;
X return 0;
X}
END_OF_FILE
echo shar: NEWLINE appended to \"'Hash.c'\"
if test 5405 -ne `wc -c <'Hash.c'`; then
echo shar: \"'Hash.c'\" unpacked with wrong size!
fi
# end of 'Hash.c'
fi
if test -f 'Menu.c' -a "${1}" != "-c" ; then
echo shar: Will not clobber existing file \"'Menu.c'\"
else
echo shar: Extracting \"'Menu.c'\" \(2539 characters\)
sed "s/^X//" >'Menu.c' <<'END_OF_FILE'
X/* +-------------------------------------------------------------------+ */
X/* | Copyright 1992, David Koblas. | */
X/* | Permission to use, copy, modify, and distribute this software | */
X/* | and its documentation for any purpose and without fee is hereby | */
X/* | granted, provided that the above copyright notice appear in all | */
X/* | copies and that both that copyright notice and this permission | */
X/* | notice appear in supporting documentation. This software is | */
X/* | provided "as is" without express or implied warranty. | */
X/* +-------------------------------------------------------------------+ */
X
X#include <X11/Intrinsic.h>
X#include <X11/StringDefs.h>
X#include <X11/bitmaps/xlogo16>
X
X#include <X11/Xaw/MenuButton.h>
X#include <X11/Xaw/SimpleMenu.h>
X#include <X11/Xaw/SmeBSB.h>
X#include <X11/Xaw/SmeLine.h>
X#include <X11/Xaw/Form.h>
X
X#include "xpaint.h"
X
XWidget MenuBarCreate(Widget parent, int nbar, PaintMenuBar bar[])
X{
X static int checkWidth = 0;
X int list, item;
X Widget button, menu, entry;
X Widget prevButton = NULL;
X char menuPopupName[80];
X Widget ret;
X
X /*
X ** If there is more than one entry in this bar
X ** reparent it.
X */
X if (nbar > 1)
X parent = XtVaCreateManagedWidget("menu",
X formWidgetClass, parent,
X XtNborderWidth, 0,
X NULL);
X
X if (checkWidth == 0) {
X checkWidth = 16; /* XXX */
X }
X
X for (list = 0; list < nbar; list++) {
X strcpy(menuPopupName, bar[list].name);
X strcat(menuPopupName, "Menu");
X
X button = XtVaCreateManagedWidget(bar[list].name,
X menuButtonWidgetClass, parent,
X XtNmenuName, XtNewString(menuPopupName),
X XtNfromHoriz, prevButton,
X NULL);
X prevButton = button;
X
X menu = XtCreatePopupShell(menuPopupName,
X simpleMenuWidgetClass, button,
X NULL, 0);
X
X for (item = 0; item < bar[list].nitems; item++) {
X if (bar[list].items[item].name[0] == '\0')
X entry = XtVaCreateManagedWidget("seperator",
X smeLineObjectClass, menu,
X NULL);
X else if (bar[list].items[item].flags & MF_CHECK)
X entry = XtVaCreateManagedWidget(
X bar[list].items[item].name,
X smeBSBObjectClass, menu,
X XtNleftMargin, checkWidth + 4,
X NULL);
X else
X entry = XtVaCreateManagedWidget(
X bar[list].items[item].name,
X smeBSBObjectClass, menu,
X NULL);
X
X if (bar[list].items[item].callback != NULL)
X XtAddCallback(entry, XtNcallback,
X bar[list].items[item].callback,
X bar[list].items[item].data);
X }
X }
X
X return (nbar > 1) ? parent : button;
X}
END_OF_FILE
echo shar: NEWLINE appended to \"'Menu.c'\"
if test 2540 -ne `wc -c <'Menu.c'`; then
echo shar: \"'Menu.c'\" unpacked with wrong size!
fi
# end of 'Menu.c'
fi
if test -f 'Pattern.c' -a "${1}" != "-c" ; then
echo shar: Will not clobber existing file \"'Pattern.c'\"
else
echo shar: Extracting \"'Pattern.c'\" \(5333 characters\)
sed "s/^X//" >'Pattern.c' <<'END_OF_FILE'
X/* +-------------------------------------------------------------------+ */
X/* | Copyright 1992, David Koblas. | */
X/* | Permission to use, copy, modify, and distribute this software | */
X/* | and its documentation for any purpose and without fee is hereby | */
X/* | granted, provided that the above copyright notice appear in all | */
X/* | copies and that both that copyright notice and this permission | */
X/* | notice appear in supporting documentation. This software is | */
X/* | provided "as is" without express or implied warranty. | */
X/* +-------------------------------------------------------------------+ */
X
X#include <X11/IntrinsicP.h>
X#include <X11/Shell.h>
X#include <X11/StringDefs.h>
X#include <X11/Xaw/Form.h>
X#include <X11/Xaw/Scrollbar.h>
X#include <X11/Xaw/Command.h>
X#include <X11/CoreP.h>
X#include <X11/Xaw/ToggleP.h>
X#include "Colormap.h"
X#include "Paint.h"
X#include "xpaint.h"
X
X#define RED 1
X#define GREEN 2
X#define BLUE 3
X
Xtypedef struct {
X int add;
X Pixmap pix;
X Widget fat, widget, paint;
X} LocalInfo;
X
Xstatic void scrollCallback(Widget w, Widget cwidget, int val, int col)
X{
X XColor color;
X
X CwGetColor(cwidget, &color);
X
X switch (col) {
X case RED: color.red = val << 8; break;
X case GREEN: color.green = val << 8; break;
X case BLUE: color.blue = val << 8; break;
X }
X
X CwSetColor(cwidget, &color);
X}
X
Xstatic void redCallback(Widget w, Widget color, float *percent)
X{
X int val = *percent * 255;
X scrollCallback(w, color, val, RED);
X}
Xstatic void greenCallback(Widget w, Widget color, float *percent)
X{
X int val = *percent * 255;
X scrollCallback(w, color, val, GREEN);
X}
Xstatic void blueCallback(Widget w, Widget color, float *percent)
X{
X int val = *percent * 255;
X scrollCallback(w, color, val, BLUE);
X}
Xstatic void colorCallback(Widget w, Widget* bars, XColor *color)
X{
X float r = (float)color->red / 65536.0;
X float g = (float)color->green / 65536.0;
X float b = (float)color->blue / 65536.0;
X
X XtVaSetValues(bars[0], XtNtopOfThumb, &r, NULL);
X XtVaSetValues(bars[1], XtNtopOfThumb, &g, NULL);
X XtVaSetValues(bars[2], XtNtopOfThumb, &b, NULL);
X XtVaSetValues(bars[3], XtNforeground, color->pixel, NULL);
X#if 0
X XawScrollbarSetThumb(bars[0], r, -1.0);
X XawScrollbarSetThumb(bars[1], g, -1.0);
X XawScrollbarSetThumb(bars[2], b, -1.0);
X#endif
X}
X
Xstatic void buttonCallback(Widget w, LocalInfo *info, void *junk2)
X{
X Pixmap pix = None;
X int width, height;
X Widget form, icon;
X
X if (info) {
X PwGetPixmap(info->fat, &pix, &width, &height);
X if (info->add) {
X form = XtParent(info->widget);
X
X XawFormDoLayout(form, True);
X icon = XtVaCreateManagedWidget(NULL,
X toggleWidgetClass, form,
X XtNbitmap, pix,
X XtNradioGroup, info->widget,
X NULL);
X XtAddCallback(icon, XtNcallback, ToggleSetPattern, info->paint);
X XtVaSetValues(icon, XtNradioData, icon, NULL);
X } else {
X Widget data;
X
X data = (Widget)XawToggleGetCurrent(info->widget);
X XtVaSetValues(data, XtNbitmap, pix, NULL);
X }
X XtVaSetValues(info->paint, XtNpattern, pix, NULL);
X }
X XtDestroyWidget(GetShell(w));
X}
X
XPatternEdit(Widget w, Pixmap pix, Widget button)
X{
X Widget shell, form, topf;
X Widget color, fat;
X Widget red, green, blue;
X Widget okButton, cancelButton;
X Colormap cmap;
X Widget *bars = (Widget*)XtMalloc(sizeof(Widget)*4);
X LocalInfo *info = (LocalInfo*)XtMalloc(sizeof(LocalInfo));
X
X info->paint = w;
X info->add = (pix == None);
X
X XtVaGetValues(w, XtNcolormap, &cmap, NULL);
X
X shell = XtVaCreatePopupShell("pattern", transientShellWidgetClass, w,
X XtNcolormap, cmap,
X NULL);
X
X topf = XtVaCreateManagedWidget("form", formWidgetClass, shell,
X NULL);
X
X form = XtVaCreateManagedWidget("form", formWidgetClass, topf,
X NULL);
X
X if (pix == None)
X fat = XtVaCreateManagedWidget("bits", paintWidgetClass, form,
X XtNpixmap, pix,
X XtNzoom, 8,
X XtNdrawWidth, 32,
X XtNdrawHeight, 32,
X NULL);
X else
X fat = XtVaCreateManagedWidget("bits", paintWidgetClass, form,
X XtNpixmap, pix,
X XtNzoom, 8,
X NULL);
X color = XtVaCreateManagedWidget("cedit", colormapWidgetClass, form,
X XtNwidth, 256,
X XtNheight, 256,
X XtNcolormap, cmap,
X XtNfromHoriz, fat,
X NULL);
X
X red = XtVaCreateManagedWidget("red", scrollbarWidgetClass, form,
X XtNfromHoriz, color,
X XtNlength, 255,
X NULL);
X green = XtVaCreateManagedWidget("green", scrollbarWidgetClass, form,
X XtNfromHoriz, red,
X XtNlength, 255,
X NULL);
X blue = XtVaCreateManagedWidget("blue", scrollbarWidgetClass, form,
X XtNfromHoriz, green,
X XtNlength, 255,
X NULL);
X
X XtAddCallback(red, XtNjumpProc, redCallback, color);
X XtAddCallback(green, XtNjumpProc, greenCallback, color);
X XtAddCallback(blue, XtNjumpProc, blueCallback, color);
X bars[0] = red;
X bars[1] = green;
X bars[2] = blue;
X bars[3] = fat;
X XtAddCallback(color, XtNcallback, colorCallback, bars);
X
X info->widget = button;
X info->fat = fat;
X
X okButton = XtVaCreateManagedWidget("ok",
X commandWidgetClass, topf,
X XtNfromVert, form,
X NULL);
X
X cancelButton = XtVaCreateManagedWidget("cancel",
X commandWidgetClass, topf,
X XtNfromVert, form,
X XtNfromHoriz, okButton,
X NULL);
X XtAddCallback(cancelButton, XtNcallback, buttonCallback, NULL);
X XtAddCallback(okButton, XtNcallback, buttonCallback, info);
X
X XtPopup(shell, XtGrabNone);
X
X GraphicAdd(fat);
X}
END_OF_FILE
echo shar: NEWLINE appended to \"'Pattern.c'\"
if test 5334 -ne `wc -c <'Pattern.c'`; then
echo shar: \"'Pattern.c'\" unpacked with wrong size!
fi
# end of 'Pattern.c'
fi
if test -f 'ReadWritePNM.c' -a "${1}" != "-c" ; then
echo shar: Will not clobber existing file \"'ReadWritePNM.c'\"
else
echo shar: Extracting \"'ReadWritePNM.c'\" \(4487 characters\)
sed "s/^X//" >'ReadWritePNM.c' <<'END_OF_FILE'
X/* +-------------------------------------------------------------------+ */
X/* | Copyright 1992, David Koblas. | */
X/* | Permission to use, copy, modify, and distribute this software | */
X/* | and its documentation for any purpose and without fee is hereby | */
X/* | granted, provided that the above copyright notice appear in all | */
X/* | copies and that both that copyright notice and this permission | */
X/* | notice appear in supporting documentation. This software is | */
X/* | provided "as is" without express or implied warranty. | */
X/* +-------------------------------------------------------------------+ */
X
X#include <stdio.h>
X#include <X11/StringDefs.h>
X#include <X11/Intrinsic.h>
X#include "libpnmrw.h"
X#include "Hash.h"
X#include "Cmap.h"
X
X#define HASH_SIZE 128
X#define HASH(r,g,b) ((r + g + b) % HASH_SIZE)
X
Xtypedef struct he {
X int r,g,b;
X int pixel;
X struct he *next;
X} hashEntry;
X
Xstatic void *htable = NULL;
Xstatic int format;
X
Xstatic int getPixel(Display *dpy, Cmap *cmap, int r, int g, int b)
X{
X XColor c;
X
X c.red = r * 256;
X c.green = g * 256;
X c.blue = b * 256;
X
X CmapAlloc(cmap, &c);
X
X return c.pixel;
X}
X
Xint ReadPNM(Widget w, char *file, unsigned int *width, unsigned int *height, Pixmap *pix, Colormap *cmap)
X{
X static int inited = FALSE;
X int y, x;
X XImage *xim = NULL;
X xel **image = NULL;
X xel *curel;
X char *data = NULL;
X int depth = DefaultDepthOfScreen(XtScreen(w));
X int status = TRUE;
X GC gc;
X xelval maxval;
X int format;
X int isPPM;
X FILE *fd;
X int wth, hth;
X Display *dpy = XtDisplay(w);
X Cmap *map;
X
X *pix = None;
X
X pnm_init2(file);
X if ((fd = fopen(file, "r")) == NULL)
X return TRUE;
X if ((image=pnm_readpnm(fd, &wth, &hth, &maxval, &format))==NULL)
X return TRUE;
X isPPM = PPM_FORMAT_TYPE(format) == PPM_TYPE;
X *width = wth;
X *height = hth;
X fclose(fd);
X
X map = CreateCmap(w);
X *cmap = map->cmap;
X
X if ((*pix = XCreatePixmap(dpy, XtWindow(w),
X *width, *height, depth)) == None)
X goto out;
X
X if ((data = XtMalloc(*width * *height * sizeof(char) * 4)) == NULL)
X goto out;
X if ((xim = XCreateImage(dpy, NULL, depth,
X ZPixmap, 0, data, *width, *height, 8, 0)) == NULL)
X goto out;
X
X for (curel = image[y = 0]; y < *height; curel = image[++y]) {
X for (x = 0; x < *width; x++, curel++) {
X int pixel;
X XColor c;
X int val;
X
X if (isPPM) {
X pixel = getPixel(dpy, map,
X 255 * PPM_GETR(*curel) / maxval,
X 255 * PPM_GETG(*curel) / maxval,
X 255 * PPM_GETB(*curel) / maxval);
X } else {
X val = 255 * PNM_GET1(*curel) / maxval;
X pixel = getPixel(dpy, map, val, val, val);
X }
X
X XPutPixel(xim, x, y, pixel);
X }
X }
X
X gc = XtGetGC(w, 0, NULL);
X XPutImage(dpy, *pix, gc, xim, 0, 0, 0, 0, *width, *height);
X XtReleaseGC(w, gc);
X
X status = FALSE;
Xout:
X if (image != NULL)
X pnm_freearray(image, *height);
X if (xim != NULL)
X XDestroyImage(xim);
X if (status && *pix != None)
X XFreePixmap(dpy, *pix);
X return status;
X}
X
Xint writeCMP(XColor *a, XColor *b)
X{
X return a->pixel - b->pixel;
X}
X
Xvoid find(Display *dpy, Colormap cmap, long val, xel *pv)
X{
X XColor c, *col;
X
X c.pixel = val;
X
X if ((col = HashFind(htable, val % HASH_SIZE, &c)) == NULL) {
X col = (XColor *)malloc(sizeof(XColor));
X col->pixel = val;
X col->flags = DoRed|DoGreen|DoBlue;
X XQueryColor(dpy, cmap, col);
X HashAdd(htable, val % HASH_SIZE, col);
X }
X
X PPM_ASSIGN(*pv, col->red >> 8, col->green >> 8, col->blue >> 8);
X
X if (format != PPM_FORMAT)
X if (col->red != col->green || col->green != col->blue)
X format = PPM_FORMAT;
X if (format == PBM_FORMAT)
X if (col->red != 0 && (col->red & 0xff00) != 0xff00)
X format = PGM_FORMAT;
X}
X
Xint WritePNM(Widget w, char *file, int width, int height, Pixmap pix)
X{
X xel **xels;
X XImage *xim = XGetImage(XtDisplay(w), pix, 0, 0, width, height, ~0, ZPixmap);
X Colormap cmap;
X Display *dpy = XtDisplay(w);
X int x, y;
X FILE *fd;
X
X if (xim == NULL)
X return TRUE;
X if ((fd = fopen(file, "w")) == NULL) {
X XDestroyImage(xim);
X return TRUE;
X }
X
X XtVaGetValues(w, XtNcolormap, &cmap, NULL);
X
X format = PBM_FORMAT;
X htable = HashCreate(writeCMP, NULL, HASH_SIZE);
X
X pnm_init2(file);
X
X xels = pnm_allocarray(width, height);
X
X for (y = 0; y < height; y++)
X for (x = 0; x < width; x++)
X find(dpy, cmap, XGetPixel(xim, x, y), &xels[y][x]);
X
X pnm_writepnm(fd, xels, width, height, 255, format, FALSE);
X
X pnm_freearray(xels, height);
X XDestroyImage(xim);
X fclose(fd);
X HashDestroy(htable);
X htable = NULL;
X
X return FALSE;
X}
END_OF_FILE
echo shar: NEWLINE appended to \"'ReadWritePNM.c'\"
if test 4488 -ne `wc -c <'ReadWritePNM.c'`; then
echo shar: \"'ReadWritePNM.c'\" unpacked with wrong size!
fi
# end of 'ReadWritePNM.c'
fi
if test -f 'SelectAreaOp.c' -a "${1}" != "-c" ; then
echo shar: Will not clobber existing file \"'SelectAreaOp.c'\"
else
echo shar: Extracting \"'SelectAreaOp.c'\" \(5743 characters\)
sed "s/^X//" >'SelectAreaOp.c' <<'END_OF_FILE'
X/* +-------------------------------------------------------------------+ */
X/* | Copyright 1992, David Koblas. | */
X/* | Permission to use, copy, modify, and distribute this software | */
X/* | and its documentation for any purpose and without fee is hereby | */
X/* | granted, provided that the above copyright notice appear in all | */
X/* | copies and that both that copyright notice and this permission | */
X/* | notice appear in supporting documentation. This software is | */
X/* | provided "as is" without express or implied warranty. | */
X/* +-------------------------------------------------------------------+ */
X
X#include <X11/Intrinsic.h>
X#include <X11/StringDefs.h>
X#include <X11/cursorfont.h>
X#include "xpaint.h"
X
Xtypedef struct {
X int startX, startY, endX, endY;
X int id, pos;
X GC gc;
X Boolean drawn;
X
X XPoint pbuf[1024];
X int npoints;
X} LocalInfo;
X
X#if 0
X
X
X#define DELAY 100
X
Xstatic void freeFunc(void *region)
X{
X XPoint *pnts = ((RegionArea_t*)region)->points;
X
X XtFree(pnts);
X}
X
Xstatic Pixmap generateMask(Widget wid)
X{
X PaintWidget w = (PaintWidget)wid;
X GC gc;
X XGCValues values;
X Pixmap pix;
X RegionArea_t *area = (RegionArea_t*)w->paint.region;
X int x, y;
X
X pix = XCreatePixmap(XtDisplay(w), XtWindow(w),
X area->bbox.width,
X area->bbox.height, 1);
X
X values.foreground = False;
X values.background = False;
X gc = XCreateGC(XtDisplay(w), pix, GCForeground|GCBackground, &values);
X XFillRectangle(XtDisplay(w), pix, gc, 0, 0,
X area->bbox.width, area->bbox.height);
X XSetForeground(XtDisplay(w), gc, True);
X
X x = area->points[0].x;
X y = area->points[0].y;
X
X area->points[0].x = area->startX;
X area->points[0].y = area->startY;
X
X XFillPolygon(XtDisplay(w), pix, gc, area->points, area->npoints - 1,
X Complex, CoordModePrevious);
X
X area->points[0].x = x;
X area->points[0].y = y;
X
X XFreeGC(XtDisplay(w), gc);
X
X return pix;
X}
X
Xstatic void flash(PaintWidget w)
X{
X XGCValues values;
X
X XDrawLines(XtDisplay(w), XtWindow(w), gc,
X w->paint.region->area.points,
X w->paint.region->area.npoints,
X CoordModePrevious);
X
X values.dash_offset = (++pos) % 8;
X XChangeGC(XtDisplay(w), gc, GCDashOffset, &values);
X XDrawLines(XtDisplay(w), XtWindow(w), gc,
X w->paint.region->area.points,
X w->paint.region->area.npoints,
X CoordModePrevious);
X
X id = XtAddTimeOut(DELAY, flash, w);
X}
X
Xstatic void press(PaintWidget w, void *junk, XButtonEvent *event)
X{
X drawn = False;
X
X if (id != NULL) {
X XDrawLines(XtDisplay(w), XtWindow(w), gc,
X w->paint.region->area.points,
X w->paint.region->area.npoints,
X CoordModePrevious);
X XtRemoveTimeOut(id);
X
X id = NULL;
X }
X
X pbuf[0].x = event->x;
X pbuf[0].y = event->y;
X npoints = 1;
X}
X
Xstatic void motion(PaintWidget w, void *junk, XMotionEvent *event)
X{
X pbuf[npoints].x = event->x;
X pbuf[npoints].y = event->y;
X
X XDrawLine(XtDisplay(w), XtWindow(w), w->paint.gcx,
X pbuf[npoints-1].x, pbuf[npoints-1].y,
X pbuf[npoints].x, pbuf[npoints].y);
X
X npoints++;
X}
X
Xstatic void release(PaintWidget w, void *junk, XButtonEvent *event)
X{
X RegionArea_t *area;
X int i;
X int xmin, xmax, ymin, ymax;
X XRectangle rect;
X
X XDrawLines(XtDisplay(w), XtWindow(w), w->paint.gcx,
X pbuf, npoints, CoordModeOrigin);
X if (npoints > 2) {
X XDrawPoints(XtDisplay(w), XtWindow(w), w->paint.gcx,
X pbuf+1, npoints-2, CoordModeOrigin);
X }
X
X pbuf[npoints].x = pbuf[0].x;
X pbuf[npoints].y = pbuf[0].y;
X npoints++;
X
X area = (RegionArea_t*)XtMalloc(sizeof(RegionArea_t));
X area->mask = generateMask;
X area->free = freeFunc;
X area->points = (XPoint*)XtMalloc(sizeof(XPoint) * npoints);
X area->npoints = npoints;
X
X xmin = xmax = pbuf[0].x;
X ymin = ymax = pbuf[0].y;
X area->points[0].x = pbuf[0].x;
X area->points[0].y = pbuf[0].y;
X for (i = 1; i < npoints; i++) {
X xmin = MIN(xmin, pbuf[i].x);
X ymin = MIN(ymin, pbuf[i].y);
X xmax = MAX(xmax, pbuf[i].x);
X ymax = MAX(ymax, pbuf[i].y);
X
X area->points[i].x = pbuf[i].x - pbuf[i - 1].x;
X area->points[i].y = pbuf[i].y - pbuf[i - 1].y;
X }
X
X area->startX = pbuf[0].x - xmin;
X area->startY = pbuf[0].y - ymin;
X
X area->bbox.x = xmin;
X area->bbox.y = ymin;
X area->bbox.width = xmax - xmin;
X area->bbox.height = ymax - ymin;
X
X SETREGION(w->paint.region, area);
X
X XDrawLines(XtDisplay(w), XtWindow(w), gc,
X w->paint.region->area.points,
X w->paint.region->area.npoints,
X CoordModePrevious);
X
X id = XtAddTimeOut(DELAY, flash, w);
X}
X#endif
X
X/*
X** Those public functions
X*/
Xvoid *SelectAreaAdd(Widget w)
X{
X LocalInfo *l = (LocalInfo*)XtMalloc(sizeof(LocalInfo));
X#if 0
X PaintWidget pw = (PaintWidget)w;
X static char dashList[] = { 4, 4 };
X Cursor c;
X
X OpAddEventHandler(w, ButtonPressMask, FALSE, press, NULL);
X OpAddEventHandler(w, ButtonMotionMask, FALSE, motion, NULL);
X OpAddEventHandler(w, ButtonReleaseMask, FALSE, release, NULL);
X
X gc = XCreateGC(XtDisplay(w), XtWindow(w), 0, NULL);
X XCopyGC(XtDisplay(w), pw->paint.gcx, ~0, gc);
X XSetLineAttributes(XtDisplay(w), gc, 0,
X LineOnOffDash, CapButt, JoinMiter);
X XSetDashes(XtDisplay(w), gc, 0, dashList, XtNumber(dashList));
X
X c = XCreateFontCursor(XtDisplay(w), XC_pencil);
X XDefineCursor(XtDisplay(w), XtWindow(w), c);
X#endif
X return l;
X}
Xvoid SelectAreaRemove(Widget w, LocalInfo *l)
X{
X#if 0
X PaintWidget pw = (PaintWidget)w;
X
X if (id != NULL) {
X XDrawLines(XtDisplay(w), XtWindow(w), gc,
X pw->paint.region->area.points,
X pw->paint.region->area.npoints,
X CoordModePrevious);
X XtRemoveTimeOut(id);
X
X id = NULL;
X }
X
X XFreeGC(XtDisplay(w), gc);
X
X OpRemoveEventHandler(w, ButtonPressMask, FALSE, press, NULL);
X OpRemoveEventHandler(w, ButtonMotionMask, FALSE, motion, NULL);
X OpRemoveEventHandler(w, ButtonReleaseMask, FALSE, release, NULL);
X#endif
X XtFree(l);
X}
END_OF_FILE
echo shar: NEWLINE appended to \"'SelectAreaOp.c'\"
if test 5744 -ne `wc -c <'SelectAreaOp.c'`; then
echo shar: \"'SelectAreaOp.c'\" unpacked with wrong size!
fi
# end of 'SelectAreaOp.c'
fi
if test -f 'SelectBoxOp.c' -a "${1}" != "-c" ; then
echo shar: Will not clobber existing file \"'SelectBoxOp.c'\"
else
echo shar: Extracting \"'SelectBoxOp.c'\" \(5106 characters\)
sed "s/^X//" >'SelectBoxOp.c' <<'END_OF_FILE'
X/* +-------------------------------------------------------------------+ */
X/* | Copyright 1992, David Koblas. | */
X/* | Permission to use, copy, modify, and distribute this software | */
X/* | and its documentation for any purpose and without fee is hereby | */
X/* | granted, provided that the above copyright notice appear in all | */
X/* | copies and that both that copyright notice and this permission | */
X/* | notice appear in supporting documentation. This software is | */
X/* | provided "as is" without express or implied warranty. | */
X/* +-------------------------------------------------------------------+ */
X
X#include <X11/IntrinsicP.h>
X#include <X11/StringDefs.h>
X#include <X11/cursorfont.h>
X#include "xpaint.h"
X#include "PaintP.h"
X
Xtypedef struct {
X int rx, ry;
X int startX, startY, endX, endY;
X GC gc;
X int id, pos;
X Boolean drawn;
X} LocalInfo;
X
X#define MKRECT(rect, sx, sy, ex, ey) do { \
X (rect)->x = MIN(sx, ex); \
X (rect)->y = MIN(sy, ey); \
X (rect)->width = MAX(sx, ex) - (rect)->x; \
X (rect)->height = MAX(sy, ey) - (rect)->y; \
X } while (0)
X
X#define DELAY 50
X
Xstatic Pixmap generateMask(Widget wid)
X{
X PaintWidget w = (PaintWidget)wid;
X GC gc;
X XGCValues values;
X Pixmap pix;
X RegionBox_t *box = (RegionBox_t*)w->paint.region;
X
X pix = XCreatePixmap(XtDisplay(w), XtWindow(w),
X box->bbox.width,
X box->bbox.height, 1);
X
X values.foreground = True;
X values.background = False;
X gc = XCreateGC(XtDisplay(w), pix, GCForeground|GCBackground, &values);
X
X XFillRectangles(XtDisplay(w), pix, gc, &box->bbox, 1);
X
X XFreeGC(XtDisplay(w), gc);
X
X return pix;
X}
X
X#if 0
Xstatic void flash(PaintWidget w)
X{
X XGCValues values;
X
X XDrawRectangles(XtDisplay(w), XtWindow(w), gc,
X &w->paint.region->box.bbox, 1);
X
X values.dash_offset = (++pos) % 8;
X XChangeGC(XtDisplay(w), gc, GCDashOffset, &values);
X XDrawRectangles(XtDisplay(w), XtWindow(w), gc,
X &w->paint.region->box.bbox, 1);
X
X id = XtAddTimeOut(DELAY, flash, w);
X}
X#endif
X
Xstatic void press(PaintWidget w, LocalInfo *l, XButtonEvent *event, OpInfo *info)
X{
X if (info->surface != opWindow)
X return;
X
X l->rx = info->x;
X l->ry = info->y;
X l->startX = l->endX = event->x;
X l->startY = l->endY = event->y;
X
X l->drawn = False;
X
X#if 0
X if (id != NULL) {
X XDrawRectangles(XtDisplay(w), XtWindow(w), gc,
X &w->paint.region->area.bbox, 1);
X XtRemoveTimeOut(id);
X
X id = NULL;
X }
X#endif
X}
X
Xstatic void motion(PaintWidget w, LocalInfo *l, XMotionEvent *event, OpInfo *info)
X{
X XRectangle rect;
X
X if (info->surface != opWindow)
X return;
X
X if (l->drawn) {
X MKRECT(&rect, l->startX, l->startY, l->endX, l->endY);
X XDrawRectangles(XtDisplay(w), XtWindow(w),
X Global.gcx, &rect, 1);
X }
X
X l->endX = event->x;
X l->endY = event->y;
X
X if (l->drawn = (l->startX != l->endX && l->startY != l->endY)) {
X MKRECT(&rect, l->startX, l->startY,
X l->endX, l->endY);
X
X XDrawRectangles(XtDisplay(w), XtWindow(w),
X Global.gcx, &rect, 1);
X }
X}
X
Xstatic void release(PaintWidget w, LocalInfo *l, XButtonEvent *event, OpInfo *info)
X{
X RegionBox_t *box;
X XRectangle rect;
X
X if (info->surface != opWindow)
X return;
X
X if (l->drawn) {
X MKRECT(&rect, l->startX, l->startY, l->endX, l->endY);
X
X XDrawRectangles(XtDisplay(w), XtWindow(w),
X Global.gcx, &rect, 1);
X }
X
X box = (RegionBox_t*)XtMalloc(sizeof(RegionBox_t));
X MKRECT(&box->bbox, l->rx, l->ry, info->x, info->y);
X box->mask = generateMask;
X box->free = NULL;
X
X SETREGION(w->paint.region, box);
X
X#if 0
X XDrawRectangles(XtDisplay(w), XtWindow(w), gc,
X &w->paint.region->box.bbox, 1);
X
X l->id = XtAddTimeOut(DELAY, flash, w);
X#endif
X}
X
X/*
X** Those public functions
X*/
Xvoid *SelectBoxAdd(Widget w)
X{
X LocalInfo *l = (LocalInfo*)XtMalloc(sizeof(LocalInfo));
X PaintWidget pw = (PaintWidget)w;
X Cursor c;
X static char dashList[] = { 4, 4 };
X
X OpAddEventHandler(w, opWindow, ButtonPressMask, FALSE, press, l);
X OpAddEventHandler(w, opWindow, ButtonMotionMask, FALSE, motion, l);
X OpAddEventHandler(w, opWindow, ButtonReleaseMask, FALSE, release, l);
X
X#if 0
X gc = XCreateGC(XtDisplay(w), XtWindow(w), 0, NULL);
X XCopyGC(XtDisplay(w), Global.gcx, ~0, gc);
X XSetLineAttributes(XtDisplay(w), gc, 0,
X LineOnOffDash, CapButt, JoinMiter);
X XSetDashes(XtDisplay(w), gc, 0, dashList, XtNumber(dashList));
X#endif
X
X c = XCreateFontCursor(XtDisplay(w), XC_pencil);
X XDefineCursor(XtDisplay(w), XtWindow(w), c);
X
X return l;
X}
X
Xvoid SelectBoxRemove(Widget w, LocalInfo *l)
X{
X PaintWidget pw = (PaintWidget)w;
X
X#if 0
X if (id != NULL) {
X XDrawRectangles(XtDisplay(w), XtWindow(w), gc,
X &pw->paint.region->box.bbox, 1);
X XtRemoveTimeOut(id);
X
X id = NULL;
X }
X
X XFreeGC(XtDisplay(w), gc);
X#endif
X
X OpRemoveEventHandler(w, opWindow, ButtonPressMask, FALSE, press, l);
X OpRemoveEventHandler(w, opWindow, ButtonMotionMask, FALSE, motion, l);
X OpRemoveEventHandler(w, opWindow, ButtonReleaseMask, FALSE, release, l);
X}
END_OF_FILE
echo shar: NEWLINE appended to \"'SelectBoxOp.c'\"
if test 5107 -ne `wc -c <'SelectBoxOp.c'`; then
echo shar: \"'SelectBoxOp.c'\" unpacked with wrong size!
fi
# end of 'SelectBoxOp.c'
fi
echo shar: End of archive 3 \(of 5\).
cp /dev/null ark3isdone
MISSING=""
for I in 1 2 3 4 5 ; do
if test ! -f ark${I}isdone ; then
MISSING="${MISSING} ${I}"
fi
done
if test "${MISSING}" = "" ; then
echo You have unpacked all 5 archives.
rm -f ark[1-9]isdone
else
echo You still need to unpack the following archives:
echo " " ${MISSING}
fi
## End of shell archive.
exit 0
--
name : David Koblas domain: koblas@mips.com
quote: If you have sex in your car, does that make it a recreational vehicle?
Technical Details
Message-ID:
<l5pakqINNmi2@spim.mips.com>Path:
arc1-ca.pugleaf.net!wupost!zaphod.mps.ohio-state.edu!mips!koblasShow Full Headers
Complete Article Headers
Path: arc1-ca.pugleaf.net!wupost!zaphod.mps.ohio-state.edu!mips!koblas From: koblas@mips.com (David Koblas) Newsgroups: comp.windows.x.apps,alt.sources Subject: BETA Version of XPaint 2.0 -- Part 3 / 5 Date: 9 Jul 1992 21:07:38 GMT Organization: MIPS Computer Systems, Sunnyvale, California Lines: 2028 Distribution: world Message-ID: <l5pakqINNmi2@spim.mips.com> NNTP-Posting-Host: lloyd.mips.com Originator: koblas@lloyd.mips.com