/*---------------------------------------------------------------------------
InfoView.m -- Copyright (c) 1991 Rex Pruess
  
   This program is free software; you can redistribute it and/or modify
   it under the terms of the GNU General Public License as published by
   the Free Software Foundation; either version 1, or (at your option)
   any later version.
  
   This program is distributed in the hope that it will be useful,
   but WITHOUT ANY WARRANTY; without even the implied warranty of
   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
   GNU General Public License for more details.
  
   You should have received a copy of the GNU General Public License
   along with this program; if not, write to the Free Software
   Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA, or send
   electronic mail to the the author.
  
Info panels are often dull.  This one throws in a little animation for the
fun of it.  Four images descend from the corners toward a black box (i.e.,
"the cube").  Once they disappear into the black box, the image turns into
a NeXT cube with an image displayed inside of it.
  
Rex Pruess <Rex-Pruess@uiowa.edu>
  
$Header: /rpruess/apps/Ph/info.subproj/RCS/InfoView.m,v 2.0 91/11/18 17:49:54 rpruess Exp $
-----------------------------------------------------------------------------
$Log:	InfoView.m,v $
Revision 2.0  91/11/18  17:49:54  rpruess
Revision 2.0 is the initial production release of Ph.

-----------------------------------------------------------------------------*/

/* Standard C header files */
#include <libc.h>

/* Appkit header files */
#import <appkit/Application.h>
#import <appkit/NXImage.h>

/* Application class header files */
#import "InfoView.h"
#import "Animator.h"

@implementation InfoView

/*---------------------------------------------------------------------------
Create the animator object for later use.  Initialize the four images that we
will need for the animation.
-----------------------------------------------------------------------------*/
- initFrame:(const NXRect *) frm
{
   [super initFrame:frm];

   infoAnimator = [[Animator alloc] initChronon:0.0
      adaptation:0.0
      target:self
      action:@selector (drawImages)
      autoStart :NO
      eventMask:0];

   imageNE = [NXImage findImageNamed:"P"];
   imageSE = [NXImage findImageNamed:"P"];

   imageNW = [NXImage findImageNamed:"h"];
   imageSW = [NXImage findImageNamed:"h"];

   return self;
}

/*---------------------------------------------------------------------------
Each image is moved diagonally closer to the center of the frame.  When
they disappear inside the black box, the final scene is drawn.  This routine
is driven by the animator.
-----------------------------------------------------------------------------*/
- drawImages
{
   NXPoint         aPt;
   NXRect          r;

   if (++nDrawPasses == 2)
      sleep (1);		/* Pause on 2nd pass (ie, prior to animation) */

   [self lockFocus];

   /*** This code assumes that all images are the same size. */

   [imageNE getSize:&r.size];

   switch (imagePt.x >= bounds.size.width / 2.- r.size.width) {
   case NO:
      PSsetgray (NX_DKGRAY);	/* Paint the entire view DKGRAY */
      NXRectFill (&bounds);

      imagePt.x += 1.;		/* Draw the four images */
      imagePt.y += 1;
      [imageNE composite:NX_SOVER toPoint:&imagePt];

      aPt.x = imagePt.x;
      aPt.y = bounds.size.height - imagePt.y - r.size.height;
      [imageSE composite:NX_SOVER toPoint:&aPt];

      aPt.x = bounds.size.width - imagePt.x - r.size.width;
      [imageSW composite:NX_SOVER toPoint:&aPt];

      aPt.y = imagePt.y;
      [imageNW composite:NX_SOVER toPoint:&aPt];

      r.origin.x = bounds.size.width / 2.- BOXSIZE / 2.;
      r.origin.y = bounds.size.height / 2.- BOXSIZE / 2.;
      r.size.width = r.size.height = BOXSIZE;

      PSsetgray (NX_BLACK);	/* Draw the black box */
      NXRectFill (&r);

      break;

   case YES:
      [self drawFinalScene:self];

      drawnOnce = YES;
      drawing = NO;
      [self stopInfoViewTimer:self];

      break;
   }

   [[self window] flushWindow];
   [self unlockFocus];

   return (self);
}

/*---------------------------------------------------------------------------
Display the black NeXT cube with the special image inside it.
-----------------------------------------------------------------------------*/
- drawFinalScene:sender
{
   id              anImage;
   NXPoint         aPt;
   NXRect          r;
   NXSize          imageSize;

   /*** Draw the black box */

   PSsetgray (NX_BLACK);
   NXRectFill (&bounds);

   /*** Draw a lighter box inside it to hold the special image */

   r.origin.x = bounds.size.width / 2.- BOXSIZE / 2.;
   r.origin.y = bounds.size.height - TOPBORDER - BOXSIZE;
   r.size.width = r.size.height = BOXSIZE;
   PSsetgray (NX_DKGRAY);
   NXRectFill (&r);

   /*** Slap up the special image in the gray box */

   anImage = [NXImage findImageNamed:"Ph"];
   [anImage getSize:&imageSize];
   aPt.x = bounds.size.width / 2.- imageSize.width / 2.;
   aPt.y = bounds.size.height - (TOPBORDER + 4.) - imageSize.height;

   [anImage composite:NX_SOVER toPoint:&aPt];

   /*** Display the cute little NeXT logo near the bottom of the cube */

   anImage = [NXImage findImageNamed:"NeXT"];
   [anImage getSize:&imageSize];
   aPt.x = bounds.size.width / 2.- imageSize.width / 2.;
   aPt.y = BOTBORDER;

   [anImage composite:NX_COPY toPoint:&aPt];

   return self;
}

/*---------------------------------------------------------------------------
This is the initial drawing method.  It sets up starting values & brings the
animator to life.
-----------------------------------------------------------------------------*/
- drawInit:sender
{
   imagePt.x = 0.;
   imagePt.y = 0.;

   drawnOnce = NO;
   nDrawPasses = 0;

   [self startInfoViewTimer:.05];
   drawing = YES;

   return self;
}

/*---------------------------------------------------------------------------
Every good view has a draw self.
-----------------------------------------------------------------------------*/
- drawSelf:(const NXRect *) r :(int)c
{
   PSsetgray (NX_DKGRAY);
   NXRectFill (&bounds);
   return (self);
}

/*---------------------------------------------------------------------------
Start or stop up the animator methods.
-----------------------------------------------------------------------------*/
- startInfoViewTimer:(float)seconds
{
   [infoAnimator setIncrement:seconds];
   [infoAnimator startEntry];

   return self;
}

- stopInfoViewTimer:sender
{
   [infoAnimator stopEntry];
   return self;
}

/*---------------------------------------------------------------------------
If the user clicks inside the view, then start the animation all over again.
-----------------------------------------------------------------------------*/
- mouseDown:(NXEvent *) theEvent
{
   if (drawnOnce)
      [self drawInit:self];

   return (self);
}

/*---------------------------------------------------------------------------
This is the magic that starts everything up.  If the window comes to life,
then begin the show.
-----------------------------------------------------------------------------*/
- windowDidBecomeKey:sender
{

   if (!(drawnOnce || drawing))
      [self drawInit:self];

   return (self);
}

/*---------------------------------------------------------------------------
If the window is going bye-bye, then stop the show.
-----------------------------------------------------------------------------*/
- windowWillClose:sender
{
   if (drawing)
      [self stopInfoViewTimer:self];

   drawing = drawnOnce = NO;

   [self lockFocus];
   [self drawSelf:0 :0];
   [self unlockFocus];

   return self;
}


@end
