home *** CD-ROM | disk | FTP | other *** search
/ Nebula 1995 August / NEBULA.bin / SourceCode / Palettes / CircularSlider / CircularSlider.subproj / CircularSliderCell.m < prev    next >
Encoding:
Text File  |  1993-02-03  |  10.4 KB  |  432 lines

  1. /*
  2.  *    Filename:    CircularSliderCell.m 
  3.  *    Created :    Sun Oct 18 16:56:38 1992 
  4.  *    Author  :    Vince DeMarco
  5.  *        <vince@whatnxt.cuc.ab.ca>
  6.  *    LastEditDate was "Wed Feb  3 17:30:28 1993"
  7.  */
  8.  
  9.  
  10. #import "CircularSliderCell.h"
  11. #import <appkit/Control.h>
  12. #import <appkit/Application.h>
  13. #import <math.h>
  14. #import <dpsclient/psops.h>
  15. #import "wraps.h"
  16.  
  17. /* Calculate the Absolute value of y safely */
  18. #define ABS(y)                       \
  19.       ({typeof (y) __x = (y);        \
  20.        (__x < 0) ? (-(__x)) : (__x); })
  21.  
  22. @implementation CircularSliderCell
  23.  
  24. /* Given a x,y point on a cart coordinate system this function returns the angle (in degrees) from
  25.  * the positive side of the Y- axis
  26.  *        ^
  27.  *        |
  28.  *        |\
  29.  *   <____|_|__>
  30.  *        | |
  31.  *        |<-
  32.  *        |
  33.  */
  34.  
  35. inline static float angle(float x, float y)
  36. {
  37.     float result;
  38.     
  39.     if (y >= 0){                                 /* Quadrants 1,4 */
  40.         if ( x >= 0){                   /* Quadrant 1 */
  41.             result  = atan(ABS(x/y));
  42.             result *= (180/M_PI);
  43.             return(ABS(result));
  44.         }else{                          /* Quadrant 4 */
  45.             result  = atan(ABS(y/x));
  46.             result *= (180/M_PI);
  47.             return(ABS(result+270.0));
  48.         }
  49.     }else{                                      /* Quadrants 2,3 */
  50.         if ( x >= 0){                   /* Quadrant 2 */
  51.             result  = atan(ABS(y/x));
  52.             result *= (180/M_PI);
  53.             return(ABS(result+90.0));
  54.         }else{                          /* Quadrant 3 */
  55.             result  = atan(ABS(x/y));
  56.             result *= (180/M_PI);
  57.             return(ABS(result+180.0));
  58.         }
  59.     }
  60. }
  61.  
  62. /* 
  63.  * xycoord does the opposite of angle,
  64.  * given an angle and a radius, xycoord returns the x,y position of 
  65.  * a point on the radius
  66.  *        ^
  67.  *        |
  68.  *        |\
  69.  *        | \  angle in degrees
  70.  *   <____|__\___>
  71.  *        |\  |
  72.  *        | \<-
  73.  *        |  \ (x,y)
  74.  */
  75. inline static void xycoord(float angle, float radius,float *x, float *y)
  76. {
  77.     *x = (radius - 3.0)*(float)sin((M_PI/180)*angle);
  78.     *y = (radius - 3.0)*(float)cos((M_PI/180)*angle);
  79. }
  80.  
  81. + (BOOL)prefersTrackingUntilMouseUp
  82. {
  83.     return YES;
  84. }
  85.  
  86. - init
  87. {
  88.     self = [super init];
  89.     minValue = value = currentang = 0.0;
  90.     maxValue = 360.0;
  91.     scale_value = 360.0/(ABS(maxValue-minValue));
  92.     pieChart = hidden = jumpToMousePoint = NO;
  93.     return self;
  94. }
  95.  
  96. - drawSelf:(const NXRect *)cellFrame inView:controlView
  97. {
  98.     center.x = cellFrame->size.width/2;
  99.     center.y = cellFrame->size.height/2;
  100.     radius = ( center.x < center.y ? center.x : center.y) - 4;
  101.     scalex = cellFrame->size.height/ cellFrame->size.width;
  102.     scaley = cellFrame->size.width / cellFrame->size.height;
  103.  
  104.     if ([controlView isFlipped]){
  105.         imFlipped = YES;
  106.     }
  107.     if (hidden == YES){
  108.     [controlView lockFocus];
  109.     /* PSsetgray(0.66666); */
  110.     NXSetColor(NX_COLORLTGRAY);
  111.     PSrectfill(cellFrame->origin.x,cellFrame->origin.y,cellFrame->size.width,cellFrame->size.height);
  112.     [controlView unlockFocus]; 
  113.     return self;
  114.     }
  115.     [controlView lockFocus];
  116.     PSgsave();
  117.     if (imFlipped) {
  118.         PSscale(1.0, -1.0);
  119.     }
  120.     if (cFlags1.bezeled == 1){
  121.     NXDrawButton(cellFrame,cellFrame);
  122.     }else{
  123.     if (cFlags1.bordered == 1){
  124.         /* PSsetgray(0.0); */
  125.         NXSetColor(NX_COLORBLACK);
  126.         NXFrameRect(cellFrame);
  127.     }
  128.     }
  129.  
  130.     if (pieChart == NO){
  131.     PSDrawBackground(cellFrame->size.height,cellFrame->size.width, center.x,center.y,radius);
  132.     }else{
  133.     if (cFlags1.disabled == 0)
  134.         PSDrawBackground(cellFrame->size.height,cellFrame->size.width, center.x,center.y,radius);
  135.     }
  136.     PSgrestore();
  137.     [controlView unlockFocus];
  138.  
  139.     [self drawInside:cellFrame inView:controlView];
  140.     return self;
  141. }
  142.  
  143. - drawInside:(const NXRect *)cellFrame inView:aView  /* Draws only control portion not bezzel */
  144. {
  145.     float x,y;
  146.  
  147.   
  148.     if (jumpToMousePoint == NO){
  149.     currentang += deltaAngle;
  150.     if (currentang > 360.0)
  151.         currentang -= 360.0;
  152.     if (currentang < 0.0)
  153.         currentang += 360.0;
  154.     }
  155.  
  156.     [aView lockFocus];
  157.     PSgsave();
  158.     if (imFlipped) {
  159.         PSscale(1.0, -1.0);
  160.     }
  161.  
  162.     if (pieChart){
  163.     if (cFlags1.disabled == 0){ 
  164.         PSPieChart(cellFrame->size.height,cellFrame->size.width, 
  165.                center.x,center.y,radius,currentang);
  166.     }else{
  167.         PSPieChartDisabled(cellFrame->size.height,cellFrame->size.width, 
  168.                    center.x,center.y,radius,currentang);
  169.     }
  170.     }else{
  171.     if (cFlags1.disabled == 0){ 
  172.         xycoord(currentang,radius,&x,&y);
  173.         PSControlKnob(cellFrame->size.height,cellFrame->size.width, center.x,center.y,radius,x,y);
  174.     }else{
  175.         PSControlKnobDisabled(cellFrame->size.height,cellFrame->size.width, center.x,center.y,radius);
  176.     }
  177.     }
  178.     PSgrestore();
  179.     [aView unlockFocus];
  180.     return self;
  181. }
  182.  
  183. - (BOOL)startTrackingAt:(const NXPoint *)startPoint inView:aView
  184. {
  185.     return YES;
  186. }
  187.  
  188. - (BOOL)trackMouse:(NXEvent *)theEvent inRect:(const NXRect *)cellFrame ofView:aView
  189. {
  190.     int             looping;                /* Flag for while in modal loop     */
  191.     int             oldMask;                /* Old event mask                   */
  192.     NXPoint         startPoint;             /* Location of mouseDown            */
  193.     NXPoint         currentPoint;           /* Location of mouseDragged/mouseUp */
  194.     float           newangle   = 0.0;
  195.     float           startangle = 0.0;
  196.  
  197.     if ((cFlags1.disabled == 0) && (hidden == NO)){ 
  198.     /* Allow mouseDragged events */
  199.     oldMask = [[aView window] addToEventMask:NX_MOUSEDRAGGEDMASK];
  200.     
  201.     /* Get the location of the mouseDown in view coordinates */
  202.     startPoint = theEvent->location;
  203.     [aView convertPoint:&startPoint fromView:nil];
  204.     
  205.     if ([self startTrackingAt:&startPoint inView:aView]){
  206.         
  207.         /* Adjust the mouseDown event's location if the Slider has been
  208.          * scaled in either the x or y direction
  209.          */
  210.         
  211.         if (scalex > scaley ){
  212.         startangle = angle(scalex*(startPoint.x-(center.x)),startPoint.y-(center.y));
  213.         }else
  214.         if (scalex < scaley ){
  215.             startangle = angle(startPoint.x-(center.x),scaley*(startPoint.y-(center.y)));
  216.         }else
  217.             startangle = angle(startPoint.x-(center.x),startPoint.y-(center.y));
  218.         
  219.         if (jumpToMousePoint == YES){
  220.         currentang = startangle;
  221.         [self drawInside:cellFrame inView:aView];
  222.         [[aView window] flushWindow];
  223.         }
  224.         
  225.         /* Run modal loop until mouse up */
  226.         looping = YES;
  227.         while (looping) {
  228.         /* Get the next mouseDragged/mouseUp event */
  229.         theEvent=[NXApp getNextEvent:NX_MOUSEUPMASK|NX_MOUSEDRAGGEDMASK];
  230.         
  231.         /* Convert location to view coordinates */
  232.         currentPoint = theEvent->location;
  233.         [aView convertPoint:¤tPoint fromView:nil];
  234.         
  235.         /* Handle the event */
  236.         if (theEvent->type == NX_MOUSEDRAGGED) {
  237.             
  238.             /* Adjust the mouseDown event's location if the Slider has been
  239.              * scaled in either the x or y direction
  240.              */
  241.             
  242.             if (scalex > scaley ){
  243.             newangle = angle(scalex*(currentPoint.x-(center.x)),currentPoint.y-(center.y));
  244.             }else
  245.             if (scalex < scaley ){
  246.                 newangle = angle(currentPoint.x-(center.x),scaley*(currentPoint.y-(center.y)));
  247.             }else
  248.                 if (scalex = scaley ){
  249.                 newangle = angle(currentPoint.x-(center.x),currentPoint.y-(center.y));
  250.                 }
  251.             if (jumpToMousePoint == NO){
  252.             deltaAngle = newangle - startangle;
  253.             startangle = newangle;
  254.             }else{
  255.             currentang = newangle;
  256.             }
  257.             if (!finite(currentang)){
  258.             currentang = 0.0;
  259.             }
  260.             if (!finite(deltaAngle)){
  261.             deltaAngle = 0.0;
  262.             }
  263. #if 0
  264.             if (currentang != currentang){ /* If this occurs, ie this test is true then 
  265.                             * currentang == NAN */
  266.             currentang = 0.0;
  267.             }
  268.             if (deltaAngle != deltaAngle){ /* If this occurs, ie this test is true then
  269.                             * deltaAngle == NAN */
  270.             deltaAngle = 0.0;
  271.             }
  272. #endif
  273.             [self drawInside:cellFrame inView:aView];
  274.             [[aView window] flushWindow];
  275.             if ([self continueTracking:&startPoint at:¤tPoint inView:aView]){
  276.             [aView sendAction: action to: target];
  277.             }
  278.         }else{
  279.             looping = NO;
  280.             [[aView window] flushWindow];
  281.             [aView sendAction: action to: target];
  282.         }
  283.         startPoint.x = currentPoint.x;
  284.         startPoint.y = currentPoint.y;        
  285.         }
  286.         [aView sendAction: action to: target];
  287.     }
  288.     [[aView window] setEventMask:oldMask];
  289.     return YES;
  290.     }
  291.     return NO;
  292. }
  293.  
  294. - highlight:(const NXRect *)cellFrame inView:aView lit:(BOOL)flag
  295. {
  296.     return self;
  297. }
  298.  
  299. - (float)floatValue
  300. {
  301.     value = (currentang/scale_value) + minValue;
  302.  
  303.     return(value);
  304. }
  305.  
  306. - (double)doubleValue
  307. {
  308.     return((double)[self floatValue]);
  309. }
  310.  
  311. - (int)intValue
  312. {
  313.     return((int)[self floatValue]);
  314. }
  315.  
  316. - setDoubleValue:(double)aDouble
  317. {
  318.     [self setFloatValue:(float)aDouble];
  319.     return self;
  320. }
  321.  
  322. - setFloatValue:(float)aFloat
  323. {
  324.     if (aFloat < minValue){
  325.     value = minValue;
  326.     currentang = 0;
  327.     }else
  328.     if (aFloat > maxValue){
  329.         value = maxValue;
  330.         currentang = 360.0;
  331.         }else{
  332.         value = aFloat;
  333.         currentang = (value - minValue)*scale_value;
  334.     }
  335.  
  336.     return self;
  337. }
  338.  
  339. - setIntValue:(int)aInt
  340. {
  341.     [self setFloatValue:(float)aInt];
  342.     return self;
  343. }
  344.  
  345. - (float)minValue
  346. {
  347.     return minValue;
  348. }
  349.  
  350. - setMinValue:(float)aFloat
  351. {
  352.     float scale = ABS(aFloat-minValue);
  353.     if (scale != 0.0){
  354.     minValue = aFloat;
  355.     scale_value = 360.0/(ABS(maxValue-minValue));
  356.     }
  357.     return self;
  358. }
  359.  
  360. - (float)maxValue
  361. {
  362.     return maxValue;
  363. }
  364.  
  365. - setMaxValue:(float)aFloat
  366. {
  367.     float scale = ABS(aFloat-minValue);
  368.     if (scale != 0.0){
  369.     maxValue = aFloat;
  370.     scale_value = 360.0/scale;
  371.     }
  372.     return self;
  373. }
  374.  
  375. - setDrawAsPieChart:(BOOL)aBOOL
  376. {
  377.     pieChart = aBOOL;
  378.     return self;
  379. }
  380.  
  381. - (BOOL)drawAsPieChart
  382. {
  383.     return pieChart;
  384. }
  385.  
  386. - setJumpToMousePoint:(BOOL)aBOOL
  387. {
  388.     jumpToMousePoint = aBOOL;
  389.     return self;
  390. }
  391.  
  392. - (BOOL)jumpToMousePoint
  393. {
  394.     return jumpToMousePoint;
  395. }
  396.  
  397. - setHidden:(BOOL)flag
  398. {
  399.     hidden = flag;
  400.     return self;
  401. }
  402.  
  403. - (BOOL)hidden
  404. {
  405.     return hidden;
  406. }
  407.  
  408. - read:(NXTypedStream *)stream
  409. {
  410.     [super read:stream];
  411.     NXReadTypes(stream,"fff",&value,&maxValue,&minValue);
  412.     NXReadTypes(stream,"ccc",&pieChart,&jumpToMousePoint,&hidden);
  413.     NXReadTypes(stream,"ff",¤tang,&radius);
  414.     NXReadPoint(stream,¢er);
  415.     NXReadTypes(stream,"ffff",&deltaAngle,&scale_value,&scalex,&scaley);
  416.     return self;
  417. }
  418.  
  419. - write:(NXTypedStream *)stream
  420. {
  421.     [super write:stream];
  422.     NXWriteTypes(stream,"fff",&value,&maxValue,&minValue);
  423.     NXWriteTypes(stream,"ccc",&pieChart,&jumpToMousePoint,&hidden);
  424.     NXWriteTypes(stream,"ff",¤tang,&radius);
  425.     NXWritePoint(stream,¢er);
  426.     NXWriteTypes(stream,"ffff",&deltaAngle,&scale_value,&scalex,&scaley);
  427.     return self;
  428. }
  429.  
  430. @end
  431.  
  432.