;==========================================================================
;file uvspanimate.pro
;==========================================================================

pro xintanim_bck, TOSS
; This procedure is the background task for the XInterAnimate Procedure.  The
; XInterAnimate Widget has a speed control that controls the length of the
; stall between updates of the animation.  If the stallcount is less then the
; the stall value, the stallcount is incremented and no animation frame is 
; drawn.  When the stallcount is equal or greater than the stall, this routine
; increments or decrements the frame pointer and then displays the apropriate
; frame.

common XInterAnimate_com, pwin, swin, nframes, xs, ys, $
	animateframe, animatebase, animatepause, animatereverse, $
	animatespeed, animateforward, displayload, $
	framedelta, curframe, stall, currentframe, stallcount, animatedisplay

if (stallcount GE stall) then begin			;if it is time to draw
  stallcount = 0					;a new frame, the 
  if framedelta eq 0 then return			;Paused?
  curframe = curframe + framedelta			;New frame
  while curframe lt 0 do curframe = curframe + nframes	;Into range
  while curframe GE nframes do curframe = curframe - nframes
  wset, swin						;Set to the drawing
							;window
  if pwin(curframe) ge 0 then $				;Next frame
	device, copy = [0, 0, xs, ys, 0, 0, pwin(curframe)] 
  empty
endif else stallcount = stallcount + 1			;slider

end ;------------------ end of procedure xintanim_bck ------------------------


;============================================================================

pro xintanim_clean, toss
; This procedure cleans up the variables when the widget dies.

common XInterAnimate_com, pwin, swin, nframes, xs, ys, $
	animateframe, animatebase, animatepause, animatereverse, $
	animatespeed, animateforward, displayload, $
	framedelta, curframe, stall, currentframe, stallcount, animatedisplay

for i=0,n_elements(pwin)-1 do $
  if (pwin(i) ge 0) then wdelete,pwin(i)
pwin = -1
nframes = 0

END ;----------------- end of procedure xintanim_clean -----------------------


;============================================================================

pro xintanim_event, event
; This procedure processes the events being sent by the XManager.  It adjusts
; the settings for the animation as well as getting and displaying the help.

common XInterAnimate_com, pwin, swin, nframes, xs, ys, $
	animateframe, animatebase, animatepause, animatereverse, $
	animatespeed, animateforward, displayload, $
	framedelta, curframe, stall, currentframe, stallcount, animatedisplay

@uvspstruct.common

  widget_control, get_uvalue=retval, event.id
  case retval OF
    "ANIMATESPEED" : begin
			widget_control, animatespeed, get_value=temp
			stall = (100 - temp)
			stallcount = stall
  	       	     end

    "ANIMATEPAUSE" : begin
			widget_control, animatespeed, sensitive=0
 			XBackRegister, "xintanim_bck", animatebase, /unregister
			framedelta = 0
			currentframe = curframe
			widget_control, animateframe, set_value=currentframe
			widget_control, animateframe, /sensitive
		     END

    "ANIMATEFRAME" : begin
		       widget_control, animateframe, get_value=curframe
    		       if (curframe ne currentframe) then begin
			 currentframe = curframe
			 device, copy = [0, 0, xs, ys, 0, 0, pwin(curframe)] 
       			 empty
       		       endif
		     end

    "ANIMATEFORWARD" : begin
			widget_control, animateframe, sensitive=0
			if (framedelta eq 0) then $
 			  XBackRegister, "xintanim_bck", animatebase
			framedelta = 1
			widget_control, animatespeed, /sensitive
		       end

    "ANIMATEREVERSE" : begin
			widget_control, animateframe, sensitive=0
			if (framedelta eq 0) then $
			  XBackRegister, "xintanim_bck", animatebase
			framedelta = -1
			widget_control, animatespeed, /sensitive
		       end

    "ANIMHELP" : xdisplayfile, "animatedemo.hlp", title="Animation Help", $
			group=event.top, width=55, height=16, $
			text=[					$
	"                                                       ", 	$
	"      Xinteranimate is used for displaying a series of", 	$
	"images created with IDL as an animation.  The user can", 	$
	"select the speed, direction or specific frames in the", 	$
	"animation.", 							$
	"      The top slider is used to control the speed of", 	$
	"the animation.  Moving it to the far right is one hundred", 	$
	"percent, as fast as the animation can go.  If there are", 	$
	"other IDL widget applications using background tasks,", 	$
	"they can slow down the animation.  Closing the other", 	$
	"applications can speed up the animation.  When the", 		$
	"animation is paused, the speed slider is inactive.", 		$
	"      The middle three buttons are reverse play, pause", 	$
	"and forward play.  Use them to select a direction or to", 	$
	"pause the animation and view specific frames.", 		$
	"      Finally, the bottom slider is used to view", 		$
	"certain frames from the animation.  The animation must", 	$
	"be paused to use the frame selection slider."	]

    "ANIMPALADJ" : xloadct, group=event.top

    "ANIMEXIT": begin
	uvspAnimate, /close
	struc.st8.numfram = 0			; reset
	end
    else:
  endcase

end ;----------------- end of procedure xintanim_event -----------------------

;==========================================================================

pro uvspanimate, rate, set = set, image = image, frame = frame, $
			 order = order, close = close, title = title, $
			 showload = showload, group = group, window = window, $
			 xoffset = xoffset, yoffset = yoffset 

common xinteranimate_com, pwin, swin, nframes, xs, ys, $
	animateframe, animatebase, animatepause, animatereverse, $
	animatespeed, animateforward, displayload, $
	framedelta, curframe, stall, currentframe, stallcount, animatedisplay

common order1, diskexp, control, generic, comment

initialspeed = 100

;=================================================================
; 
; End the movie
;
;=================================================================
             
if keyword_set(close) then begin		; when close keyword set, 
  xbackregister, "xintanim_bck", $
		animatebase, $
		/unregister 
  i = n_elements(pwin)
  if i lt 1 then return    		
  for j=0, i-1 do $
	if pwin(j) ge 0 then wdelete, pwin(j) ; delete the windows

  pwin = -1		;show nothing there
  widget_control, animatebase, /destroy
  return
endif


;Don't allow two copies of xinternimate to run at once
IF xregistered("XInterAnimate") THEN RETURN	

;============================================
;
; set up movie so frames can be loaded
;
;============================================

if keyword_set(set) then begin  	

  old_window = !d.window			; Save current window
  
  xs = set(0)					; users X size of movie window
  ys = set(1)					; users Y size of movie window
  nframes = set(2)				; num. frames user wants

  pwin = replicate(-1, nframes)			; Array of window indices
      
  ;Create the widgets used for the application
  animatebase = widget_base(/row, title='Movie')

   animatecntl = widget_base(animatebase, /column, /frame, xpad=20, ypad=20, $
								space=20)

    XPdMenu, [	'"End Animation"	ANIMEXIT',	$
		'"Adjust Color Palette"	ANIMPALADJ',	$
		'"Help"			ANIMHELP'], animatecntl

    speed = widget_base(animatecntl, /row)
     lab = widget_label(speed, value='Speed')
     animatespeed = widget_slider(speed, xsize=240, uvalue="ANIMATESPEED", $
				/drag, value=initialspeed, maximum=100, $
				minimum=0)
    animatebuts = widget_base(animatecntl, /row)
     animatereverse = widget_button(animatebuts, value=" Run reverse ", $
					     uvalue="ANIMATEREVERSE")
     animatepause = widget_button(animatebuts,   value="    pause     ", $
					   uvalue="ANIMATEPAUSE")
     animateforward = widget_button(animatebuts, value=" Run forward ", $
					     uvalue="ANIMATEFORWARD")
    curntfram= widget_base(animatecntl, /row)
     lab = widget_label(curntfram, value='Frame')
     animateframe = widget_slider(curntfram, xsize=240, uvalue="ANIMATEFRAME", $
				/drag, value=0, maximum=nframes-1, minimum=0)
     


   i = widget_base(animatebase, /column)	; To prevent stretching
    animatedisplay = widget_draw(i, xsize=xs, ysize=ys, xoffset=280, $
				  yoffset=20, retain=2)
  widget_control, animatebase, sensitive = 0


  displayload = 0
  if (old_window ge 0) then wset, old_window 	; reset to pre-movie window

  return
endif			; end of setting up the movie

;============================================
;
; Load user selected frames
;
;============================================

old_window = !d.window				; Save current window

if (n_elements(yoffset) eq 0) then yoffset = 0	;are zero unless specified.
if (n_elements(xoffset) eq 0) then xoffset = 0	;the defaults for the offsets

j = n_elements(window)				; check to see if window was set

if (j gt 0) then begin				; copy image from window
  if (j lt 5) then begin			; if coords not spec, use all
    wset, window(0)                             ; set to window to be frame
    ; use smaller of window or movie screen
    p = [ window(0), 0, 0, xs<!d.x_vsize, ys<!d.y_vsize ]  
  endif else p = window

  if pwin(frame) lt 0 then begin		; create pixwin for this frame
	window, /free, xsize = xs, ysize = ys, /pixmap
	pwin(frame) = !d.window
  endif

  ; load window into it's pixmap
  wset, pwin(frame)
  device, copy = [ p(1), p(2), p(3), p(4), xoffset, yoffset, p(0)]

  empty
  if (n_elements(swin) eq 0) then swin = -1

  if (old_window ge 0) then wset, old_window
  return
endif						;so window was not set.

if n_elements(image) ne 0  then begin		;make sure image was set.

  order = 0  					;Default order

  if pwin(frame) lt 0 then begin
		window, /free, xsize = xs, ysize = ys, /pixmap
		pwin(frame) = !d.window
  endif else wset, pwin(frame)

  tv, image, xoffset, yoffset, order = order
  empty

  if (old_window ge 0) then wset,old_window 	; reset to pre-movie window
  return
endif						;end of "if image was set".


;====================================================
;
; Register and Run movie
;
;====================================================

; register all the widgets now since all the frames have been loaded
widget_control, animatebase, /realize			
widget_control, animatedisplay, get_value = swin
widget_control, animatespeed, get_value = stall

empty

widget_control, animatebase, /sensitive 
widget_control, animateframe, sensitive = 0

; Set up the initial values used by the background task to display animation.
curframe = 0					
framedelta = 1					
stallcount = 0					

; establish initial speed for the animation 
if n_elements(rate) ne 0 then begin	
  rate = 0 > rate < 100	   			; valid range			
  stall = 100 - rate 				
  widget_control, animatespeed, set_value=rate
endif else stall = 100 - initialspeed

xmanager, "uvspanimate", animatebase, $	;register with the manager and
	  event_handler = "xintanim_event", $	;let the background task do the
	  background = "xintanim_bck", $	;frame update and the event
	  group_leader = group, $		;routine handle the events.
	  cleanup = "xintanim_clean"
end
