CalcControlRgn.c

/*
    File:       Calc ControlRgn.c
 
    Contains:   This sample shows how to call a CDEF to get the control's Region.
 
    Written by: Matthew Xavier Mora 
 
    Copyright:  Copyright © 1995-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):
                7/19/1999   Karl Groethe    Updated for Metrowerks Codewarror Pro 2.1
                02-28-96    mxm             added more comments and error checking
                05-07-96    mxm             got it ready for the cd
                
 
*/
 
#include <Resources.h>
#include <Errors.h>
#include <Windows.h>
 
#include "SAL_Public.h"
 
#define kPaintRegionOffset  ( 200 ) 
#define kNoOffset           ( 0 )
#define kNextButtonOffset   ( 50 )
#define kScrollBarFudge     ( 15 )
#define kMemorySystemErrMsg "\pMemory Manager error"
#define kOurWindowTitle     "\pCalculate a Control's Region Sample"
#define kBadThingsMsg       "\pBad things happened"
 
 pascal SInt16 DoButtonHit(ButtonItemRef me, SInt32  modifiers);
 
 
//-------------------------------------------------------------------------
// This function checks MemError and reports any errors returned
//-------------------------------------------------------------------------
    static OSErr CheckMemoryError(void)
//-------------------------------------------------------------------------
{
    OSErr   err;
    
    err = MemError();
    if (err) {
        SAL_ErrorMessage(kMemorySystemErrMsg,err,kSAL_NonFatalError);
    }   
    return err;
}
 
//-------------------------------------------------------------------------
// A utility routine to lock a Handle and report any errors. It returns the 
// the state of the handle before it was locked so you can reset the handle
// to its original state.
//-------------------------------------------------------------------------
    static OSErr MyLockHandle(Handle theHandle,SInt8 * state)
//-------------------------------------------------------------------------
{
    OSErr   err = noErr;
    SInt8   tempState;
    
    tempState = HGetState(theHandle);                   // remember the state
    err = CheckMemoryError();                           // alert the user if error
    if (err == noErr) {
        HLock(theHandle);
        err = CheckMemoryError();
    }   
    if (state) {
        *state = tempState;
    }
    return err;
}
 
//-------------------------------------------------------------------------
// A utility routine to Set a Handle state and report any errors. 
//-------------------------------------------------------------------------
    static OSErr MySetHandleState(Handle theHandle,SInt8  state)
//-------------------------------------------------------------------------
{
    OSErr   err = noErr;
    
    HSetState(theHandle,state);                 // remember the state
    err = CheckMemoryError();                   // report any errors
    return err;                                 // return error
}
 
//-------------------------------------------------------------------------
// GetControlRgn takes a control handle and an existing Rgn
// as parameters and will return in the control's rgn   
//------------------------------------------------------------------------- 
    pascal  OSStatus GetControlRegion(ControlHandle ch,ControlPartCode  inPart,RgnHandle theRgn)
//-------------------------------------------------------------------------
{
    #pragma unused(inPart)
    Handle          cdefHandle;                             // Handle to the control Proc
    SInt16          errorState = noErr ;                    // preset error state
 
    if ( (ch != nil) && (theRgn != nil) ) {                 // make sure we have a control and Rgn
        cdefHandle = (**ch).contrlDefProc;                  // Get the control's Handle
        if (!*cdefHandle) {                                 // lets load it in if its not 
            LoadResource(cdefHandle);   
            errorState = ResError();                        // check for error
        }
        if ((*cdefHandle) != nil && errorState == noErr ) { // all is well
            SInt8   state ;                                 // holding place for handle state
            errorState = MyLockHandle(cdefHandle,&state);   
            if (errorState == noErr) {
                UInt32          result;                     // the result we don't care about
                ControlDefUPP   myControlUPP;               // Holding place for the CDEF ProcPtr or UPP
                                                            //
                myControlUPP = (ControlDefUPP)(*cdefHandle); 
                // What? Casting to a UPP? Are you crazy?
                // The reason you cast in instead of creating a UPP
                // is that it may already be a UPP (ie native CDEF) 
                // and dual UPP's would really confuse Mixed Mode. If its not
                // a upp, CallControlDefProc does the right thing by passing a 
                // a valid ProcInfo to CallUniversalProc which makes
                // mixed mode a happy camper in any case.  
                result = CallControlDefProc(myControlUPP,
                                            GetControlVariant(ch),
                                            ch,
                                            calcCntlRgn,
                                            (SInt32)theRgn);
                errorState = MySetHandleState(cdefHandle,state); // reset the handle state
            }
        }
    } else {                                                // ControlHandle or theRgn is nil                                               
        errorState  = nilHandleErr;                         // set the error
    }
    return (errorState);                                    // be sure and return any errors
}
 
//-------------------------------------------------------------------------
// Simple routine to paint the region we get from the Control
//-------------------------------------------------------------------------
    static  OSErr DisplayControlRgn(ControlHandle ch)
//-------------------------------------------------------------------------
{
    RgnHandle   theRgn;
    SInt16      err = noErr;
 
    theRgn = NewRgn();                      // Get a region to work with
    if (theRgn) {
        err = GetControlRegion(ch,0,theRgn);    // Get the Button's Region
        if (err == noErr){          
            OffsetRgn(theRgn,kPaintRegionOffset,kNoOffset);     
            PaintRgn(theRgn);
            DisposeRgn(theRgn);
        } else {
           err = CheckMemoryError();
        }
    }
    return (err);
}
 
 
//-------------------------------------------------------------------------
// This gets called when the Click Me button is clicked.
// ------------------------------------------------------------------------
// Note!
// There is a problem with global optimization and call back functions.
// If you want global optimization on for the rest of your code you
// should turn it off for any call back functions unless MW has released
//  a fix. i.e #pragma optimization_level 1
//-------------------------------------------------------------------------
static pascal short DoButtonHit(const ButtonItemRef me,const  long  modifiers)
//-------------------------------------------------------------------------
{
#pragma unused (modifiers)
 
    ControlHandle   cr  = nil;
    OSErr       err = noErr;
    
    cr = (ControlHandle) SAL_GetObjectHandle((SInt32) me);  
    if (cr) {
        err = DisplayControlRgn(cr);
        if (err != noErr) {
            SAL_ErrorMessage(kBadThingsMsg,err,kSAL_NonFatalError);
        }
    }
    return err;
}
 
//-------------------------------------------------------------------------
// This gets called when the Clear button is clicked.
//-------------------------------------------------------------------------
static pascal SInt16 DoClear(const ButtonItemRef me,const SInt32  modifiers)
//-------------------------------------------------------------------------
{
#pragma unused (modifiers)
#pragma unused (me)
    Rect r;
    
    r = gSAL_CurrentWindow->portRect;           // Get the window's portRect
    r.left   += kPaintRegionOffset;             // offset so it doesn't erase
    r.right  -= kScrollBarFudge;                // our buttons and scroll bar
    r.bottom -= kScrollBarFudge;                // areas
    InvalRect(&r);                               
    return noErr;                               
}
 
//-------------------------------------------------------------------------
// This is the main function. Note how simple it is. It installs
// two Buttons and then lets SimpleApp handle the rest. 
// 
//-------------------------------------------------------------------------
    void main(void)
//-------------------------------------------------------------------------
{
    Rect    r;
    SInt16  gMyWindowID;
    SInt16  err;
    
    SAL_InitSimpleApp(1,kSAL_UseStandardMenu);  // Simple App Sets up the Tool Box For us 
    gMyWindowID = SAL_GetDocumentWindow(128,nil); // Get our stored window 
                                                // the global gSAL_CurrentWindow is maintained
                                                // by SimpleApp and it contains the active
                                                // document window reference
    SetWTitle(gSAL_CurrentWindow,kOurWindowTitle);// set the window title so we know what we are running
    SetRect(&r,10,30,100,50);                   // set the control bounds
    err = SAL_InstallPushButton (0,             // Reference ID (we don't care)
                             gSAL_CurrentWindow,    // Owner Window 
                             "\pClick Me",      // Name
                             &r,                // Bounds                       
                             kSAL_NoCommandKey, // Command Key
                             DoButtonHit ,      // Button Hit 
                             nil                // Button Update Proc 
                             );
    OffsetRect(&r,kNoOffset,kNextButtonOffset);                      
    err = SAL_InstallPushButton (0,             // Reference ID (we don't care)
                             gSAL_CurrentWindow,    // Owner Window
                             "\pClear",         // Name
                             &r,                // Bounds                       
                             kSAL_NoCommandKey, // Command Key
                             DoClear ,          // Button Hit Proc
                             nil                // Button Update Proc
                             );
    SAL_Run();                                  // Let SimpleApp handle the rest
}