ScrollBars.c

/*
    File:       ScrollBars.c
 
    Contains:   List Manager stuff and associated routines
 
    Written by: Chris White 
 
    Copyright:  Copyright © 1996-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
                
 
*/
 
 
#pragma segment Core
 
 
// System Includes
 
 
 
// Application Includes
 
#ifndef __BAREBONES__
    #include "BareBones.h"
#endif
 
 
#ifndef __PROTOTYPES__
    #include "Prototypes.h"
#endif
 
 
 
 
 
static ControlRef   gControl;
static SInt32       gValueSlop;
static SInt32       gSaveValue;
static SInt32       gStartValue;
static RgnHandle    gSaveClip = nil;
 
 
 
static SInt32   CalcValueFromPoint ( ControlRef theControl, Point thePoint );
static void     DisableDrawing ( void );
static void     EnableDrawing ( void );
 
 
 
 
 
OSErr BeginThumbTracking ( ControlRef theControl )
{
    const SInt32 kMinLowMem = 512;
    
    OSErr   theErr = noErr;
    Size    theGrow;
    Point   thePoint;
    
    gControl = theControl;
    gStartValue = GetControlValue ( theControl );
    
    gValueSlop = 0;
    GetMouse ( &thePoint );
    gValueSlop = GetControlValue ( theControl ) - CalcValueFromPoint ( theControl, thePoint );  
    
    // Preflight memory for call to NewRgn
    if ( MaxMem ( &theGrow ) < kMinLowMem )
    {
        theErr = memFullErr;
        goto CleanupAndBail;
    }
    gSaveClip = NewRgn ( );
    
    DisableDrawing ( );
    
CleanupAndBail:
    // Don't have to do any cleanup here
    
    return theErr;
}
 
    
 
void EndThumbTracking ( void )
{
    EnableDrawing ( );
    
    DisposeRgn ( gSaveClip );
    SetControlValue ( gControl, gSaveValue );
    
    return;
}
 
 
 
pascal void ScrollThumbActionProc ( void )
{
    SInt32          theValue;
    WindowRef       theWindow;
    ControlRef      theControl = gControl;
    Point           thePoint;
    Rect            theRect;
    tWindowInfoPtr  theInfo;
    
    
    theWindow = (*theControl)->contrlOwner;
    theInfo = (tWindowInfoPtr) GetWRefCon ( theWindow );
    
    #if DEBUGGING
    if ( theInfo == nil ) DebugStr ( "\p theInfo == nil" );
    #endif
    
    theRect = (*theControl)->contrlRect;
    if ( theControl == theInfo->hScrollBar )
        InsetRect ( &theRect, -kThumbTrackLengthSlop, -kThumbTrackWidthSlop );
    else
        InsetRect ( &theRect, -kThumbTrackWidthSlop, -kThumbTrackLengthSlop );
    
    // Assumes the port is correctly set up
    GetMouse ( &thePoint );
    if ( PtInRect ( thePoint, &theRect ) )
        theValue = CalcValueFromPoint ( theControl, thePoint );
    else
        theValue = gStartValue;
    
    if ( theValue != GetControlValue ( theControl ) )
    {
        EnableDrawing ( );
        
        gSaveValue = theValue;
        SetControlValue ( theControl, theValue );
        UpdateWindowContent ( theWindow );
        
        DisableDrawing ( );
        
    }
    
    return;
}
 
 
 
pascal void ScrollControlActionProc ( ControlRef theControl, SInt16 thePart )
{
    WindowRef       theWindow;
    tWindowInfoPtr  theInfo;
    SInt32          theValue,
                    theDistance,
                    limitValue;
    
    
    theWindow = (*theControl)->contrlOwner;
    theInfo = (tWindowInfoPtr) GetWRefCon ( theWindow );
    
    #if DEBUGGING
    if ( theInfo == nil ) DebugStr ( "\p theInfo == nil" );
    #endif
    
    
    switch ( thePart )
    {
        case kControlUpButtonPart:
        case kControlDownButtonPart:
            theDistance = 10;
        break;
            
        case kControlPageUpPart:
        case kControlPageDownPart:
            if ( theControl == theInfo->hScrollBar )
                theDistance = (theWindow->portRect.right - theWindow->portRect.left)
                                                - kScrollBarWidth - kPageOverlap;
            else
                theDistance = (theWindow->portRect.bottom - theWindow->portRect.top)
                                                - kScrollBarWidth - kPageOverlap;
        break;
    }
    
    theValue = GetControlValue ( theControl );
    
    switch ( thePart )
    {
        case kControlUpButtonPart:
        case kControlPageUpPart:
            limitValue = GetControlMinimum ( theControl );
            if ( theValue - theDistance < limitValue )
                theValue = limitValue;
            else
                theValue -= theDistance;
        break;
                
        case kControlDownButtonPart:
        case kControlPageDownPart:
            limitValue = GetControlMaximum ( theControl );
            if ( theValue + theDistance > limitValue )
                theValue = limitValue;
            else
                theValue += theDistance;
        break;
    }
    
    SetControlValue ( theControl, theValue );
    UpdateWindowContent ( theWindow );
    
    return;
}
 
 
 
static SInt32 CalcValueFromPoint ( ControlRef theControl, Point thePoint )
{
    SInt32          theValue,
                    theRange,
                    theDistance,
                    thePin;
    Rect            theRect;
    WindowRef       theWindow;
    tWindowInfoPtr  theInfo;
    
    
    theWindow = (*theControl)->contrlOwner;
    theInfo = (tWindowInfoPtr) GetWRefCon ( theWindow );
    
    #if DEBUGGING
    if ( theInfo == nil ) DebugStr ( "\p theInfo == nil" );
    #endif
        
    theRect = (*theControl)->contrlRect;
    theRange = GetControlMaximum ( theControl ) - GetControlMinimum ( theControl );
    if ( theControl == theInfo->vScrollBar )
    {
        // Scroll distance adjusted for scroll arrows and the thumb
        theDistance = theRect.bottom - theRect.top - kTotalWidthAdjust;
        
        // Pin thePoint to the middle of the thumb
        thePin = theRect.top + (kTotalWidthAdjust / 2);
        
        theValue = ((thePoint.v - thePin) * theRange) / theDistance;
    }
    else
    {
        // Scroll distance adjusted for scroll arrows and the thumb
        theDistance = theRect.right - theRect.left - kTotalWidthAdjust;
        
        // Pin thePoint to the middle of the thumb
        thePin = theRect.left + (kTotalWidthAdjust / 2);
        
        theValue = ((thePoint.h - thePin) * theRange) / theDistance;
    }
    
    theValue += gValueSlop;
    
    
    if ( theValue < GetControlMinimum ( theControl ) )
        theValue = GetControlMinimum ( theControl );
    else if ( theValue > GetControlMaximum ( theControl ) )
        theValue = GetControlMaximum ( theControl );
    
    return theValue;
}
 
 
 
static void DisableDrawing ( void )
{
    Rect    nullRect = { 0, 0, 0, 0 };
 
    GetClip ( gSaveClip );
    ClipRect ( &nullRect );
    
    return;
}
 
 
 
static void EnableDrawing ( void )
{
    SetClip ( gSaveClip );
    
    return;
}