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.
PictDocument.c
/* |
File: PictDocument.c |
Contains: This source file is the most important part of this program because it shows |
all the code needed to maintain Picture Documents. A Picture Document is a |
window which displays an off-screen image and lets you paint into it, and |
these two activities show how to use graphics environments to draw off screen |
and copy the off-screen image to the window on the screen. |
Written by: Forrest Tanaka |
Copyright: Copyright © 1988-1999 by Apple Computer, Inc., All Rights Reserved. |
You may incorporate this Apple sample source code into your program(s) without |
restriction. This Apple sample source code has been provided "AS IS" and the |
responsibility for its operation is yours. You are not permitted to redistribute |
this Apple sample source code as "Apple sample source 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 source |
code, but that you've made changes. |
Change History (most recent first): |
7/13/1999 Karl Groethe Updated for Metrowerks Codewarror Pro 2.1 |
*/ |
/******************************************************************************\ |
* Header Files |
\******************************************************************************/ |
/* System header files needed by MPW C */ |
#ifndef THINK_C |
#include <Errors.h> |
#include <Menus.h> |
#include <Resources.h> |
#include <Windows.h> |
#endif |
#include <GestaltEqu.h> |
#include <Palettes.h> |
#include <ColorPicker.h> |
#include <QDOffscreen.h> |
/* Header files specific to this program */ |
#include "PictDocument.h" |
#include "EmergMem.h" |
#include "ColorReset.h" |
#include "MenuHandler.h" |
#include "WindowPositioner.h" |
#ifndef topLeft |
#define topLeft(r) (((Point *) &(r))[0]) |
#endif |
#ifndef botRight |
#define botRight(r) (((Point *) &(r))[1]) |
#endif |
/******************************************************************************\ |
* Private Constants |
\******************************************************************************/ |
/* Picture Document window constants */ |
#define rPictDocWindID 128 /* Resource ID of Picture Document WIND resource */ |
#define rScrollBarID 128 /* Resource ID of scroll bar CNTL resource */ |
#define kDocWKind 128 /* windowKind field of Picture Document windows */ |
#define kMinWindowSize 64 /* Minimum size of the window in pixels */ |
/* PICT file constants */ |
#define kPictFileHeaderSize 512 /* Number of bytes in PICT file header */ |
#define kFileCreator 'CLIM' /* Creator code for this application */ |
#define kFileType 'PICT' /* File type for this appÕs documents */ |
/* Off-screen Constants */ |
#define kMaxRowBytes 0x3FFE /* Maximum number of bytes in a row of pixels */ |
#define kDefaultRes 0x00480000 /* Default resolution is 72 DPI; Fixed type */ |
#define kITabRes 4 /* Inverse-table resolution */ |
/* Miscellaneous constants */ |
#define kPaintRadius 8 /* Radius of a drop of paint in pixels */ |
/******************************************************************************\ |
* Private Types |
\******************************************************************************/ |
/* Picture Document information */ |
typedef struct |
{ |
GWorldPtr image; /* Pointer to image in off-screen GWorld */ |
Rect windowRect; /* Rectangle of window except for scroll bars */ |
Rect destRect; /* Rectangle of image in window */ |
RGBColor foreground; /* Color of foreground */ |
RGBColor background; /* Color of background */ |
ControlHandle vScrollBar; /* Horizontal scroll bar */ |
ControlHandle hScrollBar; /* Vertical scroll bar */ |
FSSpec file; /* File spec of Picture DocumentÕs PICT file */ |
short fileRef; /* File ref # of Picture DocumentÕs PICT file */ |
Boolean dithering; /* True if image should be dithered */ |
} PictDocInfoRec, *PictDocInfoPtr, **PictDocInfoHnd; |
/* Basic picture information */ |
typedef struct |
{ |
CTabHandle colors; /* Handle to color table of deepest pixel map */ |
short depth; /* Max depth for all pixmaps (in the picture) */ |
Rect frame; /* Picture frame rect (contains entire picture) */ |
} PictureInfoRec; |
/******************************************************************************\ |
* Prototypes of Private Functions |
\******************************************************************************/ |
static OSErr CreatePictDoc( |
Rect *pictureRect, |
short pictureDepth, |
CTabHandle pictureClut, |
WindowPtr *retDoc); |
static void ScrollPictDoc( |
WindowPtr docWindow, |
short hScrollDelta, |
short vScrollDelta); |
void ResizePictDoc( |
WindowPtr docWindow); |
OSErr CreateOffScreen( |
Rect *bounds, |
short depth, |
CTabHandle colors, |
CGrafPtr *retPort, |
GDHandle *retGDevice); |
OSErr SetUpPixMap( |
short depth, |
Rect *bounds, |
CTabHandle colors, |
short bytesPerRow, |
PixMapHandle aPixMap); |
OSErr CreateGDevice( |
PixMapHandle basePixMap, |
GDHandle *retGDevice); |
void DisposeOffScreen( |
CGrafPtr doomedPort, |
GDHandle doomedGDevice); |
OSErr GetPictureInfo( |
short pictFileRef, |
PictureInfoRec *retPictInfo); |
OSErr DrawFilePicture( |
short pictFileRef, |
Rect *destRect); |
OSErr OpenFilePicture( |
short pictFileRef, |
Rect *sourceRect); |
OSErr CloseFilePicture(void); |
/******************************************************************************\ |
* Global Variables |
\******************************************************************************/ |
PictureInfoRec gPictureInfo; /* Information about a PICT file */ |
PicHandle gSpoolPicture; /* Temporary picture used to spool from PICT file */ |
QDProcsPtr gSavedProcs; /* Saves existing QDProcs; used when spooling out */ |
CQDProcs gCustomProcs; /* Customized bottlenecks to spool to PICT file */ |
short gPictFileRef; /* File reference number of a PICT file */ |
short gPictureSize; /* Size of picture in bytes */ |
/******************************************************************************\ |
* NAME & SYNOPSIS: |
* FindPictDoc: Find the Picture Document window for a specific file |
* |
* PARAMETERS: |
* See PictDocument.h |
* |
* DEFINITION: |
* See PictDocument.h |
* |
* DESCRIPTION: |
* Each Picture Document window in the window list is examined to see whether it |
* has a corresponding disk file. The fileRef field of the Picture Document |
* information record is non-zero if the Picture Document has a disk file |
* associated with it. If there is a disk file, then EqualFSSpec is called to |
* see if the FSSpec that I saved in the documentÕs info record is the same as |
* the one passed in fileSpec. If they are, then a pointer to the window is |
* returned. Otherwise, the loop goes to the next Picture Document window, if |
* there is one. |
* |
* See ColorReset.h for a definition of EqualFSSpec. |
* |
* RETURN VALUES: |
* See PictDocument.h |
\******************************************************************************/ |
WindowPtr FindPictDoc( |
FSSpecPtr fileSpec) /* Specification of file to search for */ |
{ |
WindowPtr pictDocWindow; /* Pointer to Picture Document being tested */ |
PictDocInfoHnd pictDocInfo; /* Handle to Picture Document info rec */ |
Boolean foundDoc; /* True if found Pict Doc w/ same FSSpec */ |
/* Get a pointer to the first Picture Document window in the window list */ |
pictDocWindow = NextPictDocWindow( nil ); |
/* Keep searching until found or at end of list */ |
foundDoc = false; |
while (pictDocWindow != nil && !foundDoc) |
{ |
/* Only have to check FSSpecs if document has a corresponding file */ |
pictDocInfo = (PictDocInfoHnd)GetWRefCon( pictDocWindow ); |
if ((**pictDocInfo).fileRef != 0) |
{ |
/* See if the Picture DocumentÕs file is same as fileSpec */ |
HLock( (Handle)pictDocInfo ); |
foundDoc = EqualFSSpec( fileSpec, &(**pictDocInfo).file ); |
HUnlock( (Handle)pictDocInfo ); |
/* If FSSpecs arenÕt the same, then go to next Picture Document */ |
if (!foundDoc) |
pictDocWindow = NextPictDocWindow( pictDocWindow ); |
} |
} |
return pictDocWindow; |
} |
/******************************************************************************\ |
* NAME & SYNOPSIS: |
* NextPictDocWindow: Return a pointer to the next Picture Document window |
* |
* PARAMETERS: |
* See PictDocument.h |
* |
* DEFINITION: |
* See PictDocument.h |
* |
* DESCRIPTION: |
* NextPictDocWindow goes through every window in the window list thatÕs behind |
* the window specified by aWindow until either a Picture Document window is |
* found or until the end of the window list is reached. If aWindow is nil, then |
* the search starts with the front window. |
* |
* RETURN VALUES: |
* See PictDocument.h |
\******************************************************************************/ |
WindowPtr NextPictDocWindow( |
WindowPtr aWindow) /* Window to start search from, or nil if front */ |
{ |
/* Start search from next window, or front window if aWindow is nil */ |
if (aWindow == nil) |
aWindow = FrontWindow(); |
else |
aWindow = (WindowPtr)((WindowPeek)aWindow)->nextWindow; |
/* Search until Picture Document wind found or end of wind list reached */ |
while (aWindow != nil && !IsPictDocWindow( aWindow )) |
aWindow = (WindowPtr)((WindowPeek)aWindow)->nextWindow; |
return aWindow; |
} |
/******************************************************************************\ |
* NAME & SYNOPSIS: |
* IsPictDocWindow: Is a window a Picture Document window? |
* |
* PARAMETERS: |
* See PictDocument.h |
* |
* DEFINITION: |
* See PictDocument.h |
* |
* DESCRIPTION: |
* When I create a window, I store a code for that kind of window in the |
* windowKind field. IsPictDocWindow checks the windowKind field of the given |
* window against the constant kDocWKind. If theyÕre equal, then aWindow |
* must be a Picture Document window. |
* |
* RETURN VALUES: |
* See PictDocument.h |
\******************************************************************************/ |
Boolean IsPictDocWindow ( |
WindowPtr aWindow) /* Pointer to the window being tested */ |
{ |
return ((WindowPeek)aWindow)->windowKind == kDocWKind; |
} |
/******************************************************************************\ |
* NAME & SYNOPSIS: |
* DrawPictDoc: Draw the contents of a Picture Document |
* |
* PARAMETERS: |
* See PictDocument.h |
* |
* DEFINITION: |
* See PictDocument.h |
* |
* DESCRIPTION: |
* The image for Picture Documents is stored in an off-screen GrafPort, and its |
* GrafPtr is stored in the information record. This GrafPtr is retrieved, and |
* itÕs used to CopyBits the GrafPort to the window. ItÕs possible that not all |
* of the image can be copied to the window. For example, part of the window |
* might be covered by another window. In this case, the visRgn of the window |
* takes care of clipping out the undesireable parts of the original image. The |
* other case in which part of the image shouldnÕt be drawn is if part of the |
* image is scrolled out of the window. The visRgn of the window takes care of |
* part of this, but we still have to make sure that the image doesnÕt draw |
* itself over the scroll bar areas of the window in case the scroll bars are |
* hidden, which they are if the window is inactive. To take care of this, the |
* destination rectangle which is the rectangle that the off-screen image is |
* copied to, is first intersected with the window rectangle, which is the |
* rectangle of the window except for the scroll bars. This is used as the |
* destination rectangle to CopyBits. Then this rectangle is offset by the top- |
* left corner of the original destination rectangle, and this is used as the |
* source rectangle to CopyBits. The off-screen image is then copied to the |
* window. |
* |
* RETURN VALUES: |
* See PictDocument.h |
\******************************************************************************/ |
void DrawPictDoc( |
WindowPtr docWindow) /* Ptr to Picture Document window being drawn */ |
{ |
PictDocInfoHnd pictDocInfo; /* Handle to Picture Document information rec */ |
GWorldPtr image; /* Pointer to the off-screen image */ |
Rect destRect; /* Rectangle to copy image into */ |
Rect sourceRect; /* Rectangle to copy image from */ |
Rect windowRect; /* Rect of the window except for scroll bars */ |
short mode; /* Drawing mode to use */ |
/* Get a pointer to the off-screen image and the window rectangle */ |
pictDocInfo = (PictDocInfoHnd)GetWRefCon( docWindow ); |
image = (**pictDocInfo).image; |
windowRect = (**pictDocInfo).windowRect; |
/* Calculate the rectangle to copy the image to */ |
destRect = (**pictDocInfo).destRect; |
(void)SectRect( &destRect, &windowRect, &destRect ); |
/* Calculate the rectangle to copy the image from */ |
sourceRect = destRect; |
OffsetRect( &sourceRect, -(**pictDocInfo).destRect.left, |
-(**pictDocInfo).destRect.top ); |
/* Specify the drawing mode to use */ |
mode = srcCopy; |
if ((**pictDocInfo).dithering) |
mode |= ditherCopy; |
/* Draw the off-screen image to the screen */ |
EraseRect( &docWindow->portRect ); |
CopyBits( &((GrafPtr)image)->portBits, &docWindow->portBits, |
&sourceRect, &destRect, |
mode, nil ); |
/* Draw the grow box */ |
DrawGrowIcon( docWindow ); |
/* Draw the scroll bars */ |
DrawControls( docWindow ); |
} |
/******************************************************************************\ |
* NAME & SYNOPSIS: |
* ClickPictDoc: Handle a mouse click in a Picture Document window |
* |
* PARAMETERS: |
* See PictDocument.h |
* |
* DEFINITION: |
* See PictDocument.h |
* |
* DESCRIPTION: |
* The first really important call in this routine is FindControl, which is the |
* toolbox call which tells you which control and which part of the control the |
* mouse was clicked in. If it returns zero, then the mouse was clicked outside |
* of any control, and so we let the user paint into the document. |
* |
* Painting into the document is done within a loop which iterates as long as the |
* mouse button is held down. While this is the case, the current mouse position |
* is retrieved with a call to GetMouse. If the mouse position changed from the |
* previous iterationÕs mouse position, then the mouse position is offset to take |
* into account the currently-scrolled position, and then the current port is set |
* to the documentÕs off-screen GrafPort. Then, PaintOval is called which draws |
* a drop of paint into the off-screen GrafPort. |
* |
* The off-screen image then has to be copied to the window so that the user can |
* see the new drop of paint. This is done by first seeing if the drop of paint |
* can actually be seen in the window in the currently-scrolled position. If it |
* can, then the rectangle of the drop of paint is offset to take into account |
* the currently-scrolled position. Then the current port is set to the document |
* window, and CopyBits is called to copy the new drop of paint to the document |
* window. |
* |
* Finally, the mouse position is remembered and the loop iterates again if the |
* mouse button is still held down. |
* |
* If FindControl indicates that the mouse click was in the thumb of a scroll |
* bar, TrackControl is called which lets the user move the thumb around until |
* the user releases the mouse button. Then, the difference between the old and |
* new scroll bar position is calculated which indicates the number of pixels |
* that the document must be scrolled. ScrollPictDoc, defined below, is then |
* called to scroll the documentÕs image, update the scrolled-in part of the |
* image, and update the document information record to reflect the new scrolled |
* position. |
* |
* If FindControl indicates that the mouse click was in the up arrow, down arrow, |
* page up, or page down areas of either scroll bar, then TrackControl is called |
* to scroll the document appropriately. The ScrollActionProc routine, defined |
* below, handles the logistics of scrolling in this case. |
* |
* RETURN VALUES: |
* See PictDocument.h |
\******************************************************************************/ |
void ClickPictDoc( |
WindowPtr docWindow, /* Picture Document window that was clicked */ |
EventRecord *clickEvent) /* Mouse click event */ |
{ |
PictDocInfoHnd pictDocInfo; /* Handle to Picture Document info rec */ |
GWorldPtr image; /* Pointer to the off-screen image */ |
GDHandle savedDevice; /* Saves default GDevice */ |
Rect paintRect; /* Rectangle to draw paint into */ |
Rect windowPaintRect; /* Rectangle to draw paint into */ |
Rect windowRect; /* Window rect except for scroll bars */ |
Rect destRect; /* Rectangle of image in window */ |
Point newPosition; /* New pos of mouse click; local coords */ |
Point oldPosition; /* Old pos of mouse click; local coords */ |
ControlHandle scrollBar; /* Handle to the clicked scroll bar */ |
short partNumber; /* Part # of clicked part of control */ |
short scrollDelta; /* Number of pixels to scroll */ |
savedDevice = GetGDevice(); |
/* Get information about the Picture Document */ |
pictDocInfo = (PictDocInfoHnd)GetWRefCon( docWindow ); |
image = (**pictDocInfo).image; |
windowRect = (**pictDocInfo).windowRect; |
destRect = (**pictDocInfo).destRect; |
/* Get the mouse click position */ |
SetPort( docWindow ); |
newPosition = clickEvent->where; |
GlobalToLocal( /*×*/&newPosition ); |
/* Find whether the mouse was in a control */ |
partNumber = FindControl( newPosition, docWindow, /*<*/&scrollBar ); |
switch (partNumber) |
{ |
case 0: |
/* Clicked outside of any control; see if it was in the image */ |
if (PtInRect( newPosition, &windowRect )) |
{ |
/* Click in image; paint while mouse button is held down */ |
oldPosition.v = oldPosition.h = -32767; |
while (StillDown()) |
{ |
/* Only do something if the mouse moved */ |
if (!EqualPt( newPosition, oldPosition )) |
{ |
/* Need to offset paint brush for scrolled position */ |
SubPt( topLeft( destRect ), /*×*/&newPosition ); |
SetRect( /*<*/&paintRect, newPosition.h - kPaintRadius, |
newPosition.v - kPaintRadius, |
newPosition.h + kPaintRadius, |
newPosition.v + kPaintRadius ); |
/* Drop some paint into the off-screen image */ |
SetGWorld( image, nil ); |
PaintOval( &paintRect ); |
/* Offset brush back to window position */ |
AddPt( topLeft( destRect ), /*×*/&newPosition ); |
/* Calc rect in window for to brush rect in image */ |
windowPaintRect = paintRect; |
OffsetRect( &windowPaintRect, destRect.left, |
destRect.top ); |
/* Only copy if some part of brush within image */ |
if (SectRect( &windowPaintRect, &windowRect, |
&windowPaintRect )) |
{ |
/* Make clipped paint rect in off-screen image */ |
paintRect = windowPaintRect; |
OffsetRect( &paintRect, -destRect.left, |
-destRect.top ); |
/* Copy painted off-screen image to the screen */ |
SetGWorld( (CGrafPtr)docWindow, nil ); |
CopyBits( &((GrafPtr)image)->portBits, &docWindow->portBits, |
&paintRect, &windowPaintRect, |
srcCopy, nil ); |
} |
/* Remember the new mouse position */ |
oldPosition = newPosition; |
} |
/* Get the new position of the mouse */ |
SetPort( docWindow ); |
GetMouse( /*<*/&newPosition ); |
} |
} |
break; |
case kControlIndicatorPart: |
/* Mouse in thumb of scroll bar; get existing control value */ |
scrollDelta = GetControlValue( scrollBar ); |
/* Track mouse in thumb until mouse button is released */ |
partNumber = TrackControl( scrollBar, newPosition, nil ); |
if (partNumber != 0) |
{ |
/* Find diff between old and new scroll bar values */ |
scrollDelta -= GetControlValue( scrollBar ); |
if (scrollDelta != 0) |
{ |
if (scrollBar == (**pictDocInfo).vScrollBar) |
ScrollPictDoc( docWindow, 0, scrollDelta ); |
else |
ScrollPictDoc( docWindow, scrollDelta, 0 ); |
} |
} |
break; |
case kControlUpButtonPart: |
case kControlDownButtonPart: |
case kControlPageUpPart: |
case kControlPageDownPart: |
TrackControl( scrollBar, newPosition, gActionProc); |
break; |
default: |
break; |
} |
} |
/******************************************************************************\ |
* NAME & SYNOPSIS: |
* ScrollActionProc: Handle a click in a scroll bar (except for thumb) |
* |
* PARAMETERS: |
* ControlHandle control: Control that received the mouse click |
* short part: Part number of the clicked control part |
* |
* DEFINITION: |
* ScrollActionProc is called by the Control Manager when TrackControl is called |
* in the ClickPictDoc function above. It handles scrolling when the user clicks |
* in the scroll arrows or page areas of the scroll bar. The document is |
* scrolled by the appropriate amount. |
* |
* DESCRIPTION: |
* ScrollActionProc first checks to see which part of the scroll bar was clicked. |
* If it was in either of the arrows, then the desired scroll amount is one |
* pixel. If it was in either of the paging areas, then the desired scroll |
* amount is 32 pixels. The current value of the clicked scroll bar is then |
* adjusted by the desired scroll amount, and the result is compared against the |
* limits of the scroll barÕs values. If the new value is beyond either limit, |
* then itÕs pinned back into the limits. Then the real amount to scroll is |
* calculated simply by subtracting the new scroll value from the old scroll |
* value, and ScrollPictDoc (defined below) is called to scroll the Picture |
* Document window. |
* |
* RETURN VALUES: |
* None |
\******************************************************************************/ |
pascal void ScrollActionProc( |
ControlHandle control, /* Handle to clicked control */ |
short part) /* Part number of clicked control part */ |
{ |
PictDocInfoHnd pictDocInfo; /* Handle to Picture Document info rec */ |
WindowPtr docWindow; /* Clicked Picture Document window */ |
Rect windowRect; /* Window rect except for scroll bars */ |
Rect destRect; /* Rectangle of image in window */ |
short scrollDelta; /* Number of pixels to scroll by */ |
short oldValue; /* Value of scroll bar before scrolling */ |
short newValue; /* Value of scroll bar after scrolling */ |
short maxValue; /* Maximum value of the scroll bar */ |
/* Get information about the Picture Document */ |
docWindow = (**control).contrlOwner; |
pictDocInfo = (PictDocInfoHnd)GetWRefCon( docWindow ); |
windowRect = (**pictDocInfo).windowRect; |
destRect = (**pictDocInfo).destRect; |
/* Only process if the part # isnÕt zero */ |
if (part != 0) |
{ |
/* Decide scroll amount based on part of control that was clicked */ |
switch (part) |
{ |
case kControlUpButtonPart: |
scrollDelta = 1; |
break; |
case kControlDownButtonPart: |
scrollDelta = -1; |
break; |
case kControlPageUpPart: |
scrollDelta = 32; |
break; |
case kControlPageDownPart: |
scrollDelta = -32; |
break; |
default: |
scrollDelta = 0; |
break; |
} |
/* Only do something if weÕre actually scrolling */ |
if (scrollDelta != 0) |
{ |
/* Get the current scroll bar state */ |
maxValue = GetControlMaximum( control ); |
oldValue = GetControlValue( control ); |
/* Calculate the new scroll bar value pinned to the limits */ |
newValue = oldValue - scrollDelta; |
if (newValue < 0) |
newValue = 0; |
else if (newValue > maxValue) |
newValue = maxValue; |
/* Only scroll if the old and new values are different */ |
if (oldValue != newValue) |
{ |
/* Set the new value of the scroll bar */ |
SetControlValue( control, newValue ); |
/* Scroll by difference between old and new scroll bar values */ |
scrollDelta = oldValue - newValue; |
if (control == (**pictDocInfo).vScrollBar) |
ScrollPictDoc( docWindow, 0, scrollDelta ); |
else |
ScrollPictDoc( docWindow, scrollDelta, 0 ); |
} |
} |
} |
} |
/******************************************************************************\ |
* NAME & SYNOPSIS: |
* ScrollPictDoc: Scroll a Picture Document windowÕs image |
* |
* PARAMETERS: |
* WindowPtr docWindow: Pointer to Picture Document window to scroll |
* short vScrollDelta: Number of pixels to scroll vertically |
* short hScrollDelta: Number of pixels to scroll horizontally |
* |
* DEFINITION: |
* ScrollPictDoc scrolls the picture document window specified by the docWindow |
* parameter by vScrollDelta pixels vertically and hScrollDelta pixels |
* horizontally. The part of the window thatÕs scrolled in is updated, so no |
* updating is needed outside of ScrollPictDoc. |
* |
* DESCRIPTION: |
* ScrollRect is called to scroll the Picture DocumentÕs image by the specified |
* amount. The scrolled-in part is then redrawn with a call to CopyBits. The |
* destRect field of the Picture Document information record keeps track of the |
* scrolled position of the image, so itÕs updated to reflect the new scrolled |
* position. |
* |
* RETURN VALUES: |
* None |
\******************************************************************************/ |
static void ScrollPictDoc( |
WindowPtr docWindow, /* Pointer to document window to scroll */ |
short hScrollDelta, /* Number of pixels to scroll horizontally */ |
short vScrollDelta) /* Number of pixels to scroll vertically */ |
{ |
PictDocInfoHnd pictDocInfo; /* Handle to Picture Document info rec */ |
RgnHandle updateRegion; /* Region covering scrolled-in area */ |
Rect windowRect; /* Rect of window except for scroll bars */ |
Rect destRect; /* New destination rectangle */ |
GWorldPtr image; /* Off-screen document image */ |
/* Get the window rectangle and destination rectangle */ |
pictDocInfo = (PictDocInfoHnd)GetWRefCon( docWindow ); |
windowRect = (**pictDocInfo).windowRect; |
destRect = (**pictDocInfo).destRect; |
image = (**pictDocInfo).image; |
/* Scroll the image by the specified amount */ |
updateRegion = NewRgn(); |
ScrollRect( &windowRect, hScrollDelta, vScrollDelta, updateRegion ); |
/* Update the destination rectangle to the new scrolled position */ |
OffsetRect( &destRect, hScrollDelta, vScrollDelta ); |
(**pictDocInfo).destRect = destRect; |
/* Update the scrolled-in part of the window */ |
CopyBits( &((GrafPtr)image)->portBits, &docWindow->portBits, |
&image->portRect, &destRect, |
srcCopy, updateRegion ); |
/* Get rid of the update region */ |
DisposeRgn( updateRegion ); |
} |
/******************************************************************************\ |
* NAME & SYNOPSIS: |
* GrowPictDoc: Let the user change the size of a Picture Document window |
* |
* PARAMETERS: |
* See PictDocument.h |
* |
* DEFINITION: |
* See PictDocument.h |
* |
* DESCRIPTION: |
* GrowWindow is called with a boundary rectangle that specifies that the window |
* has a minimum size of kMinWindowSize (defined at the top of this source file) |
* and a maximum size thatÕs the size of the image. After the user releases the |
* mouse button, SizeWindow is called to change the size of the window, and |
* ResizePictDoc (defined below) is called to update the Picture Document to the |
* new size. |
* |
* RETURN VALUES: |
* See PictDocument.h |
\******************************************************************************/ |
void GrowPictDoc( |
WindowPtr docWindow, /* Picture Document window thatÕs to be grown */ |
EventRecord *clickEvent) /* Mouse down event */ |
{ |
PictDocInfoHnd pictDocInfo; /* Handle to Picture Document info rec */ |
Rect growBounds; /* Window can be dragged over this rectangle */ |
Point newSize; /* New size of the new window */ |
pictDocInfo = (PictDocInfoHnd)GetWRefCon( docWindow ); |
growBounds = (**pictDocInfo).image->portRect; |
growBounds.left = growBounds.top = kMinWindowSize; |
growBounds.right += kScrollBarWidth; |
growBounds.bottom += kScrollBarWidth; |
/* Let the user resize the window to any size */ |
*((long *)&newSize) = GrowWindow( docWindow, clickEvent->where, |
&growBounds ); |
/* If the user actually changed the size of the window, resize the window */ |
if (*((long *)&newSize) != 0) |
{ |
SizeWindow( docWindow, newSize.h, newSize.v, true ); |
ResizePictDoc( docWindow ); |
} |
} |
/******************************************************************************\ |
* NAME & SYNOPSIS: |
* ResizePictDoc: Update a picture document window to a new size |
* |
* PARAMETERS: |
* WindowPtr docWindow: Picture document window that was resized |
* |
* DEFINITION: |
* ResizePictDoc updates the Picture Document window specified by the docWindow |
* to a new size. This routine is called right after the size of docWindow has |
* been changed. The act of updating the Picture Document window involves moving |
* the scroll bars to the edge of the window and scrolling the document image. |
* The image has to be scrolled when the window is grown in case the bottom or |
* right edge of the window goes below or to the right of the image, in which |
* case the bottom or right edges of the image has to ÒchaseÓ the bottom or right |
* edges of the window, and that means scrolling. |
* |
* DESCRIPTION: |
* The first major thing thatÕs done is a new destination rectangle is calculated |
* in case the document has to be scrolled as described in the definition. There |
* are three conditions that have to be met before scrolling can happen: |
* 1) The upper-left corner of destRect must not be (0,0), meaning that the |
* documentÕs image is scrolled from its original position. |
* 2) The window has become bigger. |
* 3) The windowÕs rectangle has moved below or to the right of the image in |
* the window. |
* If all three of these conditions are met for either the horizontal or |
* vertical cases, a new destRect is calculated. If this new destRect is |
* different from the old destRect, ScrollPictDoc (defined above) is called to |
* scroll the image to the new position. |
* |
* After this, the windowRect field of the Picture Document information record |
* is updated to the new size of the window. Then, the maximum values of the |
* scroll bars are set to the number of pixels in the horizontal or vertical |
* direction that canÕt be seen. And then, the old position of the scroll icon |
* is invalidated so that itÕll be erased with the documentÕs image the next time |
* the window is updated. |
* |
* Both of the scroll bars are then moved along the bottom and right edges of the |
* window, and the new position of the grow icon is invalidated so that itÕs |
* redrawn in case the window was made smaller. Finally, the rectangles of the |
* scroll bars are validated so that they wonÕt be redrawn in the next update |
* event. |
* |
* RETURN VALUES: |
* None |
\******************************************************************************/ |
static void ResizePictDoc( |
WindowPtr docWindow) /* Picture document window that was resized */ |
{ |
PictDocInfoHnd pictDocInfo; /* Handle to Picture Document information rec */ |
ControlHandle vScrollBar; /* Vertical scroll bar */ |
ControlHandle hScrollBar; /* Horizontal scroll bar */ |
Rect windowRect; /* Covers part of window that contains image */ |
Rect newWindowRect; /* Covers all of window except scroll bars */ |
Rect scrollRect; /* Rectangle of scroll bar */ |
Rect destRect; /* Rectangle of to draw image into */ |
Rect newDestRect; /* Rectangle of to draw image into */ |
CGrafPtr image; /* Off-screen document image */ |
short remaining; /* # rows, columns of pixels not visible */ |
SetPort( docWindow ); |
/* Get the Picture DocumentÕs information */ |
pictDocInfo = (PictDocInfoHnd)GetWRefCon( docWindow ); |
vScrollBar = (**pictDocInfo).vScrollBar; |
hScrollBar = (**pictDocInfo).hScrollBar; |
image = (**pictDocInfo).image; |
destRect = (**pictDocInfo).destRect; |
windowRect = (**pictDocInfo).windowRect; |
/* Find the new window document area */ |
newWindowRect = docWindow->portRect; |
newWindowRect.right -= kScrollBarWidth - 1; |
newWindowRect.bottom -= kScrollBarWidth - 1; |
/* Find new destRect in case window growing causes scrolling */ |
newDestRect = destRect; |
if (newDestRect.left != 0 && |
(newWindowRect.right - newWindowRect.left) > |
(windowRect.right - windowRect.left) && |
newWindowRect.right > newDestRect.right) |
OffsetRect( /*×*/&newDestRect, (newWindowRect.right - windowRect.right) |
- (newDestRect.right - windowRect.right), 0 ); |
if (newDestRect.top != 0 && |
(newWindowRect.bottom - newWindowRect.top) > |
(windowRect.bottom - windowRect.top) && |
newWindowRect.bottom > newDestRect.bottom) |
OffsetRect( /*×*/&newDestRect, 0, (newWindowRect.bottom - |
windowRect.bottom) - (newDestRect.bottom - windowRect.bottom) ); |
/* If the new scrolled position has changed, update the windowÕs image */ |
if (!EqualRect( &newDestRect, &destRect)) |
ScrollPictDoc( docWindow, newDestRect.left - destRect.left, |
newDestRect.top - destRect.top ); |
/* Set up the rectangles for scroll bar calculations */ |
(**pictDocInfo).windowRect = newWindowRect; |
/* Calc # rows of image not visible; set as max value of scroll bar */ |
remaining = image->portRect.bottom - newWindowRect.bottom; |
if (remaining < 0) |
remaining = 0; |
SetControlMaximum( vScrollBar, remaining ); |
/* Calc # cols of image not visible; set as max value of scroll bar */ |
remaining = image->portRect.right - newWindowRect.right; |
if (remaining < 0) |
remaining = 0; |
SetControlMaximum( hScrollBar, remaining ); |
/* Invalidate the old position of the grow icon */ |
SetRect( &scrollRect, (**hScrollBar).contrlRect.right, |
(**vScrollBar).contrlRect.bottom, |
(**vScrollBar).contrlRect.right, |
(**hScrollBar).contrlRect.bottom ); |
InvalRect( &scrollRect ); |
/* Move the scroll bars along the edges of the window */ |
HideControl( vScrollBar ); |
HideControl( hScrollBar ); |
MoveControl( vScrollBar, newWindowRect.right, newWindowRect.top - 1 ); |
MoveControl( hScrollBar, newWindowRect.left - 1, newWindowRect.bottom ); |
SizeControl( vScrollBar, kScrollBarWidth, newWindowRect.bottom - |
newWindowRect.top + 2 ); |
SizeControl( hScrollBar, newWindowRect.right - newWindowRect.left + 2, |
kScrollBarWidth ); |
ShowControl( vScrollBar ); |
ShowControl( hScrollBar ); |
/* Invalidate the new position of the grow icon */ |
SetRect( &scrollRect, (**hScrollBar).contrlRect.right, |
(**vScrollBar).contrlRect.bottom, |
(**vScrollBar).contrlRect.right, |
(**hScrollBar).contrlRect.bottom ); |
InvalRect( &scrollRect ); |
/* Validate the new scroll bar areas */ |
scrollRect = (**vScrollBar).contrlRect; |
ValidRect( &scrollRect ); |
scrollRect = (**hScrollBar).contrlRect; |
ValidRect( &scrollRect ); |
} |
/******************************************************************************\ |
* NAME & SYNOPSIS: |
* ActivatePictDoc: Activate or deactivate a Picture Document window |
* |
* PARAMETERS: |
* See PictDocument.h |
* |
* DEFINITION: |
* See PictDocument.h |
* |
* DESCRIPTION: |
* If the Picture Document window is becoming active, the scroll bars are shown. |
* If itÕs becoming inactive, the scroll bars are hidden. Because hiding |
* controls causes the control rectangle to be invalidated, ActivatePictDoc |
* validates them again to avoid a very slight flicker in the lines that delimit |
* the scroll bar areas. |
* |
* DrawGrowIcon is called to show or hide the grow icon. The Window Manager |
* automatically decides whether to show or hide the grow icon. |
* |
* RETURN VALUES: |
* See PictDocument.h |
\******************************************************************************/ |
void ActivatePictDoc( |
WindowPtr docWindow, /* Pointer to Doc window being updated */ |
Boolean becomingActive) /* True if Doc wind is becoming active */ |
{ |
PictDocInfoHnd pictDocInfo; /* Handle to Picture Document information rec */ |
ControlHandle vScrollBar; /* Vertical scroll bar */ |
ControlHandle hScrollBar; /* Horizontal scroll bar */ |
Rect scrollRect; /* Rectangle of the scroll bars */ |
/* Get the scroll bars of the window */ |
pictDocInfo = (PictDocInfoHnd)GetWRefCon( docWindow ); |
vScrollBar = (**pictDocInfo).vScrollBar; |
hScrollBar = (**pictDocInfo).hScrollBar; |
/* Show scroll bars if becoming active; hide if becoming inactive */ |
if (becomingActive) |
{ |
ShowControl( vScrollBar ); |
ShowControl( hScrollBar ); |
} |
else |
{ |
HideControl( vScrollBar ); |
HideControl( hScrollBar ); |
/* To avoid a slight flicker, validate the scroll bar rectangles */ |
SetPort( docWindow ); |
scrollRect = (**vScrollBar).contrlRect; |
ValidRect( &scrollRect ); |
scrollRect = (**hScrollBar).contrlRect; |
ValidRect( &scrollRect ); |
} |
/* Show or hide the grow icon */ |
DrawGrowIcon( docWindow ); |
} |
/******************************************************************************\ |
* NAME & SYNOPSIS: |
* FixPictDocMenus: Dim, undim, check, or uncheck menus for Picture Documents |
* |
* PARAMETERS: |
* See PictDocument.h |
* |
* DEFINITION: |
* See PictDocument.h |
* |
* DESCRIPTION: |
* The Close and Save AsÉÊitems in the File menu are enabled when a Picture |
* Document window is active, as is the Choose ColorÉ item in the Colors menu. |
* |
* RETURN VALUES: |
* See PictDocument.h |
\******************************************************************************/ |
void FixPictDocMenus( |
WindowPtr docWindow) /* Pointer to active Picture Document window */ |
{ |
#pragma unused(docWindow) |
MenuHandle aMenu; /* Handle to the menus being udpated */ |
/* Set items in the File menu */ |
aMenu = GetMenuHandle( mFile ); |
EnableItem( aMenu, iClose ); |
EnableItem( aMenu, iSaveAs ); |
} |
/******************************************************************************\ |
* NAME & SYNOPSIS: |
* DoOpenPictDoc: Open a new Picture Document |
* |
* PARAMETERS: |
* See PictDocument.h |
* |
* DEFINITION: |
* See PictDocument.h |
* |
* DESCRIPTION: |
* The usual Standard File dialog is used to get the name and location of the |
* PICT file to open. Then FindPictDoc (defined earlier in this file) is called |
* to determine whether the chosen PICT file is already open within this |
* application. If it is, then that PICT fileÕs window is just selected and |
* DoOpenPictDoc returns with a pointer to that window. |
* |
* If the file isnÕt open, then itÕs opened here with HOpenDF. This routine is |
* used because it works even on systems that donÕt have the FSSpec-based File |
* Manager calls. GetPictureRect (defined later in this file) is called to get |
* the picFrame from the picture in the chosen PICT file. Once this is done, |
* CreatePictDoc is called to create a blank Picture Document window thatÕs ready |
* to read the image into. |
* |
* The current port is set to the off-screen GrafPort that CreatePictDoc created, |
* and then DrawFilePicture (defined later in this file) is called to spool the |
* PICT file into the current port. |
* |
* RETURN VALUES: |
* See PictDocument.h |
\******************************************************************************/ |
WindowPtr DoOpenPictDoc() |
{ |
WindowPtr pictDocWindow; /* Pointer to new Picture Doc window */ |
PictDocInfoHnd pictDocInfo; /* Handle to Picture Document info rec */ |
PictureInfoRec pictureInfo; /* PixMap information from PICT file */ |
Rect pictureRect; /* Rectangle of picture in PICT file */ |
CGrafPtr newImage; /* New off-screen image */ |
RGBColor color; /* Use to set default fore/back colors */ |
CGrafPtr savedPort; /* Ptr to current port for restoring */ |
GDHandle savedDevice; /* Current GDevice for restoring */ |
StandardFileReply reply; /* UserÕs choice for PICT file to open */ |
SFTypeList typeList; /* Specifies we can open 'PICT' files */ |
short pictFileRef; /* File reference number of PICT file */ |
OSErr error; |
pictDocWindow = nil; |
pictFileRef = 0; |
/* Let the user choose a PICT file */ |
typeList [0] = 'PICT'; |
if (FileSpecGet( nil, 1, typeList, /*<*/&reply )) |
{ |
/* First determine whether chosen file is already open in this app */ |
pictDocWindow = FindPictDoc( &reply.sfFile ); |
if (pictDocWindow == nil) |
{ |
/* Open the PICT file */ |
error = HOpenDF( reply.sfFile.vRefNum, reply.sfFile.parID, |
reply.sfFile.name, fsCurPerm, /*<*/&pictFileRef ); |
if (error != noErr) |
SysError(error); |
/* Get interesting information about a picture */ |
error = GetPictureInfo( pictFileRef, /*<*/&pictureInfo ); |
if (error != noErr) |
SysError(error); |
pictureRect = pictureInfo.frame; |
OffsetRect( /*×*/&pictureRect, -pictureRect.left, |
-pictureRect.top ); |
/* Open a new Picture Document window*/ |
error = CreatePictDoc( &pictureRect, pictureInfo.depth, |
pictureInfo.colors, /*<*/&pictDocWindow ); |
if (error != noErr) |
SysError(error); |
/* Fill in the Picture Document information */ |
pictDocInfo = (PictDocInfoHnd)GetWRefCon( pictDocWindow ); |
color.red = color.green = color.blue = 0x0000; |
(**pictDocInfo).foreground = color; |
color.red = color.green = color.blue = 0xFFFF; |
(**pictDocInfo).background = color; |
(**pictDocInfo).fileRef = pictFileRef; |
(**pictDocInfo).file = reply.sfFile; |
(**pictDocInfo).dithering = false; |
/* Get a handle to the Picture Document information record */ |
pictDocInfo = (PictDocInfoHnd)GetWRefCon( pictDocWindow ); |
/* Save current port and set newImage as current port */ |
newImage = (**pictDocInfo).image; |
GetGWorld( /*<*/&savedPort, /*<*/&savedDevice ); |
SetGWorld( newImage, nil ); |
/* Draw the contents of the PICT file into the current port */ |
error = DrawFilePicture( pictFileRef, &newImage->portRect ); |
/* Restore the current port and check for errors */ |
SetGWorld( savedPort, savedDevice ); |
if (error != noErr) |
SysError(error); |
/* Set the title of the window to the title of the file */ |
SetWTitle( pictDocWindow, reply.sfFile.name ); |
/* Show the window in its final size and position */ |
ShowWindow( pictDocWindow ); |
} |
else |
/* Chosen file already open; just select it */ |
SelectWindow( pictDocWindow ); |
} |
return pictDocWindow; |
} |
/******************************************************************************\ |
* NAME & SYNOPSIS: |
* CreatePictDoc: Create an empty Picture Document |
* |
* PARAMETERS: |
* Rect *pictureRect: Bounding rectangle of the image |
* WindowPtr *retDoc: Returns pointer to new Picture Document window |
* |
* DEFINITION: |
* This routine creates a new Picture Document window and returns a pointer to |
* it. If the Picture Document couldnÕt be created for some reason, then |
* CreatePictDoc returns the error code, and the retDoc parameter is untouched. |
* |
* DESCRIPTION: |
* Space for the window record is allocated before GetNewWindow is called so that] |
* heap fragmentation is minimized. Then, the window is initialized with |
* GetNewWindow. Then the vertical and horizontal scroll bars are created, and |
* the Picture Document information record is allocated and initialized. The |
* last major task is to stagger the window into position, and the routines that |
* are defined in WindowPositioner.c are used to do this. |
* |
* RETURN VALUES: |
* Result: Error code if Picture Document window couldnÕt be created |
* retDoc: Pointer to the new Picture Document window, |
\******************************************************************************/ |
static OSErr CreatePictDoc( |
Rect *pictureRect, /* Bounding rectangle of off-screen image */ |
short pictureDepth, /* Pixel depth of off-screen image */ |
CTabHandle pictureClut, /* Color table of off-screen image */ |
WindowPtr *retDoc) /* Returns ptr to new Picture Document window */ |
{ |
WindowPtr docWindow; /* Pointer to new Picture Document window */ |
Ptr windowStore; /* Pointer to pre-allocated window rec */ |
PictDocInfoHnd docInfo; /* Handle to Picture Document information */ |
PaletteHandle pictureColors; /* Palette with pictureÕs colors */ |
GWorldPtr newImage; /* New off-screen image */ |
ControlHandle vScrollBar; /* Vertical scroll bar */ |
ControlHandle hScrollBar; /* Horizontal scroll bar */ |
Rect windowRect; /* Destination rectangle of window */ |
Point windowBias; /* Bias of Picture Document window */ |
OSErr error; |
Point tempPt; |
docWindow = nil; |
docInfo = nil; |
windowStore = nil; |
/* Pre-allocate the window record to avoid heap fragmentation */ |
windowStore = NewPtrMargin( sizeof (WindowRecord), kAllocApp, !kAllocClr ); |
if (windowStore == nil) |
SysError(memFullErr); |
/* Create the off-screen graphics environment */ |
if (pictureClut == nil) |
pictureClut = GetCTable( pictureDepth ); |
error = NewGWorld( /*<*/&newImage, pictureDepth, pictureRect, pictureClut, |
nil, 0 ); |
if (error != noErr) |
SysError(error); |
/* Create a new Picture Document window */ |
docWindow = GetNewCWindow( rPictDocWindID, windowStore, |
(WindowPtr)-1L ); |
if (docWindow == nil) |
if (FailLowMemory( 0 ) || ResError() == memFullErr) |
SysError(memFullErr ); |
else if (ResError() == noErr || ResError() == resNotFound) |
SysError(resNotFound ); |
SetPort( docWindow ); |
/* Give the window a palette with the window colors */ |
pictureColors = NewPalette( (**pictureClut).ctSize + 1, pictureClut, |
pmTolerant, 0 ); |
SetPalette( docWindow, pictureColors, true ); |
/* Create the horizontal and vertical scroll bars */ |
vScrollBar = GetNewControl( rScrollBarID, docWindow ); |
if (vScrollBar == nil) |
if (FailLowMemory( 0 ) || ResError() == memFullErr) |
SysError(memFullErr ); |
else if (ResError() == noErr || ResError() == resNotFound) |
SysError(resNotFound ); |
hScrollBar = GetNewControl( rScrollBarID, docWindow ); |
if (hScrollBar == nil) |
if (FailLowMemory( 0 ) || ResError() == memFullErr) |
SysError(memFullErr ); |
else if (ResError() == noErr || ResError() == resNotFound) |
SysError(resNotFound ); |
/* Allocate a new Picture Document information record */ |
docInfo = (PictDocInfoHnd)NewHandleMargin( sizeof (PictDocInfoRec), |
kAllocApp, !kAllocClr ); |
if (docInfo == nil) |
SysError(memFullErr); |
(**docInfo).image = newImage; |
(**docInfo).vScrollBar = vScrollBar; |
(**docInfo).hScrollBar = hScrollBar; |
(**docInfo).destRect = newImage->portRect; |
(**docInfo).fileRef = 0; |
SetWRefCon( docWindow, (long)docInfo ); |
/* Stagger the window onto the screen */ |
windowBias = CalcWindowBias( documentProc, |
((WindowPeek)docWindow)->goAwayFlag ); |
SetRect( &windowRect, 0, 0, pictureRect->right + kScrollBarWidth - 1, |
pictureRect->bottom + kScrollBarWidth - 1 ); |
/*convert the windowRect to global coordinates */ |
SetPt(&tempPt, windowRect.left, windowRect.top); |
LocalToGlobal(&tempPt); |
windowRect.left = tempPt.h; |
windowRect.top = tempPt.v; |
SetPt(&tempPt, windowRect.right, windowRect.bottom); |
LocalToGlobal(&tempPt); |
windowRect.right = tempPt.h; |
windowRect.bottom = tempPt.v; |
PositionScreenRect( &windowRect, |
kParentScreenPos, kStaggerPos, NextPictDocWindow( nil ), |
windowBias.h, windowBias.v ); |
MoveWindow( docWindow, windowRect.left, windowRect.top, false ); |
SizeWindow( docWindow, windowRect.right - windowRect.left, |
windowRect.bottom - windowRect.top, false ); |
ResizePictDoc( docWindow ); |
/* Identify this window for later */ |
((WindowPeek)docWindow)->windowKind = kDocWKind; |
*retDoc = docWindow; |
return noErr; |
} |
/******************************************************************************\ |
* NAME & SYNOPSIS: |
* DoSaveAsPictDoc: Save a new Picture Document |
* |
* PARAMETERS: |
* See PictDocument.h |
* |
* DEFINITION: |
* See PictDocument.h |
* |
* DESCRIPTION: |
* The user is asked for a file name for the new Picture Document file through |
* Standard File. If the user specifies the file name and location and chooses |
* OK, DoSaveAsPictDoc creates a new PICT file if it didnÕt exist already, and |
* then it opens the PICT file for writing. The Picture DocumentÕs off-screen |
* GrafPort is set as the current port, and then OpenFilePicture (defined below) |
* is called which opens a new picture for spooling. Then the off-screen image |
* is CopyBitsÕed on top of itself which spools the off-screen image to the PICT |
* file. Then the spooled picture is closed, which completes the writing of the |
* PICT file. |
* |
* RETURN VALUES: |
* See PictDocument.h |
\******************************************************************************/ |
void DoSaveAsPictDoc( |
WindowPtr docWindow) /* Pointer to Picture Document window being saved */ |
{ |
StandardFileReply reply; /* Location and name of new PICT file */ |
Str255 docTitle; /* Holds the existing name of the document */ |
PictDocInfoHnd docInfo; /* Handle to Picture Document information */ |
CGrafPtr image; /* Points to documentÕs image */ |
CGrafPtr savedPort; /* Saves current port for later restoring */ |
GDHandle savedDevice; /* Saves current GDevice for restoring */ |
short pictFileRef; /* File reference number of PICT file */ |
OSErr error; |
pictFileRef = 0; |
/* Get the name and location of the new file from the user */ |
GetWTitle( docWindow, /*<*/docTitle ); |
StandardPutFile( "\p", docTitle, &reply ); |
if (reply.sfGood) |
{ |
/* Create the new PICT file if it doesnÕt already exist */ |
if (!reply.sfReplacing) |
{ |
error = HCreate( reply.sfFile.vRefNum, reply.sfFile.parID, |
reply.sfFile.name, kFileCreator, kFileType ); |
if (error != noErr) |
SysError(error); |
} |
/* Open the new PICT file */ |
error = HOpen( reply.sfFile.vRefNum, reply.sfFile.parID, |
reply.sfFile.name, fsCurPerm, /*<*/&pictFileRef ); |
if (error != noErr) |
SysError(error); |
/* Get the Picture DocumentÕs image and make it the current port */ |
docInfo = (PictDocInfoHnd)GetWRefCon( docWindow ); |
image = (**docInfo).image; |
GetGWorld( /*<*/&savedPort, /*<*/&savedDevice ); |
SetGWorld( image, nil ); |
/* Create a PICT file with the Picture DocumentÕs image */ |
error = OpenFilePicture( pictFileRef, &image->portRect ); |
if (error != noErr) |
SysError(error); |
CopyBits( &((GrafPtr)image)->portBits, &((GrafPtr)image)->portBits, |
&image->portRect, &image->portRect, |
srcCopy, nil ); |
error = CloseFilePicture(); |
if (error != noErr) |
SysError(error); |
/* Restore the current port */ |
SetGWorld( savedPort, savedDevice ); |
/* Close the existing PICT file if any */ |
if ((**docInfo).fileRef != 0) |
(void)FSClose( (**docInfo).fileRef ); |
/* Remember the new PICT fileÕs reference number */ |
(**docInfo).fileRef = pictFileRef; |
(**docInfo).file = reply.sfFile; |
/* Set the title of the window to the title of the file */ |
SetWTitle( docWindow, reply.sfFile.name ); |
} |
} |
/******************************************************************************\ |
* NAME & SYNOPSIS: |
* DoClosePictDoc: Close a Picture Document window |
* |
* PARAMETERS: |
* See PictDocument.h |
* |
* DEFINITION: |
* See PictDocument.h |
* |
* DESCRIPTION: |
* The off-screen image is disposed of and the Picture DocumentÕs PICT file is |
* closed. Then all the memory associated with the window is disposed of. |
* |
* RETURN VALUES: |
* See PictDocument.h |
\******************************************************************************/ |
Boolean DoClosePictDoc( |
WindowPtr docWindow) /* Ptr to Picture Document window being closed */ |
{ |
PictDocInfoHnd docInfo; /* Handle to Picture Document info record */ |
docInfo = (PictDocInfoHnd)GetWRefCon( docWindow ); |
if (docInfo != nil) |
{ |
/* Get rid of the off-screen CGrafPort */ |
if ((**docInfo).image != nil) |
DisposeGWorld( (**docInfo).image ); |
/* Close the Picture File */ |
if ((**docInfo).fileRef != 0) |
(void)FSClose( (**docInfo).fileRef ); |
/* Dispose of the Picture Document information record */ |
DisposeHandle( (Handle)docInfo ); |
} |
/* Close and dispose of the Picture Document window */ |
DisposePalette( GetPalette( docWindow ) ); |
CloseWindow( docWindow ); |
DisposePtr( (Ptr)docWindow ); |
return true; |
} |
/******************************************************************************\ |
* NAME & SYNOPSIS: |
* GetPictureInfo: Get basic information about a PICT document |
* |
* PARAMETERS: |
* short pictFileRef: File reference number of PICT file |
* PictureInfoRec *retPictRect: Returns information on picture |
* |
* DEFINITION: |
* GetPictureInfo examines the PICT file whose file reference number is specified |
* in the pictFileRef parameter to get the picFrame of the picture, and the pixel |
* depth and color table of the deepest PixMap in the picture. This information |
* is returned in the retPictInfo parameter. |
* |
* DESCRIPTION: |
* GetPictureInfo uses picture spooling to get the information about the picture |
* in the specified PICT file. A temporary CGrafPort or GrafPort is set up just |
* so that no existing ports are touched. Then a CQDProcs or QDProcs record is |
* set up so that picture data comes from the PICT file instead of memory, and so |
* that any CopyBits calls within the picture get routed to the InfoBits routine |
* (defined below). Then the standard picture spooling mechanism is used to read |
* the PICT file. The clip region is set to nothing to prevent drawingÑÑonly the |
* information about the PixMaps is needed, and InfoBits gets that. |
* |
* RETURN VALUES: |
* Result: Error code if anything went wrong |
* retPictInfo: Size of picture, and depth and color table of deepest PixMap in |
* the picture. |
\******************************************************************************/ |
static OSErr GetPictureInfo( |
short pictFileRef, /* File reference number of PICT file */ |
PictureInfoRec *retPictInfo) /* Returns information on picture */ |
{ |
CGrafPort tempPort; /* Temp port used for ÒDrawingÓ pict */ |
Boolean tempPortOpen; /* True if tempPort has been opened */ |
GrafPtr savedPort; /* Saves current port for restoring */ |
CQDProcs customProcs; /* Custom GrafProcs */ |
PicHandle spoolPict; /* Picture used for spooling */ |
Rect emptyRect; /* Used to set empty clipping region */ |
long dataLen; /* Number of bytes of data to read */ |
long qdVersion; /* Version number of QuickDraw */ |
OSErr error; |
error = noErr; |
tempPortOpen = false; |
savedPort = nil; |
spoolPict = nil; |
/* Get the current version of QuickDraw */ |
(void)Gestalt( gestaltQuickdrawVersion, /*<*/&qdVersion ); |
/* Save current port so that we can restore it later */ |
GetPort( /*<*/&savedPort ); |
/* Open the temporary CGrafPort or GrafPort, depending on QD version */ |
if (qdVersion >= gestalt8BitQD) |
OpenCPort( &tempPort ); |
else |
OpenPort( (GrafPtr)&tempPort ); |
tempPortOpen = true; |
/* DonÕt want anything drawn */ |
SetRect( /*<*/&emptyRect, 0, 0, 0, 0 ); |
ClipRect( &emptyRect ); |
/* Set up the GrafProcs for spooling */ |
if (qdVersion >= gestalt8BitQD) |
SetStdCProcs( /*<*/&customProcs ); |
else |
SetStdProcs( /*<*/(QDProcsPtr) &customProcs ); |
customProcs.bitsProc = gQDBitsUPP; |
customProcs.getPicProc = gQDGetPicUPP; |
/* Install the custom GrafProcs into the tempPort */ |
tempPort.grafProcs = &customProcs; |
/* Create the picture used for spooling */ |
spoolPict = (PicHandle)NewHandleMargin( sizeof (Picture), kAllocApp, |
!kAllocClr ); |
if (spoolPict == nil) |
SysError(memFullErr ); |
/* Skip the PICT file header */ |
error = SetFPos( pictFileRef, fsFromStart, 512L ); |
if (error != noErr) |
SysError(error); |
/* Read the picture header into spoolPict */ |
dataLen = sizeof (Picture); |
error = FSRead( pictFileRef, /*×*/&dataLen, (Ptr) *spoolPict ); |
if (error != noErr) |
SysError(error ); |
/* Spool the picture in */ |
gPictureInfo.colors = nil; |
gPictureInfo.depth = 0; |
gPictureInfo.frame = (**spoolPict).picFrame; |
gPictFileRef = pictFileRef; |
DrawPicture( spoolPict, &gPictureInfo.frame ); |
/* Clean up after myself */ |
SetPort( savedPort ); |
ClosePort( (GrafPtr)&tempPort ); |
tempPortOpen = false; |
DisposeHandle( (Handle)spoolPict ); |
/* Return picture information */ |
*retPictInfo = gPictureInfo; |
return noErr; |
} |
/******************************************************************************\ |
* NAME & SYNOPSIS: |
* InfoBits: GrafProc to get information about bit/pixel maps |
* |
* PARAMETERS: |
* BitMapPtr srcBits: Pointer to bit/pixel map being transferred |
* Rect *srcRect: Source rectangle of CopyBits call; ignored |
* Rect *dstRect: Destination rectangle of CopyBits call; ignored |
* short mode: Transfer mode; ignored |
* RgnHandle maskRgn: Region to mask CopyBits; ignored |
* |
* DEFINITION: |
* InfoBits is a custom QuickDraw graphics procedure which is used to find the |
* depth and color table of the deepest PixMap in the picture thatÕs being drawn. |
* This information is returned in the gPictureInfo global variable. |
* |
* DESCRIPTION: |
* InfoBits is called every time a CopyBits call is found in a picture thatÕs |
* being drawn. It first checks to see if the CopyBits call is for a PixMap or |
* a BitMap. If itÕs a BitMap, the most significant bit of rowBytes is clear; if |
* itÕs a PixMap, the most significant byte of rowBytes is set. If itÕs a |
* PixMap, its depth is compared against the depth of any previous PixMap that |
* has been seen in the picture. If itÕs deeper, then the depth and color table |
* of the PixMap is saved. Otherwise, the PixMap is ignored. |
* |
* If srcBits is a BitMap and no PixMaps have yet been seen in the picture, then |
* InfoBits remembers a depth of 1 bit per pixel and no color table. |
* |
* RETURN VALUES: |
* gPictureInfo: Depth and color table of deepest PixMap in a picture. |
\******************************************************************************/ |
pascal void InfoBits( |
BitMapPtr srcBits, /* Pointer to bit/pixel map being transferred */ |
Rect *srcRect, /* Source rectangle of CopyBits call; ignored */ |
Rect *dstRect, /* Destination rectangle of CopyBits call; ignored */ |
short mode, /* Transfer mode; ignored */ |
RgnHandle maskRgn) /* Region to mask CopyBits; ignored */ |
{ |
#pragma unused (srcRect,dstRect,mode,maskRgn) |
PixMapPtr srcPix; /* Handle to the pictureÕs PixMap */ |
if (srcBits->rowBytes & 0x8000) |
{ |
/* srcBits is a pixel map, get depth and color table */ |
srcPix = (PixMapPtr)srcBits; |
/* Only save info if this pixel map is deepest seen so far */ |
if (srcPix->pixelSize > gPictureInfo.depth) |
{ |
gPictureInfo.depth = srcPix->pixelSize; |
if (srcPix->pixelType != RGBDirect) |
{ |
if (gPictureInfo.colors != nil) |
DisposeHandle( (Handle)gPictureInfo.colors ); |
gPictureInfo.colors = srcPix->pmTable; |
HandToHand( (Handle *)&gPictureInfo.colors ); |
} |
} |
} |
else |
{ |
/* srcBits is a bit map, has depth of 1 and B&W color table */ |
if (gPictureInfo.depth == 0) |
{ |
gPictureInfo.depth = 1; |
if (gPictureInfo.colors != nil) |
DisposeHandle( (Handle)gPictureInfo.colors ); |
gPictureInfo.colors = nil; |
} |
} |
} |
/******************************************************************************\ |
* NAME & SYNOPSIS: |
* DrawFilePicture: Read a PICT file into the current GrafPort |
* |
* PARAMETERS: |
* short pictFileRef: File reference number of PICT file to open |
* Rect *destRect: Rectangle to draw the picture into |
* |
* DEFINITION: |
* This routine is used to read the picture data from the PICT file specified by |
* pictFileRef and draw the picture into the rectangle specified by the destRect |
* parameter in the current GrafPort. ItÕs just like DrawPicture, except the |
* file reference number of a PICT file is specified instead of a PicHandle. |
* |
* DESCRIPTION: |
* DrawFilePicture works by using the picture spooling method described in Inside |
* Macintosh V on pages 87 through 90. In this method, the getPicProc GrafProc is |
* replaced by my routine called FileGetPic which reads PICT information from |
* disk. By doing this, the DrawPicture command effectively reads PICT files. |
* |
* After setting up the GrafProcs record, this routine installs the GrafProcs |
* into the current port. Then, a temporary picture is manually allocated and |
* placed into spoolPict. This is essentially a placeholder to hold the picture |
* header (which is different from the 512-byte PICT file header) and is always |
* the size of the Picture record type without any picture data. |
* |
* The PICT file is opened using HOpen. HOpen is documented in the File Manager |
* chapter of Inside Macintosh VI, but it still works on pre-7.0 machines because |
* itÕs just glue code that calls PBHOpen. Because of the way the File Manager |
* works, this routine also works on MFS volumes. This routine is preferable to |
* FSOpen because HOpen allows you to specify access permissions, and because it |
* lets you specify a file by the more reliable volume reference number, |
* directory ID, and file name rather than by working directory reference number |
* and file name. IÕm using the FSSpec record to hold file information, so |
* specifying a file like this is especially convenient. If this were a 7.0-only |
* application, IÕd call FSpOpen instead of HOpen because FSpOpen takes an FSSpec |
* record directly. |
* |
* After the PICT file is opened, SetFPos is called to skip the first 512 bytes |
* of the file. The first 512 bytes of a PICT file is called the PICT file |
* header (not to be confused with the picture header, which contains the picSize |
* and picFrame fields of the Picture type) and holds application-specific |
* information. This application doesnÕt care whatÕs there so it just skips it. |
* The picture header follows the PICT file header and is read into spoolPict. |
* |
* Finally (almost), DrawPicture is called. Because this routine replaced the |
* current portÕs GrafProcs with my own, DrawPicture gets the picture information |
* from the PICT file rather than from spoolPict. It draws the picture into the |
* current port. |
* |
* RETURN VALUES: |
* Result: Returns an error code. |
* destRect: Returns the picFrame of the picture in the PICT file |
\******************************************************************************/ |
static OSErr DrawFilePicture( |
short pictFileRef, /* File reference number of PICT file to open */ |
Rect *destRect) /* Rectangle to draw the picture into */ |
{ |
GrafPtr currPort; /* Ptr to current port used for Drawing pict */ |
CQDProcs customProcs; /* Custom GrafProcs */ |
QDProcsPtr savedProcs; /* Current GrafPortÕs QD procs; used to restore */ |
PicHandle spoolPict; /* Picture used for spooling */ |
long dataLen; /* Number of bytes of data to read */ |
long qdVersion; /* Version number of QuickDraw */ |
OSErr error; |
currPort = nil; |
spoolPict = nil; |
savedProcs = nil; |
error = noErr; |
/* Get the current version of QuickDraw */ |
(void)Gestalt( gestaltQuickdrawVersion, /*<*/&qdVersion ); |
/* Get a pointer to the current port and determine its type */ |
GetPort( /*<*/&currPort ); |
/* Initialize the GrafProcs for reading from a PICT file */ |
if (qdVersion >= gestalt8BitQD) |
SetStdCProcs( /*<*/&customProcs ); |
else |
SetStdProcs( /*<*/(QDProcsPtr) &customProcs ); |
customProcs.getPicProc = gQDGetPicUPP; |
/* Install the custom GrafProcs into the tempPort */ |
savedProcs = currPort->grafProcs; |
currPort->grafProcs = (QDProcsPtr)&customProcs; |
/* Create the temporary picture used for spooling */ |
spoolPict = (PicHandle)NewHandleMargin( sizeof (Picture), |
kAllocApp, !kAllocClr ); |
if (spoolPict == nil) |
SysError(memFullErr ); |
/* Skip the 512-byte PICT file header */ |
error = SetFPos( pictFileRef, fsFromStart, kPictFileHeaderSize ); |
if (error != noErr) |
SysError(error ); |
/* Read the picture header (not PICT file header) into spoolPict */ |
dataLen = sizeof (Picture); |
error = FSRead( pictFileRef, /*×*/&dataLen, (Ptr)*spoolPict ); |
if (error != noErr) |
SysError(error ); |
/* Spool the picture in */ |
gPictFileRef = pictFileRef; |
DrawPicture( spoolPict, destRect ); |
/* Clean up after myself */ |
DisposeHandle( (Handle)spoolPict ); |
currPort->grafProcs = savedProcs; |
return noErr; |
} |
/******************************************************************************\ |
* NAME & SYNOPSIS: |
* FileGetPic: Get QuickDraw picture information from a file |
* |
* PARAMETERS: |
* Ptr dataPtr: Points to location that picture data should be placed |
* short byteCount: Number of bytes of picture data to read |
* |
* DEFINITION: |
* This routine is a custom QuickDraw graphics procedure which replaces the |
* standard GetPicProc. QuickDraw graphics procedures are routines that |
* QuickDraw calls to do almost everything that it does, like drawing rectangles, |
* or getting picture data. They can be replaced by setting up a QDProcs record |
* and setting the appropriate field to point to the custom QuickDraw graphics |
* procedure. In this case, the getPicProc field is set to point to FileGetPic |
* so that any DrawPicture call within the GrafPort causes FileGetPic to be |
* called to get picture data. Instead of getting picture data from memory, |
* FileGetPic gets picture data from the disk file whose file reference number is |
* stored in the gPictFileRef global variable. |
* |
* DESCRIPTION: |
* FileGetPic simply calls FSRead to read data from the file whose file reference |
* number is stored in gPictFileRef into the area pointed to by dataPtr, which is |
* an area of memory thatÕs set up by QuickDraw to receive picture data. The |
* number of bytes of picture data that QuickDraw wants is specified by the |
* byteCount parameter. |
* |
* RETURN VALUES: |
* None |
\******************************************************************************/ |
pascal void FileGetPic( |
Ptr dataPtr, /* Points to location that picture data should be placed */ |
short byteCount) /* Number of bytes of picture data to read */ |
{ |
long longCount; /* Number of bytes to read from the PICT file */ |
longCount = byteCount; |
(void)FSRead( gPictFileRef, /*×*/&longCount, dataPtr ); |
} |
/******************************************************************************\ |
* NAME & SYNOPSIS: |
* OpenFilePicture: Open a picture for spooling to a file |
* |
* PARAMETERS: |
* short pictFileRef: File reference number of PICT file to write to |
* Rect *sourceRect: Rectangle to draw the picture from |
* |
* DEFINITION: |
* Normally, when you create a picture, you call OpenPicture, draw, then call |
* ClosePicture. But if you can create a PICT file in a similar way by calling |
* OpenFilePicture and CloseFilePicture. Almost like you would normally, you |
* should set up the current port however you want it, call OpenFilePicture, |
* use QuickDraw routines to draw, then call CloseFilePicture when youÕre done. |
* But before you call OpenFilePicture, you must open the PICT file for writing, |
* and pass the fileÕs reference number in the pictFileRef parameter. Once |
* CloseFilePicture is called, the PICT file is complete. |
* |
* DESCRIPTION: |
* OpenFilePicture installs the FilePutPic custom graphics procedure by setting |
* up a QDprocs record with the default pointers, and then setting the putPicProc |
* field to point to the FilePutPic function. This QDProcs record is then |
* installed into the current GrafPort. Then, an empty picture is allocated just |
* to have something to pass to the real OpenPicture routine. Then the 512-byte |
* PICT file header is written. This program doesnÕt do anything with those 512 |
* bytes, so only zeroes are written. Also, the ten-byte picture header is |
* written with zeroes for now; itÕll get the real picture header after the PICT |
* file data is written. Finally, the global variables are set up so that |
* FilePutPic can reach them. |
* |
* RETURN VALUES: |
* Result: Error code of any error that occurs. |
\******************************************************************************/ |
static OSErr OpenFilePicture( |
short pictFileRef, /* File reference number of PICT file to open */ |
Rect *sourceRect) /* Rectangle to draw the picture from */ |
{ |
GrafPtr currPort; /* Ptr to current port used for Drawing pict */ |
long dataLen; /* Number of bytes of data to write */ |
short zeroData; /* Equal to 0; used to write PICT file header */ |
short count; /* Generic counter */ |
OSErr error; |
currPort = nil; |
gSpoolPicture = nil; |
gSavedProcs = nil; |
error = noErr; |
/* Get a pointer to the current port */ |
GetPort( /*<*/&currPort ); |
/* Initialize the GrafProcs for reading from a PICT file */ |
if (currPort->portBits.rowBytes & 0x8000) |
SetStdCProcs( /*<*/&gCustomProcs ); |
else |
SetStdProcs( /*<*/(QDProcsPtr)&gCustomProcs ); |
gCustomProcs.putPicProc = gQDPutPicUPP; |
/* Install the custom GrafProcs into the tempPort */ |
gSavedProcs = currPort->grafProcs; |
currPort->grafProcs = (QDProcsPtr)&gCustomProcs; |
/* Create the temporary picture used for spooling */ |
gSpoolPicture = (PicHandle)NewHandleMargin( sizeof (Picture), |
kAllocApp, kAllocClr ); |
if (gSpoolPicture == nil) |
SysError(memFullErr ); |
/* Make sure weÕre positioned at the beginning of the file */ |
error = SetFPos( pictFileRef, fsFromStart, 0 ); |
if (error != noErr) |
SysError( error ); |
/* Zero the 512-byte PICT file header */ |
dataLen = sizeof (short); |
zeroData = 0; |
for (count = 0; count < (kPictFileHeaderSize + sizeof (Picture)) |
/ sizeof (short); ++count) |
{ |
error = FSWrite( pictFileRef, /*×*/&dataLen, &zeroData ); |
if (error != noErr) |
SysError(error ); |
} |
/* Begin spooling the picture out */ |
gPictFileRef = pictFileRef; |
gPictureSize = sizeof (Picture); |
gSpoolPicture = nil; |
gSpoolPicture = OpenPicture( sourceRect ); |
return noErr; |
} |
/******************************************************************************\ |
* NAME & SYNOPSIS: |
* CloseFilePicture: Close a spooled picture (donÕt close the PICT file) |
* |
* PARAMETERS: |
* None |
* |
* DEFINITION: |
* ClosePictureFile is called to complete the writing of a PICT file. ItÕs |
* called the same way youÕd call ClosePicture. |
* |
* DESCRIPTION: |
* ClosePicture is called to close the currently-open picture, then the picture |
* header is written with the final values. Because the temporary picture isnÕt |
* needed anymore, KillPicture is called to get rid of it. Finally, the current |
* portÕs graphics procedures are restored to what they were before |
* OpenFilePicture was called. |
* |
* RETURN VALUES: |
* Result: Error code of any error that occurs. |
\******************************************************************************/ |
static OSErr CloseFilePicture() |
{ |
long dataLen; /* Number of bytes of data to write */ |
GrafPtr currPort; /* Pointer to the current GrafPort */ |
OSErr error; |
error = noErr; |
/* Close the spooled picture */ |
ClosePicture(); |
/* Make sure weÕre positioned just past the PICT file header */ |
error = SetFPos( gPictFileRef, fsFromStart, kPictFileHeaderSize ); |
if (error != noErr) |
SysError(error ); |
/* Write the picture header (NOT the PICT file header!) */ |
dataLen = sizeof (Picture); |
error = FSWrite( gPictFileRef, /*×*/&dataLen, (Ptr)*gSpoolPicture ); |
if (error != noErr) |
SysError(error ); |
/* Dispose of the picture */ |
KillPicture( gSpoolPicture ); |
/* Restore the previous graphics procedures */ |
GetPort( /*<*/&currPort); |
currPort->grafProcs = gSavedProcs; |
return noErr; |
} |
/******************************************************************************\ |
* NAME & SYNOPSIS: |
* FilePutPic: Write QuickDraw picture information to PICT file |
* |
* PARAMETERS: |
* Ptr dataPtr: Points to location of picture data |
* short byteCount: Number of bytes of picture data to write |
* |
* DEFINITION: |
* This routine is a custom QuickDraw graphics procedure which replaces the |
* standard PutPicProc. QuickDraw graphics procedures are routines that |
* QuickDraw calls to do almost everything that it does, like drawing rectangles, |
* or getting picture data. They can be replaced by setting up a QDProcs record |
* and setting the appropriate field to point to the custom QuickDraw graphics |
* procedure. In this case, the getPicProc field is set to point to FileGetPic |
* so that any drawing call within the GrafPort while a picture is open causes |
* FilePutPic to be called to write picture data. Instead of writing picture |
* data to memory, FileGetPic writes picture data to the disk file whose file |
* reference number is stored in the gPictFileRef global variable. |
* |
* DESCRIPTION: |
* FileGetPic calls FSWrite to write data t=o the file whose file reference |
* number is stored in gPictFileRef from the area pointed to by dataPtr, which is |
* an area of memory thatÕs set up by QuickDraw to hold picture data. The |
* number of bytes of picture data that QuickDraw has is specified by the |
* byteCount parameter. Also, the picSize field of gSpoolPicture is updated so |
* that QuickDraw can keep track of the current size of the picture. |
* |
* RETURN VALUES: |
* None |
\******************************************************************************/ |
pascal void FilePutPic( |
Ptr dataPtr, /* Points to location of picture data */ |
short byteCount) /* Number of bytes of picture data to write */ |
{ |
long dataLen; /* Number of bytes to write the PICT file */ |
dataLen = byteCount; |
gPictureSize += dataLen; |
(void)FSWrite( gPictFileRef, /*×*/&dataLen, dataPtr ); |
if (gSpoolPicture != nil) |
(**gSpoolPicture).picSize = gPictureSize; |
} |
Copyright © 2003 Apple Computer, Inc. All Rights Reserved. Terms of Use | Privacy Policy | Updated: 2003-03-12