 /*
  * Khoros: $Id: run_animate.c,v 1.4 1992/03/20 22:44:34 dkhoros Exp $
  */

#if !defined(lint) && !defined(SABER)
static char rcsid[] = "Khoros: $Id: run_animate.c,v 1.4 1992/03/20 22:44:34 dkhoros Exp $";
#endif

 /*
  * $Log: run_animate.c,v $
 * Revision 1.4  1992/03/20  22:44:34  dkhoros
 * VirtualPatch5
 *
  */ 

/*
 *----------------------------------------------------------------------
 *
 * Copyright 1990, University of New Mexico.  All rights reserved.
 * 
 * Permission to copy and modify this software and its documen-
 * tation only for internal use in your organization is hereby
 * granted, provided that this notice is retained thereon and
 * on all copies.  UNM makes no representations as too the sui-
 * tability and operability of this software for any purpose.
 * It is provided "as is" without express or implied warranty.
 * 
 * UNM DISCLAIMS ALL WARRANTIES WITH REGARD TO THIS SOFTWARE,
 * INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND FIT-
 * NESS.  IN NO EVENT SHALL UNM BE LIABLE FOR ANY SPECIAL,
 * INDIRECT OR CONSEQUENTIAL DAMAGES OR ANY OTHER DAMAGES WHAT-
 * SOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER
 * IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS
 * ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR PER-
 * FORMANCE OF THIS SOFTWARE.
 * 
 * No other rights, including for example, the right to redis-
 * tribute this software and its documentation or the right to
 * prepare derivative works, are granted unless specifically
 * provided in a separate license agreement.
 *----------------------------------------------------------------------
 */

#include "unmcopyright.h"        /* Copyright 1990 by UNM */
#include "animate.h"


/************************************************************
*
*  MODULE NAME: update_animate_mode
*
*      PURPOSE: changes the animate update method to either
*		full reverse, full forward, single step reverse
*		or forward, and stop.  This allows us to race
*		thru all the images forwards or backwards, or
*		show the next image or previous image.
*
*		A timer is added with the given speed as the
*		update time-out to do the actual display of
*		the next image.
*
*        INPUT: none
*
*       OUTPUT: none
*
*   WRITTEN BY: Mark Young
*
*
*************************************************************/

update_animate_mode()
{
	XtAppContext app_context;
	void	     update_animate();


 	if (xvanimate->id != NULL)
	{
	   XtRemoveTimeOut(xvanimate->id);
	   xvanimate->id = NULL;
	}

	if (xvanimate->continous == True)
	{
	   app_context = XtWidgetToApplicationContext(xvdisplay->raster);
	   xvanimate->id = XtAppAddTimeOut(app_context, 0, update_animate,NULL);
	}
	else
	   refresh_animate();
}



/************************************************************
*
*  MODULE NAME: redisplay_animate
*
*      PURPOSE: redisplay_animate is the event handler that
*		is used to refresh the image to the animation
*		window when an exposure is found.  It calls
*		refresh_animate() to do the actual re-displaying.
*
*
*	 INPUT: widget     -  the widget for the event
*		clientData -  not used
*		event      -  the event
*
*       OUTPUT: none - refresh_animate() does the actual refreshing
*
*   WRITTEN BY:
*
************************************************************/


void redisplay_animate(widget, clientData, event)

Widget	widget;
caddr_t clientData;
XEvent  *event;
{
	Window	    root;
	int	    x, y;
	unsigned    int width, height, border_width, depth;

	if (event->type == Expose)
	{
	   /*
	    *  refresh the animate display.
	    */
	   refresh_animate();
	}
	else if (event->type == ConfigureNotify)
	{
           if ( !XGetGeometry(XtDisplay(widget), XtWindow(widget),
	            &root, &x, &y, &width, &height,  &border_width, &depth))
           {
	      xvf_error_wait("Window does not exist.","redisplay_animate",NULL);
	      return;
           }
	   refresh_animate();
	}
}



/************************************************************
*
*  MODULE NAME: manage_icon
*
*      PURPOSE: manage_icon is the event handler that
*		is used to figure out that the toplevel
*		window has been un-iconified.
*
*
*	 INPUT: widget     -  the widget for the event
*		clientData -  not used
*		event      -  the event
*
*       OUTPUT: none - refresh_animate() does the actual refreshing
*
*   WRITTEN BY:
*
************************************************************/


void manage_icon(widget, clientData, event)

Widget	widget;
caddr_t clientData;
XEvent  *event;
{
	xvf_form *form = (xvf_form *) clientData;


	if (event->type == MapNotify)
	{
	   form->glyph_state =
	   xvanimate->iconified = False;
	}
}



/************************************************************
*
*  MODULE NAME: advance_frame
*
*      PURPOSE: advances to the next frame.  If we are at the end
*		of the frame and auto-reverse is set then we reverse
*		the direction, otherwise we set the frame to the
*		beginning or of the frame list.
*
*        INPUT: none 
*
*	OUTPUT: none
*
*   WRITTEN BY: Mark Young & Tom Sauer
*
************************************************************/

advance_frame()
{
	if (xvanimate->head == NULL)
	   return;

	if (xvanimate->current->next != NULL)
	{
	   xvanimate->current = xvanimate->current->next;
	}
	else
	{
	   if (xvanimate->control == AUTOREVERSE)
	   {
	      xvanimate->direction = REVERSE;
	      if (xvanimate->current->prev != NULL)
	         xvanimate->current = xvanimate->current->prev;
	   }
	   else
	   {
	      if (xvanimate->control == SINGLE)
		 xvanimate->continous = False;
	      else
	         xvanimate->current = xvanimate->head;
	   }
	}
}



/************************************************************
*
*  MODULE NAME: reverse_frame
*
*      PURPOSE: rewinds to the last frame.  If we are at the beginning
*		of the frame and auto-reverse is set then we reverse
*		the direction, otherwise we set the frame to the
*		end or of the frame list.
*
*        INPUT: none 
*
*	OUTPUT: none
*
*   WRITTEN BY: Mark Young & Tom Sauer
*
************************************************************/

reverse_frame()
{
	if (xvanimate->head == NULL)
	   return;

	if (xvanimate->current->prev != NULL)
	{
	   xvanimate->current = xvanimate->current->prev;
	}
	else
	{
	   if (xvanimate->control == AUTOREVERSE)
	   {
	      xvanimate->direction = FORWARD;
	      if (xvanimate->current->next != NULL)
	         xvanimate->current = xvanimate->current->next;
	   }
	   else
	   {
	      if (xvanimate->control == SINGLE)
		 xvanimate->continous = False;
	      else
	         xvanimate->current = xvanimate->tail;
	   }
	}
}



/************************************************************
*
*  MODULE NAME: update_animate
*
*      PURPOSE: Updates the animated image on the screen.  This
*		routine does not do the actual refreshing of the
*		image, but rather make sure we are showing the
*		right image and then calls refresh_animate() to
*		actually display the image.
*
*	 INPUT: widget     -  the widget for the event
*		clientData -  not used
*		event      -  the event
*
*       OUTPUT: calls refresh_animate() to display image.
*
*   WRITTEN BY: Mark Young & Tom Sauer
*
*
************************************************************/


void update_animate(widget, clientData, event)

Widget	widget;
caddr_t clientData;
XEvent  *event;
{
	unsigned long speed;
	XtAppContext app_context;


	if (xvanimate->direction == FORWARD)
	   advance_frame();
	else if (xvanimate->direction == REVERSE)
	   reverse_frame();

	refresh_animate();

	/*
	 *
	 */
	if (xvanimate->continous == True)
	{
	   speed = xvanimate->speed * 1000;
	   app_context = XtWidgetToApplicationContext(xvdisplay->raster);
	   xvanimate->id = XtAppAddTimeOut(app_context, speed, update_animate,
					   NULL);
	}
}



/************************************************************
*
*  MODULE NAME: refresh_animate
*
*      PURPOSE: refreshes the animate image to the animation
*		window.
*
*        INPUT: none 
*
*	OUTPUT: displays animated image to the animation window
*
*   WRITTEN BY: Mark Young & Tom Sauer
*
************************************************************/


refresh_animate()
{
	char	buf[6];
	Window  window;
	Display	*display = XtDisplay(xvdisplay->raster);


	/*
	 *  If there is no image to refresh then return.
	 */
	if (xvanimate->current == NULL)
	   return;

	if (xvanimate->use_root == True)
	   window = XDefaultRootWindow(display);
	else if (xvanimate->iconified == False)
	   window = XtWindow(xvdisplay->raster);
	else if (xvdisplay->icon != NULL)
	   window = XtWindow(xvdisplay->icon);
	else
	   return;

	/*
	 *  See if we are iconified or not.
	 */
	if (xvanimate->iconified == False)
	{
	   /*
	    *  If the pixmap exists then refresh that since it's faster.
	    *  Otherwise refresh it with the XImage.
	    */
	   if (xvanimate->current->pixmap != NULL)
	   {
	      if (xvanimate->current->depth == 1)
	      {
	         XCopyPlane(display, xvanimate->current->pixmap, window, gc,
			0, 0, xvanimate->width, xvanimate->height, 0, 0, 1L);
	      }
	      else
	      {
		 XCopyArea(display, xvanimate->current->pixmap, window, gc,
		        0, 0, xvanimate->width, xvanimate->height, 0, 0);
	      }
	   }
	   else if (xvanimate->current->ximage != NULL)
	   {
	      XPutImage(display, window, gc, xvanimate->current->ximage,
		        0, 0, 0, 0, xvanimate->width, xvanimate->height);
	   }
	}
	else
	{
	   /*
	    *  If the icon pixmap exists then refresh that since it's faster.
	    *  Otherwise refresh it with the icon XImage.
	    */
	   if (xvanimate->current->icon_pixmap != NULL)
	   {
	      if (xvanimate->current->depth == 1)
	      {
	         XCopyPlane(display, xvanimate->current->icon_pixmap, window,
			gc, 0, 0, xvanimate->icon_width, xvanimate->icon_height,
			0, 0, 1L);
	      }
	      else
	      {
	         XCopyArea(display, xvanimate->current->icon_pixmap, window, gc,
			0, 0, xvanimate->icon_width, xvanimate->icon_height,
			0, 0);
	      }
	   }
	   else if (xvanimate->current->icon_ximage != NULL)
	   {
	      XPutImage(display, window, gc, xvanimate->current->icon_ximage,
		        0, 0, 0, 0, xvanimate->icon_width,
			xvanimate->icon_height);
	   }
	}

	/*
	 *  If show_band is set to true then we print the band number being
	 *  displayed in the upper-left corner.
	 */
	if (xvanimate->show_band)
	{
	   sprintf(buf," %3d ", xvanimate->current->num);
	   XDrawImageString(display,window,gc,3,xvanimate->font_height,buf,5);
	}
}



/************************************************************
*
*  MODULE NAME: refresh_rootwindow
*
*      PURPOSE: refreshes the area of the root window where
*		the animation is being displayed.
*
*        INPUT: none 
*
*	OUTPUT: Clears the rootwindow area of the animation
*		being displayed
*
*   WRITTEN BY: Mark Young
*
************************************************************/

refresh_rootwindow()
{
	XClearArea(display, XDefaultRootWindow(display), 0, 0, xvanimate->width,
		   xvanimate->height, False);
}
