;+
; NAME:
;     EIS_FIT_VIEWER
;
; PURPOSE:
;     Widget-based routine for studying the Gaussian fits produced by
;     EIS_AUTO_FIT.PRO.
;
;     The top 3 graphics windows show the line intensity, line shift and
;     line width, respectively, from the Gaussian fits stored in FITDATA.
;
;     You will notice the buttons in the top left that give the choice of
;     'Zoom' or 'Pixel'. With Zoom selected, you can click-and-drag on any
;     of the three upper windows to draw a rubberband box that will
;     highlight an area in the images. Letting go of the mouse button
;     will then zoom in on the selected area.
;
;     With 'Pixel' selected you can click with the left mouse button at any
;     point in any of the three images. The line profile from the selected
;     image pixel will then be plotted in the bottom left graphics window,
;     together with the fit to the emission line (drawn as a thick line).
;
;     The three text boxes to the left of the line profile window give:
;       Int  - Line intensity, erg cm^-2 s^-1 sr^-1
;       Vel  - Velocity shift, km/s  (negative=blueshift, postive=redshift)
;       Wid  - Line width (FWHM), milli-Angstroms
;
;     The bottom right plot shows the distribution of either intensity,
;     velocity or line width (use buttons to select) for the plotted image.
;
; CATEGORY:
;     Hinode/EIS; display.
;
; INPUTS:
;     Windata:  Output from eis_getwindata.pro.
;     Fitdata:  Output from eis_auto_fit.pro.
;
; OPTIONAL INPUTS
;    Mask:     A 2D array of same size as the FITDATA line parameter
;              arrays that is used to specify a pixel mask. Pixels for
;              which MASK=0 will be flagged as missing data and so
;              will not be displayed in the output image.
;    Units:    A 2-element string array specifying units for WINDATA
;              and FITDATA. If using standard EIS processing, then
;              this is not necessary. It is intended for other types
;              of data (e.g., IRIS) that use different units.
;    Calib:    An integer specifying the EIS calibration to be applied
;              to the data. If not specified, then a value of 0 is
;              assumed, corresponding to the pre-launch laboratory
;              calibration. 1 corresponds to the Del Zanna (2013)
;              calibration, and 3 to the Warren et al. (2014)
;              calibration. See the header for EIS_GET_FITDATA for
;              more details.
;
; INTERNAL ROUTINES:
;     FV_GET_ARRAY, FV_FONT, FV_PROFILE, FV_DRAWBOX, 
;     FV_PLOT_HISTOGRAM, FV_PLOT_EXPOSURE, EIS_FV_WIDGET,
;     FV_BASE_EVENT, EFV_CONVERT_TO_PIX, EFV_CONVERT_TO_ASEC
;
; CALLS:
;     PLOT_EIS_FITS, EIS_GET_FITDATA
;
; PROGRAMMING NOTES:
;
;     Spatial scale: pixels or arcsec
;     -------------------------------
;     The tag fitdata.scale gives the scales (in arcsec) for each
;     pixel in the images. The heliocentric coordinates of the raster
;     are stored in fitdata.xcen and fitdata.ycen. I have introduced
;     the internal routines efv_convert_to_pix and efv_convert_to_asec
;     to convert between pixels and arcsec, and vice versa. When the
;     zoom or pixel options are used to zoom in or select a pixel for
;     an arcsec image, I convert the selected region/pixel to pixel
;     coordinates, and then back again to arcsec. This ensures that no
;     fractional pixels will be displayed in the images, and also
;     helps check that no "out-of-bound" locations are selected. 
;
; MODIFICATION HISTORY:
;     Version 1, 2-Feb-2010, Peter Young
;       adapted from code from the original eis_fit_viewer
;     Version 2, 9-Feb-2010, Peter Young
;       now prints line fit parameters to profile plot (rather than
;       text boxes); reduced font size for small screens; removed text
;       widgets for fit parameters; added Hardcopy button for creating
;       a postscript file.
;     Version 3, 15-Apr-2010, Peter Young
;       corrected compile problem for fv_get_array; fixed error when
;       all spectrum is missing; check on 'no fit' pixels has been
;       modified; velocity plot limits widget has been changed;
;       histogram plot limits now reflect values for displayed
;       images.
;     Version 4, 28-Apr-2010, Peter Young
;       now uses eis_get_fitdata to retrieve data arrays; corrected
;       bug with scaling of velocity image
;     Version 5, 6-May-2010, Peter Young
;       fixed bug related to previous change - width array now
;       converted to mAng
;     Version 6, 23-Sep-2010, Peter Young
;       spectrum display has been adjusted to work better for full CCD
;       spectra.
;     Version, 7, 6-Apr-2011, Peter Young
;       following changes to eis_get_fitdata, the code has been
;       modified to prevent the line width from being corrected for
;       the instrumental width.
;     Version 8, 14-Apr-2011, Peter Young
;       the postscript file is now printed in color; the intensity
;       image is now automatically scaled using sigrange to prevent
;       anomalously pixels messing up display.
;     Version 9, 25-Apr-2011, Peter Young
;       added check to make sure windata and fitdata are compatible
;       with each other.
;     Version 10, 5-May-2011, Peter Young
;       modified the check on the windata and fitdata inputs to ensure
;       they have the same y-binning and that their wavelength are
;       compatible.
;     Version 11, 11-May-2011, Peter Young
;       introduced a widget for specifying the X and Y scales (either
;       arcsec or pixels). See programming note above for details of
;       how this is implemented. Also changed how the intensity,
;       velocity and width images are scaled.
;     Version 12, 3-Apr-2012, Peter Young
;       added a help button
;     Version 13, 14-Aug-2012, Peter Young
;       added the optional input MASK=
;     Version 14, 6-Feb-2013, Peter Young
;       added time to the title of the line profile plot.
;     Version 15, 7-Nov-2013, Peter Young
;       now checks for IRIS data (slit_ind=4)
;     Version 16, 18-Aug-2014, Peter Young
;       fixed bug when displaying CDS data (but still doesn't
;       work properly). 
;     Version 17, 23-Sep-2014, Peter Young
;       added extra plot window for chi^2; also narrowed the windows
;       in X-direction.
;     Version 18, 24-Sep-2014, Peter Young
;       fixed min-max issue for chi^2 plot; added log option for
;       intensity. 
;     Version 19, 2-Mar-2015, Peter Young
;       now works for data-sets with only 1 element in the
;       X-direction.
;     Version 20, 22-May-2018, Peter Young
;       added UNITS= optional input (intended for IRIS use).
;     Version 21, 10-Feb-2020, Peter Young
;       added CALIB= optional input.
;     Version 22, 26-Mar-2020, Peter Young
;       added check on the X-scale of windata and fitdata.
;     Version 23, 05-Nov-2024, Peter Young
;       now uses fitdata.function for creating the fit function rather
;       than assume a Gaussian.
;-

FUNCTION efv_convert_to_asec, state, value, yval=yval

scale=state.wid_data.scale
xrange_pix=state.wid_data.xrange_pix
yrange_pix=state.wid_data.yrange_pix
origin=state.wid_data.origin

IF keyword_set(yval) THEN BEGIN
  scale_val=scale[1]
  orig_val=origin[1]
ENDIF ELSE BEGIN
  scale_val=scale[0]
  orig_val=origin[0]
ENDELSE 

asecval=round(value)*scale_val + orig_val

return,asecval

END

;--------------------------
FUNCTION efv_convert_to_pix, state, value, yval=yval

scale=state.wid_data.scale
xrange_pix=state.wid_data.xrange_pix
yrange_pix=state.wid_data.yrange_pix
origin=state.wid_data.origin

IF keyword_set(yval) THEN BEGIN
  scale_val=scale[1]
  orig_val=origin[1]
ENDIF ELSE BEGIN
  scale_val=scale[0]
  orig_val=origin[0]
ENDELSE 

pixval=round( (value-orig_val)/scale_val )

return,pixval

END


;--------------------
FUNCTION fv_get_array, state, int=int, vel=vel, wid=wid, chi=chi, $
                       xpix=xpix, ypix=ypix, cen=cen
;
; Extracts parameter arrays (intensity, velocity, width, chi^2) out of
; state
;
fitdata=state.fitdata
line=state.wid_data.line
xr=state.wid_data.xrange_pix
yr=state.wid_data.yrange_pix
refwvl=fitdata.refwvl[line]

IF keyword_set(chi) THEN arr=eis_get_fitdata(fitdata,line=line,/chi,/quiet)
IF keyword_set(int) THEN arr=eis_get_fitdata(fitdata,line=line,/int,/quiet, $
                                             calib=state.wid_data.calib)
IF keyword_set(cen) THEN arr=eis_get_fitdata(fitdata,line=line,/cen,/quiet)
IF keyword_set(vel) THEN arr=eis_get_fitdata(fitdata,line=line,/vel,/quiet)
IF keyword_set(wid) THEN BEGIN
  arr=eis_get_fitdata(fitdata,line=line,/wid,/quiet,keep_inst_width=1)
  k=where(arr EQ fitdata.missing,nk)
  arr=arr*1000.   ; convert to milli-angstroms
  IF nk NE 0 THEN arr[k]=fitdata.missing
ENDIF 

arr=arr[xr[0]:xr[1],yr[0]:yr[1]]

IF n_elements(xpix) NE 0 AND n_elements(ypix) NE 0 THEN BEGIN
  arr=reform(arr[xpix-xr[0],ypix-yr[0]])
ENDIF

return,arr

END


;---------------------
PRO fv_make_ps, state
;
; Creates a postscript file showing line profile
;
!p.font=0
dname=!d.name
set_plot,'ps'
device,file='idl.ps',/isolatin1,xsiz=6,ysiz=5,/inches, $
       yoff=5,xoff=1.25,/color
;
fv_profile,state,/ps
x=state.wid_data.xpix
y=state.wid_data.ypix
int=fv_get_array(state,int=1,xpix=x,ypix=y)
vel=fv_get_array(state,vel=1,xpix=x,ypix=y)
cen=fv_get_array(state,cen=1,xpix=x,ypix=y)
wid=fv_get_array(state,wid=1,xpix=x,ypix=y)
chi=fv_get_array(state,chi=1,xpix=x,ypix=y)
xr=!x.crange
yr=!y.crange
xpos=0.95*xr[0]+0.05*xr[1]
dy=0.05*(yr[1]-yr[0])
y0=-0.3*(yr[1]-yr[0])
xyouts,xpos,y0,'Pixel:  X='+trim(x)+'  Y='+trim(y)
xyouts,xpos,y0-dy,'Intensity: '+trim(string(format='(f10.1)',int))+state.wid_data.int_units
xyouts,xpos,y0-2*dy,'Centroid: '+trim(string(format='(f10.3)',cen))+' '+string(197b)
xyouts,xpos,y0-3*dy,'FWHM: '+trim(string(format='(f10.1)',wid))+' m'+string(197b)
xyouts,xpos,y0-4*dy,'Velocity: '+trim(string(format='(f10.1)',vel))+' km s!u-1!n'
xyouts,xpos,y0-5*dy,'Reduced Chi!u2!n: '+trim(string(format='(f10.1)',chi))
xyouts,xpos,y0-7*dy,'Output produced by EIS_FIT_VIEWER.PRO, '+systime()+'.'
;
device,/close
set_plot,dname
!p.font=-1
result=dialog_message('Line profile plot sent to the file idl.ps in current working directory.',/info)
END



;------------------
PRO fv_font, font, big=big, fixed=fixed, plot_scale=plot_scale
;+
;  Defines the fonts to be used in the widgets. Allows for Windows and Unix 
;  operating systems.
;-
IF n_elements(plot_scale) EQ 0 THEN plot_scale=1.0
CASE !version.os_family OF

  'unix': BEGIN
    IF keyword_set(fixed) THEN fstr='-*-courier-' ELSE $
         fstr='-adobe-helvetica-'
    IF plot_scale LT 1.2 THEN BEGIN
      IF keyword_set(big) THEN str='14' ELSE str='10'
    ENDIF ELSE BEGIN
      IF keyword_set(big) THEN str='18' ELSE str='12'
    ENDELSE 
    font=fstr+'bold-r-*-*-'+str+'-*'
  END

  ELSE: BEGIN
    IF keyword_set(fixed) THEN fstr='Courier' ELSE $
         fstr='Arial'
    IF plot_scale LT 1.2 THEN BEGIN
      IF keyword_set(big) THEN str='16' ELSE str='12'
    ENDIF ELSE BEGIN
      IF keyword_set(big) THEN str='20' ELSE str='16'
    ENDELSE 
    font=fstr+'*bold*'+str
  END

ENDCASE

END



;----------------
PRO fv_profile, state, wid, event=event, ps=ps
;
; Plots the line profile in the bottom-left window for the user-selected 
; pixel.
;
;  EVENT   If fv_profile is called after a new spatial pixel has been
;          selected with the mouse, then EVENT is used to convert the chosen
;          mouse position into a pixel position in the image array and update
;          the WID_DATA.XPIX and WID_DATA.YPIX values.
;

wid_data=state.wid_data
line=wid_data.line
fitdata=state.fitdata
xr=fitdata.xrange
yr=fitdata.yrange
bad_pix=fitdata.bad_pix
iexp_prp=fitdata.iexp_prp

windata=state.windata
lambda=windata.wvl
IF iexp_prp EQ -1 THEN BEGIN 
  int_arr=windata.int[*,xr[0]:xr[1],yr[0]:yr[1]]
  err_arr=windata.err[*,xr[0]:xr[1],yr[0]:yr[1]]
ENDIF ELSE BEGIN
  int_arr=windata.int[*,xr[0]:xr[1],yr[0]:yr[1],iexp_prp]
  err_arr=windata.err[*,xr[0]:xr[1],yr[0]:yr[1],iexp_prp]
ENDELSE 
missing=state.windata.missing
nl=state.windata.nl

;
; Get time of mid-point of exposure
;
t_tai=anytim2tai(windata.time_ccsds)
t_tai=t_tai+windata.exposure_time/2.
t_ccsds=anytim2utc(t_tai,/ccsds)


missing2=-1e5

i=where(err_arr EQ missing,ni)
IF ni NE 0 THEN int_arr[i]=missing2


tst_prof=state.wid_data.tst_prof


IF NOT keyword_set(ps) THEN BEGIN
  wset,wid
  fv_plot_exposure,state
ENDIF

IF n_tags(event) EQ 0 THEN BEGIN
  x=state.wid_data.xpix
  y=state.wid_data.ypix
ENDIF ELSE BEGIN
  x=event.x
  y=event.y
  result=convert_coord(x,y,/device,/to_data)
  x=result[0]
  y=result[1]
  IF x LT !x.crange[0] OR x GT !x.crange[1] OR y LT !y.crange[0] OR y GT !y.crange[1] OR event.release NE 1 THEN BEGIN
    return
  ENDIF ELSE BEGIN
    IF state.wid_data.pix_asec EQ 0 THEN BEGIN
      x=efv_convert_to_pix(state,x)
      IF x LT 0 OR x GT fitdata.nx-1 THEN return
      state.wid_data.xpix=x
     ;
      y=efv_convert_to_pix(state,y,/yval)
      IF y LT 0 OR y GT fitdata.ny-1 THEN return
      state.wid_data.ypix=y
    ENDIF ELSE BEGIN
      x=round(x)
      IF x LT 0 OR x GT fitdata.nx-1 THEN return
      y=round(y)
      IF y LT 0 OR y GT fitdata.ny-1 THEN return
      state.wid_data.xpix=x
      state.wid_data.ypix=y
    ENDELSE 
    widget_control,state.fv_base,set_uvalue=state
  ENDELSE
ENDELSE

int=fv_get_array(state,/int,xpix=x,ypix=y)
vel=fv_get_array(state,/vel,xpix=x,ypix=y)
wid=fv_get_array(state,/wid,xpix=x,ypix=y)
chi=fv_get_array(state,/chi,xpix=x,ypix=y)

lambda=lambda-state.fitdata.offset[x,y]

aa=fitdata.aa[*,x,y]
ngauss=fitdata.ngauss
nback=fitdata.nback

bad_pix=reform(bad_pix[x,y])

IF bad_pix GT 0 AND bad_pix LE 3 THEN nofit=1 ELSE nofit=0

;IF total(aa) EQ 0. THEN nofit=1 ELSE nofit=0

IF nofit EQ 0 THEN BEGIN
  background=fltarr(n_elements(lambda))
  IF nback EQ 1 THEN BEGIN
    background=background+aa[ngauss*3]
  ENDIF ELSE BEGIN
    x1=fitdata.x_bg1[x,y]
    x2=fitdata.x_bg2[x,y]
    y1=aa[ngauss*3]
    y2=aa[ngauss*3+1]
    cc=linfit([x1,x2],[y1,y2])
    background=cc[0]+lambda*cc[1]
  ENDELSE

;
; Generate complete fit function
;
  full_fit_fn=fltarr(n_elements(lambda))
  IF tag_exist(fitdata,'function_name') EQ 0 THEN BEGIN
    func='gauss_sg'
  ENDIF ELSE BEGIN 
    func=fitdata.FUNCTION_name
  ENDELSE
 ;
  FOR i=0,ngauss-1 DO BEGIN
    p=aa[i*3:i*3+2]
    full_fit_fn=full_fit_fn+call_FUNCTION(func,lambda,p[0:2])
;    full_fit_fn=full_fit_fn+p[0]*exp(-(lambda-p[1])^2/2./p[2]^2)
  ENDFOR
  full_fit_fn=full_fit_fn+background

;
; Generate single Gaussian function
;
  line_fn=fltarr(n_elements(lambda))
  p=aa[line*3:line*3+2]
  line_fn=line_fn+call_FUNCTION(func,lambda,p[0:2])
;  line_fn=line_fn+p[0]*exp(-(lambda-p[1])^2/2./p[2]^2)
  line_fn=line_fn+background
ENDIF ELSE BEGIN
  line_fn=fltarr(n_elements(lambda))
  full_fit_fn=fltarr(n_elements(lambda))
  background=fltarr(n_elements(lambda))
ENDELSE 

IF NOT keyword_set(ps) THEN wset,state.wid_data.prof_id



; get offset of wavelength scale
IF tag_exist(state.fitdata,'offset') THEN offset=state.fitdata.offset[x,y]

prof=int_arr[*,x,y]
err=err_arr[*,x,y]
t_obs=anytim2utc(t_ccsds[x],/ccsds,/trunc,/time)
lamb=lambda

;
; Set colour table for profile plot
;   250 - yellow
;   100 - blue
redvec=indgen(256)
bluvec=indgen(256)
grevec=indgen(256)
;
bluvec[250]=0
grevec[250]=255
redvec[250]=255
;
bluvec[100]=255
grevec[100]=100
redvec[100]=100
;
tvlct,redvec,grevec,bluvec


;
; The following creates the X-range (wavelength) for the profile plot,
; based on what the user has selected for 'xra_style'.
;
xra_style=state.wid_data.xra_style
CASE xra_style OF
  0: xrange=[min(lamb),max(lamb)]
  1: BEGIN
    wvl_select=fitdata.wvl_select
    i=where(fitdata.wvl_select.min NE 0.)
    xrange=[min(wvl_select.min[i]),max(wvl_select.max[i])]
  END 
  2: BEGIN
    cen=aa[line*3+1]
    IF cen NE 0. THEN xrange=[cen-0.25,cen+0.25] ELSE xrange=[min(lamb),max(lamb)]
  END 
ENDCASE 

;
; Only plot points greater than zero to prevent missing data appearing.
;
i=where(lambda GE xrange[0] AND lambda LE xrange[1] AND prof NE missing2,ni)
IF ni EQ 0 THEN BEGIN
  yrange=[-110,10]
ENDIF ELSE BEGIN
  CASE wid_data.ymax OF
    0: yrange=[min(prof[i]),max(full_fit_fn)*1.15]
    1: yrange=[min(prof[i]),max(line_fn)*1.15]
    2: yrange=[min(prof[i]),max(prof[i])*1.15]
  ENDCASE
ENDELSE 


IF keyword_set(ps) THEN BEGIN
  th1=3
  th2=5
ENDIF ELSE BEGIN
  th1=1
  th2=2
ENDELSE 

plot,lamb,prof,psym=10,/xsty, $
     tit='Line profile, pixel ('+trim(x)+','+trim(y)+'), t='+trim(t_obs), $
     xtit='Wavelength / '+string(197b), $
     ytit='Intensity / '+wid_data.spec_int_units, $
     yrange=yrange,ysty=3, xrange=xrange, $
     xth=th1,yth=th1,th=th1

IF nofit EQ 0 THEN BEGIN
 ;
 ; Overplot total fit function
 ;
  IF keyword_set(ps) THEN col=100 ELSE col=250
  oplot,lamb,full_fit_fn,th=th2,col=col
 ;
 ; Overplot line profile
 ; 
  oplot,lamb,line_fn,th=th2
ENDIF ELSE BEGIN
  xr=!x.crange
  yr=!y.crange
  xyouts,align=0.5,mean(xr),0.2*yr[0]+0.8*yr[1],'No Fit',charsiz=5.0
ENDELSE


;
; Overplot the error bars
;
IF tst_prof[0] EQ 1 THEN BEGIN
  oploterr,lamb,prof,err,psym=10,th=th1
ENDIF

;
; Print values for various fit parameters on top of plot
;
IF tst_prof[1] EQ 1 THEN BEGIN
  xr=!x.crange
  yr=!y.crange
  xpos=0.05*xr[1]+0.95*xr[0]
 ;
  ypos=0.95*yr[1]+0.05*yr[0]
  text=trim(string(format='(f10.1)',int))
  xyouts,xpos,ypos,'Int: '+text
 ;
  ypos=0.90*yr[1]+0.10*yr[0]
  text=trim(string(format='(f10.1)',vel))
  xyouts,xpos,ypos,'Vel: '+text
 ;
  ypos=0.85*yr[1]+0.15*yr[0]
  text=trim(string(format='(f10.1)',wid))
  xyouts,xpos,ypos,'Wid: '+text
 ;
  ypos=0.80*yr[1]+0.20*yr[0]
  text=trim(string(format='(f10.1)',chi))
  xyouts,xpos,ypos,'Chi2: '+text
ENDIF 


IF NOT keyword_set(ps) THEN fv_plot_exposure,state,point=[x,y]

END


;----------------
PRO fv_drawbox, event, state, wid
;
; This is the event handler that deals with the Zoom option for the images.
;
CASE 1 OF
  event.press EQ 1 AND state.box.flag EQ 0: BEGIN
    state.box.flag=1
    state.box.x0=event.x
    state.box.y0=event.y
    state.box.wid=wid
    wset,wid
    fv_plot_exposure,state
    Window, /Pixmap, /Free, XSize=state.box.xsiz, YSize=state.box.ysiz
    state.box.pixid = !D.Window
    Device, Copy=[0, 0, state.box.xsiz, state.box.ysiz, 0, 0, wid]
    wset,wid
    widget_control,state.fv_base,set_uvalue=state
  END

  event.release EQ 1 AND state.box.flag EQ 1: BEGIN
    WDelete, state.box.pixid
    state.box.flag=0
    state.box.x1=event.x
    state.box.y1=event.y
    widget_control,state.fv_base,set_uvalue=state
    result=convert_coord([state.box.x0,state.box.x1], $
                         [state.box.y0,state.box.y1],/device,/to_data)
;    result=fix(result)
    xra=[result[0,0],result[0,1]]
    xra=xra[sort(xra)]
    yra=[result[1,0],result[1,1]]
    yra=yra[sort(yra)]
    IF xra[0] NE xra[1] AND yra[0] NE yra[1] THEN BEGIN
      IF state.wid_data.pix_asec EQ 0 THEN BEGIN
        xr_pix=efv_convert_to_pix(state,xra)
        xr=efv_convert_to_asec(state,xr_pix)
        state.wid_data.xrange=xr
        state.wid_data.xrange_pix=xr_pix
       ;
        yr_pix=efv_convert_to_pix(state,yra,/yval)
        yr=efv_convert_to_asec(state,yr_pix,/yval)
        state.wid_data.yrange=yr
        state.wid_data.yrange_pix=yr_pix
      ENDIF ELSE BEGIN
        xr_pix=fix(xra)
        xr=efv_convert_to_asec(state,xr_pix)
        state.wid_data.xrange=xr
        state.wid_data.xrange_pix=xr_pix
       ;
        yr_pix=fix(yra)
        yr=efv_convert_to_asec(state,yr_pix,/yval)
        state.wid_data.yrange=yr
        state.wid_data.yrange_pix=yr_pix
      ENDELSE 
      widget_control,state.fv_base,set_uvalue=state
    ENDIF
    fv_plot_exposure,state
    fv_plot_histogram,state
  END

  state.box.flag EQ 1: BEGIN
    Device, Copy=[0, 0, state.box.xsiz, state.box.ysiz, 0, 0, state.box.pixid]
    PlotS, [state.box.x0, state.box.x0, event.x, event.x, state.box.x0], $
         [state.box.y0, event.y, event.y, state.box.y0, state.box.y0], $
         /Device
  END
  
  ELSE:
  
ENDCASE

END

;----------------
PRO fv_plot_histogram, state
;
; This draws the histogram plot in the bottom-right graphics window.
;
xra=state.wid_data.xrange_pix
yra=state.wid_data.yrange_pix

miss=state.fitdata.missing

int=fv_get_array(state,/int)
i=where(int NE miss,ni)

CASE state.wid_data.hist_flag OF
  0: BEGIN
    xtit='Intensity / '+state.wid_data.int_units
    y=int[i]
    histmin=state.wid_data.int_min
    histmax=state.wid_data.int_max
  END
  1: BEGIN
    y=fv_get_array(state,/vel)
    y=y[i]
    xtit='Velocity / km s!u-1!n'
    vlim=state.wid_data.vel_max
    histmin=-vlim
    histmax=vlim
  END
  2: BEGIN
    y=fv_get_array(state,/wid)
    y=y[i]
    xtit='FWHM / m'+string(197b)
    histmin=state.wid_data.wid_min
    histmax=state.wid_data.wid_max
  END
  3: BEGIN
    y=fv_get_array(state,/chi)
    y=y[i]
    xtit='Chi!u2!n (reduced)'
    histmin=0.0
    histmax=5.0
  END
ENDCASE


wset,state.wid_data.hist_id

binsize=(histmax-histmin)/50.
miny=float(histmin)
x=findgen(51)*binsize + miny

plot,x,histogram(y,binsize=binsize,min=miny),psym=10,xtit=xtit, $
     ytit='No. of pixels', $
     xticklen=-0.015,yticklen=-0.015, $
     tit='Histogram',/xsty

END


;----------------
PRO fv_plot_exposure, state, reset=reset, point=point

;+
; Plots the intensity, velocity and line width images.
;
;  RESET   Sets the XRANGE and YRANGE of the image plots to their full size.
;  POINT   When Pixel is set, shows location of the selected pixel.
;-

windata=state.windata
fitdata=state.fitdata
wid_data=state.wid_data

nx=fitdata.nx
ny=fitdata.ny

IF keyword_set(reset) THEN BEGIN
  xrange=fitdata.xrange-min(fitdata.xrange)
  yrange=fitdata.yrange-min(fitdata.yrange)
  state.wid_data.xrange_pix=xrange
  state.wid_data.yrange_pix=yrange
  state.wid_data.xrange=efv_convert_to_asec(state,xrange)
  state.wid_data.yrange=efv_convert_to_asec(state,yrange,/yval)
  widget_control,state.fv_base,set_uval=state
ENDIF ELSE BEGIN
  xrange=state.wid_data.xrange_pix
  yrange=state.wid_data.yrange_pix
  IF xrange[0] LT 0 THEN xrange[0]=0
  IF xrange[1] GT nx-1 THEN xrange[1]=nx-1
  IF yrange[0] LT 0 THEN yrange[0]=0
  IF yrange[1] GT ny-1 THEN yrange[1]=ny-1
 ;
  state.wid_data.xrange_pix=xrange
  state.wid_data.yrange_pix=yrange
  state.wid_data.xrange=efv_convert_to_asec(state,xrange)
  state.wid_data.yrange=efv_convert_to_asec(state,yrange,/yval)
 ;
  widget_control,state.fv_base,set_uval=state
ENDELSE


IF state.wid_data.autoint EQ 1 THEN BEGIN
  int=fv_get_array(state,/int)
 ;
  IF state.wid_data.log_int EQ 1 THEN BEGIN
    k=where(int EQ windata.missing,nk)
    i_sort=sort(int[k])
    i_max=min([9,nk-1])
   ;
    intmin=min(int[i_sort[0:i_max]])
    intmax=max(int)
  ENDIF ELSE BEGIN 
    chck=sigrange(int,range=range,missing=windata.missing)
 ;
    intmin=range[0]
    intmax=range[1]
  ENDELSE 
  state.wid_data.int_min=intmin
  state.wid_data.int_max=intmax
  widget_control,state.in_min_text, $
       set_value=trim(string(format='(f10.1)',intmin))
  widget_control,state.in_max_text, $
       set_value=trim(string(format='(f10.1)',intmax))
  widget_control,state.fv_base,set_uvalue=state
  int=0
ENDIF

IF state.wid_data.autovel EQ 1 THEN BEGIN
  vel=fv_get_array(state,/vel)
  k=where(vel EQ windata.missing,nk)
  IF nk NE 0 THEN vel[k]=0
  chck=sigrange(abs(vel),range=range)

  velmax=range[1]
  state.wid_data.vel_max=velmax
  widget_control,state.vel_lim_text, $
       set_value=trim(string(format='(f10.1)',velmax))
  widget_control,state.fv_base,set_uvalue=state
ENDIF

IF state.wid_data.autowid EQ 1 THEN BEGIN
  wid=fv_get_array(state,/wid)
  k=where(wid NE windata.missing,nk)
  chck=sigrange(wid[k],range=range)
  widmin=range[0]
  widmax=range[1]
;;   IF state.windata.hdr.slit_ind EQ 0 THEN BEGIN
;;     widmin=55
;;     widmax=110
;;   ENDIF ELSE BEGIN
;;     widmin=65
;;     widmax=120
;;   ENDELSE 
  state.wid_data.wid_min=widmin
  state.wid_data.wid_max=widmax
  widget_control,state.spike_min_text, $
       set_value=trim(string(format='(f10.1)',widmin))
  widget_control,state.spike_max_text, $
       set_value=trim(string(format='(f10.1)',widmax))
  widget_control,state.fv_base,set_uvalue=state
ENDIF


xtl=-0.02
ytl=-0.02

IF state.wid_data.pix_asec EQ 0 THEN BEGIN
  origin=[state.wid_data.xrange[0],state.wid_data.yrange[0]]
  scale=state.wid_data.scale
 ;
  IF n_elements(point) NE 0 THEN BEGIN 
    pt_x=efv_convert_to_asec(state,point[0])
    pt_y=efv_convert_to_asec(state,point[1],/yval)
  ENDIF
 ;
  xtitle='Solar-X / arcsec'
  ytitle='Solar-Y / arcsec'
ENDIF ELSE BEGIN
  origin=[state.wid_data.xrange_pix[0],state.wid_data.yrange_pix[0]]
  scale=[1,1]
 ;
  IF n_elements(point) NE 0 THEN BEGIN 
    pt_x=point[0]
    pt_y=point[1]
  ENDIF
 ;
  xtitle='X-pixel number'
  ytitle='Y-pixel number'
ENDELSE 

IF state.wid_data.mask_set EQ 1 THEN mask=state.wid_data.mask

wset,state.wid_data.in_id
int_min=state.wid_data.int_min
plot_eis_fits,fitdata,min=int_min, $
              max=state.wid_data.int_max,xrange=xrange, $
              yrange=yrange,title='Intensity',line=wid_data.line, $
              origin=origin,scale=scale,xtitle=xtitle,ytitle=ytitle, $
              mask=mask,log=state.wid_data.log_int
;
; If int_min is negative and log is set, then its value gets changed
; by plot_eis_fits so I have to update the int_min widget.
;
IF int_min NE state.wid_data.int_min THEN BEGIN
  state.wid_data.int_min=int_min
  widget_control,state.in_min_text,set_value=trim(string(format='(f8.1)',int_min))
  widget_control,state.fv_base,set_uvalue=state
  IF state.wid_data.hist_flag EQ 0 THEN fv_plot_histogram,state
ENDIF 
;
IF n_elements(point) NE 0 THEN BEGIN
  plots,pt_x,pt_y,psym=7,symsiz=2.0,col=1
  plots,pt_x,pt_y,psym=1,symsiz=2.0
ENDIF 
;
wset,state.wid_data.out_id
plot_eis_fits,fitdata,/velocity,min=-state.wid_data.vel_max, $
              max=state.wid_data.vel_max,xrange=xrange, $
              yrange=yrange,title='Velocity / km s!u-1!n',line=wid_data.line, $
              origin=origin,scale=scale,xtitle=xtitle,ytitle=ytitle,mask=mask
IF n_elements(point) NE 0 THEN BEGIN
  plots,pt_x,pt_y,psym=7,symsiz=2.0,col=1
  plots,pt_x,pt_y,psym=1,symsiz=2.0
ENDIF 
;
; Note that the width map is not corrected for the instrumental width
wset,state.wid_data.spike_id
plot_eis_fits,fitdata,/width,min=state.wid_data.wid_min/1000., $
              max=state.wid_data.wid_max/1000.,xrange=xrange, $
              yrange=yrange,title='FWHM / m'+string(197b),line=wid_data.line, $
              keep_inst_width=1, $
              origin=origin,scale=scale,xtitle=xtitle,ytitle=ytitle,mask=mask
IF n_elements(point) NE 0 THEN BEGIN
  plots,pt_x,pt_y,psym=7,symsiz=2.0,col=1
  plots,pt_x,pt_y,psym=1,symsiz=2.0
ENDIF 
;
; Chi^2 plot
wset,state.wid_data.chi_id
plot_eis_fits,fitdata,/chisq,min=state.wid_data.chi_min, $
              max=state.wid_data.chi_max,xrange=xrange, $
              yrange=yrange,title='Reduced chi!u2!n', $
              origin=origin,scale=scale,xtitle=xtitle,ytitle=ytitle,mask=mask
IF n_elements(point) NE 0 THEN BEGIN
  plots,pt_x,pt_y,psym=7,symsiz=2.0,col=1
  plots,pt_x,pt_y,psym=1,symsiz=2.0
ENDIF 

END


;------------------
PRO fv_base_event, event
;
;  Event handler for EIS_FIT_VIEWER
;

WIDGET_CONTROL,Event.top, get_uvalue=state


CASE event.id OF

  state.zoom_pix: BEGIN
   ;
   ; Toggles between whether the mouse is used for zooming or selecting
   ; pixels.
   ;
    widget_control,state.zoom_pix,get_val=val
    state.wid_data.zm_pix=val
    widget_control,state.fv_base,set_uval=state
    IF val EQ 1 THEN BEGIN
      widget_control,state.in_plot,draw_motion_events=0
      widget_control,state.out_plot,draw_motion_events=0
      widget_control,state.spike_plot,draw_motion_events=0
    ENDIF ELSE BEGIN
      widget_control,state.in_plot,draw_motion_events=1
      widget_control,state.out_plot,draw_motion_events=1
      widget_control,state.spike_plot,draw_motion_events=1
    ENDELSE
  END

  state.pix_asec: BEGIN
   ;
   ; Toggles between whether the image scales are in arcsec or pixels.
   ;
    widget_control,state.pix_asec,get_val=val
    state.wid_data.pix_asec=val
    widget_control,state.fv_base,set_uval=state
    fv_plot_exposure, state
    IF state.wid_data.xpix NE -1 THEN fv_profile, state, state.wid_data.in_id
  END

  state.in_plot: BEGIN
    IF state.wid_data.zm_pix EQ 0 THEN BEGIN
      fv_drawbox, event, state, state.wid_data.in_id
    ENDIF ELSE BEGIN
      IF event.release EQ 1 THEN BEGIN
        fv_profile, state, state.wid_data.in_id, event=event
        IF state.wid_data.xpix GE 0 THEN widget_control,state.prof_butts_base,sens=1
      ENDIF 
    ENDELSE
  END

  state.out_plot: BEGIN
    IF state.wid_data.zm_pix EQ 0 THEN BEGIN
      fv_drawbox, event, state, state.wid_data.out_id
    ENDIF ELSE BEGIN
      IF event.release EQ 1 THEN BEGIN
        widget_control,state.prof_butts_base,sens=1
        fv_profile, state, state.wid_data.out_id, event=event
      ENDIF 
    ENDELSE
  END

  state.spike_plot: BEGIN
    IF state.wid_data.zm_pix EQ 0 THEN BEGIN
      fv_drawbox, event, state, state.wid_data.spike_id
    ENDIF ELSE BEGIN
      IF event.release EQ 1 THEN BEGIN
        widget_control,state.prof_butts_base,sens=1
        fv_profile, state, state.wid_data.spike_id, event=event
      ENDIF 
    ENDELSE
  END

  state.chi_plot: BEGIN
    IF state.wid_data.zm_pix EQ 0 THEN BEGIN
      fv_drawbox, event, state, state.wid_data.chi_id
    ENDIF ELSE BEGIN
      IF event.release EQ 1 THEN BEGIN
        widget_control,state.prof_butts_base,sens=1
        fv_profile, state, state.wid_data.chi_id, event=event
      ENDIF 
    ENDELSE
  END

  state.unzoom: BEGIN
    fv_plot_exposure,state,/reset
    fv_plot_histogram,state
  END

  state.in_min_text: BEGIN
    widget_control,state.in_min_text,get_value=val
    state.wid_data.int_min=val
    state.wid_data.autoint=0
    widget_control,state.fv_base,set_uvalue=state
    fv_plot_exposure,state
    IF state.wid_data.hist_flag EQ 0 THEN fv_plot_histogram,state
  END

  state.in_max_text: BEGIN
    widget_control,state.in_max_text,get_value=val
    state.wid_data.int_max=val
    state.wid_data.autoint=0
    widget_control,state.fv_base,set_uvalue=state
    fv_plot_exposure,state
    IF state.wid_data.hist_flag EQ 0 THEN fv_plot_histogram,state
  END

  state.vel_lim_text: BEGIN
    widget_control,state.vel_lim_text,get_value=val
    state.wid_data.vel_max=val
    state.wid_data.autovel=0
    widget_control,state.fv_base,set_uvalue=state
    fv_plot_exposure,state
    IF state.wid_data.hist_flag EQ 1 THEN fv_plot_histogram,state
  END

  state.spike_min_text: BEGIN
    widget_control,state.spike_min_text,get_value=val
    state.wid_data.wid_min=val
    state.wid_data.autowid=0
    widget_control,state.fv_base,set_uvalue=state
    fv_plot_exposure,state
    IF state.wid_data.hist_flag EQ 2 THEN fv_plot_histogram,state
  END

  state.spike_max_text: BEGIN
    widget_control,state.spike_max_text,get_value=val
    state.wid_data.wid_max=val
    state.wid_data.autowid=0
    widget_control,state.fv_base,set_uvalue=state
    fv_plot_exposure,state
    IF state.wid_data.hist_flag EQ 2 THEN fv_plot_histogram,state
  END

  state.chi_min_text: BEGIN
    widget_control,state.chi_min_text,get_value=val
    state.wid_data.chi_min=val
    widget_control,state.fv_base,set_uvalue=state
    fv_plot_exposure,state
    IF state.wid_data.hist_flag EQ 2 THEN fv_plot_histogram,state
  END

  state.chi_max_text: BEGIN
    widget_control,state.chi_max_text,get_value=val
    state.wid_data.chi_max=val
    widget_control,state.fv_base,set_uvalue=state
    fv_plot_exposure,state
    IF state.wid_data.hist_flag EQ 2 THEN fv_plot_histogram,state
  END
  state.prof_butts: BEGIN
    widget_control,state.prof_butts,get_value=tst_prof
    state.wid_data.tst_prof=tst_prof
    widget_control,state.fv_base,set_uvalue=state
    fv_profile, state, state.wid_data.out_id
  END

  state.auto_int: BEGIN
    state.wid_data.autoint=1
    widget_control,state.fv_base,set_uvalue=state
    fv_plot_exposure,state
    IF state.wid_data.hist_flag EQ 0 THEN fv_plot_histogram,state
  END

  state.log_int: BEGIN
    widget_control,state.log_int,get_value=val
    state.wid_data.log_int=val[0]
    widget_control,state.fv_base,set_uvalue=state
    fv_plot_exposure,state
    IF state.wid_data.hist_flag EQ 0 THEN fv_plot_histogram,state
  END

  state.auto_vel: BEGIN
    state.wid_data.autovel=1
    widget_control,state.fv_base,set_uvalue=state
    fv_plot_exposure,state
    IF state.wid_data.hist_flag EQ 1 THEN fv_plot_histogram,state
  END

  state.auto_wid: BEGIN
    state.wid_data.autowid=1
    widget_control,state.fv_base,set_uvalue=state
    fv_plot_exposure,state
    IF state.wid_data.hist_flag EQ 2 THEN fv_plot_histogram,state
  END

  state.hist_butts: BEGIN
    widget_control,state.hist_butts,get_value=val
    state.wid_data.hist_flag=val
    widget_control,state.fv_base,set_uvalue=state
    fv_plot_histogram,state
  END

  state.line_list: BEGIN
    widget_control,state.line_list,get_value=val
    state.wid_data.line=val
    state.wid_data.autoint=1
    state.wid_data.autovel=1
    state.wid_data.autowid=1
    widget_control,state.fv_base,set_uvalue=state
    fv_plot_exposure, state
    fv_plot_histogram, state
    IF state.wid_data.xpix GE 0 THEN fv_profile, state, state.wid_data.in_id
  END

  state.ymax_butts: BEGIN
    widget_control,state.ymax_butts,get_value=val
    state.wid_data.ymax=val
    widget_control,state.fv_base,set_uvalue=state
    fv_profile, state, state.wid_data.in_id
  END 

  state.xrange_butts: BEGIN
    widget_control,state.xrange_butts,get_value=val
    state.wid_data.xra_style=val
    widget_control,state.fv_base,set_uvalue=state
    fv_profile, state, state.wid_data.in_id
  END 

  state.print_butt: BEGIN
    fv_make_ps,state
  END 

  state.help_butt: BEGIN
    fv_font,font
    str1=['HELP FOR EIS_FIT_VIEWER',$
'',$
'eis_fit_viewer is used to browse the emission line fits produced by',$
'eis_auto_fit. The top three graphics panels show line intensity, line ',$
'velocity and line width, respectively.', $
'', $
'The user can interact with these panels using the left mouse button. If', $
'the mouse function (top-left corner) is set to "Zoom" then ', $
'clicking-and-dragging the mouse button allows the user to zoom in one any', $
'part of the images. If the mouse function is set to "Pixel" then clicking', $
'with the mouse on an image pixel will put the line profile for that pixel', $
'in the bottom-right graphics panel.', $
'', $
'The spatial axes for the image plots can be shown in arcsec or pixel units.', $
'In the Y-direction 1 pixel is always 1 arcsec, but in the X-direction 1 pixel', $
'can be more than 1 arcsec, e.g., if the 2" slit has been used, or if the step', $
'size between raster positions is more than 1".', $
'', $
'Under each image panel there are text boxes that allow the image scaling to', $
'be adjusted manually. Clicking on "Auto" returns the image scaling to the ', $
'original values.', $
'',$
'UNITS',$
'',$
'The units for the line parameters are:', $
'', $
'   Intensity - erg / cm^2 / s / sr', $
'   Velocity  - km / s  (redshift is +ve, blueshift is -ve)', $
'   Width     - milli-angstroms', $
'', $
'Note that the width is the full width at half-maximum (FWHM) and is not', $
'corrected for the instrumental width or the thermal width.', $
'', $
'"chi^2" is the reduced chi^2 value.', $
'']

    xpopup,str1,tfont=font,bfont=font,xsiz=70,ysiz=30, $
           title='HELP file for eis_fit_viewer'

  END 

  state.exit: widget_control, event.top, /destroy

ENDCASE

END


;----------------------------------------
PRO eis_fv_widget, windata, fitdata, group=group, mask=mask, units=units, calib=calib


IF n_elements(units) NE 2 THEN BEGIN
  units=['erg cm!u-2!n s!u-1!n sr!u-1!n '+string(197b)+'!u-1!n', $
         'erg cm!u-2!n s!u-1!n sr!u-1!n' ]
ENDIF 

;
; By default the routine assumes the original laboratory calibration
; for EIS.
;
IF n_elements(calib) EQ 0 THEN calib=0

;
; Older versions of fitdata do not have the scale tag, but I can get
; this from windata instead.
;
IF tag_exist(fitdata,'scale') THEN BEGIN
  scale=fitdata.scale
ENDIF ELSE BEGIN
  scale=windata.scale
ENDELSE 

;
; Older versions of fitdata do not have the xcen, ycen tags. I could
; take the values from windata, but there could be a mis-match if
; eis_bin_windata has been used, or the xrange/yrange keywords have
; been given to eis_auto_fit.
;
IF tag_exist(fitdata,'xcen') THEN BEGIN
  origin=[ fitdata.xcen - fitdata.nx/2.*fitdata.scale[0], $
           fitdata.ycen - fitdata.ny/2.*fitdata.scale[1] ]
ENDIF ELSE BEGIN
  origin=[0., 0.]
ENDELSE 

siz=size(fitdata.int)
xrange_pix=fitdata.xrange-min(fitdata.xrange)
yrange_pix=fitdata.yrange-min(fitdata.yrange)

xrange=xrange_pix*scale[0] + origin[0]
yrange=yrange_pix*scale[1] + origin[1]


;
; Apply scale factors to the plot windows if the screen size is small
;
ss=get_screen_size()
CASE 1 OF 
  ss[0] LT 1024: plot_scale=0.7
  ss[0] GE 1024 AND ss[0] LT 1600: plot_scale=1.0
  ss[0] GE 1600 AND ss[0] LT 1900: plot_scale=1.2
  ss[0] GE 1900: plot_scale=1.5
ENDCASE

fv_font,font, plot_scale=plot_scale
fv_font,bigfont,/big, plot_scale=plot_scale
fv_font,fixfont,/fixed, plot_scale=plot_scale

line=0
int=reform(fitdata.int[line,*,*])

CASE windata.hdr.slit_ind OF
  0: BEGIN 
    wid_min=55
    wid_max=110
  END 

  2: BEGIN 
    wid_min=65
    wid_max=120
  END

  4: BEGIN
    wid_min=75
    wid_max=300
  END 
  ELSE: BEGIN
    wid_min=200
    wid_max=800
  END 
ENDCASE 


;
; Set default min, max for chi^2
;
chi=eis_get_fitdata(fitdata,/chi)
r=sigrange(chi,frac=0.95,range=range,missing=fitdata.missing)
chi_min=range[0]
chi_max=range[1]


IF n_elements(mask) NE 0 THEN BEGIN
  mask_set=1 
ENDIF ELSE BEGIN
  mask_set=0
  mask=0
ENDELSE 

;
; WID_DATA is a structure for storing various pieces of information used in
; controlling the widgets and for setting what is displayed in the plot
; windows.
;
wid_data={in_id: 0, $
          out_id: 0, $
          spike_id: 0, $
          chi_id: 0, $
          prof_id: 0, $
          hist_id: 0, $
          zm_pix: 0, $
          pix_asec: 0, $
          xrange: xrange, $
          yrange: yrange, $
          xrange_pix: xrange_pix, $
          yrange_pix: yrange_pix, $
          int_min: 0., $
          int_max: max(int), $
          chi_min: chi_min, $
          chi_max: chi_max, $
          vel_min: -30, $
          vel_max: 30 ,$
          wid_min: wid_min, $
          wid_max: wid_max, $
          tst_prof: intarr(2), $
          xpix: -1, ypix: -1, $
          autoint: 1, $
          autovel: 1, $
          autowid: 1, $
          hist_flag: 0, $
          line: line, $
          ymax: 0, $
          xra_style: 0, $
          scale: scale, $
          origin: origin, $
          mask_set: mask_set, $
          mask: mask, $
          log_int: 0, $
          calib: calib, $
          spec_int_units: units[0], $
          int_units: units[1] }

fv_base=widget_base(/col,map=1,title='FIT_VIEWER')


img_base=widget_base(fv_base,/row,map=1)


img_butts_base=widget_base(img_base,/col,map=1)

zp_base=widget_base(img_butts_base,/frame,/col)
zp_lbl=widget_label(zp_base,value='Mouse function:',font=font)
zoom_pix=cw_bgroup(zp_base,/exclusive,['Zoom','Pixel'], $
                  set_value=wid_data.zm_pix,/col,font=font)

unzoom=widget_button(img_butts_base,value='UNZOOM',font=font)

pa_base=widget_base(img_butts_base,/frame,/col)
pa_lbl=widget_label(pa_base,value='Spatial axes:',font=font)
pix_asec=cw_bgroup(pa_base,/exclusive,['Arcsec','Pixels'], $
                  set_value=wid_data.pix_asec,/col,font=font)

ngauss=fitdata.ngauss 
IF ngauss GT 1 THEN BEGIN
  line_labels=''
  FOR i=0,ngauss-1 DO BEGIN
    cen=reform(fitdata.aa[i*3+1,*,*])
;    lbl=trim(string(format='(f10.3)',average(cen,missing=0.)))
    lbl=trim(string(format='(f10.3)',fitdata.refwvl[i]))
    line_labels=[line_labels,lbl]
  ENDFOR 
  line_labels=line_labels[1:*]
 ;
  line_list=cw_bgroup(img_butts_base,/exclusive,line_labels, $
                  set_value=wid_data.line,/col,/frame,font=font)
ENDIF ELSE BEGIN 
  line_list=0
ENDELSE


help_butt=widget_button(img_butts_base,value='HELP',font=bigfont)
exit=widget_button(img_butts_base,value='EXIT',font=bigfont)


;
; Set size of plot windows
;
xsiz=fix(250*plot_scale)
ysiz=fix(300*plot_scale)
xsiz2=fix(400*plot_scale)   ; use for profile plot
xsiz3=fix(300*plot_scale)


;
; WIDGETS FOR PLOTTING INTENSITY IMAGE
; -------------------------------------
plot_base1=widget_base(img_base,/row)
in_base=widget_base(plot_base1,/col)
in_plot=widget_draw(in_base,xsiz=xsiz,ysiz=ysiz,/sens, $
                    /motion_events,/button_events)
in_base2=widget_base(in_base,/row)
in_min_lbl=widget_label(in_base2,value='Min:',font=font)
in_min_text=widget_text(in_base2,value=trim(wid_data.int_min), $
                       font=font,xsiz=8,/editable)
in_max_lbl=widget_label(in_base2,value='Max:',font=font)
in_max_text=widget_text(in_base2,$
                        value=trim(string(wid_data.int_max,format='(f8.1)')), $
                        font=font,xsiz=8,/editable)
auto_int=widget_button(in_base2,value='Auto',font=font)
log_int=cw_bgroup(in_base2,['Log'],/nonexclusive,  $
                  set_value=[wid_data.log_int],/row,font=font)

;
; WIDGETS FOR PLOTTING VELOCITY IMAGE
; -------------------------------------
out_base=widget_base(plot_base1,/col)
out_plot=widget_draw(out_base,xsiz=xsiz,ysiz=ysiz,/sens, $
                    /motion_events,/button_events)
out_base2=widget_base(out_base,/row)
vel_lim_lbl=widget_label(out_base2,value='Plot limits (+/-):',font=font)
vel_lim_text=widget_text(out_base2,value=trim(abs(wid_data.vel_max)), $
                       font=font,xsiz=8,/editable)
auto_vel=widget_button(out_base2,value='Auto',font=font)


;
; WIDGETS FOR PLOTTING LINE WIDTH IMAGE
; -------------------------------------
spike_base=widget_base(plot_base1,/col)
spike_plot=widget_draw(spike_base,xsiz=xsiz,ysiz=ysiz,/sens, $
                    /motion_events,/button_events)
spike_base2=widget_base(spike_base,/row)
spike_min_lbl=widget_label(spike_base2,value='Min:',font=font)
spike_min_text=widget_text(spike_base2,value=trim(wid_data.wid_min), $
                       font=font,xsiz=7,/editable)
spike_max_lbl=widget_label(spike_base2,value='Max:',font=font)
spike_max_text=widget_text(spike_base2,value=trim(wid_data.wid_max), $
                       font=font,xsiz=7,/editable)
auto_wid=widget_button(spike_base2,value='Auto',font=font)
;

;
; WIDGETS FOR PLOTTING CHI^2
; --------------------------
chi_base=widget_base(plot_base1,/col)
chi_plot=widget_draw(chi_base,xsiz=xsiz,ysiz=ysiz,/sens, $
                    /motion_events,/button_events)
chi_base2=widget_base(chi_base,/row)
chi_min_lbl=widget_label(chi_base2,value='Min:',font=font)
chi_min_txt=trim(string(format='(f7.1)',wid_data.chi_min))
chi_min_text=widget_text(chi_base2,value=chi_min_txt, $
                       font=font,xsiz=7,/editable)
chi_max_lbl=widget_label(chi_base2,value='Max:',font=font)
chi_max_txt=trim(string(format='(f7.1)',wid_data.chi_max))
chi_max_text=widget_text(chi_base2,value=chi_max_txt, $
                       font=font,xsiz=7,/editable)




;
; WIDGETS FOR PLOTTING LINE PROFILE
; ---------------------------------
sub_base=widget_base(fv_base,/row,map=1)
prof_base=widget_base(sub_base,/row,map=1)
prof_butts_base=widget_base(prof_base,/col,map=1,sens=0)

print_butt=widget_button(prof_butts_base,value='Hardcopy',font=font)

prof_butts=cw_bgroup(prof_butts_base,/nonexclusive, $
                ['Error bars','Display params'], $
                /col,/frame,font=font)
;
xrange_base=widget_base(prof_butts_base,/col,map=1,/frame)
xrange_lbl=widget_label(xrange_base,value='X-range options:',font=font)
xrange_butts=cw_bgroup(xrange_base,set_value=wid_data.xra_style, $
                ['Full range','Fitted pixels','Selected line'], $
                /col,font=font,/exclusive,/no_release)
;
ymax_base=widget_base(prof_butts_base,/col,map=1,/frame)
ymax_lbl=widget_label(ymax_base,value='Y-range options:',font=font)
ymax_butts=cw_bgroup(ymax_base,set_value=wid_data.ymax, $
                ['Full fit function','Selected line','Spectrum'], $
                /col,font=font,/exclusive,/no_release)

prof_plot=widget_draw(prof_base,xsiz=xsiz2,ysiz=ysiz)

;
; WIDGETS FOR PLOTTING HISTOGRAM DATA
; -----------------------------------
hist_base=widget_base(sub_base,/row,map=1)
hist_butts_base=widget_base(hist_base,/col,/frame,map=1)
hist_lbl=widget_label(hist_butts_base,value='Histogram',font=font,/align_left)
hist_butts=cw_bgroup(hist_butts_base,/exclusive, $
                     ['Intensity','Velocity','FWHM','Chi^2'], $
                     set_val=wid_data.hist_flag,/col,font=font)
hist_plot=widget_draw(hist_base,xsiz=xsiz3,ysiz=ysiz)


;
; Structure for defining the rubber-band box used for selecting sub-images
;
box={flag: 0, wid: 0, x0: 0, y0: 0, x1:0, y1:0, $
     xsiz:xsiz, ysiz: ysiz, pixid:0}


;
; The state structure for passing data around the sub-routines and for
; controlling the widgets. 
;
state={windata: windata, $
       fitdata: fitdata, $
       wid_data: wid_data, $
       box:box, $
       fv_base:fv_base, $
       in_plot: in_plot, $
       out_plot: out_plot, $
       spike_plot: spike_plot, $
       chi_plot: chi_plot, $
       zoom_pix: zoom_pix, $
       hist_butts: hist_butts, $
       prof_butts: prof_butts, $
       unzoom: unzoom, $
       exit: exit, $
       in_min_text: in_min_text, $
       in_max_text: in_max_text, $
       vel_lim_text: vel_lim_text, $
       spike_min_text: spike_min_text, $
       spike_max_text: spike_max_text, $
       chi_min_text: chi_min_text, $
       chi_max_text: chi_max_text, $
       auto_wid: auto_wid, $
       auto_vel: auto_vel, $
       auto_int: auto_int, $
       log_int: log_int, $
       line_list: line_list, $
       ymax_butts: ymax_butts, $
       print_butt: print_butt, $
       xrange_butts: xrange_butts, $
       pix_asec: pix_asec, $
       prof_butts_base: prof_butts_base, $
       help_butt: help_butt}




WIDGET_CONTROL, fv_base, /REALIZE, set_uvalue=state

WIDGET_CONTROL, in_plot, GET_VALUE=in_plot_id
WIDGET_CONTROL, out_plot, GET_VALUE=out_plot_id
WIDGET_CONTROL, spike_plot, GET_VALUE=spike_plot_id
WIDGET_CONTROL, chi_plot, GET_VALUE=chi_plot_id
WIDGET_CONTROL, prof_plot, GET_VALUE=prof_plot_id
WIDGET_CONTROL, hist_plot, GET_VALUE=hist_plot_id
;
wid_data.in_id=in_plot_id
wid_data.out_id=out_plot_id
wid_data.spike_id=spike_plot_id
wid_data.chi_id=chi_plot_id
wid_data.prof_id=prof_plot_id
wid_data.hist_id=hist_plot_id


state.wid_data=wid_data
widget_control,fv_base,set_uvalue=state

fv_plot_exposure, state
fv_plot_histogram, state

XMANAGER, 'fv_base', fv_base, group=group

END


;-----------------
PRO eis_fit_viewer, windata, fitdata, mask=mask, units=units, calib=calib


IF n_params() LT 2 THEN BEGIN
  print,'Use:  IDL> eis_fit_viewer, windata, fitdata [, mask= ]'
  return
ENDIF 

IF n_elements(mask) NE 0 THEN BEGIN
  siz=size(mask)
  IF siz[1] NE fitdata.nx OR siz[2] NE fitdata.ny THEN BEGIN
    print,'%PLOT_EIS_FITS:  The dimensions of the input MASK do not match those of FITDATA. Returning...'
    return
  ENDIF 
ENDIF


!p.multi=0   ; just in case user has previously set something different

;
; Perform some checks to make sure fitdata matches windata
;
nx1=windata.nx
nx2=fitdata.nx
ny1=windata.ny
ny2=fitdata.ny

IF fitdata.ybin NE windata.scale[1] THEN BEGIN
  print,'%EIS_FIT_VIEWER: There is a discrepancy in the Y-binning for WINDATA and FITDATA. Please check your inputs.'
  print,format='("     windata y-bin:",i5)',windata.scale[1]
  print,format='("     fitdata y-bin:",i5)',fitdata.ybin
  return
ENDIF 

IF fitdata.scale[0] NE windata.scale[0] THEN BEGIN
  print,'%EIS_FIT_VIEWER: There is a discrepancy in the X-scale for WINDATA and FITDATA. Perhaps WINDATA should be binned?'
  print,format='("     windata x-scale:",i5)',windata.scale[0]
  print,format='("     fitdata x-scale:",i5)',fitdata.scale[0]
  return
ENDIF 

IF mean(fitdata.refwvl) GT max(windata.wvl) OR mean(fitdata.refwvl) LT min(windata.wvl) THEN BEGIN
  print,'%EIS_FIT_VIEWER: wavelength mis-match - fitdata does not seem to correspond to windata. Please check your inputs.'
  print,format='("    mean(fitdata.refwvl):",f10.2)',mean(fitdata.refwvl)
  print,format='("    minmax(windata.wvl): ",2f10.2)',minmax(windata.wvl)
  return
ENDIF 

IF n_params() EQ 0 THEN BEGIN
  print,'Use: IDL> eis_fit_viewer, windata, fitdata'
  return
ENDIF

eis_fv_widget,windata,fitdata, mask=mask, units=units, calib=calib

END
