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];
[[clock stopTimedEntry] startTimedEntry:NO];
}
- 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;
}
@endThese are the contents of the former NiCE NeXT User Group NeXTSTEP/OpenStep software archive, currently hosted by Netfuture.ch.