This is MovieApp.m in view mode; [Download] [Up]
#import "MovieApp.h" #import "MovieView.h" #import "Animator.h" #import "SliderDualActing.h" #import <appkit/Button.h> #import <appkit/OpenPanel.h> #import <appkit/Matrix.h> #import <appkit/nextstd.h> #import <appkit/publicWraps.h> #import <string.h> @implementation MovieApp /* connect frameSlider, do some SliderDualActing initialization */ - setFrameSlider:anObject { frameSlider = anObject; [frameSlider setUpTarget:self action:@selector(showFrame:)]; return self; } /* connect frequencySlider, do some SliderDualActing initialization */ - setFrequencySlider:anObject { frequencySlider = anObject; [frequencySlider setUpTarget:self action:@selector(changeFrequency:)]; [frequencySlider setFormat:NO left:2 right:2]; [frequencySlider setMax:30.0 allowHigher:NO min:0.02 allowLower:NO]; [frequencySlider setAltStep:1 whole:NO default:10.0]; return self; } /* other outlets */ - setDirectionButton:anObject; { directionButton = anObject; return self; } - setGoStopButton:anObject; { goStopButton = anObject; return self; } - setEdgeMatrix:anObject { edgeMatrix = anObject; return self; } - setControlPanel:anObject { controlPanel = anObject; return self; } - setInfoPanel:anObject; { infoPanel = anObject; return self; } /* create the timer at appDidInit: time */ - appDidInit:sender { timer = [Animator newChronon:0.1 adaptation:3.0 target:self action:@selector(tickTock:) autoStart:NO eventMask:NX_ALLEVENTS]; return self; } /* bring up the Info Panel (mkof = makeKeyAndOrderFront) */ - mkofInfoPanel:sender { if (infoPanel == NULL) [self loadNibSection:"Info.nib" owner:self withNames:NO]; [infoPanel makeKeyAndOrderFront:self]; return self; } /* bring up the Control Panel (mkof = makeKeyAndOrderFront) */ - mkofControlPanel:sender { if (mainWindow == NULL) { NXRunAlertPanel("No Can Do", "The Control Panel is useless if there's no movie opened.", "OK", NULL, NULL); return self; } if (controlPanel == NULL) [self loadNibSection:"Control.nib" owner:self withNames:NO]; [self updateFrameSlider]; [controlPanel makeKeyAndOrderFront:self]; return self; } /* make the frameSlider reflect the main window's current frame */ - updateFrameSlider { [frameSlider setMax:[[mainWindow contentView] numFrames] - 1 allowHigher:NO min:0 allowLower:NO]; [frameSlider setAltStep:1 whole:YES default:[[mainWindow contentView] currentFrame]]; return self; } /* whenever a movie window resigns main, we stop the animation */ - windowDidResignMain:sender { if ([timer isTicking]) [goStopButton performClick:self]; if (mainWindow == NULL) [controlPanel orderOut:self]; return self; } /* Whenever a movie window becomes main, we bring up the Control panel */ - windowDidBecomeMain:sender { [self mkofControlPanel:self]; return self; } /* We are always ready to open another file. */ - (BOOL) appAcceptsAnotherFile:sender { return YES; } /* * appOpenFile is called by the open: method, and by other apps via * Speaker/Listener */ - (int)appOpenFile:(const char *)filename type:(const char *)aType { char temp[128]; NXStream *theStream; int i, width, height, numFrames; id theNewWin; /* read in data from movie index */ strcpy(temp, filename); strcat(temp, "/index"); theStream = NXMapFile(temp, NX_READONLY); if (theStream == NULL) { NXRunAlertPanel("Error", "%s has no index.", "OK", NULL, NULL, filename); return YES; } NXScanf(theStream, "%d%d%d", &width, &height, &numFrames); NXClose(theStream); /* is any data bad or missing? */ if ((width < 1) || (height < 1) || (numFrames < 1)) { NXRunAlertPanel("Error", "%s has a bad index.", "OK", NULL, NULL, filename); return YES; } /* create the new window, in a good place */ theNewWin = [Window newContent:[self nextRectForWidth:width Height:height] style:NX_TITLEDSTYLE backing:NX_RETAINED buttonMask:(NX_CLOSEBUTTONMASK | NX_MINIATURIZEBUTTONMASK) defer:NO]; /* we need to receive windowDidBecomeMain: and windowDidResignMain: */ [theNewWin setDelegate:self]; /* * create a new MovieView, make it the contentView of our new window, * and destroy the window's old contentView */ [[theNewWin setContentView:[MovieView newPath:filename Width:width Height:height NumFrames:numFrames]] free]; /* make sure the miniwindow has the pretty ".movie" icon */ [theNewWin setMiniwindowIcon:"movie"]; /* give the window a good title */ strcpy(temp, strrchr(filename, '/') + 1); strcat(temp, " Ð "); strncat(temp, filename, strrchr(filename, '/') - filename); [theNewWin setTitle:temp]; /* display the window, and bring it forth */ [theNewWin display]; [theNewWin makeKeyAndOrderFront:self]; /* bring up the control panel */ [self mkofControlPanel:self]; /* show the first frame */ [[theNewWin contentView] showFrameNumber:0]; return YES; } /***************************************************************************/ /* nextRectForWidth:Height: - return the next good content rectangle */ /* from Carl F. Sutter's wonderful ViewGif2 'Controller' method... */ /***************************************************************************/ /* nextTopLeft - return the next good top left window position */ /***************************************************************************/ - (NXRect *)nextRectForWidth:(NXCoord)width Height:(NXCoord)height { #define OFFSET 10.0 #define MAX_STEPS 20 #define INITIAL_X 356.0 #define INITIAL_Y 241.0 NXPoint nxpTopLeft; NXRect nxrTemp; /* used to find window height */ NXRect nxrWinHeight; /* bounds of enclosing window */ NXSize nxsScreen; /* size of screen */ static NXRect nxrResult; /* the Answer! */ static int nCurStep = 0; /* find a good top-left coord */ nxpTopLeft.x = INITIAL_X + nCurStep * OFFSET; nxpTopLeft.y = INITIAL_Y + nCurStep * OFFSET; if (++nCurStep > MAX_STEPS) nCurStep = 0; /* find window height using nxrTemp */ nxrTemp.size.width = width; nxrTemp.size.height = height; nxrTemp.origin.x = nxrTemp.origin.y = 0; [Window getFrameRect:&nxrWinHeight forContentRect:&nxrTemp style:NX_TITLEDSTYLE]; [NXApp getScreenSize:&nxsScreen]; /* find the lower-left coord */ nxrResult.origin.x = nxpTopLeft.x; nxrResult.origin.y = nxsScreen.height - nxrWinHeight.size.height - nxpTopLeft.y; nxrResult.size.width = width; nxrResult.size.height = height; return (&nxrResult); } /* open is called by the "Open..." button in the "Movie" menu */ - open:sender { const char *const ext[2] = {"movie", NULL}; const char *filename; id openReq = [OpenPanel new]; if ([openReq runModalForTypes:ext] && (filename = [openReq filename])) [self appOpenFile:filename type:""]; return self; } /* showFrame is called continuously as the "Current Frame" slider is moved */ - showFrame:sender { [[mainWindow contentView] showFrameNumber:[sender intValue]]; return self; } /* * changeFrequency is called whenever the user is done manipulating the * "Frames Per Second" slider. This method actually frees the old timer * and creates a new one, because Animator's setIncrement: method doesn't * work the way it should (it doesn't change desireddt). */ - changeFrequency:sender { BOOL wasTicking = [timer isTicking]; [timer free]; timer = [Animator newChronon:(1.0 / [sender doubleValue]) adaptation:3.0 target:self action:@selector(tickTock:) autoStart:wasTicking eventMask:NX_ALLEVENTS]; return self; } /* toggleGoStop: is called when the user hits the "Go/Stop" Button */ - toggleGoStop:sender { if ([timer isTicking]) [timer stopEntry]; else [timer startEntry]; [timer resetRealTime]; return self; } /* tickTock: is called by the timer */ - tickTock:sender { int newFrameNum; newFrameNum = [[mainWindow contentView] currentFrame]; if ([directionButton state]) newFrameNum++; else newFrameNum--; if (newFrameNum == [[mainWindow contentView] numFrames]) { switch ([edgeMatrix selectedTag]) { case 0: /* hard edges */ [goStopButton performClick:self]; return; case 1: /* bouncy edges */ [directionButton performClick:self]; newFrameNum--; break; case 2: /* wraparound */ newFrameNum = 0; break; } } else if (newFrameNum == -1) { switch ([edgeMatrix selectedTag]) { case 0: /* hard edges */ [goStopButton performClick:self]; return; case 1: /* bouncy edges */ [directionButton performClick:self]; newFrameNum++; break; case 2: /* wraparound */ newFrameNum = [[mainWindow contentView] numFrames] - 1; break; } } /* show the new frame */ [[mainWindow contentView] showFrameNumber:newFrameNum]; /* change the slider to the new frame number */ [frameSlider setIntValue:newFrameNum]; /* wait for all the Display Postscript to be executed */ NXPing(); } @end
These are the contents of the former NiCE NeXT User Group NeXTSTEP/OpenStep software archive, currently hosted by Netfuture.ch.