// gui.c // // This file implements a standard user interface using the windows defined in frame.c // // by John D. de Boer #include "common.h" #include "cstring.h" #include "cyber.h" #include "disk.h" #include "frame.h" #include "graph.h" #include "gui.h" extern windprocptr NoWindAdjust; extern comdprocptr NoWindComd; // High-Level Event handlers static voidprocptr LaunchHandler, // QuitHandler; // static docprocptr OpenHandler, // PrintHandler; // static OSErr gotrequiredparams(const AppleEvent *Event) { OSErr err; DescType D; Size S; err=AEGetAttributePtr(Event,keyMissedKeywordAttr,typeWildCard,&D,NULL,0,&S); if (err==errAEDescNotFound) return noErr; return err==noErr ? errAEEventNotHandled : err; } static OSErr installcorehandler(AEEventID ID, AEEventHandlerProcPtr Proc) { return AEInstallEventHandler(kCoreEventClass,ID,NewAEEventHandlerUPP(Proc),0,0); } static pascal OSErr oapphandler(const AppleEvent *Event, AppleEvent *Ret, long REF) { OSErr err; err=gotrequiredparams(Event); if (err) return err; if (LaunchHandler) LaunchHandler(); return noErr; } static pascal OSErr quithandler(const AppleEvent *Event, AppleEvent *Ret, long REF) { OSErr err; err=gotrequiredparams(Event); if (err) return err; if (QuitHandler) QuitHandler(); else quit(); return userCanceledErr; } static pascal OSErr gendochandler(const AppleEvent *Event, docprocptr Proc) { OSErr err; short i; long N,SIZE; FSRef F; AEDescList List; DescType R; AEKeyword Key; err=AEGetParamDesc(Event,keyDirectObject,typeAEList,&List); if (err) return err; err=gotrequiredparams(Event); if (err) return err; err=AECountItems(&List,&N); if (err) return err; if (N<1) return userCanceledErr; for (i=1;i<=N;i++) { err=AEGetNthPtr(&List,i,typeFSRef,&Key,&R,(Ptr)&F,sizeof(FSRef),&SIZE); if (err) return err; if (Proc) Proc(&F); } err=AEDisposeDesc(&List); return noErr; } static pascal OSErr odochandler(const AppleEvent *Event, AppleEvent *Ret, long REF) { return gendochandler(Event,OpenHandler); } static pascal OSErr pdochandler(const AppleEvent *Event, AppleEvent *Ret, long REF) { return gendochandler(Event,PrintHandler); } static void inithighlevel(void) { installcorehandler(kAEOpenApplication,&oapphandler); LaunchHandler=NULL; installcorehandler(kAEQuitApplication,&quithandler); QuitHandler=NULL; installcorehandler(kAEOpenDocuments, &odochandler); OpenHandler=NULL; installcorehandler(kAEPrintDocuments, &pdochandler); PrintHandler=NULL; } // Initialisation static string AppName; // the application's name static comdprocptr Command; // call-back for HI commands static voidprocptr Idle; // call-back for idle processor time static OSStatus commandhandler(EventHandlerCallRef CallRef, EventRef E, void *UserData) { HICommand C; WindowRef WP; window *W; bool res; GetEventParameter(E,kEventParamDirectObject,typeHICommand,NULL,sizeof(HICommand),NULL,&C); WP=FrontNonFloatingWindow(); W=windowfromlist(WP); if (W && W->comd) { res=W->comd(W,C.commandID); return res ? noErr : eventNotHandledErr; } else if (NoWindComd) { res=NoWindComd(NULL,C.commandID); return res ? noErr : eventNotHandledErr; } return eventNotHandledErr; } static OSStatus menuadjuster(EventHandlerCallRef CallRef, EventRef E, void *UserData) { window *W; W=frontmost(); if (W && W->adjust) W->adjust(W); if (!W && NoWindAdjust) NoWindAdjust(NULL); return eventNotHandledErr; } static void setaboutitemname(void) { OSStatus err; MenuRef Menu; MenuItemIndex ITEM; string S; Str255 P; err=GetIndMenuItemWithCommandID(NULL,'quit',1,&Menu,&ITEM); if (!Menu) return; S=cat3(0,"About ",AppName,"..."); pascalstring(S,P); old(S); err=InsertMenuItemText(Menu,P,0); if (!err) err=SetMenuItemCommandID(Menu,1,'abou'); } void initreferenceframe(const char *ApplicationName) { EventTypeSpec ET; OSStatus err; initframe(); inithighlevel(); AppName=copyof(ApplicationName); ET.eventClass=kEventClassCommand; ET.eventKind=kEventCommandProcess; err=InstallApplicationEventHandler(NewEventHandlerUPP(&commandhandler),1,&ET,NULL,NULL); ET.eventClass=kEventClassMenu; ET.eventKind=kEventMenuBeginTracking; err=InstallApplicationEventHandler(NewEventHandlerUPP(&menuadjuster),1,&ET,NULL,NULL); setaboutitemname(); } // Installation of call-back routines for non-window events void installcore(voidprocptr P1, voidprocptr P2, docprocptr P3, docprocptr P4) { LaunchHandler=P1; QuitHandler=P2; OpenHandler=P3; PrintHandler=P4; } void installcommand(comdprocptr Proc) { Command=Proc; } static void EventLoopIdleProc(EventLoopTimerRef inTimer, void *inUserData) { UInt32 n; EventQueueRef Queue; Queue=GetCurrentEventQueue(); if (!Queue) return; n=GetNumEventsInQueue(Queue); if (n>0) return; Idle(); } void installidle(voidprocptr Proc) { EventLoopRef loop; EventLoopTimerUPP upp; EventLoopTimerRef timer; Idle=Proc; loop=GetMainEventLoop(); upp=NewEventLoopTimerUPP(EventLoopIdleProc); InstallEventLoopTimer(loop,0.5 * kEventDurationSecond,10.0 * kEventDurationMillisecond,upp,NULL,&timer); } // Menu routines Handle nibmenu(char *FN, char *M) { OSStatus err; IBNibRef Nib; Handle H; if (!FN || !M) return NULL; err=CreateNibReference(macstring(FN),&Nib); if (err) halt(cat(0,"couldn't find nib file: ",FN)); err=CreateMenuBarFromNib(Nib,macstring(M),&H); if (err) halt(cat(0,"couldn't find nib-based menu: ",M)); DisposeNibReference(Nib); return H; } void addmenuitems(MenuRef M, string S) { Str255 PS; if (!M || !S) return; pascalstring(S,PS); AppendMenu(M,PS); } string menuitemstring(MenuRef M, int ITEM) { Str255 PS; if (!M) return NULL; GetMenuItemText(M,ITEM,PS); return cstring(PS); } void setsubmenu(MenuRef M, int ITEM, int SUBMENU) { if (!M) return; SetItemCmd(M,ITEM,0x1B); SetItemMark(M,ITEM,SUBMENU); } void menuenable(MenuRef M, bool Enable) { if (!M) return; if (Enable) EnableMenuItem(M,0); else DisableMenuItem(M,0); } void itemenable(MenuRef M, int ITEM, bool Enable) { if (!M) return; if (Enable) EnableMenuItem(M,ITEM); else DisableMenuItem(M,ITEM); } void allowitem(window *W, UInt32 Command, bool Enable) { OSStatus err; MenuRef Menu; MenuItemIndex ITEM; err=GetIndMenuItemWithCommandID(NULL,Command,1,&Menu,&ITEM); if (err) return; if (Enable) EnableMenuItem(Menu,ITEM); else DisableMenuItem(Menu,ITEM); } void checkitem(window *W, UInt32 Command, bool Check) { OSStatus err; MenuRef Menu; MenuItemIndex ITEM; err=GetIndMenuItemWithCommandID(NULL,Command,1,&Menu,&ITEM); if (err) return; CheckMenuItem(Menu,ITEM,Check); } void setitemtext(window *W, UInt32 Command, char *S) { OSStatus err; MenuRef Menu; MenuItemIndex ITEM; Str255 PS; err=GetIndMenuItemWithCommandID(NULL,Command,1,&Menu,&ITEM); if (err) return; pascalstring(S,PS); SetMenuItemText(Menu,ITEM,PS); } // Saving PDF files bool RecordingPicture=0; // set during a PDF save in case the application level wants to draw differently, // e.g. not highlighting GUI selection. void savepdf(window *W, const char *Name, bool Full) { bool Ok; file F; CFURLRef URL; CGContextRef Save,Context; rect SP,R; if (!W) return; Ok=saveas("Save PDF File As",Name,'****','****',&F); // '*PDF'? if (!Ok) return; URL=CFURLCreateFromFSRef(NULL,F.repl ? &(F.temp) : &(F.fsref)); if (!URL) return; if (Full && W->pdfsize) W->pdfsize(W,&R); else R=W->page; Context=CGPDFContextCreateWithURL(URL,&R,NULL); CFRelease(URL); if (!Context) return; CGContextBeginPage(Context,&R); initquartzcontext(Context,W->cs); Save=W->q2d; W->q2d=Context; SP=W->page; W->page=R; RecordingPicture=1; if (Full && W->drawpdf) W->drawpdf(W); else if (W->draw) W->draw(W); W->q2d=Save; W->page=SP; RecordingPicture=0; CGContextEndPage(Context); CGContextRelease(Context); closefile(&F); } // Printing PMPageFormat PageFormat; // page set-up information; should ideally be saved in preferences static PMSheetDoneUPP SetUpCompletion, // completion of "Page Setup..." sheet dialog PrintCompletion; // completion of "Print..." sheet dialog // The "Page Setup..." dialog static pascal void setupcompletion(PMPrintSession Session, WindowRef WP, Boolean Accepted) { window *W; OSStatus err; if (!WP) return; W=windowfromlist(WP); if (!W) return; err=PMRelease(Session); } void pagesetup(window *W) { OSStatus err; PMPrintSession Session; Boolean Res; if (!W || !W->wmw) return; err=PMCreateSession(&Session); if (err) return; err=PMSessionValidatePageFormat(Session,PageFormat,&Res); if (err) return; err=PMSessionUseSheets(Session,W->wmw,SetUpCompletion); if (err) return; err=PMSessionPageSetupDialog(Session,PageFormat,&Res); } // The "Print..." dialog static bool pagerect(rect *R) { OSStatus err; PMRect Paper,Page; if (!R) return 0; err=PMGetAdjustedPaperRect(PageFormat,&Paper); if (err) return 0; err=PMGetAdjustedPageRect(PageFormat,&Page); if (err) return 0; setrect(R,Page.left - Paper.left,Paper.bottom - Page.bottom,Page.right - Page.left,Page.bottom - Page.top); return 1; } static int totalpages(window *W) { rect R; if (!W || !W->numpages) return 1; if (!pagerect(&R)) return 1; return W->numpages(W,R); } /* static void testmargins(window *W) { int i; if (!W) return; penindex(W,robinsegg); beginpath(W); for (i=-500;i<1500;i+=50) if (i) { moveto(W,i,-500); lineto(W,i,1500); } for (i=-500;i<1500;i+=50) if (i) { moveto(W,-500,i); lineto(W,1500,i); } stroke(W); penindex(W,palerose); beginpath(W); moveto(W,0,-500); lineto(W,0,1500); moveto(W,-500,0); lineto(W,1500,0); stroke(W); }*/ static void docsthingy(PMPrintSession Session) { // required to support 10.3 OSStatus err; CFStringRef strings[1]; CFArrayRef Array; if (!Session) return; strings[0]=kPMGraphicsContextCoreGraphics; Array=CFArrayCreate(kCFAllocatorDefault,(const void **)strings,1,&kCFTypeArrayCallBacks); if (!Array) { error("docsthingy() error #1"); return; } if (Array != NULL) { err=PMSessionSetDocumentFormatGeneration(Session,kPMDocumentFormatPDF,Array,NULL); CFRelease(Array); } } static void printjob(window *W, PMPrintSession Session, PMPageFormat Format) { OSStatus err; UInt32 FIRST,LAST,TOTAL,p; CGContextRef Save,Context; rect SP,Page; if (!W || !W->settings || !W->print) return; TOTAL=totalpages(W); err=PMGetFirstPage(W->settings,&FIRST); err=PMGetLastPage(W->settings,&LAST); LAST=lsr(LAST,TOTAL); docsthingy(Session); // 10.3 err=PMSessionBeginDocument(Session,W->settings,Format); // 10.3 //err=PMSessionBeginCGDocument(Session,W->settings,Format); // 10.4 only if (err) return; for (p=FIRST;p<=LAST;p++) { err=PMSessionError(Session); if (err) break; err=PMSessionBeginPage(Session,Format,NULL); if (err) break; Context=NULL; err=PMSessionGetGraphicsContext(Session,NULL,(void **)&Context); // 10.3 //err=PMSessionGetCGGraphicsContext(Session,&Context); // 10.4 only if (err) { err=PMSessionEndPage(Session); break; } initquartzcontext(Context,W->cs); if (!pagerect(&Page)) { err=PMSessionEndPage(Session); break; } SP=W->page; Save=W->q2d; W->page=Page; W->q2d=Context; W->printing=1; CGContextClipToRect(Context,Page); //testmargins(W); W->print(W,p - 1); W->printing=0; W->page=SP; W->q2d=Save; err=PMSessionEndPage(Session); if (err) break; } // next p err=PMSessionEndDocument(Session); if (err) return; err=PMSessionError(Session); if (err) return; } static pascal void printcompletion(PMPrintSession Session, WindowRef WP, Boolean Accepted) { window *W; OSStatus err; if (!WP) return; W=windowfromlist(WP); if (!W) return; if (Accepted) printjob(W,Session,PageFormat); err=PMRelease(W->settings); W->settings=NULL; err=PMRelease(Session); } void printwindow(window *W) { OSStatus err; PMPrintSession Session; CFStringRef Title; int PAGES; Boolean Res; if (!W || !W->wmw) return; if (W->settings) { err=PMRelease(W->settings); W->settings=NULL; } err=PMCreateSession(&Session); if (err) return; err=PMSessionValidatePageFormat(Session,PageFormat,&Res); if (err) return; err=PMCreatePrintSettings(&(W->settings)); if (err) return; err=PMSessionDefaultPrintSettings(Session,W->settings); if (err) return; err=CopyWindowTitleAsCFString(W->wmw,&Title); if (err==noErr) { err=PMSetJobNameCFString(W->settings,Title); /*CFRelease(Title);*/ } PAGES=totalpages(W); err=PMSetPageRange(W->settings,1,PAGES); if (err) return; err=PMSessionUseSheets(Session,W->wmw,PrintCompletion); if (err) return; err=PMSessionPrintDialog(Session,W->settings,PageFormat,&Res); } // Initialising printing void initprint(void) { OSStatus err; PMPrintSession Session; SetUpCompletion=NewPMSheetDoneUPP(&setupcompletion); PrintCompletion=NewPMSheetDoneUPP(&printcompletion); err=PMCreatePageFormat(&PageFormat); if (err) return; err=PMCreateSession(&Session); if (!err) { err=PMSessionDefaultPageFormat(Session,PageFormat); if (err) return; err=PMRelease(Session); } }