home *** CD-ROM | disk | FTP | other *** search
/ Apple WWDC 1996 / WWDC96_1996 (CD).toast / Technology Materials / QuickTime VR / MacOS / QuickDraw™ 3D 1.0.6F4 SDK / Samples / SampleCode / SimpleViewer++ / SimpleViewer.c < prev    next >
Encoding:
C/C++ Source or Header  |  1996-02-20  |  28.7 KB  |  1,174 lines  |  [TEXT/MPCC]

  1. //--------------------------------------------------------------------------------------------
  2. // simple viewer application 
  3. // DEVELOPER SUPPORT May 95
  4. //
  5. // This is a simple viewer application, that illustrates a minimal, but
  6. // functionally complete viewer application.
  7. //
  8. // Nick Thompson, Developer Support, Apple Computer (DEVSUPPORT),
  9. // ©1995, Apple Computer Inc., All Rights Reserved
  10.  
  11. #include <AppleEvents.h>
  12. #include <menus.h>
  13. #include <PictUtil.h>
  14. #include <QDOffScreen.h>
  15. #include <Errors.h>
  16.  
  17. #include "QD3DViewer.h"
  18.  
  19. #include "QD3D.h"
  20. #include "QD3DRenderer.h"
  21. #include "QD3DView.h"
  22. //--------------------------------------------------------------------------------------------
  23. //
  24. const int    kWindowWidth = 220 ;
  25. const int    kWindowHeight = 150 ;
  26.  
  27. //--------------------------------------------------------------------------------------------
  28. //
  29. #define HiWrd(aLong)    (((aLong) >> 16) & 0xFFFF)
  30. #define LoWrd(aLong)    ((aLong) & 0xFFFF)
  31.  
  32.     
  33.  
  34. //--------------------------------------------------------------------------------------------
  35. // menu id's
  36. enum {
  37.     mApple = 128,
  38.     mFile,
  39.     mEdit,
  40.     mView
  41. } ;
  42.  
  43. //--------------------------------------------------------------------------------------------
  44. // command id's, Apple menu
  45. enum {
  46.     iAbout = 1
  47. } ;
  48.  
  49. //--------------------------------------------------------------------------------------------
  50. // command id's, File menu
  51. enum {
  52.     iNew = 1,
  53.     iOpen,
  54.     iUnused1,
  55.     iClose,
  56.     iSave,
  57.     iSaveAs,
  58.     iRevert,
  59.     iUnused2,
  60.     iQuit
  61. } ;
  62.  
  63. //--------------------------------------------------------------------------------------------
  64. // command id's, Edit menu
  65. enum {
  66.     iUndo = 1,
  67.     iUnused3,
  68.     iCut,
  69.     iCopy,
  70.     iPaste,
  71.     iClear
  72. } ;
  73.  
  74. //--------------------------------------------------------------------------------------------
  75. // command id's, Edit menu
  76. enum {
  77.     iWireframe = 1,
  78.     iInteractive
  79. } ;
  80.  
  81. //--------------------------------------------------------------------------------------------
  82. // static control variables
  83.  
  84. static Boolean gQuitFlag = false ;                // we ain't quittin yet
  85. static Point gStaggerPos = {50,50} ;            // start opening staggered windows at this point
  86. static AEAddressDesc    gSelfAddress;            // A self-addressed address descriptor record
  87. static ProcessSerialNumber    gSelfPSN;            // This application's psn
  88.  
  89. //--------------------------------------------------------------------------------------------
  90. // function prototypes
  91.  
  92. Boolean SupportsQuickDraw3D(void) ;
  93. Boolean     SupportsQuickDraw3DViewer(void) ;
  94. void         InitToolbox( void ) ;
  95. void        FailIfErr(OSErr something ) ;
  96. void         MainEventLoop( void ) ;
  97. void         HandleActivateWindow(WindowPtr theWindow, short activate);
  98. void         HandleKeyPress( EventRecord *event ) ;
  99. void        HandleAboutApp( void ) ;
  100. OSErr        HandleOpenDoc(FSSpec *theFile) ;
  101. Boolean        HandleEvent( EventRecord *theEvent ) ;
  102. void         HandleMenuCommand( long menuResult ) ;
  103. void         MyAdjustMenus( void ) ;
  104. OSErr        MyDisposeViewerWindow( WindowPtr theWindow ) ;
  105. CGrafPtr     MyCreateViewerWindow( void ) ;
  106.  
  107. //-- AppleEvent Related
  108.  
  109. Boolean SupportsAEVT(void) ;
  110. void RegisterMyEvents(void) ;
  111. pascal OSErr MyAEHandleOAPP( AppleEvent *theAppleEvent, AppleEvent *reply, long refCon) ;
  112. pascal OSErr MyAEHandleODOC(AppleEvent *theAppleEvent, AppleEvent *reply, long refCon) ;
  113. pascal OSErr MyAEHandlePDOC(AppleEvent *theAppleEvent,AppleEvent *reply,long refCon) ;
  114. pascal OSErr MyAEHandleQUIT(AppleEvent *theAppleEvent,AppleEvent *reply,long refCon) ;
  115. void DoAppOpenCommand( void ) ;
  116. void MySendQuitApp( void ) ;
  117. void MySendOpenDoc(FSSpec *myFSSpec) ;
  118.  
  119. //--------------------------------------------------------------------------------------------
  120. // Constants
  121.  
  122. const RGBColor    kRGBBlack = { 0x0000, 0x0000, 0x0000 } ;
  123. const RGBColor    kRGBWhite = { 0xFFFF, 0xFFFF, 0xFFFF } ;
  124. const int         kMyAboutDialogID = 128 ;
  125. const int         kMyFatalDialogID = 129 ;
  126. const int        kQD3DAlertID = 27309 ;
  127. //--------------------------------------------------------------------------------------------
  128. // Types
  129. typedef struct _viewerData {
  130.     TQ3ViewerObject        theViewer ;
  131.     FSSpec                theFile ;
  132.     Boolean                isFileValid ;
  133. } ViewerData, *ViewerDataPtr, **ViewerDataHandle ;
  134.  
  135. //--------------------------------------------------------------------------------------------
  136. //
  137. //
  138.  
  139. void main()
  140. {
  141.     MoreMasters(); MoreMasters() ; MoreMasters() ;
  142.     MaxApplZone() ;            // Maximise the heap - the viewer requires at least 32k
  143.     InitToolbox() ;
  144.  
  145.     // WE DON'T CHECK FOR 68K machine.
  146.     // Instead I use the NotPPC.rsrc resource file.  This is a file with a 68k CODE 0
  147.     // and CODE 1 resource that puts up a dialog that says "this app only runs on a power
  148.     // macintosh computer.
  149.     
  150.     if( SupportsAEVT() && SupportsQuickDraw3D() && SupportsQuickDraw3DViewer()) {
  151.  
  152.     
  153.         // AppleEvent stuff:
  154.         // Set up the self-addressed descriptor record.
  155.          gSelfPSN.highLongOfPSN = 0;
  156.          gSelfPSN.lowLongOfPSN = kCurrentProcess;        //* Use this instead of GetCurrentProcess *//
  157.          FailIfErr(AECreateDesc(typeProcessSerialNumber,(Ptr)&gSelfPSN,sizeof(ProcessSerialNumber),&gSelfAddress));
  158.  
  159.         RegisterMyEvents() ;    // register the appleevents for this app
  160.  
  161.         MainEventLoop() ;        // Handle events 'til we die
  162.     } 
  163.     else {
  164.         Str255 theString ;
  165.         GetIndString(theString,kQD3DAlertID,3);
  166.         ParamText( theString, 0L,  0L,  0L ) ;
  167.         (void)Alert(kQD3DAlertID,nil);
  168.     }
  169. }
  170. //---------------------------------------------------------------------
  171.  
  172. Boolean SupportsQuickDraw3D(void) 
  173. {
  174.     OSErr err;
  175.     long response;
  176.         
  177.     err = Gestalt(gestaltQD3D,&response);
  178.     if (err!=noErr)
  179.         return false;
  180.         
  181.     return (response && (response << gestaltQD3DAvailable));
  182. }
  183.  
  184. //---------------------------------------------------------------------
  185.  
  186. Boolean SupportsQuickDraw3DViewer(void) 
  187. {
  188.     OSErr err;
  189.     long response;
  190.         
  191.     err = Gestalt( gestaltQD3DViewer,&response );
  192.     if (err!=noErr)
  193.         return false;
  194.         
  195.     return (response && ( response << gestaltQD3DViewerAvailable ));
  196. }
  197.  
  198. //--------------------------------------------------------------------------------------------
  199. //
  200. //
  201. void FailIfErr( OSErr something )
  202.     OSErr myErr ; 
  203.     if(( myErr = something) != noErr ) { 
  204.         ModalFilterUPP         theProc ;
  205.         DialogPtr            theDialog ; 
  206.         short                itemHit ;
  207.         Str255                theError ;
  208.         
  209.         NumToString(something,theError);
  210.     
  211.         theDialog = GetNewDialog ( kMyFatalDialogID, nil, (WindowPtr)-1 );
  212.         
  213.         // these two lil' snappers are system 7 only
  214.         // so if you use them, check before!!
  215.         // in this app we will only run on Power
  216.         // Macintosh, so we don't check
  217.         
  218.         GetStdFilterProc( &theProc ) ;
  219.         SetDialogDefaultItem(theDialog, ok) ;
  220.         
  221.         ParamText( theError, 0L, 0L, 0L ) ;
  222.         
  223.         // put the dialog up and loop 'til
  224.         // the user hits the OK button
  225.  
  226.         do {
  227.             ModalDialog ( theProc, &itemHit );
  228.         } while( itemHit != ok ) ;
  229.         
  230.         DisposDialog ( theDialog );
  231.         
  232.         ExitToShell() ; 
  233.     } 
  234.  
  235. //--------------------------------------------------------------------------------------------
  236. //
  237. //
  238.  
  239. void InitToolbox()
  240. {
  241.     Handle        menuBar = nil;
  242.  
  243.  
  244.     InitGraf((Ptr) &qd.thePort);
  245.     InitFonts();
  246.     InitWindows();
  247.     InitMenus();
  248.     TEInit();
  249.     InitDialogs((long)nil);
  250.     InitCursor();
  251.  
  252.     // initialize application globals
  253.     
  254.     gQuitFlag = false;
  255.     
  256.     
  257.     menuBar = GetNewMBar(128);                // Read menus into menu bar, MBAR res id is 128
  258.     
  259.     if ( menuBar == nil )
  260.          ExitToShell();                        // if we dont have it then quit - your app 
  261.                                              // needs a dialog here
  262.  
  263.     SetMenuBar(menuBar);                    // Install menus
  264.     DisposHandle(menuBar);
  265.     
  266.     AddResMenu(GetMHandle(mApple), 'DRVR');    // Add DA names to Apple menu, ID 128
  267.  
  268.     MyAdjustMenus() ;
  269.     DrawMenuBar();
  270. }
  271.  
  272.  
  273. //--------------------------------------------------------------------------------------------
  274. //
  275. //
  276. void MainEventLoop()
  277. {
  278.     EventRecord         event;
  279.     WindowPtr           theWindow;
  280.     Boolean                wasViewerEvent ;
  281.     GrafPtr             savedPort ;
  282.     Point                localPt ;
  283.     TQ3ViewerObject     theViewer ;
  284.     ViewerDataHandle    myData ;
  285.     Boolean                didAdjustCursor ;
  286.  
  287.     MyAdjustMenus() ;
  288.     while( !gQuitFlag )
  289.     {
  290.         if (WaitNextEvent( everyEvent, &event, 0, nil ))
  291.         {
  292.             
  293.             if((theWindow = FrontWindow()) != nil ) {
  294.             
  295.                 myData = (ViewerDataHandle)GetWRefCon(theWindow);
  296.                 theViewer = (**myData).theViewer;
  297.             }
  298.             
  299.             if( theViewer ) {
  300.                 GetPort( &savedPort ) ;
  301.                 SetPort( (GrafPtr)theWindow ) ;
  302.                 GetMouse(&localPt);
  303.                 if (!(didAdjustCursor = Q3ViewerAdjustCursor(theViewer, &localPt))) {
  304.                     InitCursor();
  305.                 }
  306.                 else {
  307.                     // DebugStr("\pQ3ViewerAdjustCursor returned true") ;
  308.                 }
  309.                 wasViewerEvent = Q3ViewerEvent ( theViewer, &event );
  310.                 SetPort( savedPort ) ;
  311.             }
  312.             else
  313.                 wasViewerEvent = false ;
  314.             
  315.             // was it a viewer event????
  316.             if( !wasViewerEvent ) {
  317.                 HandleEvent( &event );
  318.             } 
  319.         }
  320.     }
  321. }
  322.  
  323. //----------------------------------------------------------------------------------
  324. //    HandleActivateWindow is called when an event is received that reports that
  325. //    a window is being either activated or deactivated.
  326.  
  327. void HandleActivateWindow(WindowPtr theWindow, short activate)
  328. {
  329.     if (theWindow) {
  330.         if (activate) {
  331.         
  332.             // do whatever else you'd like to do for a activate event
  333.             LoadScrap() ;
  334.  
  335.         } else {
  336.         
  337.             // do whatever you'd like to do for a deactivate event
  338.             UnloadScrap() ;
  339.         }
  340.     }
  341. }
  342.  
  343. //--------------------------------------------------------------------------------------------
  344. //
  345. //
  346. Boolean        HandleEvent( EventRecord *theEvent )
  347. {
  348.     short               thePart;
  349.     WindowPtr            theWindow ;
  350.     Rect                screenRect;
  351.     GrafPtr                oldPort ;
  352.     Point                aPoint = {100, 100};
  353.     TQ3ViewerObject     theViewer = nil ;
  354.     ViewerDataHandle    myData ;
  355.     
  356.     switch (theEvent->what) {
  357.         case mouseDown:
  358.         
  359.             thePart = FindWindow( theEvent->where, &theWindow );
  360.             
  361.             switch( thePart ) {
  362.                 case inMenuBar: 
  363.                     MyAdjustMenus() ;
  364.                     HandleMenuCommand(MenuSelect(theEvent->where));
  365.                     break;
  366.                 
  367.                 case inDrag:
  368.                     screenRect = (**GetGrayRgn()).rgnBBox;
  369.                     DragWindow( theWindow, theEvent->where, &screenRect );
  370.                     break ;
  371.             
  372.                 case inContent:
  373.                     if (theWindow != FrontWindow())
  374.                         SelectWindow( theWindow );
  375.                     break ;
  376.             
  377.                 case inGoAway:
  378.                     if (TrackGoAway( theWindow, theEvent->where )) {
  379.                         MyDisposeViewerWindow( theWindow ) ;
  380.                     }
  381.                     break ;
  382.                     
  383.                 default:
  384.                     break ;
  385.             }
  386.             break ;
  387.                     
  388.                 
  389.         case updateEvt:
  390.         
  391.             theWindow = (WindowPtr)theEvent->message;
  392.             myData = (ViewerDataHandle)GetWRefCon( theWindow ) ;
  393.             theViewer = (**myData).theViewer ;
  394.             
  395.             GetPort(&oldPort ) ;    
  396.             SetPort( theWindow );
  397.             
  398.             BeginUpdate( theWindow );
  399.             Q3ViewerDraw( theViewer ) ;
  400.             EndUpdate( theWindow );
  401.             
  402.             SetPort( oldPort ) ;
  403.             
  404.             break ;
  405.             
  406.         case keyDown:
  407.         case autoKey:
  408.             HandleKeyPress(theEvent);
  409.             break;
  410.             
  411.         case diskEvt:
  412.             if ( HiWrd(theEvent->message) != noErr ) 
  413.                 (void) DIBadMount(aPoint, theEvent->message);
  414.             break;
  415.             
  416.         case osEvt:
  417.             break ;
  418.         case activateEvt:
  419.             if ((theWindow = (WindowPtr) theEvent->message) != nil) {
  420.                 HandleActivateWindow(theWindow, (theEvent->modifiers & activeFlag));
  421.             }
  422.  
  423.             break;
  424.  
  425.         case kHighLevelEvent:                        // Let the Apple Event Manager handle high level event.
  426.             AEProcessAppleEvent(theEvent);
  427.             break;
  428.  
  429.     }
  430.     return true ;
  431. }
  432.  
  433.  
  434. //--------------------------------------------------------------------------------------------
  435. //
  436. //
  437. void HandleKeyPress(EventRecord *event)
  438. {
  439.     char    key;
  440.  
  441.     key = event->message & charCodeMask;
  442.     
  443.     // just check to see if we want to quit...
  444.     
  445.     if ( event->modifiers & cmdKey ) {        /* Command key down? */
  446.         HandleMenuCommand(MenuKey(key));
  447.     } 
  448. }
  449.  
  450. //--------------------------------------------------------------------------------------------
  451. //
  452. //
  453.  
  454. void HandleAboutApp( void )
  455. {
  456.     ModalFilterUPP         theProc ;
  457.     DialogPtr            theDialog ; 
  458.     short                itemHit ;
  459.  
  460.     theDialog = GetNewDialog ( kMyAboutDialogID, nil, (WindowPtr)-1 );
  461.     
  462.     // these two lil' snappers are system 7 only
  463.     // so if you use them, check before!!
  464.     // in this app we will only run on Power
  465.     // Macintosh, so we don't check
  466.     
  467.     GetStdFilterProc( &theProc ) ;
  468.     SetDialogDefaultItem(theDialog, ok) ;
  469.     
  470.     // put the dialog up and loop 'til
  471.     // the user hits the OK button
  472.     
  473.     do {
  474.         ModalDialog ( theProc, &itemHit );
  475.     } while( itemHit != ok ) ;
  476.     
  477.     DisposDialog ( theDialog );
  478. }
  479.  
  480. //--------------------------------------------------------------------------------------------
  481. //
  482. //
  483. OSErr HandleOpenDoc(FSSpec *theFile)
  484. {
  485.     OSErr                err ;
  486.     short                theRef ;
  487.     ViewerDataHandle    myData ;
  488.     TQ3ViewerObject     theViewer ;
  489.     WindowPtr            theWindow ;
  490.  
  491.     // display the contents
  492.     theWindow = (WindowPtr)MyCreateViewerWindow() ;
  493.     
  494.     // open the file
  495.     err = FSpOpenDF( theFile, fsRdPerm, &theRef ) ;
  496.     if (err == noErr)
  497.     {
  498.         myData = (ViewerDataHandle)GetWRefCon( theWindow ) ;
  499.         theViewer = (**myData).theViewer ;
  500.         (**myData).theFile = *theFile ;
  501.         (**myData).isFileValid = true ;
  502.         Q3ViewerUseFile(theViewer, theRef) ;
  503.         err = FSClose(theRef) ;
  504.     }
  505.     
  506.     // set the window title
  507.     SetWTitle( theWindow, theFile->name );
  508.     MyAdjustMenus() ;
  509.     return err ;
  510. }
  511.  
  512.  
  513. //--------------------------------------------------------------------------------------------
  514. //
  515. //
  516. void HandleMenuCommand(long menuResult)
  517. {
  518.     short                menuID;
  519.     short                menuItem;
  520.     Str255                daName;
  521.     
  522.  
  523.     short                numTypes = 2 ;
  524.     SFTypeList            myTypes = { '3DMF', 'TEXT' } ;
  525.     OSErr                err ;
  526.     short                theRef ;
  527.     
  528.     ViewerDataHandle    myData ;
  529.     TQ3ViewerObject     theViewer ;
  530.     WindowPtr            theWindow ;
  531.     GrafPtr                savedPort ;
  532.     
  533.     FSSpec                theFile ;
  534.         
  535.     StandardFileReply    theSFReply ;
  536.  
  537.     menuID = HiWrd(menuResult);
  538.     menuItem = LoWrd(menuResult);
  539.     
  540.     switch ( menuID ) {
  541.         //
  542.         //--------------------------------------------------------------------------    
  543.         //
  544.         case mApple:
  545.             switch ( menuItem ) {
  546.  
  547.                 case iAbout:
  548.                     HandleAboutApp() ;    
  549.                     break ;
  550.                                 
  551.                 default:
  552.                     GetItem(GetMHandle(mApple), menuItem, daName);
  553.                     (void) OpenDeskAcc(daName);
  554.                     break;
  555.             }
  556.             break;
  557.         //
  558.         //--------------------------------------------------------------------------    
  559.         //
  560.         case mFile:
  561.             switch ( menuItem ) {
  562.                 case iNew:
  563.                     // display the contents
  564.                     (void)MyCreateViewerWindow() ;
  565.                     break ;
  566.                 
  567.                 case iOpen:
  568.                     // Get the file name to open
  569.                     StandardGetFile( nil, numTypes, myTypes, &theSFReply ) ;
  570.                     
  571.                     // did the user cancel, if not open the file?
  572.                     if(theSFReply.sfGood)
  573.                         MySendOpenDoc(&theSFReply.sfFile) ;
  574.  
  575.                     break ;
  576.                     
  577.                     
  578.                 case iRevert:
  579.                 
  580.                     // we know this can't be called as long as there
  581.                     // is an app window open (MyAdjustMenus) so get the refcon
  582.                     // from the front window and get the FSSpec from that
  583.                     theWindow = FrontWindow() ;
  584.                     myData = (ViewerDataHandle)GetWRefCon( theWindow ) ;
  585.                     theFile = (**myData).theFile ;
  586.                     
  587.                     // open the file and read it back into the viewer
  588.                     err = FSpOpenDF( &theFile, fsRdPerm, &theRef ) ;
  589.                     if (err == noErr)
  590.                     {
  591.                         theViewer = (**myData).theViewer ;
  592.                         Q3ViewerUseFile(theViewer, theRef) ;
  593.                         err = FSClose(theRef) ;
  594.                     }
  595.                     GetPort( &savedPort ) ;
  596.                     SetPort((GrafPtr)theWindow) ;
  597.                     InvalRect( &theWindow->portRect ) ;
  598.                     SetPort( savedPort ) ;
  599.                     break ;        
  600.                             
  601.                 case iSave:                
  602.                 
  603.                     // we know this can't be called as long as there
  604.                     // is an app window open (MyAdjustMenus) so get the refcon
  605.                     // from the front window and get the FSSpec from that
  606.                     theWindow = FrontWindow() ;
  607.                     myData = (ViewerDataHandle)GetWRefCon( theWindow ) ;
  608.                     theFile = (**myData).theFile ;
  609.                     theViewer = (**myData).theViewer ;
  610.  
  611.                     // assumes the original file still exists
  612.                     err = FSpOpenDF(&theFile, fsWrPerm, &theRef);
  613.                     if (err == noErr)
  614.                     {
  615.                         Q3ViewerWriteFile(theViewer, theRef);
  616.                         err = FSClose(theRef);
  617.                     }
  618.                     break ;
  619.                 
  620.                 case iSaveAs:
  621.                     // we know this can't be called as long as there
  622.                     // is an app window open (MyAdjustMenus) so get the refcon
  623.                     // from the front window and get the FSSpec from that
  624.                     theWindow = FrontWindow() ;
  625.                     myData = (ViewerDataHandle)GetWRefCon( theWindow ) ;
  626.                     theViewer = (**myData).theViewer ;
  627.  
  628.                     StandardPutFile("\pSave model as:", "\pUntitled", &theSFReply);
  629.                     if (theSFReply.sfGood)
  630.                     {
  631.                         err = FSpOpenDF(&theSFReply.sfFile, fsWrPerm, &theRef);
  632.                         if (err != noErr)
  633.                         {
  634.                             err = FSpCreate(&theSFReply.sfFile, '????', '3DMF', theSFReply.sfScript);
  635.                             if (err == noErr)
  636.                                 err = FSpOpenDF(&theSFReply.sfFile, fsCurPerm, &theRef);
  637.                         }
  638.                         if (err == noErr)
  639.                         {
  640.                             Q3ViewerWriteFile(theViewer, theRef);
  641.                             err = FSClose(theRef);
  642.                         }
  643.                         
  644.                         // set up our record of the file location,
  645.                         // update the structure
  646.                         theWindow = FrontWindow() ;
  647.                         myData = (ViewerDataHandle)GetWRefCon( theWindow ) ;
  648.                         theViewer = (**myData).theViewer ;
  649.                         (**myData).theFile = theSFReply.sfFile ;
  650.                         (**myData).isFileValid = true ;
  651.                         
  652.                         // reset the window title
  653.                         SetWTitle( theWindow, theSFReply.sfFile.name );
  654.                     }
  655.                     break;                
  656.                 
  657.                 case iClose:
  658.                     MyDisposeViewerWindow ( FrontWindow() );
  659.                     break ;
  660.                     
  661.                 case iQuit:
  662.                     MySendQuitApp();
  663.                     break;
  664.             }
  665.             break;
  666.             
  667.             
  668.         //
  669.         //--------------------------------------------------------------------------    
  670.         //
  671.         case mEdit:
  672.             // display the contents
  673.             theWindow = FrontWindow() ;
  674.             myData = (ViewerDataHandle)GetWRefCon( theWindow ) ;
  675.             theViewer = (**myData).theViewer ;
  676.             switch(menuItem)
  677.             {
  678.                 case iCut:
  679.                     Q3ViewerCut(theViewer);
  680.                     break;
  681.                 case iCopy:
  682.                     Q3ViewerCopy(theViewer);
  683.                     break;
  684.                 case iPaste:
  685.                     Q3ViewerPaste(theViewer);
  686.                     break;
  687.                 case iClear:
  688.                     Q3ViewerClear(theViewer);
  689.                     break;
  690.                 default:
  691.                     break;
  692.             }
  693.             break; 
  694.             
  695.         case mView:
  696.             
  697.             theWindow = FrontWindow() ;
  698.             
  699.             if( theWindow == nil )
  700.                 break ;
  701.                 
  702.             myData = (ViewerDataHandle)GetWRefCon( theWindow ) ;
  703.             theViewer = (**myData).theViewer ;
  704.             switch(menuItem)
  705.             {
  706.                 case iWireframe:
  707.                     {
  708.                         // get the view from the viewer
  709.                         TQ3ViewObject             myView = Q3ViewerGetView( theViewer );
  710.                         TQ3Status                myStatus;
  711.                         TQ3RendererObject        myRenderer;
  712.     
  713.                         // set the renderer to wireframe
  714.                         myRenderer = Q3Renderer_NewFromType(kQ3RendererTypeWireFrame);
  715.                         if ((myStatus = Q3View_SetRenderer(myView, myRenderer)) == kQ3Failure ) {
  716.                             
  717.                             // dispose of the view, this reduces
  718.                             // the reference count and the changes we
  719.                             // made to the viewer's defualt will remain.
  720.                             Q3Object_Dispose( myView ) ;
  721.                         }
  722.                         Q3Object_Dispose( myRenderer ) ;
  723.  
  724.                     }
  725.                     break;
  726.                     
  727.                 case iInteractive:
  728.                     {
  729.                         // get the view from the viewer
  730.                         TQ3ViewObject             myView = Q3ViewerGetView( theViewer );
  731.                         TQ3Status                myStatus;
  732.                         TQ3RendererObject        myRenderer;
  733.     
  734.                         // set the renderer to use the interactive renderer
  735.                         myRenderer = Q3Renderer_NewFromType(kQ3RendererTypeInteractive);
  736.                         if ((myStatus = Q3View_SetRenderer(myView, myRenderer)) == kQ3Failure ) {
  737.                             Q3Object_Dispose( myView ) ;
  738.                         }
  739.                         Q3Object_Dispose( myRenderer ) ;
  740.  
  741.                     }
  742.                     break;
  743.                     
  744.                 default:
  745.                     break;
  746.             }
  747.             GetPort( & savedPort ) ;
  748.             SetPort( theWindow ) ;
  749.             InvalRect( &theWindow->portRect ) ;
  750.             SetPort( savedPort ) ;
  751.             break;
  752.  
  753.     }
  754.     HiliteMenu(0);        // Unhighlight whatever MenuSelect or MenuKey hilited
  755. }
  756.  
  757. //--------------------------------------------------------------------------------------------
  758. //
  759. //
  760. void MyAdjustMenus( void ) 
  761. {
  762.     WindowPtr            theWindow ;
  763.     ViewerDataHandle    myData ;
  764.     MenuHandle            theMenu ;
  765.  
  766.     theWindow = FrontWindow() ;
  767.     
  768.     
  769.     if( theWindow != nil ) {
  770.     
  771.         theMenu =  GetMHandle ( mFile ) ;
  772.         
  773.         EnableItem ( theMenu, iClose );
  774.         EnableItem ( theMenu, iSaveAs );
  775.                  
  776.         myData = (ViewerDataHandle)GetWRefCon( theWindow ) ;
  777.         
  778.          if(    (**myData).isFileValid) {
  779.             EnableItem ( theMenu, iSave );
  780.             EnableItem (theMenu, iRevert );
  781.          }
  782.          else {
  783.             DisableItem ( theMenu, iSave );
  784.             DisableItem ( theMenu, iRevert );
  785.          
  786.          }
  787.          
  788.          EnableItem ( GetMHandle ( mEdit ), 0 );
  789.  
  790.     }
  791.     else {
  792.  
  793.         theMenu =  GetMHandle ( mFile ) ;
  794.  
  795.         DisableItem ( theMenu, iClose );
  796.         DisableItem ( theMenu, iRevert );
  797.         DisableItem ( theMenu, iSave );
  798.         DisableItem ( theMenu, iSaveAs );
  799.         
  800.         DisableItem ( GetMHandle ( mEdit ), 0 );
  801.     }
  802.     
  803.     // we don't support undo
  804.     DisableItem ( GetMHandle ( mEdit ), iUndo );
  805.     
  806.     DrawMenuBar() ;
  807. }
  808.  
  809.  
  810. //--------------------------------------------------------------------------------------------
  811. //
  812. //
  813. OSErr    MyDisposeViewerWindow( WindowPtr theWindow )
  814. {
  815.     TQ3ViewerObject     theViewer ;
  816.     ViewerDataHandle    myData ;
  817.     
  818.     if( theWindow == nil)
  819.         return paramErr ;
  820.  
  821.     myData = (ViewerDataHandle)GetWRefCon( theWindow ) ;
  822.     theViewer = (**myData).theViewer ;
  823.     
  824.     DisposHandle((Handle)myData);
  825.     DisposeWindow(theWindow);
  826.     
  827.     MyAdjustMenus() ;
  828.     return     Q3ViewerDispose(theViewer);
  829. }
  830.  
  831.  
  832. //--------------------------------------------------------------------------------------------
  833. //
  834. //
  835. CGrafPtr MyCreateViewerWindow(  )
  836. {
  837.  
  838.     Rect                theRect ;
  839.     GrafPtr                savedPort ;
  840.     TQ3ViewerObject        myViewerObj ;
  841.     WindowPtr            theWindow ;
  842.     ViewerDataHandle    myData = (ViewerDataHandle)NewHandle(sizeof(ViewerData)) ;
  843.     
  844.     GetPort( &savedPort ) ;
  845.         
  846.     // set the new rect up with a stagger for multiple windows
  847.     SetRect(    &theRect, 
  848.                 gStaggerPos.h, 
  849.                 gStaggerPos.v, 
  850.                 gStaggerPos.h + kWindowWidth, 
  851.                 gStaggerPos.v + kWindowHeight );
  852.  
  853.     gStaggerPos.h += 16 ;
  854.     gStaggerPos.v += 16 ;        // this is not "real staggering code, it don't wrap ;        
  855.                          
  856.     theWindow  = NewCWindow(    nil, 
  857.                                 &theRect, 
  858.                                 "\pUntitled", 
  859.                                 false, 
  860.                                 documentProc, 
  861.                                 (WindowPtr)-1, 
  862.                                 true, 
  863.                                 0L );    
  864.                     
  865.     SetPort( (GrafPtr)theWindow ) ;
  866.     
  867.     // set up the viewer object here
  868.     myViewerObj = Q3ViewerNew ((CGrafPtr)theWindow,  &theWindow->portRect,  kQ3ViewerDefault) ; 
  869.     
  870.     //stuff the reference to the viewer in the RefCon field of the Window
  871.     (**myData).theViewer = myViewerObj ;
  872.     (**myData).isFileValid = false ;
  873.     SetWRefCon( theWindow, (long)myData );
  874.     
  875.     // make sure it is visible
  876.     ShowWindow( theWindow ) ;
  877.     
  878.     // invalidate the content region of the window - 
  879.     // we don't do any drawing to it here.
  880.     InvalRect ( &theRect );
  881.     SetPort( savedPort ) ;
  882.     
  883.     return (CGrafPtr)theWindow ;
  884. }
  885.  
  886.  
  887. //-----------------------------------------------------------------------
  888. // returns true if the platform supports appleevents - we won't run
  889. // if it doesn't
  890.  
  891. Boolean SupportsAEVT(void)
  892. {
  893.     OSErr err;
  894.     long response;
  895.         
  896.     err = Gestalt(gestaltAppleEventsAttr,&response);
  897.     if (err!=noErr)
  898.         return false;
  899.         
  900.     return (response && (response << gestaltAppleEventsPresent));
  901. }
  902.  
  903. //-----------------------------------------------------------------------
  904. // called to register our appleevent handlers
  905.  
  906. void RegisterMyEvents(void)
  907. {
  908.     OSErr err;
  909.     
  910.     if (!SupportsAEVT())
  911.         return;
  912.     
  913.     err = AEInstallEventHandler(kCoreEventClass,kAEOpenApplication,NewAEEventHandlerProc(MyAEHandleOAPP),0L,false);
  914.     if (err!=noErr)
  915.         return;
  916.                 
  917.     err = AEInstallEventHandler(kCoreEventClass,kAEOpenDocuments,NewAEEventHandlerProc(MyAEHandleODOC),0L,false);
  918.     if (err!=noErr)
  919.         return;
  920.                 
  921.     err = AEInstallEventHandler(kCoreEventClass,kAEPrintDocuments,NewAEEventHandlerProc(MyAEHandlePDOC),0L,false);
  922.     if (err!=noErr)
  923.         return;
  924.                 
  925.     err = AEInstallEventHandler(kCoreEventClass,kAEQuitApplication,NewAEEventHandlerProc(MyAEHandleQUIT),0L,false);
  926.     if (err!=noErr)
  927.         return;
  928. }
  929.  
  930. //-----------------------------------------------------------------------
  931. // open application event handler for the core event suite, 
  932. // by default we just want a blank new document
  933.  
  934. pascal OSErr MyAEHandleOAPP( AppleEvent *theAppleEvent, AppleEvent *reply, long refCon)
  935. {
  936. #pragma unused (theAppleEvent, reply, refCon)
  937.     // we don't actually do anything on open - you could,
  938.     // for example you might want to open a blank untitled 
  939.     // window
  940.     
  941.     OSErr err = noErr ;
  942.     return err;
  943. }
  944.  
  945.  
  946. //-----------------------------------------------------------------------
  947. // handler for the open document appleevent handler
  948.  
  949. pascal OSErr MyAEHandleODOC(AppleEvent *theAppleEvent, AppleEvent *reply, long refCon)
  950. {
  951. #pragma unused ( reply, refCon)
  952.     FSSpec         myFSS;
  953.     AEDescList    docList;
  954.     OSErr        err,
  955.                 ignoreErr;
  956.     long        index,
  957.                 itemsInList;
  958.     Size         actualSize;
  959.     AEKeyword    keywd;
  960.     DescType    returnedType;
  961.  
  962.     
  963.     err = AEGetParamDesc(theAppleEvent,keyDirectObject,typeAEList,&docList);
  964.     if (err == noErr) {
  965.     
  966.         // see how many descriptor items are in the list
  967.         // this is the number of documents we want to open
  968.         err = AECountItems(&docList,&itemsInList);
  969.  
  970.         // now get each descriptor record from the list
  971.         // coerce the returned data to an FSSpec record, and
  972.         // open the asoociated file
  973.         
  974.         for (index=1; index <= itemsInList && err == noErr; index++) {
  975.         
  976.             err = AEGetNthPtr(    &docList, 
  977.                                 index,
  978.                                 typeFSS,
  979.                                 &keywd,
  980.                                 &returnedType,
  981.                                 (Ptr)&myFSS,
  982.                                 sizeof(myFSS),
  983.                                 &actualSize);
  984.     
  985.             if (err == noErr)    {
  986.             
  987.                 FInfo        fndrInfo ;
  988.                 
  989.                 // we now have a valid FSSpec to reference the file, we need to know 
  990.                 // what type the file is to determine which file open function to call
  991.                 // we can determine this from the finder info for the file
  992.                 
  993.                 err = FSpGetFInfo( &myFSS, &fndrInfo );    
  994.                 
  995.                 // if we got that ok, then we switch on the file  
  996.                 // type (we don't care about the creator type)    
  997.                         
  998.                 if (err == noErr)    {
  999.                 
  1000.                     switch( fndrInfo.fdType ) {
  1001.                         case 'TEXT':
  1002.                         case '3DMF':
  1003.                             err =  HandleOpenDoc(&myFSS);
  1004.                             break ;
  1005.                     }
  1006.                 }
  1007.             }
  1008.         }
  1009.         ignoreErr = AEDisposeDesc(&docList);
  1010.     }
  1011.     return err ;
  1012. }
  1013.  
  1014. //-----------------------------------------------------------------------
  1015. // handler for the print document event handler
  1016.  
  1017. pascal OSErr MyAEHandlePDOC(AppleEvent *theAppleEvent,AppleEvent *reply,long refCon)
  1018. {
  1019. #pragma unused ( reply, refCon)
  1020.     FSSpec         myFSS;
  1021.     AEDescList    docList;
  1022.     OSErr        err;
  1023.     long        index,
  1024.                 itemsInList;
  1025.     Size         actualSize;
  1026.     AEKeyword    keywd;
  1027.     DescType    returnedType;
  1028.  
  1029.     
  1030.     err = AEGetParamDesc(theAppleEvent,keyDirectObject,typeAEList,&docList);
  1031.     if (err == noErr) {
  1032.     
  1033.         // see how many descriptor items are in the list
  1034.         // this is the number of documents we want to open
  1035.         err = AECountItems(&docList,&itemsInList);
  1036.  
  1037.         // now get each descriptor record from the list
  1038.         // coerce the returned data to an FSSpec record, and
  1039.         // open the asoociated file
  1040.         
  1041.         for (index=1; index <= itemsInList && err == noErr; index++) {
  1042.         
  1043.             err = AEGetNthPtr(    &docList, 
  1044.                                 index,
  1045.                                 typeFSS,
  1046.                                 &keywd,
  1047.                                 &returnedType,
  1048.                                 (Ptr)&myFSS,
  1049.                                 sizeof(myFSS),
  1050.                                 &actualSize);
  1051.     
  1052.             if (err == noErr)    {                    
  1053.                 // err = HandlePrintDoc( &myFSS );
  1054.                 err = errAEEventNotHandled ;         // we don't do this yet...
  1055.             }
  1056.         }
  1057.         err = AEDisposeDesc(&docList);
  1058.     }
  1059.     return err ;
  1060. }
  1061.  
  1062. //-----------------------------------------------------------------------
  1063. // quit appleevent handler
  1064.  
  1065. pascal OSErr MyAEHandleQUIT(AppleEvent *theAppleEvent,AppleEvent *reply,long refCon)
  1066. {
  1067. #pragma unused ( theAppleEvent, reply, refCon)
  1068.     OSErr             err = noErr ;        // used as return value
  1069.     WindowPtr        theWindow ;
  1070.     Boolean            quitting = true ;
  1071.  
  1072.     
  1073.     // close all windows and signal to Quit
  1074.  
  1075.         
  1076.     // attempt to close all documents
  1077.     while(( theWindow = FrontWindow()) != nil && quitting )
  1078.         quitting = (MyDisposeViewerWindow( theWindow ) == noErr);    
  1079.         
  1080.  
  1081.     // if we closed everything up successfully, we can return noErr, otherwise
  1082.     // indicate to sender of the 'quit' aevt that we canceled
  1083.     
  1084.     if (quitting) {
  1085.         gQuitFlag = true;                    // user didn't cancel
  1086.          AEDisposeDesc(&gSelfAddress);        // Dispose of my self-addressed descriptor.
  1087.     }
  1088.     else {
  1089.         err = userCanceledErr ;
  1090.     }
  1091.             
  1092.     return err ;
  1093. }
  1094.  
  1095.  
  1096. //----------------------------------------------------------------------------------//
  1097. //    Send a Quit Application Apple Event to myself to terminate this app.        
  1098.  
  1099. void MySendQuitApp( void )
  1100. {
  1101.     AppleEvent    myAppleEvent, reply;
  1102.     
  1103.     //    Create the Apple Event.
  1104.     FailIfErr(AECreateAppleEvent( kCoreEventClass, 
  1105.                                   kAEQuitApplication, 
  1106.                                   &gSelfAddress,
  1107.                                   kAutoGenerateReturnID, 
  1108.                                   kAnyTransactionID, 
  1109.                                   &myAppleEvent));
  1110.                                   
  1111.     //    Send the Apple Event.
  1112.       FailIfErr(AESend( &myAppleEvent, 
  1113.                         &reply, 
  1114.                         kAENoReply+kAENeverInteract, 
  1115.                         kAENormalPriority,
  1116.                         kAEDefaultTimeout, 
  1117.                         nil, 
  1118.                         nil));
  1119.                         
  1120.       AEDisposeDesc(&myAppleEvent);                // Dispose of the Apple Event.
  1121. } // MySendQuitApp
  1122.  
  1123.  
  1124. //----------------------------------------------------------------------------------//
  1125. //    Send a Open Document Application Apple Event to myself to open a document.        
  1126.  
  1127. void MySendOpenDoc(FSSpec *myFSSpec)
  1128. {
  1129.      AppleEvent    myAppleEvent;
  1130.     AppleEvent    defReply;
  1131.     AEDescList    docList;
  1132.     OSErr         ignoreErr;
  1133.     
  1134.     myAppleEvent.dataHandle = nil;
  1135.     docList.dataHandle  = nil;
  1136.     defReply.dataHandle = nil;
  1137.         
  1138.     // Create empty list and add one file spec
  1139.     FailIfErr(AECreateList(nil,0,false, &docList));
  1140.     
  1141.     FailIfErr(AEPutPtr(&docList,1,typeFSS,(Ptr)myFSSpec,sizeof(FSSpec)));
  1142.         
  1143.     FailIfErr(AECreateAppleEvent(    kCoreEventClass,
  1144.                                     kAEOpenDocuments,
  1145.                                     &gSelfAddress,
  1146.                                     kAutoGenerateReturnID,
  1147.                                     kAnyTransactionID,
  1148.                                     &myAppleEvent));
  1149.  
  1150.     // Put Params into our event and send it
  1151.  
  1152.     FailIfErr(AEPutParamDesc( &myAppleEvent,
  1153.                               keyDirectObject,
  1154.                               &docList));
  1155.  
  1156.     FailIfErr(AESend( &myAppleEvent,
  1157.                       &defReply,
  1158.                       kAENoReply+kAENeverInteract,
  1159.                       kAENormalPriority,
  1160.                       kAEDefaultTimeout,
  1161.                       nil,
  1162.                       nil));
  1163.         
  1164.         
  1165.     if (myAppleEvent.dataHandle) 
  1166.         ignoreErr = AEDisposeDesc(&myAppleEvent);
  1167.         
  1168.     if (docList.dataHandle) 
  1169.         ignoreErr = AEDisposeDesc(&docList);
  1170.             
  1171. }    // MySendOpenDoc 
  1172.