home
***
CD-ROM
|
disk
|
FTP
|
other
***
search
/
NeXTSTEP 3.0
/
NeXTSTEP3.0.iso
/
NextDeveloper
/
Examples
/
AppKit
/
BusyBox
/
ClockView.m
< prev
next >
Wrap
Text File
|
1992-05-28
|
11KB
|
373 lines
/*
* 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
* Modified some for 3.0 by Ali Ozer, AppKit Group, May 28, 1992
*
* Subclass of view to implement a simple clock. This view is pretty generic
* and can probably be added to any program. The setClockType: method lets
* you display an analog, digital, or sundial face. You have the option of
* turning the seconds hand on or off, as well as controlling whether the date
* is also displayed.
*
* 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 <appkit/appkit.h>
#import "ClockView.h"
#import "Clock.h" // PSwrap routines
#import <objc/NXStringTable.h>
#import <string.h>
#import <sys/time.h>
@implementation ClockView:View
#define PI (double)3.1415926535897
#define ANALOG 0
#define DIGITAL 1
#define SUNDIAL 2
/* 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 se()s 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];
}
- initFrame:(const NXRect *)frameRect
/* initFrame for newly created view, initializes the various parameters,
* grabs some fonts to be used later.
*/
{
[super initFrame:frameRect];
face = [[NXImage allocFromZone:[self zone]] initSize:&bounds.size];
[face useDrawMethod:@selector(drawFace:) inObject:self];
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 (analog face, no seconds, date on) */
clockType = ANALOG;
showSeconds = NO;
showDate = YES;
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]);
[face recache];
/* 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...
*/
{
[face free];
[self stopTimedEntry];
return [super free];
}
/* SET/GET CLOCK PARAMETERS */
- setShowSeconds:(BOOL)newValue
/* setShowSeconds: 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.
*/
{
showSeconds = newValue;
[[self stopTimedEntry] startTimedEntry:NO];
[self display];
return self;
}
- setShowDate:(BOOL)newValue
/* setShowDate: sets whether or not the date is shown.
*/
{
showDate = newValue;
[self display];
return self;
}
- setClockType:(int)newValue
/* setClockType: sets which type of clock is drawn (analog, digital, or
* sundial).
*/
{
clockT(0= newValue;
[face recache];
[self display];
return self;
}
- (BOOL)showSeconds
{
return showSeconds;
}
- (BOOL)showDate
{
return showDate;
}
- (int)clockType
{
return clockType;
}
/* TARGET/ACTION METHODS */
- changeShowDate:sender;
{
return [self setShowDate:[[sender selectedCell] state]];
}
- changeShowSeconds:sender
{
return [self setShowSeconds:[[sender selectedCell] state]];
}
- changeClockType:sender
{
return [self setClockType:[sender selectedTag]];
}
/* String keys used for look-up into string tables */
static const char *monthKeys[12] = {"Jan","Feb","Mar","Apr","May","Jun","Jul","Aug","Sep","Oct","Nov","Dec"};
static const char *months[12];
static const char *weekKeys[7] = {"Sun","Mon","Tue","Wed","Thu","Fri","Sat"};
static const char *weekdays[7];
static const char *romanDays[31] = {"I","II","III","IV","V","VI","VII","VIII","IX","X","XI","XII",
"XIII","XIV","XV","XVI","XVII","XVIII","XIX","XX","XXI","XXII","XXIII",
"XXIV","XXV","XXVI","XXVII","XXVIII","XXIX","XXX", "XXXI"};
- setSTable:anObject;
/* Get string values for months, weekdays from NXStringTable, they are stored
* as static class variables.
*/
{
int i;
sTable = anObject;
for (i = 0; i < 7; i++)
weekdays[i] = [sTable valueForStringKey:weekKeys[i]];
for (i = 0; i < 12; i++)
months[i] = [sTable valueForStringKey:monthKeys[i]];
return self;
}
/* PRIVATE METHODS */
#define HOURRATIO 0.5 /* Hour hand length compared face size */
#define MINUTERATIO 0.85 /* Minute & seconds hands */
- drawAnalog:(struct tm *)time;
/* drawAnalog draws the clock hands and date for the analog clock face
*/
{
int min,hour,sec;
char dateString[15];
min = time->tm_min;
hour = time->tm_hour;
sec = time->tm_sec;
if (showSeconds)
PSWdrawClockHand (center.x,center.y,-6.0 * sec, radius*MINUTERATIO,
NX_DKGRAY, 0.0);
PSWdrawClockHand (center.x,center.y, -(hour+min/60.0) * 30.0,
radius*HOURRATIO, NX_BLACK, 1.0);
PSWdrawClockHand (center.x,center.y,- fmod(min,60.0) * 6.0,
radius*MINUTERATIO, NX_BLACK, 1.0);
if (showDate) {
[littleFont set];
sprintf(dateString,"%s %s %d",weekdays[time->tm_wday],
months[time->tm_mon],
time->tm_mday);
PSWcenterShow(center.x+1.0,3.0,dateString,NX_WHITE);
(1enterShow(center.x,3.0,dateString,NX_DKGRAY);
}
return self;
}
- drawDigital:(struct tm *)time;
/* drawDigital draws the time and date for the digital clock face
*/
{
int hour;
char timeString[10];
char dateString[15];
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);
[bigFont set];
PSWcenterShow(center.x,center.y-8.0,timeString,NX_BLACK);
if (showDate) {
sprintf(dateString,"%s %s %d",weekdays[time->tm_wday],
months[time->tm_mon],
time->tm_mday);
[mediumFont set];
PSWcenterShow(center.x,center.y-24.0,dateString,NX_BLACK);
}
return self;
}
#define SHADOWRATIO .95 /* shadow length when compared to radius */
#define MARKERRATIO .15 /* height of marker when compared to radius */
- drawSundial:(struct tm *)time;
/* drawSundial draws the shadow and date for the sundial clock face
*/
{
float percentOfDay;
char dateString[15];
NXPoint edge;
if (showSeconds)
PSWdrawSweep (center.x,center.y,-6.0 *time->tm_sec,radius*.75);
percentOfDay = (time->tm_hour*60 + time->tm_min)/(24.0*60.0);
edge.x = sin(percentOfDay*PI*2)*radius*SHADOWRATIO;
edge.y = cos(percentOfDay*PI*2)*radius*SHADOWRATIO;
PSWdrawShadow(center.x,center.y,edge.x,edge.y,radius*MARKERRATIO);
if (showDate) {
[mediumFont set];
sprintf(dateString,"%s %s", months[time->tm_mon],
romanDays[time->tm_mday-1]);
PSWcenterShow(center.x,12.0,dateString,NX_BLACK);
}
return self;
}
- drawFace:image
/* drawFace draws the clock face image. This
* image is composited on screen and then the hands, shadow,
* whatever is drawn on top of the face for the current time.
*/
{
PSsetgray (NX_LTGRAY);
NXRectFill (&bounds); // Erase background
switch (clockType) {
case ANALOG: PSWdrawAnalogFace(center.x,center.y,radius);
break;
case DIGITAL: /* digital "face" is just blank */
break;
case SUNDIAL: PSWdrawSundialFace(center.x,center.y, radius);
break;
}
return self;
}
- drawSelf:(NXRect *)rects :(int)rectCount
/* Draws face and hands of clock.
* The clock face image(2face 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 recache was called, or if printing, this will first redraw
// the clock face by calling drawFace:
[face composite:NX_COPY toPoint:&bounds.origin];
gettimeofday (¤tTime, NULL);
localTime = localtime (&(currentTime.tv_sec));
switch (clockType) {
case ANALOG: [self drawAnalog:localTime];
break;
case DIGITAL: [self drawDigital:localTime];
break;
case SUNDIAL: [self drawSundial:localTime];
break;
}
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]);
[face setSize:&bounds.size];
return self;
}
@end