ftp.nice.ch/peanuts/GeneralData/Documents/adobe/DPS.Purple.Clock.tar.gz#/NX_Clock/Animator.m

This is Animator.m in view mode; [Download] [Up]

/*
*	Taken from the stop watch application in NextDeveloper .
*/

//  Animator.m
//  Object for general timing, animation, and dynamics.
//  Author: R. E. Crandall, Educational Technology Center
//  10-Apr-88
//  Revised by Bluce Blumberg for 0.8, 29-Sep-88
//  Revised for 1.0 by Ali Ozer, 13-Jun-89

 
/*
 *  An 'Animator' controls the timing for your action method of choice.
 *  The object may function as a general timer object; i.e.
 *  graphics are neither expected nor required by the class.
 *  When you create an Animator with +newChronon, you specify
 *  the time interval between calls, the adaptation time constant (see below),
 *  the target to which the method belongs, the action name, whether to 
 *  automatically start up the timing upon creation, and an event mask (if you 	
 *  plan to break conditionally out of loops within the action method.
 *
 *  The Animator has adaptive means for adjusting to harsh operating
 *  environments.  An adaptation constant d > 0. will invoke dynamical 
 *  correction of entry times, on-the-fly, so that the desired chronon
 *  will be realized in a real-time sense.
 *
 *  Functionality and applications are discussed in Report ETC-0008.
 */

#import "Animator.h"

#import <appkit/Application.h>
#import <sys/time.h>
#import <objc/vectors.h>

@implementation Animator

void TimerFunc(teNum,now,self)
DPSTimedEntry teNum;
double now;
id self;
{
  gettimeofday(&self->entrytime,NULL);
  if (self->howOften > 0.) [self adapt];
  [self->target perform:self->action with:self];
}
 
+ newChronon: (double) dt	/* The time increment desired. */
	adaptation:(double)howoft  /* Adaptive time constant (0.deactivates).*/
	target: (id) targ	/* Target to whom proc belongs. */
	action: (SEL) act	/* The action. */
	autoStart: (int) start	/* Automatic start of timed entry? */
	eventMask: (int) eMask  /* Mask for optional check in "shouldBreak". */
{
  self = [super new];
  ticking = NO;
  desireddt = dt;
  [self setIncrement: dt];
  [self setAdaptation: howoft];
  [self setTarget: targ];
  [self setAction: act];
  if(start) [self startEntry];
  mask = eMask;
  [self resetRealTime];
  return self;
}

- resetRealTime { 
/* After this call, getDoubleRealTime is the real time that ensues. */
	struct timeval realtime;

	gettimeofday(&realtime,NULL);
	synctime = realtime.tv_sec + realtime.tv_usec/1000000.0;
	passcounter = 0;
	t0 = 0.0;
	return self;
}

- (double) getSyncTime {
	return(synctime);
}

- (double) getDoubleEntryTime {
/* Returns real time since "resetrealTime". */
	return(- synctime + entrytime.tv_sec + entrytime.tv_usec/1000000.0);
}

- (double) getDoubleRealTime {
/* Returns real time since "resetrealTime". */
	struct timeval realtime;
	struct timezone tzone;

	gettimeofday(&realtime,&tzone);
	return(- synctime + realtime.tv_sec + realtime.tv_usec/1000000.0);
}

- (double) getDouble {
	return([self getDoubleRealTime]);
}

- adapt {
/* Adaptive time-step algorithm. */
  double t;
  if(!ticking) return self;
  ++passcounter;
  t = [self getDoubleEntryTime];
  if(t - t0 >= howOften) {  	
  	adapteddt *= desireddt*passcounter/(t - t0);
	[self setIncrement: adapteddt];
	[self startEntry];
	passcounter = 0;
	t0 = t;
  }
  return self;
}
  
- setBreakMask : (int) eventMask {
  mask = eventMask;
  return self;
}

- (int) getBreakMask {
  return(mask);
}

- (int) isTicking {
  return(ticking);
}
   
- (int) shouldBreak  {
/* Call this to see if you want to exit a loop in your action method. */
   int   found;
   NXEvent *e, event;
   e = [NXApp peekNextEvent:mask into:&event 
	      waitFor:0.0 threshold:NX_BASETHRESHOLD];
   return(e ? 1: 0);
}

- setIncrement: (double) dt {
  adapteddt = dt;
  interval = dt;
  return self;
}

- (double) getIncrement {
  return(adapteddt);
}

- setAdaptation: (double) oft {
  howOften = oft;
  return self;
}

- setTarget: (id) targ {
  target = targ;
}

- setAction:(SEL) aSelector
{
    action = aSelector;

    return self;
}

- startEntry
{ 
  [self stopEntry];
  teNum = DPSAddTimedEntry(interval,&TimerFunc,self,NX_BASETHRESHOLD);
  ticking = YES;
  return self;
}

- stopEntry
{
  if (ticking) DPSRemoveTimedEntry(teNum);
  ticking = NO;
  return self;
}

- free
{
  if (ticking) DPSRemoveTimedEntry(teNum);
  return [super free];
}

@end	

These are the contents of the former NiCE NeXT User Group NeXTSTEP/OpenStep software archive, currently hosted by Netfuture.ch.