Utilities.c

/*------------------------------------------------------------------------------
*
*  Apple Developer Technical Support
*
*  
*
*  Program: AEObject-Edition Sample
*  File:   Utilities.c -C Source
*
*  by: C.K. Haun <TR>
*
*  Copyright © 1990-1992 Apple Computer, Inc.
*  All rights reserved.
*
*------------------------------------------------------------------------------
* This file contains some of our window handling routines.  I created it 
* primarily to take some of the clutter out of the main.c file.
* It also contains the clipboard handlers
*----------------------------------------------------------------------------*/
 
#define __GUTILS__
 
#include "Sampdefines.h"
 
#pragma segment Utils
 
/* standardDialogFilter is _new_ and dispatches to the System 7 */
/* standard dialog filter.  Please see tech note #304 */
/* for details on how this works, and why  I am checking  */
/* for update events in this thing */
/* Look right below for one for Alerts */
pascal Boolean standardDialogFilter(DialogPtr theDialog, EventRecord *theEvent, short *itemHit)
{
    if (theEvent->what == updateEvt && theEvent->message != theDialog ){
        WindowPtr theWindow = (WindowPtr)theEvent->message;
        /* draw my window if it's really mine */
        if(IsMyWindow(theWindow)){
            DrawIt((WindowPtr)theWindow);     
            *itemHit = 0;
            return(false);  /* tell the dialog manager I handled this event */
        }
    } else {
        ModalFilterUPP stdProc;
        GetStdFilterProc(&stdProc);
        return CallModalFilterProc(stdProc, theDialog, theEvent, itemHit);
    }
} /* end  standardDialogFilter */
 
pascal Boolean standardAlertFilter(DialogPtr theDialog, EventRecord *theEvent, short *itemHit)
{
    Boolean returnVal = false;  
    if(theEvent->what == updateEvt && theEvent->message != theDialog ){
    WindowPtr theWindow = (WindowPtr)theEvent->message;
    /* draw my window if it's really mine */
    if(IsMyWindow(theWindow)){
    DrawIt((WindowPtr)theWindow);     
    *itemHit = 0;
    returnVal = false;
    }
    } else {
    /* for alerts we have to check for keys ourselves, since we didn't have a chance to */
    /* call SetDialogCancel or anything */
    
        if ((theEvent->what == keyDown) || (theEvent->what == autoKey)) {
    short tempItem; Handle tempHandle;
    Rect tempRect;
        char theKey = theEvent->message & charCodeMask;
        switch (theKey) {
        long tilticks;
            case kReturnKey:
            case kEnterKey:                                 /* enter key */
                /* This filters for Return or Enter as item 1, and Esc as item 2 */
                *itemHit = 1;                         /* change whatever the current item is to the OK item */
                /* now we need to invert the button */
                GetDialogItem(theDialog, 1, &tempItem, &tempHandle, &tempRect);
                if(tempItem == ctrlItem){
                /* double check for the unlikely event that this is _not_ a button */
                HiliteControl(SnatchHandle(theDialog, ok), inButton);
                Delay(8, &tilticks);                        /* wait about 8 ticks so they can see it */
                HiliteControl(SnatchHandle(theDialog, ok), false);
              
                returnVal = true;
                }
                break;
                /* This filters the escape key as the same as item 2 (the canx button, usually ) */
            case kEscKey:
                *itemHit = 2;
                if(tempItem == ctrlItem){
                /* much more likely that this may not be a button */
 
                HiliteControl(SnatchHandle(theDialog, cancel), inButton);
                Delay(8, &tilticks);                        /* wait about 8 ticks so they can see it */
                HiliteControl(SnatchHandle(theDialog, cancel), false);
                returnVal = true;
                }
                break;
            }
    
    }
    
    
    
    
    
    
    
    
    
    }
return(returnVal);  
} /* end  standardDialogFilter */
 
/* Gets the ControlHandle for the item you want in the dialog box thebox.  */
/* Handy for setting checkboxes and radio buttons */
ControlHandle SnatchHandle(DialogPtr thebox, short theGetItem)
{
    short itemtype;
    Rect itemrect;
    Handle thandle;    
    GetDialogItem(thebox, theGetItem, &itemtype, &thandle, &itemrect);
    return((ControlHandle)thandle);
} /* end SnatchHandle */
 
/* MakeRect converts two points into a rect. */
/* it also insures that the rect is not reversed */
void MakeRect(Point *aPoint, Point *bPoint, Rect *putRect)
{
    short temp;
    putRect->top = aPoint->v;
    putRect->left = aPoint->h;
    putRect->bottom = bPoint->v;
    putRect->right = bPoint->h;
    if (putRect->top > putRect->bottom) {
        temp = putRect->bottom;
        putRect->bottom = putRect->top;
        putRect->top = temp;
    }
    if (putRect->left > putRect->right) {
        temp = putRect->right;
        putRect->right = putRect->left;
        putRect->left = temp;
    }
    if (putRect->right == putRect->left)
        putRect->left++;
    if (putRect->bottom == putRect->top)
        putRect->bottom++;
} /* end MakeRect */
 
 
/* ties two P strings together.  Haven't we all written this at one time or another???? */
void AppendString(Str255 target, Str255 appendIt)
{
    BlockMove((Ptr)(appendIt + 1), (Ptr)(target + (target[0])+1), appendIt[0]);
    target[0] += appendIt[0];
} /* end AppendString */
 
/* PureCursor checks to see if the last keystroke was a 'pure' cursor */
/* moving keystroke.  This is important for setting Undo for text typing, */
/* if I had put that in */
Boolean PureCursor(char theKey)
{
    register qq;
    char curChars[4] =  {
        kLeftArrow, kRightArrow, kUpArrow, kDownArrow
    };
    Boolean result = false;
    for (qq = 0; qq < 4; qq++) {
        if (theKey == curChars[qq])
            result = true;
    }
    return(result);
    
} /* end PureCursor */
 
/* This tries as hard as it can to resize a  handle, avoiding the problem SetHandleSize */
/* has when a block is surrounded by locked stuff.  */
/* Of course if you use this, you can only have one copy of the handle around and you */
/* always must reference that handle, since the master pointer contained within it */
/* can change during the ReallocateHandle call.  But you should be doing that anyway (nag nag nag) */
OSErr MySetHandleSize(Handle theHandle, Size theSize)
{
    OSErr memErr;
    Handle tempHand = theHandle;
    SetHandleSize(theHandle, theSize);
    memErr = MemError();
    if (!memErr)
        return(noErr);
    /* could not resize the handle.  Why? */
    if (memErr != memFullErr)
        return(memErr);                                     /* not something we can deal with */
    /* either the memory is really not available, or there is a locked pointer
    *   above the handle we're resizing.  We'll try seeing if the memory 
    *   is actually there first. */
    ShowMe("\p mem err", memErr, __LINE__);
    if (!(CompactMem(theSize) >= theSize))
        return(MemError());                                 /* memory really is full, bail */
    /* OK, memory is available somewhere.  Find it */
    HandToHand(&tempHand);                                  /* copy the handle */
    ReallocateHandle(theHandle, theSize);                      /* resize by reallocation */
    HLock(tempHand);
    HLock(theHandle);
    BlockMove(*tempHand, *theHandle, GetHandleSize(theHandle));     /* only move the size of the target */
    HUnlock(theHandle);
    DisposeHandle(tempHand);
} /* end MySetHandleSize */
 
/* ShowMe is just a handy place to display a string and a number. */
/* ¥¥¥ NOTE: That I'm calling AEInteractWithUser here, instead */
/* of just blasting up an alert */
void ShowMe(Str255 in, OSErr aevtErr, short lineNo)
{
    NMRec myNotification;
    Str255 nmWords;
    Str32 theGuy;
    Str32 theLine;
    OSErr myErr;
    myNotification.qType =nmType ;
    myNotification.nmMark = nil;
    myNotification.nmIcon = nil;
    myNotification.nmSound = (Handle)-1;
    myNotification.nmStr =&nmWords ;
    myNotification.nmResp =nil ;
 
    GetIndString(&nmWords,kGeneralStrings,kErrorToSay);
    myErr = AEInteractWithUser(kAEDefaultTimeout, &myNotification, gCommonIdleFunctionUPP);
    if(myErr != errAENoUserInteraction ) {
        ModalFilterUPP upp = NewModalFilterProc(standardAlertFilter);
        InitCursor();
        NumToString((long)aevtErr, theGuy);
        NumToString((long)lineNo, theLine);
        ParamText(in, theGuy, theLine, "");
        Alert(129, upp);
        DisposeRoutineDescriptor(upp);
    
    }
} /* end ShowMe */
 
/* 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);
    }
} /* end DoDiskEvents */
 
/* CommonDStart is here just because I'm tired of typing GetNewDialog and  */
/* typing the d*mned (WindowPtr)-1 all the time. */
/* It also sets up our default and cancel items, as expalined in TN #304 */
DialogPtr CommonDStart(short DNumber, short set1, short set2)
{
    
    DialogPtr tdial = GetNewDialog(DNumber, nil, (WindowPtr)-1);
    if (set1)
        SetControlValue(SnatchHandle(tdial, set1), true);
    if (set2)
        SetControlValue(SnatchHandle(tdial, set2), true);
    SetDialogDefaultItem(tdial, ok);
    SetDialogCancelItem(tdial, cancel);
    
    return(tdial);
} /* end CommonDStart */
 
/* PullRect either drags a rect around the screen (for subscribers) or pulls a rect */
/* rubber-band wise for anything else. I'm not using DragGryRgn because I have to check some */
/* intersections along the way */
/* And since an Oval has the same calling conventions as a Rect, it calls this too */
void PullRect(windowCHandle theWind, Rect *startRect, Boolean isOval, Boolean useRect, Boolean onlyCorner)
{
    
    WindowPtr theWindow = FrontWindow();
    Rect oldRect;
    Point endPoint, thePoint;
    Boolean hreversed = false;
    Boolean vreversed = false;
    /* set up */
    if (useRect) {
        oldRect = *startRect;
    } else {
        oldRect.top = startRect->top = oldRect.bottom = startRect->bottom = gERecord.where.v;
        oldRect.right = startRect->right = oldRect.left = startRect->left = gERecord.where.h;
    }
    PenMode(srcXor);                                        /* So we can rubberband */
    /* see if we're dragging the whole rect, or just pulling a corner out */
    if (onlyCorner) {
        while (StillDown()) {                               /* Keep doing this as long as the */
            /* user keeps the mouse down */            
            GetMouse(&endPoint);                            /* Current mouse position in local */            
            if (hreversed) {
                /* see if it 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;
                }
            }
            
            /* make sure we're not intersecting a text box */
            if (!InTextBox(theWind, startRect)) {
                if (*startRect != oldRect) {                /* redraw the rect only if the mouse moved  */
                    if (isOval) {
                        FrameOval(&oldRect);
                        FrameOval(startRect);
                    } else {
                        FrameRect(&oldRect);
                        FrameRect(startRect);               /* draw the new rect */
                    }
                    oldRect = *startRect;
                }
            } else {
                *startRect = oldRect;
            }
        }
    } else {
    /* We're dragging the whole rectangle here */
        GetMouse(&thePoint);
        while (StillDown()) {                               /* keep doing it until they release the mouse */
            
            PenMode(patXor);
            if (!EqualRect(startRect, &oldRect)) {
                FrameRect(startRect);                       /* nasty way to put up a flashing border for the drag */
                FrameRect(startRect);
                
            }
            GetMouse(&endPoint);
            /* keep inside the window please, don't let them drag the */
            /* rectangle outside the window bounds */
            if ((PtInRect(endPoint, &(FrontWindow()->portRect)))) {
                if (endPoint != thePoint) {
                    oldRect = *startRect;
                    OffsetRect(startRect, endPoint.h - thePoint.h, endPoint.v - thePoint.v);
                    if (!InTextBox(theWind, startRect)) {
                        thePoint = endPoint;
                    } else {
                        *startRect = oldRect;
                        FrameRect(startRect);               /* nasty way to put up a flashing border for the drag */
                        FrameRect(startRect);
                    }
                }
            }
        }
        PenMode(normal);
        
    }
    PenMode(srcCopy);
} /* end PullRect */
 
/* DoAnts draws the marque box for the current selection.   */
/* Please note:  No one else in the known universe does marching ants */
/* like this but me.  I happen to like this   */
void DoAnts(Rect *theRect)
{
    static short nowPat = 0;
    static long timeToMarch = 0;
    WindowPtr theWind = FrontWindow();
    Pattern thePat;
    if(TickCount() > timeToMarch || timeToMarch == 0){
    if (theWind) {
        windowCHandle tempWC = (windowCHandle)GetWRefCon(theWind);
        if ((*tempWC)->hasSelection || theRect) {
            GetIndPattern(&thePat, 128, nowPat);
            nowPat++;
            if (nowPat == 8)
                nowPat = 0;
            PenMode(patXor);
            PenPat(&thePat);
            if (theRect)
                FrameRect(theRect);
            else
                FrameRect(&(*tempWC)->selectionRect);
            PenMode(normal);
            PenPat(&qd.black);
        }
    }
    timeToMarch = TickCount() + kMarchTime;
}
 
 
} /* end DoAnts */
 
/*  AdjustCursor change the cursor's shape, depending on its position. This also calculates
the region where the current cursor resides (for WaitNextEvent). If the
mouse is ever outside of that region, an event would be generated, causing
this routine to be called, allowing us to change the region to the region
the mouse is currently in.
*/
 
void AdjustCursor(Point mouse, RgnHandle region)
{
    WindowPtr window;
    RgnHandle specialRgn;
    RgnHandle tbRgn;
    Rect textRect;
    Rect globalPortRect;
    windowCHandle shortName;
    window = FrontWindow();                                 /* we only adjust the cursor when we are in front */
    if (!window){
        SetEmptyRgn(region);
        return;                                             /* ignore also if we have no open doc windows */
    }
    if (((WindowPeek)window)->windowKind == kClipboardWindow || ((WindowPeek)window)->windowKind == kAEStatusWindow) {
        InitCursor();
        SetEmptyRgn(region);  /* don't care if a doc window not frontmost */
        return;
    }
    if ((!gInBackground) && (IsMyWindow(window))) {
        specialRgn = NewRgn();
        shortName = (windowCHandle)GetWRefCon(window);
        /* calculate specialRgn */
        globalPortRect = window->portRect;
        LocalToGlobal((Point *)&globalPortRect);
        LocalToGlobal((Point *)&globalPortRect.bottom);
        RectRgn(specialRgn, &globalPortRect);
            if((*shortName)->boxHandle){
            textRect = (*shortName)->textBox;
                    LocalToGlobal((Point *)&textRect);
        LocalToGlobal((Point *)&textRect.bottom);
        tbRgn = NewRgn();
        OpenRgn();
        FrameRect(&textRect);
        CloseRgn(tbRgn);
        DiffRgn(specialRgn,tbRgn,specialRgn);
        DisposeRgn(tbRgn);
        
        
 
}
        /* change the cursor and the region parameter */
        
        if (PtInRect(mouse, &globalPortRect)) {
            short temp;
            
            temp = actsToIDs[(*shortName)->currentAction];
            SetMyCursor(temp);
            /* if textbox then poke hole for text box */
            if((*shortName)->boxHandle){
            textRect = (*shortName)->textBox;
        LocalToGlobal((Point *)&textRect);
        LocalToGlobal((Point *)&textRect.bottom);
            if(PtInRect(mouse, &textRect)){
            InitCursor();
            RectRgn(specialRgn, &textRect);
            }
            }
            CopyRgn(specialRgn, region);
        } else {                                            /* outside */
            
            InitCursor();
            /* make a region that's everything _but_ our windows vis region */
            /* Uhhh, I was asking for the gray region here, but that doesn't */
            /* include the menu bar, so you really do need to go full open */
            SetRectRgn(region, kExtremeNeg, kExtremeNeg,
                                  kExtremePos, kExtremePos);
            DiffRgn(region, specialRgn, region);
        }
        /* get rid of our local regions */
        DisposeRgn(specialRgn);
    }
}
 
/* end AdjustCursor*/
 
Boolean CompareFSSpecs(FSSpecPtr spec1,FSSpecPtr spec2)
{
    Boolean returnVal = false;
    
    if((spec1->vRefNum == spec2->vRefNum) && (spec1->parID == spec2->parID) && (EqualString(&spec1->name,&spec2->name,false,false)))
        returnVal = true;
    return(returnVal);
}
 
void SpinCursor(void)
{
    static short cID = kBaseMadFred;
    SetCursor(*GetCursor(cID));
    cID++;
    if(cID > 137)cID = kBaseMadFred;
}
 
Boolean IsMyWindow(WindowPtr theWind)
{
    return((((WindowPeek)theWind)->windowKind == kAEStatusWindow) || (((WindowPeek)theWind)->windowKind == kClipboardWindow) || (((WindowPeek)theWind)->windowKind == kDocumentWindow));
}
 
Boolean IsModalFront(void)
{
    Boolean retVal = false;
    WindowPtr theWindow = FrontWindow();
    #define peekit ((WindowPeek)theWindow)->windowKind
    if(peekit == plainDBox || peekit == altDBoxProc || peekit == movableDBoxProc)
        retVal = true;
    #undef peekit
    return(retVal); 
}
 
#undef __GUTILS__