home *** CD-ROM | disk | FTP | other *** search
- /*
- File: menus & windows.c
-
- Contains: This file contains the menu and window handling routines for the QuickDraw
- GX shell application.
-
- Written by: Developer Technical Support
-
- Copyright: © 1992-1997 by Apple Computer, Inc., all rights reserved.
-
- Writers:
-
- (DMH) Dave Hersey
- (IK) Ingrid Kelly
-
- Change History (most recent first):
-
- <6> 6/1/97 IK Modified printing routines for GXGraphics 1.1.6.
- <5> 8/1/94 DMH Universalized.
- <4> 5/1/94 DMH Fixed some bad, bad, viewport-confused code.
- <3> 9/1/93 PLA Updated to run with the b2 "GXified" interface files.
- <2> 2/1/93 DMH Debugged and plopped on GX CD.
- <1> 9/1/92 DMH First created.
- */
-
- #include <stdio.h>
- #include <Devices.h>
- #include <GXEnvironment.h>
-
- #include "FontLibrary.h"
- #include "GraphicsLibraries.h"
- #include "PrintingLibrary.h"
-
- #include "main.h"
-
- /* ---------------------------------------------------------------------------
- Constants
- --------------------------------------------------------------------------- */
-
- #define kOSEvent app4Evt /* Event used by the Process Manager. */
- #define kSuspendResumeMessage 1 /* High byte of suspend/resume event message. */
- #define kResumeMask 1 /* Bit of message field for resume event message. */
-
- /* ---------------------------------------------------------------------------
- Function prototypes
- --------------------------------------------------------------------------- */
-
- static Boolean IsAppWindow(WindowPtr window);
- static void CreateSampleImage(TH_Document document, short whichPg);
- static OSErr InsertPage(TH_Document document, short *whichPg);
- static void DisposePage(TH_Document document, short whichPg);
-
- /* ===========================================================================
- Public functions
- =========================================================================== */
-
- /* ---------------------------------------------------------------------------
- DoSetup
- Initialize the global variables and custom data structures of the
- application.
- --------------------------------------------------------------------------- */
-
- void DoSetup(void)
- {
- }
-
- /* ---------------------------------------------------------------------------
- DoDraw
- Draw the contents of a window.
- --------------------------------------------------------------------------- */
-
- void DoDraw(WindowPtr window)
- {
- if ( window != nil )
- {
- TH_Document document = GetDocument(window);
-
- if ( document != nil )
- GXDrawShape(GetPageShape(document, (*document)->page));
- }
- }
-
- /* ---------------------------------------------------------------------------
- InitDocument
- Initialize the custom data structure of a window.
- --------------------------------------------------------------------------- */
-
- OSErr InitDocument(WindowPtr window)
- {
- TH_Document document;
- gxprJobHdl gxprJob = nil;
- short newPage;
- OSErr error = noErr;
-
- /* Allocate the custom data structure of the document. */
-
- document = (TH_Document)NewHandleClear(sizeof(T_Document));
- if ( document == nil )
- {
- error = MemError();
- goto NewHandleClearFailed;
- }
-
- (*document)->window = window;
- (*document)->viewport = GXNewWindowViewPort(window);
- error = (OSErr)GXGetGraphicsError(nil);
-
- if ( error != noErr )
- goto GXNewWindowViewPortFailed;
-
- /* If QuickDraw GX printing is present, create a new job object and install
- an application override for the gxPrintingEvent message. Note that you
- only need to have this message overridden while print dialogs are
- displayed, but overriding it here doesn't hurt.
-
- Create a print job for this document. This will be the same as the system
- default until the user goes through the dialogs for Page Setup or Print.
- */
- error = GXPrNewJob(&gxprJob);
-
- /* If there are no errors, install our overrides for the format dialog (which
- will add our panel to it) and gxPrintingEvent (which will allow us to
- update our windows as the printing dialogs are moved around. Create a
- handle the size of our document structure and store the print job and one
- page description in it. Store the handle in the window's refCon field so
- that we can get at it. Note that the utility routines "GetDocumentJob"
- and "GetPageShape" can be used to do this easily.
- */
- if ( error == noErr )
- {
- GXPrInstallApplicationOverride(gxprJob, gxPrintingEventMsg, gGXPrintingEventUPP);
- GXPrInstallApplicationOverride(gxprJob, gxFormatDialogMsg, gGXFormatDialogUPP);
-
- error = GXPrGetJobError(gxprJob);
- }
- else
- goto GXPrNewJobFailed;
-
- (*document)->gxprJob = gxprJob;
- (*document)->page = 1;
- (*document)->pageCount = 0;
-
- newPage = 1;
-
- error = InsertPage(document, &newPage);
- if ( error != noErr )
- goto InsertPageFailed;
-
- SetDocument(window, document);
- if ( error == noErr )
- goto Completed;
-
- InsertPageFailed:
- if ( gxprJob != nil )
- GXPrDisposeJob(gxprJob);
-
- GXPrNewJobFailed:
- GXNewWindowViewPortFailed:
- if ( document != nil )
- DisposeHandle((Handle)document);
-
- NewHandleClearFailed:
- Completed:
- return error;
- }
-
- /* ---------------------------------------------------------------------------
- DoNew
- Create a new window.
- --------------------------------------------------------------------------- */
-
- OSErr DoNew(void)
- {
- WindowPtr window;
- OSErr error = noErr;
-
- /* Create a window for the document. */
-
- window = GetNewCWindow(rDocumentWINDID, nil, (WindowPtr)-1L);
- if ( window == nil )
- {
- error = MemError();
- goto GetNewCWindowFailed;
- }
-
- /* Create and initialize the private data for the document; attach a default
- viewport to it, and add a sample image to its page shape.
- */
- error = InitDocument(window);
- if ( error != noErr )
- goto DoDocumentInitFailed;
-
- /* Invalidate the window's portRect so that everything gets updated. */
-
- SetPort(window);
- InvalRect(&window->portRect);
- if ( error == noErr )
- goto Completed;
-
- DoDocumentInitFailed:
- DoClose(window);
-
- GetNewCWindowFailed:
- Completed:
- return error;
- }
-
- /* ---------------------------------------------------------------------------
- DoClose
- Close a window and dispose of its custom data structure.
-
- You should always dispose of your GX graphics objects before tossing your
- window. Why? It's generally good form and this approach guarantees that
- everything is disposed. If you had not disposed of everything, the call to
- DisposeWindow should dispose of the objects. If you are running the
- debugging version of the SecretGraphics init with notices set, you will
- receive a notice that you had not disposed of everything.
- --------------------------------------------------------------------------- */
-
- void DoClose(WindowPtr window)
- {
- short pageCount;
- short pg;
-
- if ( window != nil )
- {
- TH_Document document = GetDocument(window);
- gxprJobHdl gxprJob = nil;
-
- if ( document != nil )
- {
- pageCount = (*document)->pageCount; /* Get the number of pages in our document. */
-
- for ( pg = pageCount; pg >= 1; pg-- )
- DisposePage(document, pg); /* Dispose of each page's info and shapes. */
-
- /* Dispose of this document's print job. */
-
- gxprJob = GetDocumentJob(document);
- if ( gxprJob != nil )
- GXPrDisposeJob(gxprJob);
-
- DisposeHandle((Handle)document); /* Dispose of the document's private data. */
- DisposeWindow(window); /* Dispose of the window. */
- }
- }
- }
-
- /* ---------------------------------------------------------------------------
- DoIdle
- Handle idle event tasks from the event loop.
- --------------------------------------------------------------------------- */
-
- void DoIdle(WindowPtr window)
- {
- }
-
- /* ---------------------------------------------------------------------------
- DoTeardown
- Dispose of the custom data structures of the application that were created
- in DoSetup().
- --------------------------------------------------------------------------- */
-
- void DoTeardown(void)
- {
- }
-
- /* ---------------------------------------------------------------------------
- DoClick
- --------------------------------------------------------------------------- */
-
- void DoClick(WindowPtr window, Point p)
- {
- }
-
- /* ---------------------------------------------------------------------------
- DoEvent
- --------------------------------------------------------------------------- */
-
- void DoEvent(EventRecord *event)
- {
- char key;
- WindowPtr window;
- GrafPtr oldPort;
- Rect screenRect;
-
- switch( event->what )
- {
- case updateEvt:
- if ( IsAppWindow((WindowPtr)event->message) )
- {
- GetPort(&oldPort);
- SetPort((WindowPtr)event->message);
- BeginUpdate((WindowPtr)event->message);
- DoDraw((WindowPtr)event->message);
- EndUpdate((WindowPtr)event->message);
- SetPort(oldPort);
- }
- break;
-
- case mouseDown:
- switch ( FindWindow(event->where, &window) )
- {
- case inSysWindow:
- SystemClick(event, window);
- break;
-
- case inDrag:
- screenRect = (**GetGrayRgn()).rgnBBox;
- if ( IsAppWindow(window) )
- DragWindow(window, event->where, &screenRect);
- break;
-
- case inGoAway:
- if ( IsAppWindow(window) )
- if ( TrackGoAway(window, event->where) )
- DoClose(window);
- break;
-
- case inContent:
- if ( IsAppWindow(window) )
- if ( window == FrontWindow() )
- DoClick(window, event->where);
- else
- SelectWindow(window);
- break;
-
- case inMenuBar:
- DoMenuCommand(MenuSelect(event->where));
- break;
- }
- break;
-
- case keyDown:
- case autoKey:
- key = event->message & charCodeMask;
- if ( event->modifiers & cmdKey )
- if ( event->what == keyDown )
- DoMenuCommand(MenuKey(key));
- break;
-
- case kOSEvent:
- switch ( (unsigned long)event->message >> 24 ) /* high byte of message */
- {
- /* The Suspend/Resume event is also an Activate/Deactivate event. */
-
- case kSuspendResumeMessage:
- if ( (event->message & kResumeMask ) == 0 )
- gSleep = 80; /* The application is headed for the background, so slow down. */
- else
- {
- gSleep = 0; /* The application is headed for the foreground, so speed up. */
-
- /* On a resume event, we need to call GXUpdateJob on all of our documents'
- jobs. This is important because the user may have just changed something
- which affects our jobs (like the size of the paper in the printer).
-
- Since our application stores our document references in the refCon fields
- of our documents' windows, we just loop through every one of our windows,
- extract our document pointers and update the associated jobs.
- */
- window = FrontWindow();
-
- while ( window != nil )
- {
- if ( ((WindowPeek)window)->windowKind == userKind )
- GXPrUpdateJob(GetDocumentJob(GetDocument(window)));
-
- window = (WindowPtr)((WindowPeek)window)->nextWindow;
- }
- }
- break;
- }
- break;
- }
- }
-
- /* ---------------------------------------------------------------------------
- DoMenuCommand
- Handle menu event tasks from the event loop.
- --------------------------------------------------------------------------- */
-
- void DoMenuCommand(long menuResult)
- {
- short menuID;
- short menuItem;
- Str255 daName;
- WindowPtr activeWindow;
- TH_Document activeDocument;
- gxDialogResult result;
- short page;
- short pageCount;
- short newPage;
- OSErr error = noErr;
-
- menuID = menuResult >>16;
- menuItem = menuResult & 0x0000ffff;
- activeWindow = FrontWindow();
- activeDocument = GetDocument(activeWindow);
-
- switch ( menuID )
- {
- case mApple:
- switch ( menuItem )
- {
- case iAbout:
- /* Display the About box. */
- Alert(rAboutBoxALRTID, nil);
- break;
-
- default:
- /* Handle the Apple menu. */
- GetItem(GetMHandle(mApple), menuItem, daName);
- OpenDeskAcc(daName);
- break;
- }
- break;
-
- case mFile:
- switch ( menuItem )
- {
- case iNew:
- /* Create a new document. */
- error = DoNew();
- break;
-
- case iOpen:
- /* Open a document. */
- break;
-
- case iClose:
- /* Close the current document. */
- DoClose(activeWindow);
- break;
-
- case iSave:
- /* Save the current document. */
- break;
-
- case iPageSetup:
- /* Set the default page format of the current document. */
- HiliteMenu(0);
- error = DoPageFormat(activeWindow, &result);
- break;
-
- case iCustomPageSetup:
- /* Set the current page format. */
- HiliteMenu(0);
- error = DoCustomPageFormat(activeWindow, &result);
- break;
-
- case iPrint:
- /* Print the current document. */
- HiliteMenu(0);
- error = DoPrint(activeWindow);
- break;
-
- case iPrintOneCopy:
- /* Print one copy of the current document. */
- error = DoPrintOneCopy(activeWindow);
- break;
-
- case iQuit:
- gQuitting = true;
- break;
- }
- break;
-
- case mEdit:
- break;
-
- case mDocument:
- switch ( menuItem )
- {
- case iInsertPage:
- /* Add a page */
- newPage = (*activeDocument)->page;
- InsertPage(activeDocument, &newPage);
- (*activeDocument)->page = newPage;
-
- SetPort(activeWindow);
- EraseRect(&activeWindow->portRect);
- InvalRect(&activeWindow->portRect);
- break;
-
- case iDeletePage:
- /* Delete the active page. */
- page = (*activeDocument)->page;
- pageCount = (*activeDocument)->pageCount;
- if ( pageCount > 1 )
- {
- DisposePage(activeDocument, page);
-
- if ( page == pageCount )
- page = --(*activeDocument)->page;
-
- SetPort(activeWindow);
- EraseRect(&activeWindow->portRect);
- InvalRect(&activeWindow->portRect);
- }
- break;
-
- case iNextPage:
- /* Move to the next page. */
- page = (*activeDocument)->page;
- pageCount = (*activeDocument)->pageCount;
- if ( page < pageCount )
- {
- ++(*activeDocument)->page;
-
- SetPort(activeWindow);
- EraseRect(&activeWindow->portRect);
- InvalRect(&activeWindow->portRect);
- }
- break;
-
- case iPrevPage:
- /* Move to the previous page. */
- page = (*activeDocument)->page;
- if ( page > 1 )
- {
- --(*activeDocument)->page;
-
- SetPort(activeWindow);
- EraseRect(&activeWindow->portRect);
- InvalRect(&activeWindow->portRect);
- }
- break;
- }
- break;
- }
-
- HiliteMenu(0);
- }
-
- /* ---------------------------------------------------------------------------
- EventLoop
- --------------------------------------------------------------------------- */
-
- void EventLoop(void)
- {
- EventRecord event;
-
- if ( WaitNextEvent(everyEvent, &event, gSleep, nil) )
- DoEvent(&event);
- else
- DoIdle(FrontWindow());
- }
-
- /* ---------------------------------------------------------------------------
- Accessor routines for the document structure attached to a window.
- --------------------------------------------------------------------------- */
-
- TH_Document GetDocument(WindowPtr window)
- {
- TH_Document document = nil;
-
- if ( window )
- document = (TH_Document)GetWRefCon(window);
- return document;
- }
-
- void SetDocument(WindowPtr window, TH_Document document)
- {
- if ( window )
- SetWRefCon(window, (long)document);
- }
-
- /* ---------------------------------------------------------------------------
- Accessor routines for the viewport attached to a document.
- --------------------------------------------------------------------------- */
-
- gxViewPort GetDocumentViewPort(TH_Document document)
- {
- gxViewPort viewport = nil;
-
- if ( document )
- viewport = (*document)->viewport;
- return viewport;
- }
-
- void SetDocumentViewPort(TH_Document document, gxViewPort viewport)
- {
- if ( document )
- (*document)->viewport = viewport;
- }
-
- /* ---------------------------------------------------------------------------
- Accessor routines for the print job structure attached to a document.
- --------------------------------------------------------------------------- */
-
- gxprJobHdl GetDocumentJob(TH_Document document)
- {
- gxprJobHdl gxprJob = nil;
-
- if ( document )
- gxprJob = (*document)->gxprJob;
- return gxprJob;
- }
-
- void SetDocumentJob(TH_Document document, gxprJobHdl gxprJob)
- {
- if ( document )
- (*document)->gxprJob = gxprJob;
- }
-
- /* ---------------------------------------------------------------------------
- Accessor routines for the page structure(s) attached to a document.
- --------------------------------------------------------------------------- */
-
- TH_Page GetDocumentPage(TH_Document document, short whichPg)
- {
- TH_Page page = nil;
-
- if ( document )
- page = (*document)->pageArray[whichPg - 1];
- return page;
- }
-
- void SetDocumentPage(TH_Document document, short whichPg, TH_Page page)
- {
- if ( document )
- (*document)->pageArray[whichPg - 1] = page;
- }
-
- /* ---------------------------------------------------------------------------
- Accessor routines for the page format(s) attached to a document.
- --------------------------------------------------------------------------- */
-
- gxprFormatHdl GetPageFormat(TH_Document document, short whichPg)
- {
- TH_Page page;
- gxprFormatHdl gxprFormat = nil;
-
- if ( document )
- {
- page = (*document)->pageArray[whichPg - 1];
- if ( page )
- gxprFormat = (*page)->gxprFormat;
- }
- return gxprFormat;
- }
-
- void SetPageFormat(TH_Document document, short whichPg, gxprFormatHdl gxprFormat)
- {
- TH_Page page;
-
- if ( document )
- {
- page = (*document)->pageArray[whichPg - 1];
- if ( page )
- (*page)->gxprFormat = gxprFormat;
- }
- }
-
- /* ---------------------------------------------------------------------------
- Accessor routines for the page shape(s) attached to a document.
- --------------------------------------------------------------------------- */
-
- gxShape GetPageShape(TH_Document document, short whichPg)
- {
- TH_Page page;
- gxShape shape = nil;
-
- if ( document )
- {
- page = (*document)->pageArray[whichPg -1];
- if ( page )
- shape = (*page)->shape;
- }
- return shape;
- }
-
- void SetPageShape(TH_Document document, short whichPg, gxShape shape)
- {
- TH_Page page;
-
- if ( document )
- {
- page = (*document)->pageArray[whichPg - 1];
- if ( page )
- (*page)->shape = shape;
- }
- }
-
- /* ===========================================================================
- Private functions
- =========================================================================== */
-
- /* ---------------------------------------------------------------------------
- IsAppWindow
- --------------------------------------------------------------------------- */
-
- static Boolean IsAppWindow(WindowPtr window)
- {
- return window != nil && ((WindowPeek)window)->windowKind == userKind;
- }
-
- /* ---------------------------------------------------------------------------
- CreateSampleImage
- This function adds a simple shape to the page indicated in the passed
- document.
- --------------------------------------------------------------------------- */
-
- static void CreateSampleImage(TH_Document document, short whichPg)
- {
- short pageCount;
- gxShape shape;
- gxShape theText;
- gxColor textColor;
- Str255 textStr;
- short charCount;
- short loop;
-
- pageCount = (*document)->pageCount;
-
- /* Retrieve the page gxShape so we can add to it. */
-
- shape = GetPageShape(document, whichPg);
-
- charCount = sprintf((Ptr)&textStr[0], "%s %i %s", "This was added when there were", pageCount - 1, "pages");
- theText = GXNewText(charCount, (unsigned char *)textStr, nil);
- SetShapeCommonFont(theText, timesFont);
- GXSetShapeTextSize(theText, ff(30));
- GXMoveShapeTo(theText, ff(10), ff(30));
-
- /* Create an hsv gxColor space */
-
- textColor.space = gxHSVSpace;
- textColor.profile = nil;
- textColor.element.hsv.hue = 0x7400;
- textColor.element.hsv.saturation = 0xFFFF;
- textColor.element.hsv.value = 0xFFFF;
-
- for ( loop = 1; loop < 14; loop++ )
- {
- GXSetShapeColor(theText, &textColor);
- AddToShape(shape, theText);
- if ( loop < 7 )
- GXMoveShape(theText, ff(10), ff(35));
- else
- GXMoveShape(theText, ff(-10), ff(35));
- textColor.element.hsv.hue += 0x0800;
- }
-
- GXDisposeShape(theText);
- }
-
- /* ---------------------------------------------------------------------------
- InsertPage
- This routine is called when a page needs to be added to a document. The
- page is added AFTER the page number passed. If whichPg is greater than
- the last page, the new page is added to the end of the document. If
- whichPg is less than 1, the page is added to the beginning of the
- document. The page number of the new page is returned in whichPg.
- --------------------------------------------------------------------------- */
-
- static OSErr InsertPage(TH_Document document, short *whichPg)
- {
- gxprJobHdl gxprJob = nil;
- gxShape shape = nil;
- TH_Page page;
- short pageCount;
- short aPage;
- long newSize;
- OSErr error = noErr;
-
- pageCount = (*document)->pageCount;
-
- /* Pin the page number to insert after to the range (0, pageCount). */
-
- if ( *whichPg < 1 )
- *whichPg = 0;
- else if ( *whichPg > pageCount )
- *whichPg = pageCount;
-
- /* Create the page gxShape. We set the unique items attribute to make sure
- that each item added to the picture has a unique reference.
- */
- shape = GXNewShape(gxPictureType);
- GXSetShapeViewPorts(shape, 1, &(*document)->viewport);
- GXSetShapeAttributes(shape, GXGetShapeAttributes(shape) | gxUniqueItemsShape);
-
- page = (TH_Page)NewHandleClear(sizeof(T_Page));
-
- if ( page == nil )
- error = MemError();
- else
- {
- newSize = GetHandleSize((Handle)document) + sizeof(T_Page);
- SetHandleSize((Handle)document, newSize);
- error = MemError();
-
- if ( error == noErr )
- {
- (*page)->shape = shape;
- pageCount = ++(*document)->pageCount;
- ++*whichPg;
-
- if ( *whichPg < pageCount && pageCount > 1 )
- for (aPage = pageCount; aPage > *whichPg; aPage--)
- (*document)->pageArray[aPage - 1] = (*document)->pageArray[aPage - 2];
-
- (*document)->pageArray[*whichPg - 1] = page;
- CreateSampleImage(document, *whichPg);
- }
- }
-
- return error;
- }
-
- /* ---------------------------------------------------------------------------
- DisposePage
- This routine is called when a page in a document needs to be disposed of.
- It's smart enough to allow you to delete a page from the middle of the
- document, not just from the end.
- --------------------------------------------------------------------------- */
-
- static void DisposePage(TH_Document document, short whichPg)
- {
- TH_Page page;
- gxShape shape;
- gxprFormatHdl gxprFormat;
- short pageCount;
- short pageIndex;
- long newSize;
-
- if ( whichPg > (*document)->pageCount )
- return; /* ?! There aren't that many pages!! */
- if ( whichPg < 1 )
- return; /* ?! Page numbers start at 1!! */
-
- /* Dispose of this page's shape. */
-
- shape = GetPageShape(document, whichPg);
- if ( shape != nil )
- GXDisposeShape(shape);
-
- /* Dispose of this page's format. */
-
- gxprFormat = GetPageFormat(document, whichPg);
- if ( gxprFormat != nil )
- GXPrDisposeFormat(gxprFormat);
-
- page = GetDocumentPage(document, whichPg);
- if ( page != nil )
- DisposeHandle((Handle)page); /* Dispose of this page's private data. */
-
- pageCount = --(*document)->pageCount; /* Reduce the number of pages in the document. */
-
- /* If the page we deleted was not at the end of the document, we need to move
- all following pages down one. In other words, if page 5 is deleted, page 6
- becomes page 5, page 7 becomes page 6 and so forth. When done, resize the
- handle to the document's info, since we no longer need the room occupied
- by the deleted page's info.
- */
-
- if ( whichPg <= pageCount )
- {
- for ( pageIndex = whichPg; pageIndex <= pageCount + 1; pageIndex++ )
- (*document)->pageArray[pageIndex - 1] = (*document)->pageArray[pageIndex];
-
- newSize = GetHandleSize((Handle)document) - sizeof(T_Page);
- SetHandleSize((Handle)document, newSize);
- }
- }