// SImpleSaverView - a pretty mindless screensaver that does the 'iine
//                   art thing'.

// the "line art thing" is achieved by bouncing two points around the
// screen, and drawing a line between these two points.  The two points
// (point1 and point2) are moved by a delta (delta1, delta2) each time
// the screensaver animator calls us.

// This is identical 

// This file is in the public domain


#import "FullScreenSaverView.h"



@implementation FullScreenSaverView


// since we're pretending to draw all over the user's desktop, don't have the
// tell-tale 'fade to black' happen first

+ (BOOL) performGammaFade
{
    return (NO);
} // performGammaFade



// get the contents of the user's main screen as an NSImage.
// This doesn't support multiple monitors (if you have an extra you'd like
// to send me...
// to support multiple monitors, you'll need to use NSScreen and snag
// an image for each screen

- (NSImage *) grabScreenBits
{
    NSWindow *grabWindow;
    NSView *grabbedContentView;
    NSBitmapImageRep *screenBits;
    NSRect mainScreenBounds;
    NSImage *image;
    
    mainScreenBounds = [[NSScreen mainScreen] frame];

    // make a window as big as the main screen

    grabWindow = [[NSWindow alloc] initWithContentRect: mainScreenBounds
				   styleMask: NSBorderlessWindowMask
				   backing: NSBackingStoreRetained
				   defer: NO
				   screen: nil];

    // make it transparent
    [grabWindow setAlphaValue: 0.0];

    // and bring it to the front
    [grabWindow setLevel: NSPopUpMenuWindowLevel];
    [grabWindow orderWindow: NSWindowAbove  relativeTo: 0];

    // get the window's content view
    grabbedContentView = [grabWindow contentView];

    // and get the bits.  This is the main Black Magic
    [grabbedContentView lockFocus];
    screenBits = [[NSBitmapImageRep alloc] 
		     initWithFocusedViewRect: mainScreenBounds];
    [grabbedContentView unlockFocus];
    
    // make an image with the bits
    image = [[NSImage alloc] initWithSize: mainScreenBounds.size];
    [image addRepresentation: screenBits];

    // close the window.  This will release it too
    [grabWindow close];

    // since the caller didn't alloc the image, they'll assume that we're
    // returning it autoreleased.
    return ([image autorelease]);
    
} // grabScreenBits



- (id) initWithFrame: (NSRect) frame  isPreview: (BOOL) isPreview
{
    if (self = [super initWithFrame: frame isPreview: isPreview]) {
	float scaleFactor;

	// the scale factor affects the size of the delta, that is how far each
	// point moes per 'click' of the animation timer.  We want the
	// scaleFactor to be smaller for the preview window since it's
	// so small.

	if (isPreview) {
	    scaleFactor = 1.5;
	} else {
	    scaleFactor = 5;
	}

	// pick the starting points

	point1 = SSRandomPointForSizeWithinRect (NSZeroSize, frame);
	point2 = SSRandomPointForSizeWithinRect (NSZeroSize, frame);

	// and pick the deltas that the points will move by.  This
	// gives a little variety each time the screensaver is run since
	// different 'vectors' will be given to each point

	delta1 = NSMakePoint (SSRandomFloatBetween(-5, 5) * scaleFactor,
			      SSRandomFloatBetween(-5, 5) * scaleFactor);
	delta2 = NSMakePoint (SSRandomFloatBetween(-5, 5) * scaleFactor,
			      SSRandomFloatBetween(-5, 5) * scaleFactor);

	// and for fun, cycle through colors too.  Start at a random
	// RGB value

	red = SSRandomFloatBetween (0.0, 1.0);
	green = SSRandomFloatBetween (0.0, 1.0);
	blue = SSRandomFloatBetween (0.0, 1.0);

	// snarf the screen

	screenImage = [[self grabScreenBits] retain];

	// this is redundant since it defaults to a thirtieth of a
	// second, but it doesn't hurt either.

        [self setAnimationTimeInterval: 1 / 30.0];

    }

    return (self);

} // initWithFrame: isPreview



- (void) drawRect: (NSRect) rect
{
    NSRect imageRect;

    imageRect.origin = NSZeroPoint;
    imageRect.size = [screenImage size];

    // lay down the screen as it was when we started.
    [screenImage drawInRect: rect  
		 fromRect: imageRect
		 operation: NSCompositeCopy
		 fraction: 1.0];

} // drawRect



// move the two points we have in our object by their corresponding
// delta.  If they go off the screen, make them 'bounce' back in
// a different direction.

- (void) movePoints
{
    NSRect bounds = [self bounds];

    // move the first pointx
    point1.x += delta1.x;
    point1.y += delta1.y;

    // make sure it's still in bounds horiztonally

    if (point1.x < bounds.origin.x) {
	delta1.x = -delta1.x;
	point1.x = bounds.origin.x;
    } else if (point1.x > bounds.origin.x + bounds.size.width) {
	delta1.x = -delta1.x;
	point1.x = bounds.origin.x + bounds.size.width;
    }
    
    // and vertically

    if (point1.y < bounds.origin.y) {
	delta1.y = -delta1.y;
	point1.y = bounds.origin.y;
    } else if (point1.y > bounds.origin.y + bounds.size.height) {
	delta1.y = -delta1.y;
	point1.y = bounds.origin.y + bounds.size.height;
    }


    // move the second point

    point2.x += delta2.x;
    point2.y += delta2.y;


    // make sure it's still in bounds horizontally

    if (point2.x < bounds.origin.x) {
	delta2.x = -delta2.x;
	point2.x = bounds.origin.x;
    } else if (point2.x > bounds.origin.x + bounds.size.width) {
	delta2.x = -delta2.x;
	point2.x = bounds.origin.x + bounds.size.width;
    }

    // and vertically

    if (point2.y < bounds.origin.y) {
	delta2.y = -delta2.y;
	point2.y = bounds.origin.y;
    } else if (point2.y > bounds.origin.y + bounds.size.height) {
	delta2.y = -delta2.y;
	point2.y = bounds.origin.y + bounds.size.height;
    }

} // movePoints



// cycle through colors, tweaking the red, green, and blue components
// a bit each time through

- (void) updateDrawingColor
{
    red += SSRandomFloatBetween (0, 0.04);
    green += SSRandomFloatBetween (0, 0.05);
    blue += SSRandomFloatBetween (0, 0.06);

    // valid colors are 0 .. 1.0.  Wrap around if we go over
    if (red > 1.0) {
	red = 0;
    }
    if (green > 1.0) {
	green = 0;
    }
    if (blue > 1.0) {
	blue = 0;
    }

} // updateDrawingColor



- (void) animateOneFrame
{
    NSColor *drawingColor = [NSColor colorWithDeviceRed: red
				     green: green
				     blue: blue
				     alpha: 1.0];
    // draw something new

    [drawingColor set];
    [NSBezierPath strokeLineFromPoint: point1  toPoint: point2];

    // and update for the next time around

    [self updateDrawingColor];
    [self movePoints];

} // animateOneFrame



// nope, we don't have any configurations

- (BOOL) hasConfigureSheet
{
    return (NO);

} // hasConfigureSheet



// nope, still don't have any configurations

- (NSWindow*) configureSheet
{
    return (nil);

} // configureSheet


@end // FullScreenSaverView

