/* PDlog Expand.c	Derived from TN #95.Dave Hersey, Apple Developer Technical Support.  10/9/91É	v1.0  2/25/92É  v1.0.1 --> fixed lack of print handle tossing and added something to print.       <dmh>  9/29/93É  v1.0.2 --> fixed bug in Append_DITL (also in TN #95) which appends 2 extra bytes. <dmh>Think C 5.0.3 source.   NOTE: Apple reserves the top half of the screen (where the current DITL   items are located). Applications may use the bottom half of the screen to   add items, but should not change any items in the top half of the screen.   An application should expand the print dialogs only as much as is   absolutely necessary.   A global search and replace of 'Job' with 'Stl' will produce code that   modifies the style dialog.*/#include <PrintTraps.h>static TPPrDlg PrtJobDialog;        /* pointer to job dialog *//* This points to the following structure:    struct {         DialogRecord  Dlg;        (The Dialog window)        ProcPtr       pFltrProc;  (The Filter Proc.)        ProcPtr       pItemProc;  (The Item evaluating proc - we'll change this)        THPrint       hPrintUsr;  (The user's print record.)        Boolean       fDoIt;            Boolean       fDone;                (Four longs -- reserved by Apple Computer)        long          lUser1;                 long          lUser2;                long          lUser3;            long          lUser4;        } TPrDlg; *TPPrDlg;          *//* Declare ÔpascalÕ functions and procedures */extern int		Append_DITL(TPPrDlg, int);			/* Our AppendDITL function.			*/extern pascal	TPPrDlg MyJobDlgInit(THPrint);		/* Our extention to PrJobInit.		*/extern pascal	void MyJobItems(TPPrDlg, short);	/* Our modal item handler.			*/extern OSErr	Print(void);#define MyDITL 256  /* resource ID of my DITL to be spliced onto job dialog */THPrint hPrintRec;          /* handle to print record */long prFirstItem;           /* save our first item here */long prPItemProc;           /* we need to store the old itemProc here *//*-----------------------------------------------------------------------*/    WindowPtr   MyWindow;    OSErr       err;    Str255      myStr;typedef    struct dialog_item_struct    {        Handle  handle;     /* handle or procedure pointer for this item */        Rect    bounds;     /* display rectangle for this item */        char    type;       /* item type - 1 */        char    data[1];    /* length byte of data */    }    DialogItem, *DialogItemPtr, **DialogItemHandle; typedef    struct append_item_list_struct    {        int           max_index; /* number of items - 1 */        DialogItem    items[1]; /* first item in the array */    }    ItemList, *ItemListPtr, **ItemListHandle; typedef    union signed_byte_union    {        int        integer;        char    bytes[2];    }    ByteAccess;  /*    This routine appends all of the items of a specified DITL    *//*    onto the end of a specified DLOG Ñ We donÕt even need to know the format	*//*    of the DLOG    */ /*    this will be done in 3 steps:    *//*     1. append the items of the specified DITL onto the existing DLOG    *//*     2. expand the original dialog window as required    *//*     3. return the adjusted number of the first new user item    */  int Append_DITL(TPPrDlg dialog, int item_list_ID){    Point         	offset;    Rect            max_rect;    ItemListHandle 	append_item_list;    /* handle to DITL being appended */    DialogItemPtr 	item;                /* pointer to item being appended */    ItemListHandle	dlg_item_list;        /* handle to DLOG's item list */    int           	first_item;    int            	new_items, data_size, i;    ByteAccess    	usb;    OSErr          	err; /*    Using the original DLOG     1. Remember the original window Size.    2. Set the offset Point to be the bottom of the original window.    3. Subtract 5 pixels from bottom and right, to be added       back later after we have possibly expanded window.    4. Get working Handle to original item list.    5. Calculate our first item number to be returned to caller.    6. Get locked Handle to DITL to be appended.    7. Calculate count of new items.*/     if (dialog == NULL) ExitToShell();     max_rect = ((DialogPeek)dialog)->window.port.portRect;    offset.v = max_rect.bottom;    offset.h = 0;    max_rect.bottom -= 5;    max_rect.right -= 5;     dlg_item_list = (ItemListHandle)((DialogPeek)dialog)->items;    first_item = (**dlg_item_list).max_index + 2;     append_item_list = (ItemListHandle)GetResource('DITL', item_list_ID);    if ( append_item_list == NULL )        return first_item;     HLock((Handle)append_item_list);    new_items = (**append_item_list).max_index + 1; /*     For each item,      1. Offset the rectangle to follow the original window.      2. Make the original window larger if necessary.      3. fill in item handle according to type.*/     item = (**append_item_list).items;    for ( i = 0; i < new_items; i++ )    {        OffsetRect(&item->bounds, offset.h, offset.v);        UnionRect(&item->bounds, &max_rect, &max_rect);        usb.integer = 0;        usb.bytes[1] = item->data[0];         switch ( item->type & 0x7F )        {            case ctrlItem + btnCtrl :            case ctrlItem + chkCtrl :            case ctrlItem + radCtrl :                item->handle = (Handle)NewControl((DialogPtr) dialog,                                                  &item->bounds,                                                  (StringPtr)item->data,                                                  TRUE,                                                  0, 0, 1,                                                  item->type & 0x03,                                                  0);            break;             case ctrlItem + resCtrl :            {                item->handle = (Handle)GetNewControl(*(int*)(item->data + 1), (DialogPtr) dialog);                (**(ControlHandle)item->handle).contrlRect = item->bounds;            }            break;            case statText :            case editText :                err = PtrToHand(item->data + 1, &item->handle, usb.integer);            break;            case iconItem :                item->handle = GetIcon(*(int*)(item->data + 1));            break;             case picItem :                item->handle = (Handle)GetPicture(*(int*)(item->data + 1));            break;             default :                item->handle = NULL;        }         data_size = (usb.integer + 1) & 0xFFFE;        item = (DialogItemPtr)((char*)item + data_size + sizeof(DialogItem));    }  // We need to subtract the short below because otherwise the size of the DITL count // gets factored in twice, and the resulting DTIL has two bytes of garbage appended // to it.  This is a problem with the original TN#95 code as well.     err = PtrAndHand((**append_item_list).items,                     (Handle)dlg_item_list,                     GetHandleSize((Handle) append_item_list)                     - sizeof(short));    (**dlg_item_list).max_index += new_items;    HUnlock((Handle) append_item_list);    ReleaseResource((Handle) append_item_list);     max_rect.bottom += 5;    max_rect.right += 5;    SizeWindow((WindowPtr) dialog, max_rect.right, max_rect.bottom, TRUE);     return first_item;}/*------------------------------------------------------------------------*/OSErr Print(){    TPPrPort	pPrPort;    Rect		aRect;    TPrStatus	theStatus;            /* call PrJobInit to get pointer to the invisible job dialog */    hPrintRec = (THPrint)(NewHandle(sizeof(TPrint)));    PrintDefault(hPrintRec);    PrValidate(hPrintRec);    if (PrError() != noErr)        return PrError();            PrtJobDialog = PrJobInit(hPrintRec);           if (PrError() != noErr)        return PrError();            if (!PrDlgMain(hPrintRec, (ProcPtr) &MyJobDlgInit)) /* this line does all the stuff */        return iPrAbort;    if (PrError() != noErr)        return PrError();            pPrPort = PrOpenDoc(hPrintRec, NULL, NULL);    PrOpenPage(pPrPort, NULL);        aRect = (*hPrintRec)->prInfo.rPage;    InsetRect(&aRect, 20, 20);    PenSize(4, 4);    FrameRect(&aRect);        PrClosePage(pPrPort);    PrCloseDoc(pPrPort);	if (!PrError() && (*hPrintRec)->prJob.bJDocLoop == bSpoolLoop)		PrPicFile(hPrintRec, NULL, NULL, NULL, &theStatus);/* that's all for now */        	if (hPrintRec) DisposeHandle((Handle) hPrintRec);        } /* Print *//*------------------------------------------------------------------------*/pascal TPPrDlg MyJobDlgInit (hPrint)THPrint hPrint;/*   this routine appends items to the standard job dialog and sets up the   user fields of the printing dialog record TPRDlg   This routine will be called by PrDlgMain*/{    short      firstItem;    /* first new item number */        short      itemType, item;    Handle     itemH;    Rect       itemBox;        firstItem = Append_DITL(PrtJobDialog, MyDITL); /*call routine to do this */        prFirstItem = firstItem; /* save this so MyJobItems can find it *//* now we'll set up our DITL items -- The radio buttons */        for (item = 5; item <= 7; item++)    {    	GetDItem((DialogPtr) PrtJobDialog,firstItem + item -1,&itemType,&itemH,&itemBox);    	SetCtlValue((ControlHandle) itemH, (item == 5));    }    /* now we'll set up the second of our DITL items  -- The checkbox */    GetDItem((DialogPtr) PrtJobDialog,firstItem +2,&itemType,&itemH,&itemBox);    SetCtlValue((ControlHandle) itemH,1);/*   Now comes the part where we patch in our item handler.  We have to save   the old item handler address, so we can call it if one of the standard   items is hit, and put our item handler's address in pItemProc field of   the TPrDlg struct*/    prPItemProc = (long)PrtJobDialog->pItemProc;    /* Now we'll tell the modal item handler where our routine is */    PrtJobDialog->pItemProc = (ProcPtr)&MyJobItems;    /* PrDlgMain expects a pointer to the modified dialog to be returned...*/    return PrtJobDialog;    } /*myJobDlgInit*//*-----------------------------------------------------------------------*//* here's the analogue to the SF dialog hook */pascal void MyJobItems(theDialog,itemNo)TPPrDlg     theDialog;short       itemNo;{ /* MyJobItems */    short   myItem;    short   firstItem, item, itemType, theValue;    Handle  itemH;    Rect    itemBox;        firstItem = prFirstItem;      /* remember, we saved this in myJobDlgInit */    myItem = itemNo-firstItem+1;  /* "localize" current item No */    if (myItem > 0)               /* if localized item > 0, it's one of ours */    {        /* find out which of our items was hit */        switch (myItem)        {            case 1:			/*	Static text.	*/                break;            case 2:			/*	Edit text.		*/                break;            case 3:			/*	Check box.		*/       				GetDItem((DialogPtr) theDialog,firstItem +2,&itemType,&itemH,&itemBox); 					theValue = GetCtlValue((ControlHandle) itemH); 					SetCtlValue((ControlHandle) itemH, theValue != 1);                break;            case 4:			/*	Push button.	*/                break;            case 5:			/*	Radio buttons	*/            case 6:            case 7:       			for (item = 5; item <= 7; item++)       			{       				GetDItem((DialogPtr) theDialog,firstItem +item -1,&itemType,&itemH,&itemBox); 					SetCtlValue((ControlHandle) itemH, item == myItem);       			}                break;            case 8:			/*	Edit text.		*/                break;            default: Debugger(); /* OH OH */            } /* switch */    } /* if (myItem > 0) */    else /* chain to standard item handler, whose address is saved in               prPItemProc */    {		((pascal void (*) (TPPrDlg, short)) (Ptr) prPItemProc) (theDialog, itemNo);    }} /* MyJobItems */main(){        Rect        myWRect;        InitGraf(&thePort);    InitFonts();    InitWindows();    InitMenus();    InitDialogs(nil);    InitCursor();    SetRect(&myWRect,50,260,350,340);        /* call the routine that does printing */    PrOpen();    err = Print();        PrClose();} /* main */