home *** CD-ROM | disk | FTP | other *** search
-
- // Copyright (c) 1997 by Don Yacktman
- // All rights reserved.
- // Permission to use this code in your application, whether
- // commercial, shareware, or freeware, is granted.
- // This notice may not be removed or altered.
-
-
- #import "Spewer.h"
- #import "FlyingWindow.h"
- #import "Animator.h"
- #import <libc.h>
-
- @implementation Spewer:NSObject
-
- - init
- {
- [super init];
- // seed the random number generator with the current time.
- // This call should really only be done once, before the random
- // number generator is ever used. Since this object is typically
- // only instantiated once so that's not a problem.
- srandom(time(0));
- // clear this out, since we've not been started yet.
- initiator = nil;
- // get an animator instance to help us run the animation.
- animator = [[Animator allocWithZone:[self zone]] initChronon:0.05
- adaptation:0.0 target:self action:@selector(move:)
- autoStart:NO eventMask:0];
- // set up an extra list used for swapping during animation
- _extraList = [[NSMutableArray allocWithZone:[self zone]] init];
- // set up the list of extra, idle windows
- idleWindows = [[NSMutableArray allocWithZone:[self zone]] init];
- // set up the list of active windows
- windowList = [[NSMutableArray allocWithZone:[self zone]] init];
- // it is not currently OK to create ne windows.
- createOK = NO;
- return self;
- }
-
- - start:sender
- {
- // start the animation. It is OK to instantiate new windows.
- createOK = YES;
- // the sender is the one who started us off, so cache that info
- initiator = sender;
- // get a new window so that we have at least one window to animate
- [self addWindow];
- // start the animation
- [animator startEntry];
- return self;
- }
-
- - (void)stop:(id)sender
- {
- // we need to stop the animation, but need all the windows to
- // fall off the screen first. So we tell ourself that the
- // initiator is gone and disallow creation of new windows.
- createOK = NO;
- initiator = nil;
- }
-
- - (BOOL)windowShouldClose:(id)sender
- {
- // if the window is closing, then we automatically stop the
- // animation. Make sure we are the winow's delegate (hooked
- // up as such in IB) or else we won't get this message!
- [self stop:self];
- return YES;
- }
-
- - (void)dealloc
- { // clean out any windows, remove the timed antry and free everything
- int i;
- // stop the animation and get rid of the animator
- [animator stopEntry];
- [animator release];
- animator = nil;
- // get rid of all our windows--get them off the screen
- for (i=0; i<[windowList count]; i++) {
- [[windowList objectAtIndex:i] orderOut:self];
- }
- // free the active window list and its contents
- [windowList release];
- windowList = nil;
- // free the idle window list and its contents
- [idleWindows release];
- idleWindows = nil;
- [super dealloc];
- return;
- }
-
- - addWindow
- { // put up a new window on the screen
- NSPoint theCenterPoint;
- NSRect senderFrame;
- id newWindow = nil;
-
- // if we're not allowed to start any new windows, then return immediately
- if (!createOK) return nil;
- // find the point where the new window should appear on the screen.
- // find out the frame of the control which sent the -start: message
- senderFrame = [initiator frame];
- // Get the center point of the initiator's frame
- theCenterPoint.x = NSMinX(senderFrame) + NSWidth(senderFrame) / 2;
- theCenterPoint.y = NSMinY(senderFrame) + NSHeight(senderFrame) / 2;
- // Convert the point from view to screen coordinates
- theCenterPoint = [[initiator window] convertBaseToScreen:theCenterPoint];
- // recycle a window if there are any idle ones; otherwise make a new one
- // get an idle window
- newWindow = [idleWindows lastObject];
- // if we got one, then take it out of the list of idle windows
- if (newWindow) [idleWindows removeLastObject];
- // if there weeren't any idle windows, then create a new one and set it
- // to appear at the point calculated above. If we found an idle window,
- // then get it to set itself up as the same point.
- if (!newWindow) newWindow = [[FlyingWindow allocWithZone:[self zone]]
- initAt:&theCenterPoint];
- else [newWindow reInitAt:&theCenterPoint];
- // add the new window to the list of active windows.
- [windowList addObject:newWindow];
- return self;
- }
-
- - move:sender
- {
- // get a new active list
- int i; id newList = _extraList;
-
- // add any new windows spewing about if necessary...
- // if we don't have too many windows out already, then check
- // against a random number to decide if we should add a new
- // window. The larger "FREQUENCY" is, the longer the average
- // interval will be between new windows coming onto the screen.
- if (([windowList count] < MAX_SPEWS) && !(random() % FREQUENCY)) {
- [self addWindow];
- }
-
- // move all the active windows
- for (i=0; i<[windowList count]; i++) [[windowList objectAtIndex:i] move];
-
- // remove any windows that left the screen
- for (i=0; i<[windowList count]; i++) {
- id theWindow = [windowList objectAtIndex:i];
- // if the window is on the screen, transfer it to a new active list
- if ([theWindow onScreen]) [newList addObject:theWindow];
- // windows that left the screen are taken out of the animation and moved to the idle list
- else {
- [theWindow orderOut:self];
- [idleWindows addObject:theWindow]; // put in recycler
- }
- }
- // make sure no stray windows were left behind.
- [windowList removeAllObjects];
- // get rid of the old active list and set up the new one.
- _extraList = windowList;
- windowList = newList;
- // if there are no more windows in the active list, and it is no longer
- // OK to create new ones, then the animation has ended, so we'll stop
- // the timer.
- if (([windowList count] < 1) && !(createOK))
- // stop TE after all windows gone
- [animator stopEntry];
- return self;
- }
-
- @end