GrowToGrid.c

/*
    File:       GrowToGrid.c
 
    Contains:    This snippet shows how to grow a window constrained to a grid (i.e.
                only allow a window to grow or shrink by 30 pixels, or whatever).
 
                Now, you might think that using something like DragHook (see the Window 
                Manager documentation) would be the best way to approach this.  Well, I
                personally don't think so, and a lot of my pragmatic (i.e. those who
                like to ship products instead of talking about them) friends agree.  The
                easiest way to do this is just to write a small MyGrowWIndow function
                and use that. 
 
                Or, even better, just grab this one demonstrated here, and you're even more
                pragmatic than I!
 
    Written by: C.K. Haun   
 
    Copyright:  Copyright © 1994-1999 by Apple Computer, Inc., All Rights Reserved.
 
                You may incorporate this Apple sample source code into your program(s) without
                restriction. This Apple sample source code has been provided "AS IS" and the
                responsibility for its operation is yours. You are not permitted to redistribute
                this Apple sample source code as "Apple sample source code" after having made
                changes. If you're going to re-distribute the source, we require that you make
                it clear in the source that the code was descended from Apple sample source
                code, but that you've made changes.
 
    Change History (most recent first):
                8/6/1999    Karl Groethe    Updated for Metrowerks Codewarror Pro 2.1
*/
#include <fonts.h>
#include <dialogs.h>
#include <Desk.h>
#include <diskinit.h>
#include <resources.h>
#include <toolutils.h>
#include <GestaltEqu.h>
#include <Balloons.h>
#include <SegLoad.h>
#include <TextUtils.h>
 
#define kExtremeNeg -32768
#define kExtremePos (32767 - 1) /* required to address an old region bug, see develop 20 Q&As */
 
/* prototypes */
void    DrawIndString(short resID,short index);
void MyGrowWindow(WindowPtr theWindow);
void InitalizeApp(void);
void DoDiskEvents(long dinfo);                              /* hi word is error code, lo word is drive number */
void DrawMain(WindowPtr drawIt);
Boolean DoSelected(long val);
void SizeMain(WindowPtr theWindow);
void InitAEStuff(void);
void DoHighLevel(EventRecord *AERecord);
void DoDaCall(MenuHandle themenu, long theit);
void DoDocumentClick(WindowPtr theWindow);
void DoGridDialog(void);
ControlHandle SnatchHandle(DialogPtr thebox, short theGetItem);
pascal OSErr AEOpenHandler(const AppleEvent *messagein, AppleEvent *reply, unsigned long refIn);
pascal OSErr AEOpenDocHandler(const AppleEvent *messagein, AppleEvent *reply, unsigned long refIn);
pascal OSErr AEPrintHandler(const AppleEvent *messagein, AppleEvent *reply, unsigned long refIn);
pascal OSErr AEQuitHandler(const AppleEvent *messagein, AppleEvent *reply, unsigned long refIn);
void SampleHelpDialog(void);
WindowPtr AddNewWindow(short theID);
WindowPtr FindWindowByKind(short kindToFind);
void PullRect (Rect *someRect);
 
void NilProc(void);
 
/* one external */
#ifdef applec
    extern void _DataInit();                                    /* this is the C initialization code */
#endif
 
/* defines and enums */
/* windows */
enum  {
    kDocumentWindow = 1000, kDocWindow = 128
};
/* menu enums */
enum  {
    kMBarID = 128, kAppleMenu = 128, kFileMenu = 129, kEditMenu = 130, kToolsMenu = 131
};
enum  {
    kResumeMask = 1,                                        /* bit of message field for resume vs. suspend */
    kHelpString = 128
};
/* file menu enums */
enum  {
    kNewItem = 1, kOpenItem, kCloseItem, kSaveItem, kSaveAsItem, kFileBlank1, kPageSetupItem, kPrintItem, kFileBlank2, kQuitItem
};
 
enum  {
    kGridDialogItem = 1
};
 
/* alerts and dialogs */
 
enum  {
    kBadSystem = 130, kSampHelp = 129, kAboutBox = 128, kGridDialog = 131
};
 
enum  {
    kGridDialogMenuItem = 1, kGridEditLine = 4
};
 
enum  {
    kMinHeight = 200
};
 
enum {kGenStrings = 128,kSayCurrentGrid=1,kSayChangeGrid
};
 
#define ABS(A) ((A < 0) ? (A*-1):A)
 
/* structs */
struct AEinstalls {
    AEEventClass            theClass;
    AEEventID               theEvent;
    AEEventHandlerProcPtr   theProc;
};
typedef struct AEinstalls AEinstalls;
 
 
/* windowControl is the structure attached to every window I create (in the refCon */
/* field) that contains all the information I need to know about the window. */
/* this one is really simple */
struct windowControl {
    unsigned long windowID;                                 /* master ID number for section recording */
    ProcPtr drawMe;                                         /* content drawing procedure pointer */
    ProcPtr clickMe;                                        /* content click routine */
    ProcPtr saveMe;                                         /* document save procedure pointer */
    ProcPtr closeMe;                                        /* document close procedure pointer */
    ProcPtr sizeMe;
    AliasHandle fileAliasHandle;                            /* alias for this document */
    Boolean windowDirty;
    long windowIndex;                                       /* for AppleEvent information */
    
};
typedef struct windowControl windowControl, *windowCPtr, **windowCHandle;
 
/* globals */
Boolean gQuit, gInBackground;
Boolean dragIn;
EventRecord gERecord;
ProcessSerialNumber gOurSN;
short gHelpItem;
short gGridIncrement = 30;                                  // start at 30
 
#pragma segment Main
void main()
{
    
    WindowPtr twindow;
    short fHit;
    windowCHandle tempWCH;
        
    #ifdef applec    
        UnloadSeg((Ptr)_DataInit);                              /* throw out C setup code */
    #endif
    
    InitalizeApp();
    UnloadSeg((Ptr)InitalizeApp);                           /* get rid of my initialization code */
    /* start running */
    do {
    
        WaitNextEvent(everyEvent, &gERecord, 30, nil);
    
        switch (gERecord.what) {
 
            case nullEvent:
                /* no nul processing in this sample */
                break;
 
            case updateEvt:
                /* at update, draw the window */
                tempWCH = (windowCHandle)GetWRefCon((WindowPtr)gERecord.message);
                    (ProcPtr)((*tempWCH)->drawMe)((WindowPtr)gERecord.message);
                
                break;
                
            case mouseDown:
                /* first see where the hit was */
                fHit = FindWindow(gERecord.where, &twindow);
                
                switch (fHit) {
 
                    case inDesk:                            /* if they hit in desk, then the process manager */
                        break;                              /* will switch us out, we don't need to do anything */
 
                    case inMenuBar:
                        DoSelected(MenuSelect(gERecord.where));
                        break;
                        
                    case inSysWindow:
                        /* pass to the system */
                        SystemClick(&gERecord, twindow);
                        break;
 
                    case inContent:
                        /* Handle content and control clicks here */
                        if (FrontWindow()) {                /* don't do this unless we have a window open, silly */
                            windowCHandle clicker;
                            clicker = (windowCHandle)GetWRefCon(twindow);
                            /* jump to the content function stored for this window */
                            HLock((Handle)clicker);         /* lock it down so things don't get stupid */
                            (ProcPtr)((*clicker)->clickMe)(twindow);
                            HUnlock((Handle)clicker);       /* all done */
                        }
                        break;
 
                    case inDrag:
                        if (twindow == FrontWindow())
                            DragWindow(twindow, gERecord.where, &qd.screenBits.bounds);
                        break;
 
                    case inGrow:
                        /* Call GrowWindow here if you have a grow box */
                        SetPort(twindow);
                        MyGrowWindow(twindow);
                        break;
 
                    case inGoAway:
                        /* Click in Close box */
                        if (TrackGoAway(twindow, gERecord.where))
                            (ProcPtr)((*(windowCHandle)((WindowPeek)twindow)->refCon)->closeMe)(twindow);
                        
                        break;
 
                    case inZoomIn:
                    case inZoomOut:
                        if (TrackBox(twindow, gERecord.where, fHit)) {
                            windowCHandle tempWCH = (windowCHandle)GetWRefCon(twindow);
                            SetPort(twindow);
                            
                            ZoomWindow(twindow, fHit, true);
                            InvalRect(&twindow->portRect);
                            (ProcPtr)((*tempWCH)->sizeMe)(twindow);
                        }
                } /* end mouseDown case */
 
            case mouseUp:
                /* don't care */
                break;
 
                /* same action for key or auto key */
            case keyDown:
            case autoKey:
                if (gERecord.modifiers & cmdKey)
                    DoSelected(MenuKey(gERecord.message & charCodeMask));
                break;
 
            case keyUp:
                /* don't care */
                break;
 
            case diskEvt:
                /* I don't do anything special for disk events, this just passes them */
                /* to a function that checks for an error on the mount */
                DoDiskEvents(gERecord.message);
                break;
 
            case activateEvt:
                if (gERecord.modifiers & activeFlag) {
                    tempWCH = (windowCHandle)GetWRefCon((WindowPtr)gERecord.message);
                    (ProcPtr)((*tempWCH)->drawMe)((WindowPtr)gERecord.message);
                }
                break;
 
            case 10:
                /* don't care */
                break;
 
            case 11:
                /* don't care */
                break;
 
            case 15:
                switch ((gERecord.message >> 24) & 0x0FF) {     /* high byte of message */
                    case suspendResumeMessage:              /* suspend/resume is also an activate/deactivate */
                        gInBackground = (gERecord.message & kResumeMask) == 0;
                        break;
                }
                break;
 
                /* This dispatches high level events (AppleEvents, for example) */
                /* to our dispatch routine. This is NEW in the event loop for */
                /* System 7 */
            case kHighLevelEvent:
                DoHighLevel(&gERecord);
                break;
 
            default:
                break;
                
        }
    }while (gQuit != true);
    
}
 
/* DoDaCall opens the requested DA. It's here as a seperate routine if you'd */
/* like to perform some action or just know when a DA is opened in your */
/* layer. Can be handy to track memory problems when a DA is opened */
/* with an Option-open */
void DoDaCall(MenuHandle themenu, long theit)
{
    long qq;
    Str255 DAname;
    GetMenuItemText(themenu, theit, DAname);
    qq = OpenDeskAcc((ConstStr255Param)&DAname);
}
 
/* end DoDaCall */
 
/* DoDiskEvents just checks the error code from the disk mount, */
/* and puts up the 'Format' dialog (through DIBadMount) if need be */
/* You can do much more here if you care about what disks are */
/* in the drive */
void DoDiskEvents(long dinfo)                               /* hi word is error code, lo word is drive number */
{
    short hival, loval, tommy;
    Point fredpoint =  {
        40, 40
    };
    hival = HiWord(dinfo);
    loval = LoWord(dinfo);
    if (hival != noErr)                                     /* something happened */ {
        tommy = DIBadMount(fredpoint, dinfo);
    }
}
 
/* draws my window. Pretty simple */
void DrawMain(WindowPtr drawIt)
{
    RgnHandle tempRgn;
    Rect scratchRect;
    Str31 tempString;
    BeginUpdate(drawIt);
    SetPort(drawIt);
    EraseRect(&drawIt->portRect);
    MoveTo(10, 17);
    DrawIndString(kGenStrings,kSayCurrentGrid);
    NumToString(gGridIncrement, tempString);
    DrawString(tempString);
    MoveTo(10, 37);
    DrawIndString(kGenStrings,kSayChangeGrid);
    
    scratchRect = drawIt->portRect;
    scratchRect.top = scratchRect.bottom - 15;
    scratchRect.left = scratchRect.right - 15;
    tempRgn = NewRgn();
    GetClip(tempRgn);
    ClipRect(&scratchRect);
    DrawGrowIcon(drawIt);
    SetClip(tempRgn);
    DisposeRgn(tempRgn);
    
    EndUpdate(drawIt);
}
 
/* my menu action taker. It returns a Boolean which I usually ignore, but it */
/* mught be handy someday */
Boolean DoSelected(long val)
{
    short loval, hival;
    Boolean returnVal = false;
    loval = LoWord(val);
    hival = HiWord(val);
    
    switch (hival) {                                        /* switch off the menu number selected */
        case kAppleMenu:                                    /* Apple menu */
            if (loval != 1) {                               /* if this was not About, it's a DA */
                DoDaCall(GetMenuHandle(kAppleMenu), loval);
            } else {
                Alert(kAboutBox, nil);                      /* do about box */
            }
            returnVal = true;
            break;
        case kFileMenu:                                     /* File menu */
            switch (loval) {
                case kQuitItem:
                    gQuit = true;                           /* only item */
                    returnVal = true;
                    break;
                default:
                    break;
            }
            break;
        case kEditMenu:
            /* edit menu junk */
            /* don't care */
            break;
        case kToolsMenu:
        case kGridDialogItem:
            DoGridDialog();
            break;
            break;
        case kHMHelpMenuID:                                 /* Defined in Balloons.h */
            /* I only care about this item. If anything else is returned here, I don't know what */
            /* it is, so I leave it alone. Remember, the Help Manager chapter says that */
            /* Apple reserves the right to add and change things in the Help menu */
            if (loval == gHelpItem)
                SampleHelpDialog();
            break;
            
    }
    HiliteMenu(0);
    return(returnVal);
}
 
void DoDocumentClick(WindowPtr theWindow)
{
#pragma unused (theWindow )
}
 
/* InitAEStuff installs my appleevent handlers */
void InitAEStuff(void)
{
    static AEinstalls HandlersToInstall[] =
    {
        { kCoreEventClass, kAEOpenApplication,  AEOpenHandler       },
        { kCoreEventClass, kAEQuitApplication,  AEQuitHandler       },
        { kCoreEventClass, kAEOpenDocuments,    AEOpenDocHandler    },
        { kCoreEventClass, kAEPrintDocuments,   AEPrintHandler      }
    };
    
    OSErr aevtErr = noErr;
    long aLong = 0;
    Boolean gHasAppleEvents = false;
 
    /* Check this machine for AppleEvents. If they are not here (ie not 7.0)
    * then we exit */
 
    gHasAppleEvents = (Gestalt(gestaltAppleEventsAttr, &aLong) == noErr);
 
    /* The following series of calls installs all our AppleEvent Handlers.
    * These handlers are added to the application event handler list that 
    * the AppleEvent manager maintains. So, whenever an AppleEvent happens
    * and we call AEProcessEvent, the AppleEvent manager will check our
    * list of handlers and dispatch to it if there is one.
    */
 
    if (gHasAppleEvents) {
        register qq;
        for (qq = 0; qq < ((sizeof(HandlersToInstall) / sizeof(AEinstalls))); qq++) {
            aevtErr = AEInstallEventHandler
                (HandlersToInstall[qq].theClass, HandlersToInstall[qq].theEvent,
                    NewAEEventHandlerProc (HandlersToInstall[qq].theProc), 0, false);
            if (aevtErr) {
                ExitToShell();                              /* just fail, baby */
            }
        }
    } else {
        ExitToShell();
    }
}
 
/* end InitAEStuff */
/* I'm not doing error handling in this sample for clarities sake, you should. Hah, */
/* easy for me to say, huh? */
void DoHighLevel(EventRecord *AERecord)
{
    
    AEProcessAppleEvent(AERecord);
    
}
 
/* end DoHighLevel */
 
/* This is the standard Open Application event. */
pascal OSErr AEOpenHandler(const AppleEvent *messagein, AppleEvent *reply, unsigned long refIn)
{
#pragma unused (messagein,reply,refIn)
    /* we of course don't do anything here in this simple app */
    /* except open our window */
    AddNewWindow(128);
    return(noErr);
}
 
/* end AEOpenHandler */
 
/* Open Doc, opens our documents. Remember, this can happen at application start AND */
/* anytime else. If your app is up and running and the user goes to the desktop, hilites one */
/* of your files, and double-clicks or selects Open from the finder File menu this event */
/* handler will get called. Which means you don't do any initialization of globals here, or */
/* anything else except open then doc. */
/* SO-- Do NOT assume that you are at app start time in this */
/* routine, or bad things will surely happen to you. */
 
pascal OSErr AEOpenDocHandler(const AppleEvent *messagein, AppleEvent *reply, unsigned long refIn)
{
#pragma unused (messagein,refIn,reply)
    /* we of course don't do anything here */
    return(errAEEventNotHandled);                           /* we have no docs, so no odoc events should come to us */
}
 
pascal OSErr AEPrintHandler(const AppleEvent *messagein, AppleEvent *reply, unsigned long refIn)
{                                                           /* no printing handler in yet, so we'll ignore this */
    /* the operation is functionally identical to the ODOC event, with the additon */
    /* of calling your print routine. */
#pragma unused (messagein,refIn,reply)
    /* we of course don't do anything here */
    return(errAEEventNotHandled);                           /* we have no docs, so no pdoc events should come to us */
}
 
/* Standard Quit event handler, to handle a Quit event from the Finder, for example. */
/* ¥¥¥¥¥ DO NOT CALL EXITTOSHELL HERE ¥¥¥¥¥ or you will never have a happy life. */
pascal OSErr AEQuitHandler(const AppleEvent *messagein, AppleEvent *reply, unsigned long refIn)
{
#pragma unused (messagein,refIn,reply)
    
    /* prepQuit sets the Stop flag for us. It does _NOT_ quit, you */
    /* should NEVER quit from an AppleEvent handler. Calling */
    /* ExitToShell here would blow things up */
    gQuit = true;
    return(noErr);
}
 
/* This is my sample help dialog. Does not do anything, expand as you need */
void SampleHelpDialog(void)
{
    DialogPtr tdial = GetNewDialog(kSampHelp, nil, (WindowPtr)-1);
    short itemhit = 0;
    while (itemhit != 1) {
        ModalDialog(NewModalFilterProc(nil), &itemhit);
    }
    DisposeDialog(tdial);
}
 
 
#pragma segment Initialize
void InitalizeApp(void)
{
    MenuHandle helpHandle;
    Handle myMenuBar;
    StringHandle helpString;
    short count;
    long vers;
    MaxApplZone();
    InitGraf((Ptr)&qd.thePort);
    InitFonts();
    InitWindows();
    InitMenus();
    TEInit();
    InitDialogs(nil);
    InitCursor();
    /* Check system version */
    Gestalt(gestaltSystemVersion, &vers);
    vers = (vers >> 8) & 0xf;                               /* shift result over and mask out major version number */
    if (vers < 7) {
        StopAlert(kBadSystem, nil);
        ExitToShell();
    }
    InitAEStuff();
    /* set up my menu junk */
    myMenuBar = GetNewMBar(kMBarID);
    SetMenuBar(myMenuBar);
    AppendResMenu(GetMenuHandle(kAppleMenu), 'DRVR');
    /* now install my Help menu item in the Help Manager's menu */
    HMGetHelpMenuHandle(&helpHandle);                       /* Get the Hlpe menu handle */
    count = CountMItems(helpHandle);                        /* How many items are there? */
    helpString = GetString(kHelpString);                    /* get my help string */
    DetachResource((Handle)helpString);                             /* detach it */
    HNoPurge((Handle)helpString);
    MoveHHi((Handle)helpString);
    HLock((Handle)helpString);
    InsertMenuItem(helpHandle, (ConstStr255Param)helpString, count + 1);       /* insert my item in the Help menu */
    gHelpItem = CountMItems(helpHandle);                    /* The number of the item */
    
    DrawMenuBar();
    GetCurrentProcess(&gOurSN);                             /* Get our process serial number for later use, if needed */
    
}
 
 
#pragma segment Main
WindowPtr AddNewWindow(short theID)
{
    windowCHandle setControls;
    WindowPtr tempWP;
    short cnt = 0;
    tempWP = GetNewWindow(theID, 0, (WindowPtr)-1);         /* get a new window */
    SetPort(tempWP);
    ((WindowPeek)tempWP)->windowKind = kDocumentWindow;     /* mark it as a document window */
    setControls = (windowCHandle)NewHandleClear(sizeof(windowControl));     /* add our control structure to it */
    SetWRefCon(tempWP, (long)setControls);                  /* stop stuffing refCon directly <ckh 1.0.3> */
    HLock((Handle)setControls);                             /* lock it down while we fill it*/
    
    /* add pointers to our procedures for drawing, saving, and closing */
    /* This way, all I need is one dispatch point for drawing, closing */
    /* or whatever, I don't have to case off the window kind to go to the */
    /* correct routine. Kinda like object-oriented programming, but I won't */
    /* admit that. */
    (*setControls)->drawMe = (ProcPtr)DrawMain;
    (*setControls)->saveMe = (ProcPtr)NilProc;
    (*setControls)->closeMe = (ProcPtr)NilProc;
    (*setControls)->clickMe = (ProcPtr)DoDocumentClick;
    (*setControls)->sizeMe = (ProcPtr)SizeMain;
    /* now initialize all our required handles */
    return(tempWP);
}
 
void SizeMain(WindowPtr theWindow)
{
    WindowPtr tempWP;
    GetPort(&tempWP);
    InvalRect(&theWindow->portRect);
    SetPort(tempWP);
}
 
void NilProc(void)
{
    
}
 
// This will grid a window grow to a specific increment
 
void PullRect(Rect *startRect)
{
    
    Rect *oldRect;
    Point endPoint;
    Boolean hreversed = false;
    Boolean vreversed = false;
    short tempH, tempV;
    short divBy20h, divBy20v;
    /* set up */
    oldRect = startRect;
    PenMode(srcXor);                                        /* So we can rubberband */
    PenPat(&qd.gray);
    FrameRect(startRect);
    divBy20h = startRect->right;
    divBy20v = startRect->bottom;
    
    
    while (StillDown()) {                                   /* Keep doing this as long as the */
        
        /* user keeps the mouse down */
        GetMouse(&endPoint);                                /* Current mouse position in local */
        // see if it's on a  grid point
        
        tempH = ABS(endPoint.h - divBy20h) / gGridIncrement;
        tempV = ABS(endPoint.v - divBy20v) / gGridIncrement;
        // normalize to our grid values. We'll always go outwards as better
        if ((tempH * gGridIncrement) != ABS(endPoint.h - divBy20h)) {
            // shove out based on the remainer
            endPoint.h = (((endPoint.h)/gGridIncrement)*gGridIncrement)+gGridIncrement;
        }
        if ((tempV * gGridIncrement) != ABS(endPoint.v - divBy20v)) {
            endPoint.v = (((endPoint.v)/gGridIncrement)*gGridIncrement)+gGridIncrement;
            
        }
// If things reversed, we have to make sure that we don't try
// and grid the origin point of the drag, cuz that would be weird
 
            if (hreversed) {
                /* see if the rectangle flipped first */
                if (endPoint.h > startRect->right) {
                    /* they flipped back */
                    hreversed = false;                      /* and ignore this move */
                } else {
                    /* still reversed */
                    startRect->left = endPoint.h;
                }
            } else {
                if (endPoint.h < startRect->left) {
                    hreversed = true;
 
                } else {
                    startRect->right = endPoint.h;
                }
            }
            if (vreversed) {
                /* see if it flipped first */
                if (endPoint.v > startRect->bottom) {
                    /* they flipped back */
                    vreversed = false;                      /* and ignore this move */
                } else {
                    /* still reversed */
                    startRect->top = endPoint.v;
                }
            } else {
                if (endPoint.v < startRect->top) {
                    vreversed = true;
                } else {
                    startRect->bottom = endPoint.v;
                }
            }
            if (startRect != oldRect) {                    /* redraw the rect only if the mouse moved */
                FrameRect(oldRect);
                FrameRect(startRect);                       /* draw the new rect */
                oldRect = startRect;
            }
        
    }    
    FrameRect(startRect);
    
    PenMode(srcCopy);
    PenPat(&qd.black);
}
 
void MyGrowWindow(WindowPtr theWindow)
{
    PenState oldPen;
    WindowPtr tempWP, WMPort;
    Rect draggingRect = theWindow->portRect;
    Rect wideOpen =  {
        kExtremeNeg, kExtremeNeg, kExtremePos, kExtremePos
    };
    RgnHandle oldRgn = NewRgn();
    
    GetPort(&tempWP);
    SetPort(theWindow);
    /* normalize my rectangle into the window manager port coordinates */
    LocalToGlobal((Point *)&draggingRect);
    LocalToGlobal((Point *)&draggingRect.bottom);
    /*  go to the WManager port */
    GetWMgrPort(&WMPort);
    SetPort(WMPort);
    /* save the Window manager pen state since we'll be changing it */
    GetPenState(&oldPen);
    /* localize back */
    GlobalToLocal((Point *)&draggingRect);
    GlobalToLocal((Point *)&draggingRect.bottom);
    
    /* save the current clip region, and set our wide-open clip */
    GetClip(oldRgn);
    ClipRect(&wideOpen);
    /* go to the routine above and do the actual dragging */
    PullRect(&draggingRect);
    
    /* restore the original environment */
    SetClip(oldRgn);
    SetPenState(&oldPen);
    DisposeRgn(oldRgn);
    /* now size the window for the returned rect */
    SetPort(theWindow);
    InvalRect(&theWindow->portRect);
    SizeWindow(theWindow, draggingRect.right - draggingRect.left, draggingRect.bottom - draggingRect.top, true);
    SetPort(tempWP);
    
}
 
 
void DoGridDialog(void)
{
    Str255 tempString;
    WindowPtr tempWP=nil;
    WindowPtr tempPort=nil;
 
    long aLong;
    DialogPtr theDialog = GetNewDialog(kGridDialog, nil, (WindowPtr)-1);
    short itemHit = 0;
    ModalFilterUPP theStdProc=nil;   // inited to nil in case the Get fails
 
    // get some automatic dialog behaviour 
    SetDialogDefaultItem(theDialog,ok);
    SetDialogTracksCursor(theDialog,true);
    GetStdFilterProc(&theStdProc);
 
    // set the item to be the current grid value
 
    NumToString(gGridIncrement, tempString);
    SetDialogItemText((Handle)SnatchHandle(theDialog, kGridEditLine), tempString);
    
    // spin until they hit OK or Cancel
    while (itemHit != ok && itemHit !=cancel) {
        ModalDialog(theStdProc, &itemHit);
    }
    
    if (itemHit == 1) {
        // they OK'ed their new grid value
        GetDialogItemText((Handle)SnatchHandle(theDialog, kGridEditLine), tempString);
        StringToNum(tempString, &aLong);
        gGridIncrement = aLong;
    // invalidate our document window so the new value will be refelcted
    tempWP = FindWindowByKind(kDocumentWindow);
    if(tempWP != nil){
        GetPort(&tempPort);
        SetPort(tempWP);
        InvalRect(&tempWP->portRect);
        SetPort(tempPort);
    }
    }
    
    DisposeDialog(theDialog);
}
 
/* gets a handle from a dialog item  */
ControlHandle SnatchHandle(DialogPtr thebox, short theGetItem)
{
    short itemtype;
    Rect itemrect;
    Handle thandle;
    GetDialogItem(thebox, theGetItem, &itemtype, &thandle, &itemrect);
    return((ControlHandle)thandle);
}
 
/* end SnatchHandle */
 
/* loads an index string and draws it.  Just a convinice */
void    DrawIndString(short resID,short index)
{
Str255 theString;
GetIndString(theString,resID,index);
DrawString(theString);
}
 
/* returns the first window of specified kind, or nil if none */
WindowPtr FindWindowByKind(short kindToFind)
{
WindowPtr currentWindow = FrontWindow();
while(currentWindow){
    if(((WindowPeek)currentWindow)->windowKind == kindToFind){
        // found it, break
        break;
    } else {
        // go to the next one
        currentWindow = (WindowPtr) ((WindowPeek)currentWindow)->nextWindow;
    }
}
return ( currentWindow );
}