Retired Document
Important: This sample code may not represent best practices for current development. The project may use deprecated symbols and illustrate technologies and techniques that are no longer recommended.
GXFile.c
/* |
File: GXFile.c |
Contains: GX print file support for simple text application. |
Version: SimpleText 1.4 or later |
** Copyright 1993-1996 Apple Computer. All rights reserved. |
** |
** You may incorporate this sample code into your applications without |
** restriction, though the sample code has been provided "AS IS" and the |
** responsibility for its operation is 100% yours. However, what you are |
** not permitted to do is to redistribute the source as "DSC Sample Code" |
** after having made changes. If you're going to re-distribute the source, |
** we require that you make it clear in the source that the code was |
** descended from Apple Sample Code, but that you've made changes. |
*/ |
#include "MacIncludes.h" |
#include "GXFile.h" |
#pragma segment GXFile |
// -------------------------------------------------------------------------------------------------------------- |
// PRIVATE TYPEDEFS AND DECLARES |
// -------------------------------------------------------------------------------------------------------------- |
// items to the left of the horizontal scroll bar |
#define kScrollAreaWidth 120 |
#define kPageControlsWidth 32 |
#define kZoomControlsWidth 26 |
#define kToolControlWidth 16 |
// items in the pop up page selection window |
#define kPageSliderHeight 10 |
#define kPageSliderMargins 7 |
#define kPageThumbEdge 4 |
#define kPageThumbHeight (kPageSliderHeight + kPageThumbEdge*2) |
#define kPageThumbWidth (kPageThumbHeight / 2) |
#define kPageThumbMargins 3 |
#define kProxyHeight 150 |
#define kProxyWidth 150 |
#define kPopUpWindowHeightSmall (kPageThumbHeight + kPageSliderMargins*2 + kPageThumbEdge*2) |
#define kPopUpWindowHeightLarge (kPageThumbHeight + kPageSliderMargins*3 + kPageThumbEdge*2 + kProxyHeight) |
#define kMinGXDocSize kMinDocSize |
// PICT proxies for the pages |
#define kProxyBaseID (gxPrintingTagID) |
#define kProxyType 'prxy' |
// flattened GX shapes for annotations |
#define kAnnotationBaseID (gxPrintingTagID) |
#define kAnnotationType 'anot' |
// table of pop up menu items and corosponding zoom factors |
typedef struct |
{ |
short menuItem; |
Fixed zoomFactor; |
} ZoomTableEntry; |
typedef struct |
{ |
short theFont; |
short theSize; |
} TextState; |
typedef struct |
{ |
gxSpoolBlock spool; |
long reference; |
long position; |
long size; |
void *data; |
void *userField; |
} userSpool; |
#define LONGALIGN(n) (((n) + 3) & ~3L) |
#define kAtomHeaderSize (sizeof(Size) + sizeof(OSType)) |
#define ABS(n) (((n) < 0) ? -(n) : (n)) |
#if GENERATINGCFM |
extern pascal OSErr SetImageDescriptionExtension(ImageDescriptionHandle desc, Handle extension, long idType); |
#endif |
// -------------------------------------------------------------------------------------------------------------- |
// FORWARD DECLARES |
// -------------------------------------------------------------------------------------------------------------- |
OSErr GXGetDocumentRect(WindowRef pWindow, WindowDataPtr pData, |
LongRect * documentRectangle, Boolean forGrow); |
OSErr GXCommand(WindowRef pWindow, WindowDataPtr pData, short commandID, long menuResult); |
// -------------------------------------------------------------------------------------------------------------- |
// LOCAL GLOBALS |
// -------------------------------------------------------------------------------------------------------------- |
static ZoomTableEntry gZoomTable[] = { |
{i50, 0x8000}, |
{i100, ff(1)}, |
{i112, 0x00011EB8}, |
{i150, 0x00018000}, |
{i200, ff(2)}, |
{i400, ff(4)}, |
{0,0}}; |
// -------------------------------------------------------------------------------------------------------------- |
// PRIVATE ROUTINES |
// -------------------------------------------------------------------------------------------------------------- |
static void GetCurrentPageAndPaper(WindowDataPtr pData, gxRectangle *pPageSize, gxRectangle *pPaperSize) |
{ |
GXGetFormatDimensions( ((GXDataPtr)pData)->currentPageFormat, pPageSize, pPaperSize); |
if (((GXDataPtr)pData)->dontShowMargins) |
*pPaperSize = *pPageSize; |
} // GetCurrentPageAndPaper |
// ------------------------------------------------------------------------------------------------------ |
static void InitColorMatrix(Fixed m[5][4]) |
{ |
register Fixed *x; |
register short i; |
x = &m[0][0]; |
for(i = 19; i>=0; i--) |
*x++ = 0; |
m[0][0] = m[1][1] = m[2][2] = m[3][3] = fixed1; /* Identity matrix, for cleanliness */ |
} // InitColorMatrix |
// -------------------------------------------------------------------------------------------------------------- |
static void RectangleToRect(const gxRectangle* gxr, Rect* qdr) |
{ |
qdr->left = FixedRound(gxr->left); |
qdr->top = FixedRound(gxr->top); |
qdr->right = FixedRound(gxr->right); |
qdr->bottom = FixedRound(gxr->bottom); |
} // RectangleToRect |
// -------------------------------------------------------------------------------------------------------------- |
#define allocationIncrement 1024 /* the storage handle is grown by this amount */ |
static long HandleSpoolProc(gxSpoolCommand command, userSpool *block) |
{ |
gxGraphicsError anErr = noErr; |
switch (command) |
{ |
case gxOpenReadSpool: |
block->size = 0; |
block->position = 0; |
break; |
case gxOpenWriteSpool: |
block->data = NewHandle(allocationIncrement); |
block->size = allocationIncrement; |
block->position = 0; |
anErr = MemError(); |
break; |
case gxReadSpool: |
BlockMoveData((*(char **) block->data) + block->position, block->spool.buffer, block->spool.count); |
block->position += block->spool.count; |
break; |
case gxWriteSpool: |
{ |
register long oldPosition; |
oldPosition = block->position; |
block->position += block->spool.count; |
/* make sure there is at least enough room for one buffer size past current pointer */ |
if (block->position + block->spool.bufferSize > block->size) |
{ |
block->size += block->spool.bufferSize; |
HUnlock((Handle) block->data); |
SetHandleSize((Handle) block->data, block->size); |
anErr = MemError(); |
HLock((Handle) block->data); |
} |
if (anErr == noErr) |
BlockMoveData(block->spool.buffer, (*(char **) block->data + oldPosition), block->spool.count); |
} |
break; |
case gxCloseSpool: |
SetHandleSize((Handle) block->data, block->position); |
break; |
} |
return anErr; |
} // HandleSpoolProc |
#if GENERATINGCFM |
static RoutineDescriptor gHandleSpoolProcRD = BUILD_ROUTINE_DESCRIPTOR(uppgxSpoolProcInfo, HandleSpoolProc); |
static gxSpoolUPP gHandleSpoolProc = &gHandleSpoolProcRD; |
#else |
static gxSpoolUPP gHandleSpoolProc = NewgxSpoolProc(HandleSpoolProc); |
#endif |
// -------------------------------------------------------------------------------------------------------------- |
static long* AppendAtom(long stream[], Size size, OSType tag, const void* data) |
{ |
*stream++ = size + kAtomHeaderSize; |
*stream++ = tag; |
BlockMoveData(data, (Ptr)stream, size); |
return (long*)((char*)stream + size); |
} // AppendAtom |
// -------------------------------------------------------------------------------------------------------------- |
static Handle CreateQDGXStream(gxShape source, PicHandle proxie, Boolean forPrintingOnly, Boolean eraseBackground) |
/* |
* See the comment on DecompressShape for an explaination of the parameters. |
* This routine is used by both DecompressShape for embedding shapes in PICTs, |
* and AddQDGXRecorderFrame for making gx movies. |
*/ |
{ |
#define gxForPrintingOnlyAtom 'fpto' |
#define gxEraseBackgroundAtom 'erbg' |
long atomCount, shapeSize, proxieSize, dataSize, fontListSize; |
Handle dataHdl, shapeHdl; |
gxFlatFontList* fontList; |
gxTag fontListTag; |
userSpool block; |
block.spool.spoolProcedure = gHandleSpoolProc; |
block.spool.buffer = nil; |
block.spool.bufferSize = 0; |
GXFlattenShape(source, gxFontListFlatten | gxFontGlyphsFlatten | gxFontVariationsFlatten, &block.spool); |
shapeHdl = (Handle) block.data; |
if (shapeHdl == nil) |
return nil; |
if (proxie) |
{ |
atomCount = 2; |
proxieSize = LONGALIGN(GetHandleSize((Handle)proxie)); |
} |
else |
{ |
atomCount = 1; |
proxieSize = 0; |
} |
shapeSize = LONGALIGN(GetHandleSize(shapeHdl)); |
if (forPrintingOnly) |
++atomCount; |
if (eraseBackground) |
++atomCount; |
fontListSize = 0; |
fontList = nil; |
GXIgnoreGraphicsWarning(count_out_of_range); |
if (GXGetShapeTags(source, gxFlatFontListItemTag, 1, 1, &fontListTag) > 0) |
{ |
fontListSize = GXGetTag(fontListTag, nil, nil); |
if (fontListSize > 0) |
{ |
fontList = (gxFlatFontList*)NewPtr(fontListSize); |
if (fontList != nil) |
{ |
GXGetTag(fontListTag, nil, fontList); |
fontListSize = LONGALIGN(fontListSize); |
++atomCount; |
} |
else |
fontListSize = 0; |
} |
} |
GXPopGraphicsWarning(); // count_out_of_range |
dataSize = atomCount * kAtomHeaderSize + shapeSize + proxieSize + fontListSize + sizeof(long); |
dataHdl = NewHandle(dataSize); |
if (dataHdl == nil) |
{ |
DisposeHandle(shapeHdl); |
if (fontList) |
DisposePtr((Ptr)fontList); |
return nil; |
} |
{ |
long* p = (long*)*dataHdl; |
if (forPrintingOnly) |
p = AppendAtom(p, 0, gxForPrintingOnlyAtom, nil); |
if (eraseBackground) |
p = AppendAtom(p, 0, gxEraseBackgroundAtom, nil); |
if (proxie) |
p = AppendAtom(p, proxieSize, 'PICT', *proxie); |
if (fontList) |
p = AppendAtom(p, fontListSize, gxFlatFontListItemTag, fontList); |
p = AppendAtom(p, shapeSize, 'qdgx', *shapeHdl); |
*p++ = 0; // end of the atom-list |
DisposeHandle(shapeHdl); |
if (fontList) |
DisposePtr((Ptr)fontList); |
} |
return dataHdl; |
} // CreateQDGXStream |
// -------------------------------------------------------------------------------------------------------------- |
static PicHandle DecompressShape(gxShape theShape, PicHandle proxie, Boolean forPrintingOnly, Boolean eraseBackground) |
/* |
* This guy returns a Quickdraw picture containing an embedded shape, and a proxie |
* of the shape, if proxie is not nil. This is called by ShapeToScrap and DragAndDropShape. |
* |
* theShape ¥ the shape you want to embedd in a PICT |
* proxie ¥ a PICT to be drawn if theShape cannot be drawn (optional but recommended) |
* forPrintingOnly ¥ if TRUE, then the decompressor will always look for the proxie |
* and theShape will only be used when printing. Use this setting if |
* theShape might be too large or too slow when drawn from other apps. |
* ¥ If FALSE, then the decompressor will draw theShape unless it |
* gets an error, in which case it will look for a proxie. |
* eraseBackground ¥ if TRUE, the decompressor will always erase the background to WHITE |
* before drawing the shape. This is slower, but needed if the shape does not |
* fill its bounding rectangle. |
* ¥ if FALSE, the decompressor will just draw the shape. Use this setting |
* if the shape entirely fills its bounding rectangle. |
* |
* The shape [and proxie] is embedded by constructing a stream of atoms. Each atom begins |
* with a size (long) and a type (OSType) and then the data for that type. After the last atom, |
* there is a trailing zero (long) to mark the end of the stream. For embedded shapes, the type |
* is 'qdgx', and for the proxie the type is 'PICT'. Note that the size fields are rounded up to |
* a multiple of 4. Finally, to alert QuickTime that the data is in this parsable form with a |
* possible PICT proxie, we add a 'prxy' extension to the ImageDescriptionHandle. |
* |
* Picture of this form will draw the embedded shape when an application calls DrawPicture |
* if GX is around, and if not, the proxie will be drawn. When printed, the shape or the proxie |
* will be printed. This is meant to replace the PicComment described in GX 1.0 for embedding |
* shapes in pictures. |
* |
* If you want to include a flatFontList tag, be sure that theShape is a picture, otherwise GX will |
* not return the tag after GXFlattenShape. The flatFontList tag makes certain printing conditions |
* more efficient (i.e. font downloading to postscript printers). |
* |
* Your shape must not contain a gxQuickDrawPictTag, meaning it contains embedded QD data, becuase |
* this will potentially crash when it tries to print. To fix that, DecompressShape looks for occurrances |
* of the tag, and converts them to real gx data by calling GXSetShapeType(shape, gxPictureType). |
*/ |
{ |
PicHandle thePicture; |
ImageDescriptionHandle descHdl; |
ImageDescriptionPtr descPtr; |
Handle dataHdl; |
if (!gMachineInfo.haveQuickTime) |
return nil; |
/* |
* Move the shape's topLeft to 0,0 so that it draws neatly inside the picture frame. |
* Note that the qdgx movie library does not move the shape, since the shape may not |
* take up the whole frame. |
*/ |
{ |
gxRectangle bounds; |
GXGetShapeLocalBounds(theShape, &bounds); |
if (bounds.left || bounds.top) |
GXMoveShape(theShape, -bounds.left, -bounds.top); |
dataHdl = CreateQDGXStream(theShape, proxie, forPrintingOnly, eraseBackground); |
if (bounds.left || bounds.top) |
GXMoveShape(theShape, bounds.left, bounds.top); |
} |
if (dataHdl == nil) |
return nil; |
descHdl = (ImageDescriptionHandle)NewHandleClear(sizeof(ImageDescription)); |
if (descHdl) |
{ |
Rect shortBounds; |
gxRectangle bounds; |
GXGetShapeLocalBounds(theShape, &bounds); |
RectangleToRect(&bounds, &shortBounds); |
OffsetRect(&shortBounds, -shortBounds.left, -shortBounds.top); // set the topLeft of the src to 0,0 |
thePicture = OpenPicture(&shortBounds); |
descPtr = *descHdl; |
descPtr->idSize = sizeof(ImageDescription); |
descPtr->cType = 'qdgx'; |
descPtr->vendor = 'appl'; |
descPtr->temporalQuality = codecLosslessQuality; |
descPtr->width = shortBounds.right; |
descPtr->height = shortBounds.bottom; |
descPtr->hRes = descPtr->vRes = ff(72); |
descPtr->dataSize = GetHandleSize(dataHdl); |
descPtr->frameCount = 1; |
descPtr->depth = 32; |
descPtr->clutID = -1; |
// If there is a PICT proxie, add an image extension to tell QuickTime, in case GX is not around. |
if (proxie) |
{ |
Handle prxyVersionHdl = NewHandle(sizeof(long)); |
if (prxyVersionHdl != nil) |
{ |
*(long*)*prxyVersionHdl = 0; // version number for 'prxy' extension |
#if GENERATINGCFM |
SetImageDescriptionExtension(descHdl, prxyVersionHdl, 'prxy'); |
#else |
AddImageDescriptionExtension(descHdl, prxyVersionHdl, 'prxy'); |
#endif |
} |
} |
HLock(dataHdl); |
DecompressImage(*dataHdl, descHdl, ((CGrafPtr)qd.thePort)->portPixMap, &shortBounds, &shortBounds, srcCopy, nil); |
DisposeHandle((Handle)descHdl); |
ClosePicture(); |
} |
else |
thePicture = nil; |
DisposeHandle(dataHdl); |
return thePicture; |
} // DecompressShape |
// -------------------------------------------------------------------------------------------------------------- |
static PicHandle ShapeToPICT(gxShape source) |
/* |
* This guy returns a Quickdraw picture containing a 1-bit bitmap of the shape. |
* This is used by ShapeToScrap to create a proxie when calling DecompressShape. |
* If you want to make the proxie prettier (and larger), change the bitmap to 8-bit. |
* However, if you're using this in conjunction with DecompressShape to place a |
* gxShape on the clipboard, 1-bit should be enough, since the actual shape will be |
* drawn, rather than the proxie (unless forPrintingOnly is true). |
*/ |
{ |
gxRectangle bounds; |
gxShape bitShape; |
gxBitmap bitmap; |
PicHandle thePicture; |
Rect shortBounds; |
/* |
* GetShapeLocalBounds doesn't accurately report the bounds of a gxQuickDrawPictTag. |
* but we should have none of them at this point anyway. |
*/ |
GXGetShapeLocalBounds(source, &bounds); |
RectangleToRect(&bounds, &shortBounds); |
OffsetRect(&shortBounds, -shortBounds.left, -shortBounds.top); |
bitmap.width = shortBounds.right; |
bitmap.height = shortBounds.bottom; |
bitmap.rowBytes = bitmap.width + 31 >> 5 << 2; |
bitmap.pixelSize = 1; |
bitmap.space = gxIndexedSpace; |
bitmap.set = nil; |
bitmap.profile = nil; |
bitmap.image = NewPtrClear(bitmap.rowBytes * bitmap.height); |
if (bitmap.image == nil) |
return nil; |
bitShape = GXNewBitmap(&bitmap, nil); |
if (bitShape != nil) |
{ |
gxViewGroup group = GXNewViewGroup(); |
gxViewDevice device = GXNewViewDevice(group, bitShape); |
gxViewPort port = GXNewViewPort(group); |
gxTransform trans = GXCloneTransform(GXGetShapeTransform(source)); |
GXSetShapeAttributes(source, GXGetShapeAttributes(source) | gxMapTransformShape); |
GXMoveShape(source, -bounds.left, -bounds.top); |
GXSetViewPortDither(port, 4); |
GXSetShapeViewPorts(source, 1, &port); |
GXDrawShape(source); |
GXSetShapeTransform(source, trans); |
GXDisposeTransform(trans); |
GXDisposeViewGroup(group); /* this disposes the gxViewPort and gxViewDevice */ |
GXDisposeShape(bitShape); |
} |
{ |
GrafPtr thePort; |
BitMap srcBits; |
GetPort(&thePort); |
srcBits.baseAddr = bitmap.image; |
srcBits.rowBytes = bitmap.rowBytes; |
srcBits.bounds = shortBounds; |
thePicture = OpenPicture(&shortBounds); |
CopyBits(&srcBits, &thePort->portBits, &shortBounds, &shortBounds, srcOr, nil); |
ClosePicture(); |
} |
DisposePtr((Ptr)bitmap.image); |
return thePicture; |
} // ShapeToPICT |
// -------------------------------------------------------------------------------------------------------------- |
static void GetRidOfAnyQDShapeTags(gxShape shape) |
{ |
gxShapeType shapeType = GXGetShapeType(shape); |
if (shapeType == gxPictureType) |
{ |
long index, count; |
gxShape contentShape; |
count = GXGetPicture(shape, nil, nil, nil, nil); |
for (index = 0; index < count; index++) |
{ |
GXGetPictureParts(shape, index+1, 1, &contentShape, nil, nil, nil); |
GetRidOfAnyQDShapeTags(contentShape); |
} |
} |
else |
{ |
if ( (shapeType == gxRectangleType) && (GXGetShapeTags(shape, gxQuickDrawPictTag, 1, gxSelectToEnd, nil) > 0) ) |
GXSetShapeType(shape, gxPictureType); |
} |
} // GetRidOfAnyQDShapeTags |
// -------------------------------------------------------------------------------------------------------------- |
static void ShapeToScrap(gxShape source) |
/* |
* This guy puts a Quickdraw picture on the clipboard containing an embedded shape |
* and, if addProxie is true, a 1-bit bitmap of the shape. Call this in response to |
* the user choosing "Copy" or "Cut" from the Edit menu. See comment for DecompressShape |
* to explain forPrintingOnly. |
*/ |
{ |
PicHandle picture, proxy; |
proxy = ShapeToPICT(source); |
picture = DecompressShape(source, proxy, false, true); |
if (proxy) |
KillPicture(proxy); |
if (picture) |
{ |
HLock((Handle)picture); |
ZeroScrap(); |
PutScrap(GetHandleSize((Handle)picture), 'PICT', (Ptr)*picture); |
KillPicture(picture); |
} |
} // ShapeToScrap |
// -------------------------------------------------------------------------------------------------------------- |
static void CullShape(gxShape shape, gxShape addToThis, gxRectangle *pCullRect, gxStyle cullStyle, gxInk cullInk, gxTransform cullTransform) |
/* |
Add to "addToThis" the "shape", only if the shape intersects the pCullRect. |
*/ |
{ |
gxShapeType shapeType = GXGetShapeType(shape); |
if (shapeType == gxPictureType) |
{ |
long index, count; |
gxShape contentShape; |
count = GXGetPicture(shape, nil, nil, nil, nil); |
for (index = 0; index < count; index++) |
{ |
GXGetPictureParts(shape, index+1, 1, &contentShape, &cullStyle, &cullInk, &cullTransform); |
CullShape(contentShape, addToThis, pCullRect, cullStyle, cullInk, cullTransform); |
} |
} |
else |
{ |
gxRectangle bounds; |
GXGetShapeLocalBounds(shape, &bounds); |
if (IsSomewhereInRectangle(pCullRect, &bounds)) |
{ |
if ( (shapeType == gxRectangleType) && (GXGetShapeTags(shape, gxQuickDrawPictTag, 1, gxSelectToEnd, nil) > 0) ) |
{ |
// convert shape and add -- but only if it goes okay |
GXSetShapeType(shape, gxPictureType); |
if (GXGetShapeType(shape) == gxPictureType) |
CullShape(shape, addToThis, pCullRect, cullStyle, cullInk, cullTransform); |
} |
else |
{ |
GXSetPictureParts(addToThis, 0, 0, 1, &shape, &cullStyle, &cullInk, &cullTransform); |
} |
} |
} |
} // CullShape |
// -------------------------------------------------------------------------------------------------------------- |
static gxShape CullPicture(gxShape pictureShape, gxRectangle * pCullRect) |
/* |
Returns a new shape that is all of the shapes inside of pictureShape |
that intersect pCullRect. |
*/ |
{ |
gxShape newPicture = GXNewShape(gxPictureType); |
gxShape clipShape = GXNewRectangle(pCullRect); |
gxMapping mapping; |
gxRectangle clipRect; |
// new shape as same mapping as old one |
GXGetTransformMapping(GXGetShapeTransform(pictureShape), &mapping); |
GXSetShapeMapping(newPicture, &mapping); |
// clip also has the mapping, but inverted so that it's the right space |
InvertMapping(&mapping, &mapping); |
GXMapShape(clipShape, &mapping); |
GXGetShapeLocalBounds(clipShape, &clipRect); |
// clip to the selection |
GXSetShapeClip(newPicture, clipShape); |
GXDisposeShape(clipShape); |
// add all shapes that intersect the clip area |
CullShape(pictureShape, newPicture, &clipRect, nil, nil, nil); |
// new shape is zero based |
GXMoveShape(newPicture, -pCullRect->left, -pCullRect->top); |
return(newPicture); |
} // CullPicture |
// -------------------------------------------------------------------------------------------------------------- |
static gxShape GetSelectedShape(WindowDataPtr pData) |
/* |
Returns a shape that represents all shapes on the current page |
that are contained by the current selection rectangle. |
*/ |
{ |
gxRectangle cullRect; |
gxShape cullShape; |
gxPoint offset; |
Fixed zoomFactor = ((GXDataPtr)pData)->zoomFactor; |
// calculate the actual coodinate space, removing margins |
{ |
gxRectangle pageSize, paperSize; |
GetCurrentPageAndPaper(pData, &pageSize, &paperSize); |
offset.y = FixedMultiply(-paperSize.top, zoomFactor); |
offset.x = FixedMultiply(-paperSize.left, zoomFactor); |
} |
// calculate the actual coodinates to copy |
cullRect.top = FixedDivide(ff(((GXDataPtr)pData)->selectionRectangle.top) - offset.y, zoomFactor); |
cullRect.left = FixedDivide(ff(((GXDataPtr)pData)->selectionRectangle.left) - offset.x, zoomFactor); |
cullRect.bottom = FixedDivide(ff(((GXDataPtr)pData)->selectionRectangle.bottom) - offset.y, zoomFactor); |
cullRect.right = FixedDivide(ff(((GXDataPtr)pData)->selectionRectangle.right) - offset.x, zoomFactor); |
// chop the data |
cullShape = CullPicture(((GXDataPtr)pData)->currentPageShape, &cullRect); |
return(cullShape); |
} // GetSelectedShape |
// -------------------------------------------------------------------------------------------------------------- |
static pascal OSErr GXSendDataProc(FlavorType theType, void *dragSendRefCon, |
ItemReference theItem, DragReference theDrag) |
/* |
* The ItemReference is the gxShape to be sent. The dragSendRefCon is ignored. |
*/ |
{ |
#pragma unused (dragSendRefCon) |
OSErr result = noErr; |
gxShape shape = ((GXDataPtr)theItem)->tempDragShape; |
// haven't made clipped version yet? |
if (shape == nil) |
{ |
shape = GetSelectedShape((WindowDataPtr) theItem); |
((GXDataPtr)theItem)->tempDragShape = shape; |
} |
switch (theType) |
{ |
case 'qdgx': |
{ |
Handle flat; |
userSpool block; |
block.spool.spoolProcedure = gHandleSpoolProc; |
block.spool.buffer = nil; |
block.spool.bufferSize = 0; |
GXFlattenShape(shape, gxFontListFlatten | gxFontGlyphsFlatten | gxFontVariationsFlatten, &block.spool); |
flat = (Handle) block.data; |
if (flat) |
{ |
HLock(flat); |
result = SetDragItemFlavorData(theDrag, theItem, 'qdgx', *flat, GetHandleSize(flat), 0); |
DisposeHandle(flat); |
} |
} |
break; |
case 'PICT': |
{ |
PicHandle proxie = ShapeToPICT(shape); |
PicHandle pict = DecompressShape(shape, proxie, false, true); |
if (proxie) |
KillPicture(proxie); |
if (pict) |
{ |
HLock((Handle)pict); |
result = SetDragItemFlavorData(theDrag, theItem, 'PICT', (Ptr)*pict, GetHandleSize((Handle)pict), 0); |
KillPicture(pict); |
} |
} |
break; |
default: |
result = badDragFlavorErr; |
break; |
} |
return result; |
} // GXSendDataProc |
#if GENERATINGCFM |
static RoutineDescriptor gGXSendDataProcRD = BUILD_ROUTINE_DESCRIPTOR(uppDragSendDataProcInfo, GXSendDataProc); |
static DragSendDataUPP gGXSendDataProc = &gGXSendDataProcRD; |
#else |
static DragSendDataUPP gGXSendDataProc = NewDragSendDataProc(GXSendDataProc); |
#endif |
// -------------------------------------------------------------------------------------------------------------- |
static void ClearCurrentSelection(GXDataPtr pData) |
{ |
pData->currentShapeIndex = 0; |
pData->currentShapeStart = 0; |
pData->currentShapeEnd = 0; |
if (pData->currentSelectionShape) |
{ |
GXDisposeShape(pData->currentSelectionShape); |
pData->currentSelectionShape = nil; |
} |
} // ClearCurrentSelection |
// -------------------------------------------------------------------------------------------------------------- |
static OSErr GetCurrentPage(GXDataPtr pData, Boolean disposeOfSelection) |
/* |
Disposes of previously loaded page information, and loads the |
page information for the current page number. |
*/ |
{ |
OSErr anErr; |
LongRect oldRect, newRect; |
if (pData->numberOfPages != 0) |
{ |
// get rid of any previous format |
if (pData->currentPageFormat) |
{ |
GXDisposeFormat(pData->currentPageFormat); |
pData->currentPageFormat = nil; |
} |
// get rid of any previous shape |
if (pData->currentPageShape) |
{ |
GXDisposeShape(pData->currentPageShape); |
pData->currentPageShape = nil; |
} |
// get rid of selection, if desired |
if (disposeOfSelection) |
ClearCurrentSelection(pData); |
GXGetDocumentRect((WindowRef)pData, (WindowDataPtr)pData, &oldRect, false); |
GXReadPrintFilePage(pData->thePrintFile, |
pData->currentPage, |
1, &pData->childViewPort, |
&pData->currentPageFormat, &pData->currentPageShape); |
} |
anErr = GXGetJobError(pData->w.hPrint); |
if (anErr == noErr) |
{ |
GXGetDocumentRect((WindowRef)pData,(WindowDataPtr) pData, &newRect, false); |
if ( |
(oldRect.left != newRect.left) || |
(oldRect.top != newRect.top) || |
(oldRect.right != newRect.right) || |
(oldRect.bottom != newRect.bottom) |
) |
{ |
// if the resulting page is < the current window size, we need to resize, |
long newWidth = newRect.right - newRect.left + kScrollBarSize; |
long newHeight = newRect.bottom - newRect.top + kScrollBarSize; |
long oldWidth = pData->w.theWindow.port.portRect.right - pData->w.theWindow.port.portRect.left; |
long oldHeight = pData->w.theWindow.port.portRect.bottom - pData->w.theWindow.port.portRect.top; |
// but don't let it get too small! |
if (newWidth < pData->w.minHSize) |
newWidth = pData->w.minHSize; |
if (newHeight < kMinGXDocSize) |
newHeight = kMinGXDocSize; |
if ( |
(newWidth < oldWidth) || |
(newHeight < oldHeight) |
) |
{ |
if (newWidth > oldWidth) |
newWidth = oldWidth; |
if (newHeight > oldHeight) |
newHeight = oldHeight; |
SizeWindow((WindowRef)pData, newWidth, newHeight, false); |
} |
// and in any case, the scroll bars should update |
AdjustScrollBars((WindowRef)pData, true, true, nil); |
} |
} |
return(anErr); |
} // GetCurrentPage |
// -------------------------------------------------------------------------------------------------------------- |
#define charBullet '¥' |
static void GetIntlTokenChar(short whichToken, short whichScript, char *bulletString) |
// |
// GetIntlTokenChar |
// |
// This routine gets a character out of the itl4 given a script and tokenÉ |
// |
{ |
Handle itl4H; |
long offset, len; |
// default the value |
bulletString[0] = 1; |
bulletString[1] = charBullet; |
// Look up the untoken table -- bail if we canÕt get it |
GetIntlResourceTable(whichScript, iuUnTokenTable, &itl4H, &offset, &len); |
if (itl4H && (offset > 0) && (len >= 0)) |
{ |
char *sp = (*itl4H + offset); // Point to start of untoken table |
if (whichToken <= ((short *)sp)[1]) // Check if token has valid index |
{ |
sp += ((short *)sp)[2+whichToken]; // Add the string offset and voli! |
BlockMoveData(sp, bulletString, sp[0]+1); |
} |
} |
} // GetIntlTokenChar |
// -------------------------------------------------------------------------------------------------------------- |
// This code is required to change pop up menus to a different font size. It would be |
// better to use the pop up control, but it doesn't allow multiple items to be marked. |
#define SysFontSize 0xBA8 |
#define SysFontFam 0xBA6 |
#define CurFMInput 0x988 |
static void DoUseWFont(TextState *savedInfo, WindowRef owner, Boolean saveIt) |
/************************************************************* |
DoUseWFont - Sets the font mgr low mem globals so |
we can have Geneva 9 popups |
savedInfo - Fills it in if saveIt = true, else |
it sets the port to those values |
owner - Where to get the original values |
saveIt - true for save |
**************************************************************/ |
{ |
TextState myState, |
*theState; |
short aFont; |
theState = savedInfo; |
if (saveIt) |
{ |
savedInfo->theFont = GetSysFont(); // save low memory globals |
savedInfo->theSize = *((short *) SysFontSize); |
myState.theFont = GetWindowPort(owner)->txFont; |
myState.theSize = GetWindowPort(owner)->txSize; |
theState = &myState; |
// if we stuff systemFont, it will screw up Script Mgr |
if (GetWindowPort(owner)->txFont == systemFont) |
goto dosizestuff; |
} |
// if we stuff applFont, this will also screw up Script Mgr |
// instead we get the actual font |
aFont = theState->theFont; |
if (saveIt) |
if (GetWindowPort(owner)->txFont == applFont) |
aFont = GetAppFont(); |
*((short *) SysFontFam) = aFont; // set/restore low memory globals |
dosizestuff: |
*((short *) SysFontSize) = theState->theSize; |
*((long *) CurFMInput) = 0xFFFFFFFF; |
} // DoUseWFont |
// -------------------------------------------------------------------------------------------------------------- |
static void SetZoom(WindowRef pWindow, WindowDataPtr pData, Fixed newZoom) |
/* |
Sets the new zoom factor for the window, causing an update for |
the window if required. |
*/ |
{ |
Fixed scaleFactor; |
// pin to max/min zoom factors |
if (newZoom > ff(32)) |
newZoom = ff(32); |
if (newZoom < 0x0800) |
newZoom = 0x0800; |
scaleFactor = FixedDivide(newZoom, ((GXDataPtr)pData)->zoomFactor); |
if (scaleFactor != ff(1)) |
{ |
gxPoint centerPoint; |
GrafPtr pPort = (GrafPtr)GetWindowPort(pWindow); |
// zoom about the window center |
centerPoint.x = ff(pPort->portRect.left + (RectWidth(pPort->portRect) >> 1)); |
centerPoint.y = ff(pPort->portRect.top + (RectHeight(pPort->portRect) >> 1)); |
// new zoom active |
((GXDataPtr)pData)->zoomFactor = newZoom; |
// force update and recalc the size of window |
InvalRect(&pPort->portRect); |
AdjustScrollBars(pWindow, true, true, nil); |
// scale scroll values |
SetControlValue(pData->hScroll, FixedToInt( FixedDivide(centerPoint.x, scaleFactor) + FixedMultiply(ff(GetControlValue(pData->hScroll)), scaleFactor) ) ); |
SetControlValue(pData->vScroll, FixedToInt( FixedDivide(centerPoint.y, scaleFactor) + FixedMultiply(ff(GetControlValue(pData->vScroll)), scaleFactor) ) ); |
// zoom the selection |
((GXDataPtr)pData)->selectionRectangle.left = FixedToInt (FixedMultiply(ff(((GXDataPtr)pData)->selectionRectangle.left), scaleFactor) ); |
((GXDataPtr)pData)->selectionRectangle.top = FixedToInt (FixedMultiply(ff(((GXDataPtr)pData)->selectionRectangle.top), scaleFactor) ); |
((GXDataPtr)pData)->selectionRectangle.right = FixedToInt (FixedMultiply(ff(((GXDataPtr)pData)->selectionRectangle.right), scaleFactor) ); |
((GXDataPtr)pData)->selectionRectangle.bottom = FixedToInt (FixedMultiply(ff(((GXDataPtr)pData)->selectionRectangle.bottom), scaleFactor) ); |
} |
} // SetZoom |
// -------------------------------------------------------------------------------------------------------------- |
static void SetShapeGreyColorLevel(gxShape thisShape, unsigned long greyLevel) |
{ |
gxColor thisColor; |
thisColor.space = gxGraySpace; |
thisColor.profile = nil; |
thisColor.element.gray = greyLevel; |
GXSetShapeColor(thisShape, &thisColor); |
} // SetShapeGreyColorLevel |
// -------------------------------------------------------------------------------------------------------------- |
static void CenterRect(Rect *source, Rect *against) |
/* |
Centers "source" within or around "against". |
*/ |
{ |
// center picture if requested |
short height, width, pheight, pwidth; |
height = (against->bottom - against->top) >> 1; |
width = (against->right - against->left) >> 1; |
pheight = (source->bottom - source->top) >> 1; |
pwidth = (source->right - source->left) >> 1; |
source->top = against->top + height - pheight; |
source->bottom = against->bottom - height + pheight; |
source->left = against->left + width - pwidth; |
source->right = against->right - width + pwidth; |
} // CenterRect |
// -------------------------------------------------------------------------------------------------------------- |
static gxShape FindNestedIndexedLayout(gxShape shape, |
long searchIndex, long * pIndex, gxMapping *pConcatMapping) |
/* |
Returns the shape represented by "searchIndex" shapes into the picture, |
sequentially, including all nestings of pictures. Uses pIndex as |
work storage, which must be initialized to zero before the call. |
Returns shape found, or NIL if the searchIndex is larger than |
the number of shapes in the picture. If NIL is returned, |
then the contents of pIndex will contain the number of |
shapes in the picture. |
*/ |
{ |
gxShape returnShape = nil; |
gxShapeType shapeType = GXGetShapeType(shape); |
// bail on negative index |
if (searchIndex < 0) |
return(nil); |
if (shapeType == gxPictureType) |
{ |
long index, count; |
gxShape contentShape; |
gxTransform contentTransform; |
gxMapping contentMapping; |
count = GXGetPicture(shape, nil, nil, nil, nil); |
for (index = 0; index < count; index++) |
{ |
GXGetPictureParts(shape, index+1, 1, &contentShape, nil, nil, &contentTransform); |
returnShape = FindNestedIndexedLayout(contentShape, searchIndex, pIndex, pConcatMapping ? &contentMapping : nil); |
if (returnShape) |
{ |
if (pConcatMapping) |
{ |
if (!contentTransform) |
contentTransform = GXGetShapeTransform(contentShape); |
GXGetTransformMapping(contentTransform, &contentMapping); |
MapMapping(&contentMapping, pConcatMapping); |
*pConcatMapping = contentMapping; |
} |
break; |
} |
} |
} |
else |
{ |
if ( (shapeType == gxLayoutType) || (shapeType == gxGlyphType) || (shapeType == gxTextType) ) |
{ |
(*pIndex)++; |
if (searchIndex == *pIndex) |
returnShape = shape; |
} |
} |
return(returnShape); |
} // FindNestedIndexedLayout |
// -------------------------------------------------------------------------------------------------------------- |
static Boolean PerformNextFind(WindowRef pWindow, WindowDataPtr pData, |
Str255 findString, |
Boolean caseSensitive, |
Boolean backwards, |
Boolean wraparound) |
{ |
Boolean foundSomething = false; |
long searchIndex, workIndex; |
gxShape aShape; |
long direction; |
long oldPageNumber = ((GXDataPtr)pData)->currentPage; |
long endPageNumber; |
Boolean firstTime = true; |
gxMapping concatMapping; |
// initialize direction of the walk |
if (backwards) |
direction = -1; |
else |
direction = 1; |
// start searching where we last left off |
searchIndex = ((GXDataPtr)pData)->currentShapeIndex; |
if (searchIndex != 0) |
searchIndex -= direction; |
if (((GXDataPtr)pData)->numberOfPages == 1) |
wraparound = false; |
// end searching on a particular page |
if (backwards) |
endPageNumber = 0; |
else |
endPageNumber = ((GXDataPtr)pData)->numberOfPages + 1; |
// can't search on qd shapes, so we get rid of them |
GetRidOfAnyQDShapeTags(((GXDataPtr)pData)->currentPageShape); |
do |
{ |
// search for the next shape or prev shape |
searchIndex += direction; |
// initialize the working index so that we know traversal level |
workIndex = 0; |
// initialize the mapping to identity |
ResetMapping(&concatMapping); |
GXGetShapeMapping(((GXDataPtr)pData)->currentPageShape, &concatMapping); |
// find the next layout in the page |
aShape = FindNestedIndexedLayout(((GXDataPtr)pData)->currentPageShape, searchIndex, &workIndex, &concatMapping); |
if (aShape) |
{ |
gxShapeType shapeType = GXGetShapeType(aShape); |
long size; |
Handle aHandle; |
// determine size and allocate storage for layout contents |
switch (shapeType) |
{ |
case gxTextType: |
size = GXGetText(aShape, nil, nil, nil); |
break; |
case gxGlyphType: |
size = GXGetGlyphs(aShape, nil, nil, nil, |
nil, nil, nil, nil, nil); |
break; |
case gxLayoutType: |
size = GXGetLayout(aShape, nil, |
nil, nil, nil, // styles |
nil, nil, nil, // levels |
nil, nil); // options/position |
break; |
} |
aHandle = NewHandle(size); |
if (aHandle) |
{ |
long newStart, newEnd; |
// grab the contents of the layout into the temp storage |
HLock(aHandle); |
switch (shapeType) |
{ |
case gxTextType: |
GXGetText(aShape, nil, (unsigned char*)*aHandle, nil); |
break; |
case gxGlyphType: |
GXGetGlyphs(aShape, nil, (unsigned char*)*aHandle, nil, |
nil, nil, nil, nil, nil); |
break; |
case gxLayoutType: |
GXGetLayout(aShape, (unsigned char*)*aHandle, |
nil, nil, nil, // styles |
nil, nil, nil, // levels |
nil, nil); // options/position |
break; |
} |
HUnlock(aHandle); |
// search the handle for the string we're looking for, |
// but don't wraparound because we handle that over layout |
// ranges and pages ourselves |
{ |
long offset; |
if ((firstTime) && (((GXDataPtr)pData)->currentSelectionShape)) |
{ |
// for shape that we have found something in before |
// start at end of last point if forwards, start of last point |
// if backwards |
firstTime = false; |
offset = backwards ? ((GXDataPtr)pData)->currentShapeStart : ((GXDataPtr)pData)->currentShapeEnd; |
} |
else |
{ |
// for "new" shape we haven't hit before, start at |
// begining for forwards, end for backwards |
offset = backwards ? size : 0; |
} |
foundSomething = PerformSearch(aHandle, offset, findString, |
caseSensitive, backwards, false, |
&newStart, &newEnd); |
} |
// done with our temp storage |
DisposeHandle(aHandle); |
// got it? then mark it and bail out |
if (foundSomething) |
{ |
// remember where we are in the page |
((GXDataPtr)pData)->currentShapeIndex = searchIndex; |
// what offsets the selection is |
((GXDataPtr)pData)->currentShapeStart = newStart; |
((GXDataPtr)pData)->currentShapeEnd = newEnd; |
// and the shape containing the selection |
if (((GXDataPtr)pData)->currentSelectionShape) |
GXDisposeShape(((GXDataPtr)pData)->currentSelectionShape); |
((GXDataPtr)pData)->currentSelectionShape = GXCloneShape(aShape); |
((GXDataPtr)pData)->currentSelectionMapping = concatMapping; |
break; |
} // found the string |
} // allocated the handle |
} // found a shape |
else |
{ |
OSErr anErr = noErr; |
// didn't find it on this page, move on |
((GXDataPtr)pData)->currentPage += direction; |
// clamp to the ends of the range |
if (backwards) |
{ |
if (((GXDataPtr)pData)->currentPage <= endPageNumber) |
{ |
if (wraparound) |
{ |
((GXDataPtr)pData)->currentPage = ((GXDataPtr)pData)->numberOfPages; |
endPageNumber = oldPageNumber; |
wraparound = false; |
} |
else |
anErr = paramErr; |
} |
} |
else |
{ |
if (((GXDataPtr)pData)->currentPage >= endPageNumber) |
{ |
if (wraparound) |
{ |
((GXDataPtr)pData)->currentPage = 1; |
endPageNumber = oldPageNumber; |
wraparound = false; |
} |
else |
anErr = paramErr; |
} |
} |
// fetch contents |
if (anErr == noErr) |
anErr = GetCurrentPage((GXDataPtr) pData, false); |
// anything wrong? then all done searching |
if (anErr != noErr) |
{ |
break; |
} |
else |
{ |
GetRidOfAnyQDShapeTags(((GXDataPtr)pData)->currentPageShape); |
if (backwards) |
{ |
workIndex = 0; |
(void) FindNestedIndexedLayout(((GXDataPtr)pData)->currentPageShape, 0x7FFFFFF, &workIndex, nil); |
searchIndex = workIndex; |
} |
else |
searchIndex = 0; |
} |
} |
} while (!foundSomething); |
// if we found something, force and update. If not, make sure |
// that the current page is restored to the page we had when |
// coming in. |
if (foundSomething) |
{ |
InvalRect(&GetWindowPort(pWindow)->portRect); |
} |
else |
{ |
if (oldPageNumber != ((GXDataPtr)pData)->currentPage) |
{ |
((GXDataPtr)pData)->currentPage = oldPageNumber; |
GetCurrentPage((GXDataPtr) pData, false); |
} |
} |
return(foundSomething); |
} // PerformNextFind |
// -------------------------------------------------------------------------------------------------------------- |
static gxShape GetCurrentSelectionHighlight(WindowDataPtr pData, Boolean mapIt) |
{ |
gxShape highlight; |
highlight = GXGetLayoutHighlight(((GXDataPtr)pData)->currentSelectionShape, |
((GXDataPtr)pData)->currentShapeStart, ((GXDataPtr)pData)->currentShapeEnd, |
gxHighlightAverageAngle, nil); |
if (mapIt) |
GXMapShape(highlight, &((GXDataPtr)pData)->currentSelectionMapping); |
// draw and dispose of the highlight |
GXSetShapeViewPorts(highlight, 1, &((GXDataPtr)pData)->childViewPort); |
GXSetShapeFill(highlight, gxClosedFrameFill); |
GXSetShapeClip(highlight, nil); |
return(highlight); |
} // GetCurrentSelectionHighlight |
// -------------------------------------------------------------------------------------------------------------- |
static void ScrollFoundShapeIntoView(WindowRef pWindow, WindowDataPtr pData) |
{ |
gxRectangle bounds; |
Point scrollAmount; |
Point controlValues; |
gxRectangle windowBounds; |
GrafPtr pPort = (GrafPtr)GetWindowPort(pWindow); |
if ( ! (((GXDataPtr)pData)->currentSelectionShape) ) |
return; |
// cache scroll state |
controlValues.h = GetControlValue(pData->hScroll); |
controlValues.v = GetControlValue(pData->vScroll); |
// calculate visible bounds of window |
windowBounds.left = ff(pPort->portRect.left + controlValues.h); |
windowBounds.right = ff(pPort->portRect.right - kScrollBarSize + controlValues.h); |
windowBounds.top = ff(pPort->portRect.top + controlValues.v); |
windowBounds.bottom = ff(pPort->portRect.bottom - kScrollBarSize + controlValues.v); |
// grab the bounds of the shape, add on the margins, scale to zoom factor |
{ |
gxRectangle pageSize, paperSize; |
gxShape highlight = GetCurrentSelectionHighlight(pData, false); |
GXGetShapeBounds(highlight, 0, &bounds); |
GXDisposeShape(highlight); |
GetCurrentPageAndPaper(pData, &pageSize, &paperSize); |
bounds.left = FixedMultiply(bounds.left - paperSize.left, ((GXDataPtr)pData)->zoomFactor); |
bounds.right = FixedMultiply(bounds.right - paperSize.left, ((GXDataPtr)pData)->zoomFactor); |
bounds.top = FixedMultiply(bounds.top - paperSize.top, ((GXDataPtr)pData)->zoomFactor); |
bounds.bottom = FixedMultiply(bounds.bottom - paperSize.top, ((GXDataPtr)pData)->zoomFactor); |
} |
if ( |
(bounds.bottom <= windowBounds.top) || |
(bounds.top >= windowBounds.bottom) || |
(bounds.right <= windowBounds.left) || |
(bounds.left >= windowBounds.right) |
) |
{ |
scrollAmount.h = controlValues.h - FixedToInt(bounds.left); |
scrollAmount.v = controlValues.v - FixedToInt(bounds.top); |
SetControlAndClipAmount(pData->hScroll, &scrollAmount.h); |
SetControlAndClipAmount(pData->vScroll, &scrollAmount.v); |
if ((scrollAmount.h) || (scrollAmount.v)) |
DoScrollContent(pWindow, pData, scrollAmount.h, scrollAmount.v); |
} |
} // ScrollFoundShapeIntoView |
// -------------------------------------------------------------------------------------------------------------- |
static Boolean TrackIn(Rect *pTrackRect, Point clickPoint, Rect *pDrawRect, short inID, short outID) |
{ |
Boolean in = false; |
if (PtInRect(clickPoint, pTrackRect)) |
{ |
in = true; |
PlotIconID(pDrawRect, ttNone, ttNone, inID); |
while (StillDown()) |
{ |
GetMouse(&clickPoint); |
if (PtInRect(clickPoint, pTrackRect)) |
{ |
if (!in) |
{ |
in = true; |
PlotIconID(pDrawRect, ttNone, ttNone, inID); |
} |
} |
else |
{ |
if (in) |
{ |
in = false; |
PlotIconID(pDrawRect, ttNone, ttNone, outID); |
} |
} |
} |
} |
return(in); |
} // TrackIn |
// -------------------------------------------------------------------------------------------------------------- |
static void DrawPageSliderAndThumb(WindowRef pWindow, long currentValue, long maxValue) |
{ |
Rect pageSliderRect; |
Rect pageThumbRect; |
long pixelValue; |
Str255 aString; |
FontInfo theInfo; |
PicHandle proxyHandle; |
Rect proxyRect; |
GrafPtr pPort = (GrafPtr)GetWindowPort(pWindow); |
// calculate location of the slider |
pageSliderRect.left = kPageSliderMargins; |
pageSliderRect.bottom = pPort->portRect.bottom - kPageSliderMargins; |
pageSliderRect.top = pageSliderRect.bottom - kPageSliderHeight; |
pageSliderRect.right = pPort->portRect.right - kPageSliderMargins; |
// then calculate the thumb within that slider |
pixelValue = (currentValue-1) |
* |
(pageSliderRect.right - pageSliderRect.left - kPageThumbMargins*2 - kPageThumbWidth) |
/ |
(maxValue-1); |
pageThumbRect.left = pageSliderRect.left + kPageThumbMargins + pixelValue; |
pageThumbRect.right = pageThumbRect.left + kPageThumbWidth; |
pageThumbRect.top = pageSliderRect.top - kPageThumbEdge; |
pageThumbRect.bottom = pageThumbRect.top + kPageThumbHeight; |
// and finally, the location to draw the proxy (if any) |
proxyRect.top = kPageSliderMargins; |
proxyRect.bottom = proxyRect.top + kProxyHeight; |
proxyRect.left = pPort->portRect.left + |
((pPort->portRect.right - pPort->portRect.left) >> 1) - |
(kProxyWidth >> 1); |
proxyRect.right = proxyRect.left + kProxyWidth; |
if (Count1Resources(kProxyType) == 0) |
proxyRect.bottom = proxyRect.top; |
// draw the slider area |
FillRect(&pageSliderRect, &qd.gray); |
FrameRect(&pageSliderRect); |
// erase areas above and below the slider (old thumb erase) |
{ |
Rect sliderEraseRect = pageSliderRect; |
ForeColor(whiteColor); |
sliderEraseRect.top = pageThumbRect.top; |
sliderEraseRect.bottom = sliderEraseRect.top + kPageThumbEdge; |
PaintRect(&sliderEraseRect); |
sliderEraseRect.bottom = pageThumbRect.bottom; |
sliderEraseRect.top = sliderEraseRect.bottom - kPageThumbEdge; |
PaintRect(&sliderEraseRect); |
} |
// draw the thumb |
ForeColor(blackColor); |
FrameRect(&pageThumbRect); |
InsetRect(&pageThumbRect, 1, 1); |
ForeColor(whiteColor); |
FrameRect(&pageThumbRect); |
InsetRect(&pageThumbRect, 1, 1); |
ForeColor(blackColor); |
FrameRect(&pageThumbRect); |
// draw page string label |
TextFace(bold); |
TextFont(applFont); |
TextSize(9); |
TextMode(srcCopy); |
GetFontInfo(&theInfo); |
MoveTo(pageSliderRect.left, pageThumbRect.top - kPageThumbEdge - theInfo.descent); |
GetIndString(aString, kPageControlStrings, iGoToPageString); |
DrawString(aString); |
NumToString(currentValue, aString); |
DrawString(aString); |
// erase any trailing digits (pretty cheezy, but seems to work) |
DrawString("\p "); |
// draw the proxy, or erase the proxy area if no picture to draw |
proxyHandle = (PicHandle) GetResource(kProxyType, kProxyBaseID + currentValue - 1); |
if (proxyHandle) |
{ |
Rect drawRect; |
Fixed scaleFactor; |
drawRect = (**proxyHandle).picFrame; |
// compute aspect ratio preserving scale |
if (RectHeight(drawRect) > RectWidth(drawRect)) |
scaleFactor = FixRatio(RectHeight(proxyRect), RectHeight(drawRect)); |
else |
scaleFactor = FixRatio(RectWidth(proxyRect), RectWidth(drawRect)); |
drawRect.bottom = drawRect.top + |
( FixMul( (RectHeight(drawRect) << 16), scaleFactor) >> 16); |
drawRect.right = drawRect.left + |
( FixMul( (RectWidth(drawRect) << 16), scaleFactor) >> 16); |
CenterRect(&drawRect, &proxyRect); |
// erase the area outside of the picture, but inside of the |
// total proxy area, because some pictures will leave whitespace on the edge |
{ |
RgnHandle rgn1 = NewRgn(); |
RgnHandle rgn2 = NewRgn(); |
RectRgn(rgn1, &proxyRect); |
RectRgn(rgn2, &drawRect); |
DiffRgn(rgn1, rgn2, rgn1); |
EraseRgn(rgn1); |
DisposeRgn(rgn1); |
DisposeRgn(rgn2); |
} |
// finally, we can draw and dispose of the picture |
DrawPicture(proxyHandle, &drawRect); |
ReleaseResource((Handle) proxyHandle); |
} |
else |
{ |
EraseRect(&proxyRect); |
} |
} // DrawPageSliderAndThumb |
// -------------------------------------------------------------------------------------------------------------- |
static OSErr DoDrawingClick(WindowRef pWindow, WindowDataPtr pData, Point clickPoint, EventRecord *pEvent) |
{ |
#pragma unused (pEvent, pWindow) |
OSErr anErr = noErr; |
Point lastPoint = clickPoint; |
Point currentPoint; |
Fixed penSize; |
gxInk newInk = GXNewInk(); |
gxStyle newStyle = GXNewStyle(); |
gxShape newShape = GXNewShape(gxPolygonType); |
long addPoly[] = {1, 1, 0, 0}; |
// set up the style for the shape |
GXSetStylePen(newStyle, ff(10)); |
// and the ink for the shape |
{ |
gxColor redColor; |
gxTransferMode mode; |
// the color |
redColor.space = gxRGBSpace; |
redColor.profile = nil; |
redColor.element.rgb.red = 0xFFFF; |
redColor.element.rgb.green = 0x0000; |
redColor.element.rgb.blue = 0x0000; |
GXSetInkColor(newInk, &redColor); |
// the transfer mode |
mode.space = gxHSVSpace; |
mode.set = nil; |
mode.profile = nil; |
InitColorMatrix(mode.sourceMatrix); |
InitColorMatrix(mode.deviceMatrix); |
InitColorMatrix(mode.resultMatrix); |
mode.flags = 0; |
mode.component[0].mode = gxCopyMode; |
mode.component[0].flags = 0; |
mode.component[0].sourceMinimum = 0; |
mode.component[0].sourceMaximum = gxColorValue1; |
mode.component[0].deviceMinimum = 0; |
mode.component[0].deviceMaximum = gxColorValue1; |
mode.component[0].clampMinimum = 0; |
mode.component[0].clampMaximum = gxColorValue1; |
mode.component[0].operand = 0; |
mode.component[1].mode = gxCopyMode; |
mode.component[1].flags = 0; |
mode.component[1].sourceMinimum = 0; |
mode.component[1].sourceMaximum = gxColorValue1; |
mode.component[1].deviceMinimum = 0; |
mode.component[1].deviceMaximum = gxColorValue1; |
mode.component[1].clampMinimum = 0; |
mode.component[1].clampMaximum = gxColorValue1; |
mode.component[1].operand = 0; |
mode.component[2].mode = gxNoMode; |
mode.component[2].flags = 0; |
mode.component[2].sourceMinimum = 0; |
mode.component[2].sourceMaximum = gxColorValue1; |
mode.component[2].deviceMinimum = 0; |
mode.component[2].deviceMaximum = gxColorValue1; |
mode.component[2].clampMinimum = 0; |
mode.component[2].clampMaximum = gxColorValue1; |
mode.component[2].operand = 0; |
GXSetInkTransfer(newInk, &mode); |
} |
// set the style and ink of the shape |
GXSetShapeStyle(newShape, newStyle); |
GXSetShapeInk(newShape, newInk); |
GXSetShapeFill(newShape, gxOpenFrameFill); |
// initialize the first point in the shape |
addPoly[2] = ff(lastPoint.h); |
addPoly[3] = ff(lastPoint.v); |
GXSetPolygonParts(newShape, gxSelectToEnd, 1, (gxPolygons*)addPoly, gxRemoveDuplicatePointsEdit); |
// determine the amount we require the mouse to move before adding a new point |
penSize = FixedDivide(GXGetStylePen(newStyle), ff(2)); |
if (penSize < ff(1)) |
penSize = ff(1); |
do |
{ |
GetMouse(¤tPoint); |
if ( |
(ff(ABS(currentPoint.h - lastPoint.h)) > penSize) || |
(ff(ABS(currentPoint.v - lastPoint.v)) > penSize) |
) |
{ |
// add the new point to the new shape |
lastPoint = currentPoint; |
addPoly[2] = ff(lastPoint.h); |
addPoly[3] = ff(lastPoint.v); |
GXSetPolygonParts(newShape, gxSelectToEnd, 1, (gxPolygons*)addPoly, gxRemoveDuplicatePointsEdit); |
GXDrawShape(newShape); |
} |
} while (StillDown()); |
{ |
Fixed zoomFactor = ((GXDataPtr)pData)->zoomFactor; |
Fixed shapeScale = FixedDivide(ff(1), zoomFactor); |
gxRectangle pageSize, paperSize; |
// offset the shape by the scroll bars & margins |
GetCurrentPageAndPaper(pData, &pageSize, &paperSize); |
GXMoveShape(newShape, |
ff(GetControlValue(pData->hScroll)) + FixedMultiply(paperSize.left, zoomFactor), |
ff(GetControlValue(pData->vScroll)) + FixedMultiply(paperSize.top, zoomFactor) ); |
// scale the shape to the current scale factor |
GXScaleShape(newShape, shapeScale, shapeScale, 0, 0 ); |
GXSetShapePen(newShape, FixedMultiply(GXGetShapePen(newShape), shapeScale) ); |
} |
// add shape to the page |
{ |
gxShape annotationShape = (*((GXDataPtr)pData)->pageAnnotations)[((GXDataPtr)pData)->currentPage-1]; |
if (!annotationShape) |
{ |
annotationShape = GXNewShape(gxPictureType); |
(*((GXDataPtr)pData)->pageAnnotations)[((GXDataPtr)pData)->currentPage-1] = annotationShape; |
} |
if (annotationShape) |
GXSetPictureParts(annotationShape, 0, 0, 1, &newShape, nil, nil, nil); |
} |
// all done with our copies of the shape, style, and ink |
GXDisposeShape(newShape); |
GXDisposeStyle(newStyle); |
GXDisposeInk(newInk); |
// we've touched the file |
pData->changed = true; |
return(anErr); |
} // DoDrawingClick |
// -------------------------------------------------------------------------------------------------------------- |
// Handle update/activate events behind Standard File |
static pascal Boolean SaveDialogFilter(DialogPtr theDialog, EventRecord *theEvent, |
short *itemHit, void *myDataPtr) |
{ |
#pragma unused(myDataPtr) |
if (StdFilterProc(theDialog, theEvent, itemHit)) |
return true; |
// Pass updates through (Activates are tricky...was mucking with Apple menu & thereby |
// drastically changing how the system handles the menu bar during our alert) |
if (theEvent->what == updateEvt /* || theEvent->what == activateEvt */ ) |
{ |
HandleEvent(theEvent); |
} |
return false; |
} // SaveDialogFilter |
#if GENERATINGCFM |
static RoutineDescriptor gSaveDialogFilterRD = BUILD_ROUTINE_DESCRIPTOR(uppModalFilterYDProcInfo, SaveDialogFilter); |
static ModalFilterYDUPP gSaveDialogFilter = &gSaveDialogFilterRD; |
#else |
static ModalFilterYDUPP gSaveDialogFilter = NewModalFilterYDProc(SaveDialogFilter); |
#endif |
// -------------------------------------------------------------------------------------------------------------- |
#define kLoadAnnotations true |
#define kSaveAnnotations false |
static OSErr LoadOrSaveAnnotations(WindowDataPtr pData, Boolean load) |
{ |
OSErr anErr = noErr; |
short i; |
short oldResFile = CurResFile(); |
userSpool block; |
block.spool.spoolProcedure = gHandleSpoolProc; |
UseResFile(((GXDataPtr)pData)->printFileRefNum); |
for (i = 0; i < ((GXDataPtr)pData)->numberOfPages; ++i) |
{ |
gxShape annotation = (*((GXDataPtr)pData)->pageAnnotations)[i]; |
Handle annotationHandle; |
block.spool.buffer = nil; |
block.spool.bufferSize = 0; |
if (load) |
{ |
// load annotation, if any |
annotationHandle = Get1Resource(kAnnotationType, kAnnotationBaseID + i-1); |
if (annotationHandle) |
{ |
block.data = annotationHandle; |
annotation = GXUnflattenShape(&block.spool, 0, nil); |
ReleaseResource(annotationHandle); |
} |
else |
{ |
annotation = nil; |
} |
} |
else |
{ |
// remove old annotation |
annotationHandle = Get1Resource(kAnnotationType, kAnnotationBaseID + i-1); |
if (annotationHandle) |
RemoveResource(annotationHandle); |
// add new annotation |
if (annotation) |
{ |
block.spool.spoolProcedure = gHandleSpoolProc; |
block.spool.buffer = nil; |
block.spool.bufferSize = 0; |
GXFlattenShape(annotation, 0, &block.spool); |
annotationHandle = (Handle) block.data; |
if (annotationHandle) |
{ |
AddResource(annotationHandle, kAnnotationType, kAnnotationBaseID + i-1, "\p"); |
ReleaseResource(annotationHandle); |
} |
} |
} |
(*((GXDataPtr)pData)->pageAnnotations)[i] = annotation; |
} |
UpdateResFile(CurResFile()); |
UseResFile(oldResFile); |
return(anErr); |
} // LoadOrSaveAnnotations |
// -------------------------------------------------------------------------------------------------------------- |
static OSErr GXSaveAs(WindowRef pWindow, WindowDataPtr pData) |
{ |
OSErr anErr = noErr; |
StandardFileReply sfReply; |
// ask where and how to save this document |
{ |
Str255 defaultName; |
Point where = {-1, -1}; |
// setup for the call |
GetWTitle(pWindow, defaultName); |
SetCursor(&qd.arrow); |
// find out where the user wants the file |
CustomPutFile("\p", defaultName, &sfReply, |
sfPutDialogID, where, |
nil, gSaveDialogFilter, nil, nil, nil); |
// map the cancel button into a cancelling error |
if (!sfReply.sfGood) |
anErr = eUserCanceled; |
} |
// can't replace over other types |
if (sfReply.sfReplacing) |
{ |
FInfo theInfo; |
FSpGetFInfo(&sfReply.sfFile, &theInfo); |
if ( |
(theInfo.fdType != 'sjob') && |
(theInfo.fdType != 'tjob') && |
(theInfo.fdType != 'rjob') && |
(theInfo.fdType != 'qjob') |
) |
anErr = eDocumentWrongKind; |
} |
nrequire(anErr, StandardPutFile); |
GXSavePrintFile(((GXDataPtr)pData)->thePrintFile, &sfReply.sfFile); |
anErr = GXGetJobError(pData->hPrint); |
// FALL THROUGH EXCEPTION HANDLING |
StandardPutFile: |
// if everything went okay |
if (anErr == noErr) |
{ |
// update the window title |
SetWTitle(pWindow, sfReply.sfFile.name); |
// save new location |
BlockMoveData(&sfReply.sfFile, &pData->fileSpec, sizeof(FSSpec)); |
// update the refNum |
((GXDataPtr)pData)->printFileRefNum = CurResFile(); |
// and read in the current page |
anErr = GetCurrentPage((GXDataPtr) pData, true); |
} |
// Return eUserCanceled so we can avoid closing/quitting if they cancel the SF dialog |
// // don't propagate this error |
// if (anErr == eUserCanceled) |
// anErr = noErr; |
return anErr; |
} // GXSaveAs |
// -------------------------------------------------------------------------------------------------------------- |
// OOP INTERFACE ROUTINES |
// -------------------------------------------------------------------------------------------------------------- |
static OSErr GXCloseWindow(WindowRef pWindow, WindowDataPtr pData) |
{ |
#pragma unused (pWindow) |
if (((GXDataPtr)pData)->pageAnnotations) |
{ |
short i; |
for (i = 0; i < ((GXDataPtr)pData)->numberOfPages; ++i) |
{ |
gxShape annotation = (*((GXDataPtr)pData)->pageAnnotations)[i]; |
if (annotation) |
GXDisposeShape(annotation); |
} |
DisposeHandle((Handle) (((GXDataPtr)pData)->pageAnnotations) ); |
((GXDataPtr)pData)->pageAnnotations = nil; |
} |
if (((GXDataPtr)pData)->currentSelectionShape) |
{ |
GXDisposeShape(((GXDataPtr)pData)->currentSelectionShape); |
((GXDataPtr)pData)->currentSelectionShape = nil; |
} |
if (((GXDataPtr)pData)->currentPageShape) |
{ |
GXDisposeShape(((GXDataPtr)pData)->currentPageShape); |
((GXDataPtr)pData)->currentPageShape = nil; |
} |
GXClosePrintFile( ((GXDataPtr)pData)->thePrintFile); |
GXDisposeViewPort( ((GXDataPtr)pData)->parentViewPort); |
GXDisposeViewPort( ((GXDataPtr)pData)->childViewPort); |
return(noErr); |
} // GXCloseWindow |
// -------------------------------------------------------------------------------------------------------------- |
static OSErr GXUpdateWindow(WindowRef pWindow, WindowDataPtr pData) |
{ |
gxGraphicsError anErr = noErr; |
// draw informational area to the left of the horizontal scroll bar |
{ |
FontInfo theInfo; |
Rect infoArea; |
RgnHandle oldClip = NewRgn(); |
Handle theString; |
long theStringSize; |
// save old clip and clip to the label area |
GetClip(oldClip); |
infoArea.left = 0; |
infoArea.right = pData->hScrollOffset-1; |
infoArea.bottom = GetWindowPort(pWindow)->portRect.bottom; |
infoArea.top = infoArea.bottom - kScrollBarSize; |
ClipRect(&infoArea); |
// draw the label |
TextFont(applFont); |
TextSize(9); |
GetFontInfo(&theInfo); |
theString = GetResource('LSTR', kLabelString); |
if (theString) |
{ |
Handle inString = NewHandle(sizeof(Str255)); |
Str255 newString; |
Rect labelArea = infoArea; |
// erase any old string we had there |
labelArea.right -= kZoomControlsWidth + kToolControlWidth; |
if (((GXDataPtr)pData)->numberOfPages > 1) |
labelArea.left += kPageControlsWidth; |
EraseRect(&labelArea); |
// current page label |
NumToString(((GXDataPtr)pData)->currentPage, newString); |
SetHandleSize(inString, newString[0]); |
BlockMoveData(&newString[1], *inString, newString[0]); |
ReplaceText(theString, inString, "\p^0"); |
// total page count label |
NumToString(((GXDataPtr)pData)->numberOfPages, newString); |
SetHandleSize(inString, newString[0]); |
BlockMoveData(&newString[1], *inString, newString[0]); |
ReplaceText(theString, inString, "\p^1"); |
// scale factor label |
NumToString(FixedToInt( FixedMultiply(((GXDataPtr)pData)->zoomFactor, ff(100)) ), newString); |
SetHandleSize(inString, newString[0]); |
BlockMoveData(&newString[1], *inString, newString[0]); |
ReplaceText(theString, inString, "\p^2"); |
// done with replace string content |
DisposeHandle(inString); |
// draw the label |
HLock(theString); |
theStringSize = GetHandleSize(theString); |
MoveTo(labelArea.left + ((labelArea.right - labelArea.left) >> 1) - (TextWidth(*theString, 0, theStringSize) >> 1), |
labelArea.top + ((labelArea.bottom - labelArea.top)>>1) + ((theInfo.ascent + theInfo.descent) >> 1) - theInfo.descent); |
DrawText(*theString, 0, theStringSize); |
ReleaseResource(theString); |
} |
// draw the current tool |
{ |
Rect toolArea = infoArea; |
CIconHandle icon; |
toolArea.left = toolArea.right - kToolControlWidth; |
toolArea.right = toolArea.left + 32; |
toolArea.bottom = toolArea.top + 32; |
EraseRect(&toolArea); |
OffsetRect(&toolArea, -8, -8); |
icon = GetCIcon(kIconBase + ((GXDataPtr)pData)->contentClickMode); |
if (icon) |
{ |
PlotCIconHandle(&toolArea, kAlignAbsoluteCenter, ttNone, icon); |
DisposeCIcon(icon); |
} |
} |
// draw the zoom controls |
{ |
Rect zoomArea = infoArea; |
zoomArea.left = zoomArea.right - kZoomControlsWidth - kToolControlWidth; |
zoomArea.right = zoomArea.left + 32; |
zoomArea.bottom = zoomArea.top + 32; |
PlotIconID(&zoomArea, ttNone, ttNone, kZoomControlPlain); |
} |
// draw the left/right/page arrows |
if (((GXDataPtr)pData)->numberOfPages > 1) |
{ |
Rect arrowsRect; |
// erase any old arrow bits, including around the edges of the icon |
// needed when the window resizes |
arrowsRect = infoArea; |
arrowsRect.bottom = arrowsRect.top + 32; |
arrowsRect.right = arrowsRect.left + 34; |
EraseRect(&arrowsRect); |
// then draw the new arrows |
arrowsRect.left = infoArea.left + 2; |
arrowsRect.top = infoArea.top + 2; |
arrowsRect.right = arrowsRect.left + kPageControlsWidth; |
arrowsRect.bottom = arrowsRect.top + 32; |
PlotIconID(&arrowsRect, ttNone, ttNone, kPageControlPlain); |
} |
// frame the area |
MoveTo(infoArea.left, infoArea.top); |
LineTo(infoArea.right, infoArea.top); |
// restore old clip value |
SetClip(oldClip); |
DisposeRgn(oldClip); |
} |
// then draw the page shape and things around it |
{ |
gxRectangle pageSize, paperSize; |
gxShape tempShape, pageShape; |
gxMapping thisMapping; |
// clip to the content area |
paperSize.left = ff(pData->contentRect.left); |
paperSize.top = ff(pData->contentRect.top); |
paperSize.right = ff(pData->contentRect.right); |
paperSize.bottom = ff(pData->contentRect.bottom); |
tempShape = GXNewRectangle(&paperSize); |
GXSetViewPortClip(((GXDataPtr)pData)->childViewPort, tempShape); |
GXDisposeShape(tempShape); |
// get the paper sizes, account for zoom factor |
GetCurrentPageAndPaper(pData, &pageSize, &paperSize); |
pageSize.left = FixedMultiply(pageSize.left, ((GXDataPtr)pData)->zoomFactor); |
pageSize.right = FixedMultiply(pageSize.right, ((GXDataPtr)pData)->zoomFactor); |
pageSize.top = FixedMultiply(pageSize.top, ((GXDataPtr)pData)->zoomFactor); |
pageSize.bottom = FixedMultiply(pageSize.bottom, ((GXDataPtr)pData)->zoomFactor); |
paperSize.left = FixedMultiply(paperSize.left, ((GXDataPtr)pData)->zoomFactor); |
paperSize.right = FixedMultiply(paperSize.right, ((GXDataPtr)pData)->zoomFactor); |
paperSize.top = FixedMultiply(paperSize.top, ((GXDataPtr)pData)->zoomFactor); |
paperSize.bottom = FixedMultiply(paperSize.bottom, ((GXDataPtr)pData)->zoomFactor); |
// offset by the scrolling amount |
ResetMapping(&thisMapping); |
MoveMapping(&thisMapping, Long2Fix(-GetControlValue(pData->hScroll)) - paperSize.left , |
Long2Fix(-GetControlValue(pData->vScroll)) - paperSize.top ); |
// make the paper shape |
tempShape = GXNewShape(gxFullType); |
GXSetTransformViewPorts(GXGetShapeTransform(tempShape), 1, & ((GXDataPtr)pData)->childViewPort); |
GXSetShapeFill(tempShape, gxEvenOddFill); |
GXSetShapeMapping(tempShape, &thisMapping); |
// make the page shape |
pageShape = GXNewRectangle(&pageSize); |
GXSetTransformViewPorts(GXGetShapeTransform(pageShape), 1, & ((GXDataPtr)pData)->childViewPort); |
GXSetShapeFill(pageShape, gxEvenOddFill); |
GXSetShapeMapping(pageShape, &thisMapping); |
// remove the page shape from the paper shape |
GXDifferenceShape(tempShape, pageShape); |
// draw the paper shape, dispose of it |
SetShapeGreyColorLevel(tempShape, 0xD000); /* Set up light gray background */ |
GXDrawShape(tempShape); |
GXDisposeShape(tempShape); |
// draw white on the page shape |
SetShapeGreyColorLevel(pageShape, 0xFFFF); /* Set up white page */ |
GXSetShapeFill(pageShape, gxEvenOddFill); |
GXDrawShape(pageShape); |
// frame the page shape |
SetShapeGreyColorLevel(pageShape, 0x8000); /* Set up medium gray frame */ |
GXSetShapeFill(pageShape, gxClosedFrameFill); |
GXDrawShape(pageShape); |
// draw the scroll bars and grow box now to give a nice appearence |
DrawControls(pWindow); |
DrawGrowIcon(pWindow); |
// draw the page data itself, clipped to the page |
{ |
gxMapping oldMapping, flipMapping; |
// get the page shape's old mapping, and make a copy to work with |
GXGetShapeMapping(((GXDataPtr)pData)->currentPageShape, &oldMapping); |
// run the clip through the inverse of the shape mapping to scale it properly |
GXInsetShape(pageShape, ff(1)); |
ScaleMapping(&oldMapping, ((GXDataPtr)pData)->zoomFactor, ((GXDataPtr)pData)->zoomFactor, 0, 0); |
InvertMapping(&flipMapping, &oldMapping); |
GXMapShape(pageShape, &flipMapping); |
GXSetShapeFill(pageShape, gxEvenOddFill); |
GXSetShapeClip( ((GXDataPtr)pData)->currentPageShape, pageShape); |
// move the shape into position by offseting the viewPort |
GXGetViewPortMapping(((GXDataPtr)pData)->childViewPort, &thisMapping); |
GXGetViewPortMapping(((GXDataPtr)pData)->childViewPort, &oldMapping); |
ScaleMapping(&thisMapping, ((GXDataPtr)pData)->zoomFactor, ((GXDataPtr)pData)->zoomFactor, 0, 0); |
MoveMapping(&thisMapping, Long2Fix(-GetControlValue(pData->hScroll)) - paperSize.left , |
Long2Fix(-GetControlValue(pData->vScroll)) - paperSize.top ); |
GXSetViewPortMapping(((GXDataPtr)pData)->childViewPort, &thisMapping); |
/* |
* Bracket the call to DrawShape with UseResFile, so that we put the |
* document's resfile on top, allowing the translator (for QDShapes) |
* to see our embedded fonts (if any) first. |
*/ |
{ short oldResFile = CurResFile(); |
UseResFile(((GXDataPtr)pData)->printFileRefNum); |
GXDrawShape( ((GXDataPtr)pData)->currentPageShape); |
UseResFile(oldResFile); |
} |
// Draw the selection, if any |
{ |
gxShape selectionShape = ((GXDataPtr)pData)->currentSelectionShape; |
gxShape highlight; |
if (selectionShape) |
{ |
// better be a layout shape to get hilights |
GXSetShapeType(selectionShape, gxLayoutType); |
// get the highlight |
highlight = GetCurrentSelectionHighlight(pData, true); |
GXDrawShape(highlight); |
GXDisposeShape(highlight); |
} |
} |
// Draw the overlay, if any |
{ |
gxShape annotationShape = (*((GXDataPtr)pData)->pageAnnotations)[((GXDataPtr)pData)->currentPage-1]; |
if (annotationShape) |
{ |
GXSetShapeViewPorts(annotationShape, 1, &((GXDataPtr)pData)->childViewPort); |
GXDrawShape(annotationShape); |
} |
} |
// restore viewPort's mapping (so we don't use it again next time) |
GXSetViewPortMapping(((GXDataPtr)pData)->childViewPort, &oldMapping); |
} |
// done with the page shape |
GXDisposeShape(pageShape); |
DrawSelection(pData, &((GXDataPtr)pData)->selectionRectangle, &((GXDataPtr)pData)->patternPhase, false); |
GXGetGraphicsError(&anErr); |
} |
return(anErr); |
} // GXUpdateWindow |
// -------------------------------------------------------------------------------------------------------------- |
static OSErr GXContentClick(WindowRef pWindow, WindowDataPtr pData, EventRecord *pEvent) |
{ |
OSErr anErr = noErr; |
Point clickPoint = pEvent->where; |
Rect infoArea, labelArea, toolArea; |
Rect zoomOutRect, zoomInRect, zoomsRect; |
RgnHandle oldClip = NewRgn(); |
Boolean somethingHit = false; |
// convert to local space, calculate clickable areas |
GlobalToLocal(&clickPoint); |
infoArea.left = 0; |
infoArea.right = pData->hScrollOffset-1; |
infoArea.bottom = GetWindowPort(pWindow)->portRect.bottom; |
infoArea.top = infoArea.bottom - kScrollBarSize; |
// clip to the info area |
GetClip(oldClip); |
ClipRect(&infoArea); |
// label area |
labelArea = infoArea; |
labelArea.right -= kZoomControlsWidth + kToolControlWidth; |
if (((GXDataPtr)pData)->numberOfPages > 1) |
labelArea.left += kPageControlsWidth; |
// the tool pop up |
toolArea = infoArea; |
toolArea.left = toolArea.right - kToolControlWidth; |
// calculate the zoom in/out rects |
zoomInRect = infoArea; |
zoomInRect.right -= kToolControlWidth; |
zoomInRect.left = zoomInRect.right - 13; |
zoomOutRect = zoomInRect; |
OffsetRect(&zoomOutRect, -13, 0); |
zoomsRect = zoomOutRect; |
zoomsRect.bottom = zoomsRect.top + 32; |
zoomsRect.right = zoomsRect.left + 32; |
// deal with zoom in/out clicks |
if (TrackIn(&zoomInRect, clickPoint, &zoomsRect, kZoomControlRight, kZoomControlPlain)) |
{ |
somethingHit = true; |
SetZoom(pWindow, pData, FixedMultiply(((GXDataPtr)pData)->zoomFactor, ff(2)) ); |
PlotIconID(&zoomsRect, ttNone, ttNone, kZoomControlPlain); |
} |
if (TrackIn(&zoomOutRect, clickPoint, &zoomsRect, kZoomControlLeft, kZoomControlPlain)) |
{ |
somethingHit = true; |
SetZoom(pWindow, pData, FixedDivide(((GXDataPtr)pData)->zoomFactor, ff(2)) ); |
PlotIconID(&zoomsRect, ttNone, ttNone, kZoomControlPlain); |
} |
// deal with the options pop up |
if (PtInRect(clickPoint, &labelArea)) |
{ |
MenuHandle popupMenu = GetMenu(kGXPopUpMenu); |
short selectedItem; |
TextState textState; |
Point popPoint; |
char bulletString[3]; |
// figure out where to display the pop up |
popPoint.v = labelArea.top; |
popPoint.h = labelArea.left; |
LocalToGlobal(&popPoint); |
somethingHit = true; |
GetIntlTokenChar(tokenCenterDot, FontToScript(applFont), bulletString); |
// set up menu to be small sized |
TextFont(applFont); |
TextSize(9); |
DoUseWFont(&textState, pWindow, true); |
// set up the menu for selected items |
SetItemMark(popupMenu, iDontShowMargins, (((GXDataPtr)pData)->dontShowMargins) ? bulletString[1] : noMark); |
{ |
ZoomTableEntry *pEntry = &gZoomTable[0]; |
while (pEntry->menuItem != 0) |
{ |
SetItemMark(popupMenu, pEntry->menuItem, (((GXDataPtr)pData)->zoomFactor == pEntry->zoomFactor) ? bulletString[1] : noMark); |
pEntry++; |
} |
} |
// conduct the menu |
InsertMenu(popupMenu, -1); |
selectedItem = PopUpMenuSelect(popupMenu, popPoint.v, popPoint.h, CountMItems(popupMenu)+1) & 0xFFFF; |
// restore menu sizes |
DoUseWFont(&textState, nil, false); |
DeleteMenu(kGXPopUpMenu); |
switch (selectedItem) |
{ |
// toggle show/hide margins |
case iDontShowMargins: |
// flip the boolean |
((GXDataPtr)pData)->dontShowMargins = 1 - ((GXDataPtr)pData)->dontShowMargins; |
// force update and recalc the size of window |
InvalRect(&GetWindowPort(pWindow)->portRect); |
AdjustScrollBars(pWindow, true, true, nil); |
break; |
// scale graphics to fit the window |
case iScaleToFit: |
{ |
gxRectangle pageSize, paperSize; |
Fixed horizScale, vertScale; |
GrafPtr pPort = (GrafPtr)GetWindowPort(pWindow); |
GetCurrentPageAndPaper(pData, &pageSize, &paperSize); |
pageSize.left = pageSize.top = 0; |
pageSize.right = ff(pPort->portRect.right - kScrollBarSize); |
pageSize.bottom = ff(pPort->portRect.bottom - kScrollBarSize); |
horizScale = FixedDivide(pageSize.right - pageSize.left, paperSize.right - paperSize.left); |
vertScale = FixedDivide(pageSize.bottom - pageSize.top, paperSize.bottom - paperSize.top); |
if (horizScale > vertScale) |
SetZoom(pWindow, pData, vertScale); |
else |
SetZoom(pWindow, pData, horizScale); |
} |
break; |
// absolute set scale cases |
default: |
{ |
ZoomTableEntry *pEntry = &gZoomTable[0]; |
while (pEntry->menuItem != 0) |
{ |
if (selectedItem == pEntry->menuItem) |
SetZoom(pWindow, pData, pEntry->zoomFactor); |
pEntry++; |
} |
} |
break; |
} |
} |
// deal with the tool pop up |
if (PtInRect(clickPoint, &toolArea)) |
{ |
MenuHandle popupMenu = GetMenu(kGXToolMenu); |
short selectedItem; |
Point popPoint; |
short i, numItems; |
// figure out where to display the pop up |
popPoint.v = toolArea.top; |
popPoint.h = toolArea.left; |
LocalToGlobal(&popPoint); |
// we've processed the mouse click |
somethingHit = true; |
// select our current item in the menu |
numItems = CountMItems(popupMenu); |
for (i = 1; i <= numItems; ++i) |
CheckItem(popupMenu, i, (i == ((GXDataPtr)pData)->contentClickMode) ); |
// conduct the menu |
InsertMenu(popupMenu, -1); |
selectedItem = PopUpMenuSelect(popupMenu, popPoint.v, popPoint.h, numItems+1) & 0xFFFF; |
DeleteMenu(kGXPopUpMenu); |
// remember the item selected |
if (selectedItem != 0) |
((GXDataPtr)pData)->contentClickMode = selectedItem; |
// invalidation the tool picture |
InvalRect(&toolArea); |
if (selectedItem != kSelectionTool) |
{ |
// erase the old selection |
DrawSelection(pData, &((GXDataPtr)pData)->selectionRectangle, &((GXDataPtr)pData)->patternPhase, false); |
// clear the selection |
((GXDataPtr)pData)->selectionRectangle.top = 0; |
((GXDataPtr)pData)->selectionRectangle.left = 0; |
((GXDataPtr)pData)->selectionRectangle.bottom = 0; |
((GXDataPtr)pData)->selectionRectangle.right = 0; |
// draw the new selection |
DrawSelection(pData, &((GXDataPtr)pData)->selectionRectangle, &((GXDataPtr)pData)->patternPhase, true); |
} |
} |
// deal with clicks in page controls |
if (((GXDataPtr)pData)->numberOfPages > 1) |
{ |
Rect leftArrowRect, rightArrowRect, arrowsRect; |
Rect gotoPageRect; |
// calculate the minus one page arrow |
leftArrowRect.top = infoArea.top + 2; |
leftArrowRect.bottom = leftArrowRect.top + 32; |
leftArrowRect.left = infoArea.left + 2; |
leftArrowRect.right = leftArrowRect.left + 11; |
// calculate the go to a particular page rect |
gotoPageRect = leftArrowRect; |
OffsetRect(&gotoPageRect, 11, 0); |
gotoPageRect.right --; |
// calculate the plus one page arrow |
rightArrowRect = gotoPageRect; |
OffsetRect(&rightArrowRect, 10, 0); |
// calculate sum of all areas |
arrowsRect = leftArrowRect; |
arrowsRect.left = infoArea.left + 2; |
arrowsRect.right = arrowsRect.left + kPageControlsWidth; |
if (TrackIn(&leftArrowRect, clickPoint, &arrowsRect, kPageControlLeft, kPageControlPlain)) |
{ |
somethingHit = true; |
if (((GXDataPtr)pData)->currentPage > 1) |
anErr = GXCommand(pWindow, pData, cPreviousPage, 0); |
else |
PlotIconID(&arrowsRect, ttNone, ttNone, kPageControlPlain); |
} |
if (TrackIn(&rightArrowRect, clickPoint, &arrowsRect, kPageControlRight, kPageControlPlain)) |
{ |
somethingHit = true; |
if (((GXDataPtr)pData)->currentPage < ((GXDataPtr)pData)->numberOfPages) |
anErr = GXCommand(pWindow, pData, cNextPage, 0); |
else |
PlotIconID(&arrowsRect, ttNone, ttNone, kPageControlPlain); |
} |
if (PtInRect(clickPoint, &gotoPageRect)) |
{ |
long actualTicks; |
somethingHit = true; |
// pause, then check if the mouse is still down |
Delay(20, &actualTicks); |
// if still down, track preview window |
if (StillDown()) |
{ |
WindowRef popWindow; |
Rect windowRect; |
short oldResFile = CurResFile(); |
// put the print file on top |
UseResFile(((GXDataPtr)pData)->printFileRefNum); |
// figure out where to place the pop up window, and then make it |
windowRect.bottom = arrowsRect.top - 2; |
windowRect.left = 2; |
if (Count1Resources(kProxyType) > 0) |
windowRect.top = windowRect.bottom - kPopUpWindowHeightLarge; |
else |
windowRect.top = windowRect.bottom - kPopUpWindowHeightSmall; |
windowRect.right = windowRect.left + kScrollAreaWidth + kPageControlsWidth + kZoomControlsWidth + kToolControlWidth - 4; |
LocalToGlobal(&TopLeft(windowRect)); |
LocalToGlobal(&BotRight(windowRect)); |
popWindow = (WindowRef) NewCWindow(nil, &windowRect, "\p", true, plainDBox, (WindowPtr)-1, false, 0); |
if (popWindow) |
{ |
long oldValue = ((GXDataPtr)pData)->currentPage; |
long newValue = oldValue; |
GrafPtr popPort = (GrafPtr)GetWindowPort(popWindow); |
// draw initial location of the value |
SetPort(popPort); |
DrawPageSliderAndThumb(popWindow, oldValue, ((GXDataPtr)pData)->numberOfPages); |
// track the mouse, updating the value as we go |
while (StillDown()) |
{ |
GetMouse(&clickPoint); |
if (PtInRect(clickPoint, &popPort->portRect)) |
{ |
newValue = clickPoint.h |
* |
((GXDataPtr)pData)->numberOfPages |
/ |
(popPort->portRect.right - popPort->portRect.left) |
+ 1; |
if (oldValue != newValue) |
{ |
oldValue = newValue; |
DrawPageSliderAndThumb(popWindow, oldValue, ((GXDataPtr)pData)->numberOfPages); |
} |
} |
} |
// and done with the pop up window, return to main window |
DisposeWindow(popWindow); |
SetPort((GrafPtr)GetWindowPort(pWindow)); |
// if we changed the value, make it so |
if (newValue != ((GXDataPtr)pData)->currentPage) |
{ |
((GXDataPtr)pData)->currentPage = newValue; |
anErr = GetCurrentPage((GXDataPtr) pData, true); |
InvalRect(&GetWindowPort(pWindow)->portRect); |
} |
} |
// restore resource chain |
UseResFile(oldResFile); |
} |
else |
{ |
// otherwise, do the goto dialog box |
anErr = GXCommand(pWindow, pData, cGotoPage, 0); |
} |
} // if (click in goto page area) |
} // if (> 1 page) |
// restore clip |
SetClip(oldClip); |
DisposeRgn(oldClip); |
// nothing matched so far, deal with selecting the contents |
if (!somethingHit) |
{ |
Rect selectionRect = ((GXDataPtr)pData)->selectionRectangle; |
OffsetRect(&selectionRect, -GetControlValue(pData->hScroll), -GetControlValue(pData->vScroll)); |
if ( (gMachineInfo.haveDragMgr) && (PtInRect(clickPoint, &selectionRect)) ) |
{ |
((GXDataPtr)pData)->tempDragShape = nil; |
DragAndDropArea(pWindow, pData, pEvent, |
&selectionRect); |
if ( ((GXDataPtr)pData)->tempDragShape ) |
GXDisposeShape( ((GXDataPtr)pData)->tempDragShape ); |
} |
else |
{ |
LongRect docRect; |
Rect contentRect; |
contentRect = GetWindowPort(pWindow)->portRect; |
contentRect.right -= kScrollBarSize; |
contentRect.bottom -= kScrollBarSize; |
if (PtInRect(clickPoint, &contentRect)) |
{ |
switch (((GXDataPtr)pData)->contentClickMode) |
{ |
case kSelectionTool: |
GXGetDocumentRect(pWindow, pData, &docRect, false); |
contentRect.top = docRect.top; |
contentRect.left = docRect.left; |
contentRect.bottom = docRect.bottom; |
contentRect.right = docRect.right; |
anErr = SelectContents(pWindow, pData, pEvent, |
&((GXDataPtr)pData)->selectionRectangle, &contentRect, |
&((GXDataPtr)pData)->patternPhase); |
// existing text selection? clear the highlight |
if (((GXDataPtr)pData)->currentSelectionShape) |
{ |
InvalRect(&GetWindowPort(pWindow)->portRect); |
ClearCurrentSelection((GXDataPtr)pData); |
} |
break; |
case kRedMarkerTool: |
DoDrawingClick(pWindow, pData, clickPoint, pEvent); |
break; |
} // switch (mode) |
} // click in content rect |
} |
} |
return(anErr); |
} // GXContentClick |
// -------------------------------------------------------------------------------------------------------------- |
static OSErr GXAdjustMenus(WindowRef pWindow, WindowDataPtr pData) |
{ |
#pragma unused (pWindow) |
OSErr anErr = noErr; |
EnableCommand(cSaveAs); |
if (((GXDataPtr)pData)->numberOfPages > 1) |
{ |
if (((GXDataPtr)pData)->currentPage < ((GXDataPtr)pData)->numberOfPages) |
EnableCommand(cNextPage); |
if (((GXDataPtr)pData)->currentPage > 1) |
EnableCommand(cPreviousPage); |
EnableCommand(cGotoPage); |
} |
if (!EmptyRect( &((GXDataPtr)pData)->selectionRectangle) ) |
EnableCommand(cCopy); |
{ |
LongRect docRect; |
Rect shortDocRect; |
// find out the size of the document |
GXGetDocumentRect(pWindow, pData, &docRect, false); |
LongRectToRect(&docRect, &shortDocRect); |
if (EqualRect(&shortDocRect, &((GXDataPtr)pData)->selectionRectangle)) |
ChangeCommandName(cSelectAll, kMiscStrings, iSelectNoneCommand); |
else |
ChangeCommandName(cSelectAll, kMiscStrings, iSelectAllCommand); |
} |
EnableCommand(cSelectAll); |
EnableCommand(cFind); |
if (gFindString[0] != 0) |
EnableCommand(cFindAgain); |
return(anErr); |
} // GXAdjustMenus |
// -------------------------------------------------------------------------------------------------------------- |
OSErr GXCommand(WindowRef pWindow, WindowDataPtr pData, short commandID, long menuResult) |
{ |
#pragma unused (menuResult) |
OSErr anErr = noErr; |
switch (commandID) |
{ |
case cSave: |
GXSavePrintFile(((GXDataPtr)pData)->thePrintFile, nil); |
anErr = GXGetJobError(pData->hPrint); |
if (anErr == noErr) |
anErr = LoadOrSaveAnnotations(pData, kSaveAnnotations); |
// if everything went okay, then clear the changed bit |
if (anErr == noErr) |
pData->changed = false; |
break; |
case cSaveAs: |
anErr = GXSaveAs(pWindow, pData); |
if (anErr == noErr) |
anErr = LoadOrSaveAnnotations(pData, kSaveAnnotations); |
// if everything went okay, then clear the changed bit |
if (anErr == noErr) |
pData->changed = false; |
break; |
case cFind: |
if (ConductFindOrReplaceDialog(kFindWindowID) == cancel) |
break; |
// start search at top of page |
((GXDataPtr)pData)->currentShapeIndex = 0; |
// fall through from find |
case cFindAgain: |
{ |
Boolean isBackwards = ((gEvent.modifiers & shiftKey) != 0); |
SetWatchCursor(); |
if (!PerformNextFind(pWindow, pData, gFindString, gCaseSensitive, isBackwards, gWrapAround)) |
SysBeep(1); |
else |
ScrollFoundShapeIntoView(pWindow, pData); |
SetCursor(&qd.arrow); |
} |
break; |
case cCopy: |
{ |
gxShape cullShape = GetSelectedShape(pData); |
if (cullShape) |
{ |
// done with the shape now |
ShapeToScrap(cullShape); |
GXDisposeShape(cullShape); |
} |
} |
break; |
case cSelectAll: |
{ |
LongRect docRect; |
Rect shortDocRect; |
// find out the size of the document |
GXGetDocumentRect(pWindow, pData, &docRect, false); |
// erase the old selection |
DrawSelection(pData, &((GXDataPtr)pData)->selectionRectangle, &((GXDataPtr)pData)->patternPhase, false); |
LongRectToRect(&docRect, &shortDocRect); |
if (EqualRect(&shortDocRect, &((GXDataPtr)pData)->selectionRectangle)) |
{ |
((GXDataPtr)pData)->selectionRectangle.top = 0; |
((GXDataPtr)pData)->selectionRectangle.left = 0; |
((GXDataPtr)pData)->selectionRectangle.bottom = 0; |
((GXDataPtr)pData)->selectionRectangle.right = 0; |
} |
else |
{ |
((GXDataPtr)pData)->selectionRectangle.top = docRect.top; |
((GXDataPtr)pData)->selectionRectangle.left = docRect.left; |
((GXDataPtr)pData)->selectionRectangle.bottom = docRect.bottom; |
((GXDataPtr)pData)->selectionRectangle.right = docRect.right; |
} |
// draw the new selection |
DrawSelection(pData, &((GXDataPtr)pData)->selectionRectangle, &((GXDataPtr)pData)->patternPhase, true); |
} |
break; |
case cPageSetup: |
DoPageSetup(pWindow); |
anErr = GetCurrentPage((GXDataPtr) pData, false); |
InvalRect(&GetWindowPort(pWindow)->portRect); |
anErr = eActionAlreadyHandled; |
break; |
case cNextPage: |
((GXDataPtr)pData)->currentPage++; |
anErr = GetCurrentPage((GXDataPtr) pData, true); |
InvalRect(&GetWindowPort(pWindow)->portRect); |
if (anErr == noErr) |
anErr = eActionAlreadyHandled; |
break; |
case cPreviousPage: |
((GXDataPtr)pData)->currentPage--; |
anErr = GetCurrentPage((GXDataPtr) pData, true); |
InvalRect(&GetWindowPort(pWindow)->portRect); |
if (anErr == noErr) |
anErr = eActionAlreadyHandled; |
break; |
case cGotoPage: |
switch (menuResult) |
{ |
case cGotoFirst: |
((GXDataPtr)pData)->currentPage = 1; |
anErr = GetCurrentPage((GXDataPtr) pData, true); |
InvalRect(&GetWindowPort(pWindow)->portRect); |
break; |
case cGotoLast: |
((GXDataPtr)pData)->currentPage = ((GXDataPtr)pData)->numberOfPages; |
anErr = GetCurrentPage((GXDataPtr) pData, true); |
InvalRect(&GetWindowPort(pWindow)->portRect); |
break; |
default: |
{ |
DialogRef dPtr; |
short hit; |
dPtr = GetNewDialog(kGotoPageDialogID, nil, (WindowRef)-1); |
if (dPtr) |
{ |
short theType; |
Handle theHandle; |
Rect theRect; |
Str255 theString; |
GetDialogItem(dPtr, 4, &theType, &theHandle, &theRect); |
NumToString(((GXDataPtr)pData)->currentPage, theString); |
SetDialogItemText(theHandle, theString); |
SelectDialogItemText(dPtr, 4, 0, 32767); |
NumToString(((GXDataPtr)pData)->numberOfPages, theString); |
ParamText(theString, "\p", "\p", "\p"); |
SetDialogDefaultItem(dPtr, ok); |
SetDialogCancelItem(dPtr, cancel); |
BeginMovableModal(); |
do |
{ |
MovableModalDialog(nil, &hit); |
if (hit == ok) |
{ |
long tempLong; |
// convert to a page number, find and report errors |
GetDialogItemText(theHandle, theString); |
StringToNum(theString, &tempLong); |
if (tempLong < 1) |
{ |
SysBeep(1); |
tempLong = 1; |
hit = 0; |
} |
if (tempLong > ((GXDataPtr)pData)->numberOfPages) |
{ |
tempLong = ((GXDataPtr)pData)->numberOfPages; |
hit = 0; |
} |
// if we have an error, we try again, otherwise we go to the page |
if (hit == 0) |
{ |
SysBeep(1); |
NumToString(tempLong, theString); |
SetDialogItemText(theHandle, theString); |
SelectDialogItemText(dPtr, 4, 0, 32767); |
} |
else |
{ |
((GXDataPtr)pData)->currentPage = tempLong; |
anErr = GetCurrentPage((GXDataPtr) pData, true); |
InvalRect(&GetWindowPort(pWindow)->portRect); |
} |
} |
} while ((hit != ok) && (hit != cancel)); |
DisposeDialog(dPtr); |
EndMovableModal(); |
} |
} |
break; |
} |
if (anErr == noErr) |
anErr = eActionAlreadyHandled; |
break; |
} |
return(anErr); |
} // GXCommand |
// -------------------------------------------------------------------------------------------------------------- |
static OSErr GXFilePrintPage(WindowRef pWindow, WindowDataPtr pData, |
Rect * pageRect, long *pageNum) |
{ |
#pragma unused (pWindow, pageRect) |
OSErr anErr = noErr; |
gxShape thisShape; |
gxFormat thisFormat; |
GXReadPrintFilePage(((GXDataPtr)pData)->thePrintFile, *pageNum, 0, nil, &thisFormat, &thisShape); |
anErr = GXGetJobError(pData->hPrint); |
nrequire(anErr, ReadPrintFilePage); |
GXPrintPage(pData->hPrint, *pageNum, thisFormat, thisShape); |
anErr = GXGetJobError(pData->hPrint); |
nrequire(anErr, PrintPage); |
GXDisposeFormat(thisFormat); |
GXDisposeShape(thisShape); |
// FALL THROUGH EXCEPTION HANDLING |
PrintPage: |
ReadPrintFilePage: |
// tell it to stop printing when we reach the end |
if (*pageNum >= ((GXDataPtr)pData)->numberOfPages) |
*pageNum = -1; |
return(anErr); |
} // GXFilePrintPage |
// -------------------------------------------------------------------------------------------------------------- |
OSErr GXGetDocumentRect(WindowRef pWindow, WindowDataPtr pData, |
LongRect * documentRectangle, Boolean forGrow) |
{ |
#pragma unused (pWindow, forGrow) |
gxRectangle pageSize, paperSize; |
GetCurrentPageAndPaper(pData, &pageSize, &paperSize); |
documentRectangle->left = 0; |
documentRectangle->top = 0; |
documentRectangle->bottom = FixedMultiply(paperSize.bottom - paperSize.top, ((GXDataPtr)pData)->zoomFactor) >> 16; |
documentRectangle->right = FixedMultiply(paperSize.right - paperSize.left, ((GXDataPtr)pData)->zoomFactor) >> 16; |
return(noErr); |
} // GXGetDocumentRect |
// -------------------------------------------------------------------------------------------------------------- |
static long GXCalculateIdleTime(WindowRef pWindow, WindowDataPtr pData) |
{ |
#pragma unused (pWindow) |
if (!EmptyRect( &((GXDataPtr)pData)->selectionRectangle)) |
return(0); |
else |
return(kMaxWaitTime); |
} // GXCalculateIdleTime |
// -------------------------------------------------------------------------------------------------------------- |
static Boolean GXFilterEvent(WindowRef pWindow, WindowDataPtr pData, EventRecord *pEvent) |
{ |
if ( |
(!gMachineInfo.amInBackground) && |
(pEvent->what == nullEvent) && |
(pWindow == FrontWindow()) && |
(EmptyRgn( ((WindowPeek)pWindow)->updateRgn)) && |
(MOVESELECTION(pEvent->when) ) |
) |
{ |
// erase the old |
DrawSelection(pData, &((GXDataPtr)pData)->selectionRectangle, &((GXDataPtr)pData)->patternPhase, false); |
// draw the new, moving onto the next pattern |
DrawSelection(pData, &((GXDataPtr)pData)->selectionRectangle, &((GXDataPtr)pData)->patternPhase, true); |
} |
return(false); |
} // GXFilterEvent |
// -------------------------------------------------------------------------------------------------------------- |
static OSErr GXDragAddFlavors(WindowRef pWindow, WindowDataPtr pData, DragReference theDragRef) |
{ |
#pragma unused (pWindow) |
OSErr anErr = noErr; |
SetDragSendProc(theDragRef, gGXSendDataProc, nil); |
AddDragItemFlavor(theDragRef, (unsigned long)pData, 'qdgx', nil, 0, 0); |
AddDragItemFlavor(theDragRef, (unsigned long)pData, 'PICT', nil, 0, 0); |
return(anErr); |
} // GXDragAddFlavors |
// -------------------------------------------------------------------------------------------------------------- |
static OSErr GXAdjustCursor(WindowRef pWindow, WindowDataPtr pData, Point * localMouse, Rect * globalRect) |
{ |
#pragma unused (pWindow, globalRect) |
OSErr anErr = noErr; |
Handle theCursor; |
Rect selectionRect = ((GXDataPtr)pData)->selectionRectangle; |
OffsetRect(&selectionRect, -GetControlValue(pData->hScroll), -GetControlValue(pData->vScroll)); |
if (!PtInRect(*localMouse, &selectionRect) ) |
{ |
short cursorID; |
Boolean colorCursor; |
cursorID = ((GXDataPtr)pData)->contentClickMode; |
if (cursorID == kSelectionTool) |
{ |
colorCursor = false; |
cursorID = crossCursor; |
} |
else |
{ |
colorCursor = true; |
cursorID += kIconBase; |
} |
if (colorCursor) |
theCursor = (Handle)GetCCursor(cursorID); |
else |
theCursor = (Handle)GetCursor(cursorID); |
if (theCursor) |
{ |
if (colorCursor) |
{ |
SetCCursor((CCrsrHandle)theCursor); |
DisposeCCursor((CCrsrHandle)theCursor); |
} |
else |
{ |
char oldState; |
oldState = HGetState(theCursor); |
HLock((Handle) theCursor); |
SetCursor(*(CursHandle)theCursor); |
HSetState(theCursor, oldState); |
} |
anErr = eActionAlreadyHandled; |
} |
} |
return(anErr); |
} // GXAdjustCursor |
// -------------------------------------------------------------------------------------------------------------- |
static OSErr GXMakeWindow(WindowRef pWindow, WindowDataPtr pData) |
{ |
OSErr anErr = noErr; |
pData->pCloseWindow = (CloseWindowProc) GXCloseWindow; |
pData->pAdjustMenus = (AdjustMenusProc) GXAdjustMenus; |
pData->pCommand = (CommandProc) GXCommand; |
pData->pUpdateWindow = (UpdateWindowProc) GXUpdateWindow; |
pData->pContentClick = (ContentClickProc) GXContentClick; |
pData->pGetDocumentRect = (GetDocumentRectProc) GXGetDocumentRect; |
pData->pPrintPage = (PrintPageProc) GXFilePrintPage; |
pData->pFilterEvent = (FilterEventProc) GXFilterEvent; |
pData->pCalculateIdleTime = (CalculateIdleTimeProc) GXCalculateIdleTime; |
pData->pAdjustCursor = (AdjustCursorProc) GXAdjustCursor; |
pData->pDragAddFlavors = (DragAddFlavorsProc) GXDragAddFlavors; |
pData->documentOutputsGX = true; |
pData->hasGrow = true; |
pData->minHSize = kMinGXDocSize + kScrollAreaWidth + kZoomControlsWidth + kToolControlWidth; |
pData->hScrollAmount = 10; |
pData->vScrollAmount = 10; |
pData->hScrollOffset = kScrollAreaWidth + kZoomControlsWidth + kToolControlWidth; |
// default the job info, which we need to have |
anErr = DoDefault(pData); |
nrequire(anErr, DoDefault); |
((GXDataPtr)pData)->thePrintFile = GXOpenPrintFile(pData->hPrint, &pData->fileSpec, fsRdWrPerm); |
anErr = GXGetJobError(pData->hPrint); |
nrequire(anErr, OpenPrintFile); |
/* |
* The assumption here is that the GXOpenPrintFile leaves the resfile on top. |
* We need this refnum so that any resource handles the translator gets will |
* match those that GXOpenPrintFile used for calls to GXNewFont. See the call |
* to GXDrawShape in GXUpdateWindow |
*/ |
((GXDataPtr)pData)->printFileRefNum = CurResFile(); |
// close down other paths to the file -- because we don't need them |
if (pData->resRefNum != -1) |
{ |
CloseResFile(pData->resRefNum); |
pData->resRefNum = -1; |
} |
if (pData->dataRefNum != -1) |
{ |
FSClose(pData->dataRefNum); |
pData->dataRefNum = -1; |
} |
// default to normal printing -- so if the user prints, we go to normal mode at first |
{ |
Collection jobCollection = GXGetJobCollection(pData->hPrint); |
gxJobInfo theInfo; |
long theSize = sizeof(theInfo); |
if (GetCollectionItem(jobCollection, gxJobTag, gxPrintingTagID, &theSize, &theInfo) == noErr) |
{ |
theInfo.priority = gxPrintJobASAP; |
AddCollectionItem(jobCollection, gxJobTag, gxPrintingTagID, theSize, &theInfo); |
} |
} |
// by default we have no pages |
((GXDataPtr)pData)->numberOfPages = GXCountPrintFilePages(((GXDataPtr)pData)->thePrintFile); |
((GXDataPtr)pData)->currentPage = 1; |
((GXDataPtr)pData)->zoomFactor = ff(1); |
((GXDataPtr)pData)->contentClickMode = kSelectionTool; |
anErr = GXGetJobError(pData->hPrint); |
if ( (anErr == noErr) && (((GXDataPtr)pData)->numberOfPages == 0) ) |
anErr = eDocumentContainsNoPages; |
nrequire(anErr, GXCountPrintFilePages); |
if (((GXDataPtr)pData)->numberOfPages > 1) |
pData->hScrollOffset += kPageControlsWidth; |
((GXDataPtr)pData)->pageAnnotations = (gxShape**) NewHandleClear( (((GXDataPtr)pData)->numberOfPages * sizeof(gxShape)) ); |
anErr = MemError(); |
if (anErr == noErr) |
anErr = LoadOrSaveAnnotations(pData, kLoadAnnotations); |
nrequire(anErr, FailedToAllocateAnnotation); |
// set up so we can draw inside of this window |
((GXDataPtr)pData)->parentViewPort = GXNewWindowViewPort((WindowPtr)pWindow); |
((GXDataPtr)pData)->childViewPort = GXNewViewPort(gxScreenViewDevices); |
GXSetViewPortParent(((GXDataPtr)pData)->childViewPort, ((GXDataPtr)pData)->parentViewPort); |
GXSetViewPortAttributes(((GXDataPtr)pData)->childViewPort, gxAlwaysGridPort); |
GXSetViewPortDither(((GXDataPtr)pData)->childViewPort, 4); |
// fetch the current page |
anErr = GetCurrentPage((GXDataPtr) pData, true); |
nrequire(anErr, GetCurrentPage); |
// if this document contains PostScript do a warning |
{ |
gxTranslatedDocumentInfo theInfo; |
long theSize = sizeof(theInfo); |
if ( |
(GetCollectionItem(GXGetJobCollection(pData->hPrint), |
gxTranslatedDocumentTag, |
gxPrintingTagID, |
&theSize, |
&theInfo |
) == noErr) && |
(theInfo.translatorInfo & gxContainsPostScript) |
) |
ConductErrorDialog(eDocumentContainsPS, cOpen, ok); |
} |
return(anErr); |
// EXCEPTION HANDLING |
GetCurrentPage: |
FailedToAllocateAnnotation: |
GXCountPrintFilePages: |
GXClosePrintFile( ((GXDataPtr)pData)->thePrintFile); |
OpenPrintFile: |
GXDisposeJob(pData->hPrint); |
DoDefault: |
return(anErr); |
} // GXMakeWindow |
// -------------------------------------------------------------------------------------------------------------- |
OSErr GXPreflightWindow(PreflightPtr pPreflightData) |
{ |
pPreflightData->continueWithOpen = true; |
pPreflightData->wantVScroll = true; |
pPreflightData->wantHScroll = true; |
pPreflightData->doZoom = true; |
pPreflightData->makeProcPtr = GXMakeWindow; |
pPreflightData->storageSize = sizeof(GXDataRecord); |
return(noErr); |
} // GXPreflightWindow |
// -------------------------------------------------------------------------------------------------------------- |
void GXGetFileTypes(OSType * pFileTypes, OSType * pDocumentTypes, short * numTypes) |
{ |
if (gMachineInfo.haveGX) |
{ |
pFileTypes[*numTypes] = 'sjob'; |
pDocumentTypes[*numTypes] = kGXWindow; |
(*numTypes)++; |
pFileTypes[*numTypes] = 'tjob'; |
pDocumentTypes[*numTypes] = kGXWindow; |
(*numTypes)++; |
pFileTypes[*numTypes] = 'rjob'; |
pDocumentTypes[*numTypes] = kGXWindow; |
(*numTypes)++; |
pFileTypes[*numTypes] = 'qjob'; |
pDocumentTypes[*numTypes] = kGXWindow; |
(*numTypes)++; |
} |
} // GXGetFileTypes |
Copyright © 2003 Apple Computer, Inc. All Rights Reserved. Terms of Use | Privacy Policy | Updated: 2003-01-14