home *** CD-ROM | disk | FTP | other *** search
/ Celestin Apprentice 4 / Apprentice-Release4.iso / Source Code / C / Code Resources / Jims CDEFs 1.50 / CDEF Source / source / cdefSlider.c < prev    next >
Encoding:
Text File  |  1995-11-08  |  27.3 KB  |  931 lines  |  [TEXT/KAHL]

  1. //------------------------- © 1995 by James G. Stout -------------------------------
  2. //    File    : cdefSlider.c
  3. //    Date    : April 8, 1995
  4. //    Author    : Jim Stout
  5. //            :
  6. //    Purpose    : A slider CDEF. This supports several appearances via variation codes.
  7. //            : The "thumb" is always a square equal to the narrowest axis of scale.
  8. //            : Scale colors are taken from 'cctb' cTingeLight and cTingeDark.
  9. //            :
  10. //            : The variations are:
  11. //            :
  12. //            :    none                    - scale & thumb are the width/height of the
  13. //            :                            control rect.
  14. //            :
  15. //            :    narrowScale     0x0001    - scale of slider is 4 pixels smaller than the
  16. //            :                            the thumb.
  17. //            :
  18. //            :    narrowScale2     0x0002    - scale of slider is 8 pixels smaller than the
  19. //            :                            the thumb.
  20. //            :
  21. //            :    filledScale        0x0004    - low end of scale filled with cTingeDark
  22. //            :
  23. //            :    snapToScale        0x0008    - click on scale moves thumb to that point
  24. //            :
  25. //            :
  26. //            : If you find a use for this, I'd love to know about it.  Bug reports
  27. //            : are always interesting.
  28. //            :
  29. //            : Internet    : JimS@WRQ.COM(work hours, PST)
  30. //            : AppleLink   : WRQ            (daily)
  31. //            : CompuServe  : 73240,2052    (weekly or so)
  32. //            : AOL         : JasG        (weekly or so)
  33. //            : eWorld      : Jim Stout    (weekly or so)
  34. //----------------------------------------------------------------------------------
  35. //#define _DEBUGCDEF                    // comment this to build CDEF
  36.  
  37. #include "fatCDEF.h"
  38.  
  39. #include <Controls.h>
  40. #include <GestaltEqu.h>
  41. #include <Memory.h>
  42. #include <QDOffscreen.h>
  43. #include <ToolUtils.h>
  44. #include <Types.h>
  45. #include <Windows.h>
  46.  
  47. #include "grayCDEF.h"
  48. #include "colorCDEF.h"
  49. #include "miscCDEF.h"
  50. #include "qdCDEF.h"
  51.  
  52. #include "cdefSlider.h"
  53.  
  54. #ifdef _DEBUGCDEF
  55. pascal long CDmain (short, ControlHandle, short, long);
  56.  
  57. pascal long CDmain (short varCode, ControlHandle theCtl, short message, long param)
  58. #else
  59.  
  60. //==================================================================================
  61. // CDEF entry point
  62. //==================================================================================
  63. pascal long main (short varCode, ControlHandle theCtl, short message, long param)
  64. #endif
  65. {
  66.     long    ret = 0L;
  67.     SignedByte    cState, dState;
  68.  
  69. #include "fatEntry.c"
  70.     
  71.     cState = HGetState((Handle)theCtl);
  72.     HLock((Handle)theCtl);
  73.     if((**theCtl).contrlData) {
  74.         dState = HGetState((**theCtl).contrlData);
  75.         HLock((**theCtl).contrlData);
  76.     }
  77.     
  78.     switch(message) {
  79.         case initCntl:
  80.             doInit(theCtl);
  81.             if((**theCtl).contrlData) {
  82.                 dState = HGetState((**theCtl).contrlData);
  83.                 HLock((**theCtl).contrlData);
  84.             }
  85.         break;
  86.         case dispCntl:
  87.             doDisp(theCtl);
  88.         break;
  89.         case drawCntl:
  90.             if ((**theCtl).contrlVis != 0 &&
  91.                 ((WindowPeek)(**theCtl).contrlOwner)->visible) {
  92.                 doDraw(theCtl, varCode);
  93.             }
  94.         break;
  95.         case testCntl:
  96.             ret = doTest (theCtl, varCode, param);
  97.         break;
  98.         case calcCRgns:
  99.             RectRgn((RgnHandle)(param & 0x7fffffffL), &(**theCtl).contrlRect);
  100.         break;
  101.         case calcCntlRgn:
  102.         case calcThumbRgn:
  103.             RectRgn((RgnHandle)(param), &(**theCtl).contrlRect);
  104.         break;
  105.     }
  106.  
  107.     if((**theCtl).contrlData) {
  108.         HSetState((**theCtl).contrlData, dState);
  109.     }
  110.     HSetState((Handle)theCtl, cState);
  111.     
  112. #include "fatExit.c"
  113.  
  114.     return (ret);
  115. }
  116.  
  117. //==================================================================================
  118. //    Respond to a "initCntl" message.
  119. //    Initialize our control data
  120. //==================================================================================
  121.  
  122. static void doInit (ControlHandle theCtl)
  123. {
  124.     CDEFHandle    hCDEF;
  125.  
  126.     hCDEF = (CDEFHandle)NewHandle(sizeof(CDEFData));
  127.     if(hCDEF) {
  128.         (**hCDEF).offPort = 0;
  129.         (**hCDEF).qdVers = getQDVers();
  130.         (**theCtl).contrlData = (Handle)hCDEF;
  131.     }
  132.     else {
  133.         (**theCtl).contrlData = 0;
  134.     }
  135. }
  136.  
  137. //==================================================================================
  138. //    Respond to a "dispCntl" message.
  139. //    Get rid of our control data
  140. //==================================================================================
  141.  
  142. static void doDisp        (ControlHandle theCtl)
  143. {
  144.     BitMap        *theBits;
  145.     CDEFHandle    hCDEF;
  146.     
  147.     hCDEF = (CDEFHandle)(**theCtl).contrlData;
  148.     if(hCDEF) {
  149.         if((**hCDEF).offPort) {
  150.             if(((**hCDEF).offPort->portVersion & 0x8000) != 0) {    // offPort is GWorld
  151.                 DisposeGWorld((**hCDEF).offPort);                
  152.             }
  153.             else {                                                    // offport is bitmap
  154.                 theBits = &((GrafPtr)(**hCDEF).offPort)->portBits;
  155.                 DisposePtr((*theBits).baseAddr);
  156.                 ClosePort((GrafPtr)(**hCDEF).offPort);
  157.                 DisposePtr((Ptr)(**hCDEF).offPort);
  158.             }
  159.         }
  160.             
  161.         HUnlock((Handle)hCDEF);
  162.         DisposeHandle((Handle)hCDEF);
  163.         (**theCtl).contrlData = 0;
  164.     }
  165. }
  166.  
  167. //==================================================================================
  168. //    Respond to a "testCntl" message.
  169. //    Test to see if the mouse was pressed in the control thumb and drag accordingly
  170. //==================================================================================
  171.  
  172. static long doTest (ControlHandle theCtl, short varCode, long param)
  173. {
  174.     Rect        rThumb, rScale;
  175.     Point        p;
  176.     Boolean     vert=true;
  177.     long        ret=0,secs;
  178.     short        partCode;
  179.     CDEFHandle    hCDEF;
  180.     
  181.     hCDEF = (CDEFHandle)(**theCtl).contrlData;
  182.     if(!hCDEF) {
  183.         return(ret);
  184.     }
  185.  
  186.     p.h = LoWord(param);
  187.     p.v = HiWord(param);
  188.     
  189.     if(!PtInRect(p, &(**theCtl).contrlRect)) {
  190.         return(0);
  191.     }
  192.         
  193.     partCode = (**theCtl).contrlHilite;
  194.     rScale = (**theCtl).contrlRect;
  195.     if(rScale.right-rScale.left > rScale.bottom-rScale.top) {
  196.         vert=false;
  197.     }
  198.     
  199. //----------------------------------------------------------------------------------
  200. // get the thumb rect, calculated from control value
  201. //----------------------------------------------------------------------------------
  202.  
  203.     getThumbRect(theCtl, &rThumb, &rScale, vert);
  204.     
  205.     if(PtInRect(p, &rThumb)) {                                // click in thumb?
  206.         ret = inThumb;
  207.         dragThumb(theCtl, varCode, param);
  208.     }
  209.     else
  210.     if(PtInRect(p, &rScale)) {                                // click in scale?
  211.         if(vert) {
  212.             if(p.v < rThumb.top) {
  213.                 ret = inUpScale;                            // increase
  214.             }
  215.             else
  216.             if(p.v > rThumb.bottom) {
  217.                 ret = inDnScale;                            // decrease
  218.             }
  219.         }
  220.         else {
  221.             if(p.h < rThumb.left) {
  222.                 ret = inDnScale;                            // decrease
  223.             }
  224.             else
  225.             if(p.h > rThumb.right) {
  226.                 ret = inUpScale;                            // increase
  227.             }
  228.         }
  229.             
  230.         if(partCode == ret) {
  231.             scaleClick(theCtl, varCode, (short)ret, p);
  232.             Delay(6L, & secs);
  233.         }
  234.     }
  235.     return(ret);
  236. }
  237. //==================================================================================
  238. // If running with System 7, use DeviceLoop to gracefully handle multiple screens.
  239. // Simulate DeviceLoop if using System 6...
  240. //==================================================================================
  241.  
  242. static void doDraw(ControlHandle theCtl, short varCode)
  243. {
  244.     devLoopHandle            hDl;
  245.     RgnHandle                saveClip, hRgn;
  246.     DeviceLoopDrawingUPP    drawControlUPP;
  247.  
  248. //----------------------------------------------------------------------------------
  249. //    Create our data handle to pass to DeviceLoop
  250. //----------------------------------------------------------------------------------
  251.     
  252.     hDl = (devLoopHandle)NewHandle(sizeof(devLoopData));
  253.     if(hDl) {
  254.         drawControlUPP = NewDeviceLoopDrawingProc(drawControl);
  255.         
  256.         (**hDl).theCtl = theCtl;
  257.         (**hDl).varCode = varCode;
  258.         (**hDl).controlRect = (**theCtl).contrlRect;
  259.         
  260. //----------------------------------------------------------------------------------
  261. //    Do the clip region properly.  Thanks Ari!
  262. //----------------------------------------------------------------------------------
  263.  
  264.         saveClip = NewRgn();
  265.         GetClip(saveClip);
  266.         
  267.         hRgn = NewRgn();
  268.         RectRgn(hRgn, &(**hDl).controlRect);
  269.         SectRgn(saveClip, hRgn, hRgn);
  270.         
  271.         if(EmptyRgn(hRgn)) {                                    // if empty, don't waste
  272.             DisposeRgn(saveClip);                                // time drawing...
  273.             DisposeRgn(hRgn);
  274.             return;
  275.         }        
  276.  
  277. //----------------------------------------------------------------------------------
  278. //    Call DeviceLoop to take care of our drawing
  279. //----------------------------------------------------------------------------------
  280.         
  281.         if(getOSVers() >= 0x0700) {
  282.             DeviceLoop (hRgn, drawControlUPP, (long)hDl, 0);
  283.         }
  284.         else {
  285.             sys6DeviceLoop (hRgn, drawControlUPP, (long)hDl, 0);
  286.         }
  287.         
  288.         SetClip(saveClip);
  289.         DisposeRgn(hRgn);
  290.         DisposeHandle((Handle)hDl);
  291.         DisposeRoutineDescriptor(drawControlUPP);
  292.     }
  293. }
  294. //==================================================================================
  295. //    Respond to a "drawCntl" message.  The control image is really drawn into an
  296. //    offscreen bitmap in "drawParts".  If you want to change the appearance of the
  297. //    control, all you have to do is change the drawing routines in "drawParts".
  298. //
  299. // This is called by DeviceLoop, but in this case, we just pay attention to the
  300. // "depth" and "userData" parameters.
  301. //==================================================================================
  302.  
  303. pascal void drawControl (short depth, short dFlags, GDHandle theDevice, long userData)
  304. {
  305.  
  306. #pragma unused(dFlags, theDevice)
  307.  
  308.     ControlHandle    theCtl;
  309.     short            varCode,pixels;
  310.     Rect            rOff,rScale;
  311.     BitMap            *offBits;
  312.     PixMapHandle    pmHdl;
  313.     CGrafPtr        savePort;
  314.     GDHandle        saveGDev;
  315.     PenState        savePen;
  316.     Boolean            inactive = false, haveGray = false, haveGW = false, inColor = false;
  317.     Boolean            vert=true;
  318.     RGBColor        saveFore,saveBack;
  319.     RGBColor        rgbBlack = {0,0,0};
  320.     RGBColor        rgbWhite = {-1,-1,-1};
  321.     
  322.     CDEFHandle        hCDEF;                                // our private data structures
  323.     devLoopHandle    hDl;
  324.     
  325. //----------------------------------------------------------------------------------
  326. // Can we draw?
  327. //----------------------------------------------------------------------------------
  328.  
  329.     hDl = (devLoopHandle)userData;                        // need control & varCode
  330.     if(hDl) {
  331.         theCtl = (**hDl).theCtl;
  332.         varCode = (**hDl).varCode;
  333.     }
  334.     else {
  335.         return;
  336.     }
  337.     hCDEF = (CDEFHandle)(**theCtl).contrlData;
  338.     if(hCDEF) {
  339.  
  340. //----------------------------------------------------------------------------------
  341. // Create or update our GWorld    
  342. //----------------------------------------------------------------------------------
  343.     
  344.         pixels = getOff(&(**hCDEF).offPort, &(**theCtl).contrlRect);
  345.         
  346.         if(pixels == 0) {                                    // oh… oh…                
  347.             return;                                        
  348.         }
  349.         
  350.         if(((**hCDEF).offPort->portVersion & 0x8000) != 0) {    // have a GWorld
  351.             haveGW = true;
  352.             pmHdl = getLockedPixels(&(**hCDEF).offPort, (**hCDEF).qdVers);
  353.             if(!pmHdl) {
  354.                 return;
  355.             }                                                    // nuts…
  356.         }
  357.         
  358. //----------------------------------------------------------------------------------
  359. // Initialize and set for drawing into offScreen port
  360. //----------------------------------------------------------------------------------
  361.  
  362.         if((**theCtl).contrlHilite == 0xFF) {                // inactive control
  363.             inactive = true;
  364.         }
  365.         
  366.         rOff = rScale = (**theCtl).contrlRect;
  367.             
  368.         if(depth > 2) {                                        // save onscreen    
  369.             inColor = true;                                    // colors
  370.             saveColors(&saveFore, &saveBack);
  371.         }
  372.         
  373.         if(haveGW) {                                        // we have a pixMap        
  374.             GetGWorld(&savePort, &saveGDev);
  375.             SetGWorld((**hCDEF).offPort, nil);
  376.             offBits = (BitMap *)*pmHdl;
  377.             if((**(*savePort).bkPixPat).patType != 0 &&
  378.                 (savePort->portVersion & 0x8000) != 0)
  379.                 BackPixPat((*savePort).bkPixPat);
  380.         }
  381.         else {                                                // we have a bitMap    
  382.             GetPort((GrafPtr*)&savePort);
  383.             SetPort((GrafPtr)(**hCDEF).offPort);        
  384.             offBits = (BitMap *)&((GrafPtr)(**hCDEF).offPort)->portBits;
  385.         }
  386.         
  387.         if(inColor) {                                        // need same colors
  388.             RGBForeColor(&saveFore);                        // offscreen
  389.             RGBBackColor(&saveBack);
  390.         }
  391.         
  392. //----------------------------------------------------------------------------------
  393. //    Erase background of offscreen port - pay attention to origin so patterned
  394. //    backgrounds are aligned
  395. //----------------------------------------------------------------------------------
  396.  
  397.         SetOrigin((**theCtl).contrlRect.left, (**theCtl).contrlRect.top);
  398.         EraseRect(&(**theCtl).contrlRect);
  399.         SetOrigin(0,0);
  400.         
  401.         OffsetRect(&rOff, - rOff.left, - rOff.top);            // set to (0,0)
  402.  
  403. //----------------------------------------------------------------------------------
  404. // draw the control parts into the offscreen port
  405. //----------------------------------------------------------------------------------
  406.     
  407.         haveGray = drawParts (theCtl, varCode, inColor, &rOff);
  408.         
  409. //----------------------------------------------------------------------------------
  410. // restore onscreen port & set colors to b&w 
  411. //----------------------------------------------------------------------------------
  412.  
  413.         if(haveGW) {
  414.             SetGWorld(savePort, saveGDev);
  415.         } else {
  416.             SetPort((GrafPtr)savePort);
  417.         }
  418.         if(inColor) {
  419.             RGBForeColor(&rgbBlack);
  420.             RGBBackColor(&rgbWhite);
  421.         }
  422.  
  423. //----------------------------------------------------------------------------------
  424. // now copy it to the onscreen port and restore our colors
  425. //----------------------------------------------------------------------------------
  426.     
  427.         CopyBits(offBits,
  428.                 &((GrafPtr)savePort)->portBits,
  429.                 &rOff,
  430.                 &rScale,
  431.                 srcCopy, nil);
  432.         
  433.         if(haveGW) {
  434.             unlockPixels(pmHdl, (**hCDEF).qdVers);
  435.             DisposeGWorld((**hCDEF).offPort);
  436.             (**hCDEF).offPort = 0;
  437.         }
  438.         
  439.         if(inColor) {
  440.             restoreColors(&saveFore, &saveBack);
  441.         }
  442.         
  443. //----------------------------------------------------------------------------------
  444. // if we failed to get an inactive gray color, do it the old way
  445. //----------------------------------------------------------------------------------
  446.  
  447.         if(inactive && !haveGray) {                            // use the old way of drawing
  448.             GetPenState(&savePen);                            // an inactive control
  449.             PenMode(patBic);
  450.             PenPat( (ConstPatternParam) "\xAA\x55\xAA\x55\xAA\x55\xAA\x55");
  451.             PaintRect(&(**theCtl).contrlRect);
  452.             SetPenState(&savePen);
  453.         }
  454.     }
  455. }
  456.  
  457. //==================================================================================
  458. // Respond to a mouse down in our "thumb", track the mouse to reposition the thumb,
  459. // set a new control value and call the actionProc (if any).
  460. //==================================================================================
  461. static void dragThumb (ControlHandle theCtl, short varCode, long param)
  462. {
  463.     short    newVal,maxDrag,minDrag;
  464.     Rect    rThumb, rScale;
  465.     Point    p,oldPt;
  466.     Boolean    vert=true;
  467.  
  468.     rScale = (**theCtl).contrlRect;
  469.     if(rScale.right-rScale.left > rScale.bottom-rScale.top) {
  470.         vert=false;
  471.     }
  472.         
  473.     getThumbRect(theCtl, &rThumb, &rScale, vert);
  474.     
  475.     p.h = oldPt.h = LoWord(param);
  476.     p.v = oldPt.v = HiWord(param);
  477.     
  478.     if(PtInRect(p, &rThumb)) {
  479.         if(vert) {
  480.             maxDrag = rScale.bottom - (rThumb.bottom - p.v);
  481.             minDrag = rScale.top + (p.v - rThumb.top);
  482.             
  483.             while (StillDown()) {
  484.                 if(oldPt.v != p.v) {                            // mouse moved
  485.                     OffsetRect(&rThumb, 0, (p.v-oldPt.v));        // move the thumb    
  486.                     checkLimits(vert, &rThumb, &rScale);        // but not too far…
  487.                     
  488.                     newVal = getNewValue(theCtl, vert, rScale.bottom - rThumb.bottom);
  489.                     
  490.                     if(newVal != (**theCtl).contrlValue) {
  491.                         adjustControl(theCtl, varCode, inThumb, newVal);
  492.                     }
  493.                     if(p.v > minDrag && p.v < maxDrag) {        // track move
  494.                         oldPt.v = p.v;    
  495.                     }
  496.                 }
  497.                 GetMouse(&p);
  498.             }
  499.         }
  500.         else {            
  501.             maxDrag = rScale.right - (rThumb.right - p.h);
  502.             minDrag = rScale.left + (p.h - rThumb.left);
  503.             while (StillDown()) {
  504.                 if(oldPt.h != p.h) {                            // mouse moved
  505.                     OffsetRect(&rThumb, (p.h-oldPt.h), 0);        // move the thumb    
  506.                     checkLimits(vert, &rThumb, &rScale);        // but not too far…
  507.  
  508.                     newVal = getNewValue(theCtl, vert, rThumb.left - rScale.left);
  509.                                     
  510.                     if(newVal != (**theCtl).contrlValue) {
  511.                         adjustControl(theCtl, varCode, inThumb, newVal);
  512.                     }
  513.                     if(p.h > minDrag && p.h < maxDrag) {        // track move
  514.                         oldPt.h = p.h;    
  515.                     }
  516.                 }
  517.                 GetMouse(&p);
  518.             }
  519.         }
  520.     }
  521. }
  522.  
  523. //==================================================================================
  524. // Adjust the control after detecting a click in the scale instead of the thumb -
  525. // set a new control value and call the actionProc (if any).
  526. //==================================================================================
  527. static void scaleClick (ControlHandle theCtl, short varCode, short partCode, Point p)
  528. {
  529.     short    newVal,incr=1,thumbSize;
  530.     Rect    rThumb,rScale;
  531.     Boolean    vert=true;
  532.         
  533.     newVal = (**theCtl).contrlValue;
  534.  
  535.     if(varCode & snapToScale) {
  536.         rScale = (**theCtl).contrlRect;
  537.         if(rScale.right-rScale.left > rScale.bottom-rScale.top)
  538.             vert=false;
  539.         getThumbRect(theCtl, &rThumb, &rScale, vert);
  540.         thumbSize = rThumb.right - rThumb.left;
  541.         
  542.         if(vert) {
  543.             if(partCode == inUpScale) {
  544.                 rThumb.top = p.v - thumbSize/2;
  545.                 rThumb.bottom = rThumb.top + thumbSize;
  546.             }
  547.             else {
  548.                 rThumb.bottom = p.v + thumbSize/2;
  549.                 rThumb.top = rThumb.bottom - thumbSize;
  550.             }    
  551.             checkLimits(vert, &rThumb, &rScale);        // don't move too far…
  552.                             
  553.             newVal = getNewValue(theCtl, vert, rScale.bottom - rThumb.bottom);
  554.         }
  555.         else {
  556.             if(partCode == inUpScale) {
  557.                 rThumb.left = p.h - thumbSize/2;
  558.                 rThumb.right = rThumb.left + thumbSize;
  559.             }
  560.             else {
  561.                 rThumb.right = p.h + thumbSize/2;
  562.                 rThumb.left = rThumb.right - thumbSize;
  563.             }
  564.             checkLimits(vert, &rThumb, &rScale);        // don't move too far…
  565.             
  566.             newVal = getNewValue(theCtl, vert, rThumb.left - rScale.left);
  567.         }
  568.     }
  569.     else {
  570.         if((**theCtl).contrlMin > (**theCtl).contrlMax)
  571.             incr = -1;
  572.     
  573.         if(partCode == inDnScale) {                        // decrease value by 1
  574.             newVal-=incr;
  575.         }
  576.         else 
  577.         if(partCode == inUpScale) {                        // increase value by 1
  578.             newVal+=incr;        
  579.         }
  580.     }
  581.     if(newVal != (**theCtl).contrlValue) {
  582.         adjustControl(theCtl, varCode, partCode, newVal);
  583.     }
  584. }
  585.  
  586. //==================================================================================
  587. //    Calculate & position the thumbRect at the proper point on the scale
  588. //==================================================================================
  589.  
  590. static void getThumbRect(ControlHandle theCtl, Rect *rThumb, 
  591.                             Rect *rScale, Boolean vert)
  592. {
  593.     short    thumbSize,thumbOff;
  594.     
  595.     *rThumb = *rScale;
  596.     
  597.     if(vert) {
  598.         thumbSize = rThumb->right-rThumb->left;
  599.         rThumb->top = rThumb->bottom-thumbSize;
  600.         thumbOff = getThumbOffset(theCtl, vert, thumbSize);
  601.         OffsetRect(rThumb, 0, - thumbOff);
  602.     }
  603.     else {
  604.         thumbSize = rThumb->bottom-rThumb->top;
  605.         rThumb->right = rThumb->left+thumbSize;
  606.         thumbOff = getThumbOffset(theCtl, vert, thumbSize);
  607.         OffsetRect(rThumb, thumbOff, 0);
  608.     }
  609. }
  610.  
  611. //==================================================================================
  612. //    Calculate the offset of the thumb from the low end of the scale
  613. //==================================================================================
  614.  
  615. static short getThumbOffset    (ControlHandle theCtl, Boolean vert, short thumbSize)
  616. {
  617.     float    scale, range, nullPos;
  618.     
  619.     if(vert) {
  620.         scale = (**theCtl).contrlRect.bottom - (**theCtl).contrlRect.top - thumbSize;
  621.     }
  622.     else {
  623.         scale = (**theCtl).contrlRect.right - (**theCtl).contrlRect.left - thumbSize;
  624.     }
  625.     
  626.     range = (**theCtl).contrlMax - (**theCtl).contrlMin;
  627.     
  628.     nullPos = (-1 * (**theCtl).contrlMin / range) * scale;
  629.     
  630.     return((**theCtl).contrlValue * scale/range + nullPos);
  631. }
  632.  
  633. //==================================================================================
  634. //    Insure that the thumb has not moved off the scale
  635. //==================================================================================
  636. static void checkLimits    (Boolean vert, Rect *rThumb, Rect *rScale)
  637. {
  638.     if(vert) {
  639.         if(rThumb->top < rScale->top) {                    // pin to top of scale
  640.             OffsetRect(rThumb, 0, rScale->top - rThumb->top); 
  641.         }
  642.         else
  643.         if(rThumb->bottom > rScale->bottom)    {        // pin to bottom of scale
  644.             OffsetRect(rThumb, 0, rScale->bottom - rThumb->bottom); 
  645.         }
  646.     }
  647.     else {
  648.         if(rThumb->left < rScale->left) {            // pin to left of scale
  649.             OffsetRect(rThumb, rScale->left - rThumb->left, 0); 
  650.         }
  651.         else
  652.         if(rThumb->right > rScale->right) {            // pin to right of scale
  653.             OffsetRect(rThumb, rScale->right - rThumb->right, 0); 
  654.         }
  655.     }
  656. }
  657. //==================================================================================
  658. //    Calculate the value of the control from the thumb position
  659. //==================================================================================
  660.  
  661. static short getNewValue    (ControlHandle theCtl, Boolean vert, short thumbOff)
  662. {
  663.     short    thumbSize;
  664.     float    scale, range, nullPos;
  665.     
  666.     
  667.     if(vert) {
  668.         thumbSize = (**theCtl).contrlRect.right - (**theCtl).contrlRect.left;
  669.         scale = (**theCtl).contrlRect.bottom - (**theCtl).contrlRect.top - thumbSize;
  670.     }
  671.     else {
  672.         thumbSize = (**theCtl).contrlRect.bottom - (**theCtl).contrlRect.top;
  673.         scale = (**theCtl).contrlRect.right - (**theCtl).contrlRect.left - thumbSize;
  674.     }
  675.     
  676.     range = (**theCtl).contrlMax - (**theCtl).contrlMin;
  677.     
  678.     nullPos = (-1 * (**theCtl).contrlMin / range) * scale;
  679.     
  680.     return((thumbOff - nullPos) * range/scale);
  681. }
  682.  
  683. //==================================================================================
  684. //    Adjust control to reflect new thumb postion, draw it and call actionProc
  685. //==================================================================================
  686.  
  687. static void adjustControl(ControlHandle theCtl, short varCode,
  688.                             short partCode, short newVal)
  689. {
  690.     (**theCtl).contrlValue = newVal;
  691.     doDraw(theCtl, varCode);
  692.     if((**theCtl).contrlAction != nil) {
  693.         CallControlActionProc((**theCtl).contrlAction, theCtl, partCode);
  694.     }
  695. }
  696.  
  697. //==================================================================================
  698. //    Do the actual drawing of the scale and thumb into an offscreen port for use by
  699. //    the doDraw routine above. The offscreen port has been prepared and is set for
  700. //    drawing when this routine is called. 
  701. //
  702. //    Change this to customize the control appearance.
  703. //==================================================================================
  704.  
  705. static Boolean drawParts (ControlHandle theCtl, short varCode, Boolean inColor,
  706.                             Rect *rOff)
  707. {
  708.     short        mid;
  709.     Rect        rThumb, rScale, rFilled;
  710.     Boolean        haveGray = false, vert = true;
  711.     RGBColor    saveFore,saveBack,rgbE={0xeeee,0xeeee,0xeeee};
  712.     RGBColor    frameGray1,frameGray2;
  713.     CDEFHandle    hCDEF;
  714.     
  715.     hCDEF = (CDEFHandle)(**theCtl).contrlData;
  716.     if(hCDEF) {
  717.     
  718. //----------------------------------------------------------------------------------
  719. //    Initialize drawing rects
  720. //----------------------------------------------------------------------------------
  721.         if(rOff->right-rOff->left > rOff->bottom-rOff->top) {
  722.             vert=false;
  723.         }
  724.         
  725.         rScale = *rOff;                                    // get part rects
  726.         getThumbRect(theCtl, &rThumb, rOff, vert);
  727.     
  728.         if(varCode & narrowScale) {                        // adjust scale size
  729.             if(vert) {
  730.                 InsetRect(&rScale, 2, 0);
  731.             }
  732.             else {
  733.                 InsetRect(&rScale, 0, 2);
  734.             }
  735.         }
  736.         if(varCode & narrowScale2) {
  737.             if(vert) {
  738.                 InsetRect(&rScale, 4, 0);
  739.             }
  740.             else {
  741.                 InsetRect(&rScale, 0, 4);
  742.             }
  743.         }
  744.         
  745.         rFilled = rScale;
  746.         if(vert) {
  747.             rFilled.top = rThumb.bottom;
  748.         }
  749.         else {
  750.             rFilled.right = rThumb.left;
  751.         }
  752.         
  753. //----------------------------------------------------------------------------------
  754. // set up drawing colors
  755. //----------------------------------------------------------------------------------
  756.  
  757.           if(inColor) {
  758.               saveColors(&saveFore, &saveBack);            // save current colors
  759.               setPartColor(theCtl, cFrameColor, true);    // set fg 'cctb' Color
  760.               setPartColor(theCtl, cTingeLight, false);    // set bg 'cctb' Color
  761.               
  762.               if(getGray(&frameGray1)) {                    // get grays for the
  763.                   haveGray = true;                        // inactive control frame
  764.                   RGBForeColor(&frameGray1);                // or 3D shadow
  765.               }
  766.               getGray(&frameGray2);
  767.               setPartColor(theCtl, cTingeLight, true);
  768.           }
  769.           else {
  770.               ForeColor(whiteColor);
  771.           }
  772.         
  773. //----------------------------------------------------------------------------------
  774. // draw the scale body
  775. //----------------------------------------------------------------------------------
  776.         
  777.         PaintRect(&rScale);                                // fill with light color
  778.         
  779.         ForeColor(blackColor);
  780.                 
  781.         if(varCode & filledScale) {
  782.             if(inColor) {
  783.                 setPartColor(theCtl, cTingeDark, true);
  784.             }
  785.             PaintRect(&rFilled);
  786.         }
  787.         
  788. //----------------------------------------------------------------------------------
  789. // draw the scale frame
  790. //----------------------------------------------------------------------------------
  791.         
  792.         if(inColor) {
  793.             setPartColor(theCtl, cFrameColor, true);
  794.             if(haveGray &&(**theCtl).contrlHilite == 0xFF) {    // inactive control, so set
  795.                     RGBForeColor(&frameGray1);                    // to a grayed fg color
  796.             }
  797.         }
  798.         
  799.         FrameRect(&rScale);                                // frame scale in fg color
  800.             
  801.         if(inColor) {                                    // get gray for 3D "dark"
  802.             RGBForeColor(&frameGray2);                    // shadow
  803.         }
  804.                     
  805.         MoveTo(rScale.left+1,rScale.bottom-2);            // "dark" shadow along left
  806.         LineTo(rScale.left+1,rScale.top+1);                // and top edges
  807.         LineTo(rScale.right-2, rScale.top+1);
  808.             
  809.         if(inColor) {
  810.             ForeColor(whiteColor);                        // "light" shadow along right
  811.             Move(0, 1);                                    // and bottom edges
  812.             LineTo(rScale.right-2, rScale.bottom-2);
  813.             LineTo(rScale.left+2, rScale.bottom-2);
  814.         }
  815.         
  816. //----------------------------------------------------------------------------------
  817. // draw the thumb
  818. //----------------------------------------------------------------------------------
  819.         
  820.         if(inColor) {
  821.             RGBForeColor(&rgbE);
  822.         }
  823.         else {
  824.             ForeColor(whiteColor);
  825.         }
  826.             
  827.         InsetRect(&rThumb, 1, 1);                        // paint interior of
  828.         PaintRect(&rThumb);                                // thumb with foreColor
  829.         InsetRect(&rThumb, -1, -1);
  830.         
  831.         if(inColor) {        
  832.             if((**theCtl).contrlHilite == 0xFF) {        // inactive control, so set
  833.                 RGBForeColor(&frameGray1);                // a grayed fg color
  834.             }
  835.             else {
  836.                 setPartColor(theCtl, cFrameColor, true);
  837.             }
  838.         }
  839.         else {
  840.             ForeColor(blackColor);                        // for the frame        
  841.         }
  842.         
  843. //----------------------------------------------------------------------------------
  844. // if scale is narrower than thumb, don't draw the corners of the thumb frame
  845. //----------------------------------------------------------------------------------
  846.  
  847.           if(varCode & narrowScale || varCode & narrowScale2) {
  848.             MoveTo(rThumb.left, rThumb.bottom-2);
  849.             LineTo(rThumb.left, rThumb.top+1);
  850.             Move(1,-1);
  851.             LineTo(rThumb.right-2, rThumb.top);
  852.             Move(1,1);
  853.             LineTo(rThumb.right-1, rThumb.bottom-2);
  854.             Move(-1,1);
  855.             LineTo(rThumb.left+1, rThumb.bottom-1);
  856.         }
  857.         else {
  858.             FrameRect(&rThumb);                            // full frame in fg color
  859.         }
  860.         if(inColor) {                                    // get gray for 3D dark
  861.             getGray(&frameGray2);                        // shadow
  862.             RGBForeColor(&frameGray2);
  863.         }
  864.         
  865. //----------------------------------------------------------------------------------
  866. // draw shadowed frame for thumb
  867. //----------------------------------------------------------------------------------
  868.  
  869.         MoveTo(rThumb.left+1, rThumb.bottom-2);            // dark shadow
  870.         LineTo(rThumb.right-2, rThumb.bottom-2);
  871.         LineTo(rThumb.right-2, rThumb.top+1);
  872.             
  873.         if(inColor) {
  874.             ForeColor(whiteColor);                        // light shadow
  875.             Move(-1, 0);
  876.             LineTo(rThumb.left+1, rThumb.top+1);
  877.             LineTo(rThumb.left+1, rThumb.bottom-3);
  878.         }
  879.         
  880. //----------------------------------------------------------------------------------
  881. // draw indicator line in center of thumb - first the light shadow
  882. //----------------------------------------------------------------------------------
  883.         if(vert) {
  884.             mid = rThumb.top + (rThumb.bottom-rThumb.top)/2 - 1;
  885.         }
  886.         else {
  887.             mid = rThumb.left + (rThumb.right-rThumb.left)/2 - 1;
  888.         }
  889.             
  890.         if(inColor) {
  891.             if(vert) {
  892.                 MoveTo(rThumb.left+1, mid+1);
  893.                 LineTo(rThumb.right-3, mid+1);
  894.             }
  895.             else {
  896.                 MoveTo(mid+1, rThumb.top+1);
  897.                 LineTo(mid+1, rThumb.bottom-3);
  898.             }
  899.         }
  900.     
  901. //----------------------------------------------------------------------------------
  902. // draw indicator line in center of thumb - now the dark shadow
  903. //----------------------------------------------------------------------------------
  904.  
  905.         if(inColor) {
  906.             RGBForeColor(&frameGray1);
  907.         }
  908.         else {
  909.             ForeColor(blackColor);
  910.         }
  911.             
  912.         if(vert) {
  913.             MoveTo(rThumb.left+1, mid);
  914.             LineTo(rThumb.right-3, mid);
  915.         }
  916.         else {
  917.             MoveTo(mid, rThumb.top+1);
  918.             LineTo(mid, rThumb.bottom-3);
  919.         }
  920.     
  921. //----------------------------------------------------------------------------------
  922. // Done drawing - restore colors and exit
  923. //----------------------------------------------------------------------------------
  924.  
  925.           if(inColor) {
  926.               restoreColors(&saveFore, &saveBack);
  927.           }
  928.       }
  929.       return(haveGray);
  930. }
  931.