ftp.nice.ch/pub/next/tools/screen/backspace/more3.0Views.tar.gz#/more3.0Views/MovieShow/MovieShowViewPart.m

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.