home *** CD-ROM | disk | FTP | other *** search
/ Celestin Apprentice 5 / Apprentice-Release5.iso / Source Code / PowerPlant / AGA Slider 1.0 / Sources / CAGASlider.cp < prev    next >
Encoding:
Text File  |  1996-06-25  |  18.4 KB  |  687 lines  |  [TEXT/CWIE]

  1. //
  2. //    CAGASlider.cp
  3. //
  4. //    Apple Grayscale Appearance Slider class for PowerPlant
  5. //    Subclassed from LControl
  6. //
  7. //    version 1.0 - June 25, 1996
  8. //
  9. //    Copyright © 1996 by James Jennings. All rights reserved.
  10. //
  11.  
  12. //    A thought: 
  13. // We can replace mIsTracking with IsTracking() { return GetValue() != mTrackingValue; }
  14.  
  15. #include "CAGASlider.h"
  16. #include <UGWorld.h>
  17.  
  18. // constants that control the geometry of the slider
  19. static const Int16 kEndMargin = 10;        // where the indicator stops.
  20. static const Int16 kFlatMargin = 4;        // margin on the flat side on an indicator
  21. static const Int16 kPointMargin = 6;    // margin on the pointy side--not including tickmarks
  22. static const Int16 kTrackWidth = 5;        // width of the indicator's track
  23. static const Int16 kOffsideCutoff = 24;    // abort by dragging this far from control
  24. static const Int16 kTrackToTick = 10;    // center of track to start of tick mark
  25. static const Int16 kTickLen = 6;        // length of tick mark
  26. static const Int16 kIndSize = 16;        // size of indicator image
  27. static const Int16 kDepthCutoff = 4;// 4 or 8. The screen depth to start grayscale drawing.
  28.  
  29. // If there are no tick marks, the slider is 16 pixels wide.
  30. // If there are tick marks, the slide is approximately...
  31. //const Int16 kSliderWidth = kFlatMargin+kTrackWidth+kTrackToTick+kTickLen; // = 25 pixels
  32.  
  33. // Class variables for holding the indicator image data.
  34. LGWorld    *    CAGASlider::sColorData = 0;
  35. LGWorld    *    CAGASlider::sBlackAndWhiteData = 0;
  36. LGWorld    *    CAGASlider::sMaskData = 0;
  37. const Rect         kPICTDataSize = { 0, 0, 6*kIndSize, 4*kIndSize };
  38. const ResIDT    k8BitPICTid = 1000;
  39. const ResIDT    k1BitPICTid = 1001;
  40. const ResIDT    kMaskPICTid = 1002;
  41.  
  42. CAGASlider*    CAGASlider::CreateFromStream(LStream *inStream)
  43. {
  44.     return new CAGASlider( inStream );
  45. }
  46.  
  47. CAGASlider::CAGASlider(LStream *inStream)
  48.     : LControl( inStream ), mState(ind_Enabled), mContinuousBroadcast(true),
  49.       mIsTracking(false), mTrackingValue(0)
  50. {
  51.     Int32 directionCode;
  52.     inStream->ReadBlock( &directionCode, sizeof(directionCode) );
  53.     
  54.     // Convert the entered code to the enumerated type
  55.     switch ( directionCode ) {
  56.     case 'hori':    mDirection = ind_Horizontal;    break;
  57.     case 'vert':    mDirection = ind_Vertical;        break;
  58.     case 'nort':    mDirection = ind_North;            break;
  59.     case 'sout':    mDirection = ind_South;            break;
  60.     case 'east':    mDirection = ind_East;            break;
  61.     case 'west':    mDirection = ind_West;            break;
  62.     default:    // anything else (like 'prop'), base on the proportions of the pane
  63.         SDimension16 theSize;
  64.         GetFrameSize( theSize );
  65.         if ( theSize.width > theSize.height ) mDirection = ind_Horizontal;
  66.         else mDirection = ind_Vertical;
  67.         break;
  68.     }
  69.     
  70.     // If mNumberOfTicks = 0, don't display any tick marks
  71.     // If mNumberOfTicks = 1, display one tick mark per value
  72.     // If mNumberOfTicks > 1, then mNumberOfTicks is the number of tickmarks (intervals + 1)
  73.     inStream->ReadBlock( &mNumberOfTicks, sizeof(mNumberOfTicks) );
  74.     
  75.     // mContinuousBroadcast = true -> broadcast change everytime the indicator moves
  76.     // mContinuousBroadcast = false -> wait for mouseUp
  77.     inStream->ReadBlock( &mContinuousBroadcast, sizeof(mContinuousBroadcast) );
  78.     
  79.     // do we need this line?
  80. //    mState = ( (mEnabled != triState_Off) ? ind_Enabled : ind_Disabled);
  81. }
  82.  
  83. CAGASlider::~CAGASlider()
  84. {
  85.  
  86. }
  87.  
  88. void CAGASlider::DrawSelf(void)
  89. {
  90.     Rect theFrame, r;
  91.     CalcLocalFrameRect( theFrame );
  92.     
  93.     StDeviceLoop devices(theFrame);
  94.     Int16 depth;
  95.  
  96.     while (devices.NextDepth(depth)) {
  97.     
  98.         Boolean useGrays = (depth >= kDepthCutoff);
  99.         
  100.         // find the overlap between the frame and the current device
  101.         r = (*devices.GetCurrentDevice())->gdRect;
  102.         ::GlobalToLocal(&topLeft(r));
  103.         ::GlobalToLocal(&botRight(r));
  104.         if ( !::SectRect( &theFrame, &r, &r ) ) continue;
  105.         
  106.         // Use an offscreen world to avoid flickering
  107.         StOffscreenGWorld offscreen( r );
  108.         
  109.         DrawSelfBasic(useGrays);
  110.             
  111.     }
  112. }
  113.  
  114. void CAGASlider::DrawSelfBasic( Boolean useGrays )
  115. {
  116.     StColorPenState::Normalize();
  117.     Rect theFrame;
  118.     CalcLocalFrameRect( theFrame );
  119.     
  120.     EIndicatorState theState = ( IsEnabled() ? mState : ind_Disabled );
  121.     
  122.     EraseRect( theFrame );
  123.     
  124.     DrawTrack( theState, useGrays );
  125.     DrawTickMarks( mNumberOfTicks, theState, useGrays );
  126.     DrawIndicator( GetValue(), theState, useGrays );
  127.     
  128.     if ( mIsTracking && (GetValue() != mTrackingValue) )
  129.         DrawIndicator( mTrackingValue, ind_Ghost, useGrays );
  130. }
  131.  
  132. void CAGASlider::DrawTrack( EIndicatorState inState, Boolean inUseGrays )
  133. {
  134.     StColorPenState::Normalize();
  135.     
  136.     Rect r;
  137.     GetTrackRect( r );
  138.     
  139.     const Int16 kRoundness = 4;
  140.     
  141.     // Colors depend on inState
  142.     EGAColor black, gray;
  143.     if ( inState == ind_Disabled ) {
  144.         gray = ga_4;
  145.         black = ga_8;
  146.     } else {
  147.         gray = ga_5;
  148.         black = ga_Black;
  149.     }
  150.     
  151.     if ( inUseGrays ) {
  152.         r.bottom++;
  153.         r.right++;
  154.         SetForeColor( ga_White );
  155.         ::PaintRoundRect( &r, kRoundness, kRoundness );
  156.         
  157.         ::OffsetRect( &r, -1, -1 );
  158.         SetForeColor( gray );
  159.         ::PaintRoundRect( &r, kRoundness, kRoundness );
  160.         
  161.         SetForeColor( black );
  162.         r.top++;
  163.         r.left++;
  164.     }
  165.     ::FrameRoundRect( &r, kRoundness, kRoundness );
  166. }
  167.  
  168. void CAGASlider::DrawIndicator( Int32 inValue, EIndicatorState inState, Boolean inUseGrays )
  169. {
  170.     // where to draw it
  171.     Rect r;
  172.     ValueToIndicatorRect( inValue, r );
  173.     
  174.     //Commented out old version of the code: It didn't work in all cases.
  175.     //ResIDT    icon = ind_First_ics8_ID + inDirection * ind_StateOffset + inState;
  176.     //DrawIcon1( r, icon, inUseGrays ); break;
  177.     
  178.     DrawIcon( r, mDirection, inState, inUseGrays );
  179. }
  180.  
  181. /*
  182.     DrawIcon1() was my prefered method of drawing the indicator.
  183.     It did not work on all monitors on all machines.
  184.     Is there a bug in the PPC version of the Toolbox code?
  185.     
  186. void    CAGASlider::DrawIcon1( Rect inWhere, ResIDT inWhich, Boolean inUseGrays )
  187. {
  188.     OSErr anErr;
  189.     // PlotIconID() needs a 16x16 rectangle.
  190.     inWhere.bottom = inWhere.top + kIndSize;
  191.     inWhere.right = inWhere.left + kIndSize;
  192.     
  193.     anErr = ::PlotIconID( &inWhere, atNone, ttNone, inWhich );
  194.     ThrowIfOSErr_( anErr );
  195. }
  196. */
  197.  
  198. void    CAGASlider::DrawIcon( Rect inWhere, EIndicatorDirection inDirection, 
  199.                             EIndicatorState inState, Boolean inUseGrays )
  200. {    // draw the indicator out of a PICT
  201.     OSErr anErr;
  202.     // PlotIconID() needs a 16x16 rectangle.
  203.     inWhere.bottom = inWhere.top + kIndSize;
  204.     inWhere.right = inWhere.left + kIndSize;
  205.  
  206.     // we initialize the data we need (only does something on the first call)
  207.     if ( inUseGrays ) InitColorData();
  208.     else InitBlackAndWhiteData();
  209.     
  210.     GWorldPtr imageWorld = (inUseGrays ? sColorData : sBlackAndWhiteData )->GetMacGWorld();
  211.     GWorldPtr maskWorld = sMaskData->GetMacGWorld();
  212.     Assert_( imageWorld != nil && maskWorld != nil );
  213.     
  214.     PixMapHandle image = ::GetGWorldPixMap( imageWorld );
  215.     PixMapHandle mask  = ::GetGWorldPixMap( maskWorld );
  216.     ThrowIfNil_( image );
  217.     ThrowIfNil_( mask );
  218.     
  219.     Boolean notPurged;
  220.     notPurged = ::LockPixels( image );
  221.     notPurged = ::LockPixels( mask );
  222.     
  223.     Rect r = {0,0,kIndSize,kIndSize};
  224.     Rect maskRect = r;
  225.     ::OffsetRect( &r, inState * kIndSize, inDirection * kIndSize );
  226.     ::OffsetRect( &maskRect, 0, inDirection * kIndSize );
  227.     
  228.     GrafPtr thePort;
  229.     ::GetPort( & thePort );
  230.     
  231.     ::ForeColor( blackColor );
  232.     ::BackColor( whiteColor );
  233.     //    ::CopyMask( srcBits, maskBits, dstBits, srcRect, maskRect, dstRect );
  234.     ::CopyMask( (BitMapPtr)*image, (BitMapPtr)*mask, &(thePort->portBits), 
  235.                     &r, &maskRect, &inWhere );
  236.     
  237.     ::UnlockPixels( image );
  238.     ::UnlockPixels( mask );
  239. }
  240.  
  241. void    CAGASlider::InitColorData()
  242. {
  243.     InitMaskData();
  244.     
  245.     if ( sColorData != nil ) return;
  246.     
  247.     sColorData = new LGWorld( kPICTDataSize, 8 );
  248.     ThrowIfNil_( sColorData );
  249.     
  250.     InitPICTDataHelper( sColorData, k8BitPICTid, kPICTDataSize );
  251. }
  252.  
  253. void    CAGASlider::InitBlackAndWhiteData()
  254. {
  255.     InitMaskData();
  256.     
  257.     if ( sBlackAndWhiteData != nil ) return;
  258.     
  259.     sBlackAndWhiteData = new LGWorld( kPICTDataSize, 1 );
  260.     ThrowIfNil_( sBlackAndWhiteData );
  261.     
  262.     InitPICTDataHelper( sBlackAndWhiteData, k1BitPICTid, kPICTDataSize );
  263. }
  264.  
  265. void    CAGASlider::InitMaskData()
  266. {
  267.     if ( sMaskData != nil ) return;
  268.     
  269.     Rect r = kPICTDataSize;
  270.     r.right = r.left + kIndSize;
  271.     sMaskData = new LGWorld( r, 1 );
  272.     ThrowIfNil_( sMaskData );
  273.     
  274.     InitPICTDataHelper( sMaskData, kMaskPICTid, r );
  275. }
  276.  
  277. void    CAGASlider::InitPICTDataHelper( LGWorld *inWorld, const ResIDT inPICT, const Rect inRect )
  278. {
  279.     PicHandle aPicH = ::GetPicture( inPICT );
  280.     ThrowIfNil_( aPicH );
  281.     
  282.     inWorld->BeginDrawing();
  283.     ::DrawPicture( aPicH, &inRect );
  284.     inWorld->EndDrawing();
  285.     
  286.     ::ReleaseResource( (Handle)aPicH );
  287. }
  288.  
  289. void    CAGASlider::DrawTickMarks( UInt16 inNumber, EIndicatorState inState, Boolean inUseGrays )
  290. {
  291.     if ( inNumber == 0 ) return;
  292.     if ( inNumber == 1 ) inNumber = mMaxValue - mMinValue + 1;
  293.     if ( inNumber <= 1 ) return;
  294.     Assert_ ( mDirection != ind_Horizontal && mDirection != ind_Vertical );
  295.     
  296.     Rect theTrack;
  297.     GetTrackRect( theTrack );
  298.     
  299.     // Calculate the first tick mark rect, and the last tick mark position
  300.     Rect firstTick;
  301.     Point p = ValueToPosition( mMinValue );    // pos of 1st tick
  302.     Point q = ValueToPosition( mMaxValue );    // pos of last tick
  303.     switch ( mDirection ) {    // SetRect( r, left, top, right, bottom ), SetPt( p, h, v )
  304.     case ind_North:
  305.         p.v -= kTrackToTick + kTickLen + 1;
  306.         q.v -= kTrackToTick + kTickLen + 1;
  307.         ::SetRect( &firstTick, p.h, p.v, p.h + 1, p.v + kTickLen );
  308.         break;
  309.     case ind_South:
  310.         p.v += kTrackToTick;
  311.         q.v += kTrackToTick;
  312.         ::SetRect( &firstTick, p.h, p.v, p.h + 1, p.v + kTickLen );
  313.         break;
  314.     case ind_East:
  315.         p.h += kTrackToTick;
  316.         q.h += kTrackToTick;
  317.         ::SetRect( &firstTick, p.h, p.v, p.h + kTickLen, p.v + 1 );
  318.         break;
  319.     case ind_West:
  320.         p.h -= kTrackToTick + kTickLen + 1;
  321.         q.h -= kTrackToTick + kTickLen + 1;
  322.         ::SetRect( &firstTick, p.h, p.v, p.h + kTickLen, p.v + 1 );
  323.         break;
  324.     case ind_Horizontal:
  325.     case ind_Vertical:
  326.     default:
  327.         SignalPStr_("\pBad Slider Class Member");
  328.     }
  329.     
  330.     Int32 intervals = inNumber - 1;
  331.     Assert_( intervals > 0 );
  332.     for( Int32 i = 0; i <= intervals; i++ ) {
  333.     
  334.         Int16 deltah = (q.h - p.h) * i / intervals;
  335.         Int16 deltav = (q.v - p.v) * i / intervals;
  336.         Rect r = firstTick;
  337.         ::OffsetRect( &r, deltah, deltav );
  338.         
  339.         if ( inUseGrays ) {
  340.         
  341.             // Colors depend on inState
  342.             EGAColor black, gray;
  343.             if ( inState == ind_Disabled ) {
  344.                 gray = ga_4;
  345.                 black = ga_8;
  346.             } else {
  347.                 gray = ga_7;
  348.                 black = ga_Black;
  349.             }
  350.             
  351.             PaintRect( r, black );
  352.         
  353.             ::InsetRect( &r, -1, -1 );
  354.             FrameRect( r, ga_White, gray, ga_Background );
  355.             
  356.         } else {
  357.         
  358.             ::PaintRect( &r );
  359.             
  360.         }
  361.     }
  362. }
  363.  
  364. CAGASlider::EOrientation CAGASlider::GetOrientation(void)
  365. {
  366.     EOrientation theResult;
  367.     switch ( mDirection ) {
  368.     case ind_Horizontal:
  369.     case ind_North:
  370.     case ind_South:
  371.         theResult = orient_Horizontal;
  372.         break;
  373.     case ind_Vertical:
  374.     case ind_East:
  375.     case ind_West:
  376.         theResult = orient_Vertical;
  377.         break;
  378.     default:
  379.         SignalPStr_("\pBad Slider Class Member");
  380.     }
  381.     return theResult;
  382. }
  383.  
  384. void CAGASlider::ValueToIndicatorRect( Int32 inValue, Rect &outRect )
  385. {
  386.     Point center = ValueToPosition( inValue );
  387.     
  388.     switch ( mDirection ) {
  389.     case ind_Horizontal:
  390.         //    SetRect() arguments are: Rect*, left, top, right, bottom
  391.         ::SetRect( &outRect, center.h - 6, center.v - 8, center.h + 7, center.v + 8 );
  392.         break;
  393.     case ind_North:
  394.         ::SetRect( &outRect, center.h - 7, center.v -10, center.h + 8, center.v + 6 );
  395.         break;
  396.     case ind_South:
  397.         ::SetRect( &outRect, center.h - 7, center.v - 7, center.h + 8, center.v + 9 );
  398.         break;
  399.     case ind_Vertical:
  400.         ::SetRect( &outRect, center.h - 8, center.v - 6, center.h + 8, center.v + 7 );
  401.         break;
  402.     case ind_East:
  403.         ::SetRect( &outRect, center.h - 7, center.v - 7, center.h + 9, center.v + 8 );
  404.         break;
  405.     case ind_West:
  406.         ::SetRect( &outRect, center.h -10, center.v - 7, center.h + 6, center.v + 8 );
  407.         break;
  408.     default:
  409.         SignalPStr_("\pBad Slider Class Member");
  410.     }
  411. }
  412.  
  413. Point    CAGASlider::ValueToPosition( Int32 inValue )
  414. {    // find the position of the center of the indicator that corresponds to inValue
  415.     Point p;    // the result
  416.     
  417.     Assert_( mMinValue <= inValue && inValue <= mMaxValue );
  418.     
  419.     Int16 valueRange = mMaxValue - mMinValue;
  420.     Int16 pixelRange;
  421.     
  422.     // Handle special case to avoid a divide by zero later.
  423.     if ( valueRange <= 0 ) {
  424.         inValue = mMinValue;
  425.         valueRange = 1;
  426.     }
  427.     
  428.     Rect theTrack;
  429.     GetTrackRect( theTrack );
  430.     
  431.     // Non-pointy indicators (which have no tick marks) aren't as 
  432.     // wide, so we adjust the placement.
  433.     Int16 margin = kEndMargin;
  434.     if ( mDirection == ind_Horizontal || mDirection == ind_Vertical ) margin--;
  435.     
  436.     switch( GetOrientation() ) {
  437.     case orient_Horizontal:
  438.         theTrack.right--;    // aesthetic adjustments
  439.         theTrack.bottom++;
  440.         pixelRange = theTrack.right - theTrack.left - 2*margin;
  441.         p.h = theTrack.left + margin + 
  442.                 pixelRange * (inValue - mMinValue) / valueRange;
  443.         p.v = ( theTrack.top + theTrack.bottom )/2;
  444.         break;
  445.     case orient_Vertical:
  446.         theTrack.bottom--;    // aesthetic adjustments
  447.         theTrack.right++;
  448.         pixelRange = theTrack.bottom - theTrack.top - 2*margin;
  449.         p.v = theTrack.top + margin + 
  450.                 pixelRange * (inValue - mMinValue) / valueRange;
  451.         p.h = ( theTrack.right + theTrack.left )/2;
  452.         break;
  453.     default:
  454.         SignalPStr_("\pBad Slider Orientation");
  455.         break;
  456.     }
  457.     
  458.     return p;
  459. }
  460.  
  461. Int32    CAGASlider::PositionToValue( Point inPosition )
  462. {
  463.     // Handle special case to avoid a divide by zero later.
  464.     if ( mMaxValue <= mMinValue ) return mMinValue;
  465.     
  466.     Rect theTrack;
  467.     GetTrackRect( theTrack );
  468.     
  469.     // If we move the mouse too far away from the slider, 
  470.     // return the slider's old value (thus aborting the slide).
  471.     Point offside = {0,0};    // number of pixels off to the side of the slider
  472.     
  473.     if ( inPosition.v < theTrack.top )        offside.v = theTrack.top - inPosition.v;
  474.     if ( inPosition.v > theTrack.bottom )    offside.v = inPosition.v - theTrack.bottom;
  475.     if ( inPosition.h < theTrack.left )        offside.h = theTrack.left - inPosition.h;
  476.     if ( inPosition.h > theTrack.right )    offside.h = inPosition.h - theTrack.right;
  477.     
  478.     if ( (offside.h > kOffsideCutoff) || (offside.v > kOffsideCutoff) )
  479.         return GetValue();    // we're "offside" -- return the slider's current value
  480.     
  481.     // Calculate the value.
  482.     
  483.     Int32 offset, range, result;
  484.     
  485.     switch( GetOrientation() ) {
  486.     case orient_Horizontal:
  487.         offset = inPosition.h - theTrack.left - kEndMargin;
  488.         range = theTrack.right - theTrack.left - 2*kEndMargin;
  489.         Assert_( range > 0 );
  490.         break;
  491.     case orient_Vertical:
  492.         offset = inPosition.v - theTrack.top - kEndMargin;
  493.         range = theTrack.bottom - theTrack.top - 2*kEndMargin;
  494.         Assert_( range > 0 );
  495.         break;
  496.     default:
  497.         SignalPStr_("\pBad Slider Orientation");
  498.         break;
  499.     }
  500.     
  501.     // Adjust the offset to center the indicator-value on a tick mark, not between them.
  502.     offset += range / ( mMaxValue - mMinValue ) / 2;
  503.     
  504.     // calculate result
  505.     result = mMinValue + ( mMaxValue - mMinValue ) * offset / range;
  506.     
  507.     // range clipping
  508.     if ( result < mMinValue ) result = mMinValue;
  509.     if ( result > mMaxValue ) result = mMaxValue;
  510.     
  511.     return result;
  512. }
  513.  
  514. void    CAGASlider::GetTrackRect( Rect &outRect )
  515. {    // Calculate the rectange to draw the track into.
  516.     //
  517.     // This is the rect of the small black RoundRect. The white and gray highlights
  518.     // are outside this rect. Try to base all drawing on this rect.
  519.     //
  520.     // The compass direction sliders are pushed to the side of the pane away from the point.
  521.     // The plain sliders are centered.
  522.     
  523.     CalcLocalFrameRect( outRect );
  524.     
  525.     SDimension16 theSize;
  526.     GetFrameSize( theSize );
  527.  
  528.     // Center the track in the frame
  529.     switch ( GetOrientation() ) {
  530.     
  531.     case orient_Horizontal:
  532.         
  533.         switch ( mDirection ) {
  534.         case ind_Horizontal:
  535.             outRect.top += (theSize.height - kTrackWidth)/2;
  536.             break;
  537.         case ind_North:
  538.             outRect.top = outRect.bottom - kFlatMargin - kTrackWidth;
  539.             break;
  540.         case ind_South:
  541.             outRect.top += kFlatMargin;
  542.             break;
  543.         }
  544.         outRect.bottom = outRect.top + kTrackWidth;
  545.         outRect.left++;
  546.         outRect.right--;
  547.         break;
  548.         
  549.     case orient_Vertical:
  550.     
  551.         switch ( mDirection ) {
  552.         case ind_Vertical:
  553.             outRect.left += (theSize.width - kTrackWidth)/2;
  554.             break;
  555.         case ind_East:
  556.             outRect.left += kFlatMargin;
  557.             break;
  558.         case ind_West:
  559.             outRect.left = outRect.right - kFlatMargin - kTrackWidth;
  560.             break;
  561.         }
  562.         outRect.right = outRect.left + kTrackWidth;
  563.         outRect.top++;
  564.         outRect.bottom--;
  565.         break;
  566.     }
  567. }
  568.  
  569. Int16    CAGASlider::FindHotSpot(Point inPoint)    // Rewrite w/o icons !!!
  570. {
  571.     // default is None.
  572.     Int16 result = hot_None;
  573.     
  574.     // Is it in the track?
  575.     Rect r;
  576.     GetTrackRect( r );
  577.     ::InsetRect( &r, -2, -2 );
  578.     
  579.     if ( ::PtInRect( inPoint, &r ) ) result = hot_Track;
  580.     
  581.     // Is it in the indicator? If so, override track.
  582.     ValueToIndicatorRect( GetValue(), r );
  583.     
  584.     // code which relys on the PICT mask
  585.     if ( ::PtInRect( inPoint, &r ) ) {
  586.     
  587.         Point p;
  588.         p.h = inPoint.h - r.left;
  589.         p.v = inPoint.v - r.top + mDirection * kIndSize;
  590.         
  591.         // test the value of the pixel in the mask PICT (is there a toolbox call for this?)
  592.         InitMaskData();
  593.         PixMapHandle pm = ::GetGWorldPixMap( sMaskData->GetMacGWorld() );
  594.         Assert_( pm != nil );
  595.         
  596.         Ptr aPtr = ::GetPixBaseAddr( pm );
  597.         Int16 rowBytes = (*pm)->rowBytes & 0x3FFF;
  598.         aPtr += rowBytes * p.v + (p.h/8);
  599.         
  600.         if ( *aPtr & (1<<(7 - (p.h%8))) ) 
  601.             result = hot_Indicator;
  602.     }
  603.     
  604.     return result;
  605. }
  606.  
  607. Boolean    CAGASlider::PointInHotSpot(Point inPoint, Int16 inHotSpot)
  608. {
  609.     if ( inHotSpot == 0 ) return false;
  610.     
  611.     return ( FindHotSpot( inPoint ) == inHotSpot );
  612. }
  613.  
  614. void    CAGASlider::HotSpotAction(Int16 inHotSpot, Boolean inCurrInside, Boolean inPrevInside)
  615. {    // Not used? Keep it for SimulateHotSpotClick().
  616.     if ( inHotSpot != 1 ) return;    // sanity check
  617.     
  618.     if ( inCurrInside != inPrevInside ) {
  619.         if ( inCurrInside ) mState = ind_Pressed;
  620.         else mState = ind_Enabled;
  621.         Draw( nil );
  622.     }
  623. }
  624.  
  625. void    CAGASlider::HotSpotResult(Int16 inHotSpot)
  626. {
  627.     if (inHotSpot != 1) return;
  628.     
  629.     // done dragging, un-press the indicator
  630.     mState = ind_Enabled;
  631.     Draw( nil );
  632. }
  633.  
  634. Boolean    CAGASlider::TrackHotSpot(Int16 inHotSpot, Point inPoint)
  635. {
  636.     Assert_ ( inHotSpot == hot_Indicator || inHotSpot == hot_Track );
  637.     
  638.     // "Press" the indicator
  639.     mState = ind_Pressed;    // should these be "St" objects?
  640.     mIsTracking = true;
  641.     mTrackingValue = GetValue();
  642.     Draw( nil );
  643.     
  644.     // Track the mouse while it is down
  645.     Point    currPt = inPoint;
  646.     while (StillDown()) {
  647.     
  648.         ::GetMouse(&currPt);
  649.         
  650.         // calculate ghost position
  651.         Int32 currValue = PositionToValue( currPt );
  652.         
  653.         if ( currValue != mTrackingValue ) {
  654.         
  655.             mTrackingValue = currValue;
  656.             Draw( nil );
  657.             
  658.             if ( mContinuousBroadcast ) {
  659.             
  660.                 // this code modified from LControl::BroadcastValueMessage()
  661.                 if (mValueMessage != msg_Nothing) {
  662.                     Int32    value = mTrackingValue;    // broadcast tracking value
  663.                     BroadcastMessage(mValueMessage, (void*) &value);
  664.                 }
  665.                 
  666.             }
  667.             
  668.         }
  669.     }
  670.     
  671.     mState = ind_Enabled;
  672.                                     // Check if MouseUp occurred in HotSpot
  673.     EventRecord    macEvent;            // Get location from MouseUp event
  674.     if (::GetOSEvent(mUpMask, &macEvent)) {
  675.         currPt = macEvent.where;
  676.         ::GlobalToLocal(&currPt);
  677.         mTrackingValue = PositionToValue( currPt );
  678.     }
  679.     
  680.     SetValue( mTrackingValue );    // SetValue() calls BroadcastValueMessage()
  681.     Draw( nil );
  682.     
  683.     mIsTracking = false;
  684.     
  685.     return true;    // tell caller that mouse was released in hot-spot
  686. }
  687.