;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)
 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)
 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
 narg=!narg
 xmattach,b1,0,    1,1,1,0
 xmattach,b2,b1,   0,0,1,0
 xmattach,b2,0,    1,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, 1,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
 narg=!narg
 xmattach,b1,0,   1,0,0,0
 xmattach,b2,b1,   1,0,-1,-1
 if narg gt 2 then for k = 3, narg do {
   xmattach,eval('b'+string(k)),eval('b'+string(k-1)), 1,0,-1,-1
 }
 ;if narg gt 2 then xmattach,b3,b2,   1,0,-1,-1
 ;if narg gt 3 then xmattach,b4,b3,   1,0,-1,-1
 ;if narg gt 4 then xmattach,b5,b4,   1,0,-1,-1
 ;if narg gt 5 then xmattach,b6,b5,   1,0,-1,-1
 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
 }
 ;if narg gt 2 then xmattach,b3,b2,    0,1,-1,-1
 ;if narg gt 3 then xmattach,b4,b3,    0,1,-1,-1
 ;if narg gt 4 then xmattach,b5,b4,    0,1,-1,-1
 ;if narg gt 5 then xmattach,b6,b5,    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 { 
  ;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 limits in the data to screen boxes
 ;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)))
 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 switch, x1, x2
 if y1 gt y2 then switch, 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
 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 $view_data_type(win) eq 1 then {
  x = subsc(eval('$view_trace_info_flt_'+sw),0)
  xmtextfieldsetstring, subsc(eval('$imaptext'+sw),15), string(x)
  x = subsc(eval('$view_trace_info_int_'+sw),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
 ;===============================================================================
func view_map_widget(win)
 ;adjust the way image maps to screen
 sw = string(win)		;a bit indirect
 ty,'win =', win
 if defined(eval('$imagemapwidget'+sw)) 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
  ;;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,
 win = $win
 sw = string(win)		;a bit indirect
 p = eval('$viewer'+sw)
 dump, p
 ty,'p = ', p
 viq = xmdialog_form(p,0,0, 'Image Mapping for View '+sw, 5,5,5,5)
 ty,'viq = ', viq
 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)

 ;setup 5 parameter widgets for the 5 types of scaling plus one for external
 xq = intarr(6)
 ;and 13 text widgets contained within them
 wtext = intarr(20)
 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
  ;;if i eq 2 and k eq 1 then break
  }
  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  
  
  ;and one for externally scaled views
  board = xmboard(fm, 190, 54)
  xmposition,xmlabel(board,'scaling for this view is\nmanaged elsewhere',$f4),30,10
  xq(5) = board

 ;manage just one of them
 dm = $view_scaletype(win)
 for i = 0, 5 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'
 xq = xmoptionmenu(viq, 'ftsc_mode_cb,'+sw, $f4, '','mode',s1, s2, s3, s4,s5,dm)

 ;add a label for the current scaling at the bottom
 lq = xmlabel(viq,'current scaling range', $f4)
 sq2 =fstring('%g',$view_scale_range(0,win)) -
 	+ ' to ' + fstring('%g',$view_scale_range(1,win))
 $view_label(0,win) = xmlabel(viq,sq2, $f1,'',1)
 xmposition, $view_label(0,win), 10, 300

 ;some TRACE options
 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
 ;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, xq(0), ft1, lq, $view_label(0,win)
 switch, xq, eval('$imapoption'+sw)
  }
 return, eval('$imagemapwidget'+sw)
 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
 win = 11
 sw = string(win)		;a bit indirect
 if defined(eval('$mvspikewidget'+sw)) eq 0 then {
 viq = xmtoplevel_board(0,0, 'Despike for Movie window '+sw, 10, 10)
 equate, eval('$mvspikewidget'+sw), viq
 help_file = $help_path + '/instructions.mvdespike'
 topbuttonsetupsanslink, '$mvspikewidget'+sw, '$mvspikehelp', help_file
 scb = 'mvdespike_cb'
 bq = xmbutton(viq, 'Despike', scb, $f4, 'gray')
 xmposition, bq, 154, 10, 80, 30
 $mvdespike_but = bq

 iq = xmlabel(viq,'applies despike to current movie cube\nbe careful!', $f5)
 xmposition, iq, 10, 45

 s1 = 'threshold in\n% (0 to 100)'
 s2 = 'level'
 s3 = '# of iterations'
 wtext = xmtextfieldarray(viq,'',$f4,'',100,7,60,35,s1,s2,s3, 3)
 xmposition, wtext(0), 10, 80
 for i=1,num_elem(wtext)-1 do {	xmsetcolors,wtext(i),'white'
	xmfont,wtext(i),$f3
	xmposition,wtext(i),-1,-1,60,35		}
 ;some defaults
 xmtextfieldsetstring, wtext(1),'15'
 xmtextfieldsetstring, wtext(2),'7'
 xmtextfieldsetstring, wtext(3),'3'
 switch, wtext, $mvdespiketext11
 return, viq
 } else { return, eval('$mvdespikewidget'+string(win))   }
 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 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 the viewrescale_cb lets us (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
 ;;ty,'nc =', nc
 ;possible to get here with no connection at, just return in that case
 if nc le 0 then return

 ;also possible to have just one
 if nc le 1 then return
 	;;zero, $view_connectx, $view_connecty
 	;;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
 yc = mean(scs)
 if max(abs(scs-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(win),'skyblue3'
    xmsetcolors, $view_sch(win),'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
   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
 ;============================================================ 
