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

1.1     ! root        1: /* 
        !             2:  * ClockView.m, a simple clock view 
        !             3:  * Author: Ali T. Ozer, NeXT Developer Support Group
        !             4:  * Created: May 26, 1989 (for version 0.9)
        !             5:  * Modified: June 14 and Aug 14, 1989 (for version 1.0)
        !             6:  * Redesigned for 2.0 by Julie Zelenski, NeXT Developer Support
        !             7:  * Modified some for 3.0 by Ali Ozer, AppKit Group, May 28, 1992
        !             8:  *
        !             9:  * Subclass of view to implement a simple clock. This view is pretty generic 
        !            10:  * and can probably be added to any program. The setClockType: method lets 
        !            11:  * you display an analog, digital, or sundial face.  You have the option of 
        !            12:  * turning the seconds hand on or off, as well as controlling whether the date 
        !            13:  * is also displayed.  
        !            14:  *  
        !            15:  * You may freely copy, distribute and reuse the code in this example.  
        !            16:  * NeXT disclaims any warranty of any kind, expressed or implied, as to its 
        !            17:  * fitness for any particular use.
        !            18:  */
        !            19: 
        !            20: #import <appkit/appkit.h>
        !            21: #import "ClockView.h"
        !            22: #import "Clock.h"      // PSwrap routines
        !            23: #import <objc/NXStringTable.h>
        !            24: #import <string.h>
        !            25: #import <sys/time.h>   
        !            26: 
        !            27: 
        !            28: @implementation ClockView:View
        !            29: 
        !            30: 
        !            31: #define PI (double)3.1415926535897
        !            32:        
        !            33: #define ANALOG 0       
        !            34: #define DIGITAL        1
        !            35: #define SUNDIAL 2
        !            36: 
        !            37: 
        !            38: 
        !            39: /* ShowTime() is the timed entry function called by the
        !            40:  * timed entry mechanism. It first writes the time out on the face 
        !            41:  * of the clock, and then reinstalls the timed entry if the clock is 
        !            42:  * not showing the seconds. If the seconds are being shown, no need to 
        !            43:  * reinstall the timed entry; a second skipped here and then won't matter. 
        !            44:  * If minutes are being shown, we want to make sure that the minute jumps 
        !            45:  * at the next top of the minute, regardless of how long it took to service 
        !            46:  * the timed entry.
        !            47:  */
        !            48: void ShowTime (teNum, now, clock) 
        !            49: DPSTimedEntry teNum;
        !            50: double now;
        !            51: id clock;
        !            52: {
        !            53:     [clock display];    
        !            54:     if ([clock showSeconds] == NO) [[clock stopTimedEntry] startTimedEntry:NO];
        !            55: }
        !            56: 
        !            57: 
        !            58: 
        !            59:  
        !            60: - initFrame:(const NXRect *)frameRect
        !            61: /* initFrame for newly created view, initializes the various parameters,
        !            62:  * grabs some fonts to be used later.
        !            63:  */
        !            64: {
        !            65:     [super initFrame:frameRect];
        !            66: 
        !            67:     face = [[NXImage allocFromZone:[self zone]] initSize:&bounds.size];
        !            68:     [face useDrawMethod:@selector(drawFace:) inObject:self];
        !            69: 
        !            70:     littleFont = [Font newFont:"Helvetica" size:12 style:0
        !            71:                        matrix:NX_IDENTITYMATRIX];
        !            72:     mediumFont = [Font newFont:"Times-Roman" size:14 style:0
        !            73:                        matrix:NX_IDENTITYMATRIX];
        !            74:     bigFont = [Font newFont:"Times-Roman" size:24 style:0
        !            75:                        matrix:NX_IDENTITYMATRIX];
        !            76: 
        !            77:     /* Set the default state (analog face, no seconds, date on) */
        !            78:     clockType = ANALOG;
        !            79:     showSeconds = NO;
        !            80:     showDate = YES;
        !            81:     center.x = bounds.size.width/2.0;
        !            82:     center.y = bounds.size.height/2.0 + [mediumFont pointSize]/2.0;
        !            83:     radius = MIN(center.x,center.y-[mediumFont pointSize]);
        !            84:     [face recache];
        !            85:     
        !            86:     /* Start the time entry. YES indicates that this is the first time */
        !            87:     [self startTimedEntry:YES];
        !            88:     [self display];
        !            89:     return self;
        !            90: }
        !            91: 
        !            92: 
        !            93: - free
        !            94: /* Good idea to get rid of the timed entry while freeing... 
        !            95:  */
        !            96: {
        !            97:     [face free];
        !            98:     [self stopTimedEntry];
        !            99:     return [super free];
        !           100: }
        !           101: 
        !           102: 
        !           103: /* SET/GET CLOCK PARAMETERS */
        !           104: 
        !           105: - setShowSeconds:(BOOL)newValue
        !           106: /* setShowSeconds: sets whether or not the seconds hand is shown.
        !           107:  * The timed entry must be reinstalled whenever this setting is changed
        !           108:  * as time to the next firing changes.
        !           109:  */
        !           110: { 
        !           111:     showSeconds = newValue;
        !           112:     [[self stopTimedEntry] startTimedEntry:NO];
        !           113:     [self display];
        !           114:     return self;
        !           115: }
        !           116: 
        !           117: - setShowDate:(BOOL)newValue
        !           118: /* setShowDate: sets whether or not the date is shown.
        !           119:  */
        !           120: { 
        !           121:     showDate = newValue;
        !           122:     [self display];
        !           123:     return self;
        !           124: }
        !           125: 
        !           126: - setClockType:(int)newValue
        !           127: /* setClockType: sets which type of clock is drawn (analog, digital, or 
        !           128:  * sundial).
        !           129:  */
        !           130: {
        !           131:     clockType = newValue;
        !           132:     [face recache];
        !           133:     [self display];
        !           134:     return self;
        !           135: }
        !           136: 
        !           137: - (BOOL)showSeconds 
        !           138: { 
        !           139:     return showSeconds; 
        !           140: }
        !           141: - (BOOL)showDate
        !           142: { 
        !           143:     return showDate; 
        !           144: }
        !           145: - (int)clockType
        !           146: {
        !           147:     return clockType;
        !           148: }
        !           149: 
        !           150: 
        !           151: /* TARGET/ACTION METHODS */
        !           152: 
        !           153: - changeShowDate:sender;
        !           154: {
        !           155:      return [self setShowDate:[[sender selectedCell] state]];
        !           156: }
        !           157: - changeShowSeconds:sender
        !           158: {
        !           159:     return [self setShowSeconds:[[sender selectedCell] state]];
        !           160: }
        !           161: - changeClockType:sender
        !           162: {
        !           163:     return [self setClockType:[sender selectedTag]];
        !           164: }
        !           165: 
        !           166: /* String keys used for look-up into string tables */
        !           167: 
        !           168: static const char *monthKeys[12] = {"Jan","Feb","Mar","Apr","May","Jun","Jul","Aug","Sep","Oct","Nov","Dec"};
        !           169: static const char *months[12];
        !           170: static const char *weekKeys[7] = {"Sun","Mon","Tue","Wed","Thu","Fri","Sat"};
        !           171: static const char *weekdays[7];
        !           172: static const char *romanDays[31] = {"I","II","III","IV","V","VI","VII","VIII","IX","X","XI","XII",
        !           173: "XIII","XIV","XV","XVI","XVII","XVIII","XIX","XX","XXI","XXII","XXIII",
        !           174: "XXIV","XXV","XXVI","XXVII","XXVIII","XXIX","XXX", "XXXI"};
        !           175: 
        !           176: - setSTable:anObject;
        !           177: /* Get string values for months, weekdays from NXStringTable, they are stored
        !           178:  * as static class variables.
        !           179:  */  
        !           180: {
        !           181:     int i;
        !           182:     
        !           183:     sTable = anObject;
        !           184:     for (i = 0; i < 7; i++)
        !           185:          weekdays[i] = [sTable valueForStringKey:weekKeys[i]];
        !           186:     for (i = 0; i < 12; i++) 
        !           187:          months[i] = [sTable valueForStringKey:monthKeys[i]];
        !           188:     return self;
        !           189: }
        !           190: 
        !           191: /* PRIVATE METHODS */
        !           192: 
        !           193: #define HOURRATIO      0.5     /* Hour hand length compared face size */
        !           194: #define MINUTERATIO    0.85    /* Minute & seconds hands */
        !           195: 
        !           196: - drawAnalog:(struct tm *)time;
        !           197: /* drawAnalog draws the clock hands and date for the analog clock face
        !           198:  */
        !           199: {
        !           200:     int min,hour,sec;   
        !           201:     char dateString[15];
        !           202: 
        !           203:     min  = time->tm_min;
        !           204:     hour = time->tm_hour; 
        !           205:     sec  = time->tm_sec;
        !           206:     
        !           207:     if (showSeconds) 
        !           208:         PSWdrawClockHand (center.x,center.y,-6.0 * sec, radius*MINUTERATIO, 
        !           209:                        NX_DKGRAY, 0.0);
        !           210:     PSWdrawClockHand (center.x,center.y, -(hour+min/60.0) * 30.0, 
        !           211:                radius*HOURRATIO, NX_BLACK, 1.0);
        !           212:     PSWdrawClockHand (center.x,center.y,- fmod(min,60.0) * 6.0, 
        !           213:                radius*MINUTERATIO, NX_BLACK, 1.0);
        !           214:     if (showDate) {
        !           215:         [littleFont set];
        !           216:        sprintf(dateString,"%s %s %d",weekdays[time->tm_wday],
        !           217:                                months[time->tm_mon],
        !           218:                                time->tm_mday);
        !           219:        PSWcenterShow(center.x+1.0,3.0,dateString,NX_WHITE);
        !           220:        PSWcenterShow(center.x,3.0,dateString,NX_DKGRAY);
        !           221:     }
        !           222:     return self;
        !           223: }
        !           224: 
        !           225: - drawDigital:(struct tm *)time;
        !           226: /* drawDigital draws the time and date for the digital clock face
        !           227:  */
        !           228: {
        !           229:     int hour;
        !           230:     char timeString[10];
        !           231:     char dateString[15];
        !           232:     
        !           233:     hour = fmod(time->tm_hour,12); /* get us off military time */
        !           234:     if (!hour) hour = 12;  /* if noon or midnight */
        !           235:     if (showSeconds)
        !           236:         sprintf(timeString,"%d:%.2d:%.2d",hour,
        !           237:                                        time->tm_min,
        !           238:                                        time->tm_sec);
        !           239:     else 
        !           240:         sprintf(timeString,"%d:%.2d", hour,time->tm_min);
        !           241:     [bigFont set];
        !           242:     PSWcenterShow(center.x,center.y-8.0,timeString,NX_BLACK);
        !           243:     if (showDate) {
        !           244:        sprintf(dateString,"%s %s %d",weekdays[time->tm_wday],
        !           245:                                months[time->tm_mon],
        !           246:                                time->tm_mday);
        !           247:        [mediumFont set];
        !           248:        PSWcenterShow(center.x,center.y-24.0,dateString,NX_BLACK);
        !           249:     }
        !           250:     return self;
        !           251: }
        !           252: 
        !           253: #define SHADOWRATIO .95                /* shadow length when compared to radius */
        !           254: #define MARKERRATIO .15                /* height of marker when compared to radius */
        !           255: 
        !           256: - drawSundial:(struct tm *)time;
        !           257: /* drawSundial draws the shadow and date for the sundial clock face
        !           258:  */
        !           259: {   
        !           260:     float percentOfDay;
        !           261:     char dateString[15];
        !           262:     NXPoint edge;
        !           263: 
        !           264:     if (showSeconds) 
        !           265:         PSWdrawSweep (center.x,center.y,-6.0 *time->tm_sec,radius*.75);
        !           266:     percentOfDay = (time->tm_hour*60 + time->tm_min)/(24.0*60.0);
        !           267:     edge.x  = sin(percentOfDay*PI*2)*radius*SHADOWRATIO;
        !           268:     edge.y = cos(percentOfDay*PI*2)*radius*SHADOWRATIO;
        !           269:     PSWdrawShadow(center.x,center.y,edge.x,edge.y,radius*MARKERRATIO);
        !           270:     if (showDate) {
        !           271:        [mediumFont set];
        !           272:        sprintf(dateString,"%s %s", months[time->tm_mon],
        !           273:                        romanDays[time->tm_mday-1]);
        !           274:        PSWcenterShow(center.x,12.0,dateString,NX_BLACK);
        !           275:     }
        !           276:     return self;
        !           277: }
        !           278: 
        !           279: - drawFace:image
        !           280: /* drawFace draws the clock face image.  This
        !           281:  * image is composited on screen and then the hands, shadow,
        !           282:  * whatever is drawn on top of the face for the current time.
        !           283:  */
        !           284: {
        !           285:     PSsetgray (NX_LTGRAY);
        !           286:     NXRectFill (&bounds);      // Erase background
        !           287:     switch (clockType) {
        !           288:         case ANALOG:   PSWdrawAnalogFace(center.x,center.y,radius);
        !           289:                        break;
        !           290:        case DIGITAL:   /* digital "face" is just blank */
        !           291:                        break;
        !           292:        case SUNDIAL:   PSWdrawSundialFace(center.x,center.y, radius);
        !           293:                        break;
        !           294:     }
        !           295:     return self;
        !           296: }
        !           297: 
        !           298: 
        !           299: - drawSelf:(NXRect *)rects :(int)rectCount
        !           300: /* Draws face and hands of clock.
        !           301:  * The clock face image in face is copied into the bounds of the 
        !           302:  * view, and a routine is called to display the current date and time
        !           303:  */ 
        !           304: {      
        !           305:     struct tm *localTime;
        !           306:     struct timeval currentTime;
        !           307: 
        !           308:     // If recache was called, or if printing, this will first redraw
        !           309:     // the clock face by calling drawFace:
        !           310:     [face composite:NX_COPY toPoint:&bounds.origin];
        !           311: 
        !           312:     gettimeofday (&currentTime, NULL);
        !           313:     localTime = localtime (&(currentTime.tv_sec));
        !           314:     switch (clockType) {
        !           315:         case ANALOG:   [self drawAnalog:localTime];
        !           316:                        break;
        !           317:        case DIGITAL:   [self drawDigital:localTime];
        !           318:                        break;
        !           319:        case SUNDIAL:   [self drawSundial:localTime];
        !           320:                        break;
        !           321:     }
        !           322:     return self;
        !           323: }
        !           324: 
        !           325: 
        !           326: - startTimedEntry:(BOOL)fireASAP
        !           327: /* startTimedEntry will install the timed entry. If fireASAP is YES, the
        !           328:  * timed entry is set to fire off as soon as possible (this would be the case
        !           329:  * at the start of the program, for instance). If fireASAP is NO, then the
        !           330:  * timed entry is set to fire off in one second (if seconds are being shown)
        !           331:  * or at the top of the next minute (in anytime between 0 and 60 seconds).
        !           332:  */
        !           333: {
        !           334:     double fireIn;
        !           335: 
        !           336:     if (fireASAP) fireIn = 0.0;                  // Fire as soon as possible!
        !           337:     else if (showSeconds) fireIn = 1.0;          // Fire in a second (good enough)
        !           338:     else {
        !           339:         struct timeval currentTime;
        !           340:        gettimeofday (&currentTime, NULL);
        !           341:        fireIn = 60.0 - (currentTime.tv_sec % 60);  // Top of the minute
        !           342:     }
        !           343:        
        !           344:     teNum = DPSAddTimedEntry(fireIn, &ShowTime, self, NX_MODALRESPTHRESHOLD);
        !           345:     return self;
        !           346: }
        !           347: 
        !           348: - stopTimedEntry
        !           349: /* Removes the clock timed entry.
        !           350:  */
        !           351: {
        !           352:     if (teNum)
        !           353:          DPSRemoveTimedEntry (teNum);
        !           354:     teNum = (DPSTimedEntry)0;
        !           355:     return self;
        !           356: }
        !           357: 
        !           358: 
        !           359: - sizeTo:(NXCoord)w :(NXCoord)h
        !           360: /* Overriding sizeTo:: allows us to resize and fix up the clock whenever
        !           361:  * the size is changed.  Figure the radius of the clock (based on the size
        !           362:  * of the view) and then redraw
        !           363:  */
        !           364: {
        !           365:     [super sizeTo:w :h];
        !           366:     center.x = bounds.size.width/2.0;
        !           367:     center.y = bounds.size.height/2.0 + [mediumFont pointSize]/2.0;
        !           368:     radius = MIN(center.x, center.y-[mediumFont pointSize]);
        !           369:     [face setSize:&bounds.size];
        !           370:     return self;
        !           371: }
        !           372: 
        !           373: @end

unix.superglobalmegacorp.com

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