This is ClockView.m in view mode; [Download] [Up]
/* ClockView.m, a 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) * Redesigned for 2.0 by Julie Zelenski, NeXT Developer Support Group * Adapted by Mai Nguyen for this mini-example. Basically, only the digital * view of the clock is being used. * * Subclass of view to implement a simple clock. This view is pretty generic * and can probably be added to any program. * You may freely copy, distribute and reuse the code in this example. * NeXT disclaims any warranty of any kind, expressed or implied, as to its * fitness for any particular use. */ #import "ClockView.h" #import "Clock.h" // PSwrap routines #import <appkit/Application.h> #import <appkit/Button.h> #import <appkit/Window.h> #import <appkit/Font.h> #import <objc/NXStringTable.h> #import <string.h> #import <sys/time.h> #import <dpsclient/wraps.h> #import <appkit/nextstd.h> @implementation ClockView:View /* 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]; } - initFrame:(const NXRect *)frameRect /* initFrame for newly created view, initializes the various paramaters. * The constants above determine the lengths of the clock hands. */ { [super initFrame:frameRect]; cacheWindow = [Window newContent:frameRect style:NX_PLAINSTYLE backing:NX_RETAINED buttonMask:0 defer:NO]; littleFont = [Font newFont:"Helvetica" size:12 style:0 matrix:NX_IDENTITYMATRIX]; mediumFont = [Font newFont:"Times-Roman" size:14 style:0 matrix:NX_IDENTITYMATRIX]; bigFont = [Font newFont:"Times-Roman" size:24 style:0 matrix:NX_IDENTITYMATRIX]; /* Set the default state (NO seconds, no date) */ showSeconds = NO; center.x = bounds.size.width/2.0; center.y = bounds.size.height/2.0 + [mediumFont pointSize]/2.0; radius = MIN(center.x,center.y-[mediumFont pointSize]); needRedraw = YES; /* Start the time entry. YES indicates that this is the first time */ [self startTimedEntry:YES]; [self display]; return self; } - free /* Good idea to get rid of the timed entry while freeing... */ { [cacheWindow free]; [self stopTimedEntry]; return [super free]; } /* PRIVATE METHODS */ - drawFace; /* drawFace draws the clock face image in the offscreen window. This * offscreen cache is composited on screen and then the hands, shadow, * whatever is drawn on top of the face for the current time. Just * erase the background before redrawing the digital time. */ { [[cacheWindow contentView] lockFocus]; PSsetgray (NX_LTGRAY); NXRectFill (&bounds); // Erase background [[cacheWindow contentView] unlockFocus]; needRedraw = NO; return self; } - drawDigital:(struct tm *)time; /* drawDigital draws the time and date for the digital clock face */ { int hour; char timeString[10]; hour = fmod(time->tm_hour,12); /* get us off military time */ if (!hour) hour = 12; /* if noon or midnight */ if (showSeconds) sprintf(timeString,"%d:%.2d:%.2d",hour, time->tm_min, time->tm_sec); else sprintf(timeString,"%d:%.2d", hour,time->tm_min); [mediumFont set]; PSWcenterShow(center.x,center.y-8.0,timeString,NX_BLACK); return self; } - drawSelf:(NXRect *)rects :(int)rectCount /* Draws face and hands of clock. If needRedraw is YES, a parameter has * changed and the face must be redrawn in the offscreen window. * Otherwise, the image in cacheWindow is copied into the bounds of the * view, and a routine is called to display the current date and time */ { struct tm *localTime; struct timeval currentTime; if (needRedraw) [self drawFace]; PScomposite(0.0, 0.0, bounds.size.width, bounds.size.height, [cacheWindow gState], bounds.origin.x, bounds.origin.y, NX_COPY); gettimeofday (¤tTime, NULL); localTime = localtime (&(currentTime.tv_sec)); [self drawDigital:localTime]; return self; } - startTimedEntry:(BOOL)fireASAP /* 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). */ { 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 } teNum = DPSAddTimedEntry(fireIn, &ShowTime, self, NX_MODALRESPTHRESHOLD); return self; } - stopTimedEntry /* Removes the clock timed entry. */ { if (teNum) DPSRemoveTimedEntry (teNum); teNum = (DPSTimedEntry)0; return self; } - sizeTo:(NXCoord)w :(NXCoord)h /* Overriding sizeTo:: allows us to resize and fix up the clock whenever * the size is changed. Figure the radius of the clock (based on the size * of the view) and then redraw */ { [super sizeTo:w :h]; center.x = bounds.size.width/2.0; center.y = bounds.size.height/2.0 + [mediumFont pointSize]/2.0; radius = MIN(center.x, center.y-[mediumFont pointSize]); needRedraw = YES; return self; } @end
These are the contents of the former NiCE NeXT User Group NeXTSTEP/OpenStep software archive, currently hosted by Netfuture.ch.