Annotation of Examples/AppKit/BusyBox/GaugeView.m, revision 1.1

1.1     ! root        1: /* 
        !             2:  * GaugeView.m, analog gauge view
        !             3:  * Author: Bruce Blumberg, NeXT Developer Support Group.
        !             4:  * Originally written for 0.6 mid 1988, modified for 1.0 by Ali Ozer.
        !             5:  * Redesigned for 2.0 by Julie Zelenski, NeXT Developer Support
        !             6:  *
        !             7:  * Subclass of view to implement a simple round analog gauge. You can set the 
        !             8:  * minimum, maximum value, start angle, angle range, title, font, and more.  
        !             9:  * It is a pretty generic round gauge view, if you ever have need for one.
        !            10:  *
        !            11:  * You may freely copy, distribute and reuse the code in this example.  
        !            12:  * NeXT disclaims any warranty of any kind, expressed or implied, as to 
        !            13:  * its fitness for any particular use.
        !            14:  */
        !            15: 
        !            16: #import "GaugeView.h"
        !            17: #import "Gauge.h"      // PSwrap routines
        !            18: #import <appkit/Font.h>
        !            19: #import <appkit/Window.h>
        !            20: #import <appkit/Slider.h>
        !            21: #import <soundkit/Sound.h>
        !            22: #import <dpsclient/wraps.h>    // PScomposite(), ...
        !            23: #import <math.h>               // sin(), cos(), ...
        !            24: #import <string.h>             // strcpy(), ...
        !            25: 
        !            26: 
        !            27: @implementation GaugeView : View
        !            28: 
        !            29: 
        !            30: #define HANDRATIO      0.65    /* hand length compared face size */
        !            31: 
        !            32: - initFrame:(NXRect *)frameRect; 
        !            33: /* Basic initFrame method which just calls the more complicated 
        !            34:  * initFrame:min:max... method with some generally good default values.
        !            35:  */
        !            36: {
        !            37:     [self initFrame:frameRect min:0.0 max:100.0 
        !            38:                startAngle:215.0 range:250.0 tickInterval:10]; 
        !            39:     return self;
        !            40: }
        !            41: 
        !            42: - initFrame:(NXRect *)frameRect min:(float)min max:(float)max 
        !            43:        startAngle:(float)start range:(float)range tickInterval:(int)interval
        !            44: /* Init method for newly created analog gauge. It creates the face of the 
        !            45:  * gauge in an offscreen window called cacheWindow when drawSelf:: is called 
        !            46:  * the image is composited into the view and the hand is drawn on top of the 
        !            47:  * face.
        !            48:  */
        !            49: {
        !            50:     [super initFrame:frameRect];
        !            51:        /* Create offscreen window for face. Note that the defer: argument
        !            52:         * has to be NO for windows which will remain offscreen. Deferred
        !            53:         * windows only get created on a orderFront: (or any other method
        !            54:         * that causes them to come on screen).
        !            55:         */
        !            56:     cacheWindow = [[Window allocFromZone:[self zone]]
        !            57:                         initContent:frameRect 
        !            58:                                style:NX_PLAINSTYLE
        !            59:                             backing:NX_RETAINED 
        !            60:                          buttonMask:0 
        !            61:                               defer:NO];    
        !            62:     startAngle = start;
        !            63:     angleRange = range;
        !            64:     tickInterval = interval;
        !            65:     value = min;
        !            66:     [self setMin:min];
        !            67:     [self setMax:max];
        !            68:     [self setFont:"Helvetica" size:10.0];
        !            69:     [self setTitle:"Stress"];
        !            70:     center.x = bounds.size.width/2.0;
        !            71:     center.y = bounds.size.height/2.0;
        !            72:     radius = (bounds.size.height/2.0) - 8.0;
        !            73: 
        !            74:     /* This pswrap creates a PS function which is used to draw the hand. */
        !            75:     PSWmakeHand(radius*HANDRATIO);
        !            76:     [self drawFace];
        !            77:     return self;
        !            78: }
        !            79: 
        !            80: - free;
        !            81: /* Free cacheWindow, too!
        !            82:  */
        !            83: {
        !            84:     [cacheWindow free];
        !            85:     return [super free];
        !            86: }
        !            87: 
        !            88: 
        !            89: /* SET PARAMETERS */
        !            90: 
        !            91: - setFont:(char *)fName size:(float)fSize
        !            92: /* Sets font used for drawing title and numbers. Change is displayed
        !            93:  * next time drawSelf:: is executed. needRedraw is set to indicate that 
        !            94:  * face image must be redrawn.
        !            95:  */
        !            96: {      
        !            97:     font = [Font newFont:fName size:fSize style:0 matrix:NX_IDENTITYMATRIX];
        !            98:     needRedraw = YES;
        !            99:     return self;
        !           100: }
        !           101: 
        !           102: - setTitle:(char *)str;
        !           103: /* Sets title of gauge.  needRedraw is set to indicate that 
        !           104:  * face image must be redrawn.
        !           105:  */
        !           106: {
        !           107:     strcpy(title,str);
        !           108:     needRedraw = YES;
        !           109:     return self;
        !           110: }
        !           111: 
        !           112: - setMin:(float)newValue;
        !           113: /* Sets minimum for gauge, recalculates degreesPerUnit which is used to 
        !           114:  * determine interval of ticks and labels. needRedraw is set to indicate that 
        !           115:  * face image must be redrawn.
        !           116:  */
        !           117: {
        !           118:     minValue = newValue;
        !           119:     degreesPerUnit = angleRange/(maxValue-minValue);
        !           120:     needRedraw = YES;
        !           121:     return self;
        !           122: }
        !           123: 
        !           124: - setMax:(float)newValue;
        !           125: /* Sets maximum for gauge, recalculates degreesPerUnit which is used to 
        !           126:  * determine interval of ticks and labels. needRedraw is set to indicate that 
        !           127:  * face image must be redrawn.
        !           128:  */
        !           129: {
        !           130:     maxValue = newValue;
        !           131:     degreesPerUnit = angleRange/(maxValue-minValue);
        !           132:     needRedraw = YES;
        !           133:     return self;
        !           134: }
        !           135: 
        !           136: - setStartAngle:(float)newValue;
        !           137: /* Sets start angle for gauge, which is the angle of the arm when at the 
        !           138:  * minimum value.  needRedraw is set to indicate that face image must be 
        !           139:  * redrawn.
        !           140:  */
        !           141: {
        !           142:     startAngle = newValue;
        !           143:     needRedraw = YES;
        !           144:     return self;
        !           145: }
        !           146: 
        !           147: - setAngleRange:(float)newValue;
        !           148: /* Sets angle range for gauge, which is the sweep of the arm from minimum
        !           149:  * value to maximum value.  The value cannot exceed 360 degrees (a full
        !           150:  * revolution).  Recalculates degreesPerUnit which is used to 
        !           151:  * determine interval of ticks and labels. needRedraw is set to indicate that 
        !           152:  * face image must be redrawn.
        !           153:  */
        !           154: {
        !           155:     if (newValue > 360) newValue = 360.0;
        !           156:     angleRange = newValue;
        !           157:     degreesPerUnit = angleRange/(maxValue-minValue);
        !           158:     needRedraw = YES;
        !           159:     return self;
        !           160: }
        !           161: 
        !           162: - setTickInterval:(int)newValue;
        !           163: /* Sets tick interval for gauge, which is number of units between tick
        !           164:  * marks on gauge face.  needRedraw is set to indicate that 
        !           165:  * face image must be redrawn.
        !           166:  */
        !           167: {
        !           168:     tickInterval = newValue;
        !           169:     needRedraw = YES;
        !           170:     return self;
        !           171: }
        !           172: 
        !           173: 
        !           174: - setValueFormCell:anObject;
        !           175: {
        !           176:     valueFormCell = anObject;
        !           177:     [valueFormCell setFloatingPointFormat:NO left:3 right:0];
        !           178:     return self;
        !           179: }
        !           180: 
        !           181: - (BOOL)textWillEnd:textObject;
        !           182: /* Rejects entry into the form cell if it isn't in the range of the
        !           183:  * min and max value for the gauge.
        !           184:  */
        !           185: {
        !           186:     id cell;
        !           187:     float newValue;
        !           188:     
        !           189:     cell = [textObject delegate];
        !           190:     newValue = [cell floatValue];
        !           191:     return (newValue > maxValue) || (newValue < minValue);
        !           192: }
        !           193: 
        !           194: /* TARGET/ACTION METHODS  */
        !           195: 
        !           196: - changeValue:sender
        !           197: /* Target/Action for a IB control.  Takes floatValue from control (could be
        !           198:  * slider or field), makes sure slider and field are in sync,  displays arm 
        !           199:  * at new value.
        !           200:  */
        !           201: {   float newValue;
        !           202: 
        !           203:     newValue = [sender floatValue];
        !           204:     if (newValue != value) {   // if value changed
        !           205:         value = newValue;
        !           206:         if (sender == valueSlider)
        !           207:            [valueFormCell setFloatValue:newValue];
        !           208:        else
        !           209:            [valueSlider setFloatValue:newValue];
        !           210:        [self display]; 
        !           211:        if (value == maxValue)  // if at maximum value
        !           212:             [[Sound findSoundFor:"HighStress"] play];
        !           213:     }
        !           214:     return self;
        !           215: }
        !           216:        
        !           217:        
        !           218: /* PRIVATE METHODS */
        !           219: 
        !           220: - drawFace
        !           221: /* drawFace draws the gauge face image in the offscreen window.  It erases
        !           222:  * the background, draws the circular border, displays the gauge title, 
        !           223:  * draws the tick marks and labels them appropriately. The offscreen cache 
        !           224:  * is composited on screen and then the hand is drawn on top of the face 
        !           225:  * for the current gauge value.
        !           226:  */
        !           227: {      
        !           228:     float angle, angleIncrement;
        !           229:     int number;
        !           230:     NXSize string;
        !           231:     NXPoint pt;
        !           232:     char numString[10];
        !           233:     
        !           234:     [[cacheWindow contentView] lockFocus];
        !           235:     
        !           236:     PSsetgray(NX_LTGRAY);
        !           237:     NXRectFill(&bounds);
        !           238:     PSWdrawBorder(center.x, center.y, radius);
        !           239:     angleIncrement = angleRange/((maxValue-minValue)/tickInterval); 
        !           240:     PSWdrawTicks(center.x, center.y, radius*HANDRATIO,
        !           241:                angleIncrement/2, startAngle, startAngle+angleRange); 
        !           242:     [font set];    
        !           243:     string.height = [font pointSize];
        !           244:     string.width = [font getWidthOf:title];
        !           245:     PSWdrawString((bounds.size.width-string.width)/2, center.y+8, title);
        !           246:     
        !           247:     number =  minValue;
        !           248:     for(angle=startAngle;angle>=startAngle-angleRange;angle -= angleIncrement){
        !           249:         sprintf(numString,"%d",number);
        !           250:        string.width = [font getWidthOf:numString];
        !           251:        pt.x = cos(angle/57.3)*(radius-1.0-string.width/2)+ center.x; 
        !           252:        pt.y = sin(angle/57.3)*(radius-1.0-string.height/2) + center.y ;
        !           253:        PSWdrawString(pt.x-(string.width/2), pt.y-(string.height/2.5),
        !           254:                        numString);
        !           255:        number += tickInterval;
        !           256:     }
        !           257:     
        !           258:     [[cacheWindow contentView] unlockFocus]; 
        !           259:     needRedraw = NO;
        !           260:     return self;
        !           261: }      
        !           262: 
        !           263: 
        !           264: - drawHand
        !           265: /* Calculates the angle for the current value and draws the hand there.
        !           266:  */
        !           267: {
        !           268:     float valueAngle;
        !           269:     
        !           270:     valueAngle = startAngle - degreesPerUnit*(value-minValue);
        !           271:     PSWdrawHand(center.x,center.y,valueAngle);
        !           272:     return self;
        !           273: }
        !           274: 
        !           275: - drawSelf:(NXRect *)drawRects :(int)rectCount
        !           276: /* Draws face and hand of gauge. If needRedraw is YES, a parameter has 
        !           277:  * changed and the face must be redrawn in the offscreen window. 
        !           278:  * Otherwise, the image in cacheWindow is copied into the bounds of the 
        !           279:  * view, and a PSWrap is called which draws the hand in the 
        !           280:  * correct position.
        !           281:  */
        !           282: {
        !           283:        
        !           284:     if (needRedraw)
        !           285:         [self drawFace];
        !           286:     PScomposite(0.0, 0.0, bounds.size.width, bounds.size.height,
        !           287:                [cacheWindow gState], 0.0, 0.0, NX_COPY);
        !           288:     [self drawHand];
        !           289:     return self;
        !           290: }
        !           291: 
        !           292: @end

unix.superglobalmegacorp.com

This archive runs on limited infrastructure. Preserving old code on modern bandwidth. Automated agents are requested to crawl responsibly.