home *** CD-ROM | disk | FTP | other *** search
/ Developer CD Series 1998 November: Tool Chest / Dev.CD Nov 98 TC.toast / Sample Code / Snippets / Toolbox / GridWindowGrow / Source / GrowToGrid.c
Encoding:
C/C++ Source or Header  |  1996-09-17  |  27.1 KB  |  819 lines  |  [TEXT/CWIE]

  1. //problem: main window doesn't appear!
  2.  
  3. /* simple example of creating a gridded window grow routine */
  4. /* to allow you to only let someone grow a window in increments */
  5. /* of 20 pixels, for example */
  6.  
  7. /* Look at the routine  MyGrowWindow  for the how-to*/
  8. /* C.K. Haun */
  9. /* Apple DTS */
  10. /* 8/4/94 */
  11. #include <quickdraw.h>
  12. #include <Types.h>
  13. #include <memory.h>
  14. #include <Packages.h>
  15. #include <Errors.h>
  16. #include <fonts.h>
  17. #include <dialogs.h>
  18. #include <windows.h>
  19. #include <menus.h>
  20. #include <events.h>
  21. #include <OSEvents.h>
  22. #include <Desk.h>
  23. #include <diskinit.h>
  24. #include <OSUtils.h>
  25. #include <resources.h>
  26. #include <toolutils.h>
  27. #include <AppleEvents.h>
  28. #include <EPPC.h>
  29. #include <GestaltEqu.h>
  30. #include <PPCToolbox.h> 
  31. #include <Processes.h>
  32. #include <Balloons.h>
  33. #include <Aliases.h>
  34. #include <Aliases.h>
  35. #include <SegLoad.h>
  36. #include <TextUtils.h>
  37.  
  38. #define kExtremeNeg -32768
  39. #define kExtremePos (32767 - 1) /* required to address an old region bug, see develop 20 Q&As */
  40.  
  41. /* prototypes */
  42. void    DrawIndString(short resID,short index);
  43. void MyGrowWindow(WindowPtr theWindow);
  44. void InitalizeApp(void);
  45. void DoDiskEvents(long dinfo);                              /* hi word is error code, lo word is drive number */
  46. void DrawMain(WindowPtr drawIt);
  47. Boolean DoSelected(long val);
  48. void SizeMain(WindowPtr theWindow);
  49. void InitAEStuff(void);
  50. void DoHighLevel(EventRecord *AERecord);
  51. void DoDaCall(MenuHandle themenu, long theit);
  52. void DoDocumentClick(WindowPtr theWindow);
  53. void DoGridDialog(void);
  54. ControlHandle SnatchHandle(DialogPtr thebox, short theGetItem);
  55. pascal OSErr AEOpenHandler(const AppleEvent *messagein, AppleEvent *reply, long refIn);
  56. pascal OSErr AEOpenDocHandler(const AppleEvent *messagein, AppleEvent *reply, long refIn);
  57. pascal OSErr AEPrintHandler(const AppleEvent *messagein, AppleEvent *reply, long refIn);
  58. pascal OSErr AEQuitHandler(const AppleEvent *messagein, AppleEvent *reply, long refIn);
  59. void SampleHelpDialog(void);
  60. WindowPtr AddNewWindow(short theID);
  61. WindowPtr FindWindowByKind(short kindToFind);
  62. void PullRect (Rect    *someRect);
  63.  
  64. void NilProc(void);
  65.  
  66. /* one external */
  67. #ifdef applec
  68.     extern void _DataInit();                                    /* this is the C initialization code */
  69. #endif
  70.  
  71. /* defines and enums */
  72. /* windows */
  73. enum  {
  74.     kDocumentWindow = 1000, kDocWindow = 128
  75. };
  76. /* menu enums */
  77. enum  {
  78.     kMBarID = 128, kAppleMenu = 128, kFileMenu = 129, kEditMenu = 130, kToolsMenu = 131
  79. };
  80. enum  {
  81.     kResumeMask = 1,                                        /* bit of message field for resume vs. suspend */
  82.     kHelpString = 128
  83. };
  84. /* file menu enums */
  85. enum  {
  86.     kNewItem = 1, kOpenItem, kCloseItem, kSaveItem, kSaveAsItem, kFileBlank1, kPageSetupItem, kPrintItem, kFileBlank2, kQuitItem
  87. };
  88.  
  89. enum  {
  90.     kGridDialogItem = 1
  91. };
  92.  
  93. /* alerts and dialogs */
  94.  
  95. enum  {
  96.     kBadSystem = 130, kSampHelp = 129, kAboutBox = 128, kGridDialog = 131
  97. };
  98.  
  99. enum  {
  100.     kGridDialogMenuItem = 1, kGridEditLine = 4
  101. };
  102.  
  103. enum  {
  104.     kMinHeight = 200
  105. };
  106.  
  107. enum {kGenStrings = 128,kSayCurrentGrid=1,kSayChangeGrid
  108. };
  109.  
  110. #define ABS(A) ((A < 0) ? (A*-1):A)
  111.  
  112. /* structs */
  113. struct AEinstalls {
  114.     AEEventClass            theClass;
  115.     AEEventID                theEvent;
  116.     AEEventHandlerProcPtr    theProc;
  117. };
  118. typedef struct AEinstalls AEinstalls;
  119.  
  120.  
  121. /* windowControl is the structure attached to every window I create (in the refCon */
  122. /* field) that contains all the information I need to know about the window. */
  123. /* this one is really simple */
  124. struct windowControl {
  125.     unsigned long windowID;                                 /* master ID number for section recording */
  126.     ProcPtr drawMe;                                         /* content drawing procedure pointer */
  127.     ProcPtr clickMe;                                        /* content click routine */
  128.     ProcPtr saveMe;                                         /* document save procedure pointer */
  129.     ProcPtr closeMe;                                        /* document close procedure pointer */
  130.     ProcPtr sizeMe;
  131.     AliasHandle fileAliasHandle;                            /* alias for this document */
  132.     Boolean windowDirty;
  133.     long windowIndex;                                       /* for AppleEvent information */
  134.     
  135. };
  136. typedef struct windowControl windowControl, *windowCPtr, **windowCHandle;
  137.  
  138. /* globals */
  139. Boolean gQuit, gInBackground;
  140. Boolean dragIn;
  141. EventRecord gERecord;
  142. ProcessSerialNumber gOurSN;
  143. short gHelpItem;
  144. short gGridIncrement = 30;                                  // start at 30
  145.  
  146. #pragma segment Main
  147. void main()
  148. {
  149.     
  150.     WindowPtr twindow;
  151.     short fHit;
  152.     windowCHandle tempWCH;
  153.         
  154.     #ifdef applec    
  155.         UnloadSeg((Ptr)_DataInit);                              /* throw out C setup code */
  156.     #endif
  157.     
  158.     InitalizeApp();
  159.     UnloadSeg((Ptr)InitalizeApp);                           /* get rid of my initialization code */
  160.     /* start running */
  161.     do {
  162.     
  163.         WaitNextEvent(everyEvent, &gERecord, 30, nil);
  164.     
  165.         switch (gERecord.what) {
  166.  
  167.             case nullEvent:
  168.                 /* no nul processing in this sample */
  169.                 break;
  170.  
  171.             case updateEvt:
  172.                 /* at update, draw the window */
  173.                 tempWCH = (windowCHandle)GetWRefCon((WindowPtr)gERecord.message);
  174.                     (ProcPtr)((*tempWCH)->drawMe)((WindowPtr)gERecord.message);
  175.                 
  176.                 break;
  177.                 
  178.             case mouseDown:
  179.                 /* first see where the hit was */
  180.                 fHit = FindWindow(gERecord.where, &twindow);
  181.                 
  182.                 switch (fHit) {
  183.  
  184.                     case inDesk:                            /* if they hit in desk, then the process manager */
  185.                         break;                              /* will switch us out, we don't need to do anything */
  186.  
  187.                     case inMenuBar:
  188.                         DoSelected(MenuSelect(gERecord.where));
  189.                         break;
  190.                         
  191.                     case inSysWindow:
  192.                         /* pass to the system */
  193.                         SystemClick(&gERecord, twindow);
  194.                         break;
  195.  
  196.                     case inContent:
  197.                         /* Handle content and control clicks here */
  198.                         if (FrontWindow()) {                /* don't do this unless we have a window open, silly */
  199.                             windowCHandle clicker;
  200.                             clicker = (windowCHandle)GetWRefCon(twindow);
  201.                             /* jump to the content function stored for this window */
  202.                             HLock((Handle)clicker);         /* lock it down so things don't get stupid */
  203.                             (ProcPtr)((*clicker)->clickMe)(twindow);
  204.                             HUnlock((Handle)clicker);       /* all done */
  205.                         }
  206.                         break;
  207.  
  208.                     case inDrag:
  209.                         if (twindow == FrontWindow())
  210.                             DragWindow(twindow, gERecord.where, &qd.screenBits.bounds);
  211.                         break;
  212.  
  213.                     case inGrow:
  214.                         /* Call GrowWindow here if you have a grow box */
  215.                         SetPort(twindow);
  216.                         MyGrowWindow(twindow);
  217.                         break;
  218.  
  219.                     case inGoAway:
  220.                         /* Click in Close box */
  221.                         if (TrackGoAway(twindow, gERecord.where))
  222.                             (ProcPtr)((*(windowCHandle)((WindowPeek)twindow)->refCon)->closeMe)(twindow);
  223.                         
  224.                         break;
  225.  
  226.                     case inZoomIn:
  227.                     case inZoomOut:
  228.                         if (TrackBox(twindow, gERecord.where, fHit)) {
  229.                             windowCHandle tempWCH = (windowCHandle)GetWRefCon(twindow);
  230.                             SetPort(twindow);
  231.                             
  232.                             ZoomWindow(twindow, fHit, true);
  233.                             InvalRect(&twindow->portRect);
  234.                             (ProcPtr)((*tempWCH)->sizeMe)(twindow);
  235.                         }
  236.                 } /* end mouseDown case */
  237.  
  238.             case mouseUp:
  239.                 /* don't care */
  240.                 break;
  241.  
  242.                 /* same action for key or auto key */
  243.             case keyDown:
  244.             case autoKey:
  245.                 if (gERecord.modifiers & cmdKey)
  246.                     DoSelected(MenuKey(gERecord.message & charCodeMask));
  247.                 break;
  248.  
  249.             case keyUp:
  250.                 /* don't care */
  251.                 break;
  252.  
  253.             case diskEvt:
  254.                 /* I don't do anything special for disk events, this just passes them */
  255.                 /* to a function that checks for an error on the mount */
  256.                 DoDiskEvents(gERecord.message);
  257.                 break;
  258.  
  259.             case activateEvt:
  260.                 if (gERecord.modifiers & activeFlag) {
  261.                     tempWCH = (windowCHandle)GetWRefCon((WindowPtr)gERecord.message);
  262.                     (ProcPtr)((*tempWCH)->drawMe)((WindowPtr)gERecord.message);
  263.                 }
  264.                 break;
  265.  
  266.             case 10:
  267.                 /* don't care */
  268.                 break;
  269.  
  270.             case 11:
  271.                 /* don't care */
  272.                 break;
  273.  
  274.             case 15:
  275.                 switch ((gERecord.message >> 24) & 0x0FF) {     /* high byte of message */
  276.                     case suspendResumeMessage:              /* suspend/resume is also an activate/deactivate */
  277.                         gInBackground = (gERecord.message & kResumeMask) == 0;
  278.                         break;
  279.                 }
  280.                 break;
  281.  
  282.                 /* This dispatches high level events (AppleEvents, for example) */
  283.                 /* to our dispatch routine. This is NEW in the event loop for */
  284.                 /* System 7 */
  285.             case kHighLevelEvent:
  286.                 DoHighLevel(&gERecord);
  287.                 break;
  288.  
  289.             default:
  290.                 break;
  291.                 
  292.         }
  293.     }while (gQuit != true);
  294.     
  295. }
  296.  
  297. /* DoDaCall opens the requested DA. It's here as a seperate routine if you'd */
  298. /* like to perform some action or just know when a DA is opened in your */
  299. /* layer. Can be handy to track memory problems when a DA is opened */
  300. /* with an Option-open */
  301. void DoDaCall(MenuHandle themenu, long theit)
  302. {
  303.     long qq;
  304.     Str255 DAname;
  305.     GetMenuItemText(themenu, theit, DAname);
  306.     qq = OpenDeskAcc((ConstStr255Param)&DAname);
  307. }
  308.  
  309. /* end DoDaCall */
  310.  
  311. /* DoDiskEvents just checks the error code from the disk mount, */
  312. /* and puts up the 'Format' dialog (through DIBadMount) if need be */
  313. /* You can do much more here if you care about what disks are */
  314. /* in the drive */
  315. void DoDiskEvents(long dinfo)                               /* hi word is error code, lo word is drive number */
  316. {
  317.     short hival, loval, tommy;
  318.     Point fredpoint =  {
  319.         40, 40
  320.     };
  321.     hival = HiWord(dinfo);
  322.     loval = LoWord(dinfo);
  323.     if (hival != noErr)                                     /* something happened */ {
  324.         tommy = DIBadMount(fredpoint, dinfo);
  325.     }
  326. }
  327.  
  328. /* draws my window. Pretty simple */
  329. void DrawMain(WindowPtr drawIt)
  330. {
  331.     RgnHandle tempRgn;
  332.     Rect scratchRect;
  333.     Str31 tempString;
  334.     BeginUpdate(drawIt);
  335.     SetPort(drawIt);
  336.     EraseRect(&drawIt->portRect);
  337.     MoveTo(10, 17);
  338.     DrawIndString(kGenStrings,kSayCurrentGrid);
  339.     NumToString(gGridIncrement, tempString);
  340.     DrawString(tempString);
  341.     MoveTo(10, 37);
  342.     DrawIndString(kGenStrings,kSayChangeGrid);
  343.     
  344.     scratchRect = drawIt->portRect;
  345.     scratchRect.top = scratchRect.bottom - 15;
  346.     scratchRect.left = scratchRect.right - 15;
  347.     tempRgn = NewRgn();
  348.     GetClip(tempRgn);
  349.     ClipRect(&scratchRect);
  350.     DrawGrowIcon(drawIt);
  351.     SetClip(tempRgn);
  352.     DisposeRgn(tempRgn);
  353.     
  354.     EndUpdate(drawIt);
  355. }
  356.  
  357. /* my menu action taker. It returns a Boolean which I usually ignore, but it */
  358. /* mught be handy someday */
  359. Boolean DoSelected(long val)
  360. {
  361.     short loval, hival;
  362.     Boolean returnVal = false;
  363.     loval = LoWord(val);
  364.     hival = HiWord(val);
  365.     
  366.     switch (hival) {                                        /* switch off the menu number selected */
  367.         case kAppleMenu:                                    /* Apple menu */
  368.             if (loval != 1) {                               /* if this was not About, it's a DA */
  369.                 DoDaCall(GetMenuHandle(kAppleMenu), loval);
  370.             } else {
  371.                 Alert(kAboutBox, nil);                      /* do about box */
  372.             }
  373.             returnVal = true;
  374.             break;
  375.         case kFileMenu:                                     /* File menu */
  376.             switch (loval) {
  377.                 case kQuitItem:
  378.                     gQuit = true;                           /* only item */
  379.                     returnVal = true;
  380.                     break;
  381.                 default:
  382.                     break;
  383.             }
  384.             break;
  385.         case kEditMenu:
  386.             /* edit menu junk */
  387.             /* don't care */
  388.             break;
  389.         case kToolsMenu:
  390.         case kGridDialogItem:
  391.             DoGridDialog();
  392.             break;
  393.             break;
  394.         case kHMHelpMenuID:                                 /* Defined in Balloons.h */
  395.             /* I only care about this item. If anything else is returned here, I don't know what */
  396.             /* it is, so I leave it alone. Remember, the Help Manager chapter says that */
  397.             /* Apple reserves the right to add and change things in the Help menu */
  398.             if (loval == gHelpItem)
  399.                 SampleHelpDialog();
  400.             break;
  401.             
  402.     }
  403.     HiliteMenu(0);
  404.     return(returnVal);
  405. }
  406.  
  407. void DoDocumentClick(WindowPtr theWindow)
  408. {
  409. #pragma unused (theWindow )
  410. }
  411.  
  412. /* InitAEStuff installs my appleevent handlers */
  413. void InitAEStuff(void)
  414. {
  415.     static AEinstalls HandlersToInstall[] =
  416.     {
  417.         { kCoreEventClass, kAEOpenApplication,    AEOpenHandler        },
  418.         { kCoreEventClass, kAEQuitApplication,    AEQuitHandler        },
  419.         { kCoreEventClass, kAEOpenDocuments,    AEOpenDocHandler    },
  420.         { kCoreEventClass, kAEPrintDocuments,    AEPrintHandler        }
  421.     };
  422.     
  423.     OSErr aevtErr = noErr;
  424.     long aLong = 0;
  425.     Boolean gHasAppleEvents = false;
  426.  
  427.     /* Check this machine for AppleEvents. If they are not here (ie not 7.0)
  428.     * then we exit */
  429.  
  430.     gHasAppleEvents = (Gestalt(gestaltAppleEventsAttr, &aLong) == noErr);
  431.  
  432.     /* The following series of calls installs all our AppleEvent Handlers.
  433.     * These handlers are added to the application event handler list that 
  434.     * the AppleEvent manager maintains. So, whenever an AppleEvent happens
  435.     * and we call AEProcessEvent, the AppleEvent manager will check our
  436.     * list of handlers and dispatch to it if there is one.
  437.     */
  438.  
  439.     if (gHasAppleEvents) {
  440.         register qq;
  441.         for (qq = 0; qq < ((sizeof(HandlersToInstall) / sizeof(AEinstalls))); qq++) {
  442.             aevtErr = AEInstallEventHandler
  443.                 (HandlersToInstall[qq].theClass, HandlersToInstall[qq].theEvent,
  444.                     NewAEEventHandlerProc (HandlersToInstall[qq].theProc), 0, false);
  445.             if (aevtErr) {
  446.                 ExitToShell();                              /* just fail, baby */
  447.             }
  448.         }
  449.     } else {
  450.         ExitToShell();
  451.     }
  452. }
  453.  
  454. /* end InitAEStuff */
  455. /* I'm not doing error handling in this sample for clarities sake, you should. Hah, */
  456. /* easy for me to say, huh? */
  457. void DoHighLevel(EventRecord *AERecord)
  458. {
  459.     
  460.     AEProcessAppleEvent(AERecord);
  461.     
  462. }
  463.  
  464. /* end DoHighLevel */
  465.  
  466. /* This is the standard Open Application event. */
  467. pascal OSErr AEOpenHandler(const AppleEvent *messagein, AppleEvent *reply, long refIn)
  468. {
  469. #pragma unused (messagein,reply,refIn)
  470.     /* we of course don't do anything here in this simple app */
  471.     /* except open our window */
  472.     AddNewWindow(128);
  473.     return(noErr);
  474. }
  475.  
  476. /* end AEOpenHandler */
  477.  
  478. /* Open Doc, opens our documents. Remember, this can happen at application start AND */
  479. /* anytime else. If your app is up and running and the user goes to the desktop, hilites one */
  480. /* of your files, and double-clicks or selects Open from the finder File menu this event */
  481. /* handler will get called. Which means you don't do any initialization of globals here, or */
  482. /* anything else except open then doc. */
  483. /* SO-- Do NOT assume that you are at app start time in this */
  484. /* routine, or bad things will surely happen to you. */
  485.  
  486. pascal OSErr AEOpenDocHandler(const AppleEvent *messagein, AppleEvent *reply, long refIn)
  487. {
  488. #pragma unused (messagein,refIn,reply)
  489.     /* we of course don't do anything here */
  490.     return(errAEEventNotHandled);                           /* we have no docs, so no odoc events should come to us */
  491. }
  492.  
  493. pascal OSErr AEPrintHandler(const AppleEvent *messagein, AppleEvent *reply, long refIn)
  494. {                                                           /* no printing handler in yet, so we'll ignore this */
  495.     /* the operation is functionally identical to the ODOC event, with the additon */
  496.     /* of calling your print routine. */
  497. #pragma unused (messagein,refIn,reply)
  498.     /* we of course don't do anything here */
  499.     return(errAEEventNotHandled);                           /* we have no docs, so no pdoc events should come to us */
  500. }
  501.  
  502. /* Standard Quit event handler, to handle a Quit event from the Finder, for example. */
  503. /* ••••• DO NOT CALL EXITTOSHELL HERE ••••• or you will never have a happy life. */
  504. pascal OSErr AEQuitHandler(const AppleEvent *messagein, AppleEvent *reply, long refIn)
  505. {
  506. #pragma unused (messagein,refIn,reply)
  507.     
  508.     /* prepQuit sets the Stop flag for us. It does _NOT_ quit, you */
  509.     /* should NEVER quit from an AppleEvent handler. Calling */
  510.     /* ExitToShell here would blow things up */
  511.     gQuit = true;
  512.     return(noErr);
  513. }
  514.  
  515. /* This is my sample help dialog. Does not do anything, expand as you need */
  516. void SampleHelpDialog(void)
  517. {
  518.     DialogPtr tdial = GetNewDialog(kSampHelp, nil, (WindowPtr)-1);
  519.     short itemhit = 0;
  520.     while (itemhit != 1) {
  521.         ModalDialog(NewModalFilterProc(nil), &itemhit);
  522.     }
  523.     DisposeDialog(tdial);
  524. }
  525.  
  526.  
  527. #pragma segment Initialize
  528. void InitalizeApp(void)
  529. {
  530.     MenuHandle helpHandle;
  531.     Handle myMenuBar;
  532.     StringHandle helpString;
  533.     short count;
  534.     long vers;
  535.     MaxApplZone();
  536.     InitGraf((Ptr)&qd.thePort);
  537.     InitFonts();
  538.     InitWindows();
  539.     InitMenus();
  540.     TEInit();
  541.     InitDialogs(nil);
  542.     InitCursor();
  543.     /* Check system version */
  544.     Gestalt(gestaltSystemVersion, &vers);
  545.     vers = (vers >> 8) & 0xf;                               /* shift result over and mask out major version number */
  546.     if (vers < 7) {
  547.         StopAlert(kBadSystem, nil);
  548.         ExitToShell();
  549.     }
  550.     InitAEStuff();
  551.     /* set up my menu junk */
  552.     myMenuBar = GetNewMBar(kMBarID);
  553.     SetMenuBar(myMenuBar);
  554.     AppendResMenu(GetMenuHandle(kAppleMenu), 'DRVR');
  555.     /* now install my Help menu item in the Help Manager's menu */
  556.     HMGetHelpMenuHandle(&helpHandle);                       /* Get the Hlpe menu handle */
  557.     count = CountMItems(helpHandle);                        /* How many items are there? */
  558.     helpString = GetString(kHelpString);                    /* get my help string */
  559.     DetachResource((Handle)helpString);                             /* detach it */
  560.     HNoPurge((Handle)helpString);
  561.     MoveHHi((Handle)helpString);
  562.     HLock((Handle)helpString);
  563.     InsertMenuItem(helpHandle, (ConstStr255Param)helpString, count + 1);       /* insert my item in the Help menu */
  564.     gHelpItem = CountMItems(helpHandle);                    /* The number of the item */
  565.     
  566.     DrawMenuBar();
  567.     GetCurrentProcess(&gOurSN);                             /* Get our process serial number for later use, if needed */
  568.     
  569. }
  570.  
  571.  
  572. #pragma segment Main
  573. WindowPtr AddNewWindow(short theID)
  574. {
  575.     windowCHandle setControls;
  576.     WindowPtr tempWP;
  577.     short cnt = 0;
  578.     tempWP = GetNewWindow(theID, 0, (WindowPtr)-1);         /* get a new window */
  579.     SetPort(tempWP);
  580.     ((WindowPeek)tempWP)->windowKind = kDocumentWindow;     /* mark it as a document window */
  581.     setControls = (windowCHandle)NewHandleClear(sizeof(windowControl));     /* add our control structure to it */
  582.     SetWRefCon(tempWP, (long)setControls);                  /* stop stuffing refCon directly <ckh 1.0.3> */
  583.     HLock((Handle)setControls);                             /* lock it down while we fill it*/
  584.     
  585.     /* add pointers to our procedures for drawing, saving, and closing */
  586.     /* This way, all I need is one dispatch point for drawing, closing */
  587.     /* or whatever, I don't have to case off the window kind to go to the */
  588.     /* correct routine. Kinda like object-oriented programming, but I won't */
  589.     /* admit that. */
  590.     (*setControls)->drawMe = (ProcPtr)DrawMain;
  591.     (*setControls)->saveMe = (ProcPtr)NilProc;
  592.     (*setControls)->closeMe = (ProcPtr)NilProc;
  593.     (*setControls)->clickMe = (ProcPtr)DoDocumentClick;
  594.     (*setControls)->sizeMe = (ProcPtr)SizeMain;
  595.     /* now initialize all our required handles */
  596.     return(tempWP);
  597. }
  598.  
  599. void SizeMain(WindowPtr theWindow)
  600. {
  601.     WindowPtr tempWP;
  602.     GetPort(&tempWP);
  603.     InvalRect(&theWindow->portRect);
  604.     SetPort(tempWP);
  605. }
  606.  
  607. void NilProc(void)
  608. {
  609.     
  610. }
  611.  
  612. // This will grid a window grow to a specific increment
  613.  
  614. void PullRect(Rect *startRect)
  615. {
  616.     
  617.     Rect *oldRect;
  618.     Point endPoint;
  619.     Boolean hreversed = false;
  620.     Boolean vreversed = false;
  621.     short tempH, tempV;
  622.     short divBy20h, divBy20v;
  623.     /* set up */
  624.     oldRect = startRect;
  625.     PenMode(srcXor);                                        /* So we can rubberband */
  626.     PenPat(&qd.gray);
  627.     FrameRect(startRect);
  628.     divBy20h = startRect->right;
  629.     divBy20v = startRect->bottom;
  630.     
  631.     
  632.     while (StillDown()) {                                   /* Keep doing this as long as the */
  633.         
  634.         /* user keeps the mouse down */
  635.         GetMouse(&endPoint);                                /* Current mouse position in local */
  636.         // see if it's on a  grid point
  637.         
  638.         tempH = ABS(endPoint.h - divBy20h) / gGridIncrement;
  639.         tempV = ABS(endPoint.v - divBy20v) / gGridIncrement;
  640.         // normalize to our grid values. We'll always go outwards as better
  641.         if ((tempH * gGridIncrement) != ABS(endPoint.h - divBy20h)) {
  642.             // shove out based on the remainer
  643.             endPoint.h = (((endPoint.h)/gGridIncrement)*gGridIncrement)+gGridIncrement;
  644.         }
  645.         if ((tempV * gGridIncrement) != ABS(endPoint.v - divBy20v)) {
  646.             endPoint.v = (((endPoint.v)/gGridIncrement)*gGridIncrement)+gGridIncrement;
  647.             
  648.         }
  649. // If things reversed, we have to make sure that we don't try
  650. // and grid the origin point of the drag, cuz that would be weird
  651.  
  652.             if (hreversed) {
  653.                 /* see if the rectangle flipped first */
  654.                 if (endPoint.h > startRect->right) {
  655.                     /* they flipped back */
  656.                     hreversed = false;                      /* and ignore this move */
  657.                 } else {
  658.                     /* still reversed */
  659.                     startRect->left = endPoint.h;
  660.                 }
  661.             } else {
  662.                 if (endPoint.h < startRect->left) {
  663.                     hreversed = true;
  664.  
  665.                 } else {
  666.                     startRect->right = endPoint.h;
  667.                 }
  668.             }
  669.             if (vreversed) {
  670.                 /* see if it flipped first */
  671.                 if (endPoint.v > startRect->bottom) {
  672.                     /* they flipped back */
  673.                     vreversed = false;                      /* and ignore this move */
  674.                 } else {
  675.                     /* still reversed */
  676.                     startRect->top = endPoint.v;
  677.                 }
  678.             } else {
  679.                 if (endPoint.v < startRect->top) {
  680.                     vreversed = true;
  681.                 } else {
  682.                     startRect->bottom = endPoint.v;
  683.                 }
  684.             }
  685.             if (startRect != oldRect) {                    /* redraw the rect only if the mouse moved */
  686.                 FrameRect(oldRect);
  687.                 FrameRect(startRect);                       /* draw the new rect */
  688.                 oldRect = startRect;
  689.             }
  690.         
  691.     }    
  692.     FrameRect(startRect);
  693.     
  694.     PenMode(srcCopy);
  695.     PenPat(&qd.black);
  696. }
  697.  
  698. void MyGrowWindow(WindowPtr theWindow)
  699. {
  700.     PenState oldPen;
  701.     WindowPtr tempWP, WMPort;
  702.     Rect draggingRect = theWindow->portRect;
  703.     Rect wideOpen =  {
  704.         kExtremeNeg, kExtremeNeg, kExtremePos, kExtremePos
  705.     };
  706.     RgnHandle oldRgn = NewRgn();
  707.     
  708.     GetPort(&tempWP);
  709.     SetPort(theWindow);
  710.     /* normalize my rectangle into the window manager port coordinates */
  711.     LocalToGlobal((Point *)&draggingRect);
  712.     LocalToGlobal((Point *)&draggingRect.bottom);
  713.     /*  go to the WManager port */
  714.     GetWMgrPort(&WMPort);
  715.     SetPort(WMPort);
  716.     /* save the Window manager pen state since we'll be changing it */
  717.     GetPenState(&oldPen);
  718.     /* localize back */
  719.     GlobalToLocal((Point *)&draggingRect);
  720.     GlobalToLocal((Point *)&draggingRect.bottom);
  721.     
  722.     /* save the current clip region, and set our wide-open clip */
  723.     GetClip(oldRgn);
  724.     ClipRect(&wideOpen);
  725.     /* go to the routine above and do the actual dragging */
  726.     PullRect(&draggingRect);
  727.     
  728.     /* restore the original environment */
  729.     SetClip(oldRgn);
  730.     SetPenState(&oldPen);
  731.     DisposeRgn(oldRgn);
  732.     /* now size the window for the returned rect */
  733.     SetPort(theWindow);
  734.     InvalRect(&theWindow->portRect);
  735.     SizeWindow(theWindow, draggingRect.right - draggingRect.left, draggingRect.bottom - draggingRect.top, true);
  736.     SetPort(tempWP);
  737.     
  738. }
  739.  
  740.  
  741. void DoGridDialog(void)
  742. {
  743.     Str255 tempString;
  744.     WindowPtr tempWP=nil;
  745.     WindowPtr tempPort=nil;
  746.  
  747.     long aLong;
  748.     DialogPtr theDialog = GetNewDialog(kGridDialog, nil, (WindowPtr)-1);
  749.     short itemHit = 0;
  750.     ModalFilterUPP theStdProc=nil;   // inited to nil in case the Get fails
  751.  
  752.     // get some automatic dialog behaviour 
  753.     SetDialogDefaultItem(theDialog,ok);
  754.     SetDialogTracksCursor(theDialog,true);
  755.     GetStdFilterProc(&theStdProc);
  756.  
  757.     // set the item to be the current grid value
  758.  
  759.     NumToString(gGridIncrement, tempString);
  760.     SetDialogItemText((Handle)SnatchHandle(theDialog, kGridEditLine), tempString);
  761.     
  762.     // spin until they hit OK or Cancel
  763.     while (itemHit != ok && itemHit !=cancel) {
  764.         ModalDialog(theStdProc, &itemHit);
  765.     }
  766.     
  767.     if (itemHit == 1) {
  768.         // they OK'ed their new grid value
  769.         GetDialogItemText((Handle)SnatchHandle(theDialog, kGridEditLine), tempString);
  770.         StringToNum(tempString, &aLong);
  771.         gGridIncrement = aLong;
  772.     // invalidate our document window so the new value will be refelcted
  773.     tempWP = FindWindowByKind(kDocumentWindow);
  774.     if(tempWP != nil){
  775.         GetPort(&tempPort);
  776.         SetPort(tempWP);
  777.         InvalRect(&tempWP->portRect);
  778.         SetPort(tempPort);
  779.     }
  780.     }
  781.     
  782.     DisposeDialog(theDialog);
  783. }
  784.  
  785. /* gets a handle from a dialog item  */
  786. ControlHandle SnatchHandle(DialogPtr thebox, short theGetItem)
  787. {
  788.     short itemtype;
  789.     Rect itemrect;
  790.     Handle thandle;
  791.     GetDialogItem(thebox, theGetItem, &itemtype, &thandle, &itemrect);
  792.     return((ControlHandle)thandle);
  793. }
  794.  
  795. /* end SnatchHandle */
  796.  
  797. /* loads an index string and draws it.  Just a convinice */
  798. void    DrawIndString(short resID,short index)
  799. {
  800. Str255 theString;
  801. GetIndString(theString,resID,index);
  802. DrawString(theString);
  803. }
  804.  
  805. /* returns the first window of specified kind, or nil if none */
  806. WindowPtr FindWindowByKind(short kindToFind)
  807. {
  808. WindowPtr currentWindow = FrontWindow();
  809. while(currentWindow){
  810.     if(((WindowPeek)currentWindow)->windowKind == kindToFind){
  811.         // found it, break
  812.         break;
  813.     } else {
  814.         // go to the next one
  815.         currentWindow = (WindowPtr) ((WindowPeek)currentWindow)->nextWindow;
  816.     }
  817. }
  818. return ( currentWindow );
  819. }