This is MovieShowViewPart.m in view mode; [Download] [Up]
/*
* MovieShowView - version 1.0
*
* hacked from: "SlideShowView" by brighton@phuket.nbn.com, 13 Nov 91
* hacked by: Paul Burchard <burchard@math.utah.edu>
* further hacked by sam <sam_s@next.com> to add BackSpace 3.0 inspector
*/
#import <appkit/NXImage.h> // NXImage
#import <appkit/OpenPanel.h> // NXRunAlertPanel()
#import <appkit/Text.h> // NXOrderStrings()
#import <appkit/Button.h>
#import <dpsclient/wraps.h> // PSsetgray()
#import <defaults/defaults.h> // NXDefaults stuff
#import <libc.h> // lots of sys stuff
#import <math.h> // floor()
#import <string.h> // strcmp(), index()
#import <c.h> // TRUE, FALSE, etc
#import <sys/dir.h> // opendir(), etc
#import "MovieShowViewPart.h"
#import "Thinker.h"
// States.
#define msh_DARK 0
#define msh_BEGIN 1
#define msh_FRAME 2
#define msh_END 3
static const char *module = "MovieShow";
static int stringToBool(const char *answer)
{
if (strcasecmp(answer, "yes") == 0) return 1;
if (strcasecmp(answer, "on") == 0) return 1;
return atoi(answer); // returns zero if no digits encountered
}
@implementation MovieShowView
+ initialize
{
static NXDefaultsVector MovieShowDefaults = {
{ "Movie", "~/Library/Images/MovieShow.anim" },
{ "FrameTime", "1" },
{ "BeginPause", "12" },
{ "EndPause", "30" },
{ "DarkTime", "0" },
{ "Jump", "YES" },
{ "SlideFrames", "NO" },
{ "SlidePauses", "NO" },
{ "TimeUnit", "25" },
{ NULL }
};
NXRegisterDefaults(module, MovieShowDefaults);
return self;
}
- getDefaults
{
const char *app = module;
// Read from defaults database.
NXUpdateDefaults();
theMovie = NXGetDefaultValue(app, "Movie");
timeunit = (unsigned)atoi(NXGetDefaultValue(app, "TimeUnit"));
frametime = (unsigned)atoi(NXGetDefaultValue(app, "FrameTime"));
beginpause = (unsigned)atoi(NXGetDefaultValue(app, "BeginPause"));
endpause = (unsigned)atoi(NXGetDefaultValue(app, "EndPause"));
darktime = (unsigned)atoi(NXGetDefaultValue(app, "DarkTime"));
if(stringToBool(NXGetDefaultValue(app, "SlideFrames"))) slideframes = YES;
else slideframes = NO;
if(stringToBool(NXGetDefaultValue(app, "SlidePauses")))
slidebegin = slideend = YES;
else slidebegin = slideend = NO;
if(stringToBool(NXGetDefaultValue(app, "Jump"))) jump = YES;
else jump = NO;
// Clean up.
if(timeunit == 0) timeunit = 1;
if(frametime == 0) frametime = 1;
if(beginpause == 0) slidebegin = NO;
if(endpause == 0) slideend = NO;
return self;
}
- initFrame:(NXRect *)frameRect
{
[super initFrame:frameRect];
[self getDefaults];
[self initMovie];
return self;
}
- initMovie
{
broken = NO;
running = NO;
[self loadMovie];
if(!broken)
{
image = [imageList objectAt:0];
[image getSize:&imageRect.size];
[self setImageConstraints];
}
state = msh_DARK;
currentFrame = 0;
wait = 1;
countdown = 1;
slideDelta.x = randBetween(0.5, 4.0);
slideDelta.y = randBetween(0.5, 4.0);
return self;
}
- drawSelf:(const NXRect *)rects :(int)rectCount
{
NXPoint p;
if (!rects || !rectCount) return self;
[super drawSelf:rects :rectCount];
p.x = floor(imageRect.origin.x);
p.y = floor(imageRect.origin.y);
// Draw current image.
if(broken) return self;
if(!running) [self cacheMovie];
[image composite:NX_SOVER toPoint:&p];
return self;
}
- oneStep
{
int prevFrame;
// Wait for designated time period.
if(![self timePassed:(wait*timeunit)]) return self;
if(!running) [self cacheMovie];
if(broken) return self;
// Erase previous image.
prevFrame = currentFrame;
PSsetgray(0.0);
NXRectFill(&imageRect);
// State machine.
if(--countdown == 0)
{
// Determine new state and movie frame.
switch(state)
{
case msh_DARK:
if(beginpause != 0) { state = msh_BEGIN; currentFrame = 0; }
else { state = msh_FRAME; currentFrame = 0; }
break;
case msh_BEGIN:
state = msh_FRAME;
currentFrame = 0;
break;
case msh_FRAME:
if(currentFrame < (numberOfFrames-1))
{ state = msh_FRAME; currentFrame++; }
else if(endpause != 0)
{ state = msh_END; currentFrame = (numberOfFrames-1); }
else if(darktime != 0) { state = msh_DARK; currentFrame = 0; }
else if(beginpause != 0) { state = msh_BEGIN; currentFrame = 0; }
else { state = msh_FRAME; currentFrame = 0; }
break;
case msh_END:
if(darktime != 0) { state = msh_DARK; currentFrame = 0; }
else if(beginpause != 0) { state = msh_BEGIN; currentFrame = 0; }
else { state = msh_FRAME; currentFrame = 0; }
break;
default:
state = msh_DARK; currentFrame = 0;
break;
}
// Set waiting period and countdown repeater for new state.
switch(state)
{
case msh_DARK:
wait = darktime;
countdown = 1;
break;
case msh_BEGIN:
wait = (slidebegin ? 1 : beginpause);
countdown = (slidebegin ? beginpause : 1);
break;
case msh_FRAME:
wait = (slideframes ? 1 : frametime);
countdown = (slideframes ? frametime : 1);
break;
case msh_END:
wait = (slideend ? 1 : endpause);
countdown = (slideend ? endpause : 1);
break;
default:
wait = 1;
countdown = 1;
break;
}
}
// Perform graphics action.
image = [imageList objectAt:currentFrame];
[image getSize:&imageRect.size];
[self setImageConstraints];
if(jump && currentFrame<prevFrame)
{
imageRect.origin.x = floor(randBetween(0, maxCoord.x));
imageRect.origin.y = floor(randBetween(0, maxCoord.y));
}
switch(state)
{
case msh_BEGIN:
if(slidebegin) [self slideImageRectOrigin];
[image composite:NX_SOVER toPoint:&imageRect.origin];
break;
case msh_FRAME:
if(slideframes) [self slideImageRectOrigin];
[image composite:NX_SOVER toPoint:&imageRect.origin];
break;
case msh_END:
if(slideend) [self slideImageRectOrigin];
[image composite:NX_SOVER toPoint:&imageRect.origin];
break;
}
return self;
}
- slideImageRectOrigin
{
float rand;
NXPoint p;
p.x = imageRect.origin.x + slideDelta.x;
p.y = imageRect.origin.y + slideDelta.y;
rand = randBetween(0.5, 4.0);
if (p.x < 0) {
p.x = 0;
slideDelta.x = rand;
} else
if (p.x > maxCoord.x) {
p.x = maxCoord.x;
slideDelta.x = -rand;
}
rand = randBetween(0.5, 4.0);
if (p.y < 0) {
p.y = 0;
slideDelta.y = rand;
} else
if (p.y > maxCoord.y) {
p.y = maxCoord.y;
slideDelta.y = -rand;
}
imageRect.origin.x = p.x;
imageRect.origin.y = p.y;
return self;
}
- loadMovie
{
char filename[MAXPATHLEN];
char animFrame[MAXPATHLEN];
int i, len, fd;
id local_image;
const char *tiffext = ".tiff";
char animName[100];
// Reasonable directory name?
if(broken) return self;
if(!theMovie || !(theMovie[0]=='/' || theMovie[0]=='~'))
{
NXRunAlertPanel(module, "Bogus movie file.",
NULL, NULL, NULL, theMovie, module);
broken = TRUE;
return self;
}
// Clean up directory name, replacing initial '~' with HOME.
if(theMovie[0] == '~')
{
strcpy(filename, NXHomeDirectory());
if(theMovie[1] != '/') strcat(filename, "/");
strcat(filename, theMovie+1);
}
else strcpy(filename, theMovie);
len = strlen(filename);
if(len>1 && filename[len-1]=='/')
filename[--len] = 0;
imageList = [[List alloc] init];
strcpy(animName,rindex(filename,'/')+1);
*rindex(animName,'.') = 0;
for (i=0; ; i++)
{
sprintf(animFrame, "%s/%s.%d.tiff", filename, animName, i+1);
if (!(local_image = [NXImage findImageNamed:animFrame]))
{
if ((fd=open(animFrame, O_RDONLY)) < 0) break;
close(fd);
local_image = [[NXImage alloc] initFromFile:animFrame];
if (local_image == NULL) break; // never null, even if no file
[local_image setName:animFrame];
}
[imageList addObject:local_image];
}
numberOfFrames = i;
currentFrame = 0;
// Check if empty movie.
if((numberOfFrames = [imageList count]) <= 0)
{
NXRunAlertPanel(module, "Could not open any frames in movie folder \"%s\"\n\n",
NULL, NULL, NULL, filename);
broken = TRUE;
return self;
}
return self;
}
- cacheMovie
{
id this_image;
int i;
// Force lazy images to load now so that first movie run is correct speed.
if(running) return self;
running = YES;
numberOfFrames = [imageList count];
for(i=0; i<numberOfFrames; i++)
{
this_image = [imageList objectAt:i];
if([this_image lockFocus]) [this_image unlockFocus];
else fprintf(stderr, "%s: bad image: %s\n",
module, [this_image name]);
}
return self;
}
// override this method so that Thinker can't set the default image.
- setImage:newImage
{
return self;
}
// override
- (BOOL) useBufferedWindow
{
return YES;
}
- setJump:sender
{
jump = [jumpButton state] ? YES:NO;
NXWriteDefault("MovieShow", "Jump", jump ? "YES":"NO");
return self;
}
- setSlideFrames:sender
{
slideframes = [slideFramesButton state] ? YES:NO;
NXWriteDefault("MovieShow", "SlideFrames", slideframes ? "YES":"NO");
return self;
}
- setSlidePauses:sender
{
slidebegin = slideend = [slidePausesButton state] ? YES:NO;
NXWriteDefault("MovieShow", "SlidePauses", slidebegin ? "YES":"NO");
return self;
}
- setFile:sender
{
const char *const types[] = {"tiff", NULL};
char *iptr;
BOOL done = NO;
int i;
// if ([[OpenPanel new] runModalForTypes:types])
do {
if ([[OpenPanel new] runModalForDirectory:theMovie file:"" types:types])
{
if (movieNameBuffer) free(movieNameBuffer);
theMovie = movieNameBuffer = NXCopyStringBuffer([[OpenPanel new] filename]);
if (iptr = rindex(movieNameBuffer, '/')) *iptr = '\0';
i = strlen(movieNameBuffer);
if (i > 5 && !strcmp(&movieNameBuffer[i-5], ".anim"))
{
[filesTextField setStringValue:theMovie];
NXWriteDefault("MovieShow", "Movie", theMovie);
[imageList freeObjects];
[imageList free];
imageList = nil;
[self initMovie];
done = YES;
}
else
{
NXRunAlertPanel(module,
"Please select a tiff in a \".anim\" folder.", NULL, NULL, NULL);
}
}
else done = YES;
} while (!done);
return self;
}
- setBeginPause:sender
{
char str[100];
beginpause = [beginPauseTextField intValue];
sprintf(str,"%d", (int)beginpause);
NXWriteDefault("MovieShow", "BeginPause", str);
return self;
}
- setEndPause:sender
{
char str[100];
endpause = [endPauseTextField intValue];
sprintf(str,"%d", (int)endpause);
NXWriteDefault("MovieShow", "EndPause", str);
return self;
}
- setDarkFor:sender
{
char str[100];
darktime = [darkForTextField intValue];
sprintf(str,"%d", (int)darktime);
NXWriteDefault("MovieShow", "DarkTime", str);
return self;
}
- setTimeUnit:sender
{
char str[100];
timeunit = [timeUnitTextField intValue];
sprintf(str,"%d", (int)timeunit);
NXWriteDefault("MovieShow", "TimeUnit", str);
return self;
}
- inspector:sender
{
char buf[MAXPATHLEN];
if (!inspectorPanel)
{
sprintf(buf,"%s/movie.nib",[sender moduleDirectory:"MovieShow"]);
[NXApp loadNibFile:buf owner:self withNames:NO];
[filesTextField setStringValue:theMovie];
[beginPauseTextField setIntValue:beginpause];
[endPauseTextField setIntValue:endpause];
[darkForTextField setIntValue:darktime];
[timeUnitTextField setIntValue:timeunit];
[jumpButton setState: (jump ? 1:0)];
[slideFramesButton setState: (slideframes ? 1:0)];
[slidePausesButton setState: (slidebegin ? 1:0)];
}
return inspectorPanel;
}
@end
These are the contents of the former NiCE NeXT User Group NeXTSTEP/OpenStep software archive, currently hosted by Netfuture.ch.