This is Clock.m in view mode; [Download] [Up]
// Clock.m, simple clock view // Author: Ali T. Ozer, NeXT Developer Support Group // Created: May 26, 1989 (for version 0.9) // Modified: June 14 and Aug 14, 1989 (for version 1.0) // // Modifier: Jiro Nakamura, Independent NeXT Developer // Modified: May 11, 1990 (for Cassandra) // // Subclass of view to implement a simple analog or digital clock. This view is // pretty generic and can probably be added to any program. Different clock // faces can be set through the setBackgroundGray: and setClockGray: methods; // you can also specify TIFF files as background images for the clock through // the setClockFaceToBitmapNamed: method. Finally you have the option of // turning the seconds hand on or off. static char authorid[] = "$Author: jiro $"; static char rcsid[] = "$Id: Clock.m,v 1.3 90/12/03 01:55:16 jiro Exp Locker: jiro $"; #import "Clock.h" #import "ClockPS.h" // PSwrap routines #import <dpsclient/wraps.h> #import <appkit/nextstd.h> #import <appkit/Application.h> #import <appkit/Button.h> #import <appkit/Window.h> #import <objc/typedstream.h> #import <string.h> #import <sys/time.h> #import "calendar.h" // Defining DEBUG for Clock can sometimes get very screen messy // since Cassandra uses it so often #ifdef DEBUG #undef DEBUG #define DEBUG2 #endif #define MAX_CVIEW_WIDTH 14 @implementation Clock // ShowTime() is the timed entry function called by the // timed entry mechanism. It first writes the time out on the face of the // clock, and then reinstalls the timed entry if the clock is not showing the // seconds. If the seconds are being shown, no need to reinstall the timed // entry; a second skipped here and then won't matter. If minutes are being // shown, we want to make sure that the minute jumps at the next top of the // minute, regardless of how long it took to service the timed entry. void ShowTime (teNum, now, clock) DPSTimedEntry teNum; double now; id clock; { [clock display]; if ([clock showSeconds] == NO) [[clock stopTimedEntry] startTimedEntry:NO]; } // newFrame creates the view and initializes the various paramaters. The // constants below determine the lengths of the clock hands. #define HOURRATIO 0.2 /* Hour hand length compared face size */ #define MINUTERATIO 0.35 /* Minute & seconds hands */ + newFrame:(const NXRect *)frm { self = [super newFrame:frm]; [self initMoreStuff]; return self; } - initMoreStuff { char dumbChar[5]; // dumb references to some static constants, just // to avoid warning messages from the compiler (Garance) dumbChar[0] = authorid[0]; // dumb dumbChar[1] = rcsid[0]; // de dumb // Set the default state (no special face, no seconds, grays). clockFace = nil; showSeconds = NO; showDate = NO; backgroundGray = NX_LTGRAY; clockGray = NX_BLACK; [self computeNewSizes]; // Start the time entry. YES indicates that this is the first time. [self startTimedEntry:YES]; return self; } // Good idea to get rid of the timed entry while freeing... - free { [self stopTimedEntry]; return [super free]; } // startTimedEntry will install the timed entry. If fireASAP is YES, the // timed entry is set to fire off as soon as possible (this would be the case // at the start of the program, for instance). If fireASAP is NO, then the // timed entry is set to fire off in one second (if seconds are being shown) // or at the top of the next minute (in anytime between 0 and 60 seconds). - startTimedEntry:(BOOL)fireASAP { double fireIn; if (fireASAP) fireIn = 0.0; // Fire as soon as possible! else if (showSeconds) fireIn = 1.0; // Fire in a second (good enough) else { struct timeval currentTime; gettimeofday (¤tTime, NULL); fireIn = 60.0 - (currentTime.tv_sec % 60); // Top of the minute } clockTE = DPSAddTimedEntry(fireIn, &ShowTime, self, NX_MODALRESPTHRESHOLD); return self; } // stopTimedEntry stops the timed entry. Don't call this method unless // the timed entry is installed an running. - stopTimedEntry { DPSRemoveTimedEntry (clockTE); return self; } // drawSelf:: displays the face of the clock, showing the correct time. // The seconds hand will be shown only if desired. - drawSelf:(NXRect *)rects :(int)rectCount { int min, hour, sec; struct tm *localTime; struct timeval currentTime; static char buf[10]; extern const char *shortWeekDays[7]; extern const char *shortMonths[12]; // Additions by Jiro for target/action response //Send the <action> to the <target>. // Mod Jan 6, 1990 [target perform:action with:self]; gettimeofday (¤tTime, NULL); localTime = localtime (&(currentTime.tv_sec)); min = localTime->tm_min; hour = localTime->tm_hour; sec = localTime->tm_sec; // Erase the background and composite the clock face // in if there is one. // Note that we erase even though we might have a bitmap; // this way if the // bitmap is smaller than the view it'll still look OK. In a more // efficient frame of mind, one could try to avoid unnecessary fills. if (backgroundGray >= 0.0 && backgroundGray <= 1.0) { PSsetgray (backgroundGray); NXRectFill (&bounds); } // If we have a clockface, let's display it if(clockFace != nil) { #ifdef DEBUG fprintf(stderr,"%s: Compositing clock face.\n", PROGNAME); #endif [clockFace composite:NX_COPY toPoint:&compositeTo]; } switch( clockType) { case CLOCK_ANALOG: // Display the seconds arm, if desired, and then // the hours and minutes. if (showSeconds) drawClockHand (-6.0 * sec, minuteLen, clockGray, 0.0); drawClockHand (- (hour + min / 60.0) * 30.0, hourLen, clockGray, 2.0); drawClockHand (- fmod(min, 60.0) * 6.0, minuteLen, clockGray, 2.0); if( showDate) { sprintf(buf, "%s %2d", shortMonths[localTime->tm_mon], localTime->tm_mday); drawClockString( 0, 7, 8, buf); drawClockString( 0, -10, 8, (char *) shortWeekDays[localTime->tm_wday]); } break; case CLOCK_DIGITAL: if( !militaryTime) { if( hour >= 12 ) hour -= 12; if( hour == 0 ) hour = 12; } sprintf(buf, "%2d:%02d", hour, min); drawClockString( 0, 6, 18, buf); sprintf(buf,"%s %s %2d", (char *) shortWeekDays[localTime->tm_wday], shortMonths[localTime->tm_mon], localTime->tm_mday); drawClockString( 0, -1, 8, buf); PSmoveto( -10, -5); PSlineto( 10, -5); PSstroke(); drawClockString( 0, -14, 8, eventTime); drawClockString( 0, -21, 8, eventMessage); break; default: fprintf(stderr,"%s: Unrecognized clock type: %d\n", PROGNAME, clockType); } return self; } // Set the clock face to the specified bitmap. If bitmapName is NULL, // then we have no clock face. - setClockFaceToBitmapNamed:(const char *)bitmapName { #ifdef DEBUG2 fprintf(stderr, "%s: Setting clockface bitmap to %s\n", PROGNAME, bitmapName); #endif if (bitmapName && (clockFace = [NXImage findImageNamed:bitmapName])) { [self computeBitmapLocation]; } else { #ifdef DEBUG2 fprintf(stderr,"%s: Couldn't find a icon for %s.\n", PROGNAME, bitmapName); #endif clockFace = nil; } [self display]; return self; } // Compute and cache the location where the clock face should be // composited into. This method should be invoked everytime the clock face // changes or the view is resized. // // We assume that the view is translated so that the origin is at the center. - computeBitmapLocation { if (clockFace) { NXSize bitmapSize; [clockFace getSize:&bitmapSize]; compositeTo.x = - bitmapSize.width / 2.0; compositeTo.y = - bitmapSize.height / 2.0; } return self; } // Figure the lengths of the hands (based on the size of the view) and // translate the view so that the center is (0,0). - computeNewSizes { // Translate view so that the center is 0,0. [self setDrawOrigin:-bounds.size.width/2.0 :-bounds.size.height/2.0]; // Compute the hand lengths and cache bitmap location. [self computeBitmapLocation]; minuteLen = MIN(bounds.size.width, bounds.size.height) * MINUTERATIO; hourLen = MIN(bounds.size.width, bounds.size.height) * HOURRATIO; return self; } // Overriding sizeTo:: allows us to resize and fix up the clock whenever // the size is changed. - sizeTo:(NXCoord)w :(NXCoord)h { [super sizeTo:w :h]; [self computeNewSizes]; return self; } // setShowSecondsToBool: sets whether or not the seconds hand is shown. // The timed entry must be reinstalled whenever this setting is changed // as time to the next firing changes. - setShowSecondsToBool:(BOOL)seconds { showSeconds = seconds; [[self stopTimedEntry] startTimedEntry:NO]; [self display]; return self; } - setShowDateToBool: (BOOL) date { showDate = date; [[self stopTimedEntry] startTimedEntry:NO]; [self display]; return self; } - setMilitaryTimeToBool: (BOOL) mt { militaryTime = mt; [[self stopTimedEntry] startTimedEntry:NO]; [self display]; return self; } - setClockTypeToInt: (int) type { clockType = type; [[self stopTimedEntry] startTimedEntry:NO]; [self display]; return self; } // Methods to set/get background and clock hand colors. - setBackgroundGrayToFloat:(float)gray { backgroundGray = gray; [self display]; return self; } - setClockGrayToFloat:(float)gray { clockGray = gray; [self display]; return self; } - setMessage: (char *) buf1 : (char *) buf2 { strncpy( eventTime, buf1, MAX_CVIEW_WIDTH); strncpy( eventMessage, buf2, MAX_CVIEW_WIDTH); if( clockType == CLOCK_DIGITAL) [self display]; return self; } // Methods to return the values of the above parameters - (BOOL)showSeconds { return showSeconds; } - (BOOL)showDate { return showDate; } - (const char *)clockFaceBitmapName { return [clockFace name]; } - (float)backgroundGray { return backgroundGray; } - (float)clockGray { return clockGray; } // Finally, the IB-callable (target/action) versions of the above methods. - setClockFace:sender { return [self setClockFaceToBitmapNamed:[sender stringValue]]; } - setShowSeconds:sender { return [self setShowSecondsToBool:[sender state]]; } - setShowDate:sender { return [self setShowDateToBool:[sender state]]; } - setBackgroundGray:(id)sender { return [self setBackgroundGrayToFloat:[sender floatValue]]; } - setClockGray:(id)sender { return [self setClockGrayToFloat:[sender floatValue]]; } // Additions to allow target/action response // Mods by Jiro Nakamura, Jan 6, 1990 - setTarget: (id) aTarget { target = aTarget; return self; } - setAction: (SEL) anAction { action = anAction; return self; } // Archiving methods. - awake { [self computeNewSizes]; [self startTimedEntry:YES]; return self; } - write:(NXTypedStream *)stream { const char *bitmapName = [self clockFaceBitmapName]; [super write:stream]; NXWriteTypes (stream, "ffi*", &backgroundGray, &clockGray, &showSeconds, &bitmapName); return self; } - read:(NXTypedStream *)stream { char *bitmapName; [super read:stream]; NXReadTypes (stream, "ffi*", &backgroundGray, &clockGray, &showSeconds, &bitmapName); [self setClockFaceToBitmapNamed:bitmapName]; if (bitmapName) free (bitmapName); return self; } @end
These are the contents of the former NiCE NeXT User Group NeXTSTEP/OpenStep software archive, currently hosted by Netfuture.ch.