;some routines used by several of the other toolsets
 ;also some of routines used for views
 ;============================================================================
subr set_text_fields, wg, col_string, font_string, dx, dy
 n=num_elem(wg)-1
 for i=1,n do {	xmsetcolors,wg(i),col_string
		xmfont,wg(i),font_string
		xmposition,wg(i),-1,-1,dx, dy
		}
 endsubr
 ;============================================================================
subr set_boxes_red, wg
 n=num_elem(wg)-1
 for i=1,n do xmselectcolor,wg(i),'red'
 endsubr
 ;===============================================================================
subr generic_link_cb, window_widget, window_widget2
 narg = !narg
 xmtextfieldsetstring, window_widget, string($link_window)
 if narg lt 2 then return
 ;get the parameters of the array
 sq = '$data'+istring($link_window,2,2)
 if isarray(eval(sq)) eq 0 then { s = 'no data' } else {
 s = show_array(eval(sq)) }
 xmtextfieldsetstring, window_widget2, s
 endsubr
 ;===============================================================================
subr topbuttonsetup, wprefix, link_cb_string
 wts = wprefix+'widget'

 whs = wprefix+'help'
 help_file = $help_path + 'instructions.' + strreplace(wprefix,'$','',5)
 sq='widget_help, '+whs+ ','''+ help_file+''''
 bq = xmbutton(eval(wts),'Help', sq, $f4,'gray')
 xmposition,bq, 10, 10, 60, 30

 bq = xmbutton(eval(wts),'Dismiss', 'widget_dismiss, '+wts+','+whs, $f4,'gray')
 xmposition,bq, 80, 10, 64, 30

 sq = '{$link_action='''+link_cb_string+''' link_setup }'
 bq = xmbutton(eval(wts), 'Link', sq, $f4, 'darkgreen')
 xmposition, bq, 154, 10, 55, 30
 endsubr
 ;===============================================================================
func std_tlform_setup(title, wprefix, wq)
 w = xmtoplevel_form(0,0, title,0,0,5,5)
 wts = wprefix+'widget'
 equate, eval(wts), w
 wq = topbuttonsetup_tl(wprefix)
 return, w
 endfunc
  ;===============================================================================
func std_tlformsanslink_setup(title, wprefix, wq)
 w = xmtoplevel_form(0,0, title,0,0,5,5)
 wts = wprefix+'widget'
 equate, eval(wts), w
 wq = topbuttonsetupsanslink_tl(wprefix)
 return, w
 endfunc
  ;===============================================================================
func std_tlboardsanslink_setup(title, wprefix, wq)
 w = xmtoplevel_board(0,0, title,5,5)
 wts = wprefix+'widget'
 equate, eval(wts), w
 wq = topbuttonsetupsanslink_tl(wprefix)
 return, w
 endfunc
;===============================================================================
func std_tlboard_setup(title, wprefix, wq)
 w = xmtoplevel_board(0,0, title,5,5)
 wts = wprefix+'widget'
 equate, eval(wts), w
 wq = topbuttonsetup_tl(wprefix)
 return, w
 endfunc
;===============================================================================
func std2_tlboard_setup(title, wprefix, wq)
 ;a variation on std_tlboard_setup that eliminates the array info, more
 ;compact as a result
 w = xmtoplevel_board(0,0, title,5,5)
 ;need to define w as a global here because topbuttonsetup2_tl uses it
 wts = wprefix+'widget'
 equate, eval(wts), w
 wq = topbuttonsetup2_tl(wprefix)
 return, w
 endfunc
;===============================================================================
func std2_tlform_setup(title, wprefix, wq)
 ;a variation on std_tlform_setup that eliminates the array info, more
 ;compact as a result
 w = xmtoplevel_form(0,0, title,0,0,5,5)
 ;need to define w as a global here because topbuttonsetup2_tl uses it
 wts = wprefix+'widget'
 equate, eval(wts), w
 wq = topbuttonsetup2_tl(wprefix)
 return, w
 endfunc
 ;===============================================================================
func std_board_2links_setup(title, wprefix)
 ;used by several widgets to setup the shell, a few buttons, and a source
 ;window box. Used by fade
 wq = xmtoplevel_board(0,0, title,5,5)
 wts = wprefix+'widget'
 whs = wprefix+'help'
 help_file = $help_path + 'instructions.' + strreplace(wprefix,'$','',5)
 sq='widget_help, '+whs+ ','''+ help_file+''''
 bq = xmbutton(wq,'Help', sq, $f4,'gray')
 xmposition,bq, 0, 0, 60, 30
 bq = xmbutton(wq,'Dismiss', 'widget_popdown, '+wts+','+whs, $f4,'gray')
 xmposition,bq, 70, 0, 64, 30

 ;the first link and the source window
 ix=5	iy=45
 fw7 = xmframe(wq)
 xmposition, fw7, ix, iy
 board = xmboard(fw7, 0, 0)
 xmposition, xmlabel(board,'sources',$f4), 10, 50
 xmposition, xmlabel(board,'A',$f4), 12, 0
 xmposition, xmlabel(board,'B',$f4), 52, 0
 t1 = xmtextfield(board,'',30,'',$f3,'white')
 equate, eval(wprefix+'text1'), t1
 xmposition, t1, 2, 19, 36, 30
 link_cb_string = 'generic_link_cb,'+string(t1)
 sq = '{$link_action='''+link_cb_string+''' link_setup }'
 bq = xmbutton(wq, 'Link 1', sq, $f4, 'darkgreen')
 xmposition, bq, 144, 0, 55, 30
 xmtextfieldsetstring, t1, '0'

 ;the second link and the source window
 t1 = xmtextfield(board,'',30,'',$f3,'white')
 xmposition, t1, 42, 19, 36, 30
 equate, eval(wprefix+'text2'), t1	;note text2 here
 link_cb_string = 'generic_link_cb,'+string(t1)
 sq = '{$link_action='''+link_cb_string+''' link_setup }'
 bq = xmbutton(wq, 'Link 2', sq, $f4, 'darkgreen')
 xmposition, bq, 214, 0, 55, 30
 xmtextfieldsetstring, t1, '1'

 return, wq
 endfunc
 ;===============================================================================
func std_board_2links_alt(title, wprefix)
 ;used by several widgets to setup the shell, a few buttons, and a source
 ;window box. Used by superpose_widget, crossplot_widget, bops_widget,
 ; align_widget
 ;this is similar to std_board_2links_setup except that the text window
 ;widget names are used instead of generating the "standard" set. This allows
 ;different varieties of text windows as required by superpose and crossplot.
 ;Note that the names of the widgets must be global and need not be defined
 ;in advance (and aren't since this sets up their parent).
 wq = xmtoplevel_board(0,0, title,5,5)
 wts = wprefix+'widget'
 whs = wprefix+'help'
 help_file = $help_path + 'instructions.' + strreplace(wprefix,'$','',5)
 sq='widget_help, '+whs+ ','''+ help_file+''''
 bq = xmbutton(wq,'Help', sq, $f4,'gray')
 xmposition,bq, 0, 0, 60, 30
 bq = xmbutton(wq,'Dismiss', 'widget_popdown, '+wts+','+whs, $f4,'gray')
 xmposition,bq, 70, 0, 64, 30

 ;the first link
 link_cb_string = 'generic_link_cb,'+wprefix+'text1'
 sq = '{$link_action='''+link_cb_string+''' link_setup }'
 bq = xmbutton(wq, 'Link 1', sq, $f4, 'darkgreen')
 xmposition, bq, 144, 0, 55, 30

 ;the second link
 link_cb_string = 'generic_link_cb,'+wprefix+'text2'
 sq = '{$link_action='''+link_cb_string+''' link_setup }'
 bq = xmbutton(wq, 'Link 2', sq, $f4, 'darkgreen')
 xmposition, bq, 214, 0, 55, 30

 return, wq
 endfunc
 ;===============================================================================
func std_tlboard_2_setup(title, wprefix)
 ;used by several widgets to setup the shell, a few buttons, and a source/
 ;result window box. Used by filter, threshold, basin, noise
 wq = xmtoplevel_board(0,0, title,5,5)

 wts = wprefix+'widget'
 whs = wprefix+'help'
 help_file = $help_path + 'instructions.' + strreplace(wprefix,'$','',5)
 sq='widget_help, '+whs+ ','''+ help_file+''''
 bq = xmbutton(wq,'Help', sq, $f4,'gray')
 xmposition,bq, 0, 0, 60, 30
 bq = xmbutton(wq,'Dismiss', 'widget_popdown, '+wts+','+whs, $f4,'gray')
 xmposition,bq, 70, 0, 64, 30

 ;some text fields for window choices
 iq = xmlabel(wq,'windows for',$f5)
 xmposition,iq, 20, 50
 ix = 10		iy = 75
 fw=xmframe(wq)
 xmposition,fw, ix, iy
 board=xmboard(fw, 150, 95)
 s1 = 'source image'	s2='result image'
 text = xmtextfieldarray(board,'',$f5,'',80,10,40,35,s1,s2)
 n=num_elem(text)-1
 for i=1,n do {	xmsetcolors,text(i),'white'
		 xmfont,text(i),$f3
		 xmposition,text(i),-1,-1,40,35
		 }
 equate, eval(wprefix+'text'), text

 link_cb_string = 'generic_link_cb,'+string(text(1))
 sq = '{$link_action='''+link_cb_string+''' link_setup }'
 bq = xmbutton(wq, 'Link', sq, $f4, 'darkgreen')
 xmposition, bq, 144, 0, 55, 30

 return, wq
 endfunc
 ;============================================================================
func topbuttonsetup_tl(wprefix)
 return, topbuttonsetup(wprefix, 40, 1)
 endfunc
 ;============================================================================
func topbuttonsetup(wprefix, dyin, modein)
 ;11/30/96 (Zoe's birthday) a more complicated version of the earlier subr
 ;form, also use widget name pre-fix to avoid passing as many arguments and
 ;force more standardization
 ;returns a board widget containing 3 buttons and 2 text fields
 narg = !narg
 if narg gt 1 then dy = dyin else dy = 40
 if narg gt 2 then mode = modein else mode = 0
 wts = wprefix+'widget'
 wq = xmboard(eval(wts),0,0)
 xmposition, wq, 0, 0
 window_array_frame, wq, t1, t2, 0, dy
 equate, eval(wprefix+'text1'), t1

 whs = wprefix+'help'
 help_file = $help_path + 'instructions.' + strreplace(wprefix,'$','',5)
 sq='widget_help, '+whs+ ','''+ help_file+''''
 bq = xmbutton(wq,'Help', sq, $f4,'gray')
 xmposition,bq, 0, 0, 60, 30
 ;the mode is used to distinquish between top level and dialog widgets
 ty,'mode =', mode
 if mode eq 0 then
   bq = xmbutton(wq,'Dismiss', 'widget_dismiss, '+wts+','+whs, $f4,'gray')
   else bq = xmbutton(wq,'Dismiss', 'widget_popdown, '+wts+','+whs, $f4,'gray')
 xmposition,bq, 70, 0, 64, 30

 link_cb_string = 'generic_link_cb,'+string(t1)+','+string(t2)
 sq = '{$link_action='''+link_cb_string+''' link_setup }'
 bq = xmbutton(wq, 'Link', sq, $f4, 'darkgreen')
 xmposition, bq, 144, 0, 55, 30
 return, wq
 endfunc
 ;============================================================================
func topbuttonsetup2_tl(wprefix)
 ;a variation of topbuttonsetup without the array info
 ;returns a board widget containing 3 buttons and 1 text fields
 wts = wprefix+'widget'
 wq = xmboard(eval(wts),0,0)
 xmposition, wq, 0, 0
 ;source window #
 ix = 203		iy = 0
 t1 = xmtextfield(wq,'',2,'',$f3,'white')
 xmposition, t1, ix, iy, 40,30
 equate, eval(wprefix+'text1'), t1

 whs = wprefix+'help'
 help_file = $help_path + 'instructions.' + strreplace(wprefix,'$','',5)
 sq='widget_help, '+whs+ ','''+ help_file+''''
 bq = xmbutton(wq,'Help', sq, $f4,'gray')
 xmposition,bq, 0, 0, 60, 30
 bq = xmbutton(wq,'Dismiss', 'widget_popdown, '+wts+','+whs, $f4,'gray')
 xmposition,bq, 70, 0, 64, 30

 link_cb_string = 'generic_link_cb,'+string(t1)
 sq = '{$link_action='''+link_cb_string+''' link_setup }'
 bq = xmbutton(wq, 'Link', sq, $f4, 'darkgreen')
 xmposition, bq, 144, 0, 55, 30

 return, wq
 endfunc
 ;===============================================================================
subr topbuttonsetupsanslink, wts, whs, help_file, wq
 sq='widget_help, '+whs+ ','''+ help_file+''''
 ;;bq = xmbutton(eval(wts),'Help', sq, $f4,'gray')
 wq = xmboard(eval(wts))
 bq = xmbutton(wq,'Help', sq, $f4,'gray')
 xmposition,bq, 10, 10, 60, 30
 ;;bq = xmbutton(eval(wts),'Dismiss', 'widget_dismiss, '+wts+','+whs, $f4,'gray')
 bq = xmbutton(wq,'Dismiss', 'widget_dismiss, '+wts+','+whs, $f4,'gray')
 xmposition,bq, 80, 10, 64, 30
 endsubr
 ;===============================================================================
func topbuttonsetupsanslink(wprefix)
 wts = wprefix+'widget'
 wq = xmboard(eval(wts),0,0)
 xmposition, wq, 0, 0
 whs = wprefix+'help'
 help_file = $help_path + 'instructions.' + strreplace(wprefix,'$','',5)
 sq='widget_help, '+whs+ ','''+ help_file+''''
 bq = xmbutton(wq,'Help', sq, $f4,'gray')
 xmposition,bq, 0, 0, 60, 30
 bq = xmbutton(wq,'Dismiss', 'widget_dismiss, '+wts+','+whs, $f4,'gray')
 xmposition,bq, 70, 0, 64, 30
 return, wq
 endfunc
 ;===============================================================================
func topbuttonsetupsanslink_tl(wprefix)
 ;for use with top level widgets
 wts = wprefix+'widget'
 wq = xmboard(eval(wts),0,0)
 xmposition, wq, 0, 0
 whs = wprefix+'help'
 help_file = $help_path + 'instructions.' + strreplace(wprefix,'$','',5)
 sq='widget_help, '+whs+ ','''+ help_file+''''
 bq = xmbutton(wq,'Help', sq, $f4,'gray')
 xmposition,bq, 0, 0, 60, 30
 bq = xmbutton(wq,'Dismiss', 'widget_popdown, '+wts+','+whs, $f4,'gray')
 xmposition,bq, 70, 0, 64, 30
 return, wq
 endfunc
 ;===============================================================================
func topbuttonsetupsanslink_tlun(wprefix)
 ;for use with top level widgets and also unmanages, this makes
 ;popup's more complicated because you have to manage them also
 ;but it allows testing if widget is managed
 wts = wprefix+'widget'
 wq = xmboard(eval(wts),0,0)
 xmposition, wq, 0, 0
 whs = wprefix+'help'
 help_file = $help_path + 'instructions.' + strreplace(wprefix,'$','',5)
 sq='widget_help, '+whs+ ','''+ help_file+''''
 bq = xmbutton(wq,'Help', sq, $f4,'gray')
 xmposition,bq, 0, 0, 60, 30
 bq = xmbutton(wq,'Dismiss', 'widget_popdown_unman, '+wts+','+whs, $f4,'gray')
 xmposition,bq, 70, 0, 64, 30
 return, wq
 endfunc
 ;============================================================================
subr window_array_frame, parent, wn, warr, ix, iy
 ;convenience routine to put up a framed area for window number and
 ;a text field for the associated array information, widgets for the
 ;last 2 are returned
 fw=xmframe(parent)
 xmposition,fw, ix, iy
 board=xmboard(fw, 308, 40)
 xmposition, xmlabel(board,'window',$f4), 10, 8
 xmposition, xmlabel(board,'array',$f4), 115, 8
 wn = xmtextfield(board,'',2,'',$f3,'white')
 xmposition, wn, 70, 2, 40, 35
 warr = xmtextfield(board,'',2,'',$f3,'white')
 xmtextfieldseteditable, warr, 0
 xmposition,warr, 160, 2, 140, 35
 endsubr
 ;========================================================
subr formvstack,b1,b2,b3,b4,b5,b6,b7,b8,b9,b10,b11,b12,b13,b14,b15,b16,b17,b18
 ;works from top down
 ;note that a widget that is attached on both top and bottom will have its
 ;height controlled by the form, this is usually the last one but
 ;if a value is negative, we will attach both sizes of abs(bx) and not
 ;attach both sides of the bottom
 narg=!narg
 bflag = 0
 bq = abs(b1)
 xmattach,bq,0,    1,1,1,0
 if b1 lt 0 then {
   xmattach,bq,b2,0,0,0,1
   bflag = 1
   if b2 lt 0 then { ty,'error in formvstack, 2 or more negative values' return}
 } else {
   xmattach,abs(b2),b1,0,0,1,0
 }
 xmattach,abs(b2),0,    1,1,0,0
 if narg gt 2 then for k = 3, narg do {
   w1 = eval('b'+string(k-1))
   w2 = eval('b'+string(k))
   if w1 lt 0 then { if bflag then {
     ty,'error in formvstack, 2 or more negative values' return
   } else bflag = 1 }
   w1 = abs(w1)   w2 = abs(w2)
   if bflag then xmattach,w1,w2, 0,0,0,1 else xmattach,w2,w1, 0,0,1,0
   xmattach,w2,0, 1,1,0,0
 }
 ;always want the last one attached to the bottom
 xmattach, abs(eval('b'+string(narg))),0,0,0,0,1
 endsubr
 ;========================================================
subr formvstack_arr, b
 ;works from top down
 if isarray(b) then {
   n = num_elem(b)
   if n lt 2 then {
     errormess,'formvstack_arr arg not an array at least 2 long'
   }
   xmattach,b(0),0,    1,1,1,0
   xmattach,b(1),b(0), 0,0,1,0
   xmattach,b(1),0,    1,1,0,0
   if n gt 2 then for k = 2, n-1 do {
     xmattach,b(k),b(k-1), 0,0,1,0
     xmattach,b(k),0, 1,1,0,0
   }
   xmattach,b(n-1),0,1,1,0,1
 } else {
   errormess,'formvstack_arr arg not an array'
 }
 endsubr
 ;========================================================
subr formvstackrhs,b1,b2,b3,b4,b5,b6,b7,b8,b9,b10,b11,b12,b13,b14,b15,b16,b17,b18
 ;works from top down
 narg=!narg
 xmattach,b1,0,    0,1,1,0
 xmattach,b2,b1,   0,0,1,0
 xmattach,b2,0,    0,1,0,0
 if narg gt 2 then for k = 3, narg do {
   xmattach,eval('b'+string(k)),eval('b'+string(k-1)), 0,0,1,0
   xmattach,eval('b'+string(k)),0, 0,1,0,0
 }
 xmattach,eval('b'+string(narg)),0,0,0,0,1
 endsubr
 ;========================================================
subr formhstack,b1,b2,b3,b4,b5,b6,b7,b8,b9,b10,b11,b12,b13,b14,b15,b16,b17,b18
 ;works from left to right
 ;note that a widget that is attached on both left and right will have its
 ;width controlled by the form, this is usually the last one but
 ;if a value is negative, we will attach both sizes of abs(bx) and not
 ;attach both sides of the right
 narg=!narg
 bflag = 0
 bq = abs(b1)
 xmattach,bq,0,   1,0,0,0
 if b1 lt 0 then {
   xmattach,bq,b2,0,1,-1,-1
   bflag = 1
   if b2 lt 0 then { ty,'error in formhstack, 2 or more negative values' return}
 } else {
   xmattach,abs(b2),b1,1,0,-1,-1
 }

 if narg gt 2 then for k = 3, narg do {
   w1 = eval('b'+string(k-1))
   w2 = eval('b'+string(k))
   if w1 lt 0 then { if bflag then {
     ty,'error in formhstack, 2 or more negative values' return
   } else bflag = 1 }
   w1 = abs(w1)   w2 = abs(w2)
   if bflag then xmattach,w1,w2, 0,1,-1,-1 else xmattach,w2,w1, 1,0,-1,-1
 }
 ;always want the last one attached to the right
 xmattach,eval('b'+string(narg)),0,0,1,0,0
 endsubr
 ;========================================================
subr formhstackr,b1,b2,b3,b4,b5,b6,b7,b8,b9,b10,b11,b12,b13,b14,b15,b16,b17,b18
 ;very often we want the right side widget to determine the size,
 ;so this right to left variation is provided
 ;works from right to left
 narg=!narg
 xmattach,b1,0,   0,1,0,0
 xmattach,b2,b1,   0,1,-1,-1
 if narg gt 2 then for k = 3, narg do {
   xmattach,eval('b'+string(k)),eval('b'+string(k-1)), 0,1,-1,-1
 }
 xmattach,eval('b'+string(narg)),0,1,0,0,0
 endsubr
 ;========================================================
func labeled_button(callback,s,ix,iy,parent)
 b=xmbutton(parent, ' ', callback, $f4, 'red')
 xmposition,b,ix,iy,30,30
 lq = xmlabel(parent, s, $f4)
 xmposition,lq, ix+40,iy+3
 return,b
 endfunc
 ;========================================================
subr widget_help, help_widget_name, file_name
 ty,'file name: ', file_name
 if defined(help_widget_name) eq 0 then {
   help_widget_name = xmdialog_form(0,0,0, 'tool instructions',0,0,10,10)
   f3='-adobe-courier-bold-r-normal--12*'
   ls = xmtextfromfile(help_widget_name, file_name, 30, 80, f3, 'white')
   xmattach, xtparent(ls), 0,   1,1,1,1
   xmtextseteditable, ls, 0	;makes non-editable
   xtmanage, help_widget_name
   flipflop = 1
 } else {
   if flipflop eq 1 then { xtunmanage, help_widget_name   flipflop = 0 } else {
 	xtmanage, help_widget_name flipflop = 1 }
 }
 endsubr
 ;===============================================================================
subr widget_dismiss, widget_name, help_widget_name
 xtunmanage, widget_name
 if defined(help_widget_name) ne 0 then xtunmanage, help_widget_name
 if $blocking then { $blocking = 0  !motif = 0 }
 endsubr
 ;===============================================================================
subr widget_popdown, widget_name, help_widget_name
 xtpopdown, widget_name
 if defined(help_widget_name) ne 0 then xtunmanage, help_widget_name
 if $blocking then { $blocking = 0  !motif = 0 }
 endsubr
 ;===============================================================================
subr widget_popdown_unman, widget_name, help_widget_name
 xtunmanage, widget_name
 xtpopdown, widget_name
 if defined(help_widget_name) ne 0 then xtunmanage, help_widget_name
 if $blocking then { $blocking = 0  !motif = 0 }
 endsubr
 ;===============================================================================
subr file_select
 ;set up a file selection dialog
 if defined($fs1) eq 1 then xtmanage, $fs1 else {
 s1 = 'Read and Display File'
 $fs1=xmfileselect(0, s1,'single_display','Display','fhelp','fcancel', $f3,$f5)
 }
 return
 endsubr
 ;==============================================================================
subr fcancel
 ;just unmanage, kept for older programs, now use fscancel
 xtunmanage, $fs1
 return
 endsubr
 ;========================================================
subr fscancel, win
 ;just unmanage
 xtunmanage, eval('$fs'+string(win))
 return
 endsubr
 ;========================================================
subr prompt_cb
 !motif =0
 endsubr
 ;========================================================
subr redraw_cb, win
 ;a front end for view except we do the button thing
 sq = '$view_redraw_button'+string(win)
 change_button_label, eval(sq), 'wait', 'red'
 xtloop, 2
 view, win
 change_button_label, eval(sq), 'Redraw', 'gray'
 endsubr
 ;========================================================
subr file_view, k
 ;set up a file selection dialog
 sk = string(k)
 wname = '$fv'+ sk
 if defined(eval(wname)) eq 1 then xtmanage, eval(wname) else {
 sq = 'enter path for file\nselection dialog\nor leave blank'
 sq = sq + '\nfor current directory'
 xmprompt, sq,'','prompt_cb', 1, $f7, '',!screen_width/2 -50,!screen_height/2-50
 xtloop, 1
 ;we get here after the prompt_cb lets us (it sets !motif = 0)
 dirq = $textfield_value
 xtloop, 0
 !motif = 1
 help_file = $help_path + '/instructions.fview'
 s1 = 'Viewer'+ sk
 scommand = 'display,'+ sk
 whs = wname + '_help'
 scancel = 'widget_dismiss, '+wname+','+whs
 shelp = 'widget_help, '+whs+ ','''+ help_file+''''
 iq=xmfileselect(0, s1, scommand,'Display', shelp, scancel,$f3,$f5, '', dirq)
 switch, iq, eval(wname)
 }
 return
 endsubr
 ;========================================================
subr file_load, scommand
 ;set up a file selection dialog for loading a file name into a text widget
 ;otherwise very similar to file_view
 ;scommand is the command to be done when the load file button is pressed,
 ;it should be a global string variable
 wname = '$file_load'
 if defined(eval(wname)) eq 1 then xtmanage, eval(wname) else {
 sq = 'enter path for file\nselection dialog\nor leave blank'
 sq = sq + '\nfor current directory'
 xmprompt, sq,'','prompt_cb', 1, $f7, '',!screen_width/2 -50,!screen_height/2-50
 xtloop, 1
 ;we get here after the prompt_cb lets us (it sets !motif = 0)
 dirq = $textfield_value
 xtloop, 0
 !motif = 1
 help_file = $help_path + 'instructions.fload'
 s1 = 'Load File Name'
 whs = wname + '_help'
 scancel = 'widget_dismiss, '+wname+','+whs
 shelp = 'widget_help, '+whs+ ','''+ help_file+''''
 iq=xmfileselect(0, s1, scommand,'Load File', shelp, scancel,$f3,$f5, '', dirq)
 switch, iq, eval(wname)
 }
 return
 endsubr
 ;========================================================
subr fhelp
 xmmessage,$mess3, $f7,'red'
 return
 endsubr
 ;========================================================
func ftsc_old(x)
 ;the older version of ftsc, obsolete
 ;returns a scaled byte array version of x, could be either an ft type scaling
 ;or just a specified scale range depending on $scaletype parameter
 ;check for mapping info
 hbot = .001	htop = .999	gam = 1.0
 if defined($imagemapwidget) eq 1 then {
  hbot = float(xmtextfieldgetstring ($imaptext1)
  htop = float(xmtextfieldgetstring ($imaptext2)
  gam = float(xmtextfieldgetstring ($imaptext3)
 } else { $scaletype = 2 }	 ;if widget not defined, always option 2
 ;don't be mislead by the names above, they will be interpreted according to
 ;$scaletype
 ncase $scaletype
 {  if hbot eq 0 and htop eq 0 then { hbot = min(x)  htop = !lastmax }
    return, pscale(x, hbot, htop, gam) }
 {  hbot = min(x)  htop = !lastmax
    return, pscale(x, hbot, htop, gam) }
 {  
    return, ft(x, hbot, htop, gam) }
 endcase
 endfunc
 ;========================================================
subr tvbrow, x, win, cflag
 ;used for simple displays that require the mapping parameters
 ;cflag controls compression by 2 or central area display
 if symclass(x) ne 4 then {
   errormess,'no such image'
   return }

 nx = dimen(x, 0)		ny = dimen(x,1)
 ;since we want to match the window to the image, we need to check for
 ;one of the transpose cases of !iorder
 nxx = nx  nyy = ny
 if (!iorder % 2) eq 1 then { nxx = ny   nyy = nx }
 if cflag eq 1 or cflag eq 2 then  {
	xport,win,nxx/2,nyy/2,10,10 } else { xport,win,nxx,nyy,10,10 }
 if cflag eq 0 then tv,ftsc_old(x),0,0,win else
   if cflag eq 1 tv,ftsc_old(compress(x,2)),0,0,win else
    if cflag eq 2 then tv,ftsc_old(center(x,nx/2,ny/2)),0,0,win
 xraise, win
 $window_orientation(win) = !iorder
 xflush
 endsubr
 ;========================================================
subr tvbrowsansft, x, win, cflag
 ;used for simple displays without an ft, just passes data to tv
 ;cflag controls compression by 2 or central area display
 nx = dimen(x, 0)		ny = dimen(x,1)
 ;since we want to match the window to the image, we need to check for
 ;one of the transpose cases of !iorder
 nxx = nx  nyy = ny
 if (!iorder % 2) eq 1 then { nxx = ny   nyy = nx }
 if cflag eq 1 or cflag eq 2 then  {
	xport,win,nxx/2,nyy/2,10,10 } else { xport,win,nxx,nyy,10,10 }
 if cflag eq 0 then tv, x,0,0,win else
   if cflag eq 1 tv,compress(x,2),0,0,win else
    if cflag eq 2 then tv,center(x,nx/2,ny/2),0,0,win
 xraise, win
 xflush
 endsubr
 ;=============================================================================
func subarea_radiobox(parent, ix, iy)
 widget = xmradiobox(parent,'',$f4,'','entire image','subarea #')
 xmposition,widget(0), ix, iy
 n=num_elem(widget)-1
 for i=1,n do xmselectcolor,widget(i),'red'
 xmtogglesetstate, widget(1), 1
 return, widget
 endfunc
 ;=============================================================================
func labelarray(par,font,color,w,h,ix,iy,alig,l1,l2,l3,l4,l5,l6,l7,l8,l9,l10)
 ;assemble a vertical array of labels, lots of arguments and a bit
 ;complicated to make it flexible
 nlab = !narg - 8
 if nlab le 0 then { ty,'too few args in labelarray' return, 0 }
 if nlab gt 10 then { ty,'too many labels in labelarray' return, 0 }
 warray = lonarr(nlab)
 zero, warray
 for i=0,nlab-1 do {
 ;ty,'labelarrayrj, i =',i
 iq = xmlabel(par,eval('l'+string(i+1)),font,color,1)
 warray(i) = iq
 xmalignment, iq, alig
 xmposition, iq, ix,iy+i*h,w
 }
 d, warray
 return,warray
 endfunc
 ;=============================================================================
subr convertfordata, x1, y1, win
 ;used to convert screen boxes to limits in the data
 ;we have to check for "super views" that exceed the data space size, these
 ;are always coupled
 ;first account for any zoom and offset
 zm = $view_zoom_fac(win)
 if zm lt 0 then { zm = 1.0/abs(zm) }	;make zm fp, so have to "fix" a lot
 x1 = fix(x1/zm) + $view_ix(win)
 y1 = fix(y1/zm) + $view_iy(win)
 ;are we part of a connected set of views ?
 if $view_connect(win) then {
 	x1 = x1 + $view_connectx(win)
 	y1 = y1 + $view_connecty(win)
  }
 ;to get the coord. in the original array, need to know orientation
 iq = $view_order(win)
 nx = $view_nx(win)
 ny = $view_ny(win)
 jq = iq%4
 ;reverse direction of x and y as needed
 if jq lt 2 then { y1 = ny-1-y1 }
 if jq%2 eq 1 then { x1 = nx-1-x1 }
 ;check if a transpose
 if iq ge 4 then { switch, x1,y1 }
 ;always return integers
 x1 = rfix(x1)	y1 = rfix(y1)
 ;12/23/99 - part of a coupled set ?
 ;;12/23/99 - no longer force to be in range
 ;;force to be in range
 ;;x1 = (x1>0)<(nx-1)
 ;;y1 = (y1>0)<(ny-1)
 endsubr
 ;=============================================================================
subr convertview2solar, x, y, win, ss
 timeslice = 0
 movie = 0
 if win ge 20 then timeslice = 1 else if win ge #play_window then movie = 1
 viewonly = (timeslice + movie) eq 0
 ;can't do timeslice windows
 if timeslice then {
 	errormess,'subareas not supported\nfor window '+string(win)
	return
	}

 zm = float($view_zoom_fac(win))
 if zm lt 0 then  zm = 1.0/abs(zm)

 if viewonly then {
  ss = $view_sun_pixel_scale(win)
  nx = $view_nx(win)
  ny = $view_ny(win)
  xcen = $view_sun_xc(win)
  ycen = $view_sun_yc(win)
  tai = $view_tai(win)
  ;like convertfordata except we don't round
  x = fix(x/zm) + $view_ix(win)
  y = fix(y/zm) + $view_iy(win)
  ;are we part of a connected set of views ?
  if $view_connect(win) then {
 	 x = x + $view_connectx(win)
 	 y = y + $view_connecty(win)
   }
  ;to get the coord. in the original array, need to know orientation
  iord = $view_order(win)
 }

 if movie then {
  j = $now+$j1
  dx = $view_ix(win)
  dy = $view_iy(win)
  ;for movies, the $view_order should always be 2 but the movie may be
  ;computed otherwise, this will affect the translation to solar
  ;;iord = $mv_order xor 2
  iord = $mv_order
  if win eq #play_window then {
    vname = '$data'+string(win)
    it = $play_index(j)
    $mouse_tai = $movie_times(it)
    dx = dx + $mv_track_dx(it)
    dy = dy + $mv_track_dy(it)
    ss = $movie_pixsc(it)
    xcen = $movie_xc(it)
    ycen = $movie_yc(it)
  } else {
    ;one of the multi-movies, use the multi arrays based on j
    i = win - $play_window(1)
    vname = '$movie'+string(i+1)
    $mouse_tai = $multi_times_image(j, i)
    it = $play_multi(j, i)
    dx = dx + $multi_track_dx(j, i)
    dy = dy + $multi_track_dy(j, i)
    xcen = $multi_xc(j, i)
    ycen = $multi_yc(j, i)
    ss = $multi_ref_scale
  }
  ;convert to coords in the displayed array (order always 2)
  x = fix(x/zm) + rfix(dx)
  y = fix(y/zm) + rfix(dy)
  get_nx_ny, eval(vname), it, nx, ny	;note nx, ny returned
 }

 ;the following should work now for both regular views and movies
 ;check if a transpose
 transpose = iord ge 4
 ;reverse direction of x and y as needed
 if iord%4 lt 2   then { y = ny-1-y }
 if iord%2 eq 1 then { x = nx-1-x }
 if transpose then { exchange, x,y }
 ;(x,y) are now in "data" coordinates which are always in normal orientation
 if transpose then { exchange, nx, ny }  ;because this is the view, not the data

 ;if the scale is not known, try to still make this useful for the original
 ;image by setting scale to 1.0 and (xcen, ycen) to (0,0), but pass original
 ;ss back to caller
 ;get the solar coordinates of the corner
 if ss le 0 then {  sst=1.0  xcen =0  ycen = 0 }else sst = ss
 xcorner = xcen - (.5*nx -.5)*sst
 ycorner = ycen - (.5*ny -.5)*sst
 x = xcorner + x*sst
 y = ycorner + y*sst
 endsubr
 ;=============================================================================
subr convertsolar2data_or_view, x1, y1, w1, tai, mode
 ;convert a position on the sun in arc sec from disk center to data coords
 ;or to screen offset in a view, depending on mode (0 for data, 1 for view)
 ;tai is needed only for timeslices, for movies we use only the
 ;position on the currently displayed frame (which is generally at a different
 ;time than tai)
 ;x1 and y1 are the modified results
 ;for timeslice, the mode is assumed to be 1 at present
 xwindow, w1
 ;determine if a time slice view or a movie or just an image
 timeslice = 0
 movie = 0
 if w1 ge 20 then timeslice = 1 else if w1 ge #play_window then movie = 1
 viewonly = (timeslice + movie) eq 0
 nx = $view_nx(w1)
 ny = $view_ny(w1)
 iord = $view_order(w1)
 ;nx and ny and iord will be superseded for the movie case, dx and dy
 ;are not used (here) for view only case but are used for the others
 ;check if a transpose
 transpose = iord ge 4
 dx = $view_ix(w1)
 dy = $view_iy(w1)

 if timeslice then {
  ;the number of the timeslice, currently range is 0 to 4
  nts = w1 - 20
  ;here we have to account for the orientation of the viewed slice and also the orientation
  ;of the data used for the slice
  ;this will vary depending on the type of slice, for line slice xcorner,
  ;ycorner is the starting position of the line (as a fn of time), for
  ;circles it is the center
  xcorner = $ts_sunx1(nts)	;note, these are arrays (nt)
  ycorner = $ts_suny1(nts)
  ;the spatial direction in the timeslice has both x and y components on the
  ;sun, pre-compute these for any index found below
  if transpose then { nt = nx  ns = ny } else { ns = nx  nt = ny }
  len = float(ns-1)
  if nt ne dimen_symarr($ts_times,nts,0) then {
   errormess,'internal error\ninconsistent nt for time slice'
   x1 = 0   y1 = 0
   return
  }
  tstype = $ts_type(nts)
  if tstype gt 2 then { errormess,'internal error\non ts type' return }
  if tstype eq 1 then {
    ;we have a straight line
    ;$ts_sundx and $ts_sundy are the solar x and y extents in arc sec
    dxss = $ts_sundx(nts)/len
    dyss = $ts_sundy(nts)/len
    ss = sqrt(dxss*dxss + dyss*dyss)
  } else if tstype eq 2 then {
    ;a circle, $ts_sundx is the radius for circles
    dxss = $ts_sundx(nts)	;this is radius
    ss = len/#2pi		;this is pixels per radian
    ;dyss is not used
  }
  ;the times are already in $ts_times
  }

 if viewonly then {
  ss = $view_sun_pixel_scale(w1)
  xcen = $view_sun_xc(w1)
  ycen = $view_sun_yc(w1)
 }

 if movie then {
  ;note that the time index of the displayed frame is used to get the offset
  ;the passed value t is not used except for timeslices
  j = $now+$j1
  zm = float($view_zoom_fac(w1))
  ;for movies, the $view_order should always be 2
  if zm lt 0 then  zm = 1.0/abs(zm)
  iord = $mv_order
  transpose = iord ge 4
  if w1 eq #play_window then {
    vname = '$data'+string(w1)
    it = $play_index(j)
    dx = dx + $mv_track_dx(it)
    dy = dy + $mv_track_dy(it)
    ss = $movie_pixsc(it)
    xcen = $movie_xc(it)
    ycen = $movie_yc(it)
  } else {
    ;one of the multi-movies, use the multi arrays based on j
    i = w1 - $play_window(1)
    vname = '$movie'+string(i+1)
    it = $play_multi(j, i)
    dx = dx + $multi_track_dx(j, i)
    dy = dy + $multi_track_dy(j, i)
    xcen = $multi_xc(j, i)
    ycen = $multi_yc(j, i)
    ss = $multi_ref_scale
  }
  get_nx_ny, eval(vname), it, nx, ny	;note nx, ny returned
 }

 if timeslice eq 0 then {
  if transpose then { switch, nx, ny }  ;because this is the view, not the data
  ;if we got here with ss = 0, then we assume we are just working with
  ;pixels and set ss = 1.0 (or we blow up below)
  if ss le 0.0 then ss = 1.0
  ;get the solar coordinates of the (0,0) corner
  xcorner = xcen - (.5*nx -.5)*ss
  ycorner = ycen - (.5*ny -.5)*ss
  x1 = (x1 - xcorner)/ss
  y1 = (y1 - ycorner)/ss
  if viewonly then {
   ;for the viewonly case, we are already in data coords, do view only if mode=1
   if mode then convertforview, x1, y1, w1
  } else {
   if movie then {
     ;6/17/2002 - the view coords and coords in the movie image are the same
     ;directions, both are generally different from the solar coords
     if transpose then { switch, x1,y1   switch, nx, ny }
     ;reverse direction of x and y as needed
     if iord%4 lt 2   then { y1 = ny-1-y1 }
     if iord%2 eq 1 then { x1 = nx-1-x1 }
     ;for the view case (mode = 1), adjust for offset and zoom
     if mode then {
       x1 = rfix((x1 - dx) * zm)
       y1 = rfix((y1 - dy) * zm)
     }
   }
  }
 } else { 
  ;timeslice case
  ;more work here, it might not be on the line of course nor in the time range
  ts_times = $ts_times(nts)	;extract the appropiate time array
  jt = minloc(abs(ts_times - tai))
  jt = jt(0)
  ;check if at an end
  if jt le 0 or jt ge (nt - 1) then {
    if !lastmin gt mean(abs(differ(ts_times))) then
    	errormess,'warning: time out of range'
    	;but we'll use the limit
  }
  ;get the x and y distances from the ref position (start of line or
  ;center of circle)
  ix = (x1 - xcorner(jt))
  iy = (y1 - ycorner(jt))
  offline = 0
  ;lines and circles are different (again)
  if tstype eq 1 then {
    ;8/14/2003 - this didn't do vertical or horizontal lines correctly
    ;just assume we really are on line and simplify
    ty,'ix,iy,dxss,dyss', ix,iy,dxss, dyss
    x1 = rfix( sqrt(ix*ix + iy*iy)/ss)
    x1 = (x1 < len) > 0
    ;;ix = ix/dxss
    ;;iy = iy/dyss
    ;;ty,'converted ix,iy', ix,iy
    ;if both give the same (basic) answer, then on line (or close)
    ;;if abs(ix-iy) ge 2 then offline = 1
    ;;if ix lt 0 or iy lt 0 or ix gt len or iy gt len then offline = 1
    ;;ix = (ix < len) > 0
    ;;iy = (iy < len) > 0
    ;;x1 = rfix( 0.5*(ix + iy))
  } else if tstype eq 2 then {
    ;ix and iy give us a radius and an angle, we want the radius to
    ;be close or we complain
    if (abs(dxss - sqrt(ix*ix+iy*iy))) ge 2 then offline = 1
    x1 = atan2(iy, ix)
    x1 = x1 + (x1 lt 0) * #2pi
    x1 = x1 * ss
  }
  
  if offline then errormess,'warning: position off the line or curve'
  
  y1 = jt	;time goes to y1
  ;we now have the indices in the data in x1, y1
  ;where x1 is along space line and y1 is time
  ;reverse directions as needed, note use of ns and nt
  if iord%4 lt 2   then { y1 = nt-1-y1 }
  if iord%2 eq 1 then { x1 = ns-1-x1 }
  if transpose then { exchange, x1, y1 }
  ;zooms are handled differently for time slices, zm is always 1
  x1 = x1 - dx
  ;the time gets put into y1
  y1 = y1 - dy
 }
 ;it might be outside the window, clamp to edge, but only for view mode
 ;;if mode then { x1=(x1<!ixhigh)>0   y1=(y1<!iyhigh)>0 }
 ;use some globals to avoid re-doing some things in some callers
 $nx = nx	$ny = ny	$iord = iord	$ss = ss
 return
 endsubr
 ;=============================================================================
subr convertforview, x1, y1, win
 ;used to convert coords in the data to view
 ;the view coordinates are from the upper left hand corner
 ;are we part of a connected set of views ?
 if $view_connect(win) then {
  x1 = x1 - $view_connectx(win)
  y1 = y1 - $view_connecty(win)
  }
 ;need to know orientation, apply transpose first for this direction
 iq = $view_order(win)
 ;check if a transpose
 if iq ge 4 then { switch, x1,y1 }
 jq = iq%4
 nx = $view_nx(win)
 ny = $view_ny(win)
 ;reverse direction of x and y as needed
 if jq lt 2 then { y1 = ny-1-y1 }
 if jq%2 eq 1 then { x1 = nx-1-x1 }
 ;account for any zoom and offset
 zm = $view_zoom_fac(win)
 if zm lt 0 then { zm = 1.0/abs(zm) }	;make zm fp, so have to "fix" a lot
 ;ty,'zm, $view_ix(win), $view_iy(win) =', zm, $view_ix(win), $view_iy(win)
 x1 = rfix(zm*(x1 - $view_ix(win)))
 y1 = rfix(zm*(y1 - $view_iy(win)))
 ;set some globals (7/17/2007) also
 $nx = nx
 $ny = ny
 $iord = $view_order(win)
 
 endsubr
 ;=============================================================================
subr convertbbforview, x1, y1, x2, y2, win
 ;used to convert limits in the data to screen boxes
 ;need to know orientation, apply transpose first for this direction
 ;are we part of a connected set of views ?
 if $view_connect(win) then {
  x1 = x1 - $view_connectx(win)
  y1 = y1 - $view_connecty(win)
  }
 iq = $view_order(win)
 ;check if a transpose
 if iq ge 4 then { switch, x1,y1  switch, x2,y2 }
 jq = iq%4
 nx = $view_nx(win)
 ny = $view_ny(win)
 ;reverse direction of x and y as needed
 if jq lt 2 then { y1 = ny-1-y1  y2 = ny-1-y2 }
 if jq%2 eq 1 then { x1 = nx-1-x1  x2 = nx-1-x2 }
 ;account for any zoom and offset
 zm = $view_zoom_fac(win)
 if zm lt 0 then { zm = 1.0/abs(zm) }	;make zm fp, so have to "fix" a lot
 ;ty,'zm, $view_ix(win), $view_iy(win) =', zm, $view_ix(win), $view_iy(win)
 if x1 gt x2 then exchange, x1, x2
 if y1 gt y2 then exchange, y1, y2
 x1 = fix(zm*(x1 - $view_ix(win)))
 y1 = fix(zm*(y1 - $view_iy(win)))
 x2 = fix(zm*(x2 +.9999 - $view_ix(win)))
 y2 = fix(zm*(y2 +.9999 - $view_iy(win)))
 endsubr
 ;=============================================================================
subr latlongupdate, win
 if $radio_state then $viewlatlongflag(win) =1  else $viewlatlongflag(win) =0
 endsubr
 ;=============================================================================
subr viewclockupdate, win
 if $radio_state then {
   $viewclockflag(win) =1 
   view_clock_box, win
 } else {
   $viewclockflag(win) =0
   xtunmanage, eval('$viewclockbox'+ string(win))
 }
 endsubr
 ;=============================================================================
subr despikeupdate, win
 ty,'despikeupdate, win =', win, ' $radio_state =', $radio_state
 if $radio_state then $viewdespikeflag(win) =1  else $viewdespikeflag(win) =0
 ty,'result =', $viewdespikeflag(win)
 endsubr
 ;=============================================================================
subr emiupdate, win
 if $radio_state then $viewemiflag(win) =1  else $viewemiflag(win) =0
 endsubr
 ;=============================================================================
subr emidebug, win
 if $radio_state then $viewemidebug(win) =1  else $viewemidebug(win) =0
 endsubr
 ;=============================================================================
subr get_despike_stuff, wtext
 ;3/24/99 - if the target doesn't exist, return default values
 ;8/3/99 - fix bugs, when a bad value encountered, set to default
 $despike_thr = 0.20
 $despike_level = 7
 $despike_niter = 3
 $despike_rms = .002
 $despike_cck = 0.0
 $despike_edge_trim = 1
 $despike_edge_trim_level = 87
 if isarray(wtext) then {
  xq = fix(xmtextfieldgetstring( wtext(1))) * 0.01
  if xq lt .01 or xq gt 2.0 then {
	 xmtextfieldsetstring, wtext(1), string(fix($despike_thr*100))
	 errormess,'despike threshold\nout of range'
	 } else $despike_thr = xq

  xq = fix(xmtextfieldgetstring( wtext(2)))
  if xq lt -1 or xq gt 15 then {
	 xmtextfieldsetstring, wtext(2), string($despike_level)
	 errormess,'despike level\nout of range'
	 } else $despike_level = xq

  xq = (fix(xmtextfieldgetstring( wtext(3))))
  if xq lt 0 or xq gt 15 then {
	 xmtextfieldsetstring, wtext(3), string($despike_niter)
	 errormess,'despike niter\nout of range'
	 } else $despike_niter = xq

  $despike_rms = .01*(float(xmtextfieldgetstring( wtext(4))))
  $despike_cck = float(xmtextfieldgetstring( wtext(5)))
  $despike_edge_trim_level = fix(xmtextfieldgetstring( wtext(6)))
 }
 endsubr
 ;=============================================================================
subr viewdespike, win
 ;extended to work with single key input as well as widget button push, this
 ;means the widget may not be defined, cope with it
 sq = '$imagedespiketext'+string(win)
 
 if defined(eval(sq)) then {
 ; if despike widget defined for this window, get the parameters
 change_button_label, $viewdespike_but(win), 'wait', 'red'
 xtloop,2
 get_despike_stuff, eval(sq)
 $despike_edge_trim = xmtogglegetstate(eval('$imagedespiketrim_ck'+string(win)))
 ty,'$despike_edge_trim =', $despike_edge_trim
 } else {
 ;otherwise assign defaults
 $despike_thr = 0.20
 $despike_level = 7
 $despike_niter = 3
 $despike_rms = .002
 $despike_cck = 0.0
 $despike_edge_trim = 1
 $despike_edge_trim_level = 87
 }
 data_str = '$data'+string(win)
 if symdtype(eval(data_str)) ne 1 then {
 	errormess,'despike only\noperates on\nI*2 arrays'  return }
 ;10/17/98 - need to check size of array if a cell rms check is requested
 switch, xq, eval(data_str)
 rms_value = $despike_rms
 nx = dimen(xq,0)
 ny = dimen(xq,1)
 if ($despike_edge_trim) then {
  ;this will destroy a little around the edges
  zq = zero(xq(*,0:1)) + $despike_edge_trim_level
  insert, xq, zq, 0, 0
  insert, xq, zq, 0, ny - 2
  zq = zero(xq(0:1,*)) + $despike_edge_trim_level
  insert, xq, zq, 0, 0
  insert, xq, zq, nx-2, 0
 }
 if $despike_rms ne 0.0 then {
   if (nx%8 or ny%8) then {
     ty,'despike roughness check requires 8x8 cells, not applied here'
     rms_value = 0.0
   }
 }
 if $despike_niter gt 0 then {
 xq = despike(xq, $despike_thr, $despike_level,$despike_niter,0,rms_value)
 }
 ;also apply CCK's style, based on his trace_cleanjpg
 if $despike_cck gt 0 then xq = trace_cleanjpg(xq ,$despike_cck)
 ;can't leave the dark edges so extend out if we trimmed above
 if ($despike_edge_trim) then {
  zq = xq(*,2)
  redim, zq, nx, 1
  insert, xq, zq, 0, 0
  insert, xq, zq, 0, 1
  zq = xq(*,ny-3)
  redim, zq, nx, 1
  insert, xq, zq, 0, ny - 2
  insert, xq, zq, 0, ny - 1
  zq = xq(2,*)
  redim, zq, 1, ny
  insert, xq, zq, 0, 0
  insert, xq, zq, 1, 0
  zq = xq(nx-3,*)
  redim, zq, 1, ny
  insert, xq, zq, nx-2, 0
  insert, xq, zq, nx-1, 0
 }

 switch, xq, eval(data_str)
 xq = 0
 if defined(eval(sq)) then
 	change_button_label, $viewdespike_but(win), 'Despike', 'gray'
 endsubr
 ;=============================================================================
func despike_internal(x)
 if defined($despike_niter) eq 0 or isarray(x) eq 0 then {
 	errormess,'internal\ndespiker error' return, 0}
 if symdtype(x) ne 1 then { errormess,'despike only\noperates on I*2\arrays'
 	return, x }
 rms_value = $despike_rms
 nx = dimen(x,0)
 ny = dimen(x,1)
 if ($despike_edge_trim) then {
  ;this will destroy a little around the edges
  zq = zero(x(*,0:1)) + $despike_edge_trim_level
  insert, x, zq, 0, 0
  insert, x, zq, 0, ny - 2
  zq = zero(x(0:1,*)) + $despike_edge_trim_level
  insert, x, zq, 0, 0
  insert, x, zq, nx-2, 0
  zq = 0
 }
 if $despike_rms ne 0.0 then {
   if (nx%8 or ny%8) then {
     ty,'despike roughness check requires 8x8 cells, not applied here'
     rms_value = 0.0
   }
 }
 x = despike(x, $despike_thr, $despike_level, $despike_niter, 0, $despike_rms)
 ;also apply CCK's style, based on his trace_cleanjpg
 if $despike_cck gt 0 then x = trace_cleanjpg(x ,$despike_cck)
 ;can't leave the dark edges so extend out if we trimmed above
 if ($despike_edge_trim) then {
  zq = x(*,2)
  redim, zq, nx, 1
  insert, x, zq, 0, 0
  insert, x, zq, 0, 1
  zq = x(*,ny-3)
  redim, zq, nx, 1
  insert, x, zq, 0, ny - 2
  insert, x, zq, 0, ny - 1
  zq = x(2,*)
  redim, zq, 1, ny
  insert, x, zq, 0, 0
  insert, x, zq, 1, 0
  zq = x(nx-3,*)
  redim, zq, 1, ny
  insert, x, zq, nx-2, 0
  insert, x, zq, nx-1, 0
 }
 return, x
 endfunc
 ;=============================================================================
subr viewemi, win
 ;the widget may not be defined, cope with it
 sq = '$imageemiwidget'+string(win)
 
 if defined(eval(sq)) then {
 ; if despike widget defined for this window, get the parameters
 change_button_label, $viewemi_but(win), 'wait', 'red'
 xtloop,2
 ;get parameters here if/when we have some
  } else {
 ;otherwise assign defaults
  ty,'no defaults'
 }
 data_str = '$data'+string(win)
 xq = remove_emi(eval(data_str), win)
 switch, xq, eval(data_str)
 xq = 0
 if defined(eval(sq)) then
 	change_button_label, $viewemi_but(win), 'Reduce EMI', 'gray'
 endsubr
 ;=============================================================================
subr viewdespike_cb, win
 viewdespike, win
 view, win
 endsubr
 ;=============================================================================
subr viewemi_cb, win
 viewemi, win
 view, win
 endsubr
 ;=============================================================================
subr viewstatsupdate, win
 if $radio_state then $viewstatsflag(win) =1  else $viewstatsflag(win) =0
 endsubr
 ;=============================================================================
subr viewstats, win
 ;recompute
 ;first check if the widget exists
 if defined(eval('$imagestatswidget'+string(win))) eq 0 then {
  ;fake a pushing of the menu
  $option_value = 0
  view_option, win
 }
 sq = viewstatstring(win)
 xmsetlabel, eval('$istatslab'+string(win)), sq
 endsubr
 ;===============================================================================
subr getarraystats(x, type, xmax, xmin, xmean, xrms, xskew, xkurt)
 type = symdtype(x)
 array_statistics, x, xmax, xmin, xmean, xrms, xskew, xkurt
 xmean = mean(x)
 xmax = max(x)		xmin = !lastmin
 xrms = sdev(x)
 endsubr
 ;===============================================================================
subr imagemaptraceaec_cb, win
 if win eq $limbwinflag then {
   ;this is an exception that works the limb enhance tool options, here win
   ;is a flag and we have to get the real target win dynamically for $limb_scaletype
   w = getlimbenhancetarget()
   $limb_mapaec(w) = $radio_state
 } else {
   w = win < 15	;all movie windows use 15
   $view_mapaec(w) = $radio_state
 }
 endsubr
 ;===============================================================================
subr imagemap_setrefexp_cb, win
 ;get the exposure from the view if available
 ;currently only for TRACE
 sw = string(win)
 if win eq $limbwinflag then {
   ;this is an exception that works the limb enhance tool options, here win
   ;is a flag and we have to get the real target win dynamically for $view_trace_info_flt_
   ; and $view_trace_info_int_
   w = getlimbenhancetarget()
 } else {
   w = win
 }
 if $view_data_type(w) eq 1 then {
  x = subsc(eval('$view_trace_info_flt_'+string(w)),0)
  xmtextfieldsetstring, subsc(eval('$imaptext'+sw),15), string(x)
  x = subsc(eval('$view_trace_info_int_'+string(w)),7)
  xmtextfieldsetstring, subsc(eval('$imaptext'+sw),19), string(x)
  
 }
 endsubr
 ;===============================================================================
func viewstatstring(win)
 ;compute the stuff
 if defined(eval('$data'+istring(win, 1))) eq 0 then {
  sq = 'no data for this view'
  return, sq
 }
 sq = '$data'+istring(win, 1)
 getarraystats, eval(sq), type, xmax, xmin, xmean, xrms, xskew, xkurt
 ;we do more stuff for I type data than floating point and differently
 types = ['I*1','I*2','I*4','F*4','F*8']
 nx = dimen(eval(sq),0)		ny = dimen(eval(sq),1)
 if type le 2 then {
 sq = sprintf('%s\n%dx%d\n%15.7g\n%d\n%d\n%15.7g\n%15.7g\n%15.7g', types(type),nx, ny,xmean, xmax, xmin, xrms, xskew, xkurt)
 } else {
 sq = sprintf('%s\n%dx%d\n%15.7g\n%15.7g\n%15.7g\n%15.7g\n%15.7g\n%15.7g', types(type),nx,ny,xmean, xmax, xmin, xrms, xskew, xkurt)
 }
 return, sq
 endfunc
 ;===============================================================================
func view_stats_widget(win)
 ;4/15/98 shows some statistics about an image
 sw = string(win)		;a bit indirect
 if defined(eval('$imagestatswidget'+sw)) eq 0 then {
   $win = win
   compile_file, getenv('ANA_WLIB') + '/viewstats_widgettool.ana'
 }
 return, eval('$imagestatswidget'+string(win))
 endfunc
 ;===============================================================================
subr viewmapoptions, fmc, win, wtext, scomm
 fm = xmform(fmc)
 sw = string(win)
 ;setup 5 parameter widgets for the 5 types of scaling plus one for external plus
 ;TRACE options
 xq = intarr(7)
 ;and 22 text widgets contained within them
 wtext = intarr(22)
 j = 0
 ;the first 4 are very similar
 for i=0,3 do {
  board = xmboard(fm, 190, 54)
  if i eq 1 then ix = 62 else ix = 0
  for k=0,2 do {
  iq = xmtextfield(board,'',10,scomm,$f3,'white')
  xmposition,iq, ix, 4, 61, 30
  wtext(j) = iq  j = j + 1  ix = ix + 62
  if i eq 1 then break	;do just one for the auto min/max case
  }
  ncase i
   { xmposition, xmlabel(board,'min',$f4), 13, 35
     xmposition, xmlabel(board,'max',$f4), 75, 35
     xmposition, xmlabel(board,'gamma',$f4), 135, 35  }
   { xmposition, xmlabel(board,'gamma',$f4), 70, 35  }
   { xmposition, xmlabel(board,'hbot',$f4), 13, 35
     xmposition, xmlabel(board,'htop',$f4), 75, 35
     xmposition, xmlabel(board,'gamma',$f4), 135, 35  }
   { xmposition, xmlabel(board,'min',$f4), 13, 35
     xmposition, xmlabel(board,'max',$f4), 75, 35  }
   endcase  
  xq(i) = board
  }
 ;the 5th one has more parameters
  board = xmboard(fm, 190, 120)
  xq(4) = board
  ix = 0
  for k=0,2 do {
  iq = xmtextfield(board,'',10,scomm,$f3,'white')
  xmposition,iq, ix, 4, 61, 30
  wtext(j) = iq  j = j + 1  ix = ix + 62
  }
  ix = 15
  for k=0,1 do {
  iq = xmtextfield(board,'',10,scomm,$f3,'white')
  xmposition,iq, ix, 58, 61, 30
  wtext(j) = iq  j = j + 1  ix = ix + 85
  }
  ;and special labels
  xmposition, xmlabel(board,'min',$f4), 13, 35
  xmposition, xmlabel(board,'kink',$f4), 75, 35
  xmposition, xmlabel(board,'max',$f4), 140, 35
  xmposition, xmlabel(board,'gamma',$f4), 23, 88
  xmposition, xmlabel(board,'% range\nabove kink',$f4), 95, 88

  ;a 6th one for arc tan, this was added after the TRACE options and has out of
  ;sequence members for wtext, 20-21
  board = xmboard(fm, 190, 54)
  xq(5) = board
  ix = 20
  j = 20
  for k=0,1 do {
    iq = xmtextfield(board,'',10,scomm,$f3,'white')
    xmposition,iq, ix, 4, 61, 30
    wtext(j) = iq       j = j + 1  ix = ix + 100
  }
  xmposition, xmlabel(board,'min',$f4), 30, 35
  xmposition, xmlabel(board,'50% ref',$f4), 120, 35

  ;and one for externally scaled views, has no wtext
  board = xmboard(fm, 190, 54)
  xmposition,xmlabel(board,'scaling for this view is\nmanaged elsewhere',$f4),30,10
  xq(6) = board

 ;for the $limbwinflag caes we don't have a target window yet
 if win eq $limbwinflag then dm = 2 else dm = $view_scaletype(win)
 ;manage just one of them at a time
 for i = 0, 6 do {
   if i eq dm then xtmanage, xq(i) else  xtunmanage, xq(i)
   xmattach, xq(i), 0, 1,1,1,1
 }
 ;need a limb exception here
 equate, eval('$imagemaptypeswidget'+sw), xq

 s1 = 'fixed range'
 s2 = 'auto min/max'
 s3 = 'histogram trim'
 s4 = 'log'
 s5 = 'fixed->log'
 s6 = 'arc tan'
 fm2 = xmform(fmc)
 ;need a limb exception here, assume sw is just $limbwinflag
 xq = xmoptionmenu(fm2, 'ftsc_mode_cb,'+sw, $f4, '','mode',s1, s2, s3, s4,s5,s6,dm)
 
 ;add the TRACE options here, these add to the $imaptext list, 15-19
 ft1 = xmform(fmc, 0, 0, 0, 10)
 fq = xmform(ft1)
 b1 = xmbutton(ft1,'TRACE Options','manage_toggle,' +string(fq),$f4)
 formvstack, b1, fq
 s1 = 'use exp. compensation
 ;need a limb exception here
 tq = xmcheckbox(fq,'imagemaptraceaec_cb,'+sw, $f4, '', s1)
 $mvdisplayckb = tq
 xmselectcolor,tq(1),'red'
 xmtogglesetstate, tq(1), 0
 ;;$view_mapaec(#play_window) = 0		;off by default
 ;;instead, zero these in browser setup
 ;;if win eq $limbwinflag then dm = $limb_mapaec(win) else $view_mapaec(win) = 0 ;off by default
 ;;$view_mapaec(win) = 0		;off by default
 fq2 = xmform(fq)
 iq = xmtextfield(fq2,'',10,scomm,$f3,'white')
 xmsize, iq, 61, 30
 wtext(15) = iq
 lq1 = xmlabel(fq2,'ref. exposure:',$f1)
 ;need a limb exception here
 bq = xmbutton(fq2, 'set','imagemap_setrefexp_cb,'+sw, $f4,'gray')
 xmsize, bq, 35, 30
 ;formhstackr, iq, lq1
 formhstackr, bq, iq, lq1
 ;the ref sum
 fq2_2 = xmform(fq)
 iq = xmtextfield(fq2_2,'',1,scomm,$f3,'white')
 xmsize, iq, 30, 30
 wtext(19) = iq
 lq1 = xmlabel(fq2_2,'ref. sum:',$f1)
 formhstackr, iq, lq1
 ;the pedestals
 fq3 = xmform(fq)
 fq4 = xmform(fq)
 fq5 = xmform(fq)
 iq = xmtextfield(fq3,'',10,scomm,$f3,'white')
 xmsize, iq, 61, 30
 wtext(16) = iq
 lq1 = xmlabel(fq3,'pedestal (X1):',$f1)
 formhstackr, iq, lq1
 iq = xmtextfield(fq4,'',10,scomm,$f3,'white')
 xmsize, iq, 61, 30
 wtext(17) = iq
 lq1 = xmlabel(fq4,'pedestal (X2):',$f1)
 formhstackr,iq, lq1
 iq = xmtextfield(fq5,'',10,scomm,$f3,'white')
 xmsize, iq, 61, 30
 wtext(18) = iq
 lq1 = xmlabel(fq5,'noise margin:',$f1)
 formhstackr, iq, lq1
 formvstack, tq(0), fq2, fq2_2, fq3, fq4, fq5
 xtunmanage, fq
 ;end of TRACE options

 formvstack, fm, fm2, ft1 
 ;need a limb exception here
 exchange, xq, eval('$imapoption'+sw)
 return
 endsubr
 ;===============================================================================
func view_map_widget(win)
 ;adjust the way image maps to screen
 ;2/23/2008 - depending on view type
 wtype = 0
 if win ge 20 wtype = 1
 if win ge 24 wtype = 2
 sw = string(win)		;a bit indirect
 ty,'view_map_widget, win =', win
 wname = sprintf('$imagemapwidget%d', win)
 if defined(eval(wname)) eq 0 then {
   if $view_exists(win) eq 0 then {
 	  errormess,'view_map_widget can''t complete\nbecause view does not exist'
	  return, -1 }
  $win = win
  ;2/23/2008 - keep the inline code for wtype ne 2 until we understand the problems
  ;mentioned below but try the compile file approach for wtype = 2

  if wtype eq 2 then {
    compile_file, getenv('ANA_WLIB') + '/viewmapspwidgettool'
  } else {
    ty,'wtype =', wtype
    ;;compile_file, getenv('ANA_WLIB') + '/viewmapwidgettool'
   ;5/4/2002 actually the compile file didn't work for mysterious reasons, still
   ; not worked out
   ;3/4/2001 convert to compile file, re-organize and add a scaling kink
   ;3/20/99 note, a similar widget for movie cubes also exists
   ;7/13/98 call backs in text fields to redraw
   ;3/13/98 modified to be a child of the toplevel view
   ;10/4/96 modified to work with a single view specified by win
   ;some callbacks used - redraw_cb, ftsc_mode_cb,
   p = eval('$viewer'+sw)
   viq = xmdialog_form(p,0,0, 'View '+sw+' Mapping', 5,5,5,5)
   equate, eval('$imagemapwidget'+sw), viq
   wq = xmboard(viq,0,0)
   help_file = $help_path + '/instructions.imagemap'
   whs = '$imagemaphelp'
   wts = '$imagemapwidget'+sw
   sq='widget_help, '+whs+ ','''+ help_file+''''
   bq = xmbutton(wq,'Help', sq, $f4,'gray')
   xmposition,bq, 0, 0, 60, 30
   bq = xmbutton(wq,'Dismiss', 'widget_dismiss, '+wts+','+whs, $f4,'gray')
   xmposition, bq, 70, 0, 64, 30

   scomm = 'redraw_cb,'+sw
   bq = xmbutton(wq, 'Redraw', scomm, $f4, 'gray')
   xmposition, bq, 144, 0, 60, 30
   equate, eval('$view_redraw_button'+sw), bq

   fm = xmform(viq)
   viewmapoptions, fm, win, wtext, scomm

//    ;setup 5 parameter widgets for the 5 types of scaling plus one for external plus
//    ;TRACE options
//    xq = intarr(7)
//    ;and 22 text widgets contained within them
//    wtext = intarr(22)
//    j = 0
//    ;the first 4 are very similar
//    for i=0,3 do {
//     board = xmboard(fm, 190, 54)
//     if i eq 1 then ix = 62 else ix = 0
//     for k=0,2 do {
//     iq = xmtextfield(board,'',10,scomm,$f3,'white')
//     xmposition,iq, ix, 4, 61, 30
//     wtext(j) = iq  j = j + 1  ix = ix + 62
//     if i eq 1 then break	;do just one for the auto min/max case
//     }
//     ncase i
//      { xmposition, xmlabel(board,'min',$f4), 13, 35
//        xmposition, xmlabel(board,'max',$f4), 75, 35
//        xmposition, xmlabel(board,'gamma',$f4), 135, 35  }
//      { xmposition, xmlabel(board,'gamma',$f4), 70, 35  }
//      { xmposition, xmlabel(board,'hbot',$f4), 13, 35
//        xmposition, xmlabel(board,'htop',$f4), 75, 35
//        xmposition, xmlabel(board,'gamma',$f4), 135, 35  }
//      { xmposition, xmlabel(board,'min',$f4), 13, 35
//        xmposition, xmlabel(board,'max',$f4), 75, 35  }
//      endcase  
//     xq(i) = board
//     }
//    ;the 5th one has more parameters
//     board = xmboard(fm, 190, 120)
//     xq(4) = board
//     ix = 0
//     for k=0,2 do {
//     iq = xmtextfield(board,'',10,scomm,$f3,'white')
//     xmposition,iq, ix, 4, 61, 30
//     wtext(j) = iq  j = j + 1  ix = ix + 62
//     }
//     ix = 15
//     for k=0,1 do {
//     iq = xmtextfield(board,'',10,scomm,$f3,'white')
//     xmposition,iq, ix, 58, 61, 30
//     wtext(j) = iq  j = j + 1  ix = ix + 85
//     }
//     ;and special labels
//     xmposition, xmlabel(board,'min',$f4), 13, 35
//     xmposition, xmlabel(board,'kink',$f4), 75, 35
//     xmposition, xmlabel(board,'max',$f4), 140, 35
//     xmposition, xmlabel(board,'gamma',$f4), 23, 88
//     xmposition, xmlabel(board,'% range\nabove kink',$f4), 95, 88
//     
//     ;a 6th one for arc tan, this was added after the TRACE options and has out of
//     ;sequence members for wtext, 20-21
//     board = xmboard(fm, 190, 54)
//     xq(5) = board
//     ix = 20
//     j = 20
//     for k=0,1 do {
//       iq = xmtextfield(board,'',10,scomm,$f3,'white')
//       xmposition,iq, ix, 4, 61, 30
//       wtext(j) = iq       j = j + 1  ix = ix + 100
//     }
//     xmposition, xmlabel(board,'min',$f4), 30, 35
//     xmposition, xmlabel(board,'50% ref',$f4), 120, 35
// 
//     ;and one for externally scaled views, has no wtext
//     board = xmboard(fm, 190, 54)
//     xmposition,xmlabel(board,'scaling for this view is\nmanaged elsewhere',$f4),30,10
//     xq(6) = board
// 
//    ;manage just one of them at a time
//    dm = $view_scaletype(win)
//    for i = 0, 6 do {
//      if i eq dm then xtmanage, xq(i) else  xtunmanage, xq(i)
//      xmattach, xq(i), 0, 1,1,1,1
//    }
//    equate, eval('$imagemaptypeswidget'+sw), xq
// 
//    s1 = 'fixed range'
//    s2 = 'auto min/max'
//    s3 = 'histogram trim'
//    s4 = 'log'
//    s5 = 'fixed->log'
//    s6 = 'arc tan'
//    xq = xmoptionmenu(viq, 'ftsc_mode_cb,'+sw, $f4, '','mode',s1, s2, s3, s4,s5,s6,dm)

   ;add a label for the current scaling at the bottom (reserve lq)
   lq = xmlabel(viq,'current scaling range', $f4)
   sq2 = sprintf('%g to %g', $view_scale_range(0,win), $view_scale_range(1,win))
   $view_label(0,win) = xmlabel(viq,sq2, $f1,'',1)
   xmposition, $view_label(0,win), 0,0, 230, 30

//    ;some TRACE options, these add to the $imaptext list, 15-19
//    ft1 = xmform(viq, 0, 0, 0, 10)
//    fq = xmform(ft1)
//    b1 = xmbutton(ft1,'TRACE Options','manage_toggle,' +string(fq),$f4)
//    formvstack, b1, fq
//    s1 = 'use exp. compensation
//    tq = xmcheckbox(fq,'imagemaptraceaec_cb,'+sw, $f4, '', s1)
//    xmselectcolor,tq(1),'red'
//    xmtogglesetstate, tq(1), 0
//    $view_mapaec(win) = 0		;off by default
//    fq2 = xmform(fq)
//    iq = xmtextfield(fq2,'',10,scomm,$f3,'white')
//    xmsize, iq, 61, 30
//    wtext(15) = iq
//    lq1 = xmlabel(fq2,'ref. exposure:',$f1)
//    bq = xmbutton(fq2, 'set','imagemap_setrefexp_cb,'+sw, $f4,'gray')
//    xmsize, bq, 35, 30
//    formhstackr, bq, iq, lq1
//    ;the ref sum
//    fq2_2 = xmform(fq)
//    iq = xmtextfield(fq2_2,'',1,scomm,$f3,'white')
//    xmsize, iq, 30, 30
//    wtext(19) = iq
//    lq1 = xmlabel(fq2_2,'ref. sum:',$f1)
//    formhstackr, iq, lq1
//    ;the pedestals
//    fq3 = xmform(fq)
//    fq4 = xmform(fq)
//    fq5 = xmform(fq)
//    iq = xmtextfield(fq3,'',10,scomm,$f3,'white')
//    xmsize, iq, 61, 30
//    wtext(16) = iq
//    lq1 = xmlabel(fq3,'pedestal (X1):',$f1)
//    formhstackr, iq, lq1
//    iq = xmtextfield(fq4,'',10,scomm,$f3,'white')
//    xmsize, iq, 61, 30
//    wtext(17) = iq
//    lq1 = xmlabel(fq4,'pedestal (X2):',$f1)
//    formhstackr,iq, lq1
//    iq = xmtextfield(fq5,'',10,scomm,$f3,'white')
//    xmsize, iq, 61, 30
//    wtext(18) = iq
//    lq1 = xmlabel(fq5,'noise margin:',$f1)
//    formhstackr, iq, lq1
//    formvstack, tq(0), fq2, fq2_2,fq3, fq4, fq5
//    xtunmanage, fq
//    ;end of TRACE options
   
   ft2 = xmform(viq, 0, 0, 0, 10)
   fq = xmform(ft2)
   b1 = xmbutton(ft2,'Limb Enhancement','manage_toggle,' +string(fq),$f4)
   formvstack, b1, fq
   s1 = 'enable limb enhance'
   tq = xmcheckbox(fq,'limbenhanceenable_cb,'+sw, $f4, '', s1)
   xmselectcolor,tq(1),'red'
   xmtogglesetstate, tq(1), 0
   s1 = 'pop limb enhance tool'
   bb1 = xmboard(fq)
   bq = labeled_button('limbenhance,'+sw, s1, 5, 0, bb1)
   formvstack, tq(0), bb1
   ;need to save checkbox so we can update from elsewhere
   exchange, tq, eval('$viewlimbenhancewidget'+sw)
   xtunmanage, fq

   ;2/25/2008 - add a sep to clear the Apple widget handle at the bottom
   sep3 = xmseparator(viq, 0, 5, 0)
   xmsize, sep3, 0, 10
   sep1 = xmseparator(viq, 0, 2, 5)
   sep2 = xmseparator(viq, 0, 2, 5)
   xmsize, sep1, 0, 2
   xmsize, sep2, 0, 2

   ;populate the text widgets
   n = num_elem(wtext)
   for i = 0,n-1 do xmtextfieldsetstring, wtext(i), string($default_view_params(i))
   switch, wtext, eval('$imaptext'+sw)
   formvstack, wq, fm, ft2, sep2, lq, $view_label(0,win), sep3
   ;;switch, xq, eval('$imapoption'+sw)
   }
 }
 return, eval(wname)
 endfunc
 ;===============================================================================
func view_range_widget(win)
 ;pops up a widget that shows what part of data is in view and allows user
 ;to specify in text fields when a specific range is required (hard to do
 ;with resize bars!)
 ;3/13/98 modified to be a child of the toplevel view
 sw = string(win)
 if defined(eval('$viewrangewidget'+sw)) eq 0 then {
   $win = win
   compile_file, getenv('ANA_WLIB') + '/viewrange_widgettool.ana'
 }
 return, eval('$viewrangewidget'+sw)
 endfunc
 ;===============================================================================
func view_emi_widget(win)
 ;5/19/2000 - first version
 sw = string(win)
 if defined(eval('$imageemiwidget'+sw)) eq 0 then {
   $win = win
   compile_file, getenv('ANA_WLIB') + '/emi_widgettool.ana'
 }
 return, eval('$imageemiwidget'+sw)
 endfunc
 ;===============================================================================
func view_despike_widget(win)
 ;3/22/99 - there is a similar widget for movie cube creation
 ;5/20/98 - starting with the Mk I despiker, hopefully will be improved
 $win = win
 sw = string(win)
 if defined(eval('$imagedespikewidget'+sw)) eq 0 then {
   compile_file, getenv('ANA_WLIB') + '/despike_widgettool.ana'
 }
 return, eval('$imagedespikewidget'+sw)   	   ; removed spurious
						   ; } LS 11jul2000
 endfunc
 ;===============================================================================
func movie_despike_widget(dum)
 ;5/20/98 - based on view_despike, this is for correcting already made
 ;movie cubes, needs more options
 ;10/28/2007 - I don't think this really works well but modernize the widget
 ;now and fix problems with the rest later
 win = 15	;this wasn't updated from 11 until 10/28/2007
 ;but just use a fixed widget name $mvspikewidget15
 if defined($mvspikewidget15) eq 0 then {
   compile_file, getenv('ANA_WLIB') + '/mvspikewidgettool.ana'
 } else { xtpopup, $mvspikewidget15 }
 return, $mvspikewidget15
 endfunc
 ;===============================================================================
func view_solar_widget(win)
 ;11/18/98 - draw lat/long lines on image, other options to be added
 if defined(eval('$viewsolarwidget'+string(win))) eq 0 then {
   $win = win
   compile_file, getenv('ANA_WLIB') + '/viewsolar_widgettool.ana'
 }
 return, eval('$viewsolarwidget'+string(win))
 endfunc
 ;===============================================================================
func view_clock_widget(win)
 ;5/9/99 - control a clock/date box for the view
 sw = string(win)		;a bit indirect
 if defined(eval('$viewclockwidget'+sw)) eq 0 then {
 p = eval('$viewer'+sw)
 wg = xmdialog_form(p,0,0, 'Clock Box Options for View '+sw, 0, 0, 10, 10)
 equate, eval('$viewclockwidget'+sw), wg
 help_file = $help_path + '/instructions.viewclock'
 topbuttonsetupsanslink, '$viewclockwidget'+sw, '$viewclockhelp',help_file, wg
 
 s1 = 'show time/date'
 iq = xmcheckbox(wg, 'viewclockupdate,'+sw, $f4, '', s1, 1)
 xmselectcolor,iq(1),'red'
 ;bring up with auto update off
 $viewclockflag(win) = 0
 xmtogglesetstate, iq(1), 0
 xmposition, iq(0), 10, 50
 }
 return, eval('$viewclockwidget'+sw)
 endfunc
 ;===============================================================================
subr view_clock_box(win)
 ;make the actual clock box, a separate widget from the control
 s = string(win)
 sq = '$viewclockbox'+ s
 if defined(eval(sq)) eq 0 then {
 p = eval('$viewer'+s)
 wq = xmdialog_form(p, 0,0, sprintf('view %d', win),2,2)
 equate, eval(sq), wq
 wq = xmboard(wq)
 lq = xmlabel(wq,'1998-Apr-02\n01:00:00',$f9)
 xmposition, lq, 2, 2
 xmsetcolors, wq, 'white'
 xmsetcolors, lq, 'white'
 equate, eval('$viewclockboxtext'+s), lq
 }
 xtmanage, eval(sq)
 view_set_time, win
 endsubr
 ;============================================================ 
subr view_set_time(win)
 sq = '$viewclockboxtext'+ string(win)
 t =$view_tai(win)
 if t le 0.0 then s = 'time not\nknown' else {
   s = strtok(date_from_tai(t,0,1),'U') }
 xmsetlabel, eval(sq), s
 xtmanage, eval('$viewclockbox'+ string(win))
 endsubr
 ;============================================================ 
subr write_error, name
 errormess,'problem writing file\n'+name+'\ncheck path and privilege'
 endsubr
 ;============================================================ 
subr zap_view_data, win
 ;zero some view time and position info
 $view_tai(win) = 0
 $view_sun_xc(win) = 0
 $view_sun_yc(win) = 0
 $view_sun_pixel_scale(win) = 0
 endsubr
 ;============================================================ 
subr view_range_update, win
 ;load up the view range widget with the new values
 ;have a view range widget up, have to load it too
 nx = $view_nx(win)
 ny = $view_ny(win)
 ix = $view_ix(win)	iy = $view_iy(win)
 ;are we part of a connected set of views ?
 ;note that we want (ix, iy) as taken from array by tvplane, so the connect
 ;deltas have to be applied
 iq = $view_order(win)
 if $view_connect(win) then {
 	ix = ix + $view_connectx(win)
 	iy = iy + $view_connecty(win)
 }
 ix2 = ix + $view_width(win) -1
 iy2 = iy + $view_height(win) -1
 jq = iq%4
 ;reverse direction of x and y as needed, note that since ix and iy
 ;are coordinates in the array (not in the super view, if any), we use
 ;nx, ny for the reverseals
 if jq lt 2 then { xq=iy	iy = ny-1-iy2	iy2 = ny-1-xq }
 if jq%2 eq 1 then { xq=ix	ix = nx-1-ix2	ix2 = nx-1-xq }
 ;check if a transpose
 if iq ge 4 then { switch, ix, iy	switch, ix2, iy2 }

 sq = sprintf('( %d:%d, %d:%d )', ix, ix2, iy, iy2
 xmsetlabel, eval('$viewlab'+string(win)), sq
 wtext = eval('$viewtext'+string(win))
 xmtextfieldsetstring, wtext(1), string(ix)
 xmtextfieldsetstring, wtext(2), string(iy)
 xmtextfieldsetstring, wtext(3), string(ix2 -ix +1)
 xmtextfieldsetstring, wtext(4), string(iy2 -iy +1)
 endsubr
 ;========================================================
subr viewrescalechoices_cb
 ;used to put a particular "well known" scale into the text box
 xmtextsetstring, $viewrescale_text, string($common_scales($option_value))
 endsubr
 ;============================================================ 
subr viewrescale_cb
 if $radio_state then {
   $viewrescale_flag = $radio_button
   ty,'$viewrescale_flag =', $viewrescale_flag
 }
 ;;widget_dismiss, $viewrescalewidget, $viewrescalehelp
 endsubr
 ;============================================================ 
subr viewrescaledoit_cb
 widget_dismiss, $viewrescalewidget, $viewrescalehelp
 endsubr
 ;============================================================ 
subr view_adjust_scales, scs, in
 if defined($viewrescalewidget) eq 0 then {
   compile_file, getenv('ANA_WLIB') + '/viewrescalewidgettool.ana'
 }
 xmsetlabel, $viewrescale_lab, -
  sprintf('Inconsistent spatial scales for a set of connected\nviews. Range %6.3f to %6.3f. We can:',min(scs),max(scs))
 xmsetmodal, $viewrescalewidget, 1
 xtmanage, $viewrescalewidget
 xmtogglesetstate, $viewrescale_rb(1), 1, 1
 ;;xtpopup, $viewrescalewidget
 ;the modal above prevents any other widgets from working, also have
 ;to stop execution here until user responses to it
 $blocking = 1	;used by dismiss
 xtloop, 1
 ;we get here after a dismiss or do it (it sets !motif = 0)
 !motif = 1
 if $viewrescale_flag then {
  ;we have to do some rescaling, this gets involved
  ;uses the $viewrescale_flag to decide action
  if $viewrescale_flag eq 3 then {
   newsc = float(xmtextfieldgetstring($viewrescale_text))
   }
  if $viewrescale_flag eq 1 then newsc = max(scs)
  if $viewrescale_flag eq 2 then newsc = min(scs)
  if newsc le 0.0 then {
    errormess,sprintf('bad common newsc = %12.3g\nrescaling canceled',newsc)
    $viewrescale_flag = 0
    return
   }
  ;now convert all windows to scale but allow some margin
  nw = num_elem(in) - 1
  ty,'converting, nw =', nw
  for j=0, nw do {
    i = in(j)
    ty,'starting window ', i
    sc = $view_sun_pixel_scale(i)
    if sc le 0 then {
      errormess,sprint('invalid scale (%12.3g)\nfor window %d',sc,i)
    } else {
     xq = sc/newsc	;this is magnification to apply
     ty,'magnification =', xq
     ;see if "close enough"
     if abs(xq - 1.0) gt 0.001 then {
       ;save old data for an undo, similar to code in view_option in toolset6
       data_str = '$data'+string(i)
       save_str = '$save_last'+string(i)
       equate, eval('$save_sc'+string(i)), sc
       zq = mag3( eval(data_str), xq)
       $view_sun_pixel_scale(i) = newsc
       switch, eval(save_str), eval(data_str)
       switch, zq, eval(data_str)
       ;5/10/2002 this invalidates a specialized data type
       $view_data_type(i) = 0
       zq = 0
       ty,'ready to view #', i
       view_part1, i
     }
    }
  }
 }
 ty,'end of view_adjust_scales'
 endsubr
 ;============================================================ 
subr connect_adjust
 ; examine all the deltas and determine window sizes and biased offsets
 ; the offsets are computed for iorder = 0 but then may be modified for
 ; the current orientation
 ;2/10/2001 - try to do something sensible if the scales don't match
 nw = num_elem($view_connect) - 1
 ;check the scales in a preliminary loop
 nc = 0
 xc = 0
 for i=0, nw do {
   ;note, supports only one match or connection set
   if $view_connect(i) and $view_exists(i) then {
     yc = $view_sun_pixel_scale(i)
     if nc then {
       scs = [scs, yc]
       in = [in, i]
     } else {
       scs = yc
       in = i
     }
     nc = nc + 1   
   }
 }

 zero, $view_connectx, $view_connecty
 zeroifundefined, $view_super_nx, $view_super_ny
 zero, $view_super_nx, $view_super_ny
 nw = num_elem(in)-1
 ;possible to get here with no connection at, just return in that case
 ;also possible to have just one
 if nc le 1 then return

 ;now check if the scales are nearly all the same, define no adjustment
 ;as default, any adjustment will affect window properties
 $viewrescale_flag = 0
 ;if any are 0, remove from test because we they won't rescale anyhow
 i = sieve(scs gt 0.0)
 if num_elem(i) gt 1 then {
   xc = scs(i)	;reduced set
   yc = mean(xc)
   if max(abs(xc-yc)) gt 0.01*yc then {
     view_adjust_scales, scs, in
   }
 }
 ;;ty,'mark 1'
 for j=0, nw do {
    i = in(j)
    ;get the extreme ranges for this window
    xc = 0.0
    yc = 0.0
    nx = $view_nx(i)
    ny = $view_ny(i)
    ;the $view_nx and ny are exchanged when the view is a transpose, for
    ;the connectx and y we want the normal situation
    if $view_order(i) ge 4 then { switch, nx, ny }
    nx2 = float(nx-1)*0.5
    ny2 = float(ny-1)*0.5
    sc = $view_sun_pixel_scale(i)
    if sc gt 0 then {
      sc = 1./sc
      xc = $view_sun_xc(i)*sc
      yc = $view_sun_yc(i)*sc
     }
    ;also check for additional offsets, these work in same direction as
    ;solar coordinates (so that the coordinates can be entered as these
    ;offsets when the coords are unknown and therefore set to 0)
    ;note that these are in pixels however
    if $view_offset_widgets(0, i) ne 0 then {
     xc = xc + rfix(float(xmtextfieldgetstring($view_offset_widgets(0, i))))
     yc = yc + rfix(float(xmtextfieldgetstring($view_offset_widgets(1, i))))
    }
    
    x1 = xc - nx2	;floating point
    x2 = xc + nx2
    $view_connectx(i) = rfix(x1)
    y1 = yc - ny2
    y2 = yc + ny2
    ;remember that for display, y runs from top to bottom of screen
    $view_connecty(i) = rfix(y2)
    if j then {
      xleft = xleft < x1
      xright = xright > x2
      ytop = ytop > y2
      ybot = ybot < y1
    } else {
      xleft = x1
      xright = x2
      ybot = y1
      ytop = y2
    }
 }
 ;;ty,'xleft, xright =', xleft, xright
 ;;ty,'ybot, ytop =', ybot, ytop
 ;;ty,'x,y range =', xright - xleft, ytop - ybot
 $view_super_nx = rfix(xright - xleft + 1.0)
 $view_super_ny = rfix(ytop - ybot + 1.0)
 $view_connectx(in) = rfix(xleft - $view_connectx(in))
 $view_connecty(in) = rfix($view_connecty(in) - ytop )
 ;;ty,in, $view_connectx(in), $view_connecty(in)
 ;but, we also make $view_connectx and y dependent on the orientation, this
 ;looks like it simplifies some of the translations made for convertfordata
 ;so, adjust each to the present orientation of its view, these may be
 ;different if the windows were not previously connected

 for j=0, nw do {
  i = in(j)
  ;;t,'j,i =', j,i
  nx = $view_nx(i)
  ny = $view_ny(i)
  reverse_flag = $view_order(i) % 4
  transpose_flag = $view_order(i) / 4
  if transpose_flag then {
  	xq = $view_connectx(i)
  	$view_connectx(i) = $view_connecty(i)
  	$view_connecty(i) = xq
  	nxs = $view_super_ny
  	nys = $view_super_nx
   } else {
  	nxs = $view_super_nx
  	nys = $view_super_ny
   }
  if reverse_flag gt 0 then {
    ncase reverse_flag-1
     {	$view_connectx(i) = nx - nxs - $view_connectx(i)  }
     {	$view_connecty(i) = ny - nys - $view_connecty(i)  }
     {	$view_connectx(i) = nx - nxs - $view_connectx(i)
	$view_connecty(i) = ny - nys - $view_connecty(i)  }
    endcase    
    }
 
 }
 ;and force a display of result
 slave_align, in(0)
 endsubr
 ;=============================================================================
subr viewsetconnect_on, win
   if win gt 14 or win lt 0 then {
      errormess,'not a connectable window'
      return }
   $view_connect(win) = 1 
   connect_adjust
   xmsetcolors, $view_scv(win),'slateblue3'
   xmsetcolors, $view_sch(win),'slateblue3'
 endsubr
 ;=============================================================================
subr viewsetconnect_off, win
   if win gt 14 or win lt 0 then return
   $view_connect(win) =0 
   connect_adjust
   xmsetcolors, $view_scv(win),'skyblue3'
   xmsetcolors, $view_sch(win),'skyblue3'
 endsubr
 ;=============================================================================
subr viewconnectupdate, win
 if $radio_state then {
   viewsetconnect_on, win
 } else {
   viewsetconnect_off, win
 }
 endsubr
 ;=============================================================================
subr zap_connections, win
 nw = num_elem($view_connect)-1
 match = $view_connect(win)	; just one type at present but ...
 for i=0, nw do {
   if $view_connect(i) eq match then {
     $view_connect(i) = 0
     xmsetcolors, $view_scv(i),'skyblue3'
     xmsetcolors, $view_sch(i),'skyblue3'
   }
   xmtogglesetstate, $view_offset_widgets(2,i), 0
 }
 connect_adjust
 endsubr
 ;=============================================================================
subr view_zero_offsets
 ;zero the text in any of the widgets that exist
 nw = num_elem($view_connect)-1
 for i=0, nw do {
  if $view_offset_widgets(0, i) ne 0 then {
   xmtextfieldsetstring, $view_offset_widgets(0, i), ''
   xmtextfieldsetstring, $view_offset_widgets(1, i), ''
  }
 }
 connect_adjust
 endsubr
 ;===============================================================================
func view_connect_widget(win)
 ;12/20/99 - connection options for this view
 sw = string(win)		;a bit indirect
 if defined(eval('$viewconnectwidget'+sw)) eq 0 then {
   $win = win
   compile_file, getenv('ANA_WLIB') + '/viewconnect_widgettool.ana'
 }
 return, eval('$viewconnectwidget'+sw)
 endfunc
 ;============================================================ 
subr slave_align, win
 ;win is the window that the user adjusted, the others must align
 match = $view_connect(win)	; just one type at present but ...
 nw = num_elem($view_connect)-1
 ;get the zoom state, note that more than one might be
 ;set in win at this stage, so do the conversion instead of getstate
 if !tvplanezoom lt 0 then {
  if !tvplanezoom eq -4 then iz = 0 else iz =1
  } else {
  if !tvplanezoom lt 5 then iz = !tvplanezoom + 1 else {
   if !tvplanezoom eq 8 then iz = 6 else iz = 7 } }
 nz = dimen($view_zoom_widgets,0)-1
 vorder = $view_order(win)
 nxs = $view_super_nx
 nys = $view_super_ny
 if vorder ge 4 then { switch, nxs, nys }
 for i=0, nw do {
   isw = string(i)
   if $view_connect(i) eq match then {
     if i ne win then {
     ; may have to resize if not the adjusted window
     ; and set scrollbars
     ; and change the orientation
     this_order = $view_order(i)
     if vorder ne this_order then {
      re_orient, this_order, vorder, i 
      xmsetoptionselection, $view_order_widgets(0,i), -
      	$view_order_widgets(vorder+1,i)
      }
     $view_zoom_fac(i) = !tvplanezoom
     $view_xsize(i) = $view_xsize(win)
     $view_ysize(i) = $view_ysize(win)
     ix = $view_ix(win)
     iy = $view_iy(win)
     $view_ix(i) = ix
     $view_iy(i) = iy
     draw_x = $view_width(win)
     $view_width(i) = draw_x
     draw_y = $view_height(win)
     $view_height(i) = draw_y
     ;because the xmsize will generally call view_resize_cb, we must get
     ;the centers done here
     $view_ixc(i) = $view_ixc(win)
     $view_iyc(i) = $view_iyc(win)
     xmscrollbarsetvalues, $view_sch(i), ix, nxs, draw_x, .5*draw_x
     xmscrollbarsetvalues, $view_scv(i), iy, nys, draw_y, .5*draw_y
     xmsize, $view_draw(i), $view_xsize(i), $view_ysize(i)

     for j = 0, nz do {
      if j eq iz then state = 1 else state = 0
      xmtogglesetstate, $view_zoom_widgets(j,i), state, 0
      }
     }
   if defined(eval('$viewrangewidget'+isw)) eq 1 then view_range_update, i
   ix = $view_ix(i) + $view_connectx(i)
   iy = $view_iy(i) + $view_connecty(i)
   ;;ty,'i, $view_ix, $view_iy, $view_connectx, $view_connecty',i,$view_ix(i), -
   ;;	$view_iy(i), $view_connectx(i), $view_connecty(i)
   ;;ty,'i, ix, iy =', i, ix,iy
   tvplane, eval('$view_data'+isw), 0, ix, iy, i
 } }
 endsubr
 ;============================================================ 
func get_nt(x)
 ;get nt for either a cube or a symarr
 if  issymarr(x) then nt = num_elem(x) else
 	nt=dimen(x,2)
 return, nt
 endfunc
 ;========================================================
subr fviewer_cb, mode
 ;$num_file_viewers is # of existing file viewers
 if mode eq 0 then {
   sw = string($num_file_viewers)
   $num_file_viewers += 1
   sq = '$fs'+sw
   s1 = 'File Reader '+string($num_file_viewers)+' for Selected View'
   iq=xmfileselect(0, s1,'read_file_current','Load','finspect','fscancel,'+sw, -
   	$f3,$f5, '', '', 'Inspectx', 'Dismiss')
   equate, eval(sq), iq
   scanpositions, iq, 'fs'+sw, $bw_ix, $bw_iy
   xmposition, iq, $bw_ix, $bw_iy
   xtloop, 2
   return
  }
 ;otherwise we just pop up all existing ones
 for i=1,$num_file_viewers do {
  widg = eval('$fs'+string(i-1))
  xtmanage, widg
  xtpopup, widg
 }
 endsubr
 ;============================================================ 
