This is ImportView.c in view mode; [Download] [Up]
/*
* $RCSfile: ImportView.c,v $
*
* Copyright (C) 1992 by Adobe Systems Incorporated.
* All rights reserved.
*
* Permission to use, copy, modify, and distribute this software and its
* documentation for any purpose and without fee is hereby granted,
* provided that the above copyright notices appear in all copies and that
* both those copyright notices and this permission notice appear in
* supporting documentation and that the name of Adobe Systems
* Incorporated not be used in advertising or publicity pertaining to
* distribution of the software without specific, written prior
* permission. If any portion of this software is changed, it cannot be
* marketed under Adobe's trademarks and/or copyrights unless Adobe, in
* its sole discretion, approves by a prior writing the quality of the
* resulting implementation.
*
* ADOBE MAKES NO REPRESENTATIONS ABOUT THE SUITABILITY OF THE SOFTWARE FOR
* ANY PURPOSE. IT IS PROVIDED "AS IS" WITHOUT EXPRESS OR IMPLIED WARRANTY.
* ADOBE DISCLAIMS ALL WARRANTIES WITH REGARD TO THIS SOFTWARE, INCLUDING ALL
* IMPLIED WARRANTIES OF MERCHANTABILITY FITNESS FOR A PARTICULAR PURPOSE AND
* NON-INFRINGEMENT OF THIRD PARTY RIGHTS. IN NO EVENT SHALL ADOBE BE LIABLE
* TO YOU OR ANY OTHER PARTY FOR ANY SPECIAL, INDIRECT, OR CONSEQUENTIAL
* DAMAGES OR ANY DAMAGES WHATSOEVER WHETHER IN AN ACTION OF CONTRACT,
* NEGLIGENCE, STRICT LIABILITY OR ANY OTHER ACTION ARISING OUT OF OR IN
* CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. ADOBE WILL NOT
* PROVIDE ANY TRAINING OR OTHER SUPPORT FOR THE SOFTWARE.
*
* PostScript, Display PostScript, and Adobe are trademarks of Adobe Systems
* Incorporated registered in the U.S.A. and other countries.
*
* Author: Adobe Systems Incorporated
*/
/***************************************************************
**
** INCLUDES
**
***************************************************************/
#include "Import.h"
#include <X11/Xproto.h>
#include <sys/stat.h>
/***************************************************************
**
** FUNCTION: setOrigin
**
** DESCRIPTION: Sets the origin to where it should by using translation and
** updates the saved transformation matrices. Re-initializes
** the matrix and sets it to avoid cumulative roundoff error
**
** PARAMETERS: None
**
** RETURN: None.
**
***************************************************************/
void setOrigin()
{
Point pt;
XPoint xpt;
xpt.x = AppData.originX;
xpt.y = AppData.originY;
convertToOrigDPS(&xpt, &pt);
PSWSetMatrixAndGetTransform(pt.x, pt.y,
AppData.originX, AppData.originY,
AppData.ctm, AppData.invctm,
&AppData.xOffset, &AppData.yOffset);
} /* end setOrigin() */
/***************************************************************
**
** FUNCTION: scrollProc
**
** DESCRIPTION: Callback routine for hitting scroll bars
**
** PARAMETERS: w callback widget ID
** clientData callback client data
** callData callback Motif data structure
**
** RETURN: None.
**
***************************************************************/
void scrollProc (w, clientData, callData)
Widget w;
XtPointer clientData, callData;
{
int x, y;
int deltaX, deltaY;
Widget draw = AppData.drawingArea;
/*
** Get the new values of the scroll bars
*/
XtVaGetValues(AppData.hScroll, XmNvalue, &x, NULL);
XtVaGetValues(AppData.vScroll, XmNvalue, &y, NULL);
/*
** Calculate the delta in the scrolling
*/
deltaX = x - AppData.scrollX;
deltaY = y - AppData.scrollY;
/*
** If we are not already scrolling, and there is some scrolling to do,
** then scroll the pixmap and copy the pixmap to the window
*/
if (deltaX == 0 && deltaY == 0) return;
if (!AppData.scrolling) {
doScroll(deltaX, deltaY);
XCopyArea(XtDisplay(draw), AppData.original,
XtWindow(draw), AppData.gc, 0, 0,
AppData.drawingWidth, AppData.drawingHeight, 0, 0);
if (AppData.selected) drawSelectionMarks();
}
/*
** Set the scrolling flag; future scrolls will not update the window
** until the current one is done
*/
AppData.scrolling = True;
} /* end scrollProc() */
/***************************************************************
**
** FUNCTION: doScroll
**
** DESCRIPTION: Scroll the drawing area by some delta
**
** PARAMETERS: deltaX X displacement
** deltaY Y displacement
**
** RETURN: None.
**
***************************************************************/
void doScroll(deltaX, deltaY)
int deltaX, deltaY;
{
/*
** Set the PS origin in the X window to the new settings of
** the scrollbars
*/
AppData.originX -= deltaX;
AppData.originY -= deltaY;
/*
** Update the graphics states to reflect new origin
*/
(void) XDPSSetContextGState(AppData.dpsCtxt, AppData.origGState);
setOrigin();
(void) XDPSUpdateContextGState(AppData.dpsCtxt, AppData.origGState);
(void) XDPSSetContextGState(AppData.dpsCtxt, AppData.compGState);
setOrigin();
(void) XDPSUpdateContextGState(AppData.dpsCtxt, AppData.compGState);
(void) XDPSSetContextGState(AppData.dpsCtxt, AppData.winGState);
setOrigin();
(void) XDPSUpdateContextGState(AppData.dpsCtxt, AppData.winGState);
/*
** Update the stored position of the scroll bars
*/
AppData.scrollX += deltaX;
AppData.scrollY += deltaY;
/*
** Redisplay
*/
drawSelf(NULL);
} /* end doScroll() */
/***************************************************************
**
** FUNCTION: graphicExpose
**
** DESCRIPTION: Callback routine that handles GraphicsExpose and
** NoExpose events. We get one for each copy into the window
** from the pixmap, so they should always be NoExpose events.
** When we get one, call scrollProc to see if we need to
** scroll any more. Not handling further scroll callbacks
** until the event arrives makes scrolling much more responsive.
**
** PARAMETERS: w window widget
** clientData clientdata
** event event information
** goOn continue to dispatch
**
** RETURN: None.
**
***************************************************************/
void graphicExpose (w, clientData, event, goOn)
Widget w;
XtPointer clientData;
XEvent *event;
Boolean *goOn;
{
if (AppData.scrolling) {
AppData.scrolling = False;
scrollProc(w, NULL, NULL);
}
} /* end graphicExpose() */
/***************************************************************
**
** FUNCTION: positionDrawingArea
**
** DESCRIPTION: Routine to position the origin so that the
** point (ix, iy) on the image, in PS coordinates,
** corresponds to the point (vx, vy) on the visible
** window, in X coords.
**
** PARAMETERS:
** ix x coord of point on DPS context (PS coordinates)
** iy y coord of point on DPS context (PS coordinates)
** vx x coors of point on drawing area (X coordinates)
** vy y coors of point on drawing area (X coordinates)
**
** RETURN: None.
**
***************************************************************/
void positionDrawingArea (ix, iy, vx, vy)
float ix;
float iy;
int vx;
int vy;
{
int xoff, yoff;
int hSize, vSize;
float scrollX, scrollY;
/* Convert ix, iy into X units */
ix *= ((float) AppData.scaledWidth) / PAGE_WIDTH;
iy *= ((float) AppData.scaledHeight) / PAGE_HEIGHT;
if (AppData.drawingWidth >= AppData.scaledWidth) {
/*
** The scaled width is narrower than the view window, so
** center the picture and set scroll bar to be unscrollable
*/
xoff = (AppData.drawingWidth - AppData.scaledWidth) / 2.0;
scrollX = 0;
hSize = AppData.scaledWidth;
} else {
/*
** The scaled width is larger than the view window, so
** turn on the scroll bar, and set up its maximum and
** slider size. Do this by subtracting the view offset from the
** image offset.
*/
scrollX = ix - vx;
scrollX = MAX(scrollX, 0);
scrollX = MIN(scrollX,
AppData.scaledWidth - (int) AppData.drawingWidth);
hSize = AppData.drawingWidth;
xoff = -(int) (scrollX + 0.5);
}
/*
** Now do the same thing for the height. We want to compute the offset
** relative to the lower left corner, but X coordinates are relative
** to the upper left, so the drawing height must be added in. Also, since
** the coordinates go in the other direction, the view offset must be
** added, not subtracted.
*/
if (AppData.drawingHeight >= AppData.scaledHeight) {
yoff = (AppData.drawingHeight - AppData.scaledHeight) / 2.0;
scrollY = AppData.scaledHeight - (int) AppData.drawingHeight;
vSize = AppData.scaledHeight;
vy = AppData.drawingHeight / 2;
} else {
scrollY = iy + vy - (int) AppData.drawingHeight;
scrollY = MAX(scrollY, 0);
scrollY = MIN(scrollY,
AppData.scaledHeight - (int) AppData.drawingHeight);
vSize = AppData.drawingHeight;
yoff = -(int) (scrollY + 0.5);
}
/*
** Update the scrollbars
*/
AppData.scrollX = (int) (scrollX + 0.5);
AppData.scrollY = (int) (AppData.scaledHeight -
(int) AppData.drawingHeight - scrollY + 0.5);
XtVaSetValues(AppData.hScroll, XmNmaximum, AppData.scaledWidth,
XmNvalue, AppData.scrollX, XmNsliderSize, hSize, NULL);
XtVaSetValues(AppData.vScroll, XmNmaximum, AppData.scaledHeight,
XmNvalue, AppData.scrollY, XmNsliderSize, vSize, NULL);
/*
** Store the new origin and update the gstates to use this origin
*/
AppData.originX = xoff;
AppData.originY = AppData.drawingHeight - yoff;
(void) XDPSSetContextGState(AppData.dpsCtxt, AppData.origGState);
setOrigin();
(void) XDPSUpdateContextGState(AppData.dpsCtxt, AppData.origGState);
(void) XDPSSetContextGState(AppData.dpsCtxt, AppData.compGState);
setOrigin();
(void) XDPSUpdateContextGState(AppData.dpsCtxt, AppData.compGState);
(void) XDPSSetContextGState(AppData.dpsCtxt, AppData.winGState);
setOrigin();
(void) XDPSUpdateContextGState(AppData.dpsCtxt, AppData.winGState);
} /* end positionDrawingArea() */
/***************************************************************
**
** FUNCTION: pixmapHandler
**
** DESCRIPTION: New error handler to detect pixmap allocation failure
**
** PARAMETERS: dpy Current display
** error Error event
**
** RETURN: 0
**
***************************************************************/
static Boolean pixmapError;
static int (*oldHandler)();
static int pixmapHandler(dpy, error)
Display *dpy;
XErrorEvent *error;
{
if (error->error_code == BadAlloc &&
error->request_code == X_CreatePixmap) {
pixmapError = True;
return 0;
} else return (*oldHandler) (dpy, error);
} /* end pixmapHandler() */
/***************************************************************
**
** FUNCTION: allocPixmap
**
** DESCRIPTION: Allocate a pixmap of the desired size, but if
** it would exceed the memory limit or if the allocation
** fails, return None
**
** PARAMETERS: dpy The display
** win A window on the screen
** w, h The pixmap dimensions
** d Pixmap depth
**
** RETURN: The pixmap, or None
**
***************************************************************/
Pixmap allocPixmap(dpy, win, w, h, d)
Display *dpy;
Window win;
unsigned int w, h, d;
{
Pixmap p;
unsigned int dBytes;
dBytes = (d + 7) / 8; /* Convert into bytes */
if (w * h * dBytes > AppData.pixmapMaxSize) return None;
XSync(dpy, False);
oldHandler = XSetErrorHandler(pixmapHandler);
pixmapError = False;
p = XCreatePixmap(dpy, win, w, h, d);
XSync(dpy, False);
(void) XSetErrorHandler(oldHandler);
if (pixmapError) return None;
else return p;
} /* end allocPixmap() */
/*
** Constant for use with the next four procedures. Tells
** XDPSSetContextParameters to set all context parameters.
*/
#define XDPSContextAll (XDPSContextScreenDepth | XDPSContextDrawable |\
XDPSContextGrayMap | XDPSContextRGBMap)
/*************************************************************
**
** FUNCTION: setDrawingParameters
**
** DESCRIPTION: Sets up a context to draw into a pixmap. Assumes that
** it has the depth and screen of the drawing area and uses
** the default color cube and gray ramp. Puts the origin in the
** lower left corner of the pixmap
**
** PARAMETERS: d Drawable (pixmap)
** height Height of pixmap
**
** RETURN: None
**
*************************************************************/
static void setDrawingParameters(d, height)
Drawable d;
int height;
{
(void) XDPSSetContextParameters(AppData.imageCtxt,
XtScreen(AppData.drawingArea), AppData.depth, d, height,
(XDPSStandardColormap *) NULL, (XDPSStandardColormap *) NULL,
XDPSContextAll);
} /* end setDrawingParameters() */
/*************************************************************
**
** FUNCTION: setMaskParameters
**
** DESCRIPTION: Sets up a context to draw into a mask bitmap. Assumes that
** it has depth 1 and the screen of the drawing area. Sets
** a mask transfer and puts the origin in the
** lower left corner of the bitmap
**
** PARAMETERS: d Drawable (bitmap)
** height Height of bitmap
**
** RETURN: None
**
*************************************************************/
static void setMaskParameters(d, height)
Drawable d;
int height;
{
XDPSStandardColormap maskMap;
XDPSStandardColormap rgbMap;
/*
** Drawing is with a gray ramp that has black = 1, white = 0
*/
maskMap.colormap = None;
maskMap.red_max = 1;
maskMap.red_mult = -1;
maskMap.base_pixel = 1;
/*
** No color map, just draw in black and white
*/
rgbMap.colormap = None;
rgbMap.red_max = rgbMap.green_max = rgbMap.blue_max =
rgbMap.red_mult = rgbMap.green_mult = rgbMap.blue_mult =
rgbMap.base_pixel = 0;
(void) XDPSSetContextParameters(AppData.imageCtxt,
XtScreen(AppData.drawingArea), 1,
d, height, &rgbMap, &maskMap,
XDPSContextAll);
/*
** Set transfer functions to that any color comes out as black
*/
PSWSetMaskTransfer(AppData.imageCtxt);
} /* end setMaskParameters() */
/*************************************************************
**
** FUNCTION: setEPSIBitmapParameters
**
** DESCRIPTION: Sets up a context to draw into a preview bitmap. Assumes
** that it has depth 1 and the screen of the drawing area.
** Puts the origin in the lower left corner of the bitmap
**
** PARAMETERS: d Drawable (bitmap)
** height Height of bitmap
**
** RETURN: None
**
*************************************************************/
void setEPSIBitmapParameters(d, height)
Drawable d;
int height;
{
XDPSStandardColormap grayMap;
XDPSStandardColormap rgbMap;
/*
** Set gray ramp so that black = 1, white = 0
*/
grayMap.colormap = None;
grayMap.red_max = 1;
grayMap.red_mult = -1;
grayMap.base_pixel = 1;
/*
** No color map, just draw in black and white
*/
rgbMap.colormap = None;
rgbMap.red_max = rgbMap.green_max = rgbMap.blue_max =
rgbMap.red_mult = rgbMap.green_mult = rgbMap.blue_mult =
rgbMap.base_pixel = 0;
(void) XDPSSetContextParameters(AppData.imageCtxt,
XtScreen(AppData.drawingArea), 1,
d, height, &rgbMap, &grayMap,
XDPSContextAll);
} /* end setEPSIBitmapParameters() */
/*************************************************************
**
** FUNCTION: setEPSIPixmapParameters
**
** DESCRIPTION: Sets up a context to draw into a preview pixmap. Assumes
** that it has depth 8 and the screen of the drawing area.
** Puts the origin in the lower left corner of the bitmap
**
** PARAMETERS: d Drawable (pixmap)
** height Height of pixmap
**
** RETURN: None
**
*************************************************************/
void setEPSIPixmapParameters(d, height)
Drawable d;
int height;
{
XDPSStandardColormap grayMap;
XDPSStandardColormap rgbMap;
/*
** Set gray ramp with black = 255, white = 0, and 255 values in between
*/
grayMap.colormap = None;
grayMap.red_max = 255;
grayMap.red_mult = -1;
grayMap.base_pixel = 255;
/*
** No color map, just draw in shades of gray
*/
rgbMap.colormap = None;
rgbMap.red_max = rgbMap.green_max = rgbMap.blue_max =
rgbMap.red_mult = rgbMap.green_mult = rgbMap.blue_mult =
rgbMap.base_pixel = 0;
(void) XDPSSetContextParameters(AppData.imageCtxt,
XtScreen(AppData.drawingArea), 8,
d, height, &rgbMap, &grayMap,
XDPSContextAll);
} /* end setEPSIPixmapParameters() */
/*************************************************************
**
** FUNCTION: calculatePositionParameters
**
** DESCRIPTION: Compute scale, translation, and rotation values
** for a newly added element.
**
** PARAMETERS: e Element being added
**
** RETURN: None
**
*************************************************************/
static void calculatePositionParameters(e)
Element *e;
{
Point pt;
XPoint xpt;
int width, height;
/*
** Compute size of picture in user space
*/
width = e->origBBox.ur.x - e->origBBox.ll.x;
height = e->origBBox.ur.y - e->origBBox.ll.y;
/*
** Compute scale by dividing size of X bounding box by size of user space
** bounding box and converting from user space to X units
*/
e->sx = (float) e->xBBox.width *
(PAGE_WIDTH / (float) AppData.scaledWidth) / (float) width;
e->sy = (float) e->xBBox.height *
(PAGE_HEIGHT / (float) AppData.scaledHeight) / (float) height;
/*
** Compute translation by taking origin of bounding box and converting
** into user space. This gives the translation relative to the window,
** so factor in the window origin to obtain the translation in the page
*/
xpt.x = e->sizeBox.x + AppData.originX;
xpt.y = e->sizeBox.y - AppData.scaledHeight + AppData.originY;
convertToDPS(&xpt, &pt);
e->tx = pt.x;
e->ty = pt.y;
xpt.x = AppData.originX;
xpt.y = AppData.originY;
convertToDPS(&xpt, &pt);
e->tx -= pt.x;
e->ty -= pt.y;
e->rotation = 0;
} /* end calculatePositionParameters() */
/*************************************************************
**
** FUNCTION: imageToPixmap
**
** DESCRIPTION: Renders into the image and mask pixmaps in an element
**
** PARAMETERS: e Element to render
**
** RETURN: None
**
*************************************************************/
static Boolean imageToPixmap(e)
Element *e;
{
XPoint xpt;
Point pt;
/*
** Compute the user space coordinates of the origin of the pixmap. This
** must be subtracted from the translation of the element to obtain
** the translation within the pixmap
*/
xpt.x = e->xBBox.x + AppData.originX;
xpt.y = e->xBBox.y + e->xBBox.height - AppData.scaledHeight +
AppData.originY;
convertToDPS(&xpt, &pt);
/*
** Set up context for rendering and transform the coordinate system
** for EPSF inclusion
*/
setDrawingParameters(e->image, e->xBBox.height);
PSWTransformBeforeEPSF(AppData.imageCtxt, e->tx - pt.x, e->ty - pt.y,
e->sx, e->sy, e->rotation,
-e->origBBox.ll.x, -e->origBBox.ll.y);
DPSerasepage(AppData.imageCtxt);
/*
** Execute the file using the current settings. imageFile
** will return whether there was an error. If there was no error,
** proceed to the mask rendering
*/
if (!imageFile(e)) {
DPSgsave(AppData.imageCtxt);
setMaskParameters(e->mask, e->xBBox.height);
PSWTransformBeforeEPSF(AppData.imageCtxt, e->tx - pt.x, e->ty - pt.y,
e->sx, e->sy, e->rotation,
-e->origBBox.ll.x, -e->origBBox.ll.y);
/*
** We need to make sure the mask starts out with 0's
*/
XFillRectangle(XtDisplay(AppData.drawingArea), e->mask,
AppData.bitmapgc, 0, 0,
e->xBBox.width, e->xBBox.height);
(void) imageFile(e);
DPSgrestore(AppData.imageCtxt);
return False;
} else return True;
} /* end imageToPixmap() */
/*************************************************************
**
** FUNCTION: renderElement
**
** DESCRIPTION: Allocate pixmaps and render an element
**
** PARAMETERS: e Element to render
**
** RETURN: None
**
*************************************************************/
void renderElement(e)
Element *e;
{
Display *dpy = XtDisplay(AppData.drawingArea);
Window w = XtWindow(AppData.drawingArea);
/*
** Allocate image and mask pixmaps
*/
e->image = allocPixmap(dpy, w, e->xBBox.width, e->xBBox.height,
AppData.depth);
e->mask = allocPixmap(dpy, w, e->xBBox.width, e->xBBox.height, 1);
if (e->image == None) {
fprintf(stderr, "Could not allocate pixmap to hold file %s\n",
e->filename);
if (e->mask != None) {
XFreePixmap(dpy, e->mask);
e->mask = None;
}
} else if (e->mask == None) {
fprintf(stderr, "Could not allocate mask for file %s\n",
e->filename);
XFreePixmap(dpy, e->image);
e->image = None;
} else {
XDefineCursor(dpy, w, AppData.busyCursor);
XFlush(dpy);
/*
** Execute the EPS file. If unsucessful, give error and free pixmaps
*/
if (imageToPixmap(e)) {
fprintf(stderr, "PostScript language execution error in file %s\n",
e->filename);
XFreePixmap(dpy, e->image);
XFreePixmap(dpy, e->mask);
e->image = e->mask = None;
}
XDefineCursor(dpy, w, None);
}
} /* end renderElement() */
/*************************************************************
**
** FUNCTION: addElement
**
** DESCRIPTION: Add an element to the picture. Make it fit within
** the specified rectangle
**
** PARAMETERS: rect Rectangle to hold element
**
** RETURN: None
**
*************************************************************/
void addElement(rect)
XRect *rect;
{
/*
** The xBBox is the rectangle, but with the origin adjusted to be
** relative to the page. This avoids having to move it whenever we
** scroll
*/
AppData.adding->xBBox = *rect;
AppData.adding->xBBox.x -= AppData.originX;
AppData.adding->xBBox.y += AppData.scaledHeight - AppData.originY;
/*
** The sizeBox starts out the same as the xBBox, but it has its origin
** coincident with the picture origin (and thus is not a valid X
** rectangle, since the height must be negative (towards the top
** of the screen)
*/
AppData.adding->sizeBox = AppData.adding->xBBox;
AppData.adding->sizeBox.y += AppData.adding->sizeBox.height;
AppData.adding->sizeBox.height = -AppData.adding->sizeBox.height;
/*
** Compute translation, scale, and rotation based on the rectangle
*/
calculatePositionParameters(AppData.adding);
/*
** If not using boxes, render the element. If rendering was unsuccessful
** abort adding
*/
if (!AppData.useBoxes) {
renderElement(AppData.adding);
if (AppData.adding->image == None) {
freeElement(AppData.adding);
AppData.adding = NULL;
return;
}
}
/*
** Add element to the list and select it
*/
if (AppData.elements == NULL) AppData.lastElement = AppData.adding;
else AppData.elements->prev = AppData.adding;
AppData.adding->next = AppData.elements;
AppData.adding->prev = NULL;
AppData.elements = AppData.adding;
drawSelfAndUpdate(AppData.adding);
selectElement(AppData.adding);
AppData.adding = NULL;
} /* end addElement() */
/*************************************************************
**
** FUNCTION: updateElement
**
** DESCRIPTION: Update the bounding boxes of an element to reflect
** changed translation, scale, or rotation
**
** PARAMETERS: e Element to update
**
** RETURN: None
**
*************************************************************/
void updateElement(e)
Element *e;
{
Display *dpy = XtDisplay(AppData.drawingArea);
int llx, lly, urx, ury;
XPoint xpt1, xpt2;
Point pt;
int width, height;
/*
** Compute the bounding box of the element and convert to X coordinates
*/
computeBBox(e, &llx, &lly, &urx, &ury);
pt.x = llx;
pt.y = lly;
convertToX(&xpt1, &pt);
pt.x = urx;
pt.y = ury;
convertToX(&xpt2, &pt);
/*
** The xBBox is exactly the same as the bounding box, but adjusted to
** be relative to the page instead of the origin
*/
e->xBBox.x = xpt1.x - AppData.originX;
e->xBBox.y = xpt2.y + AppData.scaledHeight - AppData.originY;
e->xBBox.width = xpt2.x - xpt1.x;
e->xBBox.height = xpt1.y - xpt2.y;
/*
** The origin of sizeBox is the same as the origin of the picture
** (i.e. the translation of the picture)
*/
pt.x = e->tx;
pt.y = e->ty;
convertToX(&xpt1, &pt);
e->sizeBox.x = xpt1.x - AppData.originX;
e->sizeBox.y = xpt1.y + AppData.scaledHeight - AppData.originY;
/*
** The size of sizeBox is the size of the picture, scaled and converted
** to X coordinates
*/
width = e->origBBox.ur.x - e->origBBox.ll.x;
height = e->origBBox.ur.y - e->origBBox.ll.y;
e->sizeBox.width = width * e->sx *
((float) AppData.scaledWidth / PAGE_WIDTH);
e->sizeBox.height = -height * e->sy *
((float) AppData.scaledHeight / PAGE_HEIGHT);
/*
** Free old pixmaps and re-render using new values
*/
if (e->image != None) XFreePixmap(dpy, e->image);
if (e->mask != None) XFreePixmap(dpy, e->mask);
e->image = e->mask = None;
if (!AppData.useBoxes) renderElement(e);
} /* end updateElement() */
/*************************************************************
**
** FUNCTION: computeXrect
**
** DESCRIPTION: Compute the X rectangle necessary to hold the element.
** Assumes the scale is (1,1) and the rotation 0
**
** PARAMETERS: e Element to compute
**
** RETURN: rect Size of element
**
*************************************************************/
static void computeXrect(e, rect)
Element *e;
XRect *rect;
{
XPoint xpt;
Point pt;
/*
** The origin of the rectangle is the lower left corner
*/
pt.x = e->origBBox.ll.x;
pt.y = e->origBBox.ll.y;
convertToX(&xpt, &pt);
rect->x = xpt.x;
rect->y = xpt.y;
/*
** Convert the upper right corner and subtract to get the size
** Negate the height to account for X coordinate direction and move
** the origin up to the upper right corner
*/
pt.x = e->origBBox.ur.x;
pt.y = e->origBBox.ur.y;
convertToX(&xpt, &pt);
rect->width = xpt.x - rect->x;
rect->height = rect->y - xpt.y;
rect->y -= rect->height;
} /* end computeXrect() */
/*************************************************************
**
** FUNCTION: copyToFile
**
** DESCRIPTION: Copy a string into a temporary file
**
** PARAMETERS: buf String to copy
** len Length of buffer
** filename Buffer to hold file name
**
** RETURN: Whether copy was successful
**
*************************************************************/
static Boolean copyToFile(buf, len, filename)
char *buf;
unsigned long len;
char *filename;
{
static int suffix = 0;
static int pid;
FILE *f;
/*
** Construct a unique file name based on the proccess id
*/
if (suffix == 0) pid = (int) getpid();
sprintf(filename, "/tmp/import-%d-%d", pid, suffix);
suffix++;
/*
** Open file and write buffer
*/
f = fopen(filename, "w");
if (f == NULL) {
fprintf(stderr, "Couldn't create temporary file to hold selection.\n");
XtFree(buf);
return True;
}
if (fwrite(buf, 1, len-1, f) != len-1) {
fprintf(stderr, "Couldn't write selection to temporary file.\n");
XtFree(buf);
fclose(f);
return True;
}
fclose(f);
XtFree(buf);
return False;
} /* end copyToFile() */
/*************************************************************
**
** FUNCTION: pasteEPS
**
** DESCRIPTION: Paste an EPS buffer into the picture. Copy it into
** a temporary file then add the file
**
** PARAMETERS: buf String containing EPS description
** len Length of string
**
** RETURN: None
**
*************************************************************/
void pasteEPS(buf, len)
char *buf;
unsigned long len;
{
char filenamebuf[20];
FILE *f;
Element *e;
struct stat sbuf;
XRect rect;
/*
** Copy buffer to a temporary file
*/
if (copyToFile(buf, len, filenamebuf)) return;
/*
** Reopen file and unlink it so it will go away when the application
** exits
*/
f = fopen(filenamebuf, "r");
if (f == NULL) {
fprintf(stderr, "Couldn't reopen temporary file with selection.\n");
return;
}
unlink(filenamebuf);
/*
** Add file just like any other
*/
if (AppData.adding != NULL) {
e = AppData.adding;
XtFree(e->filename);
freeResourceList(e->resources);
fclose(e->f);
} else {
e = XtNew(Element);
e->tx = e->ty = e->sx = e->sy = e->rotation = 0.0;
e->origBBox.ll.x = e->origBBox.ll.y =
e->origBBox.ur.x = e->origBBox.ur.y = 0.0;
}
(void) fstat(fileno(f), &sbuf);
e->filename = XtNewString(filenamebuf);
e->length = sbuf.st_size;
e->f = f;
e->image = e->mask = None;
e->next = NULL;
e->resources = NULL;
if (parseFileHeader(e)) {
AppData.adding = e;
} else {
XtFree(e->filename);
fclose(e->f);
XtFree((XtPointer) e);
AppData.adding = NULL;
return;
}
if (AppData.selected != NULL) unselect();
computeXrect(e, &rect);
addElement(&rect);
} /* end pasteEPS() */
/*************************************************************
**
** FUNCTION: selectElement
**
** DESCRIPTION: Draw selection marks around an element
**
** PARAMETERS: e Element to select
**
** RETURN: None
**
*************************************************************/
void selectElement(e)
Element *e;
{
if (AppData.selected == e) return;
if (AppData.selected != NULL) unselect();
AppData.selected = e;
drawSelectionMarks();
} /* end selectElement() */
/*************************************************************
**
** FUNCTION: unselect
**
** DESCRIPTION: Unselects an element and updates the display
** to erase selection marks
**
** PARAMETERS: None
**
** RETURN: None
**
*************************************************************/
void unselect()
{
if (AppData.selected == NULL) return;
AppData.selected = NULL;
XCopyArea(XtDisplay(AppData.drawingArea), AppData.original,
XtWindow(AppData.drawingArea), AppData.gc, 0, 0,
AppData.drawingWidth, AppData.drawingHeight, 0, 0);
} /* end unselect() */
/*************************************************************
**
** FUNCTION: freeElement
**
** DESCRIPTION: Free the storage used in an element structure
**
** PARAMETERS: e Element to free
**
** RETURN: None
**
*************************************************************/
void freeElement(e)
Element *e;
{
Display *dpy = XtDisplay(AppData.drawingArea);
XtFree(e->filename);
fclose(e->f);
if (e->image != None) XFreePixmap(dpy, e->image);
if (e->mask != None) XFreePixmap(dpy, e->mask);
XtFree((XtPointer) e);
} /* end freeElement() */
/*************************************************************
**
** FUNCTION: pointInElement
**
** DESCRIPTION: Determines whether a point is within an element
**
** PARAMETERS: xpt X coordinates of point
** e Element to test
**
** RETURN: None
**
*************************************************************/
Boolean pointInElement(xpt, e)
XPoint *xpt;
Element *e;
{
int x, y;
float r, theta;
int minx, miny, maxx, maxy;
/*
** If not within the bounding box, cannot be within the element
*/
if (xpt->x < e->xBBox.x || xpt->x > e->xBBox.x + e->xBBox.width ||
xpt->y < e->xBBox.y ||
xpt->y > e->xBBox.y + e->xBBox.height) return False;
/*
** If the rotation is 0, the xBBox is the true bounding box, so
** nothing more to test.
*/
if (e->rotation == 0.0) return True;
/*
** If we're at the origin, we're in.
*/
if (xpt->x == e->sizeBox.x && xpt->y == e->sizeBox.y) return True;
/*
** Rotate the point around the sizeBox origing by the element's rotation
*/
x = xpt->x - e->sizeBox.x;
y = xpt->y - e->sizeBox.y;
r = sqrt((float) (x * x + y * y));
theta = atan2((float) y, (float) x) + DTOR(e->rotation);
x = r * cos(theta) + e->sizeBox.x;
y = r * sin(theta) + e->sizeBox.y;
/*
** See whether the rotated point is within the sizeBox
*/
minx = MIN(e->sizeBox.x, e->sizeBox.x + e->sizeBox.width);
maxx = MAX(e->sizeBox.x, e->sizeBox.x + e->sizeBox.width);
miny = MIN(e->sizeBox.y, e->sizeBox.y + e->sizeBox.height);
maxy = MAX(e->sizeBox.y, e->sizeBox.y + e->sizeBox.height);
return (x >= minx && x <= maxx && y >= miny && y <= maxy);
} /* end pointInElement() */
These are the contents of the former NiCE NeXT User Group NeXTSTEP/OpenStep software archive, currently hosted by Netfuture.ch.