Annotation of Examples/AppKit/BusyBox/ClockView.m, revision 1.1.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.