home *** CD-ROM | disk | FTP | other *** search
- /* Timer.m
- * Written By: Thomas Burkholder
- *
- * 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 "Timer.h"
-
- #define DEFAULTPERIOD 1.0
- #define LOWPERIOD 0.05
- #define HIGHPERIOD MAXDOUBLE
-
- #define DEFAULTSYNC 60
- #define LOWSYNC 1
- #define HIGHSYNC MAXINT
-
- #define DEFAULTSTART 0.0
- #define LOWSTART MINDOUBLE
- #define HIGHSTART MAXDOUBLE
-
- #define LOWWRAP MINDOUBLE
- #define HIGHWRAP MAXDOUBLE
-
- #define DEFAULTINCREMENT 1.0
- #define LOWINCREMENT MINFLOAT
- #define HIGHINCREMENT MAXFLOAT
-
- #define DEFAULTPRIORITY NX_BASETHRESHOLD
- #define LOWPRIORITY 0
- #define HIGHPRIORITY 30
-
-
- //#define MAX(_x,_y) (_x>_y)?_x:_y
- //#define MIN(__x,__y) (__x<__y)?__x:__y
- #define CONSTRAIN(__a,__low,__high) MIN(MAX(__a,__low),__high)
-
- @implementation Timer
-
- // function that does what's necessary to the object. To maximise speed,
- // methodFor: is used.
- void handle(DPSTimedEntry tag, double now, char *userdata)
- {
- Timer *self = (id)userdata;
-
- self->value += self->incrementBy;
- self->syncCounter++;
- if (self->bFlags.sync && (self->syncCounter >= self->syncValue)) {
- [self synchronize:self];
- self->syncCounter = 0;
- }
- if (self->bFlags.wrap && (self->value >= self->wrapValue))
- self->value = self->startValue;
- if (self->actionFunc)
- self->actionFunc(self->target,self->action,self);
- return;
- }
-
- // initializing and freeing
- + initialize
- {
- if (self == [Timer class])
- [self setVersion:1];
- return self;
- }
-
- - init
- {
- [super init];
-
- entry = NULL;
- period = DEFAULTPERIOD;
- priority = DEFAULTPRIORITY;
-
- bFlags.visibleDebug = NO;
- bFlags.wrap = YES;
- bFlags.sync = NO;
-
- syncValue = DEFAULTSYNC;
- value = 0.0;
- startValue = DEFAULTSTART;
- wrapValue = 60.0;
- incrementBy = DEFAULTINCREMENT;
-
- target = nil;
- action = (SEL)0;
- actionFunc = NULL;
- return self;
- }
-
- - free
- {
- if (entry) {
- [self stop:self];
- }
- return [super free];
- }
-
- // debugging methods
- - logError:(char *)str
- {
- if (bFlags.visibleDebug)
- NXRunAlertPanel("ERROR",str,NULL,NULL,NULL);
- NXLogError(str);
- return self;
- }
-
- // private methods
- - stopEntry
- {
- if (entry == NULL) {
- [self logError:"Stop called on stopped timer!\n"];
- return nil;
- } else {
- DPSRemoveTimedEntry(entry);
- entry = NULL;
- }
- return self;
- }
-
- - startEntry
- {
- if (entry != NULL) {
- [self stopEntry];
- }
-
- // get function for method, so we can be super-efficient
- if (target && action)
- actionFunc = [target methodFor:action];
-
- // make a new timed entry
- entry = DPSAddTimedEntry(period,(DPSTimedEntryProc)handle,self,priority);
-
- // check it
- if ((int)entry == -1) {
- [self logError:"Couldn't start timer!\n"];
- entry = NULL;
- return nil;
- }
- return self;
- }
-
- // actions
- - start:sender
- {
- // stop timer if necessary
- value = startValue;
- syncTime = [self currentTime];
- syncCounter = 0;
- [self startEntry];
- return self;
- }
-
- - stop:sender
- {
- return [self stopEntry];
- }
-
- - pause:sender
- {
- return [self stopEntry];;
- }
-
- - resume:sender
- {
- return [self startEntry];
- }
-
- // just in case anyone wants to fool with the timer directly
- - (DPSTimedEntry) entry
- {
- return entry;
- }
-
- - (unsigned int)currentTime
- {
- struct timeval curTime;
- gettimeofday (&curTime, NULL);
- return (curTime.tv_sec) * 1000 + curTime.tv_usec / 1000;
- }
-
- - synchronize:sender;
- {
- int correctedTicks = (([self currentTime]-syncTime)/((int)(period*1000)));
- if (bFlags.wrap) {
- correctedTicks = correctedTicks % (int)((wrapValue-startValue)/incrementBy);
- }
- value = correctedTicks*incrementBy;
- return self;
- }
-
- // methods to get/set the value of the timer
- - (float)floatValue { return value; }
- - setFloatValue:(float)aValue { value = aValue; return self; }
- - (int)intValue { return (int)value; }
- - setIntValue:(int)aValue { value = (float)aValue; return self; }
- - (const char *)stringValue { static char str[20]; sprintf(str,"%f",value); return str; }
- - setStringValue:(const char *)aValue { value = atof(aValue); return self; }
- - (double)doubleValue { return (double)value; }
- - setDoubleValue:(double)aValue { value = (double)aValue; return self; }
-
- // methods to get/set behaviours
- - setIncrementBy:(float)aValue { incrementBy = aValue; return self; }
- - (float)incrementBy { return incrementBy; }
- - setStartValue:(float)aValue { startValue = aValue; return self; }
- - (float)startValue { return startValue; }
- - setWrap:(BOOL)yn { bFlags.wrap = yn; return self; }
- - (BOOL)wrap { return (BOOL)(bFlags.wrap); }
- - setWrapValue:(float)aValue { wrapValue = CONSTRAIN(aValue,LOWWRAP,HIGHWRAP); return self; }
- - (float)wrapValue { return wrapValue; }
- - (int)syncValue { return syncValue; }
- - setSyncValue:(int)aValue { syncValue = CONSTRAIN(aValue,LOWSYNC,HIGHSYNC); return self; }
- - (BOOL)sync { return (BOOL)(bFlags.sync); }
- - setSync:(BOOL)yn { bFlags.sync = yn; return self; }
- - (BOOL)visibleDebug { return (BOOL)(bFlags.visibleDebug); }
- - setVisibleDebug:(BOOL)yn { bFlags.visibleDebug = yn; return self; }
- - (int)priority { return priority; }
- - setPriority:(int)aPriority { priority = CONSTRAIN(aPriority,LOWPRIORITY,HIGHPRIORITY); return self; }
- - (double)period { return period; }
- - setPeriod:(double)aPeriod { period = CONSTRAIN(aPeriod,LOWPERIOD,HIGHPERIOD); return self; }
- - (SEL)action { return action; }
-
- - setAction:(SEL)anAction
- {
- action = anAction;
- // in case someone decides to change targets while the timer is operational
- if (target && action)
- actionFunc = [target methodFor:action];
- return self;
- }
-
- - target
- {
- return target;
- }
-
- - setTarget:anObject
- {
- target = anObject;
- // in case someone decides to change targets while the timer is operational
- if (target && action)
- actionFunc = [target methodFor:action];
- return self;
- }
-
- // archival methods
- - read:(NXTypedStream *)stream
- {
- float sv;
- [super read:stream];
- switch (NXTypedStreamClassVersion(stream, "Timer")) {
- case 0 : // syncValue was a float
- NXReadTypes(stream,"@:dicfffff", &target, &action, &period,
- &priority, &bFlags, &sv,
- &startValue, &wrapValue, &value,
- &incrementBy);
- syncValue = (int)sv;
- break;
- default:
- NXReadTypes(stream,"@:diciffff", &target, &action, &period,
- &priority, &bFlags, &syncValue,
- &startValue, &wrapValue, &value,
- &incrementBy);
- }
- entry = NULL;
- actionFunc = NULL;
- return self;
- }
-
- - write:(NXTypedStream *)stream
- {
- [super write:stream];
- NXWriteTypes(stream,"@:diciffff", &target, &action, &period,
- &priority, &bFlags, &syncValue,
- &startValue, &wrapValue, &value,
- &incrementBy);
- return self;
- }
-
- @end
-