Demonstration Program
// ��������������������������������������������������������������������������������������
// Printing.h
// ��������������������������������������������������������������������������������������
//
// This program:
//
// � Opens a window in which the contents of the main fields of the TPrint, TPrJob,
// TPrStl and TPrInfo structures are displayed when the user dismisses the style
// dialog box, and in which the first part of a document is displayed when the user
// hits the Print button in the job dialog box.
//
// � Adds a pop-up menu button, three radio buttons, a checkbox, and a group box to the
// job dialog box.
//
// � Allows the user to print a document containing a picture and text, with the text
// being printed in the font and font size, and with the fractional widths setting,
// specified using the items added to the job dialog box.
//
// The program utilises the following resources:
//
// � 'MBAR' resource and associated 'MENU' resources (preload, non-purgeable).
//
// � A 'WIND' resource (purgeable).
//
// � A 'TEXT' resource (non-purgeable) used for printing.
//
// � A 'PICT' resource (non-purgeable) used for printing.
//
// � 'CNTL' resources (purgeable) for controls added to the job dialog box.
//
// � A 'DITL' resource (purgeable) specifying the items to be appended to the job
// dialog box.
//
// � A 'MENU' resource (preload, non-purgeable) for the pop-up menu button.
//
// ��������������������������������������������������������������������������������������
// ............................................................................. includes
#include <Appearance.h>
#include <ControlDefinitions.h>
#include <Devices.h>
#include <Printing.h>
#include <Processes.h>
#include <Resources.h>
#include <ToolUtils.h>
// .............................................................................. defines
#define mApple 128
#define mFile 129
#define iQuit 11
#define iPageSetup 8
#define iPrint 9
#define rMenubar 128
#define rWindow 128
#define rText 128
#define rPicture 128
#define rJobDialogAppendDITL 128
#define iPopupButton 1
#define iRadioButton10pt 2
#define iRadioButton12pt 3
#define iRadioButton14pt 4
#define iCheckboxFracWidths 5
#define kMargin 90
#define MAXLONG 0x7FFFFFFF
#define MIN(a,b) ((a) < (b) ? (a) : (b))
// .................................................................. function prototypes
void main (void);
void doInitManagers (void);
void doEvents (EventRecord *);
void doUpdate (EventRecord *);
void doMenuChoice (long);
void doPrinting (void);
OSErr doCreatePrintRecord (void);
void doPrStyleDialog (void);
SInt16 doCalcNumberOfPages (Rect);
void doDrawPage (Rect,SInt16,SInt16);
SInt16 doGetPageOrientation (void);
Boolean doIsPrGeneralThere (void);
void doPrintRecordsInfo (void);
void doDrawRectStrings (Str255,SInt16,SInt16,Str255,SInt16,SInt16,Str255);
void doDrawPageOrientation (void);
void doErrorAlert (SInt16,Boolean);
void doConcatPStrings (Str255,Str255);
pascal TPPrDlg initialisationFunction (THPrint);
void doAppendTheDITL (TPPrDlg);
pascal void itemEvaluationFunction (TPPrDlg,SInt16);
pascal Boolean eventFilter (DialogPtr,EventRecord *,SInt16 *);
// ��������������������������������������������������������������������������������������
// Printing.c
// ��������������������������������������������������������������������������������������
// ........................... includes
#include "Printing.h"
// ....................... global variables
THPrint gTPrintHdl;
WindowPtr gWindowPtr;
Boolean gDone;
Boolean gPrintStructureInited = false;
Boolean gInhibitPrintStructuresInfo = false;
TEHandle gEditRecHdl;
Handle gTextHdl;
PicHandle gPictureHdl;
SInt16 gFontNumber;
SInt16 gFontSize;
RGBColor gWhiteColour = { 0xFFFF, 0xFFFF, 0xFFFF };
RGBColor gBlackColour = { 0x0000, 0x0000, 0x0000 };
RGBColor gBlueColour = { 0x1818, 0x4B4B, 0x8181 };
extern TPPrDlg gTPrDlgStructurePtr;
extern PDlgInitUPP gInitialisationFunctionUPP;
extern PItemUPP gNewItemEvaluateFunctionUPP;
extern ModalFilterUPP gEventFilterUPP;
// ��������������������������������������������������������������������������������� main
void main(void)
{
Handle menubarHdl;
MenuHandle menuHdl;
EventRecord eventStructure;
Boolean gotEvent;
// ...................... initialise managers
doInitManagers();
// .................... set up menu bar and menus
if(!(menubarHdl = GetNewMBar(rMenubar)))
ExitToShell();
SetMenuBar(menubarHdl);
DrawMenuBar();
if(!(menuHdl = GetMenuHandle(mApple)))
ExitToShell();
else
AppendResMenu(menuHdl,'DRVR');
// ........................ open window
if(!(gWindowPtr = GetNewCWindow(rWindow,NULL,(WindowPtr)-1)))
ExitToShell();
SetPort(gWindowPtr);
TextSize(10);
RGBBackColor(&gBlueColour);
EraseRect(&gWindowPtr->portRect);
// ................. load 'TEXT' and 'PICT' resources
gTextHdl = GetResource('TEXT',rText);
if(gTextHdl == NULL)
ExitToShell();
gPictureHdl = GetPicture(rPicture);
if(gPictureHdl == NULL)
ExitToShell();
// ......................... event loop
gDone = false;
while(!gDone)
{
gotEvent = WaitNextEvent(everyEvent,&eventStructure,MAXLONG,NULL);
if(gotEvent)
doEvents(&eventStructure);
}
}
// ����������������������������������������������������������������������� doInitManagers
void doInitManagers(void)
{
MaxApplZone();
MoreMasters();
InitGraf(&qd.thePort);
InitFonts();
InitWindows();
InitMenus();
TEInit();
InitDialogs(NULL);
InitCursor();
FlushEvents(everyEvent,0);
RegisterAppearanceClient();
}
// ����������������������������������������������������������������������������� doEvents
void doEvents(EventRecord *eventStrucPtr)
{
WindowPtr windowPtr;
SInt16 partCode;
SInt8 charCode;
windowPtr = (WindowPtr) eventStrucPtr->message;
switch(eventStrucPtr->what)
{
case mouseDown:
partCode = FindWindow(eventStrucPtr->where,&windowPtr);
switch(partCode)
{
case inMenuBar:
doMenuChoice(MenuSelect(eventStrucPtr->where));
break;
case inContent:
if(windowPtr != FrontWindow())
SelectWindow(windowPtr);
break;
case inDrag:
DragWindow(windowPtr,eventStrucPtr->where,&qd.screenBits.bounds);
break;
case inGoAway:
if(TrackGoAway(windowPtr,eventStrucPtr->where) == true)
gDone = true;
break;
}
break;
case keyDown:
case autoKey:
charCode = eventStrucPtr->message & charCodeMask;
if((eventStrucPtr->modifiers & cmdKey) != 0)
doMenuChoice(MenuEvent(eventStrucPtr));
break;
case updateEvt:
doUpdate(eventStrucPtr);
break;
case activateEvt:
doPrintRecordsInfo();
break;
}
}
// ����������������������������������������������������������������������������� doUpdate
void doUpdate(EventRecord *eventStrucPtr)
{
WindowPtr windowPtr;
windowPtr = (WindowPtr) eventStrucPtr->message;
BeginUpdate(windowPtr);
doPrintRecordsInfo();
EndUpdate(windowPtr);
}
// ������������������������������������������������������������������������� doMenuChoice
void doMenuChoice(long menuChoice)
{
SInt16 menuID, menuItem;
Str255 itemName;
SInt16 daDriverRefNum;
menuID = HiWord(menuChoice);
menuItem = LoWord(menuChoice);
if(menuID == 0)
return;
switch(menuID)
{
case mApple:
GetMenuItemText(GetMenuHandle(mApple),menuItem,itemName);
daDriverRefNum = OpenDeskAcc(itemName);
break;
case mFile:
if(menuItem == iPageSetup)
{
gInhibitPrintStructuresInfo = false;
doPrStyleDialog();
}
else if(menuItem == iPrint)
doPrinting();
else if(menuItem == iQuit)
gDone = true;
break;
}
HiliteMenu(0);
}
// ��������������������������������������������������������������������������� doPrinting
void doPrinting(void)
{
GrafPtr oldPort;
SInt16 printError;
Boolean userClickedOK;
SInt16 numberOfPages, numberOfCopies;
SInt16 firstPage, lastPage, copy, page;
TPPrPort printPortPtr;
TPrStatus tprStatus;
GetPort(&oldPort);
PrOpen();
if(PrError() == noErr)
{
if(!gPrintStructureInited)
printError = doCreatePrintRecord();
else
printError = noErr;
gTPrDlgStructurePtr = PrJobInit(gTPrintHdl);
printError = PrError();
if(printError == noErr)
{
gInitialisationFunctionUPP = NewPDlgInitProc((ProcPtr) initialisationFunction);
gNewItemEvaluateFunctionUPP = NewPItemProc((ProcPtr) itemEvaluationFunction);
gEventFilterUPP = NewModalFilterProc((ProcPtr) eventFilter);
userClickedOK = PrDlgMain(gTPrintHdl,gInitialisationFunctionUPP);
DisposeRoutineDescriptor(gInitialisationFunctionUPP);
DisposeRoutineDescriptor(gNewItemEvaluateFunctionUPP);
DisposeRoutineDescriptor(gEventFilterUPP);
if(userClickedOK)
{
gInhibitPrintStructuresInfo = true;
numberOfPages = doCalcNumberOfPages((*gTPrintHdl)->prInfo.rPage);
numberOfCopies = (*gTPrintHdl)->prJob.iCopies;
firstPage = (*gTPrintHdl)->prJob.iFstPage;
lastPage = (*gTPrintHdl)->prJob.iLstPage;
(*gTPrintHdl)->prJob.iFstPage = 1;
(*gTPrintHdl)->prJob.iLstPage = iPrPgMax;
if(numberOfPages < lastPage)
lastPage = numberOfPages;
for(copy=1;copy<numberOfCopies+1;copy++)
{
for(page=firstPage;page<lastPage+1;page++)
{
if((page - firstPage) % iPFMaxPgs == 0)
{
if(page != firstPage)
{
PrCloseDoc(printPortPtr);
if(((*gTPrintHdl)->prJob.bJDocLoop == bSpoolLoop) &&
(PrError() == noErr))
PrPicFile(gTPrintHdl,NULL,NULL,NULL,&tprStatus);
}
printPortPtr = PrOpenDoc(gTPrintHdl,NULL,NULL);
}
if(PrError() == noErr)
{
PrOpenPage(printPortPtr,NULL);
if(PrError() == noErr)
doDrawPage((*gTPrintHdl)->prInfo.rPage,page,numberOfPages);
PrClosePage(printPortPtr);
}
}
PrCloseDoc(printPortPtr);
if(((*gTPrintHdl)->prJob.bJDocLoop == bSpoolLoop) && (PrError() == noErr))
PrPicFile(gTPrintHdl,NULL,NULL,NULL,&tprStatus);
}
}
}
}
printError = PrError();
PrClose();
if(printError != noErr && printError != iPrAbort)
doErrorAlert(printError,false);
SetPort(oldPort);
doPrintRecordsInfo();
}
// ������������������������������������������������������������������ doCreatePrintRecord
OSErr doCreatePrintRecord(void)
{
SInt16 printError;
gTPrintHdl = (THPrint) NewHandleClear(sizeof(TPrint));
if(gTPrintHdl != NULL )
{
PrintDefault(gTPrintHdl);
printError = PrError();
if(printError == noErr)
gPrintStructureInited = true;
return(printError);
}
else
ExitToShell();
}
// ���������������������������������������������������������������������� doPrStyleDialog
void doPrStyleDialog(void)
{
SInt16 printError;
PrOpen();
printError = PrError();
if(printError == noErr)
{
if(!gPrintStructureInited)
{
printError = doCreatePrintRecord();
if(printError != noErr)
doErrorAlert(printError,true);
}
PrStlDialog(gTPrintHdl);
}
else
doErrorAlert(printError,false);
PrClose();
}
// ������������������������������������������������������������������ doCalcNumberOfPages
SInt16 doCalcNumberOfPages(Rect pageRect)
{
Rect destRect, pictureRect;
SInt16 heightDestRect, linesPerPage, numberOfPages;
RGBForeColor(&gBlackColour);
RGBBackColor(&gWhiteColour);
EraseRect(&(gWindowPtr->portRect));
SetRect(&destRect,pageRect.left + kMargin,pageRect.top + (kMargin * 1.5),
pageRect.right - kMargin,pageRect.bottom - (kMargin * 1.5));
OffsetRect(&destRect,- (kMargin - 5),- ((kMargin * 1.5) - 5));
TextFont(gFontNumber);
TextSize(gFontSize);
gEditRecHdl = TENew(&destRect,&destRect);
TEInsert(*gTextHdl,GetHandleSize(gTextHdl),gEditRecHdl);
heightDestRect = destRect.bottom - destRect.top;
linesPerPage = heightDestRect / (*gEditRecHdl)->lineHeight;
numberOfPages = ((*gEditRecHdl)->nLines / linesPerPage) + 1;
SetRect(&pictureRect,destRect.left,destRect.top,
destRect.left + ((*gPictureHdl)->picFrame.right - (*gPictureHdl)->picFrame.left),
destRect.top + ((*gPictureHdl)->picFrame.bottom - (*gPictureHdl)->picFrame.top));
DrawPicture(gPictureHdl,&pictureRect);
return(numberOfPages);
}
// ��������������������������������������������������������������������������� doDrawPage
void doDrawPage(Rect pageRect,SInt16 pageNumber,SInt16 numberOfpages)
{
Rect destRect, pictureRect;
SInt16 heightDestRect, linesPerPage, numberOfLines;
TEHandle pageEditRecHdl;
Handle textHdl;
SInt32 startOffset, endOffset;
Str255 theString;
SetRect(&destRect,pageRect.left + kMargin,pageRect.top + (kMargin * 1.5),
pageRect.right - kMargin,pageRect.bottom - (kMargin * 1.5));
heightDestRect = destRect.bottom - destRect.top;
linesPerPage = heightDestRect / (*gEditRecHdl)->lineHeight;
numberOfLines = (*gEditRecHdl)->nLines;
TextFont(gFontNumber);
TextSize(gFontSize);
pageEditRecHdl = TENew(&destRect,&destRect);
textHdl = (*gEditRecHdl)->hText;
startOffset = (*gEditRecHdl)->lineStarts[(pageNumber - 1) * linesPerPage];
if(pageNumber == numberOfpages)
endOffset = (*gEditRecHdl)->lineStarts[numberOfLines];
else
endOffset = (*gEditRecHdl)->lineStarts[pageNumber * linesPerPage];
HLock(textHdl);
TEInsert(*textHdl + startOffset,endOffset - startOffset,pageEditRecHdl);
HUnlock(textHdl);
if(pageNumber == 1)
{
SetRect(&pictureRect,destRect.left,destRect.top,
destRect.left + ((*gPictureHdl)->picFrame.right - (*gPictureHdl)->picFrame.left),
destRect.top + ((*gPictureHdl)->picFrame.bottom - (*gPictureHdl)->picFrame.top));
DrawPicture(gPictureHdl,&pictureRect);
}
MoveTo(destRect.left,pageRect.bottom - 25);
NumToString((SInt32) pageNumber,theString);
DrawString(theString);
}
// ������������������������������������������������������������������ drawPageOrientation
void doDrawPageOrientation(void)
{
SInt16 orientation;
MoveTo(20,260);
DrawString("\pOrientation selected:");
orientation = doGetPageOrientation();
MoveTo(190,260);
if(orientation == 1)
DrawString("\pLandscape");
else if(orientation == 2)
DrawString("\pPortrait");
else
DrawString("\p(PrGeneral not supported by driver)");
}
// ����������������������������������������������������������������� doGetPageOrientation
SInt16 doGetPageOrientation(void)
{
TGetRotnBlk getRotRec;
if(doIsPrGeneralThere)
{
getRotRec.iOpCode = getRotnOp;
getRotRec.hPrint = gTPrintHdl;
PrGeneral((Ptr) &getRotRec);
if((getRotRec.iError == noErr) && (PrError() == noErr) && getRotRec.fLandscape)
return(1);
else
return(2);
}
else
return(3);
}
// ������������������������������������������������������������������� doIsPrGeneralThere
Boolean doIsPrGeneralThere(void)
{
TGetRotnBlk getRotRec;
OSErr printError;
printError = 0;
getRotRec.iOpCode = getRotnOp;
getRotRec.hPrint = gTPrintHdl;
PrGeneral((Ptr) &getRotRec);
printError = PrError();
PrSetError(noErr);
if(printError == resNotFound)
return(false);
else
return(true);
}
// ������������������������������������������������������������������� doPrintRecordsInfo
void doPrintRecordsInfo(void)
{
RGBColor oldForeColour, oldBackColour;
SInt16 fontNum;
Str255 s2, s3;
if(FrontWindow() == gWindowPtr && gPrintStructureInited && !gInhibitPrintStructuresInfo)
{
GetForeColor(&oldForeColour);
GetBackColor(&oldBackColour);
RGBForeColor(&gWhiteColour);
RGBBackColor(&gBlueColour);
EraseRect(&(gWindowPtr->portRect));
GetFNum("\pGeneva",&fontNum);
TextFont(fontNum);
TextSize(10);
MoveTo(20,25);
TextFace(bold);
DrawString("\pFrom TPrint, TPrInfo and TPrStl structures:");
TextFace(normal);
NumToString((long) (*gTPrintHdl)->rPaper.top,s2);
NumToString((long) (*gTPrintHdl)->rPaper.left,s3);
doDrawRectStrings("\pPaper Rectangle (top,left):",20,45,s2,190,45,s3);
NumToString((long) (*gTPrintHdl)->rPaper.bottom,s2);
NumToString((long) (*gTPrintHdl)->rPaper.right,s3);
doDrawRectStrings("\pPaper Rectangle (bottom,right):",20,60,s2,190,60,s3);
NumToString((long) ((*gTPrintHdl)->prInfo.rPage).top,s2);
NumToString((long) ((*gTPrintHdl)->prInfo.rPage).left,s3);
doDrawRectStrings("\pPage Rectangle (top,left):",20,75,s2,190,75,s3);
NumToString((long) ((*gTPrintHdl)->prInfo.rPage).bottom,s2);
NumToString((long) ((*gTPrintHdl)->prInfo.rPage).right,s3);
doDrawRectStrings("\pPage Rectangle (bottom,right):",20,90,s2,190,90,s3);
MoveTo(20,105);
DrawString("\pFeed Type:");
MoveTo(190,105);
if((*gTPrintHdl)->prStl.feed == 0)
DrawString("\pCut sheet");
else if((*gTPrintHdl)->prStl.feed == 1)
DrawString("\pFanfold");
MoveTo(20,120);
DrawString("\pVertical resolution:");
NumToString((long) (*gTPrintHdl)->prInfo.iVRes,s2);
MoveTo(190,120);
DrawString(s2);
MoveTo(20,135);
DrawString("\pHorizontal resolution:");
NumToString((long) (*gTPrintHdl)->prInfo.iHRes,s2);
MoveTo(190,135);
DrawString(s2);
MoveTo(20,155);
TextFace(bold);
DrawString("\pFrom TPrJob structure:");
TextFace(normal);
MoveTo(20,175);
DrawString("\pFirst Page:");
NumToString((long) (*gTPrintHdl)->prJob.iFstPage,s2);
MoveTo(190,175);
DrawString(s2);
MoveTo(20,190);
DrawString("\pLast Page:");
NumToString((long) (*gTPrintHdl)->prJob.iLstPage,s2);
MoveTo(190,190);
DrawString(s2);
MoveTo(20,205);
DrawString("\pNumber of Copies:");
NumToString((long) (*gTPrintHdl)->prJob.iCopies,s2);
MoveTo(190,205);
DrawString(s2);
MoveTo(20,245);
DrawString("\pNote: Some printer drivers always set the iCopies field of the TPrJob");
MoveTo(20,260);
DrawString("\pstructure to 1 and handle multiple copies internally.");
}
RGBForeColor(&oldForeColour);
RGBBackColor(&oldBackColour);
}
// �������������������������������������������������������������������� doDrawRectStrings
void doDrawRectStrings(Str255 s1,SInt16 x1,SInt16 y1,Str255 s2,SInt16 x2,
SInt16 y2,Str255 s3)
{
MoveTo(x1,y1);
DrawString(s1);
MoveTo(x2,y2);
DrawString("\p(");
DrawString(s2);
DrawString("\p,");
DrawString(s3);
DrawString("\p)");
}
// ������������������������������������������������������������������������� doErrorAlert
void doErrorAlert(SInt16 errorType,Boolean fatal)
{
AlertStdAlertParamRec paramRec;
Str255 theString, errorString = "\pPrinting Manager Error ";
SInt16 itemHit;
paramRec.movable = true;
paramRec.helpButton = false;
paramRec.filterProc = NULL;
paramRec.defaultText = (StringPtr) kAlertDefaultOKText;
paramRec.cancelText = NULL;
paramRec.otherText = NULL;
paramRec.defaultButton = kAlertStdAlertOKButton;
paramRec.cancelButton = 0;
paramRec.position = kWindowDefaultPosition;
NumToString((long) errorType,theString);
doConcatPStrings(errorString,theString);
if(!fatal)
StandardAlert(kAlertCautionAlert,errorString,NULL,¶mRec,&itemHit);
else
{
StandardAlert(kAlertStopAlert,errorString,NULL,¶mRec,&itemHit);
ExitToShell();
}
}
// ��������������������������������������������������������������������� doConcatPStrings
void doConcatPStrings(Str255 targetString,Str255 appendString)
{
SInt16 appendLength;
appendLength = MIN(appendString[0],255 - targetString[0]);
if(appendLength > 0)
{
BlockMoveData(appendString+1,targetString+targetString[0]+1,(SInt32) appendLength);
targetString[0] += appendLength;
}
}
// ��������������������������������������������������������������������������������������
// JobDialogAppend.c
// ��������������������������������������������������������������������������������������
// ........................... includes
#include "Printing.h"
// ....................... global variables
TPPrDlg gTPrDlgStructurePtr;
SInt32 gFirstAppendedItemNo;
PDlgInitUPP gInitialisationFunctionUPP;
PItemUPP gOldItemEvaluateFunctionUPP;
PItemUPP gNewItemEvaluateFunctionUPP;
ModalFilterUPP gEventFilterUPP;
extern SInt16 gFontNumber;
extern SInt16 gFontSize;
// ��������������������������������������������������������������� initialisationFunction
pascal TPPrDlg initialisationFunction(THPrint hPrint)
{
ControlHandle controlHdl;
MenuHandle menuHdl;
SInt16 numberOfItems, a, fontNumber;
Str255 fontName;
// ........................ append the DITL
doAppendTheDITL(gTPrDlgStructurePtr);
// ... make pop-up menu WYSIWYG, check second radio button, set fractional widths off
GetDialogItemAsControl((DialogPtr) gTPrDlgStructurePtr,gFirstAppendedItemNo,
&controlHdl);
GetControlData(controlHdl,kControlNoPart,kControlPopupButtonMenuHandleTag,
sizeof(menuHdl),(Ptr) &menuHdl,NULL);
numberOfItems = CountMenuItems(menuHdl);
for(a=1;a<=numberOfItems;a++)
{
GetMenuItemText(menuHdl,a,fontName);
GetFNum(fontName,&fontNumber);
SetMenuItemFontID(menuHdl,a,fontNumber);
}
GetDialogItemAsControl((DialogPtr) gTPrDlgStructurePtr,gFirstAppendedItemNo + 2,
&controlHdl);
SetControlValue(controlHdl,1);
gFontSize = 12;
GetDialogItemAsControl((DialogPtr) gTPrDlgStructurePtr,gFirstAppendedItemNo + 4,
&controlHdl);
SetControlValue(controlHdl,0);
SetFractEnable(false);
// ........ save old evaluation function and assign new evaluation function
gOldItemEvaluateFunctionUPP = gTPrDlgStructurePtr->pItemProc;
gTPrDlgStructurePtr->pItemProc = gNewItemEvaluateFunctionUPP;
// ................. assign new event filter function
gTPrDlgStructurePtr->pFltrProc = gEventFilterUPP;
// ...... PrDlgMain expects a pointer to the modified dialog to be returned
return gTPrDlgStructurePtr;
}
// ���������������������������������������������������������������������� doAppendTheDITL
void doAppendTheDITL(TPPrDlg theDialog)
{
Handle ditlHdl;
SInt16 numberOfExistingItems;
ditlHdl = GetResource('DITL',rJobDialogAppendDITL);
numberOfExistingItems = CountDITL((DialogPtr) theDialog);
AppendDITL((DialogPtr) theDialog,(Handle) ditlHdl,appendDITLBottom);
gFirstAppendedItemNo = numberOfExistingItems + 1;
}
// ��������������������������������������������������������������� itemEvaluationFunction
pascal void itemEvaluationFunction(TPPrDlg theDialog,short itemHit)
{
SInt16 localizedItemNo, controlValue;
ControlHandle controlHdl;
MenuHandle menuHdl;
Str255 itemName;
localizedItemNo = itemHit - gFirstAppendedItemNo + 1;
if(localizedItemNo > 0)
{
if(localizedItemNo == iPopupButton)
{
GetDialogItemAsControl((DialogPtr) theDialog,gFirstAppendedItemNo,&controlHdl);
controlValue = GetControlValue(controlHdl);
GetControlData(controlHdl,kControlNoPart,kControlPopupButtonMenuHandleTag,
sizeof(menuHdl),(Ptr) &menuHdl,NULL);
GetMenuItemText(menuHdl,controlValue,itemName);
GetFNum(itemName,&gFontNumber);
}
else if(localizedItemNo >= iRadioButton10pt &&
localizedItemNo <= iRadioButton14pt)
{
GetDialogItemAsControl((DialogPtr) theDialog,gFirstAppendedItemNo + 1,&controlHdl);
SetControlValue(controlHdl,0);
GetDialogItemAsControl((DialogPtr) theDialog,gFirstAppendedItemNo + 2,&controlHdl);
SetControlValue(controlHdl,0);
GetDialogItemAsControl((DialogPtr) theDialog,gFirstAppendedItemNo + 3,&controlHdl);
SetControlValue(controlHdl,0);
GetDialogItemAsControl((DialogPtr) theDialog,itemHit,&controlHdl);
SetControlValue(controlHdl,1);
if(localizedItemNo == iRadioButton10pt)
gFontSize = 10;
else if(localizedItemNo == iRadioButton12pt)
gFontSize = 12;
else if(localizedItemNo == iRadioButton14pt)
gFontSize = 14;
}
else if(localizedItemNo == iCheckboxFracWidths)
{
GetDialogItemAsControl((DialogPtr) theDialog,gFirstAppendedItemNo +
4,&controlHdl);
SetControlValue(controlHdl,!GetControlValue(controlHdl));
SetFractEnable(GetControlValue(controlHdl));
}
}
else
{
CallPItemProc(gOldItemEvaluateFunctionUPP,(DialogPtr) theDialog,itemHit);
}
}
// �������������������������������������������������������������������������� eventFilter
pascal Boolean eventFilter(DialogPtr dialogPtr,EventRecord *eventStrucPtr,
SInt16 *itemHit)
{
Boolean handledEvent;
GrafPtr oldPort;
handledEvent = false;
if((eventStrucPtr->what == updateEvt) &&
((WindowPtr) eventStrucPtr->message != dialogPtr))
{
doUpdate(eventStrucPtr);
}
else
{
GetPort(&oldPort);
SetPort(dialogPtr);
handledEvent = StdFilterProc(dialogPtr,eventStrucPtr,itemHit);
SetPort(oldPort);
}
return(handledEvent);
}
// ��������������������������������������������������������������������������������������
Demonstration Program Comments
When the program is run, the user should:
* Choose Page Setup... from the File menu, make changes in the style dialog, and
observe the resulting contents of the main fields of the Tprint, TPrJob, TPrStyl,
and TPrInfo structures in the window.
* Choose Print... from the File menu, note the items added to the job dialog box,
select the desired font, font size, and fractional widths setting using these items,
and print the simulated document.
The user should print the simulated document several times using different page size,
scaling, and orientation settings in the style dialog, and occasionally limiting the
printout to one page only by changing the page range settings in the job dialog.
Printing.h
#define
Constants are established for the resource IDs of the 'PICT' and 'TEXT' resources used
for the printing demonstration, and for the 'DITL' resource containing the items to be
appended to the job dialog. Five constants are established for the item numbers of the
items in the 'DITL' resource. kMargin is used to set the margins for the printed page.
Printing.c
Global Variables
gTPrintHdl will be assigned a handle to a TPrint structure. gWindowPtr will be assigned
a pointer to the window. gDone controls the exit from the main loop and thus program
termination.
gPrintRecordInited will be set to true when a TPrint structure has been created and
initialised. gInhibitPrintRecordsInfo is a flag which will prevent the display of
information in the window in certain circumstances. gEditRecHdl will be assigned a
handle to a TextEdit edit structure. gTextHdl will be assigned a handle to the text used
for printing. gPictureHdl will be assigned a handle to the picture used for printing.
gFontNumber will be assigned a font number derived from the font name obtained via
user-selection from the Font pop-up menu appended by the application to the job dialog.
gFontSize will be assigned a font size obtained via user-selection from the appended
radio buttons.
gTPrDlgStructurePtr will be assigned a pointer to a TPrDlg structure. The next four
globals will be assigned universal procedure pointers relating to the initialisation
function, item evaluation function, and event filter function associated with the
appending of items to the job dialog.
main
After the window is opened, GetResource is called to loads the 'TEXT' resource, and
GetPicture is used to load the 'PICT' resource, used in the printing demonstration.
Note that, in this program, error handling of all errors other than Printing Manager
errors is somewhat rudimentary. The program simply exits.
doUpdate
doUpdate calls the application-defined function which draws information in the window.
Note that this function will be called from the application defined event-filter function
for the modified job dialog box.
doMenuChoice
If the user chooses Page Setup... from the File menu, the application-defined function
doPrStyleDialog is called. If the user chooses Print... from the File menu, the
application-defined function doPrinting is called.
doPrinting
doPrinting contains the printing loop. It supports printers using deferred printing.
However, it does not use a saved TPrint structure (but rather creates one for the print
job), and does not use a custom status dialog box and associated idle function. Also, it
does not unload unneeded code segments at the beginning. (Unloading code segments
applies only to 680x0 code. See Chapter 23 - Miscellany.)
The first line saves the pointer to the current graphics port. The call to PrOpen opens
the Printing Manager, together with the current printer driver.
If the global variable gPrintStructureInited indicates that a TPrint structure has not
already been created, the application-defined function doCreatePrintRecord is called to
create and initialise a TPrint structure.
Before the printing loop is entered, and because the application will be modifying the
standard job dialog box, PrJobInit is called to get a pointer to the TPrDlg structure for
the dialog box defined in the resource file for the current printer driver. This pointer
will be used in the initialisation function which appends items to the standard job
dialog.
If no errors have occurred, routine descriptors are created for the functions associated
with the modification of the standard job dialog box, and PrDlgMain is called to display
the dialog. A universal procedure pointer to the initialisation function which appends
items to the standard job dialog is passed in the last parameter of this call. When the
user dismisses the dialog, the routine descriptors are disposed of.
Note that, if an unmodified job dialog is required, the call to PrJobInit, together with
the calls to create and dispose of the routine descriptors, should be deleted. In
addition, the call to PrDlgMain should be replaced by:
userClickedOK = PrJobDialog(gTPrintHdl);
Note also that, when the Print button is hit, PrDlgMain calls PrValidate to ensure that
the contents of the TPrint structure are compatible with the printer driver for the
current printer.
If false is returned by the call to PrDlgMain (that is, the user clicked the Cancel
button), the printing loop is bypassed. Otherwise, the first actions are to call an
application-defined function to calculate the number of pages, and then retrieve the
number of copies, the first page and the last page from the relevant fields of the TPrJob
structure.
Since the only information that should be preserved between separate printings of the
same document is that obtained via the style dialog box, the fields of the TPrJob
structure which store the first and last page numbers are set back to 1 and iPrPgMax
(9999) respectively before proceeding further.
If the last page number specified by the user exceeds the total number of pages in the
document, the variable holding the last page value is set to the actual number of pages.
The copies loop is then entered, followed by the nested pages loop. The maximum number
of pages that can be printed at a time is represented by the constant iPFMaxPgs (128).
The first two lines in the pages loop determine whether this is the first or the 129th
(or 257th, etc.) time around the pages loop. If, for example, it is the 129th (that is,
128 pages have been printed), PrCloseDoc is called to close the printing graphics port
and, if the printer driver is using deferred printing, PrPicFile is called to send the
spool file to the printer. If this is either the first page of all or the first page
after the first 128 (or 257, etc.) have been printed, PrOpenDoc is called to initialise a
new printing graphics port and makes it the current port.
For each page, PrOpenPage re-initialises the printing graphics port, the
application-defined function doDrawPage is called to draw that page's contents in the
printing graphics port, and PrClosePage wraps up the printing of the current page.
When all pages have been printed, PrCloseDoc closes the printing graphics port and, if
the printer driver is using deferred printing, PrPicFile sends the spool file to the
printer.
When all copies have been printed (or if control fell through as a result of an error),
PrClose releases all memory associated with the Printing Manager (except the printer
driver), and the result of the preceding call to PrError is then examined. If an error
occurred, and provided that error was not the error that is reported when the user (or
the application) requests an abort, a Caution alert is displayed advising the user of the
error and error number.
Finally, the saved graphics port is restored.
doCreatePrintRecord
doCreatePrintRecord creates and initialises a TPrint structure.
Memory is allocated by the call to NewHandleClear. If the call to allocate memory is
successful, PrintDefault initialises the TPrint structure to the system standard
settings. If this call is successful, the global variable (gPrintStructureInited) which
indicates whether an initialised TPrint structure exists is set to true. The result of
the PrError call is returned to the calling function.
If the call to allocate memory is not successful, the last line simply closes down the
program.
doPrStyleDialog
doPrStyleDialog is called when the user chooses Page Setup... from the File menu.
The call to PrOpen opens the Printing Manager and printer driver. If the call is
successful, the second if statement determines whether a TPrint structure currently
exists. If not, doCreatePrintRecord is called to create a new TPrint structure. If
doCreatePrintRecord does not return noErr, a Stop alert is invoked.
PrStylDialog opens the style dialog box.
If the call to PrOpen was not successful, a Caution alert is invoked.
PrClose closes the Printing Manager (but not the printer driver), releasing the
associated memory.
doCalcNumberOfPages
doCalcNumberOfPages is called by doPrinting to calculate the number of pages in the
(simulated) document.
The simulated document is provided by a 'TEXT' resource, which will be inserted into a
TextEdit monostyled edit structure. TextEdit is not addressed until Chapter 19 - Text
and TextEdit; however, to facilitate an understanding of what is to follow, it is
sufficient at this stage to understand that a monostyled edit structure contains the
following fields:
destRect The destination rectangle into which text is drawn. The bottom of the
destination rectangle can extend to accommodate the end of the text. In
other words, you can think of the destination rectangle as bottomless.
viewRect The rectangle within which text is actually displayed.
hText A handle to the text.
lineHeight The vertical spacing, in pixels, of the lines of text.
nLines The total number of lines of text.
linestarts An array with a number of elements corresponding to the number of lines
of text. Each element contains the offset of the first character in
each line.
EraseRect erases the window preparatory to the simulated document being drawn in the
window.
The next block establishes a rectangle equal to the received page rectangle less 180
pixels in width and 270 pixels in height. (As will be seen, this is the same size as the
rectangle to be used in the drawing of each page in the printing graphics port.) The
call to OffsetRect simply offsets this rectangle so that, when the document is drawn in
the window, the top and right margins will be reduced to five pixels.
The calls to TextFont and TextSize set the window's font and font size to those
chosen/selected by the user at the pop-up menu and radio buttons added by the application
to the standard job dialog box.
TENew creates a new monostyled edit structure with the previously defined rectangle
passed in both the destination rectangle parameter and the view rectangle parameters.
TEInsert inserts the previously loaded 'TEXT' resource into the edit structure. The
hText field of the edit structure is now a handle to that text. The call to TEInsert
also causes the text to be drawn in the window. (A 'TEXT' resource, rather than a 'TEXT'
file, is used in this demonstration simply to keep that part of the source code that is
not related to printing per se to a minimum.)
The matter of the actual calculation of the number of pages now follows. The first line
in this block gets the height of the previously defined rectangle. The next line
calculates how many lines of text will fit into that height. The third line then
calculates the total number of rectangles (and thus the number of pages) required to
accommodate the whole of the text.
Before the calculated number of pages is returned to the calling function, the previously
loaded picture is drawn at the top of the destination rectangle. This latter is simply
to display the full contents of the top of the simulated document in the window. (Space
for the picture is accounted for by the fact that the first 11 lines in the 'TEXT'
resource are carriage returns.)
The edit structure is retained because it will be used in the following function.
doDrawPage
doDrawPage is called by doPrinting to draw a specified page in the printing graphics
port.
The first block establishes a rectangle equal to the received page rectangle less 180
pixels in width and 270 pixels in height. This smaller rectangle is centred on the page
rectangle both laterally and vertically.
The next block calculates the number of lines of text that will fit into the height of
that rectangle, and gets the total number of lines in the monostyled edit structure
created in the function doCalcNumberOfPages.
The next block sets the printing graphics port's font and font size to the same font and
size used to calculate the number of pages.
TENew creates a new monostyled edit structure with the previously defined rectangle
passed in both the destination rectangle parameter and the view rectangle parameter. The
following line gets a handle to the text in the monostyled edit structure created in the
function doCalcNumberOfPages.
In the next block, the first line gets the starting offset, that is, the offset from the
first character in the block of text to the first character in the first line of text for
the specified page number. The next four lines get the ending offset, that is, the
offset to the last character in the last line of text for the specified page.
Using these offsets, TEInsert then inserts the text for the page into the newly created
edit structure, an action which causes that text to be drawn in the printing graphics
port.
If this is the first page, the next block draws the previously loaded picture at the top
left of the previously defined rectangle.
The last three lines draw the page number at the bottom left of that rectangle.
doDrawPageOrientation
doDrawPageOrientation ascertains the page orientation selected by the user in the style
dialog box and prints it in the window. It gets a value representing the orientation via
a call to the application-defined function doGetPageOrientation.
doGetPageOrientation
doGetPageOrientation uses PrGeneral to establish the page orientation setting to be used
for printing.
A TGetRotnBlk structure is used when PrGeneral is used to determine whether landscape
orientation has been specified.
If the current printer driver supports PrGeneral (determined by the call to
doIsPrGeneralThere), the iopCode field of the TGetRotnBlk structure is assigned the
opcode getRtnOp and the hPrint field is assigned the handle to the TPrintRecord.
PrGeneral is then called with the address of the TGetRotnBlk structure as its argument.
Following the call, the fLandscape field of the TGetRotnBlk structure will contain true
if landscape orientation has been selected. In this case (and assuming no errors), a
value representing landscape orientation is returned to the calling function, otherwise a
value representing portrait orientation is returned.
If the current printer driver does not support PrGeneral, a value representing this
situation is returned.
doIsPrGeneralThere
doIsPrGeneralThere is called by doGetPageOrientation to determine whether the current
printer driver supports PrGeneral. The procedure is similar to that in
doGetPageOrientation, except that here we are interested only in the error code generated
by a call to PrGeneral. If that error is the error represented by the constant
resNotFound (-192), PrGeneral is not supported and false is returned, otherwise true is
returned.
Note that PrSetError is used to set the value in the low-memory global PrintErr to noErr
in case PrGeneral generated an error code other than noErr. PrintErr holds the most
recent Printing Manager error code and, since an actual printing error did not occur, it
is necessary to ensure that PrintErr reflects that fact.
doPrintRecordsInfo and doDrawRectStrings
doPrintRecordsInfo extracts information from the TPrint, TPrInfo, TPrStyl and TPrJob
structures and prints it in the window if a TPrint structure has been initialised and the
global variable gInhibitPrintStructuresInfo contains false. doDrawRectStrings supports
doPrintRecords.
doErrorAlert
doPrintError is called from doPrinting and doPrStyleDialog if an error code is generated
following a call to a Printing Manager function. Depending on the nature of the error,
either a Stop alert or a Caution alert is displayed, each containing the reported error
code. In the case of a Stop alert, the program terminates when the user clicks the OK
button.
JobDialogAppend.c
initialisationFunction
Recall that, in the function doPrinting, a universal procedure pointer to
initialisationFunction was passed in the pDlgInit parameter of the PrDlgMain call.
PrDialogMain thus calls this function to append the DITL to the end of the job dialog's
item list, and to set up the pItemProc (item evaluation) and pFilterProc (event filter
function) fields of the TPrDlg structure.
The DITL to be appended contains the following items:
* A pop-up menu button (AddResMenu variant) for font selection. 'FONT' is the
specified resource type.
* Three radio buttons for font size selection.
* A checkbox for selecting fractional widths on or off.
* A primary group box (text title variant).
At the first line, the application-defined function doAppendTheDITL is called to append
the items. Amongst other things, doAppendTheDITL assigns a value to the global variable
gFirstAppendedItemNo. This value represents the item number in the job dialog's item
list of the first appended item (the pop-up menu button).
The next three blocks make the font pop-up menu WYSIWYG (using essentially the same code
as was used in the demonstration program Menus2) check the second radio button and set
the global variable holding the current font size to 12pt, and uncheck the checkbox and
set fractional widths to off.
The printer driver's item evaluation function will be called upon by the
application-defined item evaluation function to handle mouse-downs in the job dialog's
standard items. Accordingly, the universal procedure pointer in the TPrDlg structure's
pItemProc field is saved for future use. The universal procedure pointer to the
application-defined item evaluation function is then assigned to the pItemProc field.
As is required by PrDlgMain, the last line returns a pointer to the modified TPrDlg
structure.
doAppendTheDITL
doAppendTheDITL is called by initialisationFunction to append the new items to the job
dialog.
GetResource loads the specified 'DITL' resource and gets a handle to it. CountDITL
counts the current number of items in the job dialog. AppendDITL then appends the new
items at the bottom of the dialog, causing the dialog box to expand downwards to
accommodate them.
Note: If the currently chosen printer is the LaserWriter 8 (driver version 8.4 and
later), the result of the AppendDITL call will be somewhat different in that the items
will be added to a pane and the name of the application will be inserted into the menu of
a pop-up group box. (See Fig 5.)
The global variable gFirstAppendedItemNo is then assigned the item number in the new job
dialog item list of the first appended item (the pop-up menu button).
itemEvaluationFunction
itemEvaluationFunction handles item hits in the job dialog. The item number of the item
hit is received in the second parameter.
At the first line, the item number of the item hit is "localised". This means that, for
example, the localised item number of the pop-up menu button will be 1. In other words,
if the localised item number is greater than 0, it will be the item number of one of the
appended items; otherwise, it will be the item number of one of the job dialog's standard
items.
If the localised item number is greater than 0, and if it is the localised item number
for the pop-up menu button, the control's value (that is, the menu item number) is
retrieved. GetMenuItemText is called to get the text of the menu item, and GetFNum is
called to get the font number for this font and assign it to the relevant global
variable.
If the localised item number is the localised item number for one of the radio buttons,
all radio buttons are unchecked, the radio button hit is checked, and the global variable
which holds the current text size is assigned the appropriate value. If the localised
item number is the localised item number for the checkbox, the current value of that
control is flipped and SetFractEnable is called to set fractional widths on or off as
appropriate.
If the localised item number is 0 or less, the item must be one of the job dialog's
standard items. In this case, the printer driver's item evaluation function is called
upon to handle the item hit.
eventFilter
eventFilter is identical to the custom event filter for modal dialogs introduced at
Chapter 8 - Dialogs and Alerts. The use of a the event filter is optional. Its use in
this program simply allows the dialog, together with windows belonging to background
applications, to receive update events.
|