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.
VwrFrameWork.c
/* |
* This is a viewer application shell |
* |
* Nick Thompson, nickt@apple.com |
* send bug reports to devsupport@apple.com |
* |
* ©1995-7 Apple Computer Inc., All Rights Reserved. |
* |
* This is a sample app that was originally written for an article in Develop |
* issue 29, but please note that it is really extended from the example |
* presented in that article. |
* |
* I've extended it to be the "reference" app for supporting plug-in |
* renderers. Along the way it became apparent that just sticking all the renderers |
* into a popup menu, simply did not cut the mustard. Here's why. There is a |
* distinction between interactive (for example the apple interactive renderer) |
* and non interactive renderers (such as the lightwork renderer). Bear in mind |
* that the interactivity of a renderer is often a tradeoff against speed. In particular, |
* it makes no sense whatsoever to support interactivity with a non interactive |
* renderer. |
* |
* This led me to the big change in the application. I decided that if the |
* renderer was non-interactive, then it should draw into a new window, which |
* the user could save as a pict, print, or whatever. Bear in mind that this is |
* not the only way to do this. Another simpler way would be to let the user |
* chose a non interactive renderer, and just render one into the window, then |
* switch back to the non interactive renderer. I saw a couple of problems with |
* this approach for this particular application, in particular that if the |
* window received an update event (out of the users control) then the window |
* or worse - part of the window - would get redrawn with the "wrong" renderer. |
* |
* This remains a work in progress. As sample code it is useful as an |
* illustration of how to use the viewer, and an illustration of how to use |
* plug-in renderers. |
* |
* As usual this is a work in progress, which means use the code at your own risk!! |
* |
* If you fix a bug, or add some functionality feel free to send me the change and |
* I'll roll it in. |
* |
* |
* |
* TO DO: drag and drop support for pict windows |
* saving and restoring print records to files. |
*/ |
/*------------------------------------------------------------ */ |
#include <AppleEvents.h> |
#include <ColorPicker.h> |
#include <Devices.h> |
#include <Dialogs.h> |
#include <Diskinit.h> |
#include <Events.h> |
#include <Errors.h> |
#include <Fonts.h> |
#include <Gestalt.h> |
#include <LowMem.h> |
#include <Printing.h> |
#include <QDOffscreen.h> |
#include <QuickDraw.h> |
#include <Menus.h> |
#include <Scrap.h> |
#include <SegLoad.h> |
#include <StandardFile.h> |
#include <TextUtils.h> |
#include <Strings.h> |
#include <Windows.h> |
#include <ctype.h> |
#include <stdarg.h> |
/* always include this before anything else when using the QuickDraw 3D library */ |
#include "QD3D.h" |
/* viewer support */ |
#include "QD3DViewer.h" |
/* this has the routines for renderer objects */ |
#include "QD3DRenderer.h" |
/* this has the routines for view objects */ |
#include "QD3DView.h" |
/* this header allows us to check for the viewer */ |
#include <CodeFragments.h> |
/*------------------------------------------------------------ */ |
/* convenience macros to peek at event records */ |
#define HiWrd(aLong) (((aLong) >> 16) & 0xFFFF) |
#define LoWrd(aLong) ((aLong) & 0xFFFF) |
#define kMaxRendererCount 30 |
#define RETURN_KEY 0x0D |
#define ENTER_KEY 0x03 |
#define ESCAPE 0x1B |
#define kProgressBarDlogID 1028 |
#define kProgressBarPBItemID 2 |
/*------------------------------------------------------------ */ |
/* constants */ |
const short kWindHeight = 350 ; /* default theWindow height */ |
const short kWindWidth = 300 ; /* default theWindow width */ |
const short kMaxHeight = 400 ; /* max theWindow height */ |
const short kMaxWidth = 560 ; /* max theWindow width */ |
const SFTypeList kTypeList = { '3DMF' } ; /* file type we can open */ |
const short kNumTypes = 1 ; /* num of file types we can recognise */ |
const short kAppMenuBarID = 128 ; /* resource ID for the application's menu bar */ |
const short kFatalAlert = 128 ; /* res ID for error alert before we bail */ |
const short kErrorAlertStrings = 128 ; /* res ID for alert strs */ |
const short kAboutDialogID = 129; /* ID for the about box dialog */ |
const short kFinalRenderDialogID = 130; /* ID for the final quality render dialog */ |
const short kInsetPixelsConst = 30 ; /* num of pixels to inset view by */ |
/* error codes */ |
enum { |
kNoMenuBar = 1, |
kNoQD3DViewerLib, |
kNoAEVTSupport |
} ; |
/* menu resource IDs */ |
enum { |
mInteractiveRendererMenu = 1, /* hierarchical, stored in the view menu */ |
mNonInteractiveRendererMenu , /* hierarchical, stored in final dialog */ |
mAppleMenu = 128, |
mFileMenu, |
mEditMenu, |
mViewMenu |
} ; |
/* item numbers - Apple menu */ |
enum { |
iAppleAboutItem = 1 |
} ; |
/* item numbers - File menu */ |
enum { |
iFileNewItem = 1, |
iFileOpenItem, |
iFileCloseItem = 4, |
iFileSaveItem, |
iFileSaveAsItem, |
iFileRevertItem, |
iFilePageSetupItem = 9, |
iFilePrintItem, |
iFileQuitItem = 12 |
} ; |
/* item numbers - Edit menu */ |
enum { |
iEditUndoItem = 1, |
iEditCutItem = 3, |
iEditCopyItem, |
iEditPasteItem, |
iEditClearItem = 7, |
iEditRendererPrefsItem = 9 |
} ; |
/* item numbers - View menu */ |
enum { |
iViewRendererItem = 1, |
iViewFinalRendererItem, |
iViewBadgeItem = 4, |
iViewCameraButtonItem = 6, |
iViewTruckButtonItem, |
iViewOrbitButtonItem, |
iViewZoomButtonItem, |
iViewDollyButtonItem, |
iViewInsetNFrameItem = 12, |
iViewSetBackgroundColorItem |
} ; |
/* items in the final quality render menu */ |
enum { |
kFinalRendrOK = 1, |
kFinalRendrCancel, |
kFinalRendrIcon, |
kFinalRendrTitle, |
kFinalRendrText, |
kFinalRendrSep1, |
kFinalRendrSep2, |
kFinalRendrSep3, |
kFinalRendrPopup, |
kFinalRendrConfigure, |
kFinalRendrWinSzTxt, |
kFinalRendrHtTxt, |
kFinalRendrWiTxt, |
kFinalRendrHeight, |
kFinalRendrWidth |
} ; |
/* res ID's for small picts used in the progress bar dialog */ |
enum { |
kResIDStartCap = 1028, |
kResIDEndCap, |
kResIDDropShadow |
} ; |
/*------------------------------------------------------------ */ |
/* |
* type definitions - these magic numbers are the first field of the struct |
* that we stuff in the window's refcon field |
*/ |
/* |
* as this app grow's I'm in the process of factoring it, here's a list |
* of functions that can be stuffed in the document record |
*/ |
typedef void (*AdjustMenusProc)( WindowPtr theWindow ) ; |
typedef Boolean (*HandleEventProc)( WindowPtr theWindow, EventRecord *theEventRecord) ; |
typedef void (*UpdateContentProc)( WindowPtr theWindow ) ; |
typedef WindowPtr (*NewProc)( unsigned char *windowTitle ) ; |
typedef OSErr (*SaveAsProc)( WindowPtr theWindow ) ; |
typedef OSErr (*SaveProc)( WindowPtr theWindow ) ; |
typedef OSErr (*RevertProc)( WindowPtr theWindow ) ; |
typedef WindowPtr (*OpenProc)( FSSpec *theFSSpec ) ; |
typedef OSErr (*CloseProc)( WindowPtr theWindow ) ; |
typedef short (*CountPagesProc)( WindowPtr theWindow, Rect *pageRect ) ; |
typedef void (*PrintPageProc)( WindowPtr theWindow, Rect *pageRect, GrafPtr imagingPort, short pageNum ) ; |
typedef void (*PrePrintProc)( WindowPtr theWindow ) ; |
typedef void (*PostPrintProc)( WindowPtr theWindow ) ; |
typedef OSErr (*CutProc)( WindowPtr theWindow ) ; |
typedef OSErr (*CopyProc)( WindowPtr theWindow ) ; |
typedef OSErr (*PasteProc)( WindowPtr theWindow ) ; |
typedef OSErr (*ClearProc)( WindowPtr theWindow ) ; |
typedef OSErr (*UndoProc)( WindowPtr theWindow ) ; |
/* |
* This struct is used to store related items for a progress bar, |
* these cached items can then be used when updating the PB |
*/ |
typedef struct { |
DialogPtr thePBDialog ; /* the dialog containing a 14 pixel high user item * |
* within which the PB is drawn */ |
short thePBItemNumber ; /* item number in the DITL for the PB user item */ |
Rect thePBRect ; /* it's rect, local coodinates in the dialog */ |
GWorldPtr thePBGWorld ; /* a GWorld that is used to draw the pb, it's then blitted to the dialog */ |
long thePBMaxValue ; /* the maximum value the PB can be */ |
long thePBCurrValue ; /* the current value for the progress bar */ |
} ProgressBarDlogInfoData, **ProgressBarDlogInfoHdl ; |
/* |
* this is a struct that contains the fp's associated with a document class |
* later we'll use this to set up menus. If a fp is null then the menu is |
* disabled, this will really reduce the size of the adjust menus proc. |
* |
* Each document record will have this as the second field. |
*/ |
typedef struct Procs { |
AdjustMenusProc adjustMenusP ; /* fix up window specific menus */ |
UpdateContentProc updateWindowP ; /* redraw the window */ |
HandleEventProc handleEventP ; /* handle events for the window */ |
NewProc newP ; /* do window specific stuff post create (unused at the moment) */ |
SaveAsProc saveAsP ; /* save the window contens ask for a file */ |
SaveProc saveP ; /* save the window contents to the original file */ |
RevertProc revertP ; /* revert to the last saved copy of the windows file */ |
OpenProc openP ; /* read in some document data */ |
CloseProc closeP ; /* close and destroy */ |
CountPagesProc countPagesP ; /* count the number of pages for a print job */ |
PrintPageProc printPageP ; /* print one page */ |
PrePrintProc prePrintP ; /* stuff to do before printing */ |
PostPrintProc postPrintP ; /* stuff to do after printing */ |
CutProc cutProc ; /* handle clipboard cut, same as copy followed by clear */ |
CopyProc copyProc ; /* handle clipboard copy */ |
PasteProc pasteProc ; /* paste compatible scrap type from the scrap */ |
ClearProc clearProc ; /* clear the document contents without a save to the scrap */ |
UndoProc undoProc ; /* undo the last action - if supported */ |
} Procs ; |
/* |
* eventually to make a new doc, we'll just define the structure of the private |
* field for each class. Right now they are kind of copies which can be cast around. |
* |
* Make sure that the fields are in the same order, again this is something I'm |
* planning to fix. |
*/ |
typedef struct { |
unsigned long fDocumentMagic ; /* use this to describe the contents of the fPrivate field */ |
Procs *procs ; /* a pointer to a set of function pointers for this window type */ |
THPrint fPrintRec ; /* print record so we can print the doc contents */ |
void *fPrivate ; /* the private data associated with this class */ |
} Document, *DocumentPtr, **DocumentHdl ; |
/* these structures get stuffed in the private field of a generic document record */ |
typedef struct { |
TQ3ViewerObject fViewer ; /* stores reference to the viewer object */ |
GWorldPtr fGWorld ; /* used temporarily during printing */ |
FSSpec fFSSpec ; /* reference to the file for the document */ |
} ViewerData, *ViewerDataPtr, **ViewerDataHdl ; |
typedef struct { |
GWorldPtr fGWorld ; /* a buffer that stores the picture */ |
} PictData, *PictDataPtr, **PictDataHdl ; |
/* |
* Structure for the private data for a popup control. |
* This structure is documented on page 5-77 |
* Inside Macintosh: Macintosh Toolbox Essentials |
*/ |
typedef struct popupPrivateData { |
MenuHandle mHandle; /* the popup menu handle */ |
short mID; /* the popup menu ID */ |
/* |
* after these two public fields is the mPrivate private data, |
* which may be any old size and should not be messed with |
*/ |
} popupPrivateData; |
/*------------------------------------------------------------ */ |
/* function prototypes for the application */ |
void SetUpRendererMenu( void ) ; |
void TearDownRendererMenu( void ) ; |
void LoadApplicationDialogs( void ) ; |
void LoadMenuBarForApplication( short myMenuBarID ) ; |
void FatalAlert( short theErrorMessage ) ; |
void InitializeToolBox( void ) ; |
Boolean HasQuickDraw3DViewer( void ) ; |
Boolean SupportsAEVT( void ) ; |
void RegisterRequiredAppleEventHandlers( void ) ; |
/* routines to handle the renderer progress bar */ |
ProgressBarDlogInfoHdl PB_New( |
DialogPtr thePBDialog, |
short thePBItemNumber, |
long maxValue, |
long currValue ) ; |
void PB_Update(ProgressBarDlogInfoHdl theInfo ) ; |
void PB_Delete(ProgressBarDlogInfoHdl theInfo ) ; |
pascal OSErr HandleCoreAppleEventOfTypeOAPP( AppleEvent *theAppleEvent, |
AppleEvent *theAppleEventReply, |
long userDefinedReferenceConstant) ; |
pascal OSErr HandleCoreAppleEventOfTypeODOC( AppleEvent *theAppleEvent, |
AppleEvent *theAppleEventReply, |
long userDefinedReferenceConstant) ; |
pascal OSErr HandleCoreAppleEventOfTypePDOC( AppleEvent *theAppleEvent, |
AppleEvent *theAppleEventReply, |
long userDefinedReferenceConstant) ; |
pascal OSErr HandleCoreAppleEventOfTypeQUIT( AppleEvent *theAppleEvent, |
AppleEvent *theAppleEventReply, |
long userDefinedReferenceConstant) ; |
void MainEventLoop( void ) ; |
TQ3Boolean HandleEvent( const EventRecord *theEventRecord ) ; |
void HandleKeyPress(EventRecord *theEventRecord) ; |
void HandleMenuCommand(long menuResult) ; |
void HandleAppleMenu( short menuItem ) ; |
void HandleFileMenu( short menuItem ) ; |
OSErr HandleFilePageSetupItem( WindowPtr theWindow ) ; |
OSErr HandleFilePrintItem( WindowPtr theWindow ) ; |
OSErr HandleFileQuitItem( void ) ; |
void HandleEditMenu( short menuItem ) ; |
pascal Boolean OurFilter(DialogPtr dlg, EventRecord *event, short *itemHit) ; |
void HandleViewFinalRendererOption( void ) ; |
void HandleInteractiveRendererMenu( short menuItem ) ; |
void HandleViewMenu( short menuItem ) ; |
OSErr GetViewerVersion( unsigned long *major, unsigned long *minor ) ; |
Boolean BackgroundColor(RGBColor *theRGBColor, unsigned char *thePrompt ) ; |
void AdjustMenus( void ) ; |
void DoDrawGrowIcon(WindowPtr theWindow) ; |
WindowPtr DoCreateNewViewerWindow( unsigned char *windowName ) ; |
void ViewerWindow_Update( WindowPtr theWindow ) ; |
void ViewerWindow_AdjustMenus( WindowPtr theWindow ) ; |
Boolean ViewerWindow_HandleEvent( WindowPtr theWindow, EventRecord *theEventRecord) ; |
WindowPtr ViewerWindow_New( unsigned char *windowTitle ) ; |
OSErr ViewerWindow_SaveAs( WindowPtr theWindow ) ; |
OSErr ViewerWindow_Save( WindowPtr theWindow ) ; |
OSErr ViewerWindow_Revert( WindowPtr theWindow ) ; |
WindowPtr ViewerWindow_Open( FSSpec *theFSSpec ) ; |
OSErr ViewerWindow_Close( WindowPtr theWindow ) ; |
short ViewerWindow_CountPages( WindowPtr theWindow, Rect *pageRect ) ; |
void ViewerWindow_PrintPage( WindowPtr theWindow, Rect *pageRect, GrafPtr imagingPort, short pageNum ) ; |
void ViewerWindow_PrePrint( WindowPtr theWindow ) ; |
void ViewerWindow_PostPrint( WindowPtr theWindow ) ; |
OSErr ViewerWindow_Cut( WindowPtr theWindow ) ; |
OSErr ViewerWindow_Copy( WindowPtr theWindow ) ; |
OSErr ViewerWindow_Paste( WindowPtr theWindow ) ; |
OSErr ViewerWindow_Clear( WindowPtr theWindow ) ; |
OSErr ViewerWindow_Undo( WindowPtr theWindow ) ; |
WindowPtr DoCreateNewPictWindow( unsigned char *windowName, long windWidth, long windHeight ) ; |
void PictWindow_Update( WindowPtr theWindow ) ; |
void PictWindow_AdjustMenus( WindowPtr theWindow ) ; |
Boolean PictWindow_HandleEvent( WindowPtr theWindow, EventRecord *theEventRecord) ; |
WindowPtr PictWindow_New( unsigned char *windowTitle ) ; |
OSErr PictWindow_SaveAs( WindowPtr theWindow ) ; |
OSErr PictWindow_Save( WindowPtr theWindow ) ; |
OSErr PictWindow_Revert( WindowPtr theWindow ) ; |
WindowPtr PictWindow_Open( FSSpec *theFSSpec ) ; |
OSErr PictWindow_Close( WindowPtr theWindow ) ; |
short PictWindow_CountPages( WindowPtr theWindow, Rect *pageRect ) ; |
void PictWindow_PrintPage( WindowPtr theWindow, Rect *pageRect, GrafPtr imagingPort, short pageNum ) ; |
void PictWindow_PrePrint( WindowPtr theWindow ) ; |
void PictWindow_PostPrint( WindowPtr theWindow ) ; |
OSErr PictWindow_Copy( WindowPtr theWindow ) ; |
/*------------------------------------------------------------ */ |
/* global variables */ |
DialogPtr gFinalRenderDialog = NULL ; /* the non interactive renderer dial0g */ |
DialogPtr gProgressModelessDialog = NULL ; |
Boolean gQuitFlag = false ; /* set to true to quit application */ |
AEAddressDesc gSelfAddress; /* A self-addressed address descriptor record */ |
/* these are used for the menus */ |
static TQ3ObjectType pInteractiveTypes[ kMaxRendererCount ] ; /* renderer types installed - includes plug-ins */ |
static TQ3ObjectType pNonInteractiveTypes[ kMaxRendererCount ] ; /* renderer types installed - includes plug-ins */ |
static long pNonInteractiveRendererCount = 0; /* the number of non-interactive renderers installed on this system */ |
static long pInteractiveRendererCount = 0; /* the number of interactive renderers installed on this system */ |
static Boolean pHasFinalQualityRenderer = false ; /* set true if one or more non interactive renderers are installed */ |
/* |
* this is a list of the installed renderers that we can use to switch easily. |
* By this point you are probably muttering that this app has way to many globals, |
* and you might be right, however keeping a list of renderer objects makes sense. |
* The most obvious reason to build a list of the available renderers, together |
* with an instance of each mish be efficiency considerations, but the real reason |
* is somewhat more subtle. We want renderer prefs to be "sticky". In other words |
* if I set prefs for a renderer I want those prefs to be the same for multiple |
* uses of the renderer. Just setting the renderer is not enough, since each time |
* a renderer object is created it is created with the default set of prefs which |
* may not be what I selected last time I bought the prefs dialog up. |
* |
* The way this structure is used is to build a list of renderer types and an |
* instance of each when the application is launched, then this list is used |
* whenever renderer prefs need to be set or when a new renderer is selected. |
* This way the prefs will stay with the renderer for the life time of the program. |
* |
* This list contains both interactive and non interactive renderers, it has no |
* real order (first come first served) and is seached linearly by renderer type. |
* |
* In the future, it might be good to build a list of renderer prefs for each |
* document and save these along with the document, or to have a global list of |
* prefs for the application.. |
*/ |
static struct { |
TQ3ObjectType fRendererType ; /* the object type for this renderer */ |
TQ3RendererObject fRendererObject ; /* an instance of the renderer type */ |
} pRendererList[ 2 * kMaxRendererCount ] ; |
static short pRendererCount = 0 ; /* indexes the pRendererList array */ |
ModalFilterUPP gModalFilterProcUPP ; |
/******************************************************************************** |
* Colors used to draw the progress bar |
*/ |
/* |
I got these by dumping a scroll bar from the MacOS 8 finder and poking around in photoshop. |
Color table, byte value (e.g. from photoshop) on LHS |
8bit 16bit 16bit (Hex) |
0, 0, 0x0000 |
51, 13107, 0x3333 |
102, 26214, 0x6666 |
136, 34952, 0x8888 |
153, 39321, 0x9999 |
170, 43690, 0xaaaa |
187, 48059, 0xbbbb |
204, 52428, 0xcccc |
221, 56797, 0xdddd |
255, 65535, 0xffff |
*/ |
const RGBColor RGBBlack = { 0x0000, 0x0000, 0x0000 } ; |
const RGBColor RGBDkGrey = { 0x8888, 0x8888, 0x8888 } ; |
const RGBColor RGBMedGrey = { 0xaaaa, 0xaaaa, 0xaaaa } ; |
const RGBColor RGBGrey = { 0xbbbb, 0xbbbb, 0xbbbb } ; |
const RGBColor RGBLtGrey = { 0xdddd, 0xdddd, 0xdddd } ; |
const RGBColor RGBWhite = { 0xffff, 0xffff, 0xffff } ; |
/* blue shades used */ |
const RGBColor RGBDkBlue = { 0x3333, 0x3333, 0x6666 } ; |
const RGBColor RGBMedBlue = { 0x6666, 0x6666, 0x9999 } ; |
const RGBColor RGBBlue = { 0x9999, 0x9999, 0xcccc } ; |
const RGBColor RGBLtBlue = { 0xcccc, 0xcccc, 0xffff } ; |
static GWorldPtr theStartCap = NULL; |
static GWorldPtr theEndCap = NULL ; |
static GWorldPtr theDropShadow = NULL ; |
const unsigned long kViewerMagic = 0xBADB00CA ; /* viewer windows */ |
const unsigned long kPICTMagic = 0xBADABADA ; /* picture windows */ |
/* these MUST be in the same order as above or bad things happen. |
* function procs for the regular viewer window. Setting these up |
* this way is a little dangerous, if the fields get jumbled up |
* unexpected results can happen, it might make more sense to use |
* a metahandler approach to install the methods - like QD3D |
* extensions... |
*/ |
Procs viewerProcs = { |
ViewerWindow_AdjustMenus, |
ViewerWindow_Update, |
ViewerWindow_HandleEvent, |
ViewerWindow_New, |
ViewerWindow_SaveAs, |
ViewerWindow_Save, |
ViewerWindow_Revert, |
ViewerWindow_Open, |
ViewerWindow_Close, |
ViewerWindow_CountPages, |
ViewerWindow_PrintPage, |
ViewerWindow_PrePrint, |
ViewerWindow_PostPrint, |
ViewerWindow_Cut, |
ViewerWindow_Copy, |
ViewerWindow_Paste, |
ViewerWindow_Clear, |
ViewerWindow_Undo |
}; |
/* function procs for the pict window */ |
Procs pictProcs = { |
PictWindow_AdjustMenus, |
PictWindow_Update, |
PictWindow_HandleEvent, |
PictWindow_New, |
PictWindow_SaveAs, |
PictWindow_Save, |
PictWindow_Revert, |
PictWindow_Open, |
PictWindow_Close, |
PictWindow_CountPages, |
PictWindow_PrintPage, |
NULL, /* pre print method is not supported */ |
NULL, /* post print method is not supported */ |
NULL, /* cut method is not supported */ |
PictWindow_Copy, |
NULL, /* paste method is not supported */ |
NULL, /* clear method is not supported */ |
NULL /* undo method is not supported */ |
}; |
/*------------------------------------------------------------ */ |
/* REMOVE THIS */ |
#include <Types.h> |
#include <Memory.h> |
#include <Quickdraw.h> |
#include <Gestalt.h> |
#include <Fonts.h> |
#include <Events.h> |
#include <Menus.h> |
#include <Windows.h> |
#include <TextEdit.h> |
#include <Dialogs.h> |
#include <OSUtils.h> |
#include <ToolUtils.h> |
#include <SegLoad.h> |
#include <Notification.h> |
#include <OSUtils.h> |
/* Prototypes */ |
Boolean IsVMCurrentlyOn(void) ; |
static Str255 VMIsCurrentlyOnStr = "\pVirtual memory is currently on" ; |
static Str255 VMIsCurrentlyOffStr = "\pVirtual memory is currently off" ; |
static NMRec myNotification ; |
void notify(void) |
{ |
OSErr theErr ; |
myNotification.qType = nmType ; |
myNotification.nmIcon = NULL ; |
myNotification.nmSound = NULL ; |
myNotification.nmResp = NULL ; |
myNotification.nmRefCon = 0L ; |
/* check Gestalt to see if VM is on */ |
if( IsVMCurrentlyOn() ) |
{ |
myNotification.nmStr = VMIsCurrentlyOnStr ; |
} |
else |
{ |
myNotification.nmStr = VMIsCurrentlyOffStr ; |
} |
theErr = NMInstall( &myNotification ) ; |
} |
/* |
* returns true if the VM is on |
*/ |
Boolean IsVMCurrentlyOn(void) |
{ |
OSErr theError; |
long response; |
theError = Gestalt(gestaltVMAttr, &response); |
if (theError!=noErr) |
return false; |
return (response && (response << gestaltVMPresent)); |
} |
/* END REMOVE THIS */ |
void main(void) |
{ |
InitializeToolBox() ; |
gModalFilterProcUPP = NewModalFilterProc( OurFilter ) ; |
LoadApplicationDialogs() ; |
LoadMenuBarForApplication( kAppMenuBarID ) ; |
/* |
* check that we have AppleEvents, and if so install the |
* AppleEvent handlers for the required AppleEvents |
*/ |
if( SupportsAEVT() ) |
{ |
RegisterRequiredAppleEventHandlers() ; |
/* |
* Check that the viewer is installed |
*/ |
if( HasQuickDraw3DViewer() ) |
{ |
Q3Initialize() ; |
SetUpRendererMenu() ; |
MainEventLoop() ; |
TearDownRendererMenu() ; |
Q3Exit() ; |
} |
} |
ExitToShell(); |
} |
/*------------------------------------------------------------ */ |
/* |
* Load the final quality renderer dialog. We do this here so |
* that we can set up the menu properly. Don't display it just |
* yet though. |
*/ |
void LoadApplicationDialogs(void) |
{ |
/* |
* load the dialog but don't show it. As a side note since the |
* dialog is going to be around for a while, the items in the dialog |
* should not be purgable. |
*/ |
gFinalRenderDialog = GetNewDialog( kFinalRenderDialogID, NULL, (WindowPtr)-1) ; |
gProgressModelessDialog = GetNewDialog( kProgressBarDlogID, NULL, (WindowPtr)-1) ; |
/* the popup menu for the renderers is item 9 */ |
} |
/*------------------------------------------------------------ */ |
/* |
* Load the menu bar specified. |
*/ |
void LoadMenuBarForApplication( short myMenuBarID ) |
{ |
Handle menuBar = NULL; |
/* |
*Read menus into menu bar specified by the resource |
* id passed into this routine by myMenuBarID |
*/ |
menuBar = GetNewMBar(myMenuBarID); |
if ( menuBar == NULL ) |
ExitToShell(); |
/* Install the menus we just read in */ |
SetMenuBar(menuBar); |
/* it is now safe to dispose the menu handle */ |
DisposeHandle(menuBar); |
/* |
* this next routine adds the names of desk accessories |
* to the specified menu, in this case the apple menu |
*/ |
AppendResMenu( GetMenuHandle( mAppleMenu ), 'DRVR' ); |
/* |
* now add the two hierarchical menus |
*/ |
InsertMenu(GetMenu( mInteractiveRendererMenu ), -1); |
/* call our routine to grey out menus as appropriate */ |
AdjustMenus() ; |
/* finally ensure the new menubar gets drawn */ |
DrawMenuBar(); |
} |
/*------------------------------------------------------------ */ |
/* |
* dispose of the global rtenderer list |
*/ |
void TearDownRendererMenu( void ) |
{ |
long theIndex ; |
for( theIndex = 0; theIndex < pRendererCount ; theIndex++ ) |
Q3Object_Dispose( pRendererList[ theIndex ].fRendererObject ) ; |
} |
/*------------------------------------------------------------ */ |
/* |
* set up the interactive renderer menu and the non interactive |
* renderer popup menu for the "final render" dialog. Build up |
* a list of renderer objects in the pRendererList struct to make |
* switching between renderers easier |
*/ |
void SetUpRendererMenu( void ) |
{ |
MenuHandle theMenu, interactiveRendererMenu, nonInteractiveRendererMenu ; |
TQ3SubClassData subClassData; |
TQ3ObjectType *classPointer; |
short i; |
TQ3ObjectClassNameString objectClassName; |
TQ3RendererObject tempRendererObject ; |
unsigned char nameBuffer[256] ; |
unsigned long actualLength ; |
TQ3ObjectClassNameString objectClassString ; |
Boolean isInteractive ; |
popupPrivateData **myPopupPrivateDataPtr ; |
/* some variables for accessing the fields of the dialog */ |
short iKind; |
Handle iHandle; |
Rect iRect; |
interactiveRendererMenu = GetMHandle(mInteractiveRendererMenu); |
/* |
* Set up the dialog renderer popup. We know the item number for the popup |
* we need to get the menuhandle associated with the control, it is in the private |
* control data field, as documented in Inside Macintosh: Toolbox page 5-77 |
*/ |
/* get the control handle for the popup from the dialog */ |
GetDialogItem ( gFinalRenderDialog, kFinalRendrPopup, &iKind, &iHandle, &iRect) ; |
/* extract from the control the menuhandle */ |
myPopupPrivateDataPtr = (popupPrivateData **)(**(ControlHandle)iHandle).contrlData ; |
nonInteractiveRendererMenu = (**myPopupPrivateDataPtr).mHandle ; |
HLock((Handle)nonInteractiveRendererMenu) ; |
/* the popup control has a problem under 7.5 and 7.6, since it expects the |
* menu to alredy be constructed otherwise the default value for the control |
* is 0, which means nothing is selected after the menu items have been added, |
* so i put a dummy item in the menu, we need to delete this before adding |
* any new items |
*/ |
DeleteMenuItem ( nonInteractiveRendererMenu, 1 ) ; |
Q3ObjectHierarchy_GetSubClassData(kQ3SharedTypeRenderer, &subClassData); |
classPointer = subClassData.classTypes; |
i = subClassData.numClasses; |
while( i-- > 0 && pInteractiveRendererCount <= kMaxRendererCount) { |
/* |
* the "generic" renderer is used internally, it can't draw, |
* so don't display it in any user interface item |
*/ |
if( *classPointer != kQ3RendererTypeGeneric ) |
{ |
/* |
* Q3RendererClass_GetNickNameString is only available on 1.5.1, so |
* check for the existance of this trap before calling. If the call |
* is not installed just set the string to NULL, we'll use the class name |
* instead and everthing will be hunky dory. |
*/ |
if( Q3RendererClass_GetNickNameString != (void *)kUnresolvedCFragSymbolAddress ) |
Q3RendererClass_GetNickNameString(*classPointer, objectClassString ); |
else |
objectClassString[0] = '\0' ; |
/* |
* Create an instance of a renderer object and then call |
* Q3Renderer_IsInteractive to determine if the renderer is |
* an interactive renderer (this is something the renderer |
* tells QuickDraw 3D). Stash the renderer and the type in |
* the pRendererList structure array. |
*/ |
tempRendererObject = Q3Renderer_NewFromType( *classPointer ) ; |
isInteractive = Q3Renderer_IsInteractive( tempRendererObject ) ; |
/* cache the renderer and type */ |
pRendererList[ pRendererCount ].fRendererType = *classPointer ; |
pRendererList[ pRendererCount ].fRendererObject = tempRendererObject; |
pRendererCount++ ; /* bump the count of elements in the array */ |
if( isInteractive ) |
{ |
theMenu = interactiveRendererMenu ; |
pInteractiveTypes[pInteractiveRendererCount++] = *classPointer ; |
} |
else |
{ |
theMenu = nonInteractiveRendererMenu ; |
pHasFinalQualityRenderer = true ; |
pNonInteractiveTypes[pNonInteractiveRendererCount++] = *classPointer ; |
} |
/* |
* check to see if we got a string back, if not use the renderer class name |
*/ |
if( objectClassString[0] == '\0' ) |
{ |
/* the renderer did not provide the name, just use the class name */ |
Q3ObjectHierarchy_GetStringFromType(*classPointer, objectClassName); |
AppendMenu(theMenu,c2pstr((char *)objectClassName)); |
} |
else |
{ |
AppendMenu(theMenu,c2pstr(objectClassString)); |
} |
} |
classPointer++ ; |
} |
HLock((Handle)nonInteractiveRendererMenu) ; |
/* null terminate the arrays */ |
pInteractiveTypes[pInteractiveRendererCount] = NULL ; |
pNonInteractiveTypes[pInteractiveRendererCount] = NULL ; |
pRendererList[ pRendererCount ].fRendererType = 0L ; |
pRendererList[ pRendererCount ].fRendererObject = NULL; |
Q3ObjectHierarchy_EmptySubClassData( &subClassData ) ; |
} |
/*------------------------------------------------------------ */ |
/* |
* Display an alert and quit. |
*/ |
void FatalAlert( short theErrorMessage ) |
{ |
unsigned char *thePString, theErrorStr[256] ; |
thePString = theErrorStr ; |
GetIndString( thePString, kErrorAlertStrings, theErrorMessage ) ; |
ParamText( thePString, "\p", "\p", "\p" ) ; |
StopAlert( kFatalAlert, NULL ) ; |
ExitToShell() ; |
} |
/*------------------------------------------------------------ */ |
/* |
* Initialize all the needed managers. |
*/ |
void InitializeToolBox( void ) |
{ |
/* |
* Initialize the toolbox managers |
*/ |
InitGraf((Ptr)&qd.thePort); |
InitFonts(); |
InitWindows(); |
InitMenus(); |
TEInit(); |
InitDialogs((long)NULL); |
InitCursor(); |
/* |
* must call this so that the heap is expanded to maximum |
* size before calling any viewer routines |
*/ |
MaxApplZone() ; |
} |
/*------------------------------------------------------------ */ |
/* |
* return true if the viewer is installed |
*/ |
Boolean HasQuickDraw3DViewer( void ) |
{ |
return((long) Q3ViewerNew != kUnresolvedCFragSymbolAddress) ; |
} |
/*------------------------------------------------------------ */ |
/* |
* returns true if the platform supports appleevents - we won't run |
* if it doesn't |
*/ |
Boolean SupportsAEVT(void) |
{ |
OSErr theError; |
long response; |
theError = Gestalt(gestaltAppleEventsAttr,&response); |
if (theError!=noErr) |
return false; |
return (response && (response << gestaltAppleEventsPresent)); |
} |
/******************************************************************************** |
* LoadPictIntoGWorld - read pict from the current resource chain, create a 32 bit |
* GWorld the size of the pict, image the pict into the GWorld, dispose of the |
* pict. Return a reference to the gworld. |
*/ |
static GWorldPtr LoadPictIntoGWorld( short resID ) |
{ |
Rect pictRect ; |
GWorldPtr theGWorld = NULL; |
QDErr theErr ; |
PicHandle aPicH = GetPicture(resID); |
if( aPicH != NULL ) |
{ |
/* create a GWorld the size of the pict */ |
pictRect.top = (**aPicH).picFrame.top ; |
pictRect.left = (**aPicH).picFrame.left ; |
pictRect.bottom = (**aPicH).picFrame.bottom ; |
pictRect.right = (**aPicH).picFrame.right ; |
OffsetRect(&pictRect, -pictRect.left, -pictRect.top); |
theErr = NewGWorld(&theGWorld, 32, &pictRect, NULL, NULL, 0L) ; |
if( theErr != noErr ) |
theGWorld = NULL ; |
else |
{ |
CGrafPtr savedPort ; |
GDHandle gdh ; |
GetGWorld( &savedPort, &gdh); |
SetGWorld( (CGrafPtr)theGWorld, NULL ) ; |
DrawPicture( aPicH, &theGWorld->portRect ) ; |
SetGWorld( savedPort, gdh); |
} |
} |
return theGWorld ; |
} |
/*------------------------------------------------------------ */ |
/* |
* PBNew set up for a new progress bar in a dialog, get all of the info we'll |
* need in order to draw it and allocate a GWorld to composite the Scroll bar. |
*/ |
ProgressBarDlogInfoHdl PB_New( |
DialogPtr thePBDialog, |
short thePBItemNumber, |
long maxValue, |
long currValue ) |
{ |
ProgressBarDlogInfoHdl theInfo ; |
/* first make sure we have the requisite pict's loaded */ |
if(theStartCap == NULL ) |
theStartCap = LoadPictIntoGWorld( kResIDStartCap ) ; |
if(theEndCap == NULL ) |
theEndCap = LoadPictIntoGWorld( kResIDEndCap ) ; |
if(theDropShadow == NULL ) |
theDropShadow = LoadPictIntoGWorld( kResIDDropShadow ) ; |
theInfo = (ProgressBarDlogInfoHdl)NewHandle(sizeof(ProgressBarDlogInfoData)) ; |
if( theInfo != NULL ) |
{ |
short itemType ; |
Handle item ; |
Rect box ; |
QDErr theErr ; |
GWorldPtr theOffscreen ; |
/* stash the other values passed in */ |
(**theInfo).thePBDialog = thePBDialog ; /* reference to the dialog containing the progressbar */ |
(**theInfo).thePBItemNumber = thePBItemNumber ; /* the item number in the dialog that is the progress bar */ |
(**theInfo).thePBMaxValue = maxValue ; /* the max value that the progress bar can be */ |
(**theInfo).thePBCurrValue = currValue ; /* current value of the progress bar (usually 0 ) */ |
/* get the rect of the given item number in local co-ordinates */ |
GetDialogItem(thePBDialog, thePBItemNumber, &itemType, &item, &box) ; |
/* save the box information, we'll use this to draw into */ |
(**theInfo).thePBRect.top = box.top ; |
(**theInfo).thePBRect.left = box.left ; |
(**theInfo).thePBRect.bottom = box.bottom ; |
(**theInfo).thePBRect.right = box.right ; |
OffsetRect( &box, -box.left, -box.top ) ; |
/* make a new GWorld for the progress bar, we composite the PB in here and copy to the screen */ |
theErr = NewGWorld( &theOffscreen, 32, &box, NULL, NULL, 0L); |
if( theErr != noErr || theOffscreen == NULL ) |
{ |
/* we couldn't create the offscree, zero the info rec. */ |
DisposeHandle((Handle)theInfo) ; |
theInfo = NULL ; |
} |
else |
{ |
(**theInfo).thePBGWorld = theOffscreen ; |
} |
} |
return theInfo ; |
} |
/*------------------------------------------------------------ */ |
/* |
* Redraw the progress bar, assumes the caller has just updated the |
* value in current. |
*/ |
void PB_Update( ProgressBarDlogInfoHdl theInfo ) |
{ |
CGrafPtr savedPort ; |
GDHandle gdh ; |
Rect theFrame ; |
short numPixels ; |
Rect tmpRect ; |
Rect destRect ; |
HLock((Handle)theInfo) ; |
GetGWorld( &savedPort, &gdh); |
SetGWorld( (CGrafPtr)(**theInfo).thePBGWorld, NULL ) ; |
/* fill the entire rect with the default grey */ |
RGBForeColor(&RGBGrey) ; |
PaintRect(&(**theInfo).thePBGWorld->portRect) ; |
/* frame the outline of the progress bar */ |
/* copy the rect to the frame rect */ |
theFrame.top = (**theInfo).thePBGWorld->portRect.top ; |
theFrame.left = (**theInfo).thePBGWorld->portRect.left ; |
theFrame.bottom = (**theInfo).thePBGWorld->portRect.bottom ; |
theFrame.right = (**theInfo).thePBGWorld->portRect.right ; |
/* how long is the progress part of the progress bar in pixels */ |
numPixels = ((float)(**theInfo).thePBCurrValue / (**theInfo).thePBMaxValue ) |
* ((**theInfo).thePBGWorld->portRect.right - (**theInfo).thePBGWorld->portRect.left - 2) ; |
/* and inset for the frame */ |
InsetRect( &theFrame, 1, 1 ) ; |
RGBForeColor( &RGBBlack ) ; |
FrameRect( &theFrame ) ; |
/* apply highlight to top and left edges (outermost) */ |
MoveTo( (**theInfo).thePBGWorld->portRect.left, |
(**theInfo).thePBGWorld->portRect.bottom - 1) ; |
RGBForeColor( &RGBLtGrey ) ; |
MoveTo( (**theInfo).thePBGWorld->portRect.left, |
(**theInfo).thePBGWorld->portRect.bottom - 2 ) ; |
RGBForeColor( &RGBMedGrey ) ; |
LineTo( (**theInfo).thePBGWorld->portRect.left, |
(**theInfo).thePBGWorld->portRect.top ); |
LineTo( (**theInfo).thePBGWorld->portRect.right - 1, |
(**theInfo).thePBGWorld->portRect.top ); |
/* hit the pixel at the top left */ |
RGBForeColor( &RGBLtGrey ) ; |
LineTo( (**theInfo).thePBGWorld->portRect.right, |
(**theInfo).thePBGWorld->portRect.top ); |
/* right and bottom edges */ |
RGBForeColor( &RGBWhite ) ; |
MoveTo( (**theInfo).thePBGWorld->portRect.right - 1, |
(**theInfo).thePBGWorld->portRect.top + 1 ) ; |
LineTo( (**theInfo).thePBGWorld->portRect.right - 1, |
(**theInfo).thePBGWorld->portRect.bottom - 1); |
LineTo( (**theInfo).thePBGWorld->portRect.left + 1, |
(**theInfo).thePBGWorld->portRect.bottom - 1); |
/* apply highlight to top and left edges (innermost) */ |
MoveTo( (**theInfo).thePBGWorld->portRect.left + 2, |
(**theInfo).thePBGWorld->portRect.bottom - 3) ; |
RGBForeColor( &RGBDkGrey ) ; |
LineTo( (**theInfo).thePBGWorld->portRect.left + 2, |
(**theInfo).thePBGWorld->portRect.top + 2 ) ; |
LineTo( (**theInfo).thePBGWorld->portRect.right - 4, |
(**theInfo).thePBGWorld->portRect.top + 2) ; |
/* hit the single pixel in the inside corner */ |
RGBForeColor( &RGBGrey ) ; |
LineTo( (**theInfo).thePBGWorld->portRect.right - 3, |
(**theInfo).thePBGWorld->portRect.top + 2) ; |
/* right and bottom */ |
RGBForeColor( &RGBLtGrey ) ; |
LineTo( (**theInfo).thePBGWorld->portRect.right - 3, |
(**theInfo).thePBGWorld->portRect.bottom - 3) ; |
LineTo( (**theInfo).thePBGWorld->portRect.left + 3, |
(**theInfo).thePBGWorld->portRect.bottom - 3) ; |
RGBForeColor( &RGBBlack ) ; |
/* set up the rect for the progress part of the PB */ |
tmpRect.top = theFrame.top ; |
tmpRect.left = theFrame.left ; |
tmpRect.bottom = theFrame.bottom ; |
tmpRect.right = theFrame.right ; |
InsetRect( & tmpRect, 1, 1 ) ; |
tmpRect.right = theFrame.left + numPixels ; |
/* lock the compositing GWorld for updates */ |
LockPixels(GetGWorldPixMap((**theInfo).thePBGWorld)) ; |
/* what do we want to draw today */ |
if( numPixels <= 8 ) |
{ |
/* we don't start doing the 3d effect until we have enough pixels for the |
* start and end caps, so before that just draw a blue rect. |
*/ |
RGBForeColor( &RGBBlue ) ; |
PaintRect(&tmpRect) ; |
RGBForeColor( &RGBBlack ) ; |
} |
else |
{ |
short startLine = tmpRect.top ; |
/* draw the line gradation */ |
MoveTo( tmpRect.left, startLine ) ; |
RGBForeColor( &RGBDkBlue ) ; |
LineTo( tmpRect.right, startLine++) ; |
MoveTo( tmpRect.left, startLine ) ; |
RGBForeColor( &RGBMedBlue ) ; |
LineTo( tmpRect.right, startLine++) ; |
MoveTo( tmpRect.left, startLine ) ; |
RGBForeColor( &RGBBlue ) ; |
LineTo( tmpRect.right, startLine++) ; |
MoveTo( tmpRect.left, startLine ) ; |
RGBForeColor( &RGBLtBlue ) ; |
LineTo( tmpRect.right, startLine++) ; |
MoveTo( tmpRect.left, startLine ) ; |
RGBForeColor( &RGBWhite ) ; |
LineTo( tmpRect.right, startLine++) ; |
MoveTo( tmpRect.left, startLine ) ; |
RGBForeColor( &RGBLtBlue ) ; |
LineTo( tmpRect.right, startLine++) ; |
MoveTo( tmpRect.left, startLine ) ; |
RGBForeColor( &RGBBlue ) ; |
LineTo( tmpRect.right, startLine++) ; |
MoveTo( tmpRect.left, startLine ) ; |
RGBForeColor( &RGBMedBlue ) ; |
LineTo( tmpRect.right, startLine++) ; |
MoveTo( tmpRect.left, startLine ) ; |
RGBForeColor( &RGBDkBlue ) ; |
LineTo( tmpRect.right, startLine++) ; |
MoveTo( tmpRect.left, startLine ) ; |
RGBForeColor( &RGBBlack ) ; |
LineTo( tmpRect.right, startLine++) ; |
if( theStartCap != NULL ) |
{ |
destRect.top = theStartCap->portRect.top ; |
destRect.left = theStartCap->portRect.left ; |
destRect.bottom = theStartCap->portRect.bottom ; |
destRect.right = theStartCap->portRect.right ; |
OffsetRect(&destRect, 2, 2) ; |
LockPixels(GetGWorldPixMap(theStartCap)) ; |
CopyBits( (BitMapPtr) &theStartCap->portPixMap, |
(BitMapPtr) &(**theInfo).thePBGWorld->portPixMap, |
& theStartCap->portRect, |
& destRect, |
srcCopy, |
0L ) ; |
UnlockPixels(GetGWorldPixMap(theStartCap)) ; |
} |
if( theEndCap != NULL ) |
{ |
destRect.top = theEndCap->portRect.top ; |
destRect.left = theEndCap->portRect.left ; |
destRect.bottom = theEndCap->portRect.bottom ; |
destRect.right = theEndCap->portRect.right ; |
OffsetRect(&destRect, numPixels + 2 - 6 , 2) ; |
LockPixels(GetGWorldPixMap(theEndCap)) ; |
CopyBits( (BitMapPtr) &theEndCap->portPixMap, |
(BitMapPtr) &(**theInfo).thePBGWorld->portPixMap, |
& theEndCap->portRect, |
& destRect, |
srcCopy, |
0L ) ; |
UnlockPixels(GetGWorldPixMap(theEndCap)) ; |
} |
} |
/* handle the drop shadow */ |
if( numPixels > 3 && theDropShadow != NULL ) |
{ |
destRect.top = theDropShadow->portRect.top ; |
destRect.left = theDropShadow->portRect.left ; |
destRect.bottom = theDropShadow->portRect.bottom ; |
destRect.right = theDropShadow->portRect.right ; |
OffsetRect(&destRect, numPixels + 2 - 3, 2) ; |
LockPixels(GetGWorldPixMap(theDropShadow)) ; |
CopyBits( (BitMapPtr) &theDropShadow->portPixMap, |
(BitMapPtr) &((**theInfo).thePBGWorld->portPixMap), |
& theDropShadow->portRect, |
& destRect, |
srcCopy, |
0L ) ; |
UnlockPixels(GetGWorldPixMap(theDropShadow)) ; |
} |
SetGWorld( savedPort, gdh ) ; |
CopyBits( (BitMapPtr) &(**theInfo).thePBGWorld->portPixMap, |
&(**theInfo).thePBDialog->portBits, |
&(**theInfo).thePBGWorld->portRect, |
&(**theInfo).thePBRect, |
srcCopy, |
0L ) ; |
UnlockPixels(GetGWorldPixMap((**theInfo).thePBGWorld)) ; |
HUnlock((Handle)theInfo) ; |
} |
/*------------------------------------------------------------ */ |
/* |
* free up a progress bar info record |
*/ |
void PB_Delete( ProgressBarDlogInfoHdl theInfo ) |
{ |
GWorldPtr theGWorld ; |
/* dispose of the GWorld associated with the info record */ |
if((theGWorld = (**theInfo).thePBGWorld ) != NULL ) |
DisposeGWorld( theGWorld ) ; |
/* |
* dispose of the memory allocated for the picts used to |
* build the progress bar first make sure we have the |
* requisite pict's loaded |
*/ |
if(theStartCap == NULL ) |
DisposeGWorld( theStartCap ) ; |
if(theEndCap == NULL ) |
DisposeGWorld( theEndCap ) ; |
if(theDropShadow == NULL ) |
DisposeGWorld( theDropShadow ) ; |
/* last of all blow away the info record */ |
DisposeHandle((Handle)theInfo) ; |
} |
/* printing support */ |
/*---------------------------------------------------------------------*/ |
/* |
* SetupPrintHdl - This routine returns a default print handle for the |
* current printer driver. |
* |
* The printer driver is expected to be closed upon entry, and is |
* therefore opened and closed in this routine. |
*/ |
OSErr SetupPrintHdl(THPrint *hPrint) |
{ |
OSErr err; |
/* |
* Create a handle, open the printer driver, set the |
* default values for the handle, and close the driver. |
* Be on the lookout for errors. |
*/ |
*hPrint = (THPrint) NewHandle(sizeof(TPrint)); |
if ( *hPrint != NULL ) |
{ |
PrOpen() ; |
err = PrError() ; |
if (err == noErr) |
{ |
PrintDefault( *hPrint ) ; |
err = PrError() ; |
} |
PrClose() ; |
} |
else |
err = MemError() ; |
return err; |
} |
void DoCreatePrintRecord( DocumentHdl theDocument ) |
{ |
Boolean changed = false ; |
char theState = 0 ; |
short theResRef ; |
FSSpec theFile ; |
/* create a new print record */ |
theState = HGetState( (Handle)theDocument ) ; |
MoveHHi( (Handle)theDocument ) ; |
HLock( (Handle)theDocument ) ; |
if(SetupPrintHdl( &(**theDocument).fPrintRec ) == noErr) |
{ |
/* check we have a "good" print record */ |
changed = PrValidate( (**theDocument).fPrintRec ) ; |
} |
HSetState( (Handle)theDocument, theState ) ; |
} |
/* ---------------------------------------------------------------------------------- */ |
OSErr DoStyleDlog(THPrint hPrint) |
{ |
OSErr err = noErr ; |
Boolean changed = false ; |
PrOpen() ; |
if((err = PrError()) == noErr ) { |
changed = PrStlDialog(hPrint); |
err = PrError(); |
if (!err && !changed) err = iPrAbort; |
} |
PrClose(); |
return err; |
} |
/* ---------------------------------------------------------------------------------- */ |
OSErr DoJobDlog(THPrint hPrint) |
{ |
OSErr err = noErr ; |
Boolean changed = false ; |
PrOpen() ; |
if((err = PrError()) == noErr ) { |
changed = PrJobDialog(hPrint); |
err = PrError(); |
if (!err && !changed) err = iPrAbort; |
} |
PrClose(); |
return err; |
} |
/* ---------------------------------------------------------------------------------- */ |
/* CommandPeriod - This routine checks to see if the user has */ |
/* pressed command-period. The Printing Manager does this */ |
/* for us, but a routine like this is helpful to allow users */ |
/* to cancel in the middle of a rendering routine, rather */ |
/* than only Printing Manager operations. */ |
/* */ |
/* If there's a command-period in the event queue, the */ |
/* routine returns iPrAbort just like the Printing Manager. */ |
/* Otherwise, it returns noErr. */ |
OSErr CommandPeriod() |
{ |
Boolean cancel = false; |
EventRecord evtRec; |
while (!cancel && (WaitNextEvent(keyDownMask | autoKeyMask, &evtRec, 0, NULL))) |
cancel = (evtRec.modifiers & cmdKey) && |
((evtRec.message & charCodeMask) == '.'); |
return ((cancel)? iPrAbort: noErr); |
} |
/* ---------------------------------------------------------------------------------- */ |
/* IdleProc - This routine is a PrIdleProcPtr that spins our */ |
/* cursor and looks for command-period presses during */ |
/* printing. */ |
pascal void IdleProc() |
{ |
OSErr err; |
// BumpCursor(); |
if (err = CommandPeriod()) |
PrSetError(err); |
} |
/* ---------------------------------------------------------------------------------- */ |
short GeneralCountPages( |
GWorldPtr theGWorld, |
Rect *pageRect ) |
{ |
Rect pictRect ; |
short horizOffset, |
vertOffset, |
pagesWide = 0, /* the number of pages wide the image is */ |
pagesHigh = 0, /* the number pages high for this image */ |
pageWidth, /* the width of one page */ |
pageHeight ; /* the height of one page */ |
DocumentHdl theDocumentHdl ; |
PictDataHdl thePictDataHdl ; |
OSErr theErr ; |
pictRect = theGWorld->portRect ; |
horizOffset = -(pictRect.left) ; |
vertOffset = -(pictRect.top) ; |
OffsetRect( &pictRect, horizOffset, vertOffset ) ; /* this should make the origin of the rect (0,0) */ |
pageWidth = pageRect->right - pageRect->left ; |
pageHeight = pageRect->bottom - pageRect->top ; |
pagesWide = (1.0 + pictRect.right / pageWidth ) ; /* round up the number of pages to the nearest */ |
pagesHigh = (1.0 + pictRect.top / pageHeight ) ; /* whole page in each direction. */ |
return pagesWide * pagesHigh ; |
} |
/* ---------------------------------------------------------------------------------- */ |
void GeneralPrintPage( |
GWorldPtr theGWorld, |
Rect *pageRect, |
GrafPtr imagingPort, |
short pageNum ) |
{ |
GWorldPtr docGWorld; |
Rect pictRect, rectToPrint,srcRect,dstRect; |
short pagesWide, /* the number of pages wide the image is */ |
pagesHigh, /* the number pages high for this image */ |
horozTile, /* used in the loop to denote the H tile to print from the image */ |
vertTile ; /* used in the loop to denote the V tile to print from the image */ |
short thisPage = 1; /* used to find the page they want us to print */ |
short pictHOff, |
pictVOff, |
pictWidth, /* the width of the doc's GWorld */ |
pictHeight ; /* the height of the doc's GWorld */ |
short pageWidth, /* the width of one page */ |
pageHeight ; /* the height of one page */ |
DocumentHdl theDocumentHdl ; |
PictDataHdl thePictDataHdl ; |
OSErr theErr ; |
PixMapHandle offPixMap ; |
pictRect = theGWorld->portRect ; |
SetPort( imagingPort ) ; |
pictHOff = -(pictRect.left) ; |
pictVOff = -(pictRect.top) ; |
pictWidth = pictRect.right - pictRect.left ; |
pictHeight = pictRect.bottom - pictRect.top ; |
pageWidth = pageRect->right - pageRect->left ; |
pageHeight = pageRect->bottom - pageRect->top ; |
pagesWide = (1.0 + pictWidth / pageWidth ) ; /* round up the number of pages to the nearest */ |
pagesHigh = (1.0 + pictHeight / pageHeight ) ; /* whole page in each direction. */ |
thisPage = 1; |
for (vertTile=0; vertTile<pagesHigh; vertTile++) |
{ |
for (horozTile=0; horozTile<pagesWide; horozTile++) |
{ |
/* check this is the page we were called to print */ |
if( thisPage == pageNum ) |
{ |
srcRect = *pageRect; |
OffsetRect( &srcRect, |
pictRect.left - srcRect.left, |
pictRect.top - srcRect.top ); |
OffsetRect( &srcRect, |
horozTile * pageWidth, |
vertTile * pageHeight ); |
SectRect( &srcRect, &pictRect, &srcRect); |
/* finess the rect to print, we'll assume the the top left is always correct. */ |
/* this helps with areas of the pict that don't fit entirely on one sheet of */ |
/* paper */ |
dstRect = srcRect; |
OffsetRect( &dstRect, |
pageRect->left - srcRect.left, |
pageRect->top - srcRect.top ); |
ClipRect( &dstRect ) ; |
/* get the gworld pixmap and lock it down */ |
offPixMap = GetGWorldPixMap( theGWorld ) ; |
(void) LockPixels( offPixMap ) ; |
/* copy from the gWorld Image to the window's port */ |
CopyBits( (BitMap *) *offPixMap, |
&imagingPort->portBits, |
&srcRect, |
&dstRect, |
srcCopy, |
NULL ) ; |
/* unlock the pixmap */ |
(void) UnlockPixels( offPixMap ) ; |
} |
/* bump the page number */ |
thisPage++ ; |
} |
} |
} |
/* ---------------------------------------------------------------------------------- */ |
OSErr DoPrintLoop( WindowPtr theWindow ) |
{ |
short savedResFile = CurResFile() ; |
GrafPtr savedPort ; |
TPPrPort printingPort ; |
OSErr theErr = noErr ; |
THPrint thePrintRec ; |
PrIdleUPP myIdleProc = NewPrIdleProc(IdleProc) ; |
DocumentHdl theDocumentHdl ; |
CountPagesProc countPagesP ; |
PrintPageProc printPageP ; |
theDocumentHdl = (DocumentHdl)GetWRefCon(theWindow) ; |
if(theDocumentHdl != NULL) |
{ |
thePrintRec = (**theDocumentHdl).fPrintRec ; |
GetPort( &savedPort ) ; |
PrOpen() ; |
if( (theErr = PrError()) == noErr ) { |
short numCopies = (**thePrintRec).prJob.iCopies ; |
short firstPage = (**thePrintRec).prJob.iFstPage ; /* save the first page */ |
short lastPage = (**thePrintRec).prJob.iLstPage; /* save the last page */ |
short copies, pageNum ; |
(**thePrintRec).prJob.iFstPage = 1 ; /* reset to 1 */ |
(**thePrintRec).prJob.iLstPage = iPrPgMax ; /* reset to maximum */ |
/* we don't assign this directly because NewPrIdleProc may move memory, */ |
/* so assign to an intermediate - myIdleProc */ |
(**thePrintRec).prJob.pIdleProc = myIdleProc; /* install the cursor spinning idle proc */ |
/* |
* since the count pages function is dereferenced by a pointer we have two choices, |
* either lock the handle, or copy the function pointer. |
*/ |
countPagesP = (**theDocumentHdl).procs->countPagesP ; |
/* if there is one, call the save handling proc with this window */ |
if( countPagesP ) |
lastPage = (*countPagesP)( theWindow, &(**thePrintRec).prInfo.rPage ) ; |
for( copies = 1; copies <= numCopies ; copies++ ) { |
printingPort = PrOpenDoc( thePrintRec, NULL, NULL ) ; |
SetPort( (GrafPtr)printingPort ) ; |
if((theErr = PrError()) == noErr ) { |
for( pageNum = firstPage; pageNum <= lastPage; pageNum++ ) { |
PrOpenPage( printingPort, NULL ) ; |
if((theErr = PrError()) == noErr ) { |
/* |
* since the print page function is dereferenced by a pointer |
* we have two choices, either lock the handle, or copy the |
* function pointer. |
*/ |
printPageP = (**theDocumentHdl).procs->printPageP ; |
/* image the page */ |
if( printPageP ) |
(*printPageP)( theWindow, &(**thePrintRec).prInfo.rPage, (GrafPtr)printingPort, pageNum ) ; |
PrClosePage(printingPort) ; |
} |
} |
if( (theErr = PrError()) == noErr ) { |
TPrStatus theStatus ; |
PrCloseDoc(printingPort) ; |
theErr = PrError() ; |
/* if we're printing to our good friend the ImageWriter, or similar, despool */ |
if( theErr == noErr && ((**thePrintRec).prJob.bJDocLoop == bSpoolLoop)) |
PrPicFile( thePrintRec, NULL, NULL, NULL, &theStatus ) ; |
} |
} |
} |
} |
PrClose() ; |
DisposeRoutineDescriptor((UniversalProcPtr)myIdleProc) ; |
SetPort( savedPort ) ; |
} |
return theErr ; |
} |
/*------------------------------------------------------------ */ |
/* |
* called to register our AppleEvent handlers. |
* |
* Should really have some error handling in here. |
*/ |
void RegisterRequiredAppleEventHandlers(void) |
{ |
OSErr theError; |
ProcessSerialNumber myApplicationPSN; /* This application's psn */ |
/* Set up a self-addressed descriptor record. */ |
myApplicationPSN.highLongOfPSN = 0; |
myApplicationPSN.lowLongOfPSN = kCurrentProcess ; |
theError = AECreateDesc(typeProcessSerialNumber, |
(Ptr)&myApplicationPSN, |
sizeof(ProcessSerialNumber), |
&gSelfAddress); |
if (theError!=noErr) |
return; |
theError = AEInstallEventHandler( kCoreEventClass, |
kAEOpenApplication, |
NewAEEventHandlerProc(HandleCoreAppleEventOfTypeOAPP), |
0L, |
false); |
if (theError!=noErr) |
return; |
theError = AEInstallEventHandler( kCoreEventClass, |
kAEOpenDocuments, |
NewAEEventHandlerProc(HandleCoreAppleEventOfTypeODOC), |
0L, |
false); |
if (theError!=noErr) |
return; |
theError = AEInstallEventHandler( kCoreEventClass, |
kAEPrintDocuments, |
NewAEEventHandlerProc(HandleCoreAppleEventOfTypePDOC), |
0L, |
false); |
if (theError!=noErr) |
return; |
theError = AEInstallEventHandler( kCoreEventClass, |
kAEQuitApplication, |
NewAEEventHandlerProc(HandleCoreAppleEventOfTypeQUIT), |
0L, |
false); |
if (theError!=noErr) |
return; |
} |
/*------------------------------------------------------------ */ |
/* |
* open application theEventRecord handler for the core theEventRecord suite, |
* by default we just want a blank new document |
*/ |
pascal OSErr HandleCoreAppleEventOfTypeOAPP( AppleEvent *theAppleEvent, AppleEvent *theAppleEventReply, long userDefinedReferenceConstant) |
{ |
/* |
* we don't actually do anything on open - you could, |
* for example you might want to open a blank untitled |
* theWindow |
*/ |
OSErr theError = noErr ; |
return theError; |
} |
/*------------------------------------------------------------ */ |
/* |
* handler for the open document AppleEvent handler |
*/ |
pascal OSErr HandleCoreAppleEventOfTypeODOC(AppleEvent *theAppleEvent, AppleEvent *theAppleEventReply, long userDefinedReferenceConstant) |
{ |
FSSpec theFileSpec; |
AEDescList theDocumentList; |
OSErr theError, |
theIgnoredError; |
long myTempIndex, |
numberOfItemsInList; |
Size actualSize; |
AEKeyword theAEKeyword; |
DescType theDescriptorType; |
theError = AEGetParamDesc(theAppleEvent,keyDirectObject,typeAEList,&theDocumentList); |
if (theError == noErr) { |
/* |
* see how many descriptor items are in the list |
* this is the number of documents we want to open |
*/ |
theError = AECountItems(&theDocumentList,&numberOfItemsInList); |
/* |
* now get each descriptor record from the list |
* coerce the returned data to an FSSpec record, and |
* open the asoociated file |
*/ |
for (myTempIndex=1; myTempIndex <= numberOfItemsInList && theError == noErr; myTempIndex++) { |
theError = AEGetNthPtr( &theDocumentList, |
myTempIndex, |
typeFSS, |
&theAEKeyword, |
&theDescriptorType, |
(Ptr)&theFileSpec, |
sizeof(theFileSpec), |
&actualSize); |
if (theError == noErr) { |
FInfo fndrInfo ; |
/* |
* we now have a valid FSSpec to reference the file, we need to know |
* what type the file is to determine which file open function to call |
* we can determine this from the finder info for the file |
*/ |
theError = FSpGetFInfo( &theFileSpec, &fndrInfo ); |
/* |
* if we got that ok, then we switch on the file |
* type (we don't care about the creator type) |
*/ |
if (theError == noErr) { |
switch( fndrInfo.fdType ) { |
case 'TEXT': /* your app should NOT really open text files since |
* they may not be of type 3DMF, this is here for |
* debugging, note that the standard file dlog will |
* not allow you to open TEXT files. |
*/ |
case '3DMF': |
ViewerWindow_Open( &theFileSpec ); |
break ; |
} |
} |
} |
} |
theIgnoredError = AEDisposeDesc(&theDocumentList); |
} |
return theError ; |
} |
/*------------------------------------------------------------ */ |
/* |
* handler for the print document theEventRecord handler |
*/ |
pascal OSErr HandleCoreAppleEventOfTypePDOC(AppleEvent *theAppleEvent,AppleEvent *theAppleEventReply,long userDefinedReferenceConstant) |
{ |
FSSpec theFileSpec; |
AEDescList theDocumentList; |
OSErr theError; |
long myTempIndex, |
numberOfItemsInList; |
Size actualSize; |
AEKeyword theAEKeyword; |
DescType theDescriptorType; |
theError = AEGetParamDesc(theAppleEvent,keyDirectObject,typeAEList,&theDocumentList); |
if (theError == noErr) { |
/* |
* see how many descriptor items are in the list |
* this is the number of documents we want to print |
*/ |
theError = AECountItems(&theDocumentList,&numberOfItemsInList); |
/* |
* now get each descriptor record from the list |
* coerce the returned data to an FSSpec record, and |
* print the asoociated file |
*/ |
for (myTempIndex=1; myTempIndex <= numberOfItemsInList && theError == noErr; myTempIndex++) { |
theError = AEGetNthPtr( &theDocumentList, |
myTempIndex, |
typeFSS, |
&theAEKeyword, |
&theDescriptorType, |
(Ptr)&theFileSpec, |
sizeof(theFileSpec), |
&actualSize); |
if (theError == noErr) { |
/* |
* if the app handles printing then you could do |
* something like: theError = HandlePrintDoc( &theFileSpec ); |
*/ |
theError = errAEEventNotHandled ; |
} |
} |
theError = AEDisposeDesc(&theDocumentList); |
} |
return theError ; |
} |
/*------------------------------------------------------------ */ |
/* |
* Quit AppleEvent handler |
*/ |
pascal OSErr HandleCoreAppleEventOfTypeQUIT(AppleEvent *theAppleEvent,AppleEvent *theAppleEventReply,long userDefinedReferenceConstant) |
{ |
OSErr theError = noErr ; /* this is used as the return value */ |
theError = HandleFileQuitItem() ; |
return theError ; |
} |
/*------------------------------------------------------------ */ |
/* |
* we want to handle events until the fronmost theWindow goes away |
*/ |
void MainEventLoop( void ) |
{ |
EventRecord theEventRecord; |
while( !gQuitFlag ) |
{ |
Point mouseLoc ; |
if (WaitNextEvent( everyEvent, &theEventRecord, GetCaretTime(), NULL )) |
{ |
AdjustMenus() ; |
( void ) HandleEvent( &theEventRecord ) ; |
} |
} |
} |
/*------------------------------------------------------------ */ |
/* |
* actually handle the event, this function can also be used for |
* the anchor for the renderer. |
*/ |
TQ3Boolean HandleEvent( const EventRecord *theEventRecord ) |
{ |
WindowPtr theWindow; |
GrafPtr savedPort ; |
short thePart; |
Rect screenRect; |
Rect growRect ; |
Point aPoint = {100, 100}; |
GrafPtr oldPort ; |
Boolean eventWasHandled = false ; |
unsigned long width ; |
unsigned long height ; |
long newSize ; |
OSErr theErr ; |
Point mouseLoc ; |
TQ3Boolean handledEvent = kQ3False ; |
TQ3ViewerObject theViewer = NULL ; |
ViewerDataHdl theViewerDataHdl ; |
DocumentHdl theDocumentHdl ; |
UpdateContentProc theUpdateProc ; |
HandleEventProc theEventProc ; |
CloseProc closeP ; |
SetCursor( &qd.arrow ) ; |
switch (theEventRecord->what) |
{ |
case mouseDown: |
/* we set up thePart in the window test at the top of this routine */ |
thePart = FindWindow ( theEventRecord->where, &theWindow ) ; |
switch( thePart ) { |
case inMenuBar: |
HandleMenuCommand(MenuSelect(theEventRecord->where)); |
handledEvent = kQ3True ; |
break; |
case inDrag: |
screenRect = (**GetGrayRgn()).rgnBBox; |
DragWindow( theWindow, theEventRecord->where, &screenRect ); |
handledEvent = kQ3True ; |
break ; |
case inContent: |
if (theWindow != FrontWindow()) |
{ |
SelectWindow( theWindow ); |
handledEvent = kQ3True ; |
} |
else |
{ |
theDocumentHdl = (DocumentHdl)GetWRefCon(theWindow) ; |
/* |
* since the update function is dereferenced by a pointer we have two choices, |
* either lock the handle, or copy the function pointer. |
*/ |
theEventProc = (**theDocumentHdl).procs->handleEventP ; |
/* if there is one, call the event handling proc with this window */ |
if( theEventProc ) |
handledEvent = (*theEventProc)( theWindow, theEventRecord ) ; |
else |
handledEvent = kQ3False ; |
} |
break ; |
case inGrow: |
/* |
* get the viewer object associated with this window |
*/ |
theDocumentHdl = (DocumentHdl)GetWRefCon(theWindow) ; |
if(theDocumentHdl != NULL) |
{ |
if((**theDocumentHdl).fDocumentMagic == kViewerMagic |
&& (theViewerDataHdl = (ViewerDataHdl)((**theDocumentHdl).fPrivate)) != NULL |
&& (theViewer = (**theViewerDataHdl).fViewer) != NULL ) |
{ |
/* |
* first we need to calculate the minimum size |
* for this viewer window, fortunately the |
* viewer library has a handy little utility |
* function that we can use here: |
*/ |
GetPort( &savedPort ) ; |
SetPort( (GrafPtr)theWindow ) ; |
theErr = Q3ViewerGetMinimumDimension( |
theViewer, |
&width, |
&height ); |
growRect.top = height + LMGetMBarHeight() ; /* the height of tuhe title bar is the same as the height of the menu bar */ |
growRect.left = width + 34; /* +34 so the grow box look neat */ |
growRect.bottom = kMaxHeight ; |
growRect.right = kMaxWidth ; |
newSize = GrowWindow(theWindow, theEventRecord->where, &growRect); |
if (newSize != 0) { |
width = LoWrd(newSize) ; |
height = HiWrd(newSize) ; |
SizeWindow(theWindow, width, height, true); |
Q3ViewerSetBounds( theViewer, &theWindow->portRect ) ; |
EraseRect( &theWindow->portRect ) ; |
Q3ViewerDraw( theViewer ) ; |
DoDrawGrowIcon( theWindow ) ; |
} |
handledEvent = kQ3True ; |
SetPort( savedPort ) ; |
} |
} |
break; |
case inGoAway: |
if (TrackGoAway( theWindow, theEventRecord->where )) { |
theDocumentHdl = (DocumentHdl)GetWRefCon(theWindow) ; |
closeP = (**theDocumentHdl).procs->closeP ; |
if( closeP ) |
(*closeP)( theWindow ) ; |
} |
handledEvent = kQ3True ; |
break ; |
default: |
break ; |
} |
break ; |
case updateEvt: |
handledEvent = kQ3True ; |
theWindow = (WindowPtr)theEventRecord->message; |
theDocumentHdl = (DocumentHdl)GetWRefCon(theWindow) ; |
/* |
* since the update function is dereferenced by a pointer we have two choices, |
* either lock the handle, or copy the finction pointer. |
*/ |
theUpdateProc = (**theDocumentHdl).procs->updateWindowP ; |
/* call the update proc with this window */ |
if( theUpdateProc ) |
(*theUpdateProc)(theWindow) ; |
break ; |
case keyDown: |
case autoKey: |
HandleKeyPress(theEventRecord); |
handledEvent = kQ3True ; |
break ; |
case diskEvt: |
if ( HiWrd(theEventRecord->message) != noErr ) |
(void) DIBadMount(aPoint, theEventRecord->message) ; |
handledEvent = kQ3True ; |
break ; |
case osEvt: |
case activateEvt: |
handledEvent = kQ3False ; |
break ; |
case kHighLevelEvent: |
AEProcessAppleEvent(theEventRecord); |
handledEvent = kQ3True ; |
break ; |
} |
Done: |
return handledEvent ; |
} |
/*------------------------------------------------------------ */ |
/* |
* handle keydow events, all we do is dispatch to the |
* menu handler if the command key is down, otherwise |
* the keypress is ignored. |
*/ |
void HandleKeyPress(EventRecord *theEventRecord) |
{ |
char key; |
key = theEventRecord->message & charCodeMask; |
/* check to see if we selected a menu */ |
if ( theEventRecord->modifiers & cmdKey ) { /* Command key down? */ |
HandleMenuCommand(MenuKey(key)); |
} |
} |
/*------------------------------------------------------------ */ |
/* |
* handle menu commands |
*/ |
void HandleMenuCommand(long menuResult) |
{ |
short menuID; |
short menuItem; |
menuID = HiWrd(menuResult); |
menuItem = LoWrd(menuResult); |
switch ( menuID ) { |
case mInteractiveRendererMenu: |
HandleInteractiveRendererMenu( menuItem ) ; |
break ; |
case mAppleMenu: |
HandleAppleMenu( menuItem ) ; |
break ; |
case mFileMenu: |
HandleFileMenu( menuItem ) ; |
break; |
case mEditMenu: |
HandleEditMenu( menuItem ) ; |
break ; |
case mViewMenu: |
HandleViewMenu( menuItem ) ; |
break ; |
} |
HiliteMenu(0); // Unhighlight whatever MenuSelect or MenuKey hilited |
} |
/*------------------------------------------------------------ */ |
/* |
* handle menu commands in the apple menu |
*/ |
void HandleAppleMenu( short menuItem ) |
{ |
Str255 daName; |
DialogPtr theDialog ; |
short itemHit ; |
switch ( menuItem ) { |
ModalFilterUPP theProc ; |
case iAppleAboutItem: |
theDialog = GetNewDialog ( kAboutDialogID, NULL, (WindowPtr)-1 ); |
GetStdFilterProc( &theProc ) ; |
SetDialogDefaultItem(theDialog, ok) ; |
do { |
ModalDialog ( theProc, &itemHit ); |
} while( itemHit != ok ) ; |
DisposDialog ( theDialog ); |
break; |
default: |
GetItem(GetMHandle(mAppleMenu), menuItem, daName); |
(void) OpenDeskAcc(daName); |
break; |
} |
} |
/*------------------------------------------------------------ */ |
/* |
* handle menu commands in the file menu |
*/ |
void HandleFileMenu( short menuItem ) |
{ |
WindowPtr theWindow ; |
StandardFileReply theSFReply ; |
DocumentHdl theDocumentHdl ; |
SaveAsProc saveAsP ; |
SaveProc saveP ; |
RevertProc revertP ; |
CloseProc closeP ; |
PrePrintProc prePrintP ; |
PostPrintProc postPrintP ; |
switch ( menuItem ) { |
case iFileNewItem: |
ViewerWindow_New( "\pViewer Window" ) ; |
break ; |
case iFileSaveAsItem: |
if( (theWindow = FrontWindow()) != NULL ) |
{ |
theDocumentHdl = (DocumentHdl)GetWRefCon(theWindow) ; |
/* |
* since the save function is dereferenced by a pointer we have two choices, |
* either lock the handle, or copy the function pointer. |
*/ |
saveAsP = (**theDocumentHdl).procs->saveAsP ; |
/* if there is one, call the save handling proc with this window */ |
if( saveAsP ) |
(*saveAsP)( theWindow ) ; |
} |
break ; |
case iFileSaveItem: |
if( (theWindow = FrontWindow()) != NULL ) |
{ |
theDocumentHdl = (DocumentHdl)GetWRefCon(theWindow) ; |
/* |
* since the save function is dereferenced by a pointer we have two choices, |
* either lock the handle, or copy the function pointer. |
*/ |
saveP = (**theDocumentHdl).procs->saveP ; |
/* if there is one, call the save handling proc with this window */ |
if( saveP ) |
(*saveP)( theWindow ) ; |
} |
break ; |
case iFileRevertItem: |
if( (theWindow = FrontWindow()) != NULL ) |
{ |
theDocumentHdl = (DocumentHdl)GetWRefCon(theWindow) ; |
/* |
* since the revert function is dereferenced by a pointer we have two choices, |
* either lock the handle, or copy the function pointer. |
*/ |
revertP = (**theDocumentHdl).procs->revertP ; |
/* if there is one, call the revert handling proc with this window */ |
if( revertP ) |
(*revertP)( theWindow ) ; |
} |
break ; |
/* these need to be converted */ |
case iFilePageSetupItem: |
if( (theWindow = FrontWindow()) != NULL ) |
{ |
THPrint thePrintRec ; |
theDocumentHdl = (DocumentHdl)GetWRefCon(theWindow) ; |
thePrintRec = (**theDocumentHdl).fPrintRec ; |
DoStyleDlog( thePrintRec ) ; |
} |
break ; |
case iFilePrintItem: |
if( (theWindow = FrontWindow()) != NULL ) |
{ |
THPrint thePrintRec ; |
theDocumentHdl = (DocumentHdl)GetWRefCon(theWindow) ; |
thePrintRec = (**theDocumentHdl).fPrintRec ; |
if( DoJobDlog( thePrintRec ) == noErr ) |
{ |
/* |
* since the preprint function is dereferenced by a pointer we have two choices, |
* either lock the handle, or copy the function pointer. |
*/ |
prePrintP = (**theDocumentHdl).procs->prePrintP ; |
/* if there is one, call the revert handling proc with this window */ |
if( prePrintP ) |
(*prePrintP)( theWindow ) ; |
DoPrintLoop( theWindow ) ; |
postPrintP = (**theDocumentHdl).procs->postPrintP ; |
/* if there is one, call the revert handling proc with this window */ |
if( postPrintP ) |
(*postPrintP)( theWindow ) ; |
} |
} |
break ; |
case iFileOpenItem: |
/* currently we only open 3dmf files */ |
/* Get the file name to open */ |
StandardGetFile( NULL, kNumTypes, kTypeList, &theSFReply ) ; |
/* did the user cancel? */ |
if(theSFReply.sfGood) |
ViewerWindow_Open( &theSFReply.sfFile ) ; /* no - process the file */ |
break ; |
case iFileCloseItem: |
if( (theWindow = FrontWindow()) != NULL ) |
{ |
theDocumentHdl = (DocumentHdl)GetWRefCon(theWindow) ; |
/* |
* since the revert function is dereferenced by a pointer we have two choices, |
* either lock the handle, or copy the function pointer. |
*/ |
closeP = (**theDocumentHdl).procs->closeP ; |
/* if there is one, call the revert handling proc with this window */ |
if( closeP ) |
(*closeP)( theWindow ) ; |
} |
break ; |
case iFileQuitItem: |
HandleFileQuitItem(); |
break; |
} |
} |
/*------------------------------------------------------------ */ |
/* |
* handles the Quit menu item in the file menu |
*/ |
OSErr HandleFileQuitItem( void ) |
{ |
OSErr theError = noErr ; /* this is used as the return value */ |
WindowPtr theWindow ; |
Boolean tempQuitFlag = true ; |
CloseProc closeP ; |
DocumentHdl theDocumentHdl ; |
/* |
* if the application has any open windows, close them before |
* tempQuitFlag. Since the user may cancelduring the process of |
* closing, make sure we don't quit the app, unless they can |
* be closed |
*/ |
while(( theWindow = FrontWindow()) != NULL && tempQuitFlag ) |
{ |
theDocumentHdl = (DocumentHdl)GetWRefCon(theWindow) ; |
/* |
* since the save function is dereferenced by a pointer we have two choices, |
* either lock the handle, or copy the function pointer. |
*/ |
closeP = (**theDocumentHdl).procs->closeP ; |
/* if there is one, call the save handling proc with this window */ |
if( closeP ) |
tempQuitFlag = ((*closeP)( theWindow ) == noErr) ; |
} |
/* |
* if we closed everything up successfully, return noErr, otherwise |
* indicate to the caller of this function that we canceled |
*/ |
if (tempQuitFlag) { |
gQuitFlag = true; /* in other word the user didn't cancel */ |
AEDisposeDesc(&gSelfAddress); /* don't forget to dispose of the */ |
} |
else { |
theError = userCanceledErr ; |
} |
return theError ; |
} |
/*------------------------------------------------------------ */ |
/* |
* handle menu commands in the edit menu |
* |
* To Do: each menu command needs to be factored into the list of procs |
* for the document type. |
*/ |
void HandleEditMenu( short menuItem ) |
{ |
DocumentHdl theDocumentHdl ; |
ViewerDataHdl theViewerHdl ; |
WindowPtr theWindow ; |
TQ3ViewerObject theViewer ; |
OSErr theError ; |
GrafPtr savedPort ; |
CutProc cutProc ; /* handle clipboard cut, same as copy followed by clear */ |
CopyProc copyProc ; /* handle clipboard copy */ |
PasteProc pasteProc ; /* paste compatible scrap type from the scrap */ |
ClearProc clearProc ; /* clear the document contents without a save to the scrap */ |
UndoProc undoProc ; /* undo the last action - if supported */ |
/* |
* because we do this we are assuming that this menu is disabled for the |
* case where there is no window. |
*/ |
theWindow = FrontWindow() ; |
SetPort((GrafPtr)theWindow) ; |
if( theWindow != NULL ) |
{ |
long aLong ; |
theDocumentHdl = (DocumentHdl)GetWRefCon(theWindow) ; |
switch ( menuItem ) |
{ |
case iEditUndoItem: |
undoProc = (**theDocumentHdl).procs->undoProc ; |
/* if there is one, call the undo handling proc with this window */ |
if( undoProc ) |
(*undoProc)( theWindow ) ; |
/* redraw the content region of the window to reflect the change */ |
GetPort( &savedPort ) ; |
SetPort( theWindow ) ; |
InvalRect( &theWindow->portRect ) ; |
SetPort( savedPort ) ; |
break ; |
case iEditCutItem: |
cutProc = (**theDocumentHdl).procs->cutProc ; |
/* if there is one, call the cut handling proc with this window */ |
if( cutProc ) |
(*cutProc)( theWindow ) ; |
aLong = UnloadScrap(); |
break ; |
case iEditCopyItem: |
copyProc = (**theDocumentHdl).procs->copyProc ; |
/* if there is one, call the copy handling proc with this window */ |
if( copyProc ) |
(*copyProc)( theWindow ) ; |
aLong = UnloadScrap(); |
break ; |
case iEditPasteItem: |
pasteProc = (**theDocumentHdl).procs->pasteProc ; |
/* if there is one, call the paste handling proc with this window */ |
if( pasteProc ) |
(*pasteProc)( theWindow ) ; |
aLong = UnloadScrap(); |
break ; |
case iEditClearItem: |
clearProc = (**theDocumentHdl).procs->clearProc ; |
/* if there is one, call the clear handling proc with this window */ |
if( clearProc ) |
(*clearProc)( theWindow ) ; |
aLong = UnloadScrap(); |
break ; |
case iEditRendererPrefsItem: |
{ |
/* this should probably be factored out somewhere */ |
TQ3RendererObject qd3dRenderer; |
TQ3ViewObject qd3dView; |
TQ3Status qd3dStatus; |
TQ3Boolean qd3dCanceled; |
TQ3DialogAnchor qd3dAnchor ; |
/* |
* get the reference to our viewer document data structure |
* from the long reference constant for the window. Cast |
* it to the appropriate type. If we can't get it (i.e. it's |
* null we want to bail |
*/ |
if(theDocumentHdl != NULL |
&& (**theDocumentHdl).fDocumentMagic == kViewerMagic |
&& (theViewerHdl = (ViewerDataHdl)((**theDocumentHdl).fPrivate)) != NULL) |
{ |
/* get the reference to the viewer object from our data structure */ |
theViewer = (**theViewerHdl).fViewer ; |
if(theViewer == NULL) |
return ; |
/* Get the renderer */ |
qd3dView = Q3ViewerGetView(theViewer); |
qd3dStatus = Q3View_GetRenderer(qd3dView, &qd3dRenderer); |
/* Put up the configure dialog */ |
if (Q3Renderer_HasModalConfigure(qd3dRenderer)) |
{ |
/* this will be modal */ |
qd3dAnchor.clientEventHandler = NULL; |
qd3dStatus = Q3Renderer_ModalConfigure( |
qd3dRenderer, |
qd3dAnchor, |
&qd3dCanceled); |
} |
/* Clean up */ |
qd3dStatus = Q3Object_Dispose(qd3dRenderer); |
/* |
* assume that the renderer prefs changed something |
* so redraw the content region of the window |
*/ |
GetPort( &savedPort ) ; |
SetPort( theWindow ) ; |
InvalRect( &theWindow->portRect ) ; |
SetPort( savedPort ) ; |
} |
} |
break; |
} |
} |
} |
/*------------------------------------------------------------ */ |
/* |
* utility function to get the viewer object |
* associated with a particular viewer window |
*/ |
TQ3ViewerObject GetViewerFromViewerWindow( WindowPtr theWindow ) |
{ |
OSErr theError = paramErr ; |
short theRef ; |
TQ3ViewerObject theViewer = NULL ; |
FSSpec theFSSpec ; |
DocumentHdl theDocumentHdl ; |
if( theWindow != NULL ) /* sanity check */ |
{ |
theDocumentHdl = (DocumentHdl)GetWRefCon(theWindow) ; |
if(theDocumentHdl != NULL |
&& (**theDocumentHdl).fDocumentMagic == kViewerMagic) |
{ |
/* get the viewer object from the document */ |
ViewerDataHdl theViewerHdl = (ViewerDataHdl)((**theDocumentHdl).fPrivate) ; |
if( theViewerHdl != NULL ) |
{ |
theViewer = (**theViewerHdl).fViewer ; |
} |
} |
} |
return theViewer ; |
} |
/*------------------------------------------------------------ */ |
/* |
* utility function to get the GWorld object |
* associated with a particular pict window |
*/ |
GWorldPtr GetGWorldFromPictWindow( WindowPtr theWindow ) |
{ |
DocumentHdl theDocumentHdl ; |
PictDataHdl thePictDataHdl ; |
GWorldPtr theGWorld = NULL; |
OSErr theErr ; |
if( theWindow != NULL ) /* sanity check */ |
{ |
theDocumentHdl = (DocumentHdl)GetWRefCon(theWindow) ; |
if(theDocumentHdl != NULL |
&& (**theDocumentHdl).fDocumentMagic == kPICTMagic |
&& (thePictDataHdl = (PictDataHdl)((**theDocumentHdl).fPrivate)) != NULL) |
{ |
theGWorld = (**thePictDataHdl).fGWorld; |
} |
} |
return theGWorld ; |
} |
/*------------------------------------------------------------ */ |
/* |
* utility function to get the renderer associated with a particular |
* type. Does a linear search of the pRendererList array to |
* retrieve the renderer object associated with the type passed in. |
* Will return NULL if the renderer type is not in the list. |
*/ |
TQ3RendererObject GetRendererByType(TQ3ObjectType theRendererType) |
{ |
TQ3RendererObject myRenderer = NULL ; |
long theIndex ; |
for( theIndex = 0; theIndex < pRendererCount; theIndex++ ) |
{ |
if( pRendererList[ theIndex ].fRendererType == theRendererType ) |
myRenderer = pRendererList[ theIndex ].fRendererObject ; |
} |
return myRenderer ; |
} |
/*------------------------------------------------------------ */ |
/* |
* utility function to set the renderer for a viewer |
*/ |
TQ3Status ViewerSetRenderer( TQ3ObjectType theRendererType, TQ3ViewerObject theViewer ) |
{ |
TQ3RendererObject myRenderer = NULL ; |
long theIndex ; |
TQ3ViewObject myView ; |
TQ3Status myStatus = kQ3Failure; |
OSErr theError ; |
myRenderer = GetRendererByType( theRendererType ) ; |
/* |
* set the renderer for the view |
*/ |
myView = Q3ViewerGetView( theViewer ); |
if( myView != NULL && myRenderer != NULL ) |
{ |
/* set the renderer to the one recovered in the loop above */ |
myStatus = Q3View_SetRenderer(myView, myRenderer) ; |
} |
return myStatus ; |
} |
/*------------------------------------------------------------ */ |
/* |
* handle menu commands in the renderer menu |
*/ |
void HandleInteractiveRendererMenu( short menuItem ) |
{ |
WindowPtr theWindow ; |
TQ3ObjectType theRendererType ; |
TQ3ViewerObject theViewer ; |
GrafPtr savedPort ; |
theWindow = FrontWindow() ; |
if( theWindow != NULL ) |
{ |
theViewer = GetViewerFromViewerWindow( theWindow ) ; |
theRendererType = pInteractiveTypes[ menuItem - 1 ] ; |
ViewerSetRenderer( theRendererType, theViewer ) ; |
GetPort(&savedPort) ; |
SetPort((GrafPtr)theWindow) ; |
InvalRect(&theWindow->portRect) ; |
SetPort(savedPort) ; |
} |
} |
/*------------------------------------------------------------ */ |
/* |
* If any of the variable argument scrap types are available for pasting from |
* the scrap, deliver the first one. Otherwise, deliver 0. For example, |
* |
* if (whichType = CanPaste(3,'TEXT','PICT','STUF')) ... |
* |
* There can be any number of types in the list, as long as the preceding count, n, |
* is correct. |
*/ |
static OSType CanPaste(int n, ...) |
{ |
register OSType nextType,ans = 0L; |
long err,offset; |
va_list nextArg; |
va_start(nextArg,n); |
nextType = va_arg(nextArg, OSType); |
while (n-- > 0) { |
err = GetScrap(NULL, nextType, &offset); |
if (err >= -1) { |
ans = nextType; |
break; |
} |
nextType = va_arg(nextArg, OSType); |
} |
va_end(nextArg); |
return(ans); |
} |
/*------------------------------------------------------------ */ |
/* |
* Deliver the number of the current editText item in given dialog if any text |
* is selected in it, or 0 if none selected. |
*/ |
int TextSelected(DialogPtr dlog) |
{ |
register TEHandle textH; |
short item = 0; |
textH = ((DialogPeek)dlog)->textH; |
if (*textH) |
if ( (*textH)->selStart != (*textH)->selEnd ) |
item = ((DialogPeek)dlog)->editField+1; |
return(item); |
} |
/*------------------------------------------------------------ */ |
/* |
* filter proc for the non-interactive renderer dialog |
*/ |
pascal Boolean OurFilter(DialogPtr dlg, EventRecord *event, short *itemHit) |
{ |
ModalFilterUPP theProc ; |
Boolean retVal ; |
static Boolean isDisabled = false ; |
OSErr theErr = noErr ; |
/* stuff for getditems etc */ |
Str255 theItem ; |
short iKind; |
Handle iHandle; |
Rect iRect; |
char theKey ; |
/* get the std filter proc */ |
theErr = GetStdFilterProc( &theProc ) ; |
if( theErr != noErr ) |
ExitToShell() ; |
/* try to call the standard filter, if it handles the event, we don't */ |
if( !(retVal = CallModalFilterProc(theProc, dlg, event, itemHit)) ) |
{ |
switch (event->what) { |
case nullEvent: |
break; |
case keyDown: |
case autoKey: |
theKey = event->message & charCodeMask; |
if( isalpha(theKey) || ispunct(theKey) || isspace(theKey) ) |
{ |
/* It's not a number, reject it */ |
SysBeep(1); |
/* tell the dialog manager that we handled this already and |
* it doesn't have to, so the keystroke will _not_ get |
* added to the edit line |
*/ |
retVal = true; |
} |
else if (event->modifiers & cmdKey) { |
unsigned char ch = (unsigned char)event->message; |
switch(ch) { |
case 'x': |
case 'X': |
if (TextSelected(dlg)) { |
SystemEdit(3); |
ZeroScrap(); |
DlgCut(dlg); |
TEToScrap(); |
} |
break; |
case 'c': |
case 'C': |
if (TextSelected(dlg)) { |
SystemEdit(3); |
ZeroScrap(); |
DlgCopy(dlg); |
TEToScrap(); |
} |
break; |
case 'v': |
case 'V': |
if (CanPaste(1,'TEXT')) { |
TEFromScrap(); |
DlgPaste(dlg); |
} |
break ; |
case 'a': |
case 'A': |
if (((DialogPeek)dlg)->editField >= 0) { |
/* Dialog has text edit item: select all */ |
SelIText(dlg,((DialogPeek)dlg)->editField+1,0,32767); |
} |
*itemHit = 0; |
break; |
} |
} |
else |
retVal = false; |
break ; |
case updateEvt: |
PenPat( &qd.ltGray ) ; |
/* get the text item we are drawing in */ |
GetDialogItem ( dlg, kFinalRendrSep1, &iKind, &iHandle, &iRect) ; |
FrameRect(&iRect ) ; |
GetDialogItem ( dlg, kFinalRendrSep2, &iKind, &iHandle, &iRect) ; |
FrameRect(&iRect ) ; |
GetDialogItem ( dlg, kFinalRendrSep3, &iKind, &iHandle, &iRect) ; |
FrameRect(&iRect ) ; |
PenPat( &qd.black ) ; |
/* |
* enable or disable the OK button depending on whether |
* we made a selection yet |
*/ |
GetDialogItem( dlg, ok, &iKind, &iHandle, &iRect) ; |
retVal = false; |
break ; |
default: |
retVal = false; |
break ; |
} |
} |
return retVal ; |
} |
/*------------------------------------------------------------ */ |
/* |
* IdleProgress method, handles setup, drawing and teardown for |
* the renderer progress dialog |
*/ |
TQ3Status MyViewIdleProgressMethod( |
TQ3ViewObject view, |
const void *idlerData, /* contains the dialog ref */ |
unsigned long current, |
unsigned long completed) |
{ |
/* |
* Return kQ3Failure to cancel rendering, kQ3Success to continue. Don't |
* bother posting an error. |
*/ |
TQ3Status retVal = kQ3Success ; |
DialogPtr theDialog = (DialogPtr)idlerData ; |
ProgressBarDlogInfoHdl theInfo ; |
CGrafPtr savedPort ; |
GDHandle savedGDH ; |
EventRecord theEvent ; |
char theKey ; |
/* |
* Q3View_SetIdleMethod registers a callback that can be called |
* by the system during rendering. Unfortunately there is no way yet |
* to set timer intervals when you want to be called. Basically, it is |
* up to the application's idler callback to check clocks to see if you |
* were called back only a millisecond ago or an hour ago! |
* |
* Q3View_SetIdleProgressMethod registers a callback that also gives |
* progress information. This information is supplied by the renderer, and |
* may or may not be based on real time. |
* |
* If a renderer doesn't support the progress method, your method will be |
* called with current == 0 and completed == 0. |
* |
* Otherwise, you are GUARANTEED to get called at least 2 or more times: |
* |
* ONCE idleMethod(view, 0, n) -> Initialize, Show Dialog |
* zero or more idleMethod(view, 1..n-1, n) -> Update progress |
* ONCE idleMethod(view, n, n) -> Exit, Hide Dialog |
* |
* "current" is guaranteed to be less than or equal to "completed" |
* "completed" may change values, but current/complete always indicates |
* the degree of completion. |
* |
* The calling conventions aid in managing any data associated with a |
* progress user interface indicator. |
*/ |
if( current == 0 && completed == 0 ) |
{ |
/* renderer doesn't support progress info, so just return success */ |
retVal = kQ3Success ; |
} |
else |
{ |
if( current == 0 ) |
{ |
/* |
* make a new progress bar dlog struct - we wait til here because |
* prior to this point we have no idea what the max and min values |
* are for the dialog. |
*/ |
theInfo = PB_New( theDialog, kProgressBarPBItemID, completed, current ) ; |
/* the theInfo rec in the refCon field of the dialog */ |
SetWRefCon((WindowPtr)theDialog, (long)theInfo); |
GetGWorld( &savedPort, &savedGDH ) ; |
SetGWorld( (CGrafPtr)theDialog, NULL ) ; |
/* make the hidden dialog visible */ |
ShowWindow( theDialog ) ; |
/* select it */ |
SelectWindow( theDialog ) ; |
/* draw the dialog */ |
UpdateDialog( theDialog, theDialog->visRgn ) ; |
SetGWorld( savedPort, savedGDH ) ; |
} |
else if( current == completed ) |
{ |
GetGWorld( &savedPort, &savedGDH ) ; |
SetGWorld( (CGrafPtr)theDialog, NULL ) ; |
/* draw the last part of the progress bar */ |
theInfo = (ProgressBarDlogInfoHdl)GetWRefCon((WindowPtr)theDialog) ; |
(**theInfo).thePBCurrValue = current ; |
/* update the progress bar */ |
PB_Update( theInfo ) ; |
SetGWorld( savedPort, savedGDH ) ; |
/* tear down the progressbar dialog struct */ |
theInfo = (ProgressBarDlogInfoHdl)GetWRefCon((WindowPtr)theDialog) ; |
DisposeHandle( (Handle)theInfo ) ; |
HideWindow( theDialog ) ; |
} |
else |
{ |
/* update the progress bar */ |
GetGWorld( &savedPort, &savedGDH ) ; |
SetGWorld( (CGrafPtr)theDialog, NULL ) ; |
theInfo = (ProgressBarDlogInfoHdl)GetWRefCon((WindowPtr)theDialog) ; |
(**theInfo).thePBCurrValue = current ; |
/* update the progress bar */ |
InvalRect( &theDialog->portRect ) ; |
DrawDialog( theDialog ) ; |
PB_Update( theInfo ) ; |
SetGWorld( savedPort, savedGDH ) ; |
} |
} |
/* |
* last thing... check the event queue to see if there is a keydown event, |
* we want to see if the user hit command period to cancel. Be warned - this |
* way of doing this will flush keyevents from the event queue. |
*/ |
if( GetOSEvent( (keyDownMask | autoKeyMask), &theEvent) == true ) |
{ |
/* examine the event to see if its a command period */ |
theKey = theEvent.message & charCodeMask; |
if( (theEvent.modifiers & cmdKey) && theKey == '.') |
{ |
/* |
* we want to cancel, we can signal this by returning kQ3Failure |
* before leaving this function, clean up & hide the progress dialog |
*/ |
/* tear down the progressbar dialog struct */ |
theInfo = (ProgressBarDlogInfoHdl)GetWRefCon((WindowPtr)theDialog) ; |
DisposeHandle( (Handle)theInfo ) ; |
HideWindow( theDialog ) ; |
SysBeep(10) ; |
retVal = kQ3Failure ; |
} |
} |
return retVal ; |
} |
/*------------------------------------------------------------ */ |
/* |
* The user chose to render with a non interactive renderer, put |
* up a dialog to allow them to select and configure the renderer |
* and copy the appropriate values from the current viewer window. |
* |
* this seems like a long winded way to do this. We create a viewer |
* use that to image (which will take advantage of the renderers updates |
* get the pict for the viewer, image that into the offscreen for the window. |
*/ |
void HandleViewFinalRendererOption( void ) |
{ |
WindowPtr theFrontWindow ; |
short itemHit ; |
GrafPtr savedPort ; |
popupPrivateData **myPopupPrivateDataPtr ; |
short iKind; |
Handle iHandle; |
Rect iRect; |
MenuHandle thePopupMenuHdl ; |
unsigned char rendererName[255] ; |
TQ3RendererObject theRenderer ; |
unsigned char numText[255] ; |
OSErr theErr ; |
long width ; |
long height ; |
long theControlValue = 0; |
/* |
* the final renderer option should only be available for a |
* viewer window, so we can assume the the front window at the |
* time this is called is a viewer |
*/ |
theFrontWindow = FrontWindow() ; |
GetPort( &savedPort ) ; |
SetPort( (GrafPtr)gFinalRenderDialog ) ; |
/* |
* TODO set the window size to whatever the current viewer window size is. |
* Since this can only get called is the front window is a viewer window, |
* indeed the exact window we are concerned with, then just use the dimensions |
* of the viewer. |
*/ |
width = theFrontWindow->portRect.right - theFrontWindow->portRect.left ; |
height = theFrontWindow->portRect.bottom - theFrontWindow->portRect.top ; |
NumToString ( height, numText ) ; |
GetDialogItem ( gFinalRenderDialog, kFinalRendrHeight, &iKind, &iHandle, &iRect) ; |
SetDialogItemText ( iHandle, numText ) ; |
NumToString ( width, numText ) ; |
GetDialogItem ( gFinalRenderDialog, kFinalRendrWidth, &iKind, &iHandle, &iRect) ; |
SetDialogItemText ( iHandle, numText ) ; |
InvalRect( &((GrafPtr)gFinalRenderDialog)->portRect) ; |
SetDialogDefaultItem(gFinalRenderDialog, kStdOkItemIndex) ; |
ShowWindow( (WindowPtr)gFinalRenderDialog ) ; |
SelectWindow( (WindowPtr)gFinalRenderDialog ) ; |
do { |
ModalDialog( gModalFilterProcUPP, &itemHit ) ; |
if( itemHit == kFinalRendrPopup ) { |
/* the user choose the popup. The item number selected will be the control value |
* we need to get the menuhandle associated with the control, it is in the private |
* control data field, as documented in Inside Macintosh: Toolbox page 5-77 |
*/ |
/* get the control handle for the popup */ |
GetDialogItem ( gFinalRenderDialog, kFinalRendrPopup, &iKind, &iHandle, &iRect) ; |
/* extract from the control the menuhandle */ |
myPopupPrivateDataPtr = (popupPrivateData **)(**(ControlHandle)iHandle).contrlData ; |
thePopupMenuHdl = (**myPopupPrivateDataPtr).mHandle ; |
/* get the string associated with the users selection */ |
HLock((Handle)iHandle) ; |
theControlValue = GetControlValue((ControlHandle)iHandle) ; |
GetMenuItemText ( thePopupMenuHdl, theControlValue, rendererName ); |
HUnlock((Handle)iHandle) ; |
/* reset itemHit to something else */ |
itemHit = 0 ; |
} |
else if( itemHit == kFinalRendrConfigure ) { |
/* get the control handle for the popup */ |
GetDialogItem ( gFinalRenderDialog, kFinalRendrPopup, &iKind, &iHandle, &iRect) ; |
/* extract from the control the menuhandle */ |
myPopupPrivateDataPtr = (popupPrivateData **)(**(ControlHandle)iHandle).contrlData ; |
thePopupMenuHdl = (**myPopupPrivateDataPtr).mHandle ; |
/* get the string associated with the users selection */ |
HLock((Handle)iHandle) ; |
theControlValue = GetControlValue((ControlHandle)iHandle) ; |
if( theControlValue != 0 ) |
{ |
theRenderer = GetRendererByType( pNonInteractiveTypes[theControlValue-1] ) ; |
if( theRenderer != NULL && Q3Renderer_HasModalConfigure( theRenderer )) |
{ |
TQ3DialogAnchor qd3dAnchor ; |
TQ3Boolean qd3dCanceled ; |
TQ3Status theStatus ; |
/* the renderer prefs dialog will be modal */ |
qd3dAnchor.clientEventHandler = NULL ; |
theStatus = Q3Renderer_ModalConfigure( |
theRenderer, |
qd3dAnchor, |
&qd3dCanceled) ; |
} |
} |
else |
SysBeep(10) ; |
} |
} while( itemHit != kStdCancelItemIndex && itemHit != kStdOkItemIndex ) ; |
/* we're done with the dialog window, hide it 'till next time */ |
HideWindow( (WindowPtr)gFinalRenderDialog ) ; |
/* check we didn't cancel */ |
if( itemHit == kStdOkItemIndex ) |
{ |
TQ3ViewerObject tempViewer ; |
WindowPtr finalImageWin ; |
PicHandle theImage ; |
/* get the control handle for the popup */ |
GetDialogItem ( gFinalRenderDialog, kFinalRendrPopup, &iKind, &iHandle, &iRect) ; |
/* extract from the control the menuhandle */ |
myPopupPrivateDataPtr = (popupPrivateData **)(**(ControlHandle)iHandle).contrlData ; |
thePopupMenuHdl = (**myPopupPrivateDataPtr).mHandle ; |
/* get the string associated with the users selection */ |
HLock((Handle)iHandle) ; |
theControlValue = GetControlValue((ControlHandle)iHandle) ; |
GetMenuItemText ( thePopupMenuHdl, theControlValue, rendererName ); |
HUnlock((Handle)iHandle) ; |
/* reset itemHit to something else */ |
itemHit = 0 ; |
/* get the window size - we can get the dialog item string and just StringToNum it |
* since our filter proc filders out all key stroked except digits |
*/ |
GetDialogItem ( gFinalRenderDialog, kFinalRendrHeight, &iKind, &iHandle, &iRect) ; |
GetDialogItemText ( iHandle, numText ) ; |
StringToNum ( numText, &height ) ; |
GetDialogItem ( gFinalRenderDialog, kFinalRendrWidth, &iKind, &iHandle, &iRect) ; |
GetDialogItemText ( iHandle, numText ) ; |
StringToNum ( numText, &width ) ; |
/* make a new window with the renderer name of the correct size */ |
finalImageWin = DoCreateNewPictWindow( rendererName, width, height ) ; |
/* make a viewer for this window with no controller */ |
if( finalImageWin != NULL ) |
{ |
/* get these from the original viewer referenced by FrontWindow */ |
TQ3GroupObject savedGroup ; |
TQ3CameraObject savedCamera ; |
TQ3GroupObject savedLights ; |
TQ3ColorARGB savedBGColor ; |
TQ3ViewerObject originalViewer ; |
TQ3ViewObject originalView ; |
unsigned long theViewerFlags ; |
GWorldPtr theGWorld ; |
CGrafPtr savedPort ; |
GDHandle savedGDH ; |
theGWorld = GetGWorldFromPictWindow( finalImageWin ) ; |
/* make a temp viewer to use to make the PICT */ |
if( theGWorld != NULL |
&& (tempViewer = Q3ViewerNew( (CGrafPtr)theGWorld, |
&theGWorld->portRect, |
kQ3ViewerDefault )) != NULL) |
{ |
/* lock the viewer's GWorld for updates */ |
LockPixels(GetGWorldPixMap(theGWorld)) ; |
GetGWorld( &savedPort, &savedGDH ) ; |
SetGWorld( (CGrafPtr)theGWorld, NULL ) ; |
originalViewer = GetViewerFromViewerWindow( theFrontWindow ) ; |
if( originalViewer != NULL ) |
{ |
TQ3ViewObject newView ; |
/* set the group up, copy from original viewer */ |
savedGroup = Q3ViewerGetGroup( originalViewer ) ; |
if( savedGroup != NULL ) |
{ |
Q3ViewerUseGroup( tempViewer, savedGroup) ; |
Q3Object_Dispose( savedGroup ) ; |
} |
/* copy the camera from the original viewer */ |
originalView = Q3ViewerGetView( originalViewer ) ; |
newView = Q3ViewerGetView( tempViewer ) ; |
if( originalView != NULL ) |
{ |
Q3View_GetCamera( originalView, &savedCamera ); |
if( savedCamera != NULL ) |
{ |
Q3View_SetCamera( newView, savedCamera ); |
Q3Object_Dispose( savedCamera ) ; |
} |
} |
/* copy the light group from the original viewer */ |
if( originalView != NULL ) |
{ |
Q3View_GetLightGroup( originalView, &savedLights ); |
if( savedCamera != NULL ) |
{ |
Q3View_SetLightGroup( newView, savedLights ); |
Q3Object_Dispose( savedLights ) ; |
} |
} |
/* copy the background color from the original viewer */ |
if( originalView != NULL ) |
{ |
Q3ViewerGetBackgroundColor( originalViewer, &savedBGColor ) ; |
if( savedCamera != NULL ) |
{ |
Q3ViewerSetBackgroundColor( tempViewer, &savedBGColor ) ; |
} |
} |
/* |
* we don't need to dispose the view, since viewergetview doesn't |
* increment the reference counts of the viewer. |
*/ |
theViewerFlags = Q3ViewerGetFlags( tempViewer ) ; |
theViewerFlags = theViewerFlags &~ kQ3ViewerControllerVisible; |
theViewerFlags = theViewerFlags &~ kQ3ViewerDrawFrame; |
theViewerFlags = theViewerFlags &~ kQ3ViewerDrawDragBorder; |
Q3ViewerSetFlags( tempViewer, theViewerFlags ) ; |
/* this is a little funky - we are using a modeless dialog to display the |
* progress of the render, but the main event loop will never get called, |
* since the dialog is only "called back" from the render. |
*/ |
if( gProgressModelessDialog != NULL ) |
{ |
/* install the callback */ |
Q3View_SetIdleProgressMethod( |
newView, |
MyViewIdleProgressMethod, |
(const void *)gProgressModelessDialog ) ; |
} |
/* image the document */ |
/* set the renderer to the renderer from the popup for this document */ |
ViewerSetRenderer( pNonInteractiveTypes[theControlValue-1], tempViewer ) ; |
Q3ViewerDraw( tempViewer ) ; |
/* dispose of the viewer object */ |
Q3ViewerDispose( tempViewer ) ; |
/* |
* it is possible that if the renderer does not follow the calling conventions |
* to update the progress dialog, that that dialog can be lest on the screen |
* so check the fron window, if it is the progress dialog then hide it |
*/ |
if( FrontWindow() == gProgressModelessDialog ) |
HideWindow( gProgressModelessDialog ) ; |
} |
SetGWorld( savedPort, savedGDH ) ; |
/* lock the viewer's GWorld for updates */ |
UnlockPixels(GetGWorldPixMap(theGWorld)) ; |
} |
} |
} |
else |
{ |
SelectWindow( theFrontWindow ) ; |
SetPort( savedPort ) ; |
} |
} |
/*------------------------------------------------------------ */ |
/* |
* handle menu commands in the view menu |
*/ |
void HandleViewMenu( short menuItem ) |
{ |
DocumentHdl theDocumentHdl ; |
ViewerDataHdl theViewerHdl ; |
WindowPtr theWindow ; |
TQ3ViewerObject theViewer ; |
unsigned long theViewerFlags; |
Rect theTmpRect ; |
GrafPtr savedPort ; |
RGBColor theRGBColor ; |
TQ3ColorARGB theViewerBGColor; |
theWindow = FrontWindow() ; |
if( theWindow != NULL ) |
{ |
/* |
* get the reference to our viewer document data structure |
* from the long reference constant for the window. Cast |
* it to the appropriate type. If we can't get it (i.e. it's |
* null we want to bail |
*/ |
theDocumentHdl = (DocumentHdl)GetWRefCon(theWindow) ; |
if(theDocumentHdl == NULL) |
return ; |
/* get the reference to the viewer object from our data structure */ |
if((theViewerHdl = (ViewerDataHdl)((**theDocumentHdl).fPrivate)) == NULL) |
return ; |
/* get the reference to the viewer object from our data structure */ |
theViewer = (**theViewerHdl).fViewer ; |
if(theViewer == NULL) |
return ; |
/* |
* since most of the items in this menu rely on adjusting |
* the viewer flags, we'll get the flags here so we can |
* bitwise manipulate them in the switch below |
*/ |
theViewerFlags = Q3ViewerGetFlags( theViewer ) ; |
switch ( menuItem ) |
{ |
case iViewFinalRendererItem: |
HandleViewFinalRendererOption() ; |
break ; |
/* |
* the renderer item in this menu is handled |
* by handlers for it's respective hierarchical |
* menus, so we just need to handle the ones below |
*/ |
case iViewBadgeItem: |
/* |
* this toggles the viewer bage and hides the |
* vcontroller, clicking in the badge will |
* hide the badge and show the controller |
*/ |
theViewerFlags ^= kQ3ViewerShowBadge; |
theViewerFlags ^= kQ3ViewerControllerVisible; |
Q3ViewerSetFlags( theViewer, theViewerFlags ) ; |
break ; |
case iViewCameraButtonItem: |
theViewerFlags ^= kQ3ViewerButtonCamera ; |
Q3ViewerSetFlags( theViewer, theViewerFlags ) ; |
break ; |
case iViewTruckButtonItem: |
theViewerFlags ^= kQ3ViewerButtonTruck ; |
Q3ViewerSetFlags( theViewer, theViewerFlags ) ; |
break ; |
case iViewOrbitButtonItem: |
theViewerFlags ^= kQ3ViewerButtonOrbit ; |
Q3ViewerSetFlags( theViewer, theViewerFlags ) ; |
break ; |
case iViewZoomButtonItem: |
theViewerFlags ^= kQ3ViewerButtonZoom ; |
Q3ViewerSetFlags( theViewer, theViewerFlags ) ; |
break ; |
case iViewDollyButtonItem: |
theViewerFlags ^= kQ3ViewerButtonDolly ; |
Q3ViewerSetFlags( theViewer, theViewerFlags ) ; |
break ; |
case iViewInsetNFrameItem: |
/* |
* this toggles drawing the viewer slightly smaller |
*than the window. We key off the kQ3ViewerDrawFrame |
* viewer flag - if it is set then we are already inset |
*/ |
theTmpRect = theWindow->portRect ; |
if( theViewerFlags & kQ3ViewerDrawFrame ) |
{ |
Q3ViewerSetBounds( theViewer, &theTmpRect ) ; |
} |
else |
{ |
InsetRect( &theTmpRect, kInsetPixelsConst, kInsetPixelsConst ) ; |
Q3ViewerSetBounds( theViewer, &theTmpRect ) ; |
} |
theViewerFlags ^= kQ3ViewerDrawFrame ; |
Q3ViewerSetFlags( theViewer, theViewerFlags ) ; |
GetPort( &savedPort ) ; |
SetPort( (GrafPtr)theWindow ) ; |
EraseRect( &theWindow->portRect ) ; |
SetPort( savedPort ) ; |
break ; |
case iViewSetBackgroundColorItem: |
Q3ViewerGetBackgroundColor(theViewer, &theViewerBGColor); |
theRGBColor.red = theViewerBGColor.r * 65535.0; |
theRGBColor.green = theViewerBGColor.g * 65535.0; |
theRGBColor.blue = theViewerBGColor.b * 65535.0; |
if(BackgroundColor( &theRGBColor, "\pPick a viewer background color:" )) |
{ |
theViewerBGColor.a = 1; |
theViewerBGColor.r = theRGBColor.red / 65535.0; |
theViewerBGColor.g = theRGBColor.green / 65535.0; |
theViewerBGColor.b = theRGBColor.blue / 65535.0; |
Q3ViewerSetBackgroundColor(theViewer, &theViewerBGColor); |
} |
break; |
} |
} |
GetPort( &savedPort ) ; |
SetPort( (GrafPtr)theWindow ) ; |
InvalRect( &theWindow->portRect ) ; |
SetPort( savedPort ) ; |
} |
Boolean BackgroundColor(RGBColor *theRGBColor, unsigned char *thePrompt ) |
{ |
ColorPickerInfo cpInfo; |
Boolean returnValue = false ; |
/* setting input color to be an RGB color */ |
cpInfo.theColor.color.rgb.red = (*theRGBColor).red; |
cpInfo.theColor.color.rgb.blue = (*theRGBColor).blue; |
cpInfo.theColor.color.rgb.green = (*theRGBColor).green; |
cpInfo.theColor.profile = 0L; |
/* no colorsync destination profile */ |
cpInfo.dstProfile = 0L; |
/* set the color picker flags */ |
cpInfo.flags = AppIsColorSyncAware | CanModifyPalette | |
CanAnimatePalette; |
/* center dialog box on the deepest color screen */ |
cpInfo.placeWhere = kDeepestColorScreen; |
/* use the system default picker */ |
cpInfo.pickerType = 0L; |
/* install event filter and color-changed functions */ |
cpInfo.eventProc = NULL; |
cpInfo.colorProc = NULL; |
cpInfo.colorProcData = 0L; |
/* sanity check */ |
if( thePrompt[ 0 ] >= 255 ) |
thePrompt[ 0 ] = 255 ; |
BlockMove( thePrompt, cpInfo.prompt, thePrompt[0] ) ; |
/* describe the Edit menu for Color Picker Manager */ |
cpInfo.mInfo.editMenuID = mEditMenu ; |
cpInfo.mInfo.cutItem = iEditCutItem; |
cpInfo.mInfo.copyItem = iEditCopyItem; |
cpInfo.mInfo.pasteItem = iEditPasteItem; |
cpInfo.mInfo.clearItem = iEditClearItem; |
cpInfo.mInfo.undoItem = iEditUndoItem; |
/* display dialog box to allow user to choose a color */ |
if(PickColor(&cpInfo) == noErr && cpInfo.newColorChosen) |
{ |
/* use this new color */ |
(*theRGBColor).red = cpInfo.theColor.color.rgb.red ; |
(*theRGBColor).blue = cpInfo.theColor.color.rgb.blue ; |
(*theRGBColor).green = cpInfo.theColor.color.rgb.green ; |
/* set up the return value */ |
returnValue = cpInfo.newColorChosen ; |
} |
return returnValue ; |
} |
/*------------------------------------------------------------ */ |
/* |
* make sure that menus are enabled and disabled in an |
* appropriate manner |
*/ |
void AdjustMenus( void ) |
{ |
MenuHandle theMenu ; |
DocumentHdl theDocumentHdl ; |
WindowPtr theWindow ; |
TQ3ViewerObject theViewer ; |
TQ3ViewObject myView ; |
TQ3Status myStatus ; |
TQ3RendererObject myRenderer ; |
TQ3ObjectType theRendererType ; |
long tmpLong, theScrapOffset ; |
unsigned long theViewerFlags; |
unsigned long theViewerState ; |
AdjustMenusProc myAdjustMenus ; |
char itemString[255] ; |
unsigned long itemStringLength ; |
theWindow = FrontWindow() ; |
/* do we have a viewer window open */ |
if( theWindow != NULL ) { |
/* |
* get the reference to our viewer document data structure |
* from the long reference constant for the window. Cast |
* it to the appropriate type. If we can't get it (i.e. it's |
* null we want to bail |
*/ |
theDocumentHdl = (DocumentHdl)GetWRefCon(theWindow) ; |
if(theDocumentHdl == NULL) |
return ; |
myAdjustMenus = (**theDocumentHdl).procs->adjustMenusP ; |
if( myAdjustMenus != NULL ) |
(*myAdjustMenus)(theWindow) ; |
} |
else { |
/* there is NOT a front window, set defaults for menu commands */ |
/* adjust the file menu */ |
theMenu = GetMHandle ( mFileMenu ) ; |
EnableItem ( theMenu, iFileNewItem ); /* always enabled */ |
EnableItem ( theMenu, iFileOpenItem ); /* always enabled */ |
EnableItem ( theMenu, iFileQuitItem ); /* always enabled */ |
DisableItem ( theMenu, iFileCloseItem ); |
DisableItem ( theMenu, iFileSaveItem ); |
DisableItem ( theMenu, iFileSaveAsItem ); |
DisableItem ( theMenu, iFileRevertItem ); |
DisableItem ( theMenu, iFilePageSetupItem ); |
DisableItem ( theMenu, iFilePrintItem ); |
/* adjust the edit menu */ |
theMenu = GetMHandle ( mEditMenu ) ; |
DisableItem ( theMenu, 0L ); |
/* disable the entire view menu if there is no window */ |
theMenu = GetMHandle ( mViewMenu ) ; |
DisableItem ( theMenu, 0L ); |
} |
DrawMenuBar() ; |
} |
/*------------------------------------------------------------ */ |
/* Determining the 3D Viewer version |
* |
* Version 1.5 of the 3D viewer adds some new APIs and new features. |
* In order for an application to determine at runtime that the version |
* 1.5 functionality of the 3D viewer is available an application must |
* check the version of the viewer. Unfortunately prior to version 1.5 |
* the 3D viewer did not have a gestalt or an API call to get its version. |
* Version 1.5 of the viewer adds a call Q3ViewerGetVersion. But an |
* application will want to first check that the Q3ViewerGetVersion |
* symbol is resolved before calling the Q3ViewerGetVersion function |
* on the chance the user has an older version of viewer shared library |
* installed. An application which depends on the newer functionality |
* will then need to take appropriate action such as displaying an alert |
* or disabling specific features. |
*/ |
OSErr GetViewerVersion( unsigned long *major, unsigned long *minor ) |
{ |
/* |
* version 1.0 of the QuickDraw 3D viewer did not |
* have a get version call, so check to see if the |
* symbol for the API routine descriptor is loaded |
*/ |
if((Boolean)Q3ViewerGetVersion == kUnresolvedCFragSymbolAddress) |
{ |
*major = 1; |
*minor = 0; |
return noErr; |
} |
else |
{ |
return Q3ViewerGetVersion(major, minor); |
} |
} |
/*------------------------------------------------------------ */ |
/* |
* DoDrawGrowIcon |
* |
* Draw the grow icon. We do this in such a way that the scrollbar lines are |
* not drawn. Normally, when the Toolbox routine DrawGrowIcon is called, |
* vertical and horizontal lines are also drawn indicating where the |
* scrollbars will be drawn. We donÕt have scrollbars, so we donÕt want those |
* lines drawn. We avoid them by setting the clipping region of the window to |
* include the grow box only. We then call DrawGrowIcon, and restore the old |
* clipping region before returning. |
* |
* Make sure that this gets called after the control strip for |
* a window is drawn. |
*/ |
void DoDrawGrowIcon(WindowPtr theWindow) |
{ |
Rect iconRect; |
RgnHandle oldClip; |
SetPort(theWindow); |
oldClip = NewRgn(); |
GetClip(oldClip); |
iconRect = theWindow->portRect; |
iconRect.top = iconRect.bottom - 15; |
iconRect.left = iconRect.right - 15; |
ClipRect(&iconRect); |
PenNormal(); |
DrawGrowIcon(theWindow); |
SetClip(oldClip); |
DisposeRgn(oldClip); |
} |
/*------------------------------------------------------------ */ |
/* |
* create a new viewer document window, this includes creating a |
* document record, a window and an associated viewer object. the |
* document record is stored in the window's refcon field, so it |
* can be accessed as required via the window record. |
*/ |
WindowPtr DoCreateNewViewerWindow( unsigned char *windowName ) |
{ |
WindowPtr theWindow ; |
Rect myRect = { 0, 0, kWindHeight, kWindWidth } ; |
TQ3ViewerObject myViewer ; |
DocumentHdl myViewerDocument = NULL ; |
/* create a document record to hold the */ |
/* data for this instance */ |
if((myViewerDocument = (DocumentHdl)NewHandleClear(sizeof(Document))) == NULL) |
return NULL ; |
/* ideally we should stagger the rect */ |
OffsetRect( &myRect, 50, 50 ) ; |
theWindow = NewCWindow( NULL, |
&myRect, |
windowName, |
true, |
documentProc, |
(WindowPtr)-1, |
true, |
0L ) ; |
/* create the viewer object associated with this window */ |
if((myViewer = Q3ViewerNew( (CGrafPtr)theWindow, |
&theWindow->portRect, |
kQ3ViewerDefault )) != NULL) |
{ |
ViewerDataHdl myViewerData = (ViewerDataHdl)NewHandleClear(sizeof(ViewerData)) ; |
if(myViewerData == NULL) |
{ |
DisposeHandle( (Handle)myViewerDocument ) ; |
return NULL ; |
} |
/* put the magic cookie in the first field so we can identify this as a valid viewer */ |
(**myViewerDocument).fDocumentMagic = kViewerMagic ; |
/* set up the procs field */ |
(**myViewerDocument).procs = &viewerProcs ; |
/* set up the private data part of the document structure */ |
(**myViewerData).fViewer = myViewer ; |
/* stuff the handle in the viewerdata field */ |
(**myViewerDocument).fPrivate = (void *) myViewerData ; |
/* store a reference to the document structure in the refcon |
* field of the window |
*/ |
SetWRefCon( theWindow, (long)myViewerDocument ) ; |
/* finally create a new print record */ |
DoCreatePrintRecord( myViewerDocument ) ; |
} |
else |
{ |
/* clean up any allocates storage and quit */ |
if( myViewerDocument ) |
DisposeHandle( (Handle)myViewerDocument ) ; |
if( theWindow ) |
CloseWindow( theWindow ) ; |
theWindow = NULL ; |
} |
return theWindow ; |
} |
/*------------------------------------------------------------ */ |
/* |
* handles the New menu item in the file menu |
*/ |
WindowPtr ViewerWindow_New( unsigned char *windowTitle ) |
{ |
WindowPtr theWindow ; |
theWindow = DoCreateNewViewerWindow( windowTitle ) ; |
return theWindow ; |
} |
/*------------------------------------------------------------ */ |
/* |
* handles the Save As menu item in the file menu |
*/ |
OSErr ViewerWindow_SaveAs( WindowPtr theWindow ) |
{ |
OSErr theError = paramErr ; |
short theRef ; |
TQ3ViewerObject theViewer ; |
StandardFileReply theSFReply ; |
DocumentHdl theDocumentHdl ; |
/* this option can't be selected unless there is a frontwindow */ |
/* the option is dimmed in adjustmenus if there is no window */ |
if( theWindow != NULL ) /* sanity check */ |
{ |
theDocumentHdl = (DocumentHdl)GetWRefCon(theWindow) ; |
if(theDocumentHdl != NULL |
&& (**theDocumentHdl).fDocumentMagic == kViewerMagic ) |
{ |
StandardPutFile("\pSave model as:", "\pUntitled", &theSFReply); |
if (theSFReply.sfGood) |
{ |
theError = FSpOpenDF(&theSFReply.sfFile, fsWrPerm, &theRef); |
if (theError != noErr) |
{ |
theError = FSpCreate(&theSFReply.sfFile, '????', '3DMF', theSFReply.sfScript); |
if (theError == noErr) |
theError = FSpOpenDF(&theSFReply.sfFile, fsCurPerm, &theRef); |
} |
if (theError == noErr) |
{ |
/* get the viewer object from the document */ |
ViewerDataHdl theViewerHdl = (ViewerDataHdl)((**theDocumentHdl).fPrivate) ; |
if( theViewerHdl != NULL ) |
{ |
HLock((Handle)theViewerHdl) ; |
(**theViewerHdl).fFSSpec = theSFReply.sfFile ; |
theViewer= (**theViewerHdl).fViewer ; |
theError = Q3ViewerWriteFile(theViewer, (long)theRef); |
theError = FSClose(theRef); |
HUnlock((Handle)theViewerHdl) ; |
} |
} |
/* reset the window title */ |
SetWTitle( theWindow, theSFReply.sfFile.name ); |
} |
} |
} |
return theError ; |
} |
/*------------------------------------------------------------ */ |
/* |
* handles the Save menu item in the file menu |
*/ |
OSErr ViewerWindow_Save( WindowPtr theWindow ) |
{ |
OSErr theError = paramErr ; |
short theRef ; |
TQ3ViewerObject theViewer ; |
DocumentHdl theDocumentHdl ; |
FSSpec theFSSpec ; |
/* this option can't be selected unless there is a frontwindow */ |
/* the option is dimmed in adjustmenus if there is no window */ |
if( theWindow != NULL ) /* sanity check */ |
{ |
theDocumentHdl = (DocumentHdl)GetWRefCon(theWindow) ; |
if(theDocumentHdl != NULL |
&& (**theDocumentHdl).fDocumentMagic == kViewerMagic) |
{ |
/* get the viewer object from the document */ |
ViewerDataHdl theViewerHdl = (ViewerDataHdl)((**theDocumentHdl).fPrivate) ; |
if( theViewerHdl != NULL ) |
{ |
HLock((Handle)theViewerHdl) ; |
theFSSpec = (**theViewerHdl).fFSSpec ; |
/* open the file */ |
theError = FSpOpenDF ( &theFSSpec, fsWrPerm, &theRef ) ; |
if( theError == noErr ) |
{ |
if((theViewer = (**theViewerHdl).fViewer) != NULL) |
{ |
theError = Q3ViewerWriteFile( theViewer, (long)theRef ); |
if( theError == noErr ) |
theError = FSClose ( theRef ) ; |
} |
} |
HUnlock((Handle)theViewerHdl) ; |
} |
} |
} |
return theError ; |
} |
/*------------------------------------------------------------ */ |
/* |
* handles the Revert menu item in the file menu |
*/ |
OSErr ViewerWindow_Revert( WindowPtr theWindow ) |
{ |
OSErr theError = paramErr ; |
short theRef ; |
GrafPtr savedPort ; |
TQ3ViewerObject theViewer ; |
DocumentHdl theDocumentHdl ; |
FSSpec theFSSpec ; |
/* this option can't be selected unless there is a frontwindow */ |
/* the option is dimmed in adjustmenus if there is no window */ |
if( theWindow != NULL ) /* sanity check */ |
{ |
theDocumentHdl = (DocumentHdl)GetWRefCon(theWindow) ; |
if(theDocumentHdl != NULL |
&& (**theDocumentHdl).fDocumentMagic == kViewerMagic) |
{ |
/* get the viewer object from the document */ |
ViewerDataHdl theViewerHdl = (ViewerDataHdl)((**theDocumentHdl).fPrivate) ; |
if( theViewerHdl != NULL ) |
{ |
HLock((Handle)theViewerHdl) ; |
theFSSpec = (**theViewerHdl).fFSSpec ; |
/* open the file */ |
theError = FSpOpenDF ( &theFSSpec, fsRdPerm, &theRef ) ; |
if( theError == noErr ) |
{ |
if((theViewer = (**theViewerHdl).fViewer) != NULL) |
{ |
theError = Q3ViewerUseFile( theViewer, (long)theRef ); |
if( theError == noErr ) |
theError = FSClose ( theRef ) ; |
} |
} |
HUnlock((Handle)theViewerHdl) ; |
} |
} |
} |
GetPort( &savedPort ) ; |
SetPort( (GrafPtr)theWindow ) ; |
InvalRect( &theWindow->portRect ) ; |
SetPort( savedPort ) ; |
return theError ; |
} |
WindowPtr ViewerWindow_Open( FSSpec *theFSSpec ) |
{ |
OSErr theError ; |
short theRef ; |
WindowPtr theWindow ; |
TQ3ViewerObject theViewer ; |
DocumentHdl theDocumentHdl ; |
/* open the file */ |
theError = FSpOpenDF( theFSSpec, fsRdPerm, &theRef ) ; |
if( theError == noErr ) |
{ |
theWindow = DoCreateNewViewerWindow( theFSSpec->name) ; |
if( theWindow != NULL ) |
{ |
theDocumentHdl = (DocumentHdl)GetWRefCon(theWindow) ; |
if(theDocumentHdl != NULL |
&& (**theDocumentHdl).fDocumentMagic == kViewerMagic) |
{ |
/* get the viewer object from the document */ |
ViewerDataHdl theViewerHdl = (ViewerDataHdl)((**theDocumentHdl).fPrivate) ; |
if( theViewerHdl != NULL ) |
{ |
HLock((Handle)theViewerHdl) ; |
if((theViewer = (**theViewerHdl).fViewer) != NULL) |
{ |
(**theViewerHdl).fFSSpec = *theFSSpec ; |
theError = Q3ViewerUseFile( theViewer, theRef ); |
if( theError == noErr ) |
theError = FSClose ( theRef ) ; |
} |
HUnlock((Handle)theViewerHdl) ; |
} |
} |
} |
} |
return theWindow ; |
} |
/*------------------------------------------------------------ */ |
/* |
* handles the close menu item in the file menu |
* close the window after disposing of the associated |
* data structures (viewer, etc). |
*/ |
OSErr ViewerWindow_Close( WindowPtr theWindow ) |
{ |
OSErr theError = paramErr ; |
TQ3ViewerObject theViewer ; |
DocumentHdl theDocumentHdl ; |
/* this option can't be selected unless there is a frontwindow */ |
/* the option is dimmed in adjustmenus if there is no window */ |
if( theWindow != NULL ) /* sanity check */ |
{ |
theDocumentHdl = (DocumentHdl)GetWRefCon(theWindow) ; |
if(theDocumentHdl != NULL |
&& (**theDocumentHdl).fDocumentMagic == kViewerMagic) |
{ |
/* get the viewer object from the document */ |
ViewerDataHdl theViewerHdl = (ViewerDataHdl)((**theDocumentHdl).fPrivate) ; |
/* dispose of the print record for the document */ |
THPrint thePrintRec = (**theDocumentHdl).fPrintRec ; |
if( thePrintRec != NULL ) |
DisposeHandle((Handle)thePrintRec ) ; |
if( theViewerHdl != NULL ) |
{ |
HLock((Handle)theViewerHdl) ; |
if((theViewer = (**theViewerHdl).fViewer) != NULL) |
{ |
theError = Q3ViewerDispose( theViewer ) ; |
if( theError == noErr ) |
DisposeWindow( theWindow ) ; |
} |
HUnlock((Handle)theViewerHdl) ; |
} |
} |
} |
return theError ; |
} |
/*------------------------------------------------------------ */ |
/* |
* handle event for a viewer window |
*/ |
Boolean ViewerWindow_HandleEvent( WindowPtr theWindow, EventRecord *theEventRecord) |
{ |
GrafPtr savedPort ; |
short thePart; |
Rect screenRect; |
Rect growRect ; |
Point aPoint = {100, 100}; |
GrafPtr oldPort ; |
Boolean eventWasHandled ; |
unsigned long width ; |
unsigned long height ; |
long newSize ; |
OSErr theErr ; |
Point mouseLoc ; |
TQ3Boolean handledEvent = kQ3False ; |
TQ3ViewerObject theViewer = NULL ; |
DocumentHdl theDocumentHdl ; |
ViewerDataHdl theViewerHdl ; |
/* |
* check to see if the event is a viewer event, also since |
* the update event processing needs to be done between begin update |
* and end update, don't handle updates here for viewer objects |
*/ |
if( theWindow != NULL && theEventRecord->what != updateEvt) |
{ |
theDocumentHdl = (DocumentHdl)GetWRefCon(theWindow) ; |
if(theDocumentHdl != NULL) |
{ |
if((**theDocumentHdl).fDocumentMagic == kViewerMagic |
&& ((theViewerHdl = (ViewerDataHdl)((**theDocumentHdl).fPrivate))) != NULL |
&& (theViewer = (**theViewerHdl).fViewer) != NULL ) |
{ |
/* |
* There is a bug in versions 1.0.4 and earlier of the Viewer, |
* so the port has to be set and restored. |
*/ |
GetPort( &oldPort ) ; |
SetPort((GrafPtr)theWindow ) ; |
eventWasHandled = Q3ViewerEvent( theViewer, theEventRecord ); |
DoDrawGrowIcon(theWindow) ; |
GetMouse( &mouseLoc ) ; |
Q3ViewerAdjustCursor( theViewer, &mouseLoc ); |
/* restore the port */ |
SetPort( oldPort ) ; |
/* |
* if the window is not the frontmost |
* window, give the eventhandler |
* a chance to process the event. |
*/ |
if(theWindow != FrontWindow()) |
eventWasHandled = false ; |
} |
} |
} |
else |
{ |
eventWasHandled = false ; |
} |
return eventWasHandled ; |
} |
/*------------------------------------------------------------ */ |
/* |
* handle update for a viewer window |
*/ |
void ViewerWindow_Update(WindowPtr theWindow) |
{ |
GrafPtr oldPort ; |
DocumentHdl theDocumentHdl ; |
ViewerDataHdl theViewerHdl ; |
TQ3ViewerObject theViewer ; |
OSErr theErr ; |
GetPort( &oldPort ) ; |
SetPort( theWindow ); |
BeginUpdate( theWindow ); |
{ |
theDocumentHdl = (DocumentHdl)GetWRefCon(theWindow) ; |
if(theDocumentHdl != NULL |
&& (**theDocumentHdl).fDocumentMagic == kViewerMagic |
&& (theViewerHdl = (ViewerDataHdl)((**theDocumentHdl).fPrivate)) != NULL) |
{ |
if((theViewer = (**theViewerHdl).fViewer) != NULL) |
{ |
theErr = Q3ViewerDraw( theViewer ); |
DoDrawGrowIcon(theWindow) ; |
} |
} |
} |
EndUpdate( theWindow ); |
SetPort( oldPort ) ; |
} |
/*------------------------------------------------------------ */ |
/* |
* make sure that menus are enabled and disabled in an |
* appropriate manner for the case where the front window |
* is a viewer window. |
*/ |
void ViewerWindow_AdjustMenus( WindowPtr theWindow ) |
{ |
MenuHandle theMenu ; |
DocumentHdl theDocumentHdl ; |
ViewerDataHdl theViewerHdl ; |
TQ3ViewerObject theViewer ; |
TQ3ViewObject myView ; |
TQ3Status myStatus ; |
TQ3RendererObject myRenderer ; |
TQ3ObjectType theRendererType ; |
long tmpLong, theScrapOffset ; |
unsigned long theViewerFlags; |
unsigned long theViewerState ; |
char itemString[255] ; |
unsigned long itemStringLength ; |
/* |
* get the reference to our viewer document data structure |
* from the long reference constant for the window. Cast |
* it to the appropriate type. If we can't get it (i.e. it's |
* null we want to bail |
*/ |
theDocumentHdl = (DocumentHdl)GetWRefCon(theWindow) ; |
if(theDocumentHdl == NULL) |
return ; |
/* get the reference to the viewer object from our data structure */ |
if((theViewerHdl = (ViewerDataHdl)((**theDocumentHdl).fPrivate)) == NULL) |
return ; |
/* get the reference to the viewer object from our data structure */ |
theViewer = (**theViewerHdl).fViewer ; |
if(theViewer == NULL) |
return ; |
/* get the viewer state, we need to know if it is empty */ |
theViewerState = Q3ViewerGetState( theViewer ) ; |
/* adjust the file menu */ |
theMenu = GetMHandle ( mFileMenu ) ; |
EnableItem ( theMenu, iFileNewItem ); /* always enabled */ |
EnableItem ( theMenu, iFileOpenItem ); /* always enabled */ |
EnableItem ( theMenu, iFileQuitItem ); /* always enabled */ |
EnableItem ( theMenu, iFileCloseItem ); |
if( ((theViewerState & kQ3ViewerHasModel) ? true : false ) ) |
{ |
EnableItem ( theMenu, iFileSaveItem ); |
EnableItem ( theMenu, iFileSaveAsItem ); |
EnableItem ( theMenu, iFileRevertItem ); |
EnableItem ( theMenu, iFilePageSetupItem ); |
EnableItem ( theMenu, iFilePrintItem ); |
} |
else |
{ |
DisableItem ( theMenu, iFileSaveItem ); |
DisableItem ( theMenu, iFileSaveAsItem ); |
DisableItem ( theMenu, iFileRevertItem ); |
DisableItem ( theMenu, iFilePageSetupItem ); |
DisableItem ( theMenu, iFilePrintItem ); |
} |
/* adjust the edit menu */ |
theMenu = GetMHandle ( mEditMenu ) ; |
EnableItem ( theMenu, 0L ); |
if( ((theViewerState & kQ3ViewerHasUndo) ? true : false ) ) |
{ |
/* undo is possible, get the string for this item and enable it */ |
Boolean canUndo ; |
/* |
* Hokeyness alert. We pass in the address of the second element of |
* the itemString array, allowing us to set the length later in the |
* first element of the array, saving us the need to to an inplace |
* C to P string conversion (the Mac toolbox routines require a |
* pascal format string that has the length as the first byte. |
*/ |
canUndo = Q3ViewerGetUndoString( theViewer, &itemString[1], &itemStringLength ); |
itemString[0] = (char)itemStringLength ; |
/* if we can undo then enable the new string, else use the default cant undo string */ |
if( canUndo == true && itemStringLength > 0 ) |
{ |
SetMenuItemText ( theMenu, iEditUndoItem, (unsigned char *)itemString ) ; |
EnableItem ( theMenu, iEditUndoItem ); |
} |
else |
{ |
GetIndString ( (unsigned char *)itemString, 2223, 1 ) ; |
SetMenuItemText ( theMenu, iEditUndoItem, (unsigned char *)itemString ) ; |
DisableItem ( theMenu, iEditUndoItem ); |
} |
} |
else |
{ |
GetIndString ( (unsigned char *)itemString, 2223, 1 ) ; |
SetMenuItemText ( theMenu, iEditUndoItem, (unsigned char *)itemString ) ; |
DisableItem ( theMenu, iEditUndoItem ); |
} |
if( ((theViewerState & kQ3ViewerHasModel) ? true : false ) ) |
{ |
EnableItem ( theMenu, iEditCutItem ); |
EnableItem ( theMenu, iEditCopyItem ); |
EnableItem ( theMenu, iEditClearItem ); |
} |
else |
{ |
DisableItem ( theMenu, iEditCutItem ); |
DisableItem ( theMenu, iEditCopyItem ); |
DisableItem ( theMenu, iEditClearItem ); |
} |
/* |
* check that there is some data that we can paste. GetScrap returns |
* a long that gives either the length of the requested type, or a |
* negative error code that is used to indicate that no such type exists |
*/ |
tmpLong = GetScrap( NULL, '3DMF', &theScrapOffset ) ; |
if( tmpLong < 0 ) |
DisableItem ( theMenu, iEditPasteItem ); |
else |
EnableItem ( theMenu, iEditPasteItem ); |
/* adjust the view menu */ |
theMenu = GetMHandle ( mViewMenu ) ; |
EnableItem ( theMenu, 0L ); |
/* |
* since most of the items in this menu rely on adjusting |
* the viewer flags, we'll get the flags here so we can |
* bitwise manipulate them in the switch below |
*/ |
theViewerFlags = Q3ViewerGetFlags( theViewer ) ; |
/* |
* check each of the items that have their flag |
* bits set to true in the viewer flags. |
* |
* Note that the Boolean flag for CheckItem is defined |
* (( theViewerFlags & kQ3ViewerShowBadge ) ? true : false) |
* and so on. The reson for this is that simply adding |
* ( theViewerFlags & kQ3ViewerShowBadge ) won't be sufficient |
* if the flag is the 8th bit or more of the unsigned long |
* defined to hold the flages, since the param passed will |
* only be the first 8 bits (of couse this is dependent on |
* the develolment system size for Boolean, but this is true |
* for CodeWarrior. |
*/ |
CheckItem( theMenu, iViewBadgeItem, (( theViewerFlags & kQ3ViewerShowBadge ) ? true : false)) ; |
CheckItem( theMenu, iViewCameraButtonItem, (( theViewerFlags & kQ3ViewerButtonCamera ) ? true : false)) ; |
CheckItem( theMenu, iViewTruckButtonItem, (( theViewerFlags & kQ3ViewerButtonTruck ) ? true : false)) ; |
CheckItem( theMenu, iViewOrbitButtonItem, (( theViewerFlags & kQ3ViewerButtonOrbit ) ? true : false)) ; |
CheckItem( theMenu, iViewZoomButtonItem, (( theViewerFlags & kQ3ViewerButtonZoom ) ? true : false)) ; |
CheckItem( theMenu, iViewDollyButtonItem, (( theViewerFlags & kQ3ViewerButtonDolly ) ? true : false)) ; |
CheckItem( theMenu, iViewInsetNFrameItem, (( theViewerFlags & kQ3ViewerDrawFrame ) ? true : false)) ; |
/* adjust the renderer menu */ |
theMenu = GetMHandle ( mInteractiveRendererMenu ) ; |
/* |
* get the renderer for the view |
*/ |
myView = Q3ViewerGetView( theViewer ); |
if( myView != NULL ) |
{ |
long rendererIndex = 0 ; |
MenuHandle tempMenu ; |
/* set the renderer to the one created in the switch statement above */ |
myStatus = Q3View_GetRenderer(myView, &myRenderer) ; |
theRendererType = Q3Renderer_GetType( myRenderer ) ; |
for( rendererIndex = 0; pInteractiveTypes[ rendererIndex ] ; rendererIndex++ ) |
{ |
CheckItem( theMenu, rendererIndex+1, (theRendererType == pInteractiveTypes[rendererIndex])) ; |
} |
/* |
* Update the edit renderer prefs "edit menu" item. Should probably be done with |
* the edit menu stuff, I put this here because we have a reference |
* to the renderer here |
*/ |
/* enable the menu item appropriately */ |
tempMenu = GetMHandle ( mEditMenu ) ; |
if( Q3Renderer_HasModalConfigure(myRenderer) ) |
EnableItem ( tempMenu, iEditRendererPrefsItem ); |
else |
DisableItem ( tempMenu, iEditRendererPrefsItem ); |
/* |
* getting the renderer incremented the ref count for it, |
* we can dispose of the reference to it |
*/ |
myStatus = Q3Object_Dispose( myRenderer ) ; |
} |
} |
/*------------------------------------------------------------ */ |
/* |
* ViewerWindow_CountPages - calculate the number of pages needed to |
* image the document associated with the viewer window. For now we |
* assume 1. |
*/ |
short ViewerWindow_CountPages( |
WindowPtr theWindow, |
Rect *pageRect ) |
{ |
Rect pictRect ; |
short horizOffset, |
vertOffset, |
pagesWide = 0, /* the number of pages wide the image is */ |
pagesHigh = 0, /* the number pages high for this image */ |
pageWidth, /* the width of one page */ |
pageHeight ; /* the height of one page */ |
DocumentHdl theDocumentHdl ; |
ViewerDataHdl theViewerHdl ; |
GWorldPtr theGWorld ; |
OSErr theErr ; |
short retVal = 0 ; |
PicHandle thePicture ; |
theDocumentHdl = (DocumentHdl)GetWRefCon(theWindow) ; |
if(theDocumentHdl != NULL |
&& (**theDocumentHdl).fDocumentMagic == kViewerMagic |
&& (theViewerHdl = (ViewerDataHdl)((**theDocumentHdl).fPrivate)) != NULL) |
{ |
if((theGWorld = (**theViewerHdl).fGWorld) != NULL) |
{ |
retVal = GeneralCountPages( theGWorld, pageRect ) ; |
} |
} |
return retVal ; |
} |
/*------------------------------------------------------------ */ |
/* |
* ViewerWindow_PrintPage - image the requested page in the |
* printer port |
*/ |
void ViewerWindow_PrintPage( |
WindowPtr theWindow, |
Rect *pageRect, |
GrafPtr imagingPort, |
short pageNum ) |
{ |
GWorldPtr theGWorld; |
Rect pictRect, rectToPrint,srcRect,dstRect; |
short pagesWide, /* the number of pages wide the image is */ |
pagesHigh, /* the number pages high for this image */ |
horozTile, /* used in the loop to denote the H tile to print from the image */ |
vertTile ; /* used in the loop to denote the V tile to print from the image */ |
short thisPage = 1; /* used to find the page they want us to print */ |
short pictHOff, |
pictVOff, |
pictWidth, /* the width of the doc's GWorld */ |
pictHeight ; /* the height of the doc's GWorld */ |
short pageWidth, /* the width of one page */ |
pageHeight ; /* the height of one page */ |
OSErr theErr ; |
PixMapHandle offPixMap ; |
DocumentHdl theDocumentHdl ; |
ViewerDataHdl theViewerHdl ; |
TQ3ViewerObject theViewer ; |
theDocumentHdl = (DocumentHdl)GetWRefCon(theWindow) ; |
if(theDocumentHdl != NULL |
&& (**theDocumentHdl).fDocumentMagic == kViewerMagic |
&& (theViewerHdl = (ViewerDataHdl)((**theDocumentHdl).fPrivate)) != NULL) |
{ |
if((theGWorld = (**theViewerHdl).fGWorld) != NULL) |
{ |
GeneralPrintPage( theGWorld, pageRect, imagingPort, pageNum ) ; |
} |
} |
} |
/*------------------------------------------------------------ */ |
/* |
* ViewerWindow_PrePrint - this gets called before we print, so any |
* setup for printing can be done here. |
*/ |
void ViewerWindow_PrePrint( WindowPtr theWindow ) |
{ |
/* |
* before we print we want to get a pixmap that represents the |
* current document being imaged. We use Q3ViewerGetPict to |
* do this and use the fGWorld field of the viewer's data |
* to store this until it's been imaged. Not efficient, but |
* that's the price of using the viewer. |
*/ |
DocumentHdl theDocumentHdl ; |
ViewerDataHdl theViewerHdl ; |
TQ3ViewerObject theViewer ; |
theDocumentHdl = (DocumentHdl)GetWRefCon(theWindow) ; |
if(theDocumentHdl != NULL |
&& (**theDocumentHdl).fDocumentMagic == kViewerMagic |
&& (theViewerHdl = (ViewerDataHdl)((**theDocumentHdl).fPrivate)) != NULL) |
{ |
if((theViewer = (**theViewerHdl).fViewer) != NULL) |
{ |
PicHandle thePicture ; |
GWorldPtr theGWorld ; |
Rect pictRect ; |
OSErr theErr ; |
GrafPtr savedPort ; |
GetPort( &savedPort ) ; |
SetPort( (GrafPtr) theWindow ) ; |
thePicture = Q3ViewerGetPict( theViewer ) ; |
SetPort( savedPort ) ; |
if( thePicture != NULL ) |
{ |
pictRect.top = (**thePicture).picFrame.top ; |
pictRect.left = (**thePicture).picFrame.left ; |
pictRect.bottom = (**thePicture).picFrame.bottom ; |
pictRect.right = (**thePicture).picFrame.right ; |
/* make sure the GWorld's origin is (0,0) */ |
OffsetRect( &pictRect, -pictRect.left, -pictRect.top ) ; |
/* make a new offscreen world */ |
theErr = NewGWorld( &theGWorld, 32, &pictRect, NULL, NULL, 0L ); |
if( theErr == noErr && theGWorld != NULL ) |
{ |
PixMapHandle offPixMap ; |
CGrafPtr savedPort ; |
GDHandle gdh ; |
/* image the picture into the offscreen */ |
GetGWorld( &savedPort, &gdh ) ; |
SetGWorld( theGWorld, NULL ) ; |
/* get the gworld pixmap and lock it down */ |
offPixMap = GetGWorldPixMap( theGWorld ) ; |
(void) LockPixels( offPixMap ) ; |
/* draw the Picture in the port */ |
DrawPicture( thePicture, &theGWorld->portRect ) ; |
/* unlock the pixmap */ |
(void) UnlockPixels( offPixMap ) ; |
SetGWorld( savedPort, gdh ) ; |
(**theViewerHdl).fGWorld = theGWorld; |
} |
else |
{ |
(**theViewerHdl).fGWorld = NULL; |
} |
/* ditch the pict */ |
KillPicture( thePicture ) ; |
} |
else |
{ |
(**theViewerHdl).fGWorld = NULL ; |
} |
} |
} |
return ; |
} |
/*------------------------------------------------------------ */ |
/* |
* ViewerWindow_PostPrint - this gets called before we print, so any |
* setup for printing can be done here. |
*/ |
void ViewerWindow_PostPrint( WindowPtr theWindow ) |
{ |
/* delete the cached pict */ |
DocumentHdl theDocumentHdl ; |
ViewerDataHdl theViewerHdl ; |
TQ3ViewerObject theViewer ; |
theDocumentHdl = (DocumentHdl)GetWRefCon(theWindow) ; |
if(theDocumentHdl != NULL |
&& (**theDocumentHdl).fDocumentMagic == kViewerMagic |
&& (theViewerHdl = (ViewerDataHdl)((**theDocumentHdl).fPrivate)) != NULL) |
{ |
GWorldPtr theGWorld = (**theViewerHdl).fGWorld ; |
/* get rid of the gworld */ |
DisposeGWorld(theGWorld); |
(**theViewerHdl).fGWorld = NULL ; |
} |
return ; |
} |
/*------------------------------------------------------------ */ |
/* |
* Handle the edit menu cut command for this window type |
*/ |
OSErr ViewerWindow_Cut( WindowPtr theWindow ) |
{ |
DocumentHdl theDocumentHdl ; |
ViewerDataHdl theViewerHdl ; |
TQ3ViewerObject theViewer ; |
OSErr theError = paramErr ; |
theDocumentHdl = (DocumentHdl)GetWRefCon(theWindow) ; |
if(theDocumentHdl != NULL |
&& (**theDocumentHdl).fDocumentMagic == kViewerMagic |
&& (theViewerHdl = (ViewerDataHdl)((**theDocumentHdl).fPrivate)) != NULL) |
{ |
if((theViewer = (**theViewerHdl).fViewer) != NULL) |
{ |
theError = Q3ViewerCut ( theViewer ) ; |
} |
} |
return theError ; |
} |
/*------------------------------------------------------------ */ |
/* |
* Handle the edit menu copy command for this window type |
*/ |
OSErr ViewerWindow_Copy( WindowPtr theWindow ) |
{ |
DocumentHdl theDocumentHdl ; |
ViewerDataHdl theViewerHdl ; |
TQ3ViewerObject theViewer ; |
OSErr theError = paramErr ; |
theDocumentHdl = (DocumentHdl)GetWRefCon(theWindow) ; |
if(theDocumentHdl != NULL |
&& (**theDocumentHdl).fDocumentMagic == kViewerMagic |
&& (theViewerHdl = (ViewerDataHdl)((**theDocumentHdl).fPrivate)) != NULL) |
{ |
if((theViewer = (**theViewerHdl).fViewer) != NULL) |
{ |
theError = Q3ViewerCopy ( theViewer ) ; |
} |
} |
return theError ; |
} |
/*------------------------------------------------------------ */ |
/* |
* Handle the edit menu paste command for this window type |
*/ |
OSErr ViewerWindow_Paste( WindowPtr theWindow ) |
{ |
DocumentHdl theDocumentHdl ; |
ViewerDataHdl theViewerHdl ; |
TQ3ViewerObject theViewer ; |
OSErr theError = paramErr ; |
theDocumentHdl = (DocumentHdl)GetWRefCon(theWindow) ; |
if(theDocumentHdl != NULL |
&& (**theDocumentHdl).fDocumentMagic == kViewerMagic |
&& (theViewerHdl = (ViewerDataHdl)((**theDocumentHdl).fPrivate)) != NULL) |
{ |
if((theViewer = (**theViewerHdl).fViewer) != NULL) |
{ |
theError = Q3ViewerPaste ( theViewer ) ; |
} |
} |
return theError ; |
} |
/*------------------------------------------------------------ */ |
/* |
* Handle the edit menu clear command for this window type |
*/ |
OSErr ViewerWindow_Clear( WindowPtr theWindow ) |
{ |
DocumentHdl theDocumentHdl ; |
ViewerDataHdl theViewerHdl ; |
TQ3ViewerObject theViewer ; |
OSErr theError = paramErr ; |
theDocumentHdl = (DocumentHdl)GetWRefCon(theWindow) ; |
if(theDocumentHdl != NULL |
&& (**theDocumentHdl).fDocumentMagic == kViewerMagic |
&& (theViewerHdl = (ViewerDataHdl)((**theDocumentHdl).fPrivate)) != NULL) |
{ |
if((theViewer = (**theViewerHdl).fViewer) != NULL) |
{ |
theError = Q3ViewerClear ( theViewer ) ; |
} |
} |
return theError ; |
} |
/*------------------------------------------------------------ */ |
/* |
* Handle the edit menu undo command for this window type |
*/ |
OSErr ViewerWindow_Undo( WindowPtr theWindow ) |
{ |
DocumentHdl theDocumentHdl ; |
ViewerDataHdl theViewerHdl ; |
TQ3ViewerObject theViewer ; |
OSErr theError = paramErr ; |
theDocumentHdl = (DocumentHdl)GetWRefCon(theWindow) ; |
if(theDocumentHdl != NULL |
&& (**theDocumentHdl).fDocumentMagic == kViewerMagic |
&& (theViewerHdl = (ViewerDataHdl)((**theDocumentHdl).fPrivate)) != NULL) |
{ |
theError = Q3ViewerUndo ( theViewer ) ; |
} |
return theError ; |
} |
/*------------------------------------------------------------ */ |
/* |
* Get an output reference for a PICT file |
*/ |
OSErr GetOutputPictFileRef(short *dstPictFRef ) |
{ |
StandardFileReply aPictSFR; /* new style Standard file record */ |
OSErr result ; |
SFTypeList types = { 'PICT',0 }; /* we are only interested in PICT files */ |
StandardPutFile( "\pSave PICT as:", "\pNew PICT", &aPictSFR ) ; |
if ( aPictSFR.sfGood ) { |
/* |
* Delete the file of the same name, if one exits, |
* and create a new PICT file. |
*/ |
FSpDelete(&aPictSFR.sfFile); |
result = FSpCreate( &aPictSFR.sfFile,'????','PICT', aPictSFR.sfScript); |
if (result != noErr) { |
return result; |
} |
/* open the data fork for writing */ |
result = FSpOpenDF( &aPictSFR.sfFile, fsCurPerm, dstPictFRef); |
if (result != noErr) { |
return result; |
} |
} |
else |
return userCanceledErr ; |
return noErr ; |
} |
/*------------------------------------------------------------ */ |
/* |
* create a new viewer document window, this includes creating a |
* document record, a window and an associated viewer object. the |
* document record is stored in the window's refcon field, so it |
* can be accessed as required via the window record. |
*/ |
WindowPtr DoCreateNewPictWindow( unsigned char *windowName, long windWidth, long windHeight ) |
{ |
WindowPtr theWindow ; |
Rect myRect ; |
TQ3ViewerObject myViewer ; |
DocumentHdl myPictDocument = NULL ; |
GWorldPtr myGWorld ; |
PictDataHdl myViewerPict ; |
myRect.top = 0 ; |
myRect.left = 0 ; |
myRect.bottom = windHeight ; |
myRect.right = windWidth ; |
/* create a document record to hold the */ |
/* data for this instance */ |
if((myPictDocument = (DocumentHdl)NewHandleClear(sizeof(Document))) == NULL) |
return NULL ; |
/* make a GWorld the size requested */ |
if(NewGWorld ( &myGWorld, 32, &myRect, NULL, NULL, 0L ) != noErr) |
return NULL ; |
/* ideally we should stagger the window rect */ |
OffsetRect( &myRect, 50, 50 ) ; |
theWindow = NewCWindow( NULL, |
&myRect, |
windowName, |
true, |
documentProc, |
(WindowPtr)-1, |
true, |
0L ) ; |
myViewerPict = (PictDataHdl)NewHandleClear(sizeof(PictData)) ; |
if(myViewerPict == NULL) |
{ |
DisposeHandle( (Handle)myPictDocument ) ; |
return NULL ; |
} |
/* put the magic cookie in the first field so we can identify this as a valid pict */ |
(**myPictDocument).fDocumentMagic = kPICTMagic ; |
/* set up the procs field */ |
(**myPictDocument).procs = &pictProcs ; |
/* set up the private data part of the document structure */ |
(**myViewerPict).fGWorld = myGWorld ; |
(**myPictDocument).fPrivate = (void *)myViewerPict ; |
/* finally create a new print record */ |
DoCreatePrintRecord( myPictDocument ) ; |
/* store a reference to the document structure in the refcon |
* field of the window |
*/ |
SetWRefCon( theWindow, (long)myPictDocument ) ; |
return theWindow ; |
} |
/*------------------------------------------------------------ */ |
/* |
* PictWindow_Update |
*/ |
void PictWindow_Update( WindowPtr theWindow ) |
{ |
GrafPtr oldPort ; |
DocumentHdl theDocumentHdl ; |
PictDataHdl thePictDataHdl ; |
GWorldPtr theGWorld ; |
OSErr theErr ; |
GetPort( &oldPort ) ; |
SetPort( theWindow ); |
BeginUpdate( theWindow ); |
theDocumentHdl = (DocumentHdl)GetWRefCon(theWindow) ; |
if(theDocumentHdl != NULL |
&& (**theDocumentHdl).fDocumentMagic == kPICTMagic |
&& (thePictDataHdl = (PictDataHdl)((**theDocumentHdl).fPrivate)) != NULL) |
{ |
if((theGWorld = (**thePictDataHdl).fGWorld) != NULL) |
{ |
/* copybits from the GWorld here */ |
CopyBits ((BitMapPtr) &theGWorld->portPixMap, |
&theWindow->portBits, |
&theGWorld->portRect, |
&theWindow->portRect, |
srcCopy, |
0L); |
DoDrawGrowIcon(theWindow) ; |
} |
} |
EndUpdate( theWindow ); |
SetPort( oldPort ) ; |
} |
/*------------------------------------------------------------ */ |
/* |
* PictWindow_AdjustMenus |
*/ |
void PictWindow_AdjustMenus( WindowPtr theWindow ) |
{ |
MenuHandle theMenu ; |
DocumentHdl theDocumentHdl ; |
ViewerDataHdl theViewerHdl ; |
TQ3ViewerObject theViewer ; |
TQ3ViewObject myView ; |
TQ3Status myStatus ; |
TQ3RendererObject myRenderer ; |
TQ3ObjectType theRendererType ; |
long tmpLong, theScrapOffset ; |
unsigned long theViewerFlags; |
unsigned long theViewerState ; |
char itemString[255] ; |
unsigned long itemStringLength ; |
/* |
* get the reference to our Pict document data structure |
* from the long reference constant for the window. Cast |
* it to the appropriate type. If we can't get it (i.e. it's |
* null we want to bail |
*/ |
theDocumentHdl = (DocumentHdl)GetWRefCon(theWindow) ; |
if(theDocumentHdl == NULL) |
return ; |
/* adjust the file menu */ |
theMenu = GetMHandle ( mFileMenu ) ; |
EnableItem ( theMenu, iFileNewItem ); /* always enabled */ |
EnableItem ( theMenu, iFileOpenItem ); /* always enabled */ |
EnableItem ( theMenu, iFileQuitItem ); /* always enabled */ |
EnableItem ( theMenu, iFileCloseItem ); |
/* |
* this only gets called if we have a pict window in the first |
* place so enable saving and printing... |
*/ |
EnableItem ( theMenu, iFileSaveItem ); |
EnableItem ( theMenu, iFileSaveAsItem ); |
EnableItem ( theMenu, iFileRevertItem ); |
EnableItem ( theMenu, iFilePageSetupItem ); |
EnableItem ( theMenu, iFilePrintItem ); |
/* adjust the edit menu */ |
theMenu = GetMHandle ( mEditMenu ) ; |
EnableItem ( theMenu, 0L ); |
/* |
* there's not really anything to undo with this window type so set |
* the undo string to "Can't Undo" |
*/ |
GetIndString ( (unsigned char *)itemString, 2223, 1 ) ; |
SetMenuItemText ( theMenu, iEditUndoItem, (unsigned char *)itemString ) ; |
DisableItem ( theMenu, iEditUndoItem ); |
/* enable copy */ |
EnableItem ( theMenu, iEditCopyItem ); |
/* disable cut, paste and clear */ |
DisableItem ( theMenu, iEditClearItem ); |
DisableItem ( theMenu, iEditPasteItem ); |
DisableItem ( theMenu, iEditCutItem ); |
/* disable the renderer prefs */ |
DisableItem ( theMenu, iEditRendererPrefsItem ); |
/* adjust the view menu */ |
theMenu = GetMHandle ( mViewMenu ) ; |
DisableItem ( theMenu, 0L ); |
return ; |
} |
/*------------------------------------------------------------ */ |
/* |
* PictWindow_HandleEvent |
*/ |
Boolean PictWindow_HandleEvent( WindowPtr theWindow, EventRecord *theEventRecord) |
{ |
return false ; |
} |
/*------------------------------------------------------------ */ |
/* |
* PictWindow_New |
*/ |
WindowPtr PictWindow_New( unsigned char *windowTitle ) |
{ |
return NULL ; |
} |
/*------------------------------------------------------------ */ |
/* |
* PictWindow_SaveAs |
*/ |
OSErr PictWindow_SaveAs( WindowPtr theWindow ) |
{ |
short dstPictFRef = 0 ; |
PicHandle thePicture = NULL ; |
OSErr theErr = noErr ; |
GWorldPtr theGWorld ; |
CGrafPtr savedPort ; |
GDHandle savedGDH ; |
/* get an open a file for writing */ |
if( (theErr = GetOutputPictFileRef( &dstPictFRef )) == noErr ) { |
theGWorld = GetGWorldFromPictWindow( theWindow ) ; |
/* make a temp viewer to use to make the PICT */ |
if( theGWorld != NULL ) |
{ |
/* lock the viewer's GWorld for updates */ |
LockPixels(GetGWorldPixMap(theGWorld)) ; |
GetGWorld( &savedPort, &savedGDH ) ; |
SetGWorld( (CGrafPtr)theGWorld, NULL ) ; |
thePicture = OpenPicture(&theGWorld->portRect) ; |
/* copy onto ourselves to make the picture */ |
CopyBits ((BitMapPtr) &theGWorld->portPixMap, |
(BitMapPtr) &theGWorld->portPixMap, |
&theGWorld->portRect, |
&theGWorld->portRect, |
srcCopy, |
0L); |
ClosePicture() ; |
if( thePicture != NULL ) { |
long length ; |
long dummy ; |
long index ; |
/* ok, myPic now contains a handle to the picture */ |
HLock( (Handle)thePicture); |
/* set up the 512 byte header for a PICT file */ |
dummy = 0; |
for( index = 0; index < ( 512 / 4 ); index ++ ){ |
length = 4 ; |
if( (theErr = FSWrite(dstPictFRef, &length, &dummy)) != noErr ) { |
return theErr ; |
} |
} |
length = GetHandleSize( (Handle)thePicture); |
if( (theErr = FSWrite(dstPictFRef, &length, *thePicture)) != noErr ) { |
return theErr ; |
} |
/* now get rid of the picture handle */ |
HUnlock( (Handle) thePicture ) ; |
KillPicture(thePicture); |
FSClose(dstPictFRef); |
} |
} |
} |
return theErr ; |
} |
/*------------------------------------------------------------ */ |
/* |
* PictWindow_Save |
*/ |
OSErr PictWindow_Save( WindowPtr theWindow ) |
{ |
/* we don't really work well with pictures so just call save as */ |
PictWindow_SaveAs( theWindow ) ; |
} |
/*------------------------------------------------------------ */ |
/* |
* PictWindow_Revert |
*/ |
OSErr PictWindow_Revert( WindowPtr theWindow ) |
{ |
return noErr ; |
} |
/*------------------------------------------------------------ */ |
/* |
* PictWindow_Open |
*/ |
WindowPtr PictWindow_Open( FSSpec *theFSSpec ) |
{ |
return NULL ; |
} |
/*------------------------------------------------------------ */ |
/* |
* PictWindow_Close |
*/ |
OSErr PictWindow_Close( WindowPtr theWindow ) |
{ |
DocumentHdl theDocumentHdl ; |
PictDataHdl thePictDataHdl ; |
GWorldPtr theGWorld ; |
OSErr theErr ; |
THPrint thePrintRec ; |
theDocumentHdl = (DocumentHdl)GetWRefCon(theWindow) ; |
if(theDocumentHdl != NULL |
&& (**theDocumentHdl).fDocumentMagic == kPICTMagic |
&& (thePictDataHdl = (PictDataHdl)((**theDocumentHdl).fPrivate)) != NULL) |
{ |
if((theGWorld = (**thePictDataHdl).fGWorld) != NULL) |
{ |
DisposeGWorld( theGWorld ) ; |
} |
DisposeHandle((Handle)thePictDataHdl) ; |
thePrintRec = (**theDocumentHdl).fPrintRec ; |
if( thePrintRec != NULL ) |
DisposeHandle((Handle)thePrintRec ) ; |
DisposeHandle((Handle)theDocumentHdl) ; |
} |
DisposeWindow( theWindow ) ; |
return noErr ; |
} |
/*------------------------------------------------------------ */ |
/* |
* PictWindow_CountPages - calculate the number of pages needed to |
* image the document associated with the picture window |
*/ |
short PictWindow_CountPages( |
WindowPtr theWindow, |
Rect *pageRect ) |
{ |
Rect pictRect ; |
short horizOffset, |
vertOffset, |
pagesWide = 0, /* the number of pages wide the image is */ |
pagesHigh = 0, /* the number pages high for this image */ |
pageWidth, /* the width of one page */ |
pageHeight ; /* the height of one page */ |
DocumentHdl theDocumentHdl ; |
PictDataHdl thePictDataHdl ; |
GWorldPtr theGWorld ; |
OSErr theErr ; |
short retVal = 0 ; |
theDocumentHdl = (DocumentHdl)GetWRefCon(theWindow) ; |
if(theDocumentHdl != NULL |
&& (**theDocumentHdl).fDocumentMagic == kPICTMagic |
&& (thePictDataHdl = (PictDataHdl)((**theDocumentHdl).fPrivate)) != NULL) |
{ |
if((theGWorld = (**thePictDataHdl).fGWorld) != NULL) |
{ |
retVal = GeneralCountPages( theGWorld, pageRect ) ; |
} |
} |
return retVal ; |
} |
/*------------------------------------------------------------ */ |
/* |
* PictWindow_PrintPage - image the requested page in the |
* printer port |
*/ |
void PictWindow_PrintPage( |
WindowPtr theWindow, |
Rect *pageRect, |
GrafPtr imagingPort, |
short pageNum ) |
{ |
GWorldPtr docGWorld; |
Rect pictRect, rectToPrint,srcRect,dstRect; |
short pagesWide, /* the number of pages wide the image is */ |
pagesHigh, /* the number pages high for this image */ |
horozTile, /* used in the loop to denote the H tile to print from the image */ |
vertTile ; /* used in the loop to denote the V tile to print from the image */ |
short thisPage = 1; /* used to find the page they want us to print */ |
short pictHOff, |
pictVOff, |
pictWidth, /* the width of the doc's GWorld */ |
pictHeight ; /* the height of the doc's GWorld */ |
short pageWidth, /* the width of one page */ |
pageHeight ; /* the height of one page */ |
DocumentHdl theDocumentHdl ; |
PictDataHdl thePictDataHdl ; |
GWorldPtr theGWorld ; |
OSErr theErr ; |
PixMapHandle offPixMap ; |
theDocumentHdl = (DocumentHdl)GetWRefCon(theWindow) ; |
if(theDocumentHdl != NULL |
&& (**theDocumentHdl).fDocumentMagic == kPICTMagic |
&& (thePictDataHdl = (PictDataHdl)((**theDocumentHdl).fPrivate)) != NULL) |
{ |
if((theGWorld = (**thePictDataHdl).fGWorld) != NULL) |
{ |
GeneralPrintPage( theGWorld, pageRect, imagingPort, pageNum ) ; |
} |
} |
} |
/*------------------------------------------------------------ */ |
/* |
* PictWindow_PostPrint - this gets called before we print, so any |
* setup for printing can be done here. |
*/ |
void PictWindow_PrePrint( WindowPtr theWindow ) |
{ |
return ; /* noop for picts, couild put null in the struct to avoid the call */ |
} |
/*------------------------------------------------------------ */ |
/* |
* PictWindow_PostPrint - this gets called after we print, so any |
* setup for printing can be torn down here. |
*/ |
void PictWindow_PostPrint( WindowPtr theWindow ) |
{ |
return ; /* noop for picts, couild put null in the struct to avoid the call */ |
} |
/* |
* handle the edit copy command. |
*/ |
OSErr PictWindow_Copy( WindowPtr theWindow ) |
{ |
PicHandle thePicture ; |
OpenCPicParams thePicParams ; |
GWorldPtr theGWorld ; |
OSErr theErr ; |
PixMapHandle offPixMap ; |
if((theGWorld = GetGWorldFromPictWindow( theWindow )) != NULL) |
{ |
CGrafPtr savedPort ; |
GDHandle gdh ; |
/* save the port */ |
GetGWorld( &savedPort, &gdh); |
SetGWorld( (CGrafPtr)theGWorld, NULL ) ; |
/* set up the pic params for the OpenCPicture call */ |
thePicParams.srcRect.top = theGWorld->portRect.top; |
thePicParams.srcRect.left = theGWorld->portRect.left; |
thePicParams.srcRect.bottom = theGWorld->portRect.bottom; |
thePicParams.srcRect.right = theGWorld->portRect.right; |
thePicParams.hRes = 0x00480000 ; /* specifies 72 dpi */ |
thePicParams.vRes = 0x00480000 ; /* specifies 72 dpi */ |
thePicParams.version = -2 ; |
thePicParams.reserved1 = 0 ; |
thePicParams.reserved2 = 0 ; |
/* try to create a new picture */ |
thePicture = OpenCPicture( &thePicParams ); |
if(thePicture != NULL) |
{ |
long aLong ; |
ClipRect( &thePicParams.srcRect ); |
/* lock it down */ |
offPixMap = GetGWorldPixMap( theGWorld ) ; |
LockPixels( offPixMap ) ; |
/* make the picture */ |
CopyBits( (BitMapPtr)*offPixMap, |
(BitMapPtr)*offPixMap, |
& theGWorld->portRect, |
& theGWorld->portRect, |
srcCopy, |
0L ) ; |
ClosePicture() ; |
/* unlock */ |
UnlockPixels( offPixMap ) ; |
/* place the picture on the scrap */ |
HLock((Handle)thePicture) ; |
aLong = ZeroScrap() ; |
aLong = PutScrap(GetHandleSize((Handle)thePicture), 'PICT', *thePicture); |
HUnlock((Handle)thePicture) ; |
KillPicture(thePicture) ; |
} |
/* reset the port */ |
SetGWorld( savedPort, gdh); |
} |
return ; |
} |
Copyright © 2003 Apple Computer, Inc. All Rights Reserved. Terms of Use | Privacy Policy | Updated: 2003-01-14