;+
; NAME:
;   CRISPEX: CRIsp SPectral EXplorer
;
; PURPOSE:
;   This procedure allows browsing and analysis of multidimensional data cubes.
;   The procedure was initially written for analysis of temporal
;   spectropolarimetric data obtained with the CRISP instrument at the Swedish 
;   Solar Telescope (SST) at La Palma (Spain), however any data formatted in a
;   particular way (cf. the online reference pages) may be fed to CRISPEX for
;   browsing and/on analysis purposes
;
; CATEGORY:
;   Data browsing and analysis
;
; CALLING SEQUENCE:
;   CRISPEX, Imcube
;
; INPUTS:
;	  Imcube        - Filename of either
;                     * a 3D image datacube (dimensions [nx,ny,nt*nlp*ns]) or, if
;                       SPCUBE is not provided, a scan (dimensions [nx,ny,nlp]).
;                       If SINGLE_CUBE is specified a 3D datacube may be provided
;                       even if SPCUBE is not. Allowed data types: BYTE, INTEGER,
;                       FLOAT; or
;                     * a CRISPEX session file. All other inputs and keywords 
;                       will be overridden by the settings stored in the session
;                       file.
;
; OPTIONAL INPUTS:
;	  Spcube        - 3D spectral datacube (dimensions [nlp,nt,nx*ny*ns]).
;                   Required input if SINGLE_CUBE is not supplied with the
;                   number of linepositions and Imcube is a time series. Allowed
;                   data types: BYTE, INTEGER, FLOAT.
;
; KEYWORDS:
;	  REFCUBE	      - Reference data of same spatial dimensions as main data.
;                   REFCUBE may be supplied with either:
;			                * 2D data array: dimensions [nx,ny].
;			                * 3D data array: dimensions [nx,ny,refnt], where refnt 
;                       must be equal to nt.
;			                * Scalar string: pointing to a reference image cube of
;                       dimensions [nx,nx,refnt*refnlp] where refnt must be
;                       equal to 1 or to nt, but refnlp need not be equal to
;                       nlp.
;		 	                * 2-element string array: first element pointing to a
;                       reference image cube (dimensions [nx,ny,nt*refnlp]), the
;                       second element pointing to the corresponding reference
;                       spectral cube (dimensions [refnlp,refnt,nx*ny]).  Again,
;                       refnt must be equal to 1 or nt, while any (positive
;                       integer) value of refnlp is allowed. 
;                   Allowed data types: BYTE, INTEGER, FLOAT.
;   SJICUBE       - Slit-jaw image data corresponding to the main data. Must be
;                   supplied with a scalar string or 1D string array pointing to
;                   a slit-jaw image cube(s) of dimensions [sjinx,sjiny,sjint],
;                   where sjinx, sjiny and sjint need not be equal to nx, ny or
;                   nt, respectively. Allowed data types: BYTE, INTEGER, FLOAT.
;	  MASKCUBE	    - Mask data of same spatial dimensions as main data. Must be
;                    supplied with a scalar string pointing to a mask image cube
;                    of dimensions [nx,ny,masknt] where masknt must be equal to
;                    nt or 1. Allowed data types: BYTE, INTEGER, FLOAT.
;	  SPECTFILE	    - File containing the normalised spectrum as function of the
;                   linepositions or wavelength. Contains the required
;                   variables:
;			                * NORM_SPECT (normalised spectrum)
;                     * NORM_FACTOR (normalisation factor used to produce
;                       NORM_SPECT) 
;                     * SPECT_POS (spectral wavelength positions in any desired
;                       unit).  
;                   Optional variables: XTITLE and YTITLE (x- and y-title label
;                   for plots, respectively). If not set, the mean spectrum is
;                   determined from the scan(s) determined by the MNSPEC keyword
;                   (i.e. from all x,y pixels at all linepositions at t given by
;                   the setting of MNSPEC).
;                   SPECTFILE may be supplied with either:
;			                * Scalar string: spectral file corresponding to main data.
;			                * 2-element string array: first element is the spectral
;                       file corresponding to the main data, second element
;                       corresponds to the reference data.
;			              Set first element to '' if you only want to set the
;                   reference spectral file, e.g., 
;                   SPECTFILE=['','reference.spectfile'].
;                   NOTE: Setting of SPECTFILE will be ignored if FITS cubes are
;                   provided to Imcube, Spcube and/or REFCUBE.
;	  LINE_CENTER	  - Specifies line centre or wavelength information. LINE_CENTER
;                   may be supplied with:
;			                * Integer scalar: linecentre is set to position specified
;                       by LINE_CENTER.
;			                * 1D 2-element array (format: [WAVELENGTH, DELTA_LAMBDA]):
;                       linecentre is determined from the data and set to
;                       WAVELENGTH. The distance in wavelength between the
;                       linepositions is specified by DELTA_LAMBDA.
;			                * 1D 3-element array (format: [Integer scalar, WAVELENGTH,
;                       DELTA_LAMBDA]): combination of the two above.
;			                * 2D 1-element integer array (format: [[Integer scalar],
;                       [Integer scalar]]): first element sets the linecentre
;                       position for the main data, the second element that of
;                       the reference data.
;			                * 2D 2-element array (format: [[MAIN_WAVELENGTH,
;                       MAIN_DELTA_LAMBDA], [REF_WAVELENGTH,
;                       REF_DELTA_LAMBDA]]): the elements from the first
;                       subarray set the linecentre wavelength and wavelength
;                       spacing for the main data, while those of the second
;                       subarray set those values for the reference data.
;			                * 2D 3-element array (format: [[Integer scalar,
;                       MAIN_WAVELENGTH, MAIN_DELTA_LAMBDA],[Integer scalar,
;                       REF_WAVELENGTH, REF_DELTA_LAMBDA]]): combination of the
;                       two above.
;                   If not set: linecentre is determined from the data or from
;                   SPECTFILE.
;                   Setting of LINE_CENTER will be ignored if FITS cubes are
;                   provided to Imcube, Spcube and/or REFCUBE.
;	  MNSPEC        - Determines the calculation of the average spectrum for
;                   in-program display. MNSPEC may be supplied with:
;			                * Integer scalar: mean spectrum is determined from the
;                       t=MNSPEC scan.
;			                * 2-element integer array: mean spectrum is determined
;                       from the t=MNSPEC[0] through t=MNSPEC[1] scans.
;                   If not set: mean spectrum is determined from the t=0 scan.
;	  DT            - Specifies the elapsed time in seconds per time step.
;                   Defaults to not defined, showing frame number instead of
;                   time on the vertical axes.
;	  EXTS          -	If set, the time slices/slabs displayed in the program will
;                   be exact timeslices, obtained through linear interpolation,
;                   rather than approximated timeslices, obtained through
;                   nearest-neighbour interpolation (which is the default
;                   setting).  Note that setting this keyword may slow down the
;                   browsing of the spectral range (i.e. movement of the
;                   spectral slider) considerably, because of the
;                   computationally more expensive linear interpolation.
;	  SINGLE_CUBE	  - Single integer value specifying the number of spectral
;                   positions of the datacube. Only to be used when Imcube is
;                   provided with a 3D spectrotemporal datacube and Spcube is
;                   not specified AND Imcube is not a FITS file.
;	  SCALE_STOKES  - Spectral position of the in Stokes I value to which the
;                   Stokes Q, U, will be scaled (i.e., I/I, Q/I, U/I and/or
;                   V/I). If not set, each Stokes component will be scaled to
;                   its respective maximum.
;	  SCALE_CUBES	  - Specifies the value that the data should be multiplied with.
;                   SCALE_CUBES may be supplied with:
;			                * Integer scalar: value used for the main data.
;			                * 2-element integer array: first element is used for the
;                        main data, the second for the reference data.
;                   Defaults to 1.
;	  NO_WARP		    - Prevents the warping of the temporal spectrum when the
;                   wavelength spacing is non-equidistant. Applies equally to
;                   both sets of data if reference data is supplied. Defaults to
;                   not set.
;	  XTITLE		    - Sets the x-title of the temporal spectrum and the detailed
;                   spectrum. XTITLE may be supplied with:
;			                * Scalar string: x-title labels for the main temporal
;                       spectrum and detailed spectrum.
;			                * 2-element string array: first element sets the x-title
;                       labels for the main temporal spectrum and detailed
;                       spectrum, while the second element sets the labels for
;                       the reference data.  Set first element to '' if you only
;                       want to set the reference x-title, e.g.
;                       XTITLE=['','Height [km]'].
;   YTITLE		    - Sets the y-title of the detailed spectrum. YTITLE may be
;                   supplied with:
;			                * Scalar string: y-title label for the detailed spectrum.
;			                * 2-element string array: first element sets the y-title
;                       label for the main detailed spectrum, while the second
;                       element sets the label for the reference data.  Set
;                       first element to '' if you only want to set the
;                       reference y-title, e.g. YTITLE=['','Velocity [km/s]'].
;   OFFSET_SJI    - The (X,Y) offset in arcseconds to apply to the slit-jaw
;                   image reference coordinates. Can be a 2-element array
;                   (applied to all files supplied to SJICUBE) or a 2D
;                   concatenation of 2-element arrays specifying the individual
;                   offsets for each file supplied to SJICUBE (e.g. [[-1.5,2.3],
;                   [0.6,-1.2]]). Defaults to [0.,0.].
;	  WINDOW_LARGE	- Override the "1:1 window scaling whenever possible" setting.
;                   Useful for data with small nx and/or ny, where 1:1 image
;                   display is possible, but would yield small image display
;                   windows. If set to 1 (i.e., as flag) the window sizes will
;                   be determined based on the machine screen sizes. If set to a
;                   value larger than 1, the main image y-size will be set to
;                   that value. but only if it exceeds at least a fifth of the
;                   data y-size. Defaults to not set.
;   LAST_SESSION  - Load last session instead of one from new files. Will
;                   override any other input parameters or keywords except
;                   VERBOSE. Defaults to not set.
;	  VERBOSE		    - Verbosity setting for program setup and running. Mainly for
;                   maintenance purposes.  Verbosity levels can be set by
;                   supplying the keyword with the following values (add
;                   bitwise):
;				              * 0:  No verbosity.
;				              * 1:  Basic setup verbosity.
;				              * 2:  Extended setup verbosity.
;				              * 4:  Basic runtime verbosity.
;				              * 8:  Extended runtime verbosity.
;				              * 16: Playback statistics verbosity.
;			              In practice the values 3 and 7 are not useful and 1 has
;                   become obsolete for all practical purposes. All values
;                   larger than 26 are reduced to 26, all values smaller than 0
;                   are set to 0. Note that verbosity levels may also be set or 
;                   changed at runtime.
;
; OUTPUTS:
;	  Window outputs:
;     Depending on the call. In all cases at least three windows will appear,
;     one of which being the control panel, one the main image window and one
;     the detailed spectrum window. If called with:
;			  - one datacube, then an additional window will open, showing the
;         spectrum along a slit;
;			  - two datacubes, then an additional window will open, showing the
;         temporal spectrum;
;			  - three datacubes, then two additional windows will open, one showing
;         the temporal spectrum and one showing the reference image from the
;         third cube;
;			  - four datacubes, then four additional windows will open, one showing
;         the main temporal spectrum, one showing the reference temporal
;         spectrum, one showing the reference detailed spectrum and one showing
;         the reference image.
;		  Additional data display windows may be accessed through the tabs in the
;     control panel in all cases, although not all data display windows may be
;     available, depending on the number of data cubes with which the program
;     is called.
;	  Saveable outputs:
;		  - loop path points (*.CLSAV file);
;		  - loop path or detection space-time diagram (*.CSAV file). Note that only
;       that part of the space-time diagram between the current lower and upper
;       t-values will be saved, i.e., if you wish to save it for the full range
;       in time, be sure to reset the temporal boundaries.
;	  	- intensity versus time data for specific linepositions (*.CINT file);
;		  - (selected) timeseries as MPEG movie;
;		  - selected frame as JPEG snapshot;
;	  	- (selected) timeseries as JPEG files;
;		  - current session (*.CSES file).
;
; RESTRICTIONS:
;   Requires the following procedures and functions (not part of the
;   distribution):
;     Procedures: FITS_OPEN, FITS_CLOSE         [if reading FITS cubes]
;                 IRIS_LCT, AIA_LCT             [for IRIS and/or SDO color tables]
;     Functions:  IRIS_HISTO_OPT(), STR2UTC(),  [general; included in SolarSoft]
;                 UTC2STR()  
;                 READFITS(), FITSHEAD2STRUCT() [if reading FITS cubes]
;
; PROCEDURE:
;   In default setting, four windows are opened, one control panel and three
;   subsidiary windows containing the main image, the temporal spectrum and the
;   detailed spectrum, respectively.  Additional data browsing and analysis
;   options/windows may be obtained through control panel options.
;
;	  Some example calling sequences are discussed below. The most common calling
;   sequence is: 
;		  CRISPEX, 'main.imcube', 'main.spcube'
;
;	  Spectral information may be supplied either through the use of a spectral
;   save file or the use of the LINE_CENTER keyword, e.g.:
;
;		  CRISPEX, 'main.imcube', 'main.spcube', SPECTFILE='main.spectfile'
;	  or
;		  CRISPEX, 'main.imcube', 'main.spcube', LINE_CENTER=[6562,0.1]
;
;	  Reference data may be viewed by supplying such data to the REFCUBE keyword,
;   either in the simple reference mode:
;
;		  CRISPEX, 'main.imcube', 'main.spcube', REFCUBE='ref.imcube'
;
;	  or in the dual cube mode:
;
;		  CRISPEX, 'main.imcube', 'main.spcube', REFCUBE=['ref.imcube','ref.spcube']
;
;	  In addition, when running in dual cube mode, one may provide arrays to
;   certain keywords in order to set options for both the main and the reference
;   data, e.g.:
;	
;		  CRISPEX, 'main.imcube', 'main.spcube', $
;       REFCUBE=['ref.imcube','ref.spcube'], $
;			  SPECTFILE=['main.spectfile','ref.specftile']
;	  or
;		  CRISPEX, 'main.imcube', 'main.spcube', $
;       REFCUBE=['ref.imcube','ref.spcube'], $
;			  LINE_CENTER=[[6562,0.1],[8542,0.1]]
;	  etc.
;
;	  One may also set some of the options for the reference cube only (while
;   retaining the default options for the main data) by setting the element
;   corresponding to the main data to an empty scalar string, e.g.:
;
;		  CRISPEX, 'main.imcube', 'main.spcube', $
;       REFCUBE=['ref.imcube','ref.spcube'], $
;			  YTITLE=['','Velocity [km/s]']
;
;	  Further information on the calling sequence and specific options can be
;   found in the online reference pages, which can be reached through the
;   in-program help function or by going directly to
;   http://folk.uio.no/gregal/crispex
;
; MODIFICATION HISTORY:
;	  2009 Feb 11 GV: start buildup of program, based on Øystein Langangen's
;                   August 2008 version of CRISP_SPECTRAL_EXPLORER.PRO. Further
;                   (structural) inspiration from XIMOVIE.PRO by Oivind Wikstol
;                   and XSLICE.PRO by Alfred de Wijn
;	  2009 Feb 21 GV: incorporation of LP_HEADER.PRO functionality
;	  2009 Feb 24 GV: v0.9    - release of beta version 
;	  2009 Mar 02 GV: v0.9.1  - implementation of x- and y-slice display 
;	  2009 Mar 04 GV: v0.9.3  - implementation of display of spectral slice along
;                             a slit, including controls to set slit angle and 
;                             length 
;	  2009 Mar 09 GV: v0.9.4  - implementation of movement along the slit 
;                             direction	
;	  2009 Mar 10 GV: v0.9.5  - implementation of option to study spectral scan
;                             and show a reference image or cube 
;	  2009 Mar 15 GV: v0.9.6  - implementation of zoom option 
;	  2009 Mar 23 GV: v0.9.7  - implementation of time slice along a segmented
;                             line and	option to save the resulting data
;	  2009 Apr 14 GV: v0.9.8  - corrected extraction and saving of time slice,
;                             removed x- and y-slice display due to redundancy
;                             from spectral slice along a slit 
;	  2009 May 15 GV: v0.9.9  - implementation of extended save and retrieve
;                             options, extended image scaling	options, save and
;                             restore session options, adjustable time and
;                             spectral range, different loop linestyles,
;                             selection menu for loop overlays, parameter
;                             overview window and display of saved timeslices 
;	  2009 Aug 24 GV: v1.0    - implementation of extra zoomfactors, save as MPEG
;                             and JPEG options, save from	detection file,
;                             spectral and temporal range choice in saving
;                             timeslabs, exact timeslice display in-program,
;                             resizable display windows, read-in of full
;                             reference cubes and an option to calculate mean
;                             spectrum over a range in timesteps 
;	  2009 Nov 05 GV: v1.1    - implementation of loop path feedback, shortcut
;                             controls through keyboard,	single full cube call
;                             and also fixed a number of bugs 
;	  2010 Mar 10 GV: v1.5    - enabled visualisation of Stokes cube data, display
;                             of reference and image cube	data values, drawing
;                             of loop paths for 3D temporal image cube,
;                             retreival and saving timeslices from reference
;                             cube, extended scaling options for reference cube
;                             image, implemented spatial measurement tool and
;                             help function, moved user feedback to pop-up
;                             windows, disposed of obsolete keywords and fixed a
;                             number of bugs 
;	  2011 Jul 11 GV: v1.6    - enabled dual cube mode, in-program Doppler images,
;                             extended (Stokes) spectral	options, extended plot
;                             options, blinking while playing, setting of
;                             preferences, extraction of intensity-time plots,
;                             and made aesthetic improvements (bitmap play
;                             buttons, better cursor visibility and startup
;                             screen) 
;	  2011 Aug 22 GV: v1.6.1  - extended save as options, implemented save as PNG,
;                             saving of color MPEG, an option to open a restored
;                             loop in TANAT and fixed a number of bugs
;	  2012 Mar 23 GV: v1.6.2  - extended reference and Stokes data input options,
;                             implemented mask overlays, enabled display of
;                             multiple space-time diagrams and fixed a number of
;                             bugs 
;	  2012 Dec 04 GV: v1.6.3  - extended in-program analysis options through
;                             display of reference space-time diagram, extended
;                             image and space-time diagram scaling options and
;                             fixed a number of bugs 
;   2015 Sep 23 GV: v1.7    - extensive overhaul to accomodate read-in of IRIS
;                             data and FITS cubes in general. Overhaul of GUI, e
;                             extended space-time diagram functionality to
;                             reference and slit-jaw data, added numerous overlay
;                             options for IRIS data
;   2015 Oct 23 GV: v1.7.1  - implemented color table support and SJI loading
;                             from within CRISPEX. Added color table selection
;                             and color bars to displays, extended internal plot
;                             parameters to include line thickness, enabled
;                             loading SJICUBE from file menu even when no
;                             SJICUBE was provided initially.
;   2016 Apr 29 GV: v1.7.2  - extended reference data functionality. Enabeld
;                             loading reference data from file menu, enabled
;                             Stokes data cubes as reference data, implemented
;                             gather windows option.
;   2017 Mar 24 GV: v1.7.3  - extended slit-jaw image and spectral
;                             functionality. Load up to six slit-jaw image cubes
;                             simultaneously, also from within CRISPEX,
;                             implemented proper Stokes scaling (with options to
;                             overplot noise levels), implemented off-line center
;                             spactral zoom, reverted to checkbox buttons to
;                             select diagnostics display for main data.
;   2018 Jan 29 GV: v1.7.4  - implemented 1:1 zoom, direct loading of session
;                             save files as well as last session, handling
;                             SOLARNET-standarad tabulated FITS files,
;                             per-diagnostic restriction of wavelength range.
;                             Made control panel more compact for better fitting
;                             on small screens.
;
; ACKNOWLEDGEMENTS:
;	  This code would not be present in its current state and with the current
;   functionalities without the testing by and the valuable input and ideas
;   of Luc Rouppe van der Voort, Bart de Pontieu, Mats Carlsson, Sven Wedemeyer,
;   Patrick Antolin, Jorrit Leenaarts, Eamon Scullion and Jaime de la Cruz
;   Rodriguez. 
;
; AUTHOR:
;	  Gregal Vissers (gregal.vissers@astro.su.se)
;   @ Institute for Solar Physics, Department of Astronomy, Stockholm University
;	  (previously at Institute of Theoretical Astrophysics, University of Oslo)
;   
;-

;========================= CRISPEX FUNCTIONS
;------------------------- ARRAY ANALYSIS FUNCTION
FUNCTION CRISPEX_ARRAY_GET_GAP, input_array, ntotal
  ; Determines the lower and upper boundaries of gaps in an array. Returns the
  ; indices between which the gap occurs (gap_bound_low, gap_bound_upp)
  ninput_array = N_ELEMENTS(input_array)
  ; Sort input_array, just in case
  input_array = input_array[SORT(input_array)]
  ; Set initial values
  databounds = 0L
  ngaps = 0L
  wdatabounds = 0L
  ; Handle lower boundary first
  ngaps += (input_array[0] NE 0) 
  ; Failsafe against le 2-element arrays
  IF (ninput_array LE 2) THEN BEGIN
    databounds = 0    ; Set the first databound
    IF (ninput_array EQ 2) THEN BEGIN
      IF (ABS(input_array[1]-input_array[0]) NE 1) THEN $
        databounds = [databounds, 0, 1] 
    ENDIF
  ENDIF ELSE BEGIN
    ; Consider input_array, excluding the first point (which has been dealt with
    ; separately
    sel_array = input_array[1:ninput_array-1]
    shift_diff = SHIFT(sel_array,-1) - sel_array
    ; Since shift_diff has ninput-1 elements and want to exclude last one
    ; (due to wrap-around): ninput-1-1-1 = ninput-3
    whereshift = WHERE(shift_diff[0:ninput_array-3] NE 1, count)
    ; Are there any "non-one" shifts; add those gap boundaries
    IF (count NE 0) THEN BEGIN
      FOR i=0,count-1 DO $
        databounds = [databounds, REPLICATE(whereshift[i],2)+[1,2]]
      ngaps += LONG(count)
    ENDIF
  ENDELSE
  ; Handle upper boundary
  databounds = [databounds, (ninput_array-1)]
  ngaps += (input_array[ninput_array-1] NE (ntotal-1)) 
  wdatabounds = input_array[databounds]
  ; Save and return result structure
  result = {ngaps:ngaps, databounds:databounds, wdatabounds:wdatabounds}
  RETURN, result
END

FUNCTION CRISPEX_ARRAY_WHERE, input_array, check_array, VALUES=values
  ; Checks Input_array for all values in Check_array and returns their indices
  ; and if requested also their values. 
  ; Note: Values can only be returned for switches!
  IF ~KEYWORD_SET(VALUES) THEN result_vals = -1
  tags = TAG_NAMES(input_array)
  FOR i=0,N_ELEMENTS(check_array)-1 DO BEGIN
    idx_tmp = (WHERE(tags EQ check_array[i]))[0]
    IF (N_ELEMENTS(result_idx) GE 1) THEN BEGIN
      result_idx = [result_idx, idx_tmp] 
      IF KEYWORD_SET(VALUES) THEN $
        result_vals = [result_vals, (input_array).(idx_tmp)]
    ENDIF ELSE BEGIN
      result_idx = idx_tmp
      IF KEYWORD_SET(VALUES) THEN result_vals = (input_array).(idx_tmp)
    ENDELSE
  ENDFOR
  result = {idx:result_idx, vals:result_vals}
  RETURN, result
END

;------------------------- APPLICATION USER DIRECTORY FUNCTION
FUNCTION CRISPEX_CONFIG_DIR
; Handles creation and update of ~/.idl/gvissers/crispex/ contents 
  ; Author details
  author_dirname = 'gvissers'
  author_desc = 'Gregal Vissers (g.j.m.vissers@astro.uio.no), '+$
    'Institute for Solar Physics, '+ $
    'Stockholm University'
  author_readme_version = 1

  ; Application details
  app_dirname = 'crispex'
  app_desc = 'CRISPEX: CRIsp SPectral EXplorer'
  app_readme_txt = [$
    'This is the user configuration directory for CRISPEX, ',$
    'written by Gregal Vissers (g.j.m.vissers@astro.uio.no), ',$
    'Institute of Theoretical Astrophysics, University of Oslo.',$
    'It is used to store user preferences and enable instance ',$
    'tracking. Both the directory and its contents can be safely ',$
    'deleted, however, any stored settings will then be lost.']
  app_readme_version = 1

  RETURN, APP_USER_DIR(author_dirname, author_desc, $
    app_dirname, app_desc, app_readme_txt, app_readme_version, $
    AUTHOR_README_VERSION=author_readme_version)

END

;------------------------- CONVERSION FUNCTIONS
FUNCTION CRISPEX_TRANSFORM_DEC2BIN, decimal_number
; Handles the conversion of decimal to binary number
	IF (decimal_number NE 0) THEN BEGIN
		coarse_p = ALOG10(DOUBLE(decimal_number))/ALOG10(2.D)
		p = FLOOR(coarse_p)
		i=0
		binary_array = INTARR(FLOOR(coarse_p)+1)
		b = REVERSE((2^FINDGEN(FLOOR(coarse_p)+1)))
		WHILE (p GE 0) DO BEGIN
			IF (2^p LE decimal_number) THEN BEGIN
				binary_array[i] = 1
				decimal_number -= 2^p
			ENDIF ELSE binary_array[i] = 0
			p -= 1
			i += 1
		ENDWHILE
		binary_array = REVERSE(binary_array)
		IF (N_ELEMENTS(binary_array) LT 5) THEN $
      binary_array = [binary_array, REPLICATE(0,5-N_ELEMENTS(binary_array))]
	ENDIF ELSE binary_array = [0,0,0,0,0]
	RETURN, binary_array
END

FUNCTION CRISPEX_TRANSFORM_COORDS, x_in, y_in, dx_in, dx_out, dy_in, dy_out, $
  refxval_in, refxval_out, refyval_in, refyval_out, $
  refxpix_in, refxpix_out, refypix_in, refypix_out
  ; Conversion is from system "in" to "out"
  x_out = ((x_in-refxpix_in)*dx_in + (refxval_in-refxval_out)) / dx_out + $
            refxpix_out
  y_out = ((y_in-refypix_in)*dy_in + (refyval_in-refyval_out)) / dy_out + $
            refypix_out
  result = {x:x_out, y:y_out}
  RETURN, result
END

FUNCTION CRISPEX_TRANSFORM_DATA2DEVICE, info, X_IN=x_in, Y_IN=y_in, MAIN=main, $
  REFERENCE=reference, SJI=sji, INVERSE=inverse, IDX_SJI=idx_sji
  IF KEYWORD_SET(MAIN) THEN BEGIN
    xpos = (*(*info).zooming).xpos
    ypos = (*(*info).zooming).ypos
    winx = (*(*info).winsizes).xywinx
    winy = (*(*info).winsizes).xywiny
    d_nx = (*(*info).dataparams).d_nx
    d_ny = (*(*info).dataparams).d_ny
  ENDIF ELSE IF KEYWORD_SET(REFERENCE) THEN BEGIN
    xpos = (*(*info).zooming).xrefpos
    ypos = (*(*info).zooming).yrefpos
    winx = (*(*info).winsizes).refwinx
    winy = (*(*info).winsizes).refwiny
    d_nx = (*(*info).dataparams).d_refnx
    d_ny = (*(*info).dataparams).d_refny
  ENDIF ELSE IF KEYWORD_SET(SJI) THEN BEGIN
    xpos = (*(*info).zooming).xsjipos[idx_sji]
    ypos = (*(*info).zooming).ysjipos[idx_sji]
    winx = (*(*info).winsizes).sjiwinx[idx_sji]
    winy = (*(*info).winsizes).sjiwiny[idx_sji]
    d_nx = (*(*info).dataparams).d_sjinx[idx_sji]
    d_ny = (*(*info).dataparams).d_sjiny[idx_sji]
  ENDIF
  x_out = -1
  y_out = -1
  IF ~KEYWORD_SET(INVERSE) THEN BEGIN
    ; Data -> Device: add 0.5 pixel offset to center cursor on pixel, instead of
    ; on IDL default lower left corner
    IF (N_ELEMENTS(X_IN) NE 0) THEN x_out = (x_in+0.5 - xpos) * winx / (d_nx+1)
    IF (N_ELEMENTS(Y_IN) NE 0) THEN y_out = (y_in+0.5 - ypos) * winy / (d_ny+1)
  ENDIF ELSE BEGIN
    ; Device -> Data
    IF (N_ELEMENTS(X_IN) NE 0) THEN x_out = x_in * (d_nx+1) / winx + xpos
    IF (N_ELEMENTS(Y_IN) NE 0) THEN y_out = y_in * (d_ny+1) / winy + ypos
  ENDELSE
  result = {x:x_out, y:y_out}
  RETURN, result
END

FUNCTION CRISPEX_TRANSFORM_GET_COORDMAPS, hdr, MAINREF=mainref, $
  MAINSJI=mainsji, REFSJI=refsji, IDX_SJI=idx_sji
  ; Create main index map
  IF KEYWORD_SET(MAINREF) OR KEYWORD_SET(MAINSJI) THEN BEGIN
    idxarr_main = LONARR(2,hdr.nx,hdr.ny)
    xarr = LINDGEN(hdr.nx)
    yarr = LINDGEN(hdr.ny)
    FOR x=0,hdr.nx-1 DO idxarr_main[1,x,*] = yarr
    FOR y=0,hdr.ny-1 DO idxarr_main[0,*,y] = xarr
    a = idxarr_main
    dx_a = hdr.dx
    dy_a = hdr.dy
    refxval_a = hdr.xval
    refyval_a = hdr.yval
    refxpix_a = hdr.xpix
    refypix_a = hdr.ypix
  ENDIF
  ; Create reference index map
  IF KEYWORD_SET(MAINREF) OR KEYWORD_SET(REFSJI) THEN BEGIN
    idxarr_ref = LONARR(2,hdr.refnx,hdr.refny)
    xarr = LINDGEN(hdr.refnx)
    yarr = LINDGEN(hdr.refny)
    FOR x=0,hdr.refnx-1 DO idxarr_ref[1,x,*] = yarr
    FOR y=0,hdr.refny-1 DO idxarr_ref[0,*,y] = xarr
    IF KEYWORD_SET(MAINREF) THEN BEGIN
      b = idxarr_ref 
      dx_b = hdr.refdx
      dy_b = hdr.refdy
      refxval_b = hdr.xval_ref
      refyval_b = hdr.yval_ref
      refxpix_b = hdr.xpix_ref
      refypix_b = hdr.ypix_ref
    ENDIF ELSE BEGIN
      a = idxarr_ref
      dx_a = hdr.refdx
      dy_a = hdr.refdy
      refxval_a = hdr.xval_ref
      refyval_a = hdr.yval_ref
      refxpix_a = hdr.xpix_ref
      refypix_a = hdr.ypix_ref
    ENDELSE
  ENDIF
  ; Create slit-jaw image index map
  IF KEYWORD_SET(MAINSJI) OR KEYWORD_SET(REFSJI) THEN BEGIN
    idxarr_sji = LONARR(2,hdr.sjinx[idx_sji],hdr.sjiny[idx_sji])
    xarr = LINDGEN(hdr.sjinx[idx_sji])
    yarr = LINDGEN(hdr.sjiny[idx_sji])
    FOR x=0,hdr.sjinx[idx_sji]-1 DO idxarr_sji[1,x,*] = yarr
    FOR y=0,hdr.sjiny[idx_sji]-1 DO idxarr_sji[0,*,y] = xarr
    b = idxarr_sji
    dx_b = hdr.sjidx[idx_sji]
    dy_b = hdr.sjidy[idx_sji]
    refxval_b = hdr.xval_sji[idx_sji]
    refyval_b = hdr.yval_sji[idx_sji]
    refxpix_b = hdr.xpix_sji[idx_sji]
    refypix_b = hdr.ypix_sji[idx_sji]
  ENDIF
  ; Create conversion maps
  pix_a2b = LONARR(2,(SIZE(a))[2], (SIZE(a))[3])
  pix_b2a = LONARR(2,(SIZE(b))[2], (SIZE(b))[3])
  pix_a2b[0,*,*] = ((a[0,*,*]-refxpix_a)*dx_a + (refxval_a-refxval_b)) / $
                    dx_b + refxpix_b
  pix_a2b[1,*,*] = ((a[1,*,*]-refypix_a)*dy_a + (refyval_a-refyval_b)) / $
                    dy_b + refypix_b
  pix_b2a[0,*,*] = ((b[0,*,*]-refxpix_b)*dx_b + (refxval_b-refxval_a)) / $
                    dx_a + refxpix_a
  pix_b2a[1,*,*] = ((b[1,*,*]-refypix_b)*dy_b + (refyval_b-refyval_a)) / $
                    dy_a + refypix_a
  result = {pix_a2b:pix_a2b, pix_b2a:pix_b2a}
  RETURN, result
END

FUNCTION CRISPEX_TRANSFORM_GET_WCS, x_in, y_in, wcs_a, wcs_b, $
  PIXEL=pixel, COORD=coord, NO_ROUND=no_round
; Wrapper for WCS functions in order to process arrays
  xy_out = [[x_in], [y_in]]
  FOR i=0,N_ELEMENTS(x_in)-1 DO BEGIN
    IF KEYWORD_SET(COORD) THEN $
      xy_out[i,*] = WCS_GET_COORD(wcs_a, [xy_out[i,0], xy_out[i,1]])
    IF KEYWORD_SET(PIXEL) THEN $
      xy_out[i,*] = WCS_GET_PIXEL(wcs_b, [xy_out[i,0], xy_out[i,1]])
  ENDFOR
  IF ~KEYWORD_SET(NO_ROUND) THEN xy_out = ROUND(xy_out)
  x_out = REFORM(xy_out[*,0])
  y_out = REFORM(xy_out[*,1])
  result = {x:x_out, y:y_out}
  RETURN, result
END

;------------------------- BUTTON GROUP FUNCTIONS
FUNCTION CRISPEX_BGROUP_DIAGNOSTICS_SELECT, event
; Handles selection of diagnostics and calls necessary replot procedures
  WIDGET_CONTROL, event.TOP, GET_UVALUE = info
	IF (TOTAL(((*(*info).feedbparams).verbosity)[2:3]) GE 1) THEN $
    CRISPEX_VERBOSE_GET_ROUTINE, event
  sel_idx = event.VALUE-1
  IF (sel_idx EQ -1) THEN BEGIN
    ; Handle the setting of Display all: reset variables and list_values
    (*(*info).intparams).disp_diagnostics = $
      REPLICATE(1,(*(*info).intparams).ndiagnostics)   
    (*(*info).intparams).ndisp_diagnostics = $
      TOTAL((*(*info).intparams).disp_diagnostics)
    FOR i=0,(*(*info).intparams).ndiagnostics-1 DO $
      WIDGET_CONTROL, (*(*info).ctrlscp).specwin_button_ids[i+1], $
        /SET_BUTTON, /SENSITIVE
  ENDIF ELSE BEGIN
    (*(*info).intparams).disp_diagnostics[sel_idx] = event.SELECT
    (*(*info).intparams).ndisp_diagnostics = $
      TOTAL((*(*info).intparams).disp_diagnostics)
    ; Failsafe against hiding all diagnostics
    IF ((*(*info).intparams).ndisp_diagnostics EQ 1) THEN $
      WIDGET_CONTROL, (*(*info).ctrlscp).specwin_button_ids[$
        WHERE((*(*info).intparams).disp_diagnostics EQ 1)+1], SENSITIVE=0 $
    ELSE $
      FOR i=0,(*(*info).intparams).ndiagnostics-1 DO $
        WIDGET_CONTROL, (*(*info).ctrlscp).specwin_button_ids[i+1], /SENSITIVE
  ENDELSE
  WIDGET_CONTROL, (*(*info).ctrlscp).specwin_button_ids[0], $
    SENSITIVE=((*(*info).intparams).ndisp_diagnostics NE $
               (*(*info).intparams).ndiagnostics), $
    SET_BUTTON=((*(*info).intparams).ndisp_diagnostics EQ $
                (*(*info).intparams).ndiagnostics)
  ; Adjust label text depending on whether all or some are displayed
  IF ((*(*info).intparams).ndisp_diagnostics EQ $
      (*(*info).intparams).ndiagnostics) THEN $
    label_text = 'Main: Displaying all' $
  ELSE $
    label_text = 'Main: Displaying selected'
  WIDGET_CONTROL, (*(*info).ctrlscp).main_specwin_label, $
    SET_VALUE=label_text
  IF ((*(*info).intparams).ndisp_diagnostics NE $
      (*(*info).intparams).ndisp_refdiagnostics) THEN BEGIN
    IF (*(*info).ctrlsswitch).lp_ref_lock THEN $
      CRISPEX_SLIDER_LP_REF_LOCK, event, /UNLOCK, /NO_DRAW
    WIDGET_CONTROL, (*(*info).ctrlscp).lp_ref_but, SENSITIVE=0
  ENDIF ELSE $
    WIDGET_CONTROL, (*(*info).ctrlscp).lp_ref_but, /SENSITIVE
  CRISPEX_DRAW_GET_SPECTRAL_AXES, event, /MAIN
  ; Adjust slider settings based on available lp-range
  CRISPEX_DISPRANGE_LP_RANGE, event, /NO_DRAW
  ; Change the overall minimum/maximum Doppler values as need be
  (*(*info).dataparams).v_dop_low_min[0] = FLOOR(MIN($
    (*(*info).dataparams).v_dop_low_min[*(*(*info).intparams).wheredispdiag+1],$
    /NAN))
  (*(*info).dataparams).v_dop_low_max[0] = FLOOR(MIN($
    (*(*info).dataparams).v_dop_low_max[*(*(*info).intparams).wheredispdiag+1],$
    /NAN))
  (*(*info).dataparams).v_dop_upp_min[0] = CEIL(MAX($
    (*(*info).dataparams).v_dop_upp_min[*(*(*info).intparams).wheredispdiag+1],$
    /NAN))
  (*(*info).dataparams).v_dop_upp_max[0] = CEIL(MAX($
    (*(*info).dataparams).v_dop_upp_max[*(*(*info).intparams).wheredispdiag+1],$
    /NAN))
  CRISPEX_SLIDER_LP_RESTRICT, event, /NO_DRAW
  idx = ((*(*info).dispswitch).lp_restrict[1] EQ 1)
  IF (idx EQ 0) THEN $
    CRISPEX_DIAGNOSTICS_SELECT_UPDATE_LP_RESTRICT_SLIDERS, event
  CRISPEX_UPDATE_T, event
  CRISPEX_SCALING_APPLY_SELECTED, event
  IF (*(*info).winswitch).showsp THEN BEGIN
    CRISPEX_UPDATE_SPSLICE, event
    CRISPEX_DISPLAYS_SP_REPLOT_AXES, event
  ENDIF
  IF (*(*info).winswitch).showphis THEN BEGIN
    CRISPEX_UPDATE_PHISLICE, event, /NO_DRAW
    CRISPEX_DISPLAYS_PHIS_REPLOT_AXES, event
  ENDIF
  CRISPEX_DRAW, event, /NO_REF, /LS_NO_REF
END

FUNCTION CRISPEX_BGROUP_DETSPECT_IMREF, event, SESSION_RESTORE=session_restore
  ; Handles the selection of detspect options 
	WIDGET_CONTROL, event.TOP, GET_UVALUE = info
	IF (TOTAL(((*(*info).feedbparams).verbosity)[2:3]) GE 1) THEN $
    CRISPEX_VERBOSE_GET_ROUTINE, event
  IF ~KEYWORD_SET(SESSION_RESTORE) THEN BEGIN
    (*(*info).ctrlsswitch).imrefdetspect = event.VALUE
	  CRISPEX_DISPLAYS_DETSPECT_SET_BUTTONS, event
  ENDIF ELSE BEGIN
 		WIDGET_CONTROL, (*(*info).ctrlscp).detspect_imref_button_ids[0], $
       SET_BUTTON=ABS((*(*info).ctrlsswitch).imrefdetspect-1)
 		WIDGET_CONTROL, (*(*info).ctrlscp).detspect_imref_button_ids[1], $
       SET_BUTTON=(*(*info).ctrlsswitch).imrefdetspect,$
       SENSITIVE=(*(*info).dataswitch).refspfile
  ENDELSE
END

FUNCTION CRISPEX_BGROUP_DISPLAYS_SELECT, event, SESSION_RESTORE=session_restore
  ; Handles the selection of main data displays
	WIDGET_CONTROL, event.TOP, GET_UVALUE = info
	IF (TOTAL(((*(*info).feedbparams).verbosity)[2:3]) GE 1) THEN $
    CRISPEX_VERBOSE_GET_ROUTINE, event
  ; Idx: 0=Doppler, 1=Detailed spectrum, 2=Spectrum-time, 3=Spectrum along slit
  IF ~KEYWORD_SET(SESSION_RESTORE) THEN BEGIN
    CASE event.VALUE OF
      0: CRISPEX_DISPLAYS_DOPPLER_TOGGLE, event 
      1: CRISPEX_DISPLAYS_IMREF_LS_TOGGLE, event
      2: CRISPEX_DISPLAYS_SP_TOGGLE, event
      3: CRISPEX_DISPLAYS_PHIS_TOGGLE, event
    ENDCASE
  ENDIF ELSE BEGIN
    ; set button determined by saved winswitches
    setbarr = [(*(*info).winswitch).showdop, (*(*info).winswitch).showls, $
      (*(*info).winswitch).showsp, (*(*info).winswitch).showphis]
    ; sensitivity determined by file existence, nlp>1, and no single windows
    sensarr = [REPLICATE(((*(*info).dataparams).nlp GT 1),2), $
      (*(*info).dataswitch).spfile, $
      ((*(*info).dataparams).nlp GT 1)]
    sensarr = sensarr AND $
      REPLICATE(((*(*info).intparams).singlewav_windows EQ 0), $
      N_ELEMENTS(sensarr))
    FOR i=0,N_ELEMENTS((*(*info).ctrlscp).displays_button_ids)-1 DO $
      WIDGET_CONTROL, (*(*info).ctrlscp).displays_button_ids[i], $
        SET_BUTTON=(setbarr[i] EQ 1), SENSITIVE=(sensarr[i] EQ 1)
  ENDELSE
END

FUNCTION CRISPEX_BGROUP_REFDISPLAYS_SELECT, event, $
  SESSION_RESTORE=session_restore
  ; Handles the selection of reference data displays
	WIDGET_CONTROL, event.TOP, GET_UVALUE = info
	IF (TOTAL(((*(*info).feedbparams).verbosity)[2:3]) GE 1) THEN $
    CRISPEX_VERBOSE_GET_ROUTINE, event
  ; Idx: 0=Image, 1=Detailed spectrum, 2=Spectrum-time
  IF ~KEYWORD_SET(SESSION_RESTORE) THEN BEGIN
    CASE event.VALUE OF
      0: CRISPEX_DISPLAYS_REF_TOGGLE, event
      1: CRISPEX_DISPLAYS_IMREF_LS_TOGGLE, event, /REFERENCE
      2: CRISPEX_DISPLAYS_REFSP_TOGGLE, event
    ENDCASE
  ENDIF ELSE BEGIN  
    ; set button determined by saved winswitches
    setbarr = [(*(*info).winswitch).showref, (*(*info).winswitch).showrefls, $
      (*(*info).winswitch).showrefsp]
    ; sensitivity determined by file existence, nlp>1, and no single windows
    sensarr = [(*(*info).dataswitch).reffile, $
      ((*(*info).dataparams).refnlp GT 1), (*(*info).dataswitch).refspfile]
    sensarr = sensarr AND $
      [1,REPLICATE(((*(*info).intparams).refsinglewav_windows EQ 0),$
        N_ELEMENTS(sensarr)-1)]
    FOR i=0,N_ELEMENTS((*(*info).ctrlscp).refdisplays_button_ids)-1 DO $
      WIDGET_CONTROL, (*(*info).ctrlscp).refdisplays_button_ids[i], $
        SET_BUTTON=(setbarr[i] EQ 1), SENSITIVE=(sensarr[i] EQ 1)
  ENDELSE
END

FUNCTION CRISPEX_BGROUP_SJIDISPLAYS_SELECT, event
  ; Handles the selection of SJI data displays
	WIDGET_CONTROL, event.TOP, GET_UVALUE = info
	IF (TOTAL(((*(*info).feedbparams).verbosity)[2:3]) GE 1) THEN $
    CRISPEX_VERBOSE_GET_ROUTINE, event
  IF (*(*info).winswitch).showsji[event.VALUE] THEN $
    CRISPEX_DISPLAYS_SJI_TOGGLE, event, /KILL, IDX_SJI=event.VALUE $
  ELSE $
    CRISPEX_DISPLAYS_SJI_TOGGLE, event, /DISP, IDX_SJI=event.VALUE 
  *(*(*info).winswitch).whereshowsji = $
    WHERE((*(*info).winswitch).showsji EQ 1, nwhereshowsji)
  (*(*info).winswitch).nwhereshowsji = nwhereshowsji
END

FUNCTION CRISPEX_BGROUP_LP_RESTRICT, event, SESSION_RESTORE=session_restore
  ; Handles selecting main/reference to restrict wavelength range for
	WIDGET_CONTROL, event.TOP, GET_UVALUE = info
	IF (TOTAL(((*(*info).feedbparams).verbosity)[2:3]) GE 1) THEN $
    CRISPEX_VERBOSE_GET_ROUTINE, event
  IF ~KEYWORD_SET(SESSION_RESTORE) THEN BEGIN
    idx = event.VALUE
    flag = event.SELECT
    (*(*info).dispswitch).lp_restrict[idx] = flag
    (*(*info).dispswitch).lp_restrict[ABS(idx-1)] = ABS(flag-1)
  ENDIF ELSE $
    idx = ((*(*info).dispswitch).lp_restrict[1] EQ 1)
  CRISPEX_SLIDER_LP_RESTRICT_SETRANGE, event, idx
END

FUNCTION CRISPEX_BGROUP_LP_RESTRICT_GLOBLOC, event, SESSION_RESTORE=session_restore
  ; Handles selecting main/reference to restrict wavelength range for
	WIDGET_CONTROL, event.TOP, GET_UVALUE = info
	IF (TOTAL(((*(*info).feedbparams).verbosity)[2:3]) GE 1) THEN $
    CRISPEX_VERBOSE_GET_ROUTINE, event
  idx = ((*(*info).dispswitch).lp_restrict[1] EQ 1)
  (*(*info).dispswitch).lp_restrict_globloc[idx] = BYTE(event.VALUE)
  ; If using global, check whether certain windows need to be reset
  IF ((*(*info).dispswitch).lp_restrict_globloc[idx] EQ 0) THEN BEGIN
    CASE idx OF
      0:  validx = WHERE( (((*(*info).dispparams).v_dop_low - $
                            (*(*info).dataparams).v_dop_low_min) NE 0) OR $
                          (((*(*info).dispparams).v_dop_upp - $
                            (*(*info).dataparams).v_dop_upp_max) NE 0))
      1:  validx = WHERE( (((*(*info).dispparams).v_dop_ref_low - $
                            (*(*info).dataparams).v_dop_ref_low_min) NE 0) OR $
                          (((*(*info).dispparams).v_dop_ref_upp - $
                            (*(*info).dataparams).v_dop_ref_upp_max) NE 0))
    ENDCASE
    CRISPEX_DISPRANGE_LP_RESET, event, REFERENCE=(idx EQ 1), VALIDX=validx
  ENDIF ELSE $
    CRISPEX_SLIDER_LP_RESTRICT_SETRANGE, event, idx
END

FUNCTION CRISPEX_BGROUP_MASTER_TIME, event, NO_DRAW=no_draw
; Handles the change mask overlay window
	WIDGET_CONTROL, event.TOP, GET_UVALUE = info
	IF (TOTAL(((*(*info).feedbparams).verbosity)[2:3]) GE 1) THEN $
    CRISPEX_VERBOSE_GET_ROUTINE, event
  ; Get old time 
  CASE (*(*info).dispparams).master_time OF
    0:  BEGIN
          t_old = $
            (*(*(*info).dispparams).tarr_main)[(*(*info).dispparams).t]
          nt_old = (*(*info).dataparams).mainnt
        END
    1:  BEGIN
          t_old = (*(*(*info).dispparams).tarr_ref)[(*(*info).dispparams).t]
          nt_old = (*(*info).dataparams).refnt
        END
    2:  BEGIN
          t_old = $
            (*(*(*info).dispparams).tarr_sji[(*(*info).dispswitch).sji_select])[$
            (*(*info).dispparams).t]
          nt_old = (*(*info).dataparams).sjint[(*(*info).dispswitch).sji_select]
        END
  ENDCASE
  ; Get new timing master
  wherevalue = WHERE(TAG_NAMES(event) EQ 'VALUE', count)
  IF (count NE 0) THEN $
    (*(*info).dispparams).master_time = event.VALUE
  ; Reset timing offset to defaults
  (*(*info).dispparams).toffset_main = $
    (*(*info).dataparams).default_toffset_main
  (*(*info).dispparams).toffset_ref = (*(*info).dataparams).default_toffset_ref
  CRISPEX_COORDS_TRANSFORM_T, event, T_OLD=t_old, NT_OLD=nt_old
  CRISPEX_MASTER_TIME_UPDATE_CONTROLS, event, NO_DRAW=no_draw
END

FUNCTION CRISPEX_BGROUP_SAVE_IMREFSJI_LOOP, event
  WIDGET_CONTROL, event.TOP, GET_UVALUE = info
	IF (TOTAL(((*(*info).feedbparams).verbosity)[2:3]) GE 1) THEN $
    CRISPEX_VERBOSE_GET_ROUTINE, event
  (*(*info).savswitch).imrefsji[event.VALUE] = event.SELECT
  sens = (TOTAL((*(*info).savswitch).imrefsji) NE 1)
  wheresel = WHERE((*(*info).savswitch).imrefsji EQ 1)
  FOR i=0,TOTAL((*(*info).savswitch).imrefsji)-1 DO $
    WIDGET_CONTROL, (*(*info).ctrlsloop).save_imrefsji_ids[wheresel[i]], $
      SENSITIVE=sens, /SET_BUTTON 
	IF (((*(*info).feedbparams).verbosity)[3] EQ 1) THEN $
    CRISPEX_VERBOSE_GET, event, [TOTAL((*(*info).savswitch).imrefsji)],$
      labels=['Saving from cube setting']
END

FUNCTION CRISPEX_BGROUP_STOKES_SCALING_SELECT, event, NO_DRAW=no_draw, $
  MAINREF_SELECT=mainref_select, INFO=info
  IF (N_ELEMENTS(event) EQ 1) THEN BEGIN
	  WIDGET_CONTROL, event.TOP, GET_UVALUE = info
    mainref = event.VALUE
    scale_stokes = event.SELECT
	  IF (TOTAL(((*(*info).feedbparams).verbosity)[2:3]) GE 1) THEN $
      CRISPEX_VERBOSE_GET_ROUTINE, event
  ENDIF ELSE BEGIN
    ; If no event, then was called in setup, so by default scale_stokes = 1
    scale_stokes = 1
    mainref = KEYWORD_SET(MAINREF_SELECT)
  ENDELSE
  (*(*info).dispswitch).scalestokes[mainref] = scale_stokes
  CASE mainref OF
    0:  BEGIN
          IF ((*(*info).dispswitch).detspect_scale EQ 0) THEN $
            CRISPEX_DISPRANGE_LS_SCALE_MAIN, event, /OVERRIDE_SCALE, $
              /NO_UPDATE_TEXT
          IF scale_stokes THEN BEGIN
            scale_stokes_value = FLOAT((*(*info).dataparams).spec[$
              (*(*info).stokesparams).contpos[0],0]) 
            FOR s=1,(*(*info).dataparams).ns-1 DO BEGIN
              (*(*info).dataparams).spec[*,s] /= $
                REPLICATE(scale_stokes_value, (*(*info).dataparams).nlp)
              (*(*info).dataparams).ms[s] /= scale_stokes_value
            ENDFOR
          ENDIF ELSE BEGIN
            (*(*info).dataparams).spec = (*(*info).dataparams).spec_orig
            (*(*info).dataparams).ms = (*(*info).dataparams).ms_orig
          ENDELSE
          IF ((*(*info).dispswitch).detspect_scale EQ 0) THEN $
            CRISPEX_DISPRANGE_LS_SCALE_MAIN, event
        END
    1:  BEGIN
          IF ((*(*info).dispswitch).ref_detspect_scale EQ 0) THEN $
            CRISPEX_DISPRANGE_LS_SCALE_REF, event, /OVERRIDE_SCALE, $
              /NO_UPDATE_TEXT
          IF scale_stokes THEN BEGIN
            scale_stokes_value = FLOAT((*(*info).dataparams).refspec[$
              (*(*info).stokesparams).contpos[1],0]) 
            FOR s=1,(*(*info).dataparams).refns-1 DO BEGIN
              (*(*info).dataparams).refspec[*,s] /= $
                REPLICATE(scale_stokes_value, (*(*info).dataparams).refnlp)
              (*(*info).dataparams).refms[s] /= scale_stokes_value
            ENDFOR
          ENDIF ELSE BEGIN
            (*(*info).dataparams).refspec = (*(*info).dataparams).refspec_orig
            (*(*info).dataparams).refms = (*(*info).dataparams).refms_orig
          ENDELSE
          IF ((*(*info).dispswitch).ref_detspect_scale EQ 0) THEN $
            CRISPEX_DISPRANGE_LS_SCALE_REF, event
        END
  ENDCASE
  IF ~KEYWORD_SET(NO_DRAW) THEN CRISPEX_SCALING_STOKES_REDRAW, event, $
    MAINREF_SELECT=mainref
END

FUNCTION CRISPEX_BGROUP_STOKES_SELECT_SP, event, NO_DRAW=no_draw, $
  SET_BUTTONS=set_buttons
  WIDGET_CONTROL, event.TOP, GET_UVALUE=info
  COMPILE_OPT IDL2
	IF (TOTAL(((*(*info).feedbparams).verbosity)[2:3]) GE 1) THEN $
    CRISPEX_VERBOSE_GET_ROUTINE, event
  IF ((*(*info).stokesparams).mainref_select EQ 0) THEN BEGIN
    IF ~KEYWORD_SET(SET_BUTTONS) THEN BEGIN
    	(*(*info).stokesparams).prev_select_sp = (*(*info).stokesparams).select_sp
    	(*(*info).stokesparams).select_sp[WHERE((*(*info).stokesparams).labels EQ $
        (*(*info).stokesparams).button_labels[event.VALUE])] = $
                                          event.SELECT
    ENDIF
    select_sp = (*(*info).stokesparams).select_sp
    nselect_sp = TOTAL((*(*info).stokesparams).select_sp)
    (*(*info).stokesparams).nselect_sp = nselect_sp
    button_labels = (*(*info).stokesparams).button_labels
    labels = (*(*info).stokesparams).labels
    plot_noise = (*(*info).plotswitch).noise
    ns = (*(*info).dataparams).ns
    result = CRISPEX_PLOTAXES_UPDATE(nselect_sp,(*(*info).plotaxes).lsxticknames,$
      (*(*info).plotaxes).lsyticknames, (*(*info).plottitles).lsxtitles, $
      (*(*info).plottitles).lsytitles, (*(*info).plottitles).spxtitle, $
      (*(*info).plottitles).lsytitle, (*(*info).plottitles).lsdopxtitles, $
      (*(*info).plottitles).lsdopxtitle, (*(*info).intparams).ndiagnostics)
    (*(*info).plotaxes).lsxticknames = result.xticknames
    (*(*info).plotaxes).lsyticknames = result.yticknames
    (*(*info).plottitles).lsxtitles = result.xtitles
    (*(*info).plottitles).lsytitles = result.ytitles
    (*(*info).plottitles).lsdopxtitles = result.dopxtitles
  ENDIF ELSE BEGIN
    IF ~KEYWORD_SET(SET_BUTTONS) THEN BEGIN
    	(*(*info).stokesparams).prev_select_refsp = $
        (*(*info).stokesparams).select_refsp
    	(*(*info).stokesparams).select_refsp[$
        WHERE((*(*info).stokesparams).labels_ref EQ $
        (*(*info).stokesparams).button_labels[event.VALUE])] = $
                                          event.SELECT
    ENDIF
    select_sp = (*(*info).stokesparams).select_refsp
    nselect_sp = TOTAL((*(*info).stokesparams).select_refsp)
    (*(*info).stokesparams).nselect_refsp = nselect_sp
    button_labels = (*(*info).stokesparams).button_labels
    labels = (*(*info).stokesparams).labels_ref
    plot_noise = (*(*info).plotswitch).ref_noise
    ns = (*(*info).dataparams).refns
    result = CRISPEX_PLOTAXES_UPDATE(nselect_sp,(*(*info).plotaxes).reflsxticknames,$
      (*(*info).plotaxes).reflsyticknames, (*(*info).plottitles).reflsxtitles, $
      (*(*info).plottitles).reflsytitles, (*(*info).plottitles).refspxtitle, $
      (*(*info).plottitles).reflsytitle, (*(*info).plottitles).reflsdopxtitles, $
      (*(*info).plottitles).lsdopxtitle, (*(*info).intparams).nrefdiagnostics)
    (*(*info).plotaxes).reflsxticknames = result.xticknames
    (*(*info).plotaxes).reflsyticknames = result.yticknames
    (*(*info).plottitles).reflsxtitles = result.xtitles
    (*(*info).plottitles).reflsytitles = result.ytitles
    (*(*info).plottitles).reflsdopxtitles = result.dopxtitles
  ENDELSE
  ; Process settings
  ; Stokes parameter selected for detailed spectrum plot?
  wherestokes_sp = WHERE(select_sp EQ 1, count)
  IF (count GT 0) THEN $
	  stokes_sp_select = labels[wherestokes_sp] $
  ELSE $
	  stokes_sp_select = ''
  ; Total number of selected Stokes parameters for detailed spectrum plot?
  FOR i=0,N_ELEMENTS((*(*info).stokesparams).button_labels)-1 DO BEGIN
    ; Stokes parameter available in data?
    stokes_enabled = $
      (WHERE(labels EQ (*(*info).stokesparams).button_labels[i]) GE 0)
    ; Determine setting of buttons accordingly
    stokes_sp_set = (WHERE(stokes_sp_select EQ $
                    (*(*info).stokesparams).button_labels[i]) GE 0)
    WIDGET_CONTROL, (*(*info).ctrlscp).stokes_spbutton_ids[i], $
      SET_BUTTON=stokes_sp_set, $
      SENSITIVE=(stokes_enabled AND ((nselect_sp GT 1) OR $
                (nselect_sp AND ABS(stokes_sp_set-1))))
  ENDFOR
  WIDGET_CONTROL, (*(*info).ctrlscp).stokes_noise_button, $
    SET_BUTTON=(plot_noise AND (ns GT 1)), SENSITIVE=(ns GT 1)
  ; Redraw if necessary
  IF ~KEYWORD_SET(NO_DRAW) THEN BEGIN
    IF ((*(*info).stokesparams).mainref_select EQ 0) THEN BEGIN
      CRISPEX_UPDATE_SSP, event
  	  CRISPEX_DISPLAYS_LS_RESIZE, event, /STOKES_SELECT
    ENDIF ELSE BEGIN
      CRISPEX_UPDATE_REFSSP, event
  	  CRISPEX_DISPLAYS_REFLS_RESIZE, event, /STOKES_SELECT
    ENDELSE
  ENDIF
	IF (((*(*info).feedbparams).verbosity)[3] EQ 1) THEN $
    CRISPEX_VERBOSE_GET, event, [STRJOIN(((*(*info).stokesparams).labels)[$
      WHERE((*(*info).stokesparams).select_sp EQ 1)],', ')],$
        labels=['Stokes detspect selected']
END

FUNCTION CRISPEX_BGROUP_STOKES_SELECT_XY, event, NO_DRAW=no_draw, $
  SET_BUTTONS=set_buttons
  WIDGET_CONTROL, event.TOP, GET_UVALUE=info
	IF (TOTAL(((*(*info).feedbparams).verbosity)[2:3]) GE 1) THEN $
    CRISPEX_VERBOSE_GET_ROUTINE, event
  IF ~KEYWORD_SET(SET_BUTTONS) THEN BEGIN
    IF ((*(*info).stokesparams).mainref_select EQ 0) THEN BEGIN
      (*(*info).dataparams).s = $
        WHERE((*(*info).stokesparams).labels EQ $
          (*(*info).stokesparams).button_labels[event.VALUE])
    ENDIF ELSE BEGIN
      (*(*info).dataparams).s_ref = $
        WHERE((*(*info).stokesparams).labels_ref EQ $
          (*(*info).stokesparams).button_labels[event.VALUE])
    ENDELSE
    IF ~KEYWORD_SET(NO_DRAW) THEN BEGIN
      CRISPEX_SCALING_APPLY_SELECTED, event, $
        UPDATE_MAIN=((*(*info).stokesparams).mainref_select EQ 0), $
        UPDATE_REF=(*(*info).stokesparams).mainref_select
    	IF ((*(*info).stokesparams).mainref_select EQ $
          (*(*info).ctrlsswitch).imrefdetspect) THEN $
          CRISPEX_DISPLAYS_STOKES_SELECT_XY_RECOVER_YRANGE, event
    	CRISPEX_UPDATE_T, event
    	CRISPEX_UPDATE_SLICES, event, /NO_DRAW, $
        NO_PHIS=((*(*info).winswitch).showphis EQ 0), $
  		  SSP_UPDATE=(((*(*info).stokesparams).mainref_select EQ 0) AND $
                      ((*(*info).dataswitch).spfile EQ 0) AND $
                      (*(*info).winswitch).showls), $
        REFSSP_UPDATE=((*(*info).stokesparams).mainref_select AND $
                      ((*(*info).dataswitch).reffile EQ 1) AND $
                       ((*(*info).dataswitch).refspfile EQ 0) AND $
                        (*(*info).winswitch).showrefls) 
      IF (((*(*info).stokesparams).mainref_select EQ 0) AND $
          ((*(*info).winids).sptlb GT 0)) THEN BEGIN
        CRISPEX_DISPLAYS_SP_REPLOT_AXES, event
        CRISPEX_UPDATE_SPSLICE, event
      ENDIF
      IF ((*(*info).stokesparams).mainref_select AND $
          ((*(*info).winids).refsptlb GT 0)) THEN BEGIN
        CRISPEX_DISPLAYS_REFSP_REPLOT_AXES, event
        CRISPEX_UPDATE_REFSPSLICE, event
      ENDIF
      CRISPEX_DRAW_CTBAR, event, $
        MAIN=((*(*info).stokesparams).mainref_select EQ 0), $
        REFERENCE=(*(*info).stokesparams).mainref_select
  	  CRISPEX_DRAW, event
    ENDIF 
  ENDIF ELSE BEGIN
    IF ((*(*info).stokesparams).mainref_select EQ 0) THEN BEGIN
      labels = (*(*info).stokesparams).labels
      label_sel = labels[(*(*info).dataparams).s]
    ENDIF ELSE BEGIN
      labels = (*(*info).stokesparams).labels_ref
      label_sel = labels[(*(*info).dataparams).s_ref]
    ENDELSE
    FOR i=0,N_ELEMENTS((*(*info).stokesparams).button_labels)-1 DO BEGIN
      ; Stokes parameter available in data?
      stokes_enabled = $
        (WHERE(labels EQ (*(*info).stokesparams).button_labels[i]) GE 0)
      WIDGET_CONTROL, (*(*info).ctrlscp).stokes_button_ids[i], $
        SENSITIVE=stokes_enabled, $
        SET_BUTTON=(label_sel EQ (*(*info).stokesparams).button_labels[i])
    ENDFOR
  ENDELSE
END

FUNCTION CRISPEX_BGROUP_STOKES_SELECT_IMREF, event
  WIDGET_CONTROL, event.TOP, GET_UVALUE=info
	IF (TOTAL(((*(*info).feedbparams).verbosity)[2:3]) GE 1) THEN $
    CRISPEX_VERBOSE_GET_ROUTINE, event
  (*(*info).stokesparams).mainref_select = event.VALUE
  imbuttons = CRISPEX_BGROUP_STOKES_SELECT_XY(event, /NO_DRAW, /SET_BUTTONS)
  spbuttons = CRISPEX_BGROUP_STOKES_SELECT_SP(event, /NO_DRAW, /SET_BUTTONS)
  CRISPEX_SCALING_STOKES_CONTPOS, event, /NO_DRAW, /SET_VALUE
END

FUNCTION CRISPEX_BGROUP_LOOP_LINESTYLE, event, SESSION_RESTORE=session_restore
; Sets the display of restored loops to always (i.e. at all spectral positions)
; or selected (i.e. at saved positions)
	WIDGET_CONTROL, event.TOP, GET_UVALUE = info
	IF (TOTAL(((*(*info).feedbparams).verbosity)[2:3]) GE 1) THEN $
    CRISPEX_VERBOSE_GET_ROUTINE, event
  IF ~KEYWORD_SET(SESSION_RESTORE) THEN BEGIN
    ; Handle user input
    (*(*info).overlayparams).loop_linestyle = event.VALUE
	  CRISPEX_DRAW_IMREF, event
  ENDIF ELSE BEGIN
    ; Handle session restore; no draw
    FOR i=0,N_ELEMENTS((*(*info).ctrlscp).loop_linestyle_button_ids)-1 DO $
      WIDGET_CONTROL, (*(*info).ctrlscp).loop_linestyle_button_ids[i], $
      /SENSITIVE, SET_BUTTON=(i EQ (*(*info).overlayparams).loop_linestyle)
  ENDELSE
	IF (((*(*info).feedbparams).verbosity)[3] EQ 1) THEN $
    CRISPEX_VERBOSE_GET, event, [(*(*info).overlayparams).loop_linestyle], $
      labels=['Loop linestyle']
END

FUNCTION CRISPEX_BGROUP_LOOP_OVERLAY, event, SESSION_RESTORE=session_restore
; Handles setting of loop path linestyle 
	WIDGET_CONTROL, event.TOP, GET_UVALUE = info
	IF (TOTAL(((*(*info).feedbparams).verbosity)[2:3]) GE 1) THEN $
    CRISPEX_VERBOSE_GET_ROUTINE, event
  IF ~KEYWORD_SET(SESSION_RESTORE) THEN BEGIN
    ; Handle user input
  	(*(*info).overlayswitch).overlalways = ABS(event.VALUE-1)
  	IF ((*(*info).loopswitch).restore_loops EQ 0) THEN $
      CRISPEX_RESTORE_LOOPS_MAIN, event $
    ELSE $
      CRISPEX_DRAW, event
  ENDIF ELSE BEGIN
    ; Handle session restore; no draw
    WIDGET_CONTROL, (*(*info).ctrlscp).loop_overlay_button_ids[$
      ABS((*(*info).overlayswitch).overlalways-1)], /SET_BUTTON, $
      SENSITIVE=(*(*info).loopswitch).restore_loops
    WIDGET_CONTROL, (*(*info).ctrlscp).loop_overlay_button_ids[$
      (*(*info).overlayswitch).overlalways], $
      SENSITIVE=(*(*info).loopswitch).restore_loops
  ENDELSE
	IF (((*(*info).feedbparams).verbosity)[3] EQ 1) THEN $
    CRISPEX_VERBOSE_GET, event, [(*(*info).overlayswitch).overlalways], $
      labels=['Overlay loops always']
END

FUNCTION CRISPEX_BGROUP_MASK_OVERLAY, event
; Handles the change mask overlay window
	WIDGET_CONTROL, event.TOP, GET_UVALUE = info
	IF (TOTAL(((*(*info).feedbparams).verbosity)[2:3]) GE 1) THEN $
    CRISPEX_VERBOSE_GET_ROUTINE, event
	maskim = (*(*info).overlayswitch).maskim
	maskim[event.value] = event.select
	(*(*info).overlayswitch).maskim = maskim
	CRISPEX_DRAW, event
END

FUNCTION CRISPEX_BGROUP_RASTER_OVERLAY, event
; Handles the change raster overlay window
	WIDGET_CONTROL, event.TOP, GET_UVALUE = info
	IF (TOTAL(((*(*info).feedbparams).verbosity)[2:3]) GE 1) THEN $
    CRISPEX_VERBOSE_GET_ROUTINE, event
  CASE event.VALUE OF
    0:  (*(*info).overlayswitch).refraster = event.SELECT
    1:  (*(*info).overlayswitch).sjiraster = event.SELECT
  ENDCASE
	CRISPEX_DRAW, event, NO_REF=(event.VALUE NE 0), NO_SJI=(event.VALUE NE 1), $
    LS_NO_REF=(event.VALUE NE 0)
END

FUNCTION CRISPEX_BGROUP_RASTER_TIMING_OVERLAY, event
; Handles the change raster overlay window
	WIDGET_CONTROL, event.TOP, GET_UVALUE = info
	IF (TOTAL(((*(*info).feedbparams).verbosity)[2:3]) GE 1) THEN $
    CRISPEX_VERBOSE_GET_ROUTINE, event
    (*(*info).overlayswitch).rastertiming[event.VALUE] = event.SELECT
  CRISPEX_DRAW, event, NO_MAIN=(event.VALUE NE 0), NO_REF=(event.VALUE NE 1), $
    NO_SJI=(event.VALUE NE 2), LS_NO_MAIN=(event.VALUE NE 0), $
    LS_NO_REF=(event.VALUE NE 1)
END

FUNCTION CRISPEX_BGROUP_INT_SEL_ALLNONE, event
; Handles the change in plotting of selected diagnostics
	WIDGET_CONTROL, event.TOP, GET_UVALUE = info
	IF (TOTAL(((*(*info).feedbparams).verbosity)[2:3]) GE 1) THEN $
    CRISPEX_VERBOSE_GET_ROUTINE, event
  select_all = ABS(event.VALUE-1) ;  event.VALUE = 0: select all, 1: select none
  IF select_all THEN $
  	*(*(*info).intparams).seldisp_diagnostics = $
      REPLICATE(1,N_ELEMENTS(*(*(*info).intparams).seldisp_diagnostics)) $
  ELSE $
  	*(*(*info).intparams).seldisp_diagnostics = $
      REPLICATE(0,N_ELEMENTS(*(*(*info).intparams).seldisp_diagnostics))
	FOR i=0,N_ELEMENTS(*(*(*info).intparams).seldisp_diagnostics)-1 DO BEGIN
    btname = 'int_sel_bt_'+STRTRIM(i,2)   ; (De)select button name
    dgname = 'int_sel_dg_'+STRTRIM(i,2)   ; Diagnostics combobox name
    lpname = 'int_sel_lp_'+STRTRIM(i,2)   ; Wavelength combobox name
    lsname = 'int_sel_ls_'+STRTRIM(i,2)   ; Line-style combobox name
    clname = 'int_sel_cl_'+STRTRIM(i,2)   ; Color combobox name
		WIDGET_CONTROL, WIDGET_INFO(event.TOP, FIND_BY_UNAME=btname), $
      SET_BUTTON=select_all
		WIDGET_CONTROL, WIDGET_INFO(event.TOP, FIND_BY_UNAME=dgname), $
      SENSITIVE=select_all
		WIDGET_CONTROL, WIDGET_INFO(event.TOP, FIND_BY_UNAME=lpname), $
      SENSITIVE=select_all
		WIDGET_CONTROL, WIDGET_INFO(event.TOP, FIND_BY_UNAME=lsname), $
      SENSITIVE=select_all
		WIDGET_CONTROL, WIDGET_INFO(event.TOP, FIND_BY_UNAME=clname), $
      SENSITIVE=select_all
	ENDFOR		
	WIDGET_CONTROL, (*(*info).ctrlsint).int_sel_save, SENSITIVE=select_all
	CRISPEX_DRAW_INT, event
END

;------------------------- READ BMP BUTTONS FUNCTION
FUNCTION CRISPEX_READ_BMP_BUTTONS, filename, srcdir, DEFAULT=default
; Handles the reading of (button) BMP files
  IF FILE_TEST(srcdir+filename) THEN BEGIN
	  button_dummy = READ_BMP(srcdir+filename)  
	  button_dummy = TRANSPOSE(button_dummy, [1,2,0])
  ENDIF ELSE IF (N_ELEMENTS(DEFAULT) EQ 1) THEN $
    button_dummy = default $
  ELSE $
    button_dummy = 'N/A'
	RETURN, button_dummy
END


;------------------------- IO FUNCTIONS
FUNCTION CRISPEX_FITSPOINTER, filename, header, EXTEN_NO=exten_no, SILENT=silent
;	Finds starting position of data block in extension number exten_no in fits 
; files 
; Based on earlier FITSPOINTER.PRO, modification history:
;   v1.0 20-Sep-2012 Viggo Hansteen - first version
;   v1.1 27-Sep-2013 Mats Carlsson - added to CRISPEX directory
; Incorporated functionality into CRISPEX on 10-Oct-2013
  IF N_PARAMS() LT 1 THEN BEGIN
    MESSAGE,'fitspointer,filename ,header,exten_no=exten_no,silent=silent',/CONT
    RETURN,-1
  ENDIF
    
  doheader=ARG_PRESENT(header)
  IF N_ELEMENTS(exten_no) EQ 0 THEN exten_no=0L  
  silent=KEYWORD_SET(silent)

  OPENR, unit, filename, ERROR=error,/GET_LUN
  IF error NE 0 then begin
    MESSAGE,/CON,' ERROR - Unable to locate file ' + filename
    RETURN, -1
  ENDIF

;  Handle Unix or Fpack compressed files which will be opened via a pipe using
;  the SPAWN command. 
;  ViggoH 19092012: This piece of code can be uncommented at a later date if 
;   we want to include this capability...

  ;; if unixZ then begin
  ;;               free_lun, unit
  ;;               spawn, 'gzip -cd '+filename, unit=unit                 
  ;;               gzip = 1b
  ;; endif else if fcompress then begin 
  ;;               free_lun, unit
  ;;               spawn,'funpack -S ' + filename, unit=unit,/sh
  ;;               if eof(unit) then begin 
  ;;                 message,'Error spawning FPACK decompression',/CON
  ;;                 free_lun,unit
  ;;                 return,-1
  ;;                endif    
  ;;       endif   
  ;; endelse

  hbuf=36
  datapointer=0L

  FOR ext = 0L, exten_no DO BEGIN
               
;  Read the next header, and get the number of bytes taken up by the data.

    block = STRING(REPLICATE(32b,80,36))
    w = [-1]
    header = STRARR(36)
    headerblock = 0L
    i = 0L      

    WHILE w[0] EQ -1 DO BEGIN
      IF EOF(unit) THEN BEGIN 
            MESSAGE,/CON, $
               'EOF encountered attempting to read extension ' + STRTRIM(ext,2)
            FREE_LUN,unit
            RETURN,-1
      ENDIF

      READU, unit, block
      headerblock = headerblock + 1
      w = WHERE(STRLEN(block) NE 80, Nbad)
      IF (Nbad GT 0) THEN BEGIN
           MESSAGE,'Warning-Invalid characters in header',/INF,NoPrint=Silent
           block[w] = STRING(REPLICATE(32b, 80))
      ENDIF
      w = WHERE(STRCMP(block,'END     ',8), Nend)
      IF (headerblock EQ 1) || ((ext EQ exten_no) && (doheader)) THEN BEGIN
        IF Nend GT 0 THEN  BEGIN
          IF headerblock EQ 1 THEN header = block[0:w[0]]   $
          ELSE header = [header[0:i-1],block[0:w[0]]]
       ENDIF ELSE BEGIN
         header[i] = block
         i = i+36
         IF i MOD hbuf EQ 0 THEN header = [header,strarr(hbuf)]
       ENDELSE
      ENDIF
      datapointer=datapointer+2880L
    ENDWHILE

    IF (ext EQ 0 ) THEN $
      IF STRMID( header[0], 0, 8)  NE 'SIMPLE  ' THEN BEGIN
        MESSAGE,/CON, $
           'ERROR - Header does not contain required SIMPLE keyword'
      IF ~unitsupplied THEN FREE_LUN, unit
      RETURN, -1
    ENDIF
             
; Get parameters that determine size of data region.
                
    bitpix =  SXPAR(header,'BITPIX')
    byte_elem = ABS(bitpix)/8               ;Bytes per element
    naxis  = SXPAR(header,'NAXIS')
    gcount = SXPAR(header,'GCOUNT') > 1
    pcount = SXPAR(header,'PCOUNT')
                
    IF naxis GT 0 THEN BEGIN 
      dims = SXPAR( header,'NAXIS*')           ;Read dimensions
      ndata = PRODUCT(dims,/integer)
    ENDIF ELSE ndata = 0
                
    nbytes = byte_elem * gcount * (pcount + ndata)

;  Move to the next extension header in the file.   Use MRD_SKIP to skip with
;  fastest available method (POINT_LUN or readu) for different file
;  types (regular, compressed, Unix pipe, socket) 

    IF ext LT exten_no THEN BEGIN
      nrec = LONG64((nbytes + 2879) / 2880)
      IF nrec GT 0 THEN mrd_skip, unit, nrec*2880L
      datapointer=datapointer+nrec*2880L    
   ENDIF
  ENDFOR

  CASE BITPIX OF 
           8:   IDL_type = 1          ; Byte
          16:   IDL_type = 2          ; Integer*2
          32:   IDL_type = 3          ; Integer*4
          64:   IDL_type = 14         ; Integer*8
         -32:   IDL_type = 4          ; Real*4
         -64:   IDL_type = 5          ; Real*8
        ELSE:   BEGIN
                MESSAGE,/CON, 'ERROR - Illegal value of BITPIX (= ' +  $
                STRTRIM(bitpix,2) + ') in FITS header'
                IF ~unitsupplied THEN FREE_LUN,unit
                RETURN, -1
                END
  ENDCASE     
 
  IF nbytes EQ 0 THEN BEGIN
    IF ~SILENT THEN MESSAGE, $
         "FITS header has NAXIS or NAXISi = 0,  no data array read",/CON
    FREE_LUN, unit
    RETURN,-1
  ENDIF

  IF exten_no GT 0 THEN BEGIN
    xtension = STRTRIM( SXPAR( header, 'XTENSION' , Count = N_ext),2)
    IF N_ext EQ 0 THEN MESSAGE, /INF, NoPRINT = Silent, $
          'WARNING - Header missing XTENSION keyword'
  ENDIF 

  IF ~SILENT THEN BEGIN   ;Print size of array being read
    IF exten_no GT 0 THEN MESSAGE, $
             'Reading FITS extension of type ' + xtension, /INF  
    IF N_elements(dims) EQ 1 THEN $
        st = 'Now reading ' + STRTRIM(dims,2) + ' element vector' ELSE $                 
        st = 'Now reading ' + STRJOIN(STRTRIM(dims,2),' by ') + ' array'
        IF (exten_no GT 0) && (pcount GT 0) THEN st = st + ' + heap area'
        MESSAGE,/INF,st   
  ENDIF
  FREE_LUN, unit
  RETURN,datapointer  
END

FUNCTION CRISPEX_TAG_DELETE, Structure, Tags, VERBOSE=verbose
  ; Deletes Tags from Structure
  ntags = N_ELEMENTS(Tags) 
  IF (ntags GE 1) THEN BEGIN
    tagnames = TAG_NAMES(Structure)
    seltags = REPLICATE(1,N_ELEMENTS(tagnames))
    ; Check where the tags are located and set select array to 0 correspondingly
    FOR i=0,ntags-1 DO BEGIN
      wheretag = WHERE(STRLOWCASE(tagnames) EQ STRLOWCASE(tags[i]), count)
      IF (count NE 0) THEN BEGIN
        seltags[wheretag] = 0
        IF KEYWORD_SET(VERBOSE) THEN $
          MESSAGE, tags[i]+' found. Excluding from structure.',/INFO
      ENDIF ELSE IF KEYWORD_SET(VERBOSE) THEN $
          MESSAGE, tags[i]+' not found in structure. Skipping tag.', /INFO
    ENDFOR
    seltags = WHERE(seltags EQ 1)
    nseltags = N_ELEMENTS(seltags)
    ; Loop over remainder of tags and reconstruct the structure
    FOR i=0,nseltags-1 DO BEGIN
      IF (i NE 0) THEN $
        newstructure = CREATE_STRUCT(newstructure, $
          tagnames[seltags[i]], structure.(seltags[i])) $
      ELSE $
        newstructure = CREATE_STRUCT(tagnames[seltags[i]], $
                        structure.(seltags[i]))
    ENDFOR
  ENDIF
  RETURN, newstructure
END


;------------------------- LOOP GET FUNCTION
FUNCTION CRISPEX_GET_PATH, xp_in, yp_in, np_in, nx_in, ny_in
  xp_out = xp_in  & yp_out = yp_in
  ; If this function is called and number of elements is 1, that means the
  ; coordinates are out of range
  IF (N_ELEMENTS(xp_out) NE 1) THEN BEGIN
    ; Interpolate the points with ~1 pixel separation
  	SPLINE_P, xp_out, yp_out, xr_out, yr_out, INTERVAL=1
    xyp_out_of_range = $
      ((xp_out[np_in-1] LT 0) OR $
       (xp_out[np_in-1] GE nx_in) OR $
       (yp_out[np_in-1] LT 0) OR $
       (yp_out[np_in-1] GE ny_in))
  ENDIF ELSE BEGIN
    xr_out = xp_out
    yr_out = yp_out
    xyp_out_of_range = 1
  ENDELSE
  result = {xp:xp_out, yp:yp_out, xr:xr_out, yr:yr_out, $
            xyp_out_of_range:xyp_out_of_range}
  RETURN, result
END

;------------------------- MAIN/REF BLINK FUNCTION
FUNCTION CRISPEX_GET_IMREF_BLINK_BOUNDS, pix_main2ref, pix_ref2main, $
  xlow_main, xupp_main, ylow_main, yupp_main, $
  xlow_ref, xupp_ref, ylow_ref, yupp_ref
  ; Determine the main/reference blink window parameters
  ; Get main boundaries in terms of reference coordinate system
  xylow_main2ref = REFORM(pix_main2ref[*,xlow_main,ylow_main])
  xyupp_main2ref = REFORM(pix_main2ref[*,xupp_main,yupp_main])
  ; Get reference boundaries in terms of main coordinate system
  xylow_ref2main = REFORM(pix_ref2main[*,xlow_ref,ylow_ref])
  xyupp_ref2main = REFORM(pix_ref2main[*,xupp_ref,yupp_ref])
  ; Create index array for main on ref
  xref_selarray = INDGEN(xyupp_main2ref[0]-xylow_main2ref[0]+1)+$
                    xylow_main2ref[0]
  yref_selarray = INDGEN(xyupp_main2ref[1]-xylow_main2ref[1]+1)+$
                    xylow_main2ref[1]
  ; Create index array for ref on main
  x_selarray = INDGEN(xyupp_ref2main[0]-xylow_ref2main[0]+1)+$
                xylow_ref2main[0]
  y_selarray = INDGEN(xyupp_ref2main[1]-xylow_ref2main[1]+1)+$
                xylow_ref2main[1]
  ; Select elements within range
  xref_selarray = xref_selarray[$
                    WHERE((xref_selarray GE xlow_ref) AND $
                          (xref_selarray LE xupp_ref))]
  yref_selarray = yref_selarray[$
                    WHERE((yref_selarray GE ylow_ref) AND $
                          (yref_selarray LE yupp_ref))]
  x_selarray = x_selarray[$
                WHERE((x_selarray GE xlow_main) AND $
                      (x_selarray LE xupp_main))]
  y_selarray = y_selarray[$ 
                WHERE((y_selarray GE ylow_main) AND $
                      (y_selarray LE yupp_main))]
  ; Get boundaries
  x_main = [x_selarray[0],$
            x_selarray[N_ELEMENTS(x_selarray)-1]]
  y_main = [y_selarray[0],$
            y_selarray[N_ELEMENTS(y_selarray)-1]]
  x_ref = [xref_selarray[0],$
            xref_selarray[N_ELEMENTS(xref_selarray)-1]]
  y_ref = [yref_selarray[0],$
            yref_selarray[N_ELEMENTS(yref_selarray)-1]]
  ; Write and return results
  result = {x_main:x_main, y_main:y_main, x_ref:x_ref, y_ref:y_ref, $
    nx_sel:N_ELEMENTS(xref_selarray), ny_sel:N_ELEMENTS(yref_selarray)}
  RETURN, result
END

;------------------------- WARP FUNCTION
FUNCTION CRISPEX_GET_WARP, lps, nlp, ts, nt
  min_lps = MIN(lps, /NAN, wheremin_lps, SUBSCRIPT_MAX=wheremax_lps)
  nlparr = FINDGEN(nlp)
  ; Failsafe against decreasing lps arrays
  IF (wheremin_lps GT wheremax_lps) THEN nlparr = REVERSE(nlparr)
  ; Failsafe against single-scan data
  IF (nt EQ 1) THEN BEGIN
    nt_tmp = nt+1 
    yi = REPLICATE(1,nlp) # FINDGEN(nt_tmp)
    yo = yi
  ENDIF ELSE BEGIN
    nt_tmp = nt
    min_ts = MIN(ts, /NAN, wheremin_ts, SUBSCRIPT_MAX=wheremax_ts)
    yi = TRANSPOSE(REBIN(FINDGEN(nt_tmp), nt_tmp, nlp))
    yo = TRANSPOSE(REBIN(((ts-min_ts) / FLOAT(MAX(ts-min_ts, /NAN)) * (nt_tmp-1)), $
      nt_tmp, nlp))
  ENDELSE
  ; Determine input and output tie points
  xi = REBIN(nlparr, nlp, nt_tmp)
  xo = REBIN(((lps-min_lps) / FLOAT(MAX(lps-min_lps, /NAN)) * (nlp-1)), $
    nlp, nt_tmp)

  ; Do the triangulation: Functionality taken from IDL's WARP_TRI - needed to
  ; prevent too many calls to slow TRIANGULATE procedure
  gs = [1,1]				        ;Grid spacing
  b = [0,0, nlp-1, nt_tmp-1]			;Bounds
  ; Triangulate given the input and output tie points
  TRIANGULATE, xo, yo, tr, bounds
  xtri = TRIGRID(xo, yo, xi, tr, gs, b) ;, /QUINTIC)
  ytri = TRIGRID(xo, yo, yi, tr, gs, b) ;, /QUINTIC)
  IF (nt EQ 1) THEN BEGIN
    xtri = xtri[*,0]  &   ytri = ytri[*,0]
    xo = xo[*,0]      &   yo = yo[*,0]
    xi = xi[*,0]      &   yi = yi[*,0]
  ENDIF
  
  ; Return results
  RETURN, {xtri:xtri, ytri:ytri, xi:xi, yi:yi, xo:xo, yo:yo}
END

;------------------------- SCALING FUNCTIONS
FUNCTION CRISPEX_SCALING_CONTRAST, minimum_init, maximum_init, $
  minimum_perc, maximum_perc
  minimum_init = DOUBLE(minimum_init)
  maximum_init = DOUBLE(maximum_init)
  range = maximum_init-minimum_init
  minmax = [minimum_init+range*FLOAT(minimum_perc)/100.,$
            minimum_init+range*FLOAT(maximum_perc)/100.]
  RETURN, minmax
END

FUNCTION CRISPEX_SCALING_SLICES, dispim, gamma_val, histo_opt_val, $
  default_min, default_max, FORCE_HISTO=force_histo
  IF (gamma_val NE 1) THEN BEGIN
    whereneg = WHERE(dispim LT 0, nwhereneg)
    IF (nwhereneg GT 0) THEN BEGIN
      dispim = (TEMPORARY(ABS(dispim)))^gamma_val
      dispim[whereneg] *= -1.
    ENDIF ELSE $
      dispim = (TEMPORARY((dispim)))^gamma_val
  ENDIF
  IF ((histo_opt_val NE 0) OR KEYWORD_SET(FORCE_HISTO)) THEN BEGIN
    IF (MIN(dispim, MAX=dispmax, /NAN) NE dispmax) THEN BEGIN
      dispim = IRIS_HISTO_OPT(dispim, histo_opt_val, MISSING=-32768, /SILENT)
    ENDIF
  ENDIF
  minimum = MIN(dispim,MAX=maximum, /NAN)
  IF ((N_ELEMENTS(default_min) EQ 1) AND (N_ELEMENTS(default_max) EQ 1)) THEN $
    minmax = CRISPEX_SCALING_CONTRAST(minimum,maximum,$
      default_min, default_max) $
  ELSE $
    minmax = [minimum,maximum]
  RETURN, minmax
END

FUNCTION CRISPEX_SCALING_DESCALE, data, bscale, bzero
  missing = WHERE(data EQ -32768,count)
  floatdata = FLOAT(data)*bscale+bzero
  IF (count GT 0) THEN floatdata[missing] = !VALUES.F_NAN
  RETURN, floatdata
END

;------------------------- SLIDER FUNCTION
FUNCTION CRISPEX_SLIDER_LP_DIAG, event, lp_diag, REFERENCE=reference, $
  BLINK=blink, OVERRIDE_DIAGNOSTIC=override_diagnostic
	WIDGET_CONTROL, event.TOP, GET_UVALUE = info
	IF (TOTAL(((*(*info).feedbparams).verbosity)[2:3]) GE 1) THEN $
    CRISPEX_VERBOSE_GET_ROUTINE, event
  IF KEYWORD_SET(REFERENCE) THEN BEGIN
    disp_diag = WHERE((*(*info).intparams).disp_refdiagnostics EQ 1)
    lp = (*(*info).dataparams).lp_ref
    diag_start = (*(*info).intparams).refdiag_start[disp_diag]
    lp_low_bounds = (*(*info).dispparams).lp_ref_low_bounds[disp_diag]
    lp_upp_bounds = (*(*info).dispparams).lp_ref_upp_bounds[disp_diag]
  ENDIF ELSE BEGIN
    disp_diag = WHERE((*(*info).intparams).disp_diagnostics EQ 1)
    IF KEYWORD_SET(BLINK) THEN $
      lp = (*(*info).pbparams).lp_blink $
    ELSE $
      lp = (*(*info).dataparams).lp
    diag_start = (*(*info).intparams).diag_start[disp_diag]
    lp_low_bounds = (*(*info).dispparams).lp_low_bounds[disp_diag]
    lp_upp_bounds = (*(*info).dispparams).lp_upp_bounds[disp_diag]
  ENDELSE
  ; Determine boundary crossed
  diff_low_bounds = lp_low_bounds - lp
  diff_upp_bounds = lp_upp_bounds - lp
  diff_diag_start = diag_start - lp 
  dist_low_bounds = MIN(ABS(diff_low_bounds), where_dist_low_bounds)
  dist_upp_bounds = MIN(ABS(diff_upp_bounds), where_dist_upp_bounds)
  dist_diag_start = MIN(ABS(diff_diag_start), where_dist_diag_start)
  dists_min = [dist_diag_start, dist_low_bounds, dist_upp_bounds]
  where_min = [where_dist_diag_start, where_dist_low_bounds, $
                where_dist_upp_bounds]
  min_dist = MIN(dists_min, where_min_dist)
  IF KEYWORD_SET(OVERRIDE_DIAGNOSTIC) THEN BEGIN
    CASE where_min_dist OF 
      0:  BEGIN ; Crossed diag start
            ; Crossed from below 
            IF (diff_diag_start[where_dist_diag_start] LT $
              diff_low_bounds[where_dist_diag_start]) THEN BEGIN
              lp_diag_new = disp_diag[lp_diag]
              lp_new = lp_low_bounds[WHERE(disp_diag EQ lp_diag_new)]
            ENDIF ELSE BEGIN
              lp_diag_new = disp_diag[lp_diag]
              lp_new = lp_upp_bounds[WHERE(disp_diag EQ lp_diag_new)]
            ENDELSE
          END
      1:  BEGIN ; Crossed lower boundary
            where_cur_lp_diag = WHERE(disp_diag EQ disp_diag[lp_diag])
            new_idx = (where_cur_lp_diag - 1) MOD N_ELEMENTS(disp_diag)
            IF (new_idx LT 0) THEN new_idx = N_ELEMENTS(disp_diag)-1
            lp_diag_new = disp_diag[new_idx]
            lp_new = lp_upp_bounds[new_idx]
          END
      2:  BEGIN ; Crossed upper boundary
            where_cur_lp_diag = WHERE(disp_diag EQ disp_diag[lp_diag])
            new_idx = (where_cur_lp_diag + 1) MOD N_ELEMENTS(disp_diag)
            lp_diag_new = disp_diag[new_idx]
            lp_new = lp_low_bounds[new_idx]
          END
    ENDCASE
  ENDIF ELSE BEGIN
    ; Accessed when dragging slider
    ; If distance to lower boundary is closer, jump there
    IF (dists_min[1] LT dists_min[2]) THEN BEGIN
      lp_diag_new = disp_diag[where_min[1]]
      lp_new = lp_low_bounds[WHERE(disp_diag EQ lp_diag_new)]
    ENDIF ELSE BEGIN
      lp_diag_new = disp_diag[where_min[2]]
      lp_new = lp_upp_bounds[WHERE(disp_diag EQ lp_diag_new)]
    ENDELSE
  ENDELSE

  ; Create result structure and return
  result = {lp_diag_new:lp_diag_new, lp_new:lp_new}
  RETURN, result
END

;------------------------- PLOTAXES FUNCTION
FUNCTION CRISPEX_PLOTAXES_UPDATE, nselect_sp, xticknames, yticknames, $
  xtitles, ytitles, xtitle_default, ytitle_default, dopxtitles, $
  dopxtitle_default, ndiagnostics
  CASE nselect_sp OF
    1:  BEGIN
          *xticknames[0] = ''
          xtitles[0] = xtitle_default
          ytitles[0] = ytitle_default
        END
    2:  BEGIN
          *xticknames[0] = ''
          *xticknames[1] = ''
          xtitles[0:1] = xtitle_default
          ytitles[0] = ytitle_default
          ytitles[1] = ''
        END
    3:  BEGIN
          *xticknames[0] = REPLICATE(' ',60)
          *xticknames[1] = ''
          *xticknames[2] = ''
          xtitles[0] = ''
          ytitles[1] = ''
          xtitles[1:2] = xtitle_default
          ytitles[[0,2]] = ytitle_default
        END
    4:  BEGIN
          *xticknames[0] = REPLICATE(' ',60)
          *xticknames[1] = REPLICATE(' ',60)
          *xticknames[2] = ''
          xtitles[0:1] = ''
          ytitles[[1,3]] = ''
          xtitles[2:3] = xtitle_default
          ytitles[[0,2]] = ytitle_default
        END
  ENDCASE
  IF ((nselect_sp GT 1) OR (ndiagnostics GT 1)) THEN $
    dopxtitles = [dopxtitle_default,' '] $
  ELSE $
    dopxtitles = [' ',dopxtitle_default]

  result = {xticknames:xticknames, yticknames:yticknames, $
    xtitles:xtitles, ytitles:ytitles, dopxtitles:dopxtitles}
  RETURN, result
END

FUNCTION CRISPEX_PLOTAXES_XTICKVALS_SELECT, xtickvals_in, TICKSEP=ticksep, $
  DOPPLER=doppler
  ; Mark every TICKSEP-th major tickmark, if total # < TICKSEP: mark the $
  ; middle one
  IF (N_ELEMENTS(TICKSEP) NE 1) THEN ticksep = 4.
  nxtickvals = N_ELEMENTS(xtickvals_in)
  nticks_select = FLOOR(nxtickvals/ticksep+1) > 1
  IF KEYWORD_SET(DOPPLER) THEN BEGIN
    whereeq0 = WHERE(xtickvals_in EQ 0., count)
    IF (count GT 0) THEN $
      wheremiddle = whereeq0[0] $
    ELSE $
      wheremiddle = FLOOR(nxtickvals/2.)
  ENDIF ELSE $
    wheremiddle = FLOOR(nxtickvals/2.)
  ; Check whether able to fit multiple major tickmarks
  IF ((wheremiddle GT ticksep/2.) OR $
    (KEYWORD_SET(DOPPLER) AND (nticks_select GT 1))) THEN BEGIN
    diffarray = INDGEN(nxtickvals)*ticksep
    ; Select tickmarks centred on middle, but excluding middle (unless Doppler)
    diffarray -= diffarray[wheremiddle];-ticksep/2.
    IF ~KEYWORD_SET(DOPPLER) THEN diffarray -= ticksep/2.
    selarray = (INDGEN(nxtickvals))[wheremiddle] + diffarray
    whereselarray = WHERE((selarray GE 0) AND (selarray LT nxtickvals), count)
    IF (count GT 0) THEN $
      whereselect = selarray[whereselarray] $
    ELSE $
      whereselect = wheremiddle
  ENDIF ELSE $
    whereselect = wheremiddle
  xtickvals_tmp = REPLICATE(' ',nxtickvals)
  ; Determine output format from input format
  xtickvals_in = STRTRIM(xtickvals_in,2)
  ; Assuming all xtick_get values are formatted equally
  decimal_switch = (N_ELEMENTS(STRSPLIT(xtickvals_in[0],'.',/EXTRACT)) EQ 2)
  split_array = STRARR(nxtickvals,2)
  FOR i=0,nxtickvals-1 DO $
    split_array[i,*] = STRSPLIT(xtickvals_in[i],'.',/EXTRACT)
  ; Get number of digits left of period
  IF KEYWORD_SET(DOPPLER) THEN $;BEGIN
    min_splitarray = MIN(split_array[*,0],MAX=max_splitarray)
  ; Get number of decimals
  IF decimal_switch THEN BEGIN
    done = 0
    check_array = split_array[*,1]
    maxlen = MAX(STRLEN(check_array))
    wherenotmax = WHERE(STRLEN(check_array) NE maxlen, count)
    IF (count NE 0) THEN BEGIN
      add_array = maxlen-STRLEN(check_array)
      FOR i=0,nxtickvals-1 DO BEGIN
        IF (add_array[i] NE 0) THEN $
          check_array[i] = check_array[i]+STRJOIN(REPLICATE('0',add_array[i]))
      ENDFOR
    ENDIF
    WHILE (done EQ 0) DO BEGIN
      strpos_array = STRPOS(check_array,'0',/REVERSE_SEARCH)  
      IF ((N_ELEMENTS(strpos_array[UNIQ(strpos_array)]) EQ 1) AND $
        (MAX(STRLEN(check_array)) GT 0)) THEN $
        check_array = STRMID(check_array,0,strpos_array[0]) $
      ELSE $
        done = 1
    ENDWHILE
    ndecimals = STRLEN(check_array[0])
  ENDIF ELSE ndecimals = 0
  IF (ndecimals GT 0) THEN $
    xtick_format ='(F'+STRTRIM(STRLEN(split_array[whereselect,0])+$
      ndecimals+(ndecimals GT 0),2)+'.'+STRTRIM(ndecimals,2)+')' $
  ELSE $
    xtick_format ='(I'+STRTRIM(STRLEN(split_array[whereselect,0]),2)+')'
  FOR i=0,N_ELEMENTS(whereselect)-1 DO $
    xtickvals_tmp[whereselect[i]] = STRING(xtickvals_in[whereselect[i]],$
      FORMAT=xtick_format[i])
  xtickvals_out = [xtickvals_tmp,REPLICATE(' ',60-nxtickvals)]
  RETURN, xtickvals_out
END

FUNCTION CRISPEX_PLOTAXES_XDOPTICKLOC, xdoptickvals_orig, sel_criterion, $
  vdop_xrange, plot_xrange
  ; Determine Doppler tick mark locations
  xdopticksel = xdoptickvals_orig[sel_criterion]
  vdoprange = vdop_xrange[1]-vdop_xrange[0]
  xdoptickloc = (xdopticksel - vdop_xrange[0])/vdoprange * $
    (plot_xrange[1]-plot_xrange[0]) + plot_xrange[0]
  RETURN, xdoptickloc
END

;------------------------- WIDGET FUNCTION
FUNCTION CRISPEX_WIDGET_DIVIDER, base
  divider_base = WIDGET_BASE(base, /FRAME, /YSIZE)
  divider_labl = WIDGET_LABEL(divider_base, VALUE=' ')
  RETURN, divider_base
END

;------------------------- SPLIT MESSAGE FUNCTION
FUNCTION CRISPEX_SPLIT_MSG, message1, max_text_width
  message_split = STRSPLIT(message1, ' ', /EXTRACT)
  message_split += ' '  ; Add whitespace after each substring
  k = 0L
  i = 0L 
  total_length_left = STRLEN(message1)+1
  WHILE (total_length_left GT 0) DO BEGIN
    length_left = max_text_width
    substr_reconstr = ''
    WHILE ((length_left GT 0) AND (total_length_left GT 0)) DO BEGIN
      substr_reconstr = substr_reconstr+message_split[i]
      length_left -= STRLEN(message_split[i])
      total_length_left -= STRLEN(message_split[i])
      i += 1L
    ENDWHILE
    IF (k EQ 0) THEN $
      final_msg = substr_reconstr $
    ELSE $
      final_msg = [final_msg,substr_reconstr]
    k += 1L
  ENDWHILE
  RETURN, final_msg
END

;------------------------- MISCELLANEOUS FUNCTIONS
FUNCTION CRISPEX_CURSOR_GET_XY, event, x_tmp, y_tmp
	WIDGET_CONTROL, event.TOP, GET_UVALUE=info
	IF (TOTAL(((*(*info).feedbparams).verbosity)[2:3]) GE 1) THEN $
    CRISPEX_VERBOSE_GET_ROUTINE, event
  ; Get temporary data coordinates from temporary device coordinates
  IF (*(*info).dataswitch).sjifile THEN BEGIN
    idx_sji = (WHERE((*(*info).winids).sjidrawid EQ $
      (*(*info).winids).current_wid, count))[0] 
    IF (count EQ 0) THEN idx_sji = 0
  ENDIF ELSE $
    idx_sji = 0
  xy_tmp = CRISPEX_TRANSFORM_DATA2DEVICE(info, X=x_tmp, Y=y_tmp, $
    MAIN=(((*(*info).winids).current_wid EQ (*(*info).winids).xydrawid) OR $
          ((*(*info).winids).current_wid EQ (*(*info).winids).imrefdrawid) OR $
          ((*(*info).winids).current_wid EQ (*(*info).winids).dopdrawid)), $
    REFERENCE=((*(*info).winids).current_wid EQ (*(*info).winids).refdrawid), $
    SJI=((*(*info).winids).current_wid EQ (*(*info).winids).sjidrawid[idx_sji]), $
    /INVERSE, IDX_SJI=idx_sji)
  
  result = [xy_tmp.x, xy_tmp.y, idx_sji]

  RETURN, result
END

FUNCTION CRISPEX_GET_RGB_TABLE, event, TABLE_NAME=table_name, IRIS=iris, $
  SDO=sdo, SET_CT_CBOX=set_ct_cbox, CT_SEL=ct_sel
  IF (N_ELEMENTS(event) EQ 1) THEN $
	  WIDGET_CONTROL, event.TOP, GET_UVALUE=info
  IF KEYWORD_SET(IRIS) THEN $
      IRIS_LCT, table_name, r, g, b, /NOLOAD 
  IF KEYWORD_SET(SDO) THEN BEGIN
    ; Failsafe conversions for HMI channels
    IF (table_name EQ 'continuum') THEN $
      table_name = 6173 $
    ELSE IF (table_name EQ 'B_LOS') THEN $
      table_name = 1
    AIA_LCT, r, g, b, WAVE=FIX(table_name)
  ENDIF
    rgb_table = [[r], [g], [b]] 
  IF KEYWORD_SET(SET_CT_CBOX) THEN BEGIN
    IF (N_ELEMENTS(CT_SEL) NE 1) THEN ct_sel = 1
    IF KEYWORD_SET(IRIS) THEN $
      ct_idx_cbox = (WHERE((*(*info).plotparams).ct_iris_names EQ table_name))[0]
    IF KEYWORD_SET(SDO) THEN $
      ct_idx_cbox = (WHERE((*(*info).plotparams).ct_sdo_names EQ table_name))[0]+$
        N_ELEMENTS((*(*info).plotparams).ct_iris_names)*$
        ((*(*info).plotparams).ct_iris_names[0] NE '')
    (*(*info).plotparams).imct[ct_sel] = $
      N_ELEMENTS((*(*info).plotparams).ct_idl_names)+ct_idx_cbox
    ; Set the dropdown only if currently displaying the options for that window
    IF ((*(*info).plotparams).imct_select-1 EQ ct_sel) THEN $
      WIDGET_CONTROL, (*(*info).ctrlscp).displays_ct_cbox, $
        SET_COMBOBOX_SELECT=(*(*info).plotparams).imct[ct_sel]+1, /SENSITIVE
  ENDIF
  RETURN, rgb_table
END

FUNCTION CRISPEX_GET_PLOTPOS, ns, winx, margin, wall, V_DOP_SET=v_dop_set
  ; Get detailed spectrum plot positions
  ; Determine number of panels for detailed spectrum window
	IF (ns LE 2) THEN BEGIN
		npanels = ns	&	ncols = ns	&	rowarr = REPLICATE(0,ns)
	ENDIF ELSE BEGIN
		npanels = 4	&	ncols = 2	&	rowarr = [1,1,0,0]
	ENDELSE
	nrows = CEIL(npanels / FLOAT(ncols))
  halfmargin = margin / 2.
  ; Determine plot width and height, and consequent window height
	width = (1. - ((ncols-1)*halfmargin + margin + wall))/FLOAT(ncols)
	height 	= width * 2D / (1 + SQRT(5))
  winy = (nrows*height + (1 + KEYWORD_SET(V_DOP_SET))*margin + ((nrows-1) + $
    ABS(KEYWORD_SET(V_DOP_SET)-1)) * wall) * winx
  
  ; Determine plot positions
	x0 	= margin + (INDGEN(npanels) MOD ncols) * (width + halfmargin) 
	x1 	= x0 + width 
	y0   = (margin + rowarr*(height + wall)) * winx/winy
	y1 	= y0 + height * winx/winy

  x0_all = MIN(x0)  &   x1_all = MAX(x1)
  y0_all = MIN(y0)  &   y1_all = MAX(y1)

  result = {x0:x0, x1:x1, y0:y0, y1:y1, width:width, height:height, winy:winy, $
    x0_all:x0_all, x1_all:x1_all, y0_all:y0_all, y1_all:y1_all}

  RETURN, result
END

;========================= PROCEDURES

;========================= ABOUT WINDOW PROCEDURES
PRO CRISPEX_ABOUT_WINDOW, event 							
; Creates an about-window displaying code name, version and revision number
	WIDGET_CONTROL, event.TOP, GET_UVALUE=info
	IF (TOTAL(((*(*info).feedbparams).verbosity)[2:3]) GE 1) THEN $
    CRISPEX_VERBOSE_GET_ROUTINE, event
	title = 'CRISPEX'+(*(*info).sesparams).instance_label+': ABOUT'
	CRISPEX_WINDOW, (*(*info).winsizes).aboutwinx, (*(*info).winsizes).aboutwiny,$
    (*(*info).winids).root, title, abouttlb, aboutwid, $
    (*(*info).winsizes).aboutxoffset, (*(*info).winsizes).aboutyoffset, $
		DRAWID=aboutdrawid, DRAWBASE=aboutdrawbase
  button_base = WIDGET_BASE(aboutdrawbase, /GRID_LAYOUT, COLUMN=2, $
    /ALIGN_CENTER)
  close_button = WIDGET_BUTTON(button_base, VALUE='Close', $
    EVENT_PRO='CRISPEX_ABOUT_CLOSE')
  (*(*info).ctrlsabout).relnotes_button = $
    WIDGET_BUTTON(button_base, VALUE='   Release notes   ', $
    EVENT_PRO='CRISPEX_ABOUT_RELEASE_INFO')
	WIDGET_CONTROL, abouttlb, SET_UVALUE=info
	XMANAGER, 'CRISPEX', abouttlb,/NO_BLOCK
	(*(*info).winids).abouttlb = abouttlb
  (*(*info).winids).aboutwid = aboutwid
  CRISPEX_ABOUT_RELEASE_INFO, event, /SET_VERINFO
	IF (((*(*info).feedbparams).verbosity)[3] EQ 1) THEN $
    CRISPEX_VERBOSE_GET, event, [(*(*info).winids).abouttlb], $
      labels=['abouttlb']
END

PRO CRISPEX_ABOUT_CLOSE, event
; Handles closing the About window
	WIDGET_CONTROL, event.TOP, GET_UVALUE=info
	IF (TOTAL(((*(*info).feedbparams).verbosity)[2:3]) GE 1) THEN $
    CRISPEX_VERBOSE_GET_ROUTINE, event
	WIDGET_CONTROL, (*(*info).winids).abouttlb, /DESTROY
	(*(*info).winids).abouttlb = 0
END

PRO CRISPEX_ABOUT_RELEASE_INFO, event, SET_VERINFO=set_verinfo
	WIDGET_CONTROL, event.TOP, GET_UVALUE=info
	IF (TOTAL(((*(*info).feedbparams).verbosity)[2:3]) GE 1) THEN $
    CRISPEX_VERBOSE_GET_ROUTINE, event
  IF KEYWORD_SET(SET_VERINFO) THEN $
    (*(*info).feedbparams).relnotes = 0 $
  ELSE $
    (*(*info).feedbparams).relnotes = $
      ABS((*(*info).feedbparams).relnotes - event.SELECT)
  IF (*(*info).feedbparams).relnotes THEN BEGIN
    relnotes_file = (*(*info).paths).dir_resources+'relnotes.txt'
    IF FILE_TEST(relnotes_file) THEN BEGIN
      nlines = FILE_LINES(relnotes_file)
    	lines = STRARR(1,nlines)
    	OPENR,unit,relnotes_file,/GET_LUN
    	READF,unit,lines
    	FREE_LUN,unit
      textarr = $
        ['CRISPEX version '+(*(*info).versioninfo).version_number+$
        ' ('+(*(*info).versioninfo).revision_number+') release notes:',$
        REFORM(lines)]
    ENDIF ELSE $
      textarr = 'No release notes available for CRISPEX version '+$
        (*(*info).versioninfo).version_number+$
      ' ('+(*(*info).versioninfo).revision_number+').'
    WIDGET_CONTROL, (*(*info).ctrlsabout).relnotes_button, $
      SET_VALUE='Version info'
  ENDIF ELSE BEGIN
	  textarr = $
      ['CRISPEX version '+(*(*info).versioninfo).version_number+$
      ' ('+(*(*info).versioninfo).revision_number+')','',$
	  	'Developed by: Gregal Vissers', $
      '               Institute for Solar Physics, Stockholm University',$
      '               2016-2018',$
      '                        ',$
	  	'               Institute of Theoretical Astrophysics,',$
	  	'               University of Oslo',$
	  	'               2009-2016']
    WIDGET_CONTROL, (*(*info).ctrlsabout).relnotes_button, $
      SET_VALUE='Release notes'
  ENDELSE
  WSET, (*(*info).winids).aboutwid
  CRISPEX_UPDATE_STARTUP_FEEDBACK, (*(*info).feedbparams).startup_im, $
    (*(*info).feedbparams).xout, (*(*info).feedbparams).yout, $
    textarr
END

;========================= CLEAR ESTIMATE PROCEDURES
PRO CRISPEX_CLEAR_CURRENT_ESTIMATE, event								
; Clears current saving time estimate
	WIDGET_CONTROL, event.TOP, GET_UVALUE = info
	IF (TOTAL(((*(*info).feedbparams).verbosity)[2:3]) GE 1) THEN $
    CRISPEX_VERBOSE_GET_ROUTINE, event
	IF (*(*info).feedbparams).estimate_run THEN BEGIN
		(*(*info).feedbparams).estimate_lx = 0
		(*(*info).feedbparams).estimate_time = 0.
		(*(*info).feedbparams).estimate_run = 0
		WIDGET_CONTROL, (*(*info).ctrlscp).clear_current_estimate, SENSITIVE = 0
	ENDIF
END

PRO CRISPEX_CLEAR_CURRENT_CPFT, event								
; Clears current saving time estimate
	WIDGET_CONTROL, event.TOP, GET_UVALUE = info
	IF (TOTAL(((*(*info).feedbparams).verbosity)[2:3]) GE 1) THEN $
    CRISPEX_VERBOSE_GET_ROUTINE, event
	pftfiles = FILE_SEARCH((*(*info).paths).dir_settings+'crispex.'+$
    (*(*info).paths).hostname+'cpft', COUNT = pftfilecount)
	IF (((*(*info).feedbparams).verbosity)[3] EQ 1) THEN $
    CRISPEX_VERBOSE_GET, event, ['crispex.'+(*(*info).paths).hostname+'cpft',$
      pftfilecount], labels=['File to be deleted','Filecount']
	IF pftfilecount THEN BEGIN
    FILE_DELETE, (*(*info).paths).dir_settings+'crispex.'+$
      (*(*info).paths).hostname+'cpft', /QUIET
		(*(*info).feedbparams).estimate_lx = 0
		(*(*info).feedbparams).estimate_time = 0.
		(*(*info).feedbparams).estimate_run = 0
		WIDGET_CONTROL, (*(*info).ctrlscp).clear_current_estimate, SENSITIVE = 0
	ENDIF ELSE BEGIN
		CRISPEX_WINDOW_OK, event,'ERROR!','Could not delete crispex.'+$
      ((*(*info).paths).hostname)[0]+'cpft '+$
      'from '+(*(*info).paths).dir_settings+'. File does not exist.',$
			OK_EVENT='CRISPEX_CLOSE_EVENT_WINDOW', BASE=tlb
		(*(*info).winids).errtlb = tlb
	ENDELSE
END

PRO CRISPEX_CLEAR_CURRENT_INST, event								
; Clears current saving time estimate
	WIDGET_CONTROL, event.TOP, GET_UVALUE = info
	IF (TOTAL(((*(*info).feedbparams).verbosity)[2:3]) GE 1) THEN $
    CRISPEX_VERBOSE_GET_ROUTINE, event
	instfiles = FILE_SEARCH((*(*info).paths).dir_settings+'crispex.'+$
    (*(*info).paths).hostname+'inst', COUNT = instfilecount)
	IF (((*(*info).feedbparams).verbosity)[3] EQ 1) THEN $
    CRISPEX_VERBOSE_GET, event, ['crispex.'+(*(*info).paths).hostname+'inst',$
      instfilecount], labels=['File to be deleted','Filecount']
	IF instfilecount THEN BEGIN
		FILE_DELETE, (*(*info).paths).dir_settings+'crispex.'+$
      (*(*info).paths).hostname+'inst', /QUIET
		(*(*info).feedbparams).estimate_lx = 0
		(*(*info).feedbparams).estimate_time = 0.
		(*(*info).feedbparams).estimate_run = 0
		WIDGET_CONTROL, (*(*info).ctrlscp).clear_current_inst, SENSITIVE = 0
	ENDIF ELSE BEGIN
		CRISPEX_WINDOW_OK, event,'ERROR!','Could not delete crispex.'+$
      ((*(*info).paths).hostname)[0]+$
      'inst from '+(*(*info).paths).dir_settings+'. File does not exist.',$
			OK_EVENT='CRISPEX_CLOSE_EVENT_WINDOW', BASE=tlb
		(*(*info).winids).errtlb = tlb
	ENDELSE
END
;========================= PROGRAM EXIT PROCEDURES
PRO CRISPEX_CLOSE, event								
; Called upon closing program, checks for existence of performance test file; 
; if not present it is written
	WIDGET_CONTROL, event.TOP, GET_UVALUE = info
	IF (TOTAL(((*(*info).feedbparams).verbosity)[2:3]) GE 1) THEN $
    CRISPEX_VERBOSE_GET_ROUTINE, event
	IF ((*(*info).paths).dir_settings_write EQ 1) THEN BEGIN
		pftfiles = FILE_SEARCH((*(*info).paths).dir_settings+'crispex.'+$
      (*(*info).paths).hostname+'cpft', COUNT = pftfilecount)
		IF (pftfilecount EQ 0) AND $
        ((*(*info).feedbparams).estimate_run EQ 1) THEN BEGIN
			estimate_lx = (*(*info).feedbparams).estimate_lx
			estimate_time = (*(*info).feedbparams).estimate_time
			estimate_run = (*(*info).feedbparams).estimate_run
			SAVE, estimate_lx, estimate_time, estimate_run, $
        FILENAME=(*(*info).paths).dir_settings+'crispex.'+$
          (*(*info).paths).hostname+'cpft'
			PRINT,'Written: '+(*(*info).paths).dir_settings+'crispex.'+$
        (*(*info).paths).hostname+'cpft'
		ENDIF
    ; Save as latest session
    CRISPEX_SESSION_SAVE, event, 'crispex_last_session', $
      /LAST_SESSION
	ENDIF ELSE BEGIN
		PRINT, 'ERROR: Could not write performance file crispex.'+$
      (*(*info).paths).hostname+'cpft '
		PRINT, '       to '+(*(*info).paths).dir_settings+'. Permission denied.'
	ENDELSE
  CRISPEX_CLOSE_FREE_LUN, (*(*info).data).lunim, (*(*info).data).lunsp, $
    (*(*info).data).lunrefim, (*(*info).data).lunrefsp, $
    (*(*info).data).lunmask, (*(*info).data).lunsji, /IMDISP, $
    SPDISP=(*(*info).dataswitch).spfile, $
    REFIMDISP=((*(*info).dataswitch).reffile AND ((*(*info).data).lunrefim GT 0)),$
    REFSPDISP=((*(*info).dataswitch).refspfile AND ((*(*info).data).lunrefsp GT 0)),$
    MASKDISP=((*(*info).dataswitch).maskfile AND ((*(*info).data).lunmask GT 0)),$
	  SJIDISP=((*(*info).dataswitch).sjifile AND ((*(*info).data).lunsji GT 0))
	WIDGET_CONTROL, (*(*info).winids).root, /DESTROY
	PTR_FREE, info
END

PRO CRISPEX_CLOSE_CLEANUP, base								
; Clean-up upon closing program
	WIDGET_CONTROL, base, GET_UVALUE = info
  CRISPEX_CLOSE_FREE_LUN, (*(*info).data).lunim, (*(*info).data).lunsp, $
    (*(*info).data).lunrefim, (*(*info).data).lunrefsp, (*(*info).data).lunmask, $
    (*(*info).data).lunsji, /IMDISP, SPDISP=(*(*info).dataswitch).spfile, $
    REFIMDISP=((*(*info).dataswitch).reffile AND ((*(*info).data).lunrefim GT 0)),$
    REFSPDISP=((*(*info).dataswitch).refspfile AND ((*(*info).data).lunrefsp GT 0)),$
    MASKDISP=((*(*info).dataswitch).maskfile AND ((*(*info).data).lunmask GT 0)),$
	  SJIDISP=((*(*info).dataswitch).sjifile AND ((*(*info).data).lunsji GT 0))
	CRISPEX_CLOSE_CLEAN_INSTANCE_FILE, (*(*info).paths).dir_settings_write, $
  (*(*info).paths).dir_settings, (*(*info).paths).hostname, ((*(*info).sesparams).curr_instance_id)[0]
	PTR_FREE, info
END

PRO CRISPEX_CLOSE_FREE_LUN, lunim, lunsp, lunrefim, lunrefsp, lunmask, lunsji, $
  IMDISP=imdisp, SPDISP=spdisp, REFIMDISP=refimdisp, REFSPDISP=refspdisp, $
  MASKDISP=maskdisp, SJIDISP=sjidisp
  IF KEYWORD_SET(IMDISP) THEN FREE_LUN, lunim
  IF KEYWORD_SET(SPDISP) THEN FREE_LUN, lunsp
  IF KEYWORD_SET(REFIMDISP) THEN FREE_LUN, lunrefim
  IF KEYWORD_SET(REFSPDISP) THEN FREE_LUN, lunrefsp
  IF KEYWORD_SET(MASKDISP) THEN FREE_LUN, lunmask
  IF KEYWORD_SET(SJIDISP) THEN BEGIN
    FOR i=0,N_ELEMENTS(lunsji)-1 DO BEGIN
      IF (lunsji[i] NE 0) THEN FREE_LUN, lunsji[i]
    ENDFOR
  ENDIF
END

PRO CRISPEX_CLOSE_CLEAN_INSTANCE_FILE, dir_inst_write, dir_inst, hostname, curr_instance_id
; Called upon closing program, checks for existence of performance test file; if not 
; present it is written
	IF (dir_inst_write EQ 1) THEN BEGIN
		instfile = FILE_SEARCH(dir_inst+'crispex.'+hostname+'inst', COUNT = instfilecount)
		IF instfilecount THEN BEGIN
			nlines = (FILE_LINES(instfile))[0]
			datarr = STRARR(1,nlines)
			OPENR,unit1,instfile,/GET_LUN
			READF,unit1,datarr
			FREE_LUN,unit1
			routine_name = STRARR(nlines)
			instance_id = LONARR(nlines)
			FOR i=1,nlines-1 DO BEGIN
				splitline = STRSPLIT(datarr[i],'	',/EXTRACT)
				routine_name[i] = splitline[0]
				instance_id[i] = splitline[3]
			ENDFOR
			where_crispex = WHERE(routine_name EQ 'CRISPEX', count)
      IF (count GT 0) THEN BEGIN    ; Only clean if CRISPEX instance in file
  			sel_instance_id = instance_id[where_crispex]
  			clean_line = WHERE(sel_instance_id EQ curr_instance_id)+1
  			first_part = datarr[0:(clean_line-1)]
  			IF (clean_line NE (nlines-1)) THEN BEGIN
  				last_part = datarr[(clean_line+1):(nlines-1)] 
  				rewritten_arr = [first_part,last_part]
  			ENDIF ELSE rewritten_arr = first_part
  			OPENW, unit, instfile[0], WIDTH = 360, /GET_LUN
  			FOR i=0,nlines-2 DO PRINTF, unit,rewritten_arr[i]
      ENDIF
			FREE_LUN, unit
		ENDIF
	ENDIF
END

PRO CRISPEX_CLOSE_EVENT_WINDOW, event
; Called upon closing window when no extra processes need to be run
	WIDGET_CONTROL, event.TOP, GET_UVALUE = info
	IF (TOTAL(((*(*info).feedbparams).verbosity)[2:3]) GE 1) THEN $
    CRISPEX_VERBOSE_GET_ROUTINE, event
	IF (event.TOP EQ (*(*info).winids).savewintlb) THEN BEGIN
		(*(*info).winids).savewintlb = 0
		IF ((*(*info).winids).saveoptwintlb GT 0) THEN BEGIN
			WIDGET_CONTROL, (*(*info).winids).saveoptwintlb,/DESTROY
			(*(*info).winids).saveoptwintlb = 0
		ENDIF
	ENDIF
	IF (event.TOP EQ (*(*info).winids).saveoptwintlb) THEN (*(*info).winids).saveoptwintlb = 0
	IF (event.TOP EQ (*(*info).winids).abouttlb) THEN (*(*info).winids).abouttlb = 0
	IF (event.TOP EQ (*(*info).winids).errtlb) THEN (*(*info).winids).errtlb = 0
	IF (event.TOP EQ (*(*info).winids).warntlb) THEN (*(*info).winids).warntlb = 0
  IF (event.TOP EQ (*(*info).winids).shorttlb) THEN (*(*info).winids).shorttlb = 0
  IF (event.TOP EQ (*(*info).winids).headertlb) THEN (*(*info).winids).headertlb = 0
	WIDGET_CONTROL, event.TOP, /DESTROY
END

;========================= CURSOR PROCEDURES
PRO CRISPEX_CURSOR, event								
; Cursor handling procedure, tracks and handles events from the cursor on the 
; image windows
; Variable definitions: window draw variables are preceded by an 's', e.g., sx
; and sxr; these correspond to data variables x and xr respectively.
	WIDGET_CONTROL, event.TOP, GET_UVALUE = info
	IF (TOTAL(((*(*info).feedbparams).verbosity)[2:3]) GE 1) THEN $
    CRISPEX_VERBOSE_GET_ROUTINE, event, /IGNORE_LAST
	IF TAG_NAMES(event, /STRUCTURE_NAME) EQ 'WIDGET_TRACKING' THEN BEGIN
		IF event.ENTER THEN BEGIN
			WIDGET_CONTROL, event.HANDLER, GET_VALUE=wid
			WSET, wid
			DEVICE, CURSOR_IMAGE=(*(*info).curs).image, $
        CURSOR_MASK=(*(*info).curs).mask, CURSOR_XY=[7,7] 
		ENDIF ELSE BEGIN
      ; Upon exiting the draw window...
			IF (((*(*info).loopparams).np GE 1) AND $
           (*(*info).overlayswitch).looppath_feedback AND $
           ((*(*info).curs).lockset GT 0)) THEN $
           CRISPEX_LOOP_REMOVE_POINT, event, /CURSOR_ACTION
			IF (!D.WINDOW NE -1) THEN DEVICE, /CURSOR_CROSSHAIR
		ENDELSE
  	IF (((*(*info).feedbparams).verbosity)[3] EQ 1) THEN $
      CRISPEX_VERBOSE_GET, event, $
        [event.ENTER], labels=['WIDGET_TRACKING: event.Enter']
	ENDIF ELSE IF TAG_NAMES(event, /STRUCTURE_NAME) EQ 'WIDGET_DRAW' THEN BEGIN
    ; Else while in draw window, handle actions (mouse move or (un)lock by mouse
    ; button actions) 
    ; Determine window the mouse is in
    (*(*info).winids).current_wid = event.ID
    IF (*(*info).curs).panselect THEN BEGIN
		  CASE event.TYPE OF
		  0:	CASE event.PRESS OF
		  	1:	BEGIN	; left mouse button press -> locks cursor to location
		  			(*(*info).curs).lockset = 1
            CRISPEX_CURSOR_LOCKBUTTON_SET, event
            ; Convert device to actual data coordinates
            CRISPEX_CURSOR_SET_XY, event, event.X, event.Y
            ; Set lock variables for main
		  			(*(*info).curs).sxlock = (*(*info).curs).sx
		  			(*(*info).curs).sylock = (*(*info).curs).sy
		  			(*(*info).curs).xlock = (*(*info).dataparams).x
		  			(*(*info).curs).ylock = (*(*info).dataparams).y
            ; If reference present, set lock variables for reference
            IF ((*(*info).winids).reftlb NE 0) THEN BEGIN
              (*(*info).curs).xreflock = (*(*info).dataparams).xref
              (*(*info).curs).yreflock = (*(*info).dataparams).yref
              (*(*info).curs).sxreflock = (*(*info).curs).sxref
              (*(*info).curs).syreflock = (*(*info).curs).syref
            ENDIF
            IF (TOTAL((*(*info).winids).sjitlb) NE 0) THEN BEGIN
              FOR i=0,(*(*info).winswitch).nwhereshowsji-1 DO BEGIN
                idx_sji = (*(*(*info).winswitch).whereshowsji)[i]
                (*(*info).curs).xsjilock[idx_sji] = (*(*info).dataparams).xsji[idx_sji]
                (*(*info).curs).ysjilock[idx_sji] = (*(*info).dataparams).ysji[idx_sji]
                (*(*info).curs).sxsjilock[idx_sji] = (*(*info).curs).sxsji[idx_sji]
                (*(*info).curs).sysjilock[idx_sji] = (*(*info).curs).sysji[idx_sji]
              ENDFOR
            ENDIF
            ; If drawing path, set parameters accordingly
		  			IF (*(*info).overlayswitch).loopslit THEN BEGIN
              ; Increase number of fixed path positions by 1
              (*(*info).loopparams).np += 1
              (*(*info).loopparams).np_ref += ((*(*info).winswitch).showref EQ 1)
              (*(*info).loopparams).np_sji += $
                (TOTAL((*(*info).winswitch).showsji) GE 1)
		  				IF (((*(*info).loopparams).np GE 2) OR $
                  ((*(*info).loopparams).np_ref GE 2) OR $
                  ((*(*info).loopparams).np_sji GE 2)) THEN BEGIN
                WIDGET_CONTROL, (*(*info).ctrlscp).loop_slit_but, $
                  SET_VALUE = 'Erase path'
                ; If adjusting of main path has not been disabled and it is indeed
                ; a main path position that has been added, add variables
		  				  IF ((*(*info).loopparams).np GE 2) THEN BEGIN
  	  						*(*(*info).loopparams).xp = $
                    [*(*(*info).loopparams).xp,(*(*info).curs).xlock]
  	  						*(*(*info).loopparams).yp = $
                    [*(*(*info).loopparams).yp,(*(*info).curs).ylock]
                ENDIF
                ; If adjusting of reference path has not been disabled and it is
                ; indeed a reference path position that has been added, add
                ; variables 
                IF ((*(*info).winswitch).showref AND $
		  				      ((*(*info).loopparams).np_ref GE 2)) THEN BEGIN
  	  						*(*(*info).loopparams).xp_ref = $
                    [*(*(*info).loopparams).xp_ref,(*(*info).curs).xreflock]
  	  						*(*(*info).loopparams).yp_ref = $
                    [*(*(*info).loopparams).yp_ref,(*(*info).curs).yreflock]
                ENDIF
                IF ((TOTAL((*(*info).winswitch).showsji) GT 0) AND $
		  				      ((*(*info).loopparams).np_sji GE 2)) THEN BEGIN
                  FOR i=0,(*(*info).winswitch).nwhereshowsji-1 DO BEGIN
                    idx_sji = (*(*(*info).winswitch).whereshowsji)[i]
      							*(*(*info).loopparams).xp_sji[idx_sji] = $
                      [*(*(*info).loopparams).xp_sji[idx_sji],$
                      (*(*info).curs).xsjilock[idx_sji]]
      							*(*(*info).loopparams).yp_sji[idx_sji] = $
                      [*(*(*info).loopparams).yp_sji[idx_sji],$
                      (*(*info).curs).ysjilock[idx_sji]]
                  ENDFOR
                ENDIF
		  					CRISPEX_LOOP_GET, event, /ADD
		  					CRISPEX_UPDATE_LP, event, /NO_LOOP_GET
                WIDGET_CONTROL, (*(*info).ctrlscp).loop_slice_but, $
                  SENSITIVE=((*(*info).winids).looptlb EQ 0)
                WIDGET_CONTROL, (*(*info).ctrlscp).rem_loop_pt_but, $
                  SENSITIVE=(((*(*info).loopparams).np GE 3) OR $
                             ((*(*info).loopparams).np_ref GE 3))
		  				ENDIF ELSE BEGIN
                ; If cursor position not out of range, set first path coordinate
  	  					(*(*(*info).loopparams).xp)[0] = (*(*info).curs).xlock
  	  					(*(*(*info).loopparams).yp)[0] = (*(*info).curs).ylock
  	  					(*(*(*info).overlayparams).sxp)[0] = (*(*info).curs).sxlock
  	  					(*(*(*info).overlayparams).syp)[0] = (*(*info).curs).sylock
                IF (*(*info).winswitch).showref THEN BEGIN
  	  						(*(*(*info).loopparams).xp_ref)[0] = (*(*info).curs).xreflock
  	  						(*(*(*info).loopparams).yp_ref)[0] = (*(*info).curs).yreflock
  	  						(*(*(*info).overlayparams).sxp_ref)[0] = (*(*info).curs).sxreflock
  	  						(*(*(*info).overlayparams).syp_ref)[0] = (*(*info).curs).syreflock
                ENDIF
                IF (TOTAL((*(*info).winswitch).showsji) GT 0) THEN BEGIN
                  FOR i=0,(*(*info).winswitch).nwhereshowsji-1 DO BEGIN
                    idx_sji = (*(*(*info).winswitch).whereshowsji)[i]
  	  				  		*(*(*info).loopparams).xp_sji[idx_sji] = $
                      (*(*info).curs).xsjilock[idx_sji]
  	  				  		*(*(*info).loopparams).yp_sji[idx_sji] = $
                      (*(*info).curs).ysjilock[idx_sji]
  	  				  		*(*(*info).overlayparams).sxp_sji[idx_sji] = $
                      (*(*info).curs).sxsjilock[idx_sji]
  	  				  		*(*(*info).overlayparams).syp_sji[idx_sji] = $
                      (*(*info).curs).sysjilock[idx_sji]
                  ENDFOR
                ENDIF
		  				ENDELSE
		  			ENDIF
            ; If taking spatial measurement, set parameters accordingly
		  			IF (*(*info).meas).spatial_measurement THEN BEGIN
		  				(*(*info).meas).np = 1
		  				(*(*(*info).meas).xp) = (*(*info).curs).xlock
		  				(*(*(*info).meas).yp) = (*(*info).curs).ylock
		  				(*(*(*info).meas).sxp) = (*(*info).curs).sxlock
		  				(*(*(*info).meas).syp) = (*(*info).curs).sylock 
              IF (*(*info).winswitch).showref THEN BEGIN
  	  					(*(*(*info).meas).xp_ref) = (*(*info).curs).xreflock
  	  					(*(*(*info).meas).yp_ref) = (*(*info).curs).yreflock
  	  					(*(*(*info).meas).sxp_ref) = (*(*info).curs).sxreflock
  	  					(*(*(*info).meas).syp_ref) = (*(*info).curs).syreflock 
              ENDIF
              IF (TOTAL((*(*info).winswitch).showsji) GT 0) THEN BEGIN
                FOR i=0,(*(*info).winswitch).nwhereshowsji-1 DO BEGIN
                  idx_sji = (*(*(*info).winswitch).whereshowsji)[i]
      						*(*(*info).meas).xp_sji[idx_sji] = $
                    (*(*info).curs).xsjilock[idx_sji]
      						*(*(*info).meas).yp_sji[idx_sji] = $
                    (*(*info).curs).ysjilock[idx_sji]
      						*(*(*info).meas).sxp_sji[idx_sji] = $
                    (*(*info).curs).sxsjilock[idx_sji]
      						*(*(*info).meas).syp_sji[idx_sji] = $
                   (*(*info).curs).sysjilock[idx_sji] 
                ENDFOR
              ENDIF
		  			ENDIF
		  			CRISPEX_COORDSLIDERS_SET, 1, 1, event
		  		END
		  	2:	BEGIN	; middle mouse button press -> set second point of measurement
		  			IF ((*(*info).meas).spatial_measurement AND $
               ((*(*info).meas).np LT 2)) THEN BEGIN
              CRISPEX_CURSOR_SET_XY, event, event.X, event.Y
		  				(*(*info).meas).np = 2
		  				*(*(*info).meas).xp = $
                [(*(*(*info).meas).xp)[0],(*(*info).dataparams).x]	
		  				*(*(*info).meas).yp = $
                [(*(*(*info).meas).yp)[0],(*(*info).dataparams).y]	
		  				*(*(*info).meas).sxp = $
                [(*(*(*info).meas).sxp)[0],(*(*info).curs).sx]	
		  				*(*(*info).meas).syp = $
                [(*(*(*info).meas).syp)[0],(*(*info).curs).sy]
              IF (*(*info).winswitch).showref THEN BEGIN
  	  					*(*(*info).meas).xp_ref = $
                  [(*(*(*info).meas).xp_ref)[0],(*(*info).dataparams).xref]	
  	  					*(*(*info).meas).yp_ref = $
                  [(*(*(*info).meas).yp_ref)[0],(*(*info).dataparams).yref]	
  	  					*(*(*info).meas).sxp_ref = $
                  [(*(*(*info).meas).sxp_ref)[0],(*(*info).curs).sxref]	
  	  					*(*(*info).meas).syp_ref = $
                  [(*(*(*info).meas).syp_ref)[0],(*(*info).curs).syref]
              ENDIF
              IF (TOTAL((*(*info).winswitch).showsji) GT 0) THEN BEGIN
                FOR i=0,(*(*info).winswitch).nwhereshowsji-1 DO BEGIN
                  idx_sji = (*(*(*info).winswitch).whereshowsji)[i]
  	  					  *(*(*info).meas).xp_sji[idx_sji] = $
                    [(*(*(*info).meas).xp_sji[idx_sji])[0],(*(*info).dataparams).xsji[idx_sji]]	
  	  					  *(*(*info).meas).yp_sji[idx_sji] = $
                    [(*(*(*info).meas).yp_sji[idx_sji])[0],(*(*info).dataparams).ysji[idx_sji]]	
  	  					  *(*(*info).meas).sxp_sji[idx_sji] = $
                    [(*(*(*info).meas).sxp_sji[idx_sji])[0],(*(*info).curs).sxsji[idx_sji]]	
  	  					  *(*(*info).meas).syp_sji[idx_sji] = $
                    [(*(*(*info).meas).syp_sji[idx_sji])[0],(*(*info).curs).sysji[idx_sji]]
                ENDFOR
              ENDIF
		  				CRISPEX_COORDSLIDERS_SET, 1, 1, event
		  				CRISPEX_MEASURE_CALC, event
		  			ENDIF
		  		END
		  	4:	BEGIN	; right mouse button press -> release locked cursor
            IF ((*(*info).overlayswitch).loopslit EQ 0) THEN BEGIN
  	  				(*(*info).curs).lockset = 0
              CRISPEX_MEASURE_ENABLE, event, /DISABLE
            ENDIF
		  		END
		  	ELSE: BREAK
		  	ENDCASE
		  2:	BEGIN	; mouse movement
          ; If cursor isn't locked, adjust coordinate sliders
		  		IF ((*(*info).curs).lockset EQ 0) THEN BEGIN
            CRISPEX_CURSOR_SET_XY, event, event.X, event.Y
		  			CRISPEX_COORDSLIDERS_SET, 1, 1, event 
          ; Else if drawing path, adjust path feedback if path has been started in
          ; either main window (np>=1) or reference window (np_ref>=1)
		  		ENDIF ELSE IF ((*(*info).overlayswitch).loopslit AND $
                         (*(*info).overlayswitch).looppath_feedback AND $
                         (((*(*info).loopparams).np GE 1) OR $
                          ((*(*info).loopparams).np_ref GE 1) OR $
                          ((*(*info).loopparams).np_sji GE 1))) THEN BEGIN
            CRISPEX_CURSOR_SET_XY, event, event.X, event.Y
            ; Get new paths with current cursor coordinate
            IF ((*(*info).loopparams).np GE 1) THEN BEGIN
	          	*(*(*info).loopparams).xpdisp = $
                [(*(*(*info).loopparams).xp)[0:(*(*info).loopparams).np-1],$
                                            (*(*info).dataparams).x]
	          	*(*(*info).loopparams).ypdisp = $
                [(*(*(*info).loopparams).yp)[0:(*(*info).loopparams).np-1],$
                                            (*(*info).dataparams).y]
            ENDIF
            ; If np_ref>=1, add current coordinate to xyp_ref and compute path
            IF ((*(*info).winswitch).showref AND $
              (*(*info).loopparams).np_ref GE 1) THEN BEGIN
	          	*(*(*info).loopparams).xpdisp_ref = $
                [(*(*(*info).loopparams).xp_ref)[0:(*(*info).loopparams).np_ref-1],$
                                            (*(*info).dataparams).xref]
	          	*(*(*info).loopparams).ypdisp_ref = $
                [(*(*(*info).loopparams).yp_ref)[0:(*(*info).loopparams).np_ref-1],$
                                            (*(*info).dataparams).yref]
            ENDIF
            IF ((TOTAL((*(*info).winswitch).showsji) GT 0) AND $
		  		      ((*(*info).loopparams).np_sji GE 1)) THEN BEGIN
              FOR i=0,(*(*info).winswitch).nwhereshowsji-1 DO BEGIN
                idx_sji = (*(*(*info).winswitch).whereshowsji)[i]
	          	  *(*(*info).loopparams).xpdisp_sji[idx_sji] = $
                  [(*(*(*info).loopparams).xp_sji[idx_sji])[$
                    0:(*(*info).loopparams).np_sji-1],$
                    (*(*info).dataparams).xsji[idx_sji]]
	          	  *(*(*info).loopparams).ypdisp_sji[idx_sji] = $
                  [(*(*(*info).loopparams).yp_sji[idx_sji])[$
                    0:(*(*info).loopparams).np_sji-1],$
                    (*(*info).dataparams).ysji[idx_sji]]
              ENDFOR
            ENDIF
            CRISPEX_LOOP_GET_PATH, event, /MAIN, /REFERENCE, /SJI
		  			CRISPEX_COORDSLIDERS_SET, 1, 1, event
          ; Else if drawing measurement, adjust measurement feedback
		  		ENDIF ELSE IF ((*(*info).meas).spatial_measurement AND $
                        ((*(*info).meas).np EQ 1)) THEN BEGIN
            CRISPEX_CURSOR_SET_XY, event, event.X, event.Y
		  			*(*(*info).meas).xp = [(*(*(*info).meas).xp)[0],$
              (*(*info).dataparams).x]	
		  			*(*(*info).meas).yp = [(*(*(*info).meas).yp)[0],$
              (*(*info).dataparams).y]	
		  			*(*(*info).meas).sxp = [(*(*(*info).meas).sxp)[0],(*(*info).curs).sx]	
		  			*(*(*info).meas).syp = [(*(*(*info).meas).syp)[0],(*(*info).curs).sy]
            IF (*(*info).winswitch).showref THEN BEGIN
		  				*(*(*info).meas).xp_ref = $
                [(*(*(*info).meas).xp_ref)[0],(*(*info).dataparams).xref]	
		  				*(*(*info).meas).yp_ref = $
                [(*(*(*info).meas).yp_ref)[0],(*(*info).dataparams).yref]	
		  				*(*(*info).meas).sxp_ref = $
                [(*(*(*info).meas).sxp_ref)[0],(*(*info).curs).sxref]	
		  				*(*(*info).meas).syp_ref = $
                [(*(*(*info).meas).syp_ref)[0],(*(*info).curs).syref]
            ENDIF
            IF (TOTAL((*(*info).winswitch).showsji) GT 0) THEN BEGIN
              FOR i=0,(*(*info).winswitch).nwhereshowsji-1 DO BEGIN
                idx_sji = (*(*(*info).winswitch).whereshowsji)[i]
		  				  *(*(*info).meas).xp_sji[idx_sji] = $
                  [(*(*(*info).meas).xp_sji[idx_sji])[0],(*(*info).dataparams).xsji[idx_sji]]	
		  				  *(*(*info).meas).yp_sji[idx_sji] = $
                  [(*(*(*info).meas).yp_sji[idx_sji])[0],(*(*info).dataparams).ysji[idx_sji]]	
		  				  *(*(*info).meas).sxp_sji[idx_sji] = $
                  [(*(*(*info).meas).sxp_sji[idx_sji])[0],(*(*info).curs).sxsji[idx_sji]]	
		  				  *(*(*info).meas).syp_sji[idx_sji] = $
                  [(*(*(*info).meas).syp_sji[idx_sji])[0],(*(*info).curs).sysji[idx_sji]]
              ENDFOR
            ENDIF
		  			CRISPEX_MEASURE_CALC, event
		  			CRISPEX_COORDSLIDERS_SET, 1, 1, event
		  		ENDIF ELSE RETURN
		  	END
		  ELSE: RETURN
		  ENDCASE
      ; Update user feedback
		  IF (((*(*info).feedbparams).verbosity)[3] EQ 1) THEN $
        CRISPEX_VERBOSE_GET, event, [event.TYPE,event.PRESS,$
          (*(*info).dataparams).x,(*(*info).dataparams).y,(*(*info).curs).sx,$
          (*(*info).curs).sy], $
          labels=['WIDGET_DRAW: event.TYPE','WIDGET_DRAW: event.PRESS','x','y',$
          'sx','sy']
      ; Update display data and Redraw windows as necessary 
      IF (*(*info).winswitch).showls THEN CRISPEX_UPDATE_SSP, event
      IF (*(*info).winswitch).showsp THEN CRISPEX_UPDATE_SPSLICE, event
      IF (*(*info).winswitch).showrefls THEN CRISPEX_UPDATE_REFSSP, event
      IF (*(*info).winswitch).showrefsp THEN CRISPEX_UPDATE_REFSPSLICE, event
		  IF (*(*info).winswitch).showphis THEN BEGIN
		  	CRISPEX_PHISLIT_DIRECTION, event
        CRISPEX_UPDATE_PHISLIT_COORDS, event
		  	CRISPEX_UPDATE_PHISLICE, event
		  ENDIF ELSE CRISPEX_DRAW, event
    ENDIF ELSE BEGIN  ; Panning
      CASE event.TYPE OF
        0:  BEGIN ; Click and grab
              DEVICE, CURSOR_IMAGE=(*(*info).curs).image_grab, $
                CURSOR_MASK=(*(*info).curs).mask_grab, $
                CURSOR_XY=[7,7]
              get_xy = CRISPEX_CURSOR_GET_XY(event, event.X, event.Y)
              (*(*info).curs).pan_init_x = get_xy[0]
              (*(*info).curs).pan_init_y = get_xy[1]
              (*(*info).curs).pan_grab = 1B
            END
        1:  BEGIN ; Release grab
              DEVICE, CURSOR_IMAGE=(*(*info).curs).image_hand, $
                CURSOR_MASK=(*(*info).curs).mask_hand, $
                CURSOR_XY=[7,7]
              (*(*info).curs).pan_grab = 0B
            END
        2:  BEGIN ; Drag
              IF (*(*info).curs).pan_grab THEN BEGIN
                get_xy = CRISPEX_CURSOR_GET_XY(event, event.X, event.Y)
                xdiff = (*(*info).curs).pan_init_x - get_xy[0]
                ydiff = (*(*info).curs).pan_init_y - get_xy[1]
                imrefsji = WHERE([(*(*info).winids).xydrawid, $
                  (*(*info).winids).refdrawid, $
                  (*(*info).winids).sjidrawid[get_xy[2]]] EQ $
                  (*(*info).winids).current_wid)
                CASE imrefsji OF
                  0:  BEGIN
                        xypos = [(*(*info).zooming).xpos,(*(*info).zooming).ypos] 
                        xyupp = (*(*info).zooming).xypos_max
                      END
                  1:  BEGIN
                        xypos = [(*(*info).zooming).xrefpos,(*(*info).zooming).yrefpos] 
                        xyupp = (*(*info).zooming).xyrefpos_max
                      END
                  2:  BEGIN
                        xypos = [(*(*info).zooming).xsjipos[get_xy[2]],$
                                 (*(*info).zooming).ysjipos[get_xy[2]]]
                        xyupp = (*(*info).zooming).xysjipos_max[*,get_xy[2]]
                      END
                ENDCASE
                xyval = xypos + [xdiff, ydiff] > [0,0] < xyupp
                CRISPEX_SLIDER_XPOS, event, REFERENCE=(imrefsji EQ 1), $
                  SJI=(imrefsji EQ 2), SET_VALUE=xyval[0], IDX_SJI=get_xy[2], /NO_DRAW
                CRISPEX_SLIDER_YPOS, event, REFERENCE=(imrefsji EQ 1), $
                  SJI=(imrefsji EQ 2), SET_VALUE=xyval[1], IDX_SJI=get_xy[2], /NO_DRAW
                CRISPEX_DRAW_IMREF, event;, NO_MAIN=(imrefsji NE 0), $
;                  NO_REF=(imrefsji NE 1), NO_SJI=(imrefsji NE 2)
              ENDIF
            END
        ELSE: RETURN
      ENDCASE
    ENDELSE
	ENDIF
END

PRO CRISPEX_CURSOR_SET_XY, event, x_tmp, y_tmp
; Converts the window x and y coordinates to data x and y coordinates
  WIDGET_CONTROL, event.TOP, GET_UVALUE=info
  get_xy = CRISPEX_CURSOR_GET_XY(event, x_tmp, y_tmp)
  idx_sji = get_xy[2]
  ; Check whether current window ID is reference or main
  ; Take LONG() of temporary results to get the actual indices
  IF ((*(*info).winids).current_wid EQ (*(*info).winids).xydrawid) THEN BEGIN
  	(*(*info).dataparams).x = LONG(get_xy[0])
  	(*(*info).dataparams).y = LONG(get_xy[1])
  ENDIF ELSE $
    IF ((*(*info).winids).current_wid EQ (*(*info).winids).refdrawid) THEN BEGIN
  	(*(*info).dataparams).xref = LONG(get_xy[0])
  	(*(*info).dataparams).yref = LONG(get_xy[1])
  ENDIF ELSE BEGIN
  	(*(*info).dataparams).xsji[idx_sji] = LONG(get_xy[0])
  	(*(*info).dataparams).ysji[idx_sji] = LONG(get_xy[1])
  ENDELSE
  ; Convert x,y to values for other windows
  CRISPEX_COORDS_TRANSFORM_XY, event, $
    MAIN2SJI=(((*(*info).dataswitch).sjifile NE 0) AND $
              ((*(*info).winids).current_wid EQ (*(*info).winids).xydrawid)), $
    MAIN2REF=(((*(*info).dataswitch).reffile NE 0) AND $
              ((*(*info).winids).current_wid EQ (*(*info).winids).xydrawid)), $
    REF2MAIN=((*(*info).winids).current_wid EQ (*(*info).winids).refdrawid), $
    REF2SJI=(((*(*info).dataswitch).sjifile NE 0) AND $
              ((*(*info).winids).current_wid EQ (*(*info).winids).refdrawid)),$
    SJI2MAIN=TOTAL((*(*info).winids).current_wid EQ $
                   (*(*info).winids).sjidrawid[idx_sji]), $
    SJI2REF=(((*(*info).dataswitch).reffile NE 0) AND $
              TOTAL((*(*info).winids).current_wid EQ $
                    (*(*info).winids).sjidrawid[idx_sji])), $
    SJI2SJI=(((*(*info).dataparams).nsjifiles GT 1) AND $
              TOTAL((*(*info).winids).current_wid EQ $
                    (*(*info).winids).sjidrawid[idx_sji])), $
    WINIDX_SJI=idx_sji
  ; Get device coordinates for display
  sxy = CRISPEX_TRANSFORM_DATA2DEVICE(info, $
    X=(*(*info).dataparams).x, Y=(*(*info).dataparams).y, /MAIN)
  (*(*info).curs).sx = sxy.x
  (*(*info).curs).sy = sxy.y
  IF (*(*info).dataswitch).reffile THEN BEGIN
    sxyref = CRISPEX_TRANSFORM_DATA2DEVICE(info, $
      X=(*(*info).dataparams).xref, Y=(*(*info).dataparams).yref, /REFERENCE)
    (*(*info).curs).sxref = sxyref.x
    (*(*info).curs).syref = sxyref.y
  ENDIF
  IF (*(*info).dataswitch).sjifile THEN BEGIN
    FOR idx_tmp_sji=0,(*(*info).dataparams).nsjifiles-1 DO BEGIN
      sxysji = CRISPEX_TRANSFORM_DATA2DEVICE(info, $
        X=(*(*info).dataparams).xsji[idx_tmp_sji], $
        Y=(*(*info).dataparams).ysji[idx_tmp_sji], /SJI, IDX_SJI=idx_tmp_sji)
      (*(*info).curs).sxsji[idx_tmp_sji] = sxysji.x
      (*(*info).curs).sysji[idx_tmp_sji] = sxysji.y 
    ENDFOR
  ENDIF
	IF (((*(*info).feedbparams).verbosity)[3] EQ 1) THEN $
    CRISPEX_VERBOSE_GET, event, $
      [(*(*info).dataparams).x,(*(*info).dataparams).y], labels=['x','y']
END

PRO CRISPEX_CURSOR_LOCK, event								
; Called upon locking/unlocking cursor with 'lock cursor' or 'unlock cursor' 
; button, handles cursor (un)locking
	WIDGET_CONTROL, event.TOP, GET_UVALUE = info
	IF (TOTAL(((*(*info).feedbparams).verbosity)[2:3]) GE 1) THEN $
    CRISPEX_VERBOSE_GET_ROUTINE, event
	(*(*info).curs).lockset = ABS((*(*info).curs).lockset-1)
	IF (*(*info).curs).lockset THEN BEGIN
		(*(*info).curs).xlock = (*(*info).dataparams).x	
    (*(*info).curs).ylock = (*(*info).dataparams).y
		(*(*info).curs).sxlock = (*(*info).curs).sx	   
    (*(*info).curs).sylock = (*(*info).curs).sy
    IF ((*(*info).winids).reftlb NE 0) THEN BEGIN
      (*(*info).curs).xreflock = (*(*info).dataparams).xref
      (*(*info).curs).yreflock = (*(*info).dataparams).yref
      (*(*info).curs).sxreflock = (*(*info).curs).sxref
      (*(*info).curs).syreflock = (*(*info).curs).syref
    ENDIF
		IF (((*(*info).feedbparams).verbosity)[3] EQ 1) THEN $
			CRISPEX_VERBOSE_GET, event, [(*(*info).curs).xlock,(*(*info).curs).ylock,$
        (*(*info).curs).sxlock,(*(*info).curs).sylock], $
        labels=['xlock','ylock','sxlock','sylock']
	ENDIF
  CRISPEX_CURSOR_LOCKBUTTON_SET, event
  CRISPEX_COORDSLIDERS_SET, 1, 1, event
END

PRO CRISPEX_CURSOR_LOCKBUTTON_SET, event, NO_DRAW=no_draw
  ; Handles setting lock button and cursor image
	WIDGET_CONTROL, event.TOP, GET_UVALUE = info
	IF (TOTAL(((*(*info).feedbparams).verbosity)[2:3]) GE 1) THEN $
    CRISPEX_VERBOSE_GET_ROUTINE, event
	IF (*(*info).curs).lockset THEN BEGIN
    WIDGET_CONTROL, (*(*info).ctrlscp).cursor_button, $
      SET_VALUE=(*(*info).ctrlspbbut).cursor_locked, /SET_BUTTON 
    (*(*info).curs).mask = (*(*info).curs).mask_locked
  ENDIF ELSE BEGIN
    WIDGET_CONTROL, (*(*info).ctrlscp).cursor_button, $
      SET_VALUE=(*(*info).ctrlspbbut).cursor_unlocked, /SET_BUTTON
    (*(*info).curs).mask = (*(*info).curs).mask_default
  ENDELSE
  IF ~KEYWORD_SET(NO_DRAW) THEN $
  	DEVICE, CURSOR_IMAGE=(*(*info).curs).image, $
      CURSOR_MASK=(*(*info).curs).mask, CURSOR_XY=[7,7]
END

PRO CRISPEX_COORDSLIDERS_SET, xsensitive, ysensitive, event
; Adjusts sliders according to change in cursor position or locked/unlocked state
	WIDGET_CONTROL, event.TOP, GET_UVALUE = info
	IF (TOTAL(((*(*info).feedbparams).verbosity)[2:3]) GE 1) THEN $
    CRISPEX_VERBOSE_GET_ROUTINE, event
	WIDGET_CONTROL, (*(*info).ctrlscp).x_slider, $
    SET_VALUE=(*(*info).dataparams).x, SENSITIVE=(xsensitive AND $
    ((*(*info).dispparams).x_first NE (*(*info).dispparams).x_last) AND $
    ((*(*info).dispswitch).xy_out_of_range EQ 0))
	WIDGET_CONTROL, (*(*info).ctrlscp).y_slider, $
    SET_VALUE=(*(*info).dataparams).y, SENSITIVE=(ysensitive AND $
    ((*(*info).dispparams).y_first NE (*(*info).dispparams).y_last) AND $
    ((*(*info).dispswitch).xy_out_of_range EQ 0))
  IF (*(*info).dataswitch).reffile THEN BEGIN 
  	WIDGET_CONTROL, (*(*info).ctrlscp).xref_slider, $
      SET_VALUE=(*(*info).dataparams).xref, SENSITIVE=(xsensitive AND $
      ((*(*info).dispparams).xref_first NE (*(*info).dispparams).xref_last) AND $
      ((*(*info).dispswitch).main2ref_no_map EQ 0) AND $
      ((*(*info).dispswitch).xyref_out_of_range EQ 0))
  	WIDGET_CONTROL, (*(*info).ctrlscp).yref_slider, $
      SET_VALUE=(*(*info).dataparams).yref, SENSITIVE=(ysensitive AND $
      ((*(*info).dispparams).yref_first NE (*(*info).dispparams).yref_last) AND $
      ((*(*info).dispswitch).main2ref_no_map EQ 0) AND $
      ((*(*info).dispswitch).xyref_out_of_range EQ 0))
  ENDIF
	IF (((*(*info).feedbparams).verbosity)[3] EQ 1) THEN $
    CRISPEX_VERBOSE_GET, event, $
      [(*(*info).dataparams).x,(*(*info).dataparams).y,xsensitive,ysensitive], $
      labels=['x','y','xsensitive','ysensitive']
END

;========================= COORDINATE TRANSFORMATIONS
PRO CRISPEX_COORDS_TRANSFORM_XY, event, MAIN2SJI=main2sji, MAIN2REF=main2ref, $
  REF2MAIN=ref2main, REF2SJI=ref2sji, SJI2MAIN=sji2main, SJI2REF=sji2ref, $
  SJI2SJI=sji2sji, WINIDX_SJI=winidx_sji
; Handles transformation of x/y-coordinates in case of unequal spatial 
; dimensions
	WIDGET_CONTROL, event.TOP, GET_UVALUE = info
	IF (TOTAL(((*(*info).feedbparams).verbosity)[2:3]) GE 1) THEN $
    CRISPEX_VERBOSE_GET_ROUTINE, event
  ; Convert main to reference coordinates
  IF KEYWORD_SET(MAIN2REF) THEN BEGIN
    ; If not mapping, simply set reference to main coordinates
    IF (*(*info).dispswitch).main2ref_no_map THEN BEGIN
      (*(*info).dataparams).xref = (*(*info).dataparams).x
      (*(*info).dataparams).yref = (*(*info).dataparams).y
    ENDIF ELSE BEGIN
      ; If mapping, subscript mapping array with main coordinates
      xyref = (*(*(*info).dataparams).pix_main2ref)[*, $
          (*(*info).dataparams).x, (*(*info).dataparams).y]
      (*(*info).dataparams).xref = xyref[0]
      (*(*info).dataparams).yref = xyref[1]
    ENDELSE
  ENDIF 
  ; Convert reference to main coordinates
  IF KEYWORD_SET(REF2MAIN) THEN BEGIN
    ; If not mapping, simply set reference to reference coordinates
    IF (*(*info).dispswitch).main2ref_no_map THEN BEGIN
      (*(*info).dataparams).x = (*(*info).dataparams).xref
      (*(*info).dataparams).y = (*(*info).dataparams).yref
    ENDIF ELSE BEGIN
      ; If mapping, subscript mapping array with reference coordinates
      xy = (*(*(*info).dataparams).pix_ref2main)[*, $
          (*(*info).dataparams).xref, (*(*info).dataparams).yref]
      (*(*info).dataparams).x = xy[0]
      (*(*info).dataparams).y = xy[1]
    ENDELSE
  ENDIF
  ; Convert SJI to main coordinates
  IF KEYWORD_SET(SJI2MAIN) THEN BEGIN
      xy = (*(*(*info).dataparams).pix_sji2main[winidx_sji])[*, $
          (*(*info).dataparams).xsji[winidx_sji], $
          (*(*info).dataparams).ysji[winidx_sji]]
      (*(*info).dataparams).x = xy[0]
      (*(*info).dataparams).y = xy[1]
  ENDIF
  ; Convert SJI to main coordinates
  IF KEYWORD_SET(SJI2REF) THEN BEGIN
      xyref = (*(*(*info).dataparams).pix_sji2ref[winidx_sji])[*, $
          (*(*info).dataparams).xsji[winidx_sji], $
          (*(*info).dataparams).ysji[winidx_sji]]
      (*(*info).dataparams).xref = xyref[0]
      (*(*info).dataparams).yref = xyref[1]
  ENDIF
  ; Check whether main coordinates are out of range
  (*(*info).dispswitch).xy_out_of_range = $
    (((*(*info).dataparams).x LT 0) OR ((*(*info).dataparams).y LT 0) OR $
     ((*(*info).dataparams).x GE (*(*info).dataparams).nx) OR $
     ((*(*info).dataparams).y GE (*(*info).dataparams).ny))
  ; Check whether reference coordinates are out of range
  IF (*(*info).dataswitch).reffile THEN BEGIN
    (*(*info).dispswitch).xyref_out_of_range = $
      (((*(*info).dataparams).xref LT 0) OR ((*(*info).dataparams).yref LT 0) OR $
       ((*(*info).dataparams).xref GE (*(*info).dataparams).refnx) OR $
       ((*(*info).dataparams).yref GE (*(*info).dataparams).refny))
  ENDIF
  IF (KEYWORD_SET(MAIN2SJI) OR KEYWORD_SET(REF2SJI) OR $
      KEYWORD_SET(SJI2SJI)) THEN BEGIN
    FOR idx_sji=0,(*(*info).dataparams).nsjifiles-1 DO BEGIN
      IF (KEYWORD_SET(MAIN2SJI) AND $
        ((*(*info).dispswitch).xy_out_of_range EQ 0)) THEN $
        xysji = (*(*(*info).dataparams).pix_main2sji[idx_sji])[*,$
          (*(*info).dataparams).x, (*(*info).dataparams).y]
      IF (KEYWORD_SET(REF2SJI) AND $
        ((*(*info).dispswitch).xyref_out_of_range EQ 0)) THEN $
        xysji = (*(*(*info).dataparams).pix_ref2sji[idx_sji])[*,$
          (*(*info).dataparams).xref, (*(*info).dataparams).yref]
      IF KEYWORD_SET(SJI2SJI) THEN $
        xysji = (*(*(*info).dataparams).pix_sji2sji[winidx_sji,idx_sji])[*,$
          (*(*info).dataparams).xsji[winidx_sji], $
          (*(*info).dataparams).ysji[winidx_sji]]
      IF (N_ELEMENTS(xysji) EQ 2) THEN BEGIN
        (*(*info).dataparams).xsji[idx_sji] = xysji[0]
        (*(*info).dataparams).ysji[idx_sji] = xysji[1]
      ENDIF
      ; Check whether SJI coordinates are out of range
      (*(*info).dispswitch).xysji_out_of_range[idx_sji] = $
        (((*(*info).dataparams).xsji[idx_sji] LT 0) OR $
         ((*(*info).dataparams).ysji[idx_sji] LT 0) OR $
         ((*(*info).dataparams).xsji[idx_sji] GE $
          (*(*info).dataparams).sjinx[idx_sji]) OR $
         ((*(*info).dataparams).ysji[idx_sji] GE $
          (*(*info).dataparams).sjiny[idx_sji]))
    ENDFOR
  ENDIF 
END

PRO CRISPEX_COORDS_TRANSFORM_T, event, T_OLD=t_old, NT_OLD=nt_old
; Handles transformation of t-coordinates in case of unequal temporal dimensions
	WIDGET_CONTROL, event.TOP, GET_UVALUE = info
	IF (TOTAL(((*(*info).feedbparams).verbosity)[2:3]) GE 1) THEN $
    CRISPEX_VERBOSE_GET_ROUTINE, event
    ; Select temporal array for main and reference depending on dimensions and offset
    tarr_main = REFORM((*(*info).dataparams).tarr_full_main[$
        (*(*info).dispparams).toffset_main < (*(*info).dataparams).tfull_dims_main[0], $
        (*(*info).dataparams).lp< (*(*info).dataparams).tfull_dims_main[1], $
        (*(*info).dataparams).s < (*(*info).dataparams).tfull_dims_main[2], *])
    IF (SIZE((*(*info).dataparams).tarr_full_ref, /N_DIMENSIONS) GT 0) THEN $
      tarr_ref = REFORM((*(*info).dataparams).tarr_full_ref[$
          (*(*info).dispparams).toffset_ref < $
            (*(*info).dataparams).tfull_dims_ref[0], $
          (*(*info).dataparams).lp_ref< $
            (*(*info).dataparams).tfull_dims_ref[1], $
          (*(*info).dataparams).s_ref < $
            (*(*info).dataparams).tfull_dims_ref[2], *])
    toffset_max = 1
    CASE (*(*info).dispparams).master_time OF
      0:  BEGIN ; Select main data as timing master
            tarr_master = tarr_main
            (*(*info).dataparams).nt = (*(*info).dataparams).mainnt
            offset_value = (*(*info).dispparams).toffset_main
            is_raster = (*(*info).dataparams).tfull_dims_main[0] GE 1
            IF is_raster THEN toffset_max = (*(*info).dataparams).tfull_dims_main[0]
          END
      1:  BEGIN ; Select reference data as timing master
            tarr_master = tarr_ref
            (*(*info).dataparams).nt = (*(*info).dataparams).refnt
            offset_value = (*(*info).dispparams).toffset_ref
            is_raster = (*(*info).dataparams).tfull_dims_ref[0] GE 1
            IF is_raster THEN toffset_max = (*(*info).dataparams).tfull_dims_ref[0]
          END
      2:  BEGIN ; Select slit-jaw image data as timing master
            tarr_master = $
              *(*(*info).dataparams).tarr_sji[(*(*info).dispswitch).sji_select]
            (*(*info).dataparams).nt = $
              (*(*info).dataparams).sjint[(*(*info).dispswitch).sji_select]
            offset_value = 0
            is_raster = 0
          END
    ENDCASE
    ; Adjust time offset slider according to choices
    ; Become sensitive if timing master is a raster, so either:
    ; - single scan (nx>1 AND nt=1, tarr_raster dims = 1)
    ; - raster with time evolution (nx>1 AND nt>1, tarr_raster dims = 2)
    WIDGET_CONTROL, (*(*info).ctrlscp).time_offset_slider, $
      SENSITIVE=is_raster, SET_VALUE=offset_value, $
      SET_SLIDER_MAX=toffset_max
    IF ((((*(*info).dataparams).nt EQ 1) AND (nt_old GT 1)) OR $
        (((*(*info).dataparams).nt GT 1) AND (nt_old EQ 1))) THEN $
      CRISPEX_PB_BUTTONS_SET, event, /PAUSE_SET, /LOOP_SET, $
        SENSITIVE_SET=(((*(*info).dataparams).nt GT 1) AND (nt_old EQ 1))
    ; Initialise variables
    IF ((*(*info).dataparams).mainnt GT 1) THEN tsel_main = LONARR((*(*info).dataparams).nt)
    IF ((*(*info).dataparams).refnt GT 1) THEN tsel_ref = LONARR((*(*info).dataparams).nt)
    IF ((*(*info).dataparams).sjint[(*(*info).dispswitch).sji_select] GT 1) THEN $
      tsel_sji = LONARR((*(*info).dataparams).nsjifiles,(*(*info).dataparams).nt)
    ; Determine frame closest in time to master array
    FOR tt=0,(*(*info).dataparams).nt-1 DO BEGIN
      IF ((*(*info).dataparams).mainnt GT 1) THEN BEGIN
        tdiff_main = ABS(tarr_main - tarr_master[tt])
        tsel_main[tt] = (WHERE(tdiff_main EQ MIN(tdiff_main, /NAN)))[0]
      ENDIF
      IF ((*(*info).dataparams).refnt GT 1) THEN BEGIN 
        tdiff_ref = ABS(tarr_ref - tarr_master[tt])
        tsel_ref[tt] = (WHERE(tdiff_ref EQ MIN(tdiff_ref, /NAN)))[0]
      ENDIF
      FOR idx_sji=0,(*(*info).dataparams).nsjifiles-1 DO BEGIN
        IF ((*(*info).dataparams).sjint[idx_sji] GT 1) THEN BEGIN 
          tdiff_sji = $
            ABS(*(*(*info).dataparams).tarr_sji[idx_sji] - tarr_master[tt])
          tsel_sji[idx_sji,tt] = (WHERE(tdiff_sji EQ MIN(tdiff_sji, /NAN)))[0]
        ENDIF
      ENDFOR
    ENDFOR
    ; Populate variables with results
    IF ((*(*info).dataparams).mainnt GT 1) THEN BEGIN
      *(*(*info).dispparams).tsel_main = tsel_main
      *(*(*info).dispparams).tarr_main = tarr_main[tsel_main]
      *(*(*info).dispparams).utc_main = (*(*info).dataparams).utc_full_main[$
          (*(*info).dispparams).toffset_main < (*(*info).dataparams).tfull_dims_main[0], $
          (*(*info).dataparams).lp< (*(*info).dataparams).tfull_dims_main[1], $
          (*(*info).dataparams).s < (*(*info).dataparams).tfull_dims_main[2], $
          tsel_main]
      IF ((*(*info).dispparams).master_time EQ 0) THEN $
          *(*(*info).dispparams).date_arr = (*(*info).dataparams).date_full_main[$
            (*(*info).dispparams).toffset_main < $
            (*(*info).dataparams).tfull_dims_main[0], $
            (*(*info).dataparams).lp< (*(*info).dataparams).tfull_dims_main[1], $
            (*(*info).dataparams).s < (*(*info).dataparams).tfull_dims_main[2], $
            tsel_main]
    ENDIF
    IF ((*(*info).dataparams).refnt GT 1) THEN BEGIN 
      *(*(*info).dispparams).tsel_ref = tsel_ref
      *(*(*info).dispparams).tarr_ref = tarr_ref[tsel_ref]
      *(*(*info).dispparams).utc_ref = (*(*info).dataparams).utc_full_ref[$
          (*(*info).dispparams).toffset_ref < (*(*info).dataparams).tfull_dims_ref[0], $
          (*(*info).dataparams).lp_ref< (*(*info).dataparams).tfull_dims_ref[1], $
          (*(*info).dataparams).s_ref < (*(*info).dataparams).tfull_dims_ref[2], $
          tsel_ref]
      IF ((*(*info).dispparams).master_time EQ 1) THEN $
          *(*(*info).dispparams).date_arr = (*(*info).dataparams).date_full_ref[$
            (*(*info).dispparams).toffset_ref < $
            (*(*info).dataparams).tfull_dims_ref[0], $
            (*(*info).dataparams).lp_ref< (*(*info).dataparams).tfull_dims_ref[1], $
            (*(*info).dataparams).s_ref < (*(*info).dataparams).tfull_dims_ref[2], $
            tsel_ref]
    ENDIF
    FOR idx_sji=0,(*(*info).dataparams).nsjifiles-1 DO BEGIN
      IF ((*(*info).dataparams).sjint[idx_sji] GT 1) THEN BEGIN 
        *(*(*info).dispparams).tsel_sji[idx_sji] = REFORM(tsel_sji[idx_sji,*])
        *(*(*info).dispparams).tarr_sji[idx_sji] = $
          (*(*(*info).dataparams).tarr_sji[idx_sji])[$
           *(*(*info).dispparams).tsel_sji[idx_sji]]
        *(*(*info).dispparams).utc_sji[idx_sji] = $
          (*(*(*info).dataparams).utc_sji[idx_sji])[$
           *(*(*info).dispparams).tsel_sji[idx_sji]]
        IF ((*(*info).dispparams).master_time EQ 2) THEN $
          *(*(*info).dispparams).date_arr = $
            (*(*(*info).dataparams).date_sji[(*(*info).dispswitch).sji_select])[$
            *(*(*info).dispparams).tsel_sji[(*(*info).dispswitch).sji_select]]
      ENDIF
    ENDFOR
    ; Reset temporal boundaries and get T_SET
    (*(*info).dispparams).t_last = (*(*info).dataparams).nt-1
    IF (((*(*info).dataparams).nt NE 1) AND (N_ELEMENTS(T_OLD) EQ 1)) THEN BEGIN
      tdiff = ABS(tarr_master - t_old)
      t_set = (WHERE(tdiff EQ MIN(tdiff, /NAN)))[0]
    ENDIF ELSE t_set = 0
    CRISPEX_DISPRANGE_T_RESET, event, /NO_DRAW, T_SET=t_set
END

;========================= DIAGNOSTIC SELECTION PROCEDURES
PRO CRISPEX_REFDIAGNOSTICS_SELECT, event
	WIDGET_CONTROL, event.TOP, GET_UVALUE=info
	IF (TOTAL(((*(*info).feedbparams).verbosity)[2:3]) GE 1) THEN $
    CRISPEX_VERBOSE_GET_ROUTINE, event
  IF (event.INDEX EQ 0) THEN BEGIN
    ; Handle the setting of Display all: reset variables and list_values
    (*(*info).intparams).disp_refdiagnostics = $
      REPLICATE(1,(*(*info).intparams).nrefdiagnostics)   
    (*(*info).intparams).ndisp_refdiagnostics = $
      TOTAL((*(*info).intparams).disp_refdiagnostics)
    list_values = ['Display all', $
      REPLICATE('Hide ',(*(*info).intparams).nrefdiagnostics)+$
      (*(*info).intparams).refdiagnostics]
    WIDGET_CONTROL, (*(*info).ctrlscp).ref_specwin_cbox, SET_VALUE=list_values, $
      SET_COMBOBOX_SELECT=1
  ENDIF ELSE BEGIN
    sel_idx = event.INDEX-1
    (*(*info).intparams).disp_refdiagnostics[sel_idx] = $
      ABS((*(*info).intparams).disp_refdiagnostics[sel_idx]-1)
    (*(*info).intparams).ndisp_refdiagnostics = $
      TOTAL((*(*info).intparams).disp_refdiagnostics)
    IF ((*(*info).intparams).ndisp_refdiagnostics EQ 0) THEN BEGIN
      ; Failsafe against hiding all diagnostics
      (*(*info).intparams).disp_refdiagnostics[sel_idx] = 1
      (*(*info).intparams).ndisp_refdiagnostics = 1
    ENDIF
    ; Adjust the selected value with a Display/Hide comment
    list_values_text = (['Display ','Hide '])[$
      (*(*info).intparams).disp_refdiagnostics[sel_idx] EQ 1]
    WIDGET_CONTROL, (*(*info).ctrlscp).ref_specwin_cbox, GET_VALUE=list_values
    list_values[sel_idx+1] = list_values_text + $
      (*(*info).intparams).refdiagnostics[sel_idx]
    WIDGET_CONTROL, (*(*info).ctrlscp).ref_specwin_cbox, SET_VALUE=list_values, $
      SET_COMBOBOX_SELECT=event.INDEX
  ENDELSE
  ; Adjust label text depending on whether all or some are displayed
  IF ((*(*info).intparams).ndisp_refdiagnostics EQ $
      (*(*info).intparams).nrefdiagnostics) THEN $
    label_text = 'Reference: Displaying all' $
  ELSE $
    label_text = 'Reference: Displaying selected'
  WIDGET_CONTROL, (*(*info).ctrlscp).ref_specwin_label, $
    SET_VALUE=label_text
  IF ((*(*info).intparams).ndisp_diagnostics NE $
      (*(*info).intparams).ndisp_refdiagnostics) THEN BEGIN
    IF (*(*info).ctrlsswitch).lp_ref_lock THEN $
      CRISPEX_SLIDER_LP_REF_LOCK, event, /UNLOCK, /NO_DRAW
    WIDGET_CONTROL, (*(*info).ctrlscp).lp_ref_but, SENSITIVE=0
  ENDIF ELSE $
    WIDGET_CONTROL, (*(*info).ctrlscp).lp_ref_but, /SENSITIVE
  CRISPEX_DRAW_GET_SPECTRAL_AXES, event, /REFERENCE
  ; Adjust slider settings based on available lp-range
  CRISPEX_DISPRANGE_LP_REF_RANGE, event, /NO_DRAW
  ; Change the overall minimum/maximum Doppler values as need be
  (*(*info).dataparams).v_dop_ref_low_min[0] = FLOOR(MIN($
    (*(*info).dataparams).v_dop_ref_low_min[$
    *(*(*info).intparams).wheredisprefdiag+1],/NAN))
  (*(*info).dataparams).v_dop_ref_low_max[0] = FLOOR(MIN($
    (*(*info).dataparams).v_dop_ref_low_max[$
    *(*(*info).intparams).wheredisprefdiag+1],/NAN))
  (*(*info).dataparams).v_dop_ref_upp_min[0] = CEIL(MAX($
    (*(*info).dataparams).v_dop_ref_upp_min[$
    *(*(*info).intparams).wheredisprefdiag+1],/NAN))
  (*(*info).dataparams).v_dop_ref_upp_max[0] = CEIL(MAX($
    (*(*info).dataparams).v_dop_ref_upp_max[$
    *(*(*info).intparams).wheredisprefdiag+1],/NAN))
  CRISPEX_SLIDER_LP_RESTRICT, event, /REFERENCE, /NO_DRAW
  idx = ((*(*info).dispswitch).lp_restrict[1] EQ 1)
  IF idx THEN $
    CRISPEX_DIAGNOSTICS_SELECT_UPDATE_LP_RESTRICT_SLIDERS, event, $
      REFERENCE=idx
  CRISPEX_UPDATE_T, event
  CRISPEX_SCALING_APPLY_SELECTED, event
  IF (*(*info).winswitch).showrefsp THEN BEGIN
    CRISPEX_UPDATE_REFSPSLICE, event
    CRISPEX_DISPLAYS_REFSP_REPLOT_AXES, event
  ENDIF
  CRISPEX_DRAW, event, /NO_MAIN, /LS_NO_MAIN
END

PRO CRISPEX_DIAGNOSTICS_SELECT_UPDATE_LP_RESTRICT_SLIDERS, event, $
  REFERENCE=reference
	WIDGET_CONTROL, event.TOP, GET_UVALUE=info	
	IF (TOTAL(((*(*info).feedbparams).verbosity)[2:3]) GE 1) THEN $
    CRISPEX_VERBOSE_GET_ROUTINE, event
  idx = KEYWORD_SET(REFERENCE)
  slididx = (*(*info).dispswitch).lp_restrict_globloc[idx] * $
    ( ([(*(*info).intparams).lp_diag_all+1, $
        (*(*info).intparams).lp_ref_diag_all+1])[idx] )
  IF NOT KEYWORD_SET(REFERENCE) THEN BEGIN
    slider_low = [(*(*info).dataparams).v_dop_low_min[slididx], $
                  (*(*info).dataparams).v_dop_low_max[slididx]]
    slider_upp = [(*(*info).dataparams).v_dop_upp_min[slididx], $
                  (*(*info).dataparams).v_dop_upp_max[slididx]]
  ENDIF ELSE BEGIN
    slider_low = [(*(*info).dataparams).v_dop_ref_low_min[slididx], $
                  (*(*info).dataparams).v_dop_ref_low_max[slididx]]
    slider_upp = [(*(*info).dataparams).v_dop_ref_upp_min[slididx], $
                  (*(*info).dataparams).v_dop_ref_upp_max[slididx]]
  ENDELSE
  WIDGET_CONTROL, (*(*info).ctrlscp).lp_restr_slider_low, $
    SET_SLIDER_MIN=slider_low[0], SET_SLIDER_MAX=slider_low[1]
  WIDGET_CONTROL, (*(*info).ctrlscp).lp_restr_slider_upp, $
    SET_SLIDER_MIN=slider_upp[0], SET_SLIDER_MAX=slider_upp[1]


END

;========================= DISPLAYS PROCEDURES
PRO CRISPEX_DISPLAYS_ALL_TO_FRONT, event
; Brings all opened session windows to front
	WIDGET_CONTROL, event.TOP, GET_UVALUE = info	
	IF (TOTAL(((*(*info).feedbparams).verbosity)[2:3]) GE 1) THEN $
    CRISPEX_VERBOSE_GET_ROUTINE, event, /IGNORE_LAST
	; Data windows
	IF (TOTAL((*(*info).winids).sjitlb) NE 0) THEN BEGIN
    FOR i=0,(*(*info).winswitch).nwhereshowsji-1 DO $
      WSHOW,(*(*info).winids).sjiwid[(*(*(*info).winswitch).whereshowsji)[i]]
  ENDIF
	IF ((*(*info).winids).sptlb NE 0) THEN WSHOW, (*(*info).winids).spwid
	IF ((*(*info).winids).lstlb NE 0) THEN WSHOW, (*(*info).winids).lswid
	IF ((*(*info).winids).phistlb NE 0) THEN WSHOW, (*(*info).winids).phiswid
	IF ((*(*info).winids).reftlb NE 0) THEN WSHOW, (*(*info).winids).refwid
	IF ((*(*info).winids).doptlb NE 0) THEN WSHOW, (*(*info).winids).dopwid
	IF ((*(*info).winids).imreftlb NE 0) THEN WSHOW, (*(*info).winids).imrefwid
	IF (TOTAL(*(*(*info).winids).restlooptlb) NE 0) THEN $
    FOR i=0,N_ELEMENTS(*(*(*info).winids).restlooptlb)-1 DO WSHOW, (*(*(*info).winids).restloopwid)[i]
	IF ((*(*info).winids).retrdettlb NE 0) THEN WSHOW, (*(*info).winids).retrdetwid
	IF ((*(*info).winids).looptlb NE 0) THEN WSHOW, (*(*info).winids).loopwid
	IF ((*(*info).winids).refsptlb NE 0) THEN WSHOW, (*(*info).winids).refspwid
	IF ((*(*info).winids).reflstlb NE 0) THEN WSHOW, (*(*info).winids).reflswid
	IF ((*(*info).winids).inttlb NE 0) THEN WSHOW, (*(*info).winids).intwid
	; Action windows
	IF ((*(*info).winids).savetlb NE 0) THEN WIDGET_CONTROL, (*(*info).winids).savetlb, /SHOW
	IF ((*(*info).winids).detsavetlb NE 0) THEN WIDGET_CONTROL, (*(*info).winids).detsavetlb, /SHOW
	IF ((*(*info).winids).restoretlb NE 0) THEN WIDGET_CONTROL, (*(*info).winids).restoretlb, /SHOW
	IF ((*(*info).winids).savewintlb NE 0) THEN WIDGET_CONTROL, (*(*info).winids).savewintlb, /SHOW
	IF ((*(*info).winids).saveoptwintlb NE 0) THEN WIDGET_CONTROL, (*(*info).winids).saveoptwintlb, /SHOW
	IF ((*(*info).winids).intmenutlb NE 0) THEN WIDGET_CONTROL, (*(*info).winids).intmenutlb, /SHOW
	IF ((*(*info).winids).preftlb NE 0) THEN WIDGET_CONTROL, (*(*info).winids).preftlb, /SHOW
	; Warning and feedback windows
	IF ((*(*info).winids).paramtlb NE 0) THEN WIDGET_CONTROL, (*(*info).winids).paramtlb, /SHOW
	IF ((*(*info).winids).estimatetlb NE 0) THEN WIDGET_CONTROL, (*(*info).winids).estimatetlb, /SHOW
	IF ((*(*info).winids).feedbacktlb NE 0) THEN WIDGET_CONTROL, (*(*info).winids).feedbacktlb, /SHOW
	IF ((*(*info).winids).restsesfeedbtlb NE 0) THEN WIDGET_CONTROL, (*(*info).winids).restsesfeedbtlb, /SHOW
	IF ((*(*info).winids).abouttlb NE 0) THEN WIDGET_CONTROL, (*(*info).winids).abouttlb, /SHOW
	IF ((*(*info).winids).errtlb NE 0) THEN WIDGET_CONTROL, (*(*info).winids).errtlb, /SHOW
  ; Control panel
  ; WIDGET_CONTROL, (*(*info).winids).root, /SHOW
END

PRO CRISPEX_DISPLAYS_GATHER_ALL, event
; Gathers all windows to control panel offsets
	WIDGET_CONTROL, event.TOP, GET_UVALUE = info	
	IF (TOTAL(((*(*info).feedbparams).verbosity)[2:3]) GE 1) THEN $
    CRISPEX_VERBOSE_GET_ROUTINE, event, /IGNORE_LAST
  ; Get control panel offsets
  geometry = WIDGET_INFO((*(*info).winids).root, /GEOMETRY)
  ; Get TLBs
  tlbs = [(*(*info).winids).sjitlb, (*(*info).winids).sptlb, $
          (*(*info).winids).lstlb, (*(*info).winids).phistlb, $
          (*(*info).winids).reftlb, (*(*info).winids).doptlb, $
          (*(*info).winids).imreftlb, $ 
          (*(*info).winids).retrdettlb, (*(*info).winids).looptlb, $
          (*(*info).winids).refsptlb, (*(*info).winids).reflstlb, $
          (*(*info).winids).inttlb, $
          (*(*info).winids).savetlb, (*(*info).winids).detsavetlb, $
          (*(*info).winids).restoretlb, (*(*info).winids).savewintlb, $
          (*(*info).winids).saveoptwintlb, (*(*info).winids).intmenutlb, $
          (*(*info).winids).preftlb, $
          (*(*info).winids).paramtlb, (*(*info).winids).estimatetlb, $
	        (*(*info).winids).feedbacktlb, (*(*info).winids).restsesfeedbtlb, $
	        (*(*info).winids).abouttlb, (*(*info).winids).errtlb]
  where_tlb_set = WHERE(tlbs NE 0, nwhere_tlb_set)
  ; Apply offsets to visible windos
  FOR k=0,nwhere_tlb_set-1 DO BEGIN
    WIDGET_CONTROL, tlbs[where_tlb_set[k]], TLB_SET_XOFFSET=geometry.xoffset, $
      TLB_SET_YOFFSET=geometry.yoffset
  ENDFOR
	IF (TOTAL(*(*(*info).winids).restlooptlb) NE 0) THEN $
    FOR i=0,N_ELEMENTS(*(*(*info).winids).restlooptlb)-1 DO $
    WIDGET_CONTROL, (*(*(*info).winids).restlooptlb)[i], $
      TLB_SET_XOFFSET=geometry.xoffset, TLB_SET_YOFFSET=geometry.yoffset
  ; Bring all windos to front
  CRISPEX_DISPLAYS_ALL_TO_FRONT, event
END

PRO CRISPEX_DISPWIDS, event
; Brings all opened session windows to front
	WIDGET_CONTROL, event.TOP, GET_UVALUE = info	
	IF (TOTAL(((*(*info).feedbparams).verbosity)[2:3]) GE 1) THEN $
    CRISPEX_VERBOSE_GET_ROUTINE, event
	(*(*info).winswitch).dispwids = ABS((*(*info).winswitch).dispwids-1)
	WIDGET_CONTROL,(*(*info).ctrlscp).dispwid, SET_BUTTON = (*(*info).winswitch).dispwids
	tlbarr = [(*(*info).winids).root,(*(*info).winids).sptlb,$
    (*(*info).winids).lstlb,(*(*info).winids).reftlb,$
    (*(*info).winids).refsptlb,(*(*info).winids).reflstlb,$
    (*(*info).winids).imreftlb,(*(*info).winids).doptlb, $
    (*(*info).winids).sjitlb, $
		(*(*info).winids).phistlb,*(*(*info).winids).restlooptlb,$
    (*(*info).winids).retrdettlb,(*(*info).winids).looptlb,$
    (*(*info).winids).reflooptlb,(*(*info).winids).sjilooptlb, $
    (*(*info).winids).inttlb]
	widarr = [(*(*info).winids).imwid,(*(*info).winids).spwid,$
    (*(*info).winids).lswid,(*(*info).winids).refwid,$
    (*(*info).winids).refspwid,(*(*info).winids).reflswid,$
    (*(*info).winids).imrefwid,(*(*info).winids).dopwid, $
    (*(*info).winids).sjiwid, $
		(*(*info).winids).phiswid,*(*(*info).winids).restloopwid,$
    (*(*info).winids).retrdetwid,(*(*info).winids).loopwid,$
    (*(*info).winids).refloopwid,(*(*info).winids).sjiloopwid, $
    (*(*info).winids).intwid]
	title_arr = [(*(*info).winids).imwintitle,(*(*info).winids).spwintitle,$
    (*(*info).winids).lswintitle,(*(*info).winids).refwintitle,$
    (*(*info).winids).refspwintitle,(*(*info).winids).reflswintitle,$
		(*(*info).winids).imrefwintitle,(*(*info).winids).dopwintitle, $
    (*(*info).winids).sjiwintitle, $
    (*(*info).winids).phiswintitle,*(*(*info).winids).restloopwintitle,$
    (*(*info).winids).retrdetwintitle,(*(*info).winids).loopwintitle,$
		(*(*info).winids).refloopwintitle,(*(*info).winids).sjiloopwintitle,$
    (*(*info).winids).intwintitle]
	wherenot0 = WHERE(tlbarr NE 0, count)
	IF ((*(*info).winswitch).dispwids AND (count GT 0)) THEN BEGIN
		FOR i=0,count-1 DO $
      WIDGET_CONTROL,tlbarr[wherenot0[i]], $
        BASE_SET_TITLE = STRTRIM(widarr[wherenot0[i]],2)+' - '+title_arr[wherenot0[i]]
	ENDIF ELSE BEGIN
		FOR i=0,count-1 DO $
      WIDGET_CONTROL,tlbarr[wherenot0[i]], BASE_SET_TITLE = title_arr[wherenot0[i]]
	ENDELSE
END

PRO CRISPEX_DISPLAYS_CT_IMAGE_SELECT, event
; Handles the selection of color table image
	WIDGET_CONTROL, event.TOP, GET_UVALUE = info
	IF (TOTAL(((*(*info).feedbparams).verbosity)[2:3]) GE 1) THEN $
    CRISPEX_VERBOSE_GET_ROUTINE, event
  ;imct_select = {0,1,2,3,4} -> All, Main, reference, Doppler, slit-jaw
  (*(*info).plotparams).imct_select = event.INDEX
  showarr = [1,1,(*(*info).winswitch).showref,(*(*info).dispswitch).drawdop,$
    (*(*info).winswitch).showsji]
  IF (event.INDEX EQ 0) THEN BEGIN
    IF (TOTAL((*(*info).plotparams).imct NE $
        4*(*(*info).plotparams).imct[0])) THEN $
      set_cbox_select = 0
  ENDIF ELSE $
    set_cbox_select = (*(*info).plotparams).imct[$
      ((*(*info).plotparams).imct_select-1)>0]+1
  WIDGET_CONTROL, (*(*info).ctrlscp).displays_ct_cbox, $
    SET_COMBOBOX_SELECT=set_cbox_select, $
    SENSITIVE=showarr[(*(*info).plotparams).imct_select]
END

PRO CRISPEX_DISPLAYS_CT_SELECT, event
; Handles the change mask overlay window
	WIDGET_CONTROL, event.TOP, GET_UVALUE = info
	IF (TOTAL(((*(*info).feedbparams).verbosity)[2:3]) GE 1) THEN $
    CRISPEX_VERBOSE_GET_ROUTINE, event
  ;imct_select = {0,1,2,3,4} -> All, Main, reference, Doppler, slit-jaw
  IF ((*(*info).plotparams).imct_select EQ 0) THEN $
    FOR i=0,N_ELEMENTS((*(*info).plotparams).imct)-1 DO $
	    (*(*info).plotparams).imct[i] = (event.INDEX-1)>0 $
  ELSE $
	  (*(*info).plotparams).imct[((*(*info).plotparams).imct_select-1)>0] = $
      (event.INDEX-1)>0
  IF (event.INDEX EQ 0) THEN $
    WIDGET_CONTROL, (*(*info).ctrlscp).displays_ct_cbox, $
      SET_COMBOBOX_SELECT=1
  ; Load RGB table from selected color table. If IRIS tables present, they start
  ; at 42 (N(ct_idl_names)+1)
  n_idl_names = N_ELEMENTS((*(*info).plotparams).ct_idl_names)
  n_iris_names = N_ELEMENTS((*(*info).plotparams).ct_iris_names)
  n_sdo_names = N_ELEMENTS((*(*info).plotparams).ct_sdo_names)
  IF (event.INDEX LT n_idl_names+1) THEN $
    LOADCT, (*(*info).plotparams).imct[((*(*info).plotparams).imct_select-1)>0], $
      RGB_TABLE=rgb_table, /SILENT $
  ELSE $
    rgb_table = $
      CRISPEX_GET_RGB_TABLE(TABLE_NAME=(STRSPLIT(event.STR,' ',/EXTRACT))[1], $
        IRIS=(((*(*info).plotparams).ct_iris_names[0] NE '') AND $
              (event.INDEX-1 LT n_idl_names+n_iris_names)), $
        SDO=(((*(*info).plotparams).ct_sdo_names[0] NE '') AND $
              (event.INDEX-1 GE n_idl_names+n_iris_names * $
              ((*(*info).plotparams).ct_iris_names[0] NE '') )) )
  CASE ((*(*info).plotparams).imct_select) OF
    0:  BEGIN
          (*(*info).plotparams).rgb_main = rgb_table
          (*(*info).plotparams).rgb_ref = rgb_table
          (*(*info).plotparams).rgb_dop = rgb_table
          FOR idx_sji=0,(*(*info).dataparams).nsjifiles-1 DO $
            *(*(*info).plotparams).rgb_sji[idx_sji] = rgb_table
        END
    1:  (*(*info).plotparams).rgb_main = rgb_table
    2:  (*(*info).plotparams).rgb_ref = rgb_table
    3:  (*(*info).plotparams).rgb_dop = rgb_table
    ELSE:  *(*(*info).plotparams).rgb_sji[(*(*info).plotparams).imct_select-4] = rgb_table
  ENDCASE
  CRISPEX_DRAW_CTBAR, event, $
    MAIN=(((*(*info).plotparams).imct_select EQ 0) OR $
          ((*(*info).plotparams).imct_select EQ 1)), $
    REFERENCE=((((*(*info).plotparams).imct_select EQ 0) OR $
                ((*(*info).plotparams).imct_select EQ 2)) AND $
                (*(*info).winswitch).showref), $
    DOPPLER=((((*(*info).plotparams).imct_select EQ 0) OR $
              ((*(*info).plotparams).imct_select EQ 3)) AND $
              (*(*info).winswitch).showdop), $
    SJI=((((*(*info).plotparams).imct_select EQ 0) OR $
          ((*(*info).plotparams).imct_select GE 4)) AND $
          (TOTAL((*(*info).winswitch).showsji) GE 1))
	CRISPEX_DRAW, event
END

PRO CRISPEX_DISPLAYS_DETSPECT_SET_BUTTONS, event
; Handles the setting of scaling buttons
	WIDGET_CONTROL, event.TOP, GET_UVALUE = info
	IF (TOTAL(((*(*info).feedbparams).verbosity)[2:3]) GE 1) THEN $
    CRISPEX_VERBOSE_GET_ROUTINE, event
	IF (*(*info).ctrlsswitch).imrefdetspect THEN BEGIN		
    ; If selected options for reference
		WIDGET_CONTROL, (*(*info).ctrlscp).subtract_but, $
      SET_BUTTON=(*(*info).plotswitch).ref_subtract
		WIDGET_CONTROL, (*(*info).ctrlscp).scale_detspect_but, $
      SET_BUTTON=(*(*info).dispswitch).ref_detspect_scale
		WIDGET_CONTROL, (*(*info).ctrlscp).lower_y_text, $
      SET_VALUE=STRTRIM((*(*(*info).plotaxes).ls_low_y_ref)[$
        (*(*info).dataparams).s_ref],2)
		WIDGET_CONTROL, (*(*info).ctrlscp).upper_y_text, $
      SET_VALUE=STRTRIM((*(*(*info).plotaxes).ls_upp_y_ref)[$
        (*(*info).dataparams).s_ref],2)
		WIDGET_CONTROL, (*(*info).ctrlscp).detspect_label, $
      SET_VALUE=((*(*info).plottitles).lswintitle)[$
      (*(*info).plotswitch).refheightset]+':'
	ENDIF ELSE BEGIN				
    ; If selected options for main
		WIDGET_CONTROL, (*(*info).ctrlscp).subtract_but, $
      SET_BUTTON=(*(*info).plotswitch).subtract
		WIDGET_CONTROL, (*(*info).ctrlscp).scale_detspect_but, $
      SET_BUTTON=(*(*info).dispswitch).detspect_scale
		WIDGET_CONTROL, (*(*info).ctrlscp).lower_y_text, $
      SET_VALUE=STRTRIM((*(*(*info).plotaxes).ls_low_y)[(*(*info).dataparams).s],2)
		WIDGET_CONTROL, (*(*info).ctrlscp).upper_y_text, $
      SET_VALUE=STRTRIM((*(*(*info).plotaxes).ls_upp_y)[(*(*info).dataparams).s],2)
		WIDGET_CONTROL, (*(*info).ctrlscp).detspect_label, $
      SET_VALUE=((*(*info).plottitles).lswintitle)[$
      (*(*info).plotswitch).heightset]+':'
	ENDELSE
	IF (((*(*info).feedbparams).verbosity)[3] EQ 1) THEN $
    CRISPEX_VERBOSE_GET, event, [(*(*info).ctrlsswitch).imrefdetspect], labels=['imrefdetspect']
END

PRO CRISPEX_DISPLAYS_DOPPLER_TOGGLE, event, NO_DRAW=no_draw
; Reference image window creation procedure
	WIDGET_CONTROL, event.TOP, GET_UVALUE = info
	IF (TOTAL(((*(*info).feedbparams).verbosity)[2:3]) GE 1) THEN $
    CRISPEX_VERBOSE_GET_ROUTINE, event, /IGNORE_LAST
	(*(*info).winswitch).showdop = event.SELECT
	IF (*(*info).winswitch).showdop THEN BEGIN
		title = 'CRISPEX'+(*(*info).sesparams).instance_label+': Doppler image'
		CRISPEX_WINDOW, (*(*info).winsizes).xywinx, (*(*info).winsizes).xywiny, $
      (*(*info).winids).root, title, doptlb, dopwid, $
      (*(*info).winsizes).dopxoffset,(*(*info).winsizes).dopyoffset, $
			DRAWID=dopdrawid, DRAWBASE=dopdrawbase, $
      /CTBAR_SHOW, CTBAR_DRAWID=ctbar_drawid
		(*(*info).winids).doptlb = doptlb		
    (*(*info).winids).dopwid = dopwid	
    (*(*info).winids).dopdrawid = dopdrawid
		(*(*info).winids).dopdrawbase = dopdrawbase	
    (*(*info).winids).dopwintitle = title
		WIDGET_CONTROL, dopdrawid, EVENT_PRO='CRISPEX_CURSOR', /SENSITIVE, $
      /DRAW_MOTION_EVENTS, /TRACKING_EVENTS,/DRAW_BUTTON_EVENTS
		WIDGET_CONTROL, doptlb, SET_UVALUE=info
    WIDGET_CONTROL, ctbar_drawid, GET_VALUE=dopdrawid_ctbar
    (*(*info).winids).dopdrawid_ctbar = [dopdrawid_ctbar, ctbar_drawid]
		IF ~KEYWORD_SET(NO_DRAW) THEN BEGIN
			CRISPEX_UPDATE_T, event
      CRISPEX_DRAW_CTBAR, event, /DOPPLER
			CRISPEX_DRAW_DOPPLER, event
		ENDIF
	ENDIF ELSE BEGIN
		(*(*info).dispswitch).drawdop = 0
		IF ~KEYWORD_SET(NO_DRAW) THEN BEGIN
			CRISPEX_DRAW_SPECTRAL, event
			CRISPEX_DRAW_TIMESLICES, event
		ENDIF
		WIDGET_CONTROL, (*(*info).winids).doptlb, /DESTROY
		(*(*info).winids).doptlb = 0
	ENDELSE
	IF (*(*info).overlayswitch).mask THEN CRISPEX_MASK_BUTTONS_SET, event
  IF ((*(*info).scaling).imrefscaling EQ 2) THEN BEGIN
    CRISPEX_SCALING_SET_BOXBUTTONS, event
    CRISPEX_SCALING_SET_SLIDERS, event
  ENDIF
	IF (((*(*info).feedbparams).verbosity)[3] EQ 1) THEN $
    CRISPEX_VERBOSE_GET, event, [(*(*info).winids).doptlb,(*(*info).winids).dopwid,(*(*info).winids).dopdrawid], labels=['doptlb','dopwid','dopdrawid']
END

PRO CRISPEX_DISPLAYS_HEADER, event
; Pops up window with header information
	WIDGET_CONTROL, event.TOP, GET_UVALUE = info
	IF (TOTAL(((*(*info).feedbparams).verbosity)[2:3]) GE 1) THEN $
    CRISPEX_VERBOSE_GET_ROUTINE, event
  files = ['Main: ','Reference: ']  
  hdrlen = [STRLEN((*(*(*(*info).dataparams).hdrs[0])[0])[0]), $
            STRLEN((*(*(*(*info).dataparams).hdrs[1])[0])[0])]
  ; Append SJI header length and SJI label to "files"; has to be flexible
  FOR idx_sji=0,(*(*info).dataparams).nsjifiles-1 DO BEGIN
    files = [files, 'Slit-jaw image '+$
      STRJOIN((*(*info).dataparams).sji_labels[*,idx_sji],' ')+': ']
    hdrlen = [hdrlen, $
      STRLEN((*(*(*(*info).dataparams).hdrs[2+idx_sji])[0])[0])]
  ENDFOR
  wherefileset = WHERE((hdrlen GT 0) EQ 1, count)
  IF (count GT 0) THEN BEGIN
    FOR i=0,count-1 DO BEGIN
      exte_idx = INDGEN((*(*info).dataparams).next[wherefileset[i]])
      tmp_vals = REPLICATE(files[wherefileset[i]],(*(*info).dataparams).next[wherefileset[i]])+$
        REPLICATE('Extension ',(*(*info).dataparams).next[wherefileset[i]])+$
        STRTRIM(exte_idx,2)
      tmp_uvals = [[REPLICATE(wherefileset[i],(*(*info).dataparams).next[wherefileset[i]])],[exte_idx]]
      IF (i EQ 0) THEN BEGIN
        vals = tmp_vals 
        uvals = tmp_uvals
      ENDIF ELSE BEGIN
        vals = [vals,tmp_vals]
        uvals = [uvals,tmp_uvals]
      ENDELSE
    ENDFOR
  	base = WIDGET_BASE(TITLE = 'CRISPEX'+(*(*info).sesparams).instance_label+$
      ': File headers', GROUP_LEADER = (*(*info).winids).root, TLB_FRAME_ATTR = 1, $
      /TLB_KILL_REQUEST_EVENTS)
  	disp = WIDGET_BASE(base, /COLUMN)
    (*(*info).ctrlshdr).header_select = WIDGET_COMBOBOX(disp, VALUE=vals, UVALUE=uvals, $
      EVENT_PRO='CRISPEX_DISPLAYS_HEADER_SELECT')
    text_base = WIDGET_BASE(disp, /COLUMN)
    (*(*info).ctrlshdr).header_txt = WIDGET_TEXT(text_base, $
      VALUE=(*(*(*(*info).dataparams).hdrs[0])[0]), XSIZE=CEIL(MAX(hdrlen)*1.1), $
      YSIZE=CEIL(MAX(hdrlen)/2.), /SCROLL, /WRAP)
    close_base = WIDGET_BASE(disp, /ALIGN_CENTER)
    close_button = WIDGET_BUTTON(close_base, VALUE='Close', EVENT_PRO='CRISPEX_CLOSE_EVENT_WINDOW')
  	WIDGET_CONTROL, base, /REALIZE, TLB_SET_XOFFSET = (*(*info).winsizes).lsxoffset, $
      TLB_SET_YOFFSET = (*(*info).winsizes).lswiny+1.5*(*(*info).winsizes).ydelta
  	WIDGET_CONTROL, base, SET_UVALUE = info
  	XMANAGER, 'CRISPEX', base, /NO_BLOCK
    (*(*info).winids).headertlb = base
  ENDIF ELSE BEGIN
  	CRISPEX_WINDOW_OK, event,'ERROR!','No file headers to display.', $
  		OK_EVENT='CRISPEX_CLOSE_EVENT_WINDOW', BASE=tlb
  	(*(*info).winids).errtlb = tlb
  ENDELSE 
END

PRO CRISPEX_DISPLAYS_HEADER_SELECT, event
; Handles changing of header display
	WIDGET_CONTROL, event.TOP, GET_UVALUE = info
	IF (TOTAL(((*(*info).feedbparams).verbosity)[2:3]) GE 1) THEN $
    CRISPEX_VERBOSE_GET_ROUTINE, event
  WIDGET_CONTROL, (*(*info).ctrlshdr).header_select, GET_UVALUE=uvals
  WIDGET_CONTROL, (*(*info).ctrlshdr).header_txt, $
    SET_VALUE=(*(*(*(*info).dataparams).hdrs[uvals[event.INDEX,0]])[uvals[event.INDEX,1]])
END

PRO CRISPEX_DISPLAYS_INT_MENU, event, XOFFSET=xoffset, YOFFSET=yoffset
; Sets up the lightcurve plot options menu
  WIDGET_CONTROL, event.TOP, GET_UVALUE=info
	IF (TOTAL(((*(*info).feedbparams).verbosity)[2:3]) GE 1) THEN $
    CRISPEX_VERBOSE_GET_ROUTINE, event
  nsel_diagnostics = N_ELEMENTS(*(*(*info).intparams).sel_diagnostics)
  IF (nsel_diagnostics EQ 1) THEN BEGIN
    (*(*(*info).intparams).sel_diagnostics)[0] = (*(*info).intparams).lp_diag_all
    (*(*(*info).intparams).sellp_diagnostics)[0] = (*(*info).dataparams).lp
  ENDIF
	eventval = INDGEN(nsel_diagnostics)
	base = WIDGET_BASE(TITLE = 'CRISPEX'+(*(*info).sesparams).instance_label+$
    ': Lightcurve plot options', GROUP_LEADER = (*(*info).winids).root, $
    TLB_FRAME_ATTR = 1, /TLB_KILL_REQUEST_EVENTS)
	disp = WIDGET_BASE(base, /COLUMN)
  top_opts = WIDGET_BASE(disp, /ROW)
	sel_allnone = WIDGET_BASE(top_opts, /ROW, /ALIGN_LEFT)
	sel_allnone_lab = WIDGET_LABEL(sel_allnone, VALUE = 'Plot selected diagnostics:', $
    /ALIGN_LEFT)
	sel_allnone_buts = CW_BGROUP(sel_allnone, ['All','None'], BUTTON_UVALUE=INDGEN(2), $
    IDS=sel_allnone_ids, /EXCLUSIVE, /ROW, EVENT_FUNC='CRISPEX_BGROUP_INT_SEL_ALLNONE', $
    /NO_RELEASE)
  ; Set buttons
  set_allnone_buts = [(TOTAL(*(*(*info).intparams).seldisp_diagnostics) EQ $
    N_ELEMENTS(*(*(*info).intparams).sel_diagnostics)), $
    (TOTAL(*(*(*info).intparams).seldisp_diagnostics) EQ 0)]
  FOR i=0,N_ELEMENTS(sel_allnone_ids)-1 DO $
    WIDGET_CONTROL, sel_allnone_ids[i], SET_BUTTON=set_allnone_buts[i]
  (*(*info).ctrlsint).sel_allnone_ids = sel_allnone_ids
  ; Y-range input boxes
	yrange_base = WIDGET_BASE(top_opts, /ROW, /ALIGN_RIGHT)
	lower_y_label = WIDGET_LABEL(yrange_base, VALUE = '     Y-range:')
	(*(*info).ctrlsint).lower_y_int_text = WIDGET_TEXT(yrange_base, $
    VALUE=STRTRIM((*(*(*info).plotaxes).int_low_y)[(*(*info).dataparams).s],2), $
    /EDITABLE, XSIZE=5, EVENT_PRO='CRISPEX_DISPRANGE_INT_LOW')
	upper_y_label = WIDGET_LABEL(yrange_base, VALUE = '-')
	(*(*info).ctrlsint).upper_y_int_text = WIDGET_TEXT(yrange_base, $
    VALUE=STRTRIM((*(*(*info).plotaxes).int_upp_y)[(*(*info).dataparams).s],2), $
    /EDITABLE, XSIZE=5, EVENT_PRO='CRISPEX_DISPRANGE_INT_UPP')
  topdivider = CRISPEX_WIDGET_DIVIDER(disp)
  selopts_base = WIDGET_BASE(disp,/COLUMN, Y_SCROLL_SIZE=(nsel_diagnostics GT 11)*400, $
    X_SCROLL_SIZE=(nsel_diagnostics GT 11)*550) 
  ; Line style combobox labels
  ls_labels = STRTRIM(INDGEN(6),2)+' ('+(*(*info).intparams).linlab_diagnostics+')'
  FOR i=0,nsel_diagnostics-1 DO BEGIN
    ; Button names
    btname = 'int_sel_bt_'+STRTRIM(i,2)   ; (De)select button name
    dgname = 'int_sel_dg_'+STRTRIM(i,2)   ; Diagnostics combobox name
    lpname = 'int_sel_lp_'+STRTRIM(i,2)   ; Wavelength combobox name
    lsname = 'int_sel_ls_'+STRTRIM(i,2)   ; Line-style combobox name
    clname = 'int_sel_cl_'+STRTRIM(i,2)   ; Color combobox name
    ; Wavelength combobox labels
    lp_labels = LINDGEN((*(*info).intparams).diag_width[$
      (*(*(*info).intparams).sel_diagnostics)[i]])+$
      (*(*info).intparams).diag_start[$
      (*(*(*info).intparams).sel_diagnostics)[i]]
    IF (*(*info).plotswitch).v_dop_set THEN $
      lp_labels = STRTRIM(lp_labels,2)+' ('+STRTRIM((*(*info).dataparams).lps[$
        lp_labels[0]:lp_labels[N_ELEMENTS(lp_labels)-1]],2)+')' $
    ELSE $
      lp_labels = STRTRIM(lp_labels,2)
    ; Actual buttons and comboboxes
    sel_subopts = WIDGET_BASE(selopts_base, /ROW)
    sel_buts = WIDGET_BASE(sel_subopts, /NONEXCLUSIVE)
    sel_but = WIDGET_BUTTON(sel_buts, VALUE='', UVALUE=eventval[i], $
      EVENT_PRO='CRISPEX_DISPLAYS_INT_MENU_EVENT', UNAME=btname)
    (*(*info).ctrlsint).dg_box = WIDGET_COMBOBOX(sel_subopts, VALUE=(*(*info).intparams).diagnostics, $
      UVALUE=eventval[i], /DYNAMIC_RESIZE, EVENT_PRO='CRISPEX_DISPLAYS_INT_SEL_DIAG', $
      UNAME=dgname) 
    (*(*info).ctrlsint).lp_box = WIDGET_COMBOBOX(sel_subopts, VALUE=lp_labels,$
      UVALUE=eventval[i], /DYNAMIC_RESIZE, EVENT_PRO='CRISPEX_DISPLAYS_INT_SEL_LP', $
      UNAME=lpname) 
    (*(*info).ctrlsint).ls_box = WIDGET_COMBOBOX(sel_subopts, VALUE=ls_labels, $
      UVALUE=eventval[i], /DYNAMIC_RESIZE, EVENT_PRO='CRISPEX_DISPLAYS_INT_SEL_LINE', $
      UNAME=lsname)
    (*(*info).ctrlsint).cl_box = WIDGET_COMBOBOX(sel_subopts, $
      VALUE=(*(*info).intparams).collab_diagnostics, $
      UVALUE=eventval[i], /DYNAMIC_RESIZE, EVENT_PRO='CRISPEX_DISPLAYS_INT_SEL_COLS', $
      UNAME=clname)
    ; Set buttons: select display buttons
    WIDGET_CONTROL, sel_but, SET_BUTTON=(*(*(*info).intparams).seldisp_diagnostics)[i]
    WIDGET_CONTROL, (*(*info).ctrlsint).dg_box, $
      SET_COMBOBOX_SELECT=(*(*(*info).intparams).sel_diagnostics)[i],$
      SENSITIVE=( ((*(*info).intparams).ndiagnostics GT 1) AND $
        (*(*(*info).intparams).seldisp_diagnostics)[i] )
    WIDGET_CONTROL, (*(*info).ctrlsint).lp_box, $
      SET_COMBOBOX_SELECT=(*(*(*info).intparams).sellp_diagnostics)[i]-$
      (*(*info).intparams).diag_start[(*(*(*info).intparams).sel_diagnostics)[i]],$
      SENSITIVE=( ((*(*info).dataparams).nlp GT 1) AND $
        (*(*(*info).intparams).seldisp_diagnostics)[i] )
    WIDGET_CONTROL, (*(*info).ctrlsint).ls_box, $
      SET_COMBOBOX_SELECT=(*(*(*info).intparams).sellines_diagnostics)[i],$
      SENSITIVE=(*(*(*info).intparams).seldisp_diagnostics)[i]
    WIDGET_CONTROL, (*(*info).ctrlsint).cl_box, $
      SET_COMBOBOX_SELECT=(*(*(*info).intparams).selcol_diagnostics)[i],$
      SENSITIVE=(*(*(*info).intparams).seldisp_diagnostics)[i]
  ENDFOR
  add_base = WIDGET_BASE(selopts_base, /ROW, /ALIGN_RIGHT, GRID_LAYOUT=2)
  (*(*info).ctrlsint).remove_button = WIDGET_BUTTON(add_base, VALUE='Remove last lightcurve',$
    EVENT_PRO='CRISPEX_DISPLAYS_INT_REMOVE', $
    SENSITIVE=(N_ELEMENTS(*(*(*info).intparams).sel_diagnostics) GT 1))
  add_button = WIDGET_BUTTON(add_base, VALUE='Add lightcurve',$
    EVENT_PRO='CRISPEX_DISPLAYS_INT_ADD')
  bottomdivider = CRISPEX_WIDGET_DIVIDER(disp)
	button_base = WIDGET_BASE(disp, COLUMN=2, /GRID_LAYOUT, /ALIGN_CENTER)
	(*(*info).ctrlsint).int_sel_save = WIDGET_BUTTON(button_base, VALUE='   Save   ', $
    EVENT_PRO='CRISPEX_INT_SAVE')
	closebut = WIDGET_BUTTON(button_base, VALUE='   Close   ', $
    EVENT_PRO='CRISPEX_DISPLAYS_INT_MENU_CLOSE')
  ; Start managing
  IF (N_ELEMENTS(XOFFSET) NE 1) THEN xoffset = (*(*info).winsizes).aboutxoffset
  IF (N_ELEMENTS(YOFFSET) NE 1) THEN yoffset = (*(*info).winsizes).aboutyoffset
	WIDGET_CONTROL, base, /REALIZE, TLB_SET_XOFFSET=xoffset, TLB_SET_YOFFSET=yoffset
	WIDGET_CONTROL, base, SET_UVALUE = info
	XMANAGER, 'CRISPEX', base, /NO_BLOCK
	(*(*info).winids).intmenutlb = base
	IF (((*(*info).feedbparams).verbosity)[3] EQ 1) THEN $
    CRISPEX_VERBOSE_GET, event, [(*(*info).winids).intmenutlb], labels=['intmenutlb']
END

PRO CRISPEX_DISPLAYS_INT_MENU_EVENT, event
; Handles the selection of diagnostics to be shown in the lightcurve plot
	WIDGET_CONTROL, event.TOP, GET_UVALUE = info
	IF (TOTAL(((*(*info).feedbparams).verbosity)[2:3]) GE 1) THEN $
    CRISPEX_VERBOSE_GET_ROUTINE, event
	WIDGET_CONTROL, event.ID, GET_UVALUE = eventval
	(*(*(*info).intparams).seldisp_diagnostics)[eventval] = $
    ( (*(*(*info).intparams).seldisp_diagnostics)[eventval] EQ 0) 
  dgname = 'int_sel_dg_'+STRTRIM(eventval,2)   ; Diagnostics combobox name
  lpname = 'int_sel_lp_'+STRTRIM(eventval,2)   ; Wavelength combobox name
  lsname = 'int_sel_ls_'+STRTRIM(eventval,2)   ; Line-style combobox name
  clname = 'int_sel_cl_'+STRTRIM(eventval,2)   ; Color combobox name
	WIDGET_CONTROL, WIDGET_INFO(event.TOP, FIND_BY_UNAME=dgname), $
    SENSITIVE=(*(*(*info).intparams).seldisp_diagnostics)[eventval]
	WIDGET_CONTROL, WIDGET_INFO(event.TOP, FIND_BY_UNAME=lpname), $
    SENSITIVE=(*(*(*info).intparams).seldisp_diagnostics)[eventval]
	WIDGET_CONTROL, WIDGET_INFO(event.TOP, FIND_BY_UNAME=lsname), $
    SENSITIVE=(*(*(*info).intparams).seldisp_diagnostics)[eventval]
	WIDGET_CONTROL, WIDGET_INFO(event.TOP, FIND_BY_UNAME=clname), $
    SENSITIVE=(*(*(*info).intparams).seldisp_diagnostics)[eventval]
	IF (((*(*info).feedbparams).verbosity)[3] EQ 1) THEN $
    CRISPEX_VERBOSE_GET, event, [eventval,(*(*(*info).intparams).sel_diagnostics)[eventval]], $
      labels=['Diagnostic ID','Diagnostic selected']
	CRISPEX_DISPLAYS_INT_BUTTON_CONDITION, event
	CRISPEX_DRAW, event
END

PRO CRISPEX_DISPLAYS_INT_BUTTON_CONDITION, event
; Handles the update of buttons after selection
	WIDGET_CONTROL, event.TOP, GET_UVALUE = info
	IF (TOTAL(((*(*info).feedbparams).verbosity)[2:3]) GE 1) THEN $
    CRISPEX_VERBOSE_GET_ROUTINE, event
	condition = WHERE(*(*(*info).intparams).seldisp_diagnostics EQ 1, count)
	WIDGET_CONTROL, (*(*info).ctrlsint).int_sel_save, SENSITIVE = (count GT 0)
  WIDGET_CONTROL, (*(*info).ctrlsint).sel_allnone_ids[1], $
    SET_BUTTON=(count EQ 0)
  WIDGET_CONTROL, (*(*info).ctrlsint).sel_allnone_ids[0], $
    SET_BUTTON=(count EQ N_ELEMENTS(*(*(*info).intparams).seldisp_diagnostics))
	IF (((*(*info).feedbparams).verbosity)[3] EQ 1) THEN $
    CRISPEX_VERBOSE_GET, event, [(count EQ N_ELEMENTS(*(*(*info).intparams).seldisp_diagnostics)), $
      (count EQ 0), (count GT 0)], labels=['All selected','None selected','Save enabled']
END

PRO CRISPEX_DISPLAYS_INT_ADD, event
; Handles adding a lightcurve
	WIDGET_CONTROL, event.TOP, GET_UVALUE = info, /NO_COPY
	IF (TOTAL(((*(*info).feedbparams).verbosity)[2:3]) GE 1) THEN $
    CRISPEX_VERBOSE_GET_ROUTINE, event
  nsel_diagnostics = N_ELEMENTS(*(*(*info).intparams).sel_diagnostics)
  *(*(*info).intparams).sel_diagnostics = $
    [*(*(*info).intparams).sel_diagnostics,(*(*info).intparams).lp_diag_all]
  *(*(*info).intparams).seldisp_diagnostics = $
    [*(*(*info).intparams).seldisp_diagnostics,1B]
  *(*(*info).intparams).sellp_diagnostics = $
    [*(*(*info).intparams).sellp_diagnostics,(*(*info).dataparams).lp]
  *(*(*info).intparams).sellines_diagnostics = $
    [*(*(*info).intparams).sellines_diagnostics,$
    (((*(*(*info).intparams).sellines_diagnostics)[nsel_diagnostics-1]+1) MOD $
      N_ELEMENTS((*(*info).intparams).linlab_diagnostics))]
  *(*(*info).intparams).selcol_diagnostics = $
    [*(*(*info).intparams).selcol_diagnostics,$
    (((*(*(*info).intparams).selcol_diagnostics)[nsel_diagnostics-1]+1) MOD $
      N_ELEMENTS((*(*info).intparams).collab_diagnostics))]
  geometry = WIDGET_INFO((*(*info).winids).intmenutlb, /GEOMETRY)
  WIDGET_CONTROL, (*(*info).winids).root, SET_UVALUE=info
  WIDGET_CONTROL, event.TOP, /DESTROY
  event.TOP = (*(*info).winids).root
  CRISPEX_DISPLAYS_INT_MENU, event, XOFFSET=geometry.XOFFSET, $
    YOFFSET=geometry.YOFFSET-22   ; Empirically determined correction 
  CRISPEX_DRAW_INT, event
END

PRO CRISPEX_DISPLAYS_INT_REMOVE, event
; Handles adding a lightcurve
	WIDGET_CONTROL, event.TOP, GET_UVALUE = info, /NO_COPY
	IF (TOTAL(((*(*info).feedbparams).verbosity)[2:3]) GE 1) THEN $
    CRISPEX_VERBOSE_GET_ROUTINE, event
  nsel_diagnostics = N_ELEMENTS(*(*(*info).intparams).sel_diagnostics)
  *(*(*info).intparams).sel_diagnostics = (*(*(*info).intparams).sel_diagnostics)[0:nsel_diagnostics-2]
  *(*(*info).intparams).seldisp_diagnostics = $
    (*(*(*info).intparams).seldisp_diagnostics)[0:nsel_diagnostics-2]
  *(*(*info).intparams).sellp_diagnostics = $
    (*(*(*info).intparams).sellp_diagnostics)[0:nsel_diagnostics-2]
  *(*(*info).intparams).sellines_diagnostics = $
    (*(*(*info).intparams).sellines_diagnostics)[0:nsel_diagnostics-2]
  *(*(*info).intparams).selcol_diagnostics = $
    (*(*(*info).intparams).selcol_diagnostics)[0:nsel_diagnostics-2]
  geometry = WIDGET_INFO((*(*info).winids).intmenutlb, /GEOMETRY)
  WIDGET_CONTROL, (*(*info).winids).root, SET_UVALUE=info
  WIDGET_CONTROL, event.TOP, /DESTROY
  event.TOP = (*(*info).winids).root
  CRISPEX_DISPLAYS_INT_MENU, event, XOFFSET=geometry.XOFFSET, $
    YOFFSET=geometry.YOFFSET-22   ; Empirically determined correction 
  CRISPEX_DRAW_INT, event
END

PRO CRISPEX_DISPLAYS_INT_MENU_CLOSE, event
; Handles the closing of the intensity versus time plot options menu and clean-up of display afterwards
	WIDGET_CONTROL, event.TOP, GET_UVALUE = info
	IF (TOTAL(((*(*info).feedbparams).verbosity)[2:3]) GE 1) THEN $
    CRISPEX_VERBOSE_GET_ROUTINE, event
	IF (((*(*info).feedbparams).verbosity)[3] EQ 1) THEN $
    CRISPEX_VERBOSE_GET, event, [(*(*info).winids).intmenutlb,(*(*info).winids).inttlb], labels=['intmenutlb was','inttlb was']
	WIDGET_CONTROL, (*(*info).winids).intmenutlb, /DESTROY
	WIDGET_CONTROL, (*(*info).winids).inttlb, /DESTROY
	(*(*info).winids).intmenutlb = 0
	(*(*info).winids).inttlb = 0
	WIDGET_CONTROL, (*(*info).ctrlscp).int_toggle_but, SET_BUTTON = 0
	(*(*info).winswitch).showint = 0
END

PRO CRISPEX_DISPLAYS_INT_SEL_COLS, event
; Handles selection of linestyle of intensity versus time plot
	WIDGET_CONTROL, event.TOP, GET_UVALUE = info
	IF (TOTAL(((*(*info).feedbparams).verbosity)[2:3]) GE 1) THEN $
    CRISPEX_VERBOSE_GET_ROUTINE, event
	WIDGET_CONTROL, event.ID, GET_UVALUE = eventval
	IF ( (*(*(*info).intparams).seldisp_diagnostics)[eventval] EQ 1) THEN $
    (*(*(*info).intparams).selcol_diagnostics)[eventval] = event.INDEX
	IF (((*(*info).feedbparams).verbosity)[3] EQ 1) THEN $
    CRISPEX_VERBOSE_GET, event, $
      [eventval,(*(*(*info).intparams).selcol_diagnostics)[eventval]], $
      labels=['Diagnostic ID','Color index selected']
	CRISPEX_DRAW_INT, event
END

PRO CRISPEX_DISPLAYS_INT_SEL_LINE, event
; Handles selection of linestyle of intensity versus time plot
	WIDGET_CONTROL, event.TOP, GET_UVALUE = info
	IF (TOTAL(((*(*info).feedbparams).verbosity)[2:3]) GE 1) THEN $
    CRISPEX_VERBOSE_GET_ROUTINE, event
	WIDGET_CONTROL, event.ID, GET_UVALUE = eventval
	IF ( (*(*(*info).intparams).seldisp_diagnostics)[eventval] EQ 1) THEN $
    (*(*(*info).intparams).sellines_diagnostics)[eventval] = event.INDEX
	IF (((*(*info).feedbparams).verbosity)[3] EQ 1) THEN $
    CRISPEX_VERBOSE_GET, event, $
      [eventval,(*(*(*info).intparams).sellines_diagnostics)[eventval]], $
      labels=['Diagnostic ID','Linestyle selected']
	CRISPEX_DRAW_INT, event
END

PRO CRISPEX_DISPLAYS_INT_SEL_DIAG, event
; Handles selection of linestyle of intensity versus time plot
	WIDGET_CONTROL, event.TOP, GET_UVALUE = info
	IF (TOTAL(((*(*info).feedbparams).verbosity)[2:3]) GE 1) THEN $
    CRISPEX_VERBOSE_GET_ROUTINE, event
	WIDGET_CONTROL, event.ID, GET_UVALUE = eventval
	IF ( (*(*(*info).intparams).seldisp_diagnostics)[eventval] EQ 1) THEN $
    (*(*(*info).intparams).sel_diagnostics)[eventval] = event.INDEX
  ; Adjust possible wavelengths
  lp_labels = LINDGEN((*(*info).intparams).diag_width[$
    (*(*(*info).intparams).sel_diagnostics)[eventval]])+$
    (*(*info).intparams).diag_start[$
    (*(*(*info).intparams).sel_diagnostics)[eventval]]
  IF (*(*info).plotswitch).v_dop_set THEN $
    lp_labels = STRTRIM(lp_labels,2)+' ('+STRTRIM((*(*info).dataparams).lps[$
      lp_labels[0]:lp_labels[N_ELEMENTS(lp_labels)-1]],2)+')' $
  ELSE $
    lp_labels = STRTRIM(lp_labels,2)
  ; Change wavelength combobox accordingly
	WIDGET_CONTROL, WIDGET_INFO(event.TOP, FIND_BY_UNAME='int_sel_lp_'+STRTRIM(eventval,2)), $
    SET_VALUE=lp_labels, SET_COMBOBOX_SELECT=0
  ; Change actual wavelength variable to reflect adjustment
  (*(*(*info).intparams).sellp_diagnostics)[eventval] = $
    (*(*info).intparams).diag_start[(*(*(*info).intparams).sel_diagnostics)[eventval]]
	CRISPEX_DRAW_INT, event
END

PRO CRISPEX_DISPLAYS_INT_SEL_LP, event
; Handles selection of linestyle of intensity versus time plot
	WIDGET_CONTROL, event.TOP, GET_UVALUE = info
	IF (TOTAL(((*(*info).feedbparams).verbosity)[2:3]) GE 1) THEN $
    CRISPEX_VERBOSE_GET_ROUTINE, event
	WIDGET_CONTROL, event.ID, GET_UVALUE = eventval
	IF ( (*(*(*info).intparams).seldisp_diagnostics)[eventval] EQ 1) THEN $
    (*(*(*info).intparams).sellp_diagnostics)[eventval] = event.INDEX+$
      (*(*info).intparams).diag_start[(*(*(*info).intparams).sel_diagnostics)[eventval]]
	CRISPEX_DRAW_INT, event
END

PRO CRISPEX_DISPLAYS_INT_RESIZE, event						
; Intensity versus time window resize handler, gets new window dimensions and calls (re)display routines
	WIDGET_CONTROL, event.TOP, GET_UVALUE = info
	IF (TOTAL(((*(*info).feedbparams).verbosity)[2:3]) GE 1) THEN $
    CRISPEX_VERBOSE_GET_ROUTINE, event
	CRISPEX_DISPLAYS_PLOT_RESIZE, event, event.X, event.Y, (*(*info).winsizes).intxres, $
    (*(*info).winsizes).intyres, (*(*info).plotpos).intxmargin_init, (*(*info).plotpos).intxwall_init, $
		intxres, intyres, intwidth, intheight, intx0, intx1, inty0, inty1, ERROR=error
	IF error THEN CRISPEX_DISPLAYS_RESIZE_ERROR, event ELSE BEGIN
		(*(*info).winsizes).intxres = intxres		& 	(*(*info).winsizes).intyres = intyres
		(*(*info).plotpos).intx0 = intx0		&	(*(*info).plotpos).intx1 = intx1
		(*(*info).plotpos).inty0 = inty0		&	(*(*info).plotpos).inty1 = inty1
		(*(*info).plotaxes).intxticklen = (*(*info).plotaxes).ticklen / intheight
		(*(*info).plotaxes).intyticklen = (*(*info).plotaxes).ticklen / intwidth
	ENDELSE
	IF (((*(*info).feedbparams).verbosity)[3] EQ 1) THEN $
    CRISPEX_VERBOSE_GET, event, [error,(*(*info).winsizes).intxres,(*(*info).winsizes).intyres,(*(*info).plotpos).intx0,(*(*info).plotpos).intx1,$
		(*(*info).plotpos).inty0,(*(*info).plotpos).inty1], labels=['error','intxres','intyres','intx0','intx1','inty0','inty1']
	WIDGET_CONTROL, (*(*info).winids).intdrawid, DRAW_XSIZE = (*(*info).winsizes).intxres, DRAW_YSIZE = (*(*info).winsizes).intyres
	WIDGET_CONTROL, event.TOP, SET_UVALUE = info
	CRISPEX_DRAW_INT, event
END

PRO CRISPEX_DISPLAYS_INT_TOGGLE, event, NO_DRAW=no_draw
; Intensity versus time window creation procedure
	WIDGET_CONTROL, event.TOP, GET_UVALUE = info
	IF (TOTAL(((*(*info).feedbparams).verbosity)[2:3]) GE 1) THEN $
    CRISPEX_VERBOSE_GET_ROUTINE, event
	(*(*info).winswitch).showint = event.SELECT
	IF (*(*info).winswitch).showint THEN BEGIN
		CRISPEX_DISPLAYS_INT_MENU, event
		title = 'CRISPEX'+(*(*info).sesparams).instance_label+': Lightcurve plot'
		CRISPEX_WINDOW, (*(*info).winsizes).intxres, (*(*info).winsizes).intyres, $
      (*(*info).winids).root, title, inttlb, intwid, $
      (*(*info).winsizes).lsxoffset, 0, DRAWID = intdrawid, $
			RESIZING = 1, RES_HANDLER = 'CRISPEX_DISPLAYS_INT_RESIZE'
		(*(*info).winids).inttlb = inttlb	&	(*(*info).winids).intwid = intwid	&	(*(*info).winids).intdrawid = intdrawid
		(*(*info).winids).intwintitle = title
		WIDGET_CONTROL, (*(*info).winids).inttlb, SET_UVALUE = info
		IF (((*(*info).feedbparams).verbosity)[3] EQ 1) THEN $
      CRISPEX_VERBOSE_GET, event, [(*(*info).winids).inttlb,(*(*info).winids).intwid,(*(*info).winids).intdrawid], labels=['inttlb','intwid','intdrawid']
		IF ~KEYWORD_SET(NO_DRAW) THEN CRISPEX_DRAW_INT, event
	ENDIF ELSE CRISPEX_DISPLAYS_INT_MENU_CLOSE, event
END

PRO CRISPEX_DISPLAYS_LOOPSLAB_GET, event
; Loopslab window creation procedure
	WIDGET_CONTROL, event.TOP, GET_UVALUE = info
	IF (TOTAL(((*(*info).feedbparams).verbosity)[2:3]) GE 1) THEN $
    CRISPEX_VERBOSE_GET_ROUTINE, event
	IF (((*(*info).dataparams).refnt GT 1) OR $
	    (TOTAL((*(*info).dataparams).sjint) GT (*(*info).dataparams).nsjifiles)) THEN BEGIN
		CRISPEX_DISPLAYS_LOOPSLAB, event
  	IF ((*(*info).dataparams).refnt GT 1) THEN CRISPEX_DISPLAYS_REFLOOPSLAB, event
  	IF ((*(*info).dataswitch).sjifile AND (TOTAL((*(*info).dataparams).sjint) GT $
        (*(*info).dataparams).nsjifiles)) THEN CRISPEX_DISPLAYS_SJILOOPSLAB, event
  ENDIF ELSE CRISPEX_DISPLAYS_LOOPSLAB, event
END

PRO CRISPEX_DISPLAYS_LOOPSLAB_REPLOT_AXES, event					
; Updates loopslab display window plot axes range according to set parameters
	WIDGET_CONTROL, event.TOP, GET_UVALUE = info
	IF (TOTAL(((*(*info).feedbparams).verbosity)[2:3]) GE 1) THEN $
    CRISPEX_VERBOSE_GET_ROUTINE, event
	WSET, (*(*info).winids).loopwid
	PLOT, FINDGEN((*(*info).loopsdata).loopsize), $
    *(*(*info).dispparams).tarr_main, /NODATA, $
    YR=[(*(*info).dispparams).t_low_main,(*(*info).dispparams).t_upp_main], $
    /YS, POS = [(*(*info).plotpos).loopx0,(*(*info).plotpos).loopy0,$
    (*(*info).plotpos).loopx1,(*(*info).plotpos).loopy1], $
    YTICKLEN=(*(*info).plotaxes).loopyticklen,$
    XTICKLEN=(*(*info).plotaxes).loopxticklen, /XS, $
    YTITLE=(*(*info).plottitles).spytitle, $
    XTITLE='Pixel along loop', BACKGROUND=(*(*info).plotparams).bgplotcol, $
    COLOR=(*(*info).plotparams).plotcol
  IF (((*(*info).feedbparams).verbosity)[3] EQ 1) THEN $
    CRISPEX_VERBOSE_GET, event, [(*(*info).winids).loopwid], $
      labels=['Window ID for replot']
END

PRO CRISPEX_DISPLAYS_LOOPSLAB_RESIZE, event
; Loopslab window resize handler, gets new window dimensions and calls (re)display routines
	WIDGET_CONTROL, event.TOP, GET_UVALUE = info
	IF (TOTAL(((*(*info).feedbparams).verbosity)[2:3]) GE 1) THEN $
    CRISPEX_VERBOSE_GET_ROUTINE, event
	CRISPEX_DISPLAYS_PLOT_RESIZE, event, event.X, event.Y, (*(*info).winsizes).loopxres, (*(*info).winsizes).loopyres, (*(*info).plotpos).loopxmargin_init, (*(*info).plotpos).loopxwall_init, $
		loopxres, loopyres, loopwidth, loopheight, loopx0, loopx1, loopy0, loopy1, ERROR=error, /SLICE
	IF error THEN CRISPEX_DISPLAYS_RESIZE_ERROR, event ELSE BEGIN
		(*(*info).winsizes).loopxres = loopxres			& 	(*(*info).winsizes).loopyres = loopyres
		(*(*info).plotpos).loopx0 = loopx0			&	(*(*info).plotpos).loopx1 = loopx1
		(*(*info).plotpos).loopy0 = loopy0			&	(*(*info).plotpos).loopy1 = loopy1
		(*(*info).plotpos).loopxplspw = loopx1 - loopx0		&	(*(*info).plotpos).loopyplspw = loopy1 - loopy0
		(*(*info).plotaxes).loopxticklen = -1 * (*(*info).plotaxes).ticklen / loopheight
		(*(*info).plotaxes).loopyticklen = -1 * (*(*info).plotaxes).ticklen / loopwidth
		(*(*info).dispparams).loopnlxreb = (*(*info).plotpos).loopxplspw * (*(*info).winsizes).loopxres 
		(*(*info).dispparams).loopntreb = (*(*info).plotpos).loopyplspw * (*(*info).winsizes).loopyres 
	ENDELSE
	IF (((*(*info).feedbparams).verbosity)[3] EQ 1) THEN $
    CRISPEX_VERBOSE_GET, event, [error,(*(*info).winsizes).loopxres,(*(*info).winsizes).loopyres,(*(*info).plotpos).loopx0,(*(*info).plotpos).loopx1,$
		(*(*info).plotpos).loopy0,(*(*info).plotpos).loopy1], labels=['error','loopxres','loopyres','loopx0','loopx1','loopy0','loopy1']
	WIDGET_CONTROL, (*(*info).winids).loopdrawid, DRAW_XSIZE = (*(*info).winsizes).loopxres, DRAW_YSIZE = (*(*info).winsizes).loopyres
	WIDGET_CONTROL, event.TOP, SET_UVALUE = info
	CRISPEX_DISPLAYS_LOOPSLAB_REPLOT_AXES, event
	CRISPEX_DRAW_LOOPSLAB, event
END

PRO CRISPEX_DISPLAYS_LOOPSLAB, event, NO_DRAW=no_draw
; Loopslab window creation procedure
	WIDGET_CONTROL, event.TOP, GET_UVALUE = info
	IF (TOTAL(((*(*info).feedbparams).verbosity)[2:3]) GE 1) THEN $
    CRISPEX_VERBOSE_GET_ROUTINE, event
	(*(*info).winswitch).showloop = 1
	WIDGET_CONTROL,/HOURGLASS
	CRISPEX_LOOP_GET_PATH, event, /MAIN, /REFERENCE, /SJI
	CRISPEX_LOOP_GET_SLAB, event
	title = 'CRISPEX'+(*(*info).sesparams).instance_label+': Space-time plot'
	CRISPEX_WINDOW, (*(*info).winsizes).loopxres, (*(*info).winsizes).loopyres, $
    (*(*info).winids).root, title, tlb, wid, $
    (*(*info).winsizes).loopxoffset, (*(*info).winsizes).loopyoffset, $
    DRAWID=loopdrawid, RESIZING=1, RES_HANDLER='CRISPEX_DISPLAYS_LOOPSLAB_RESIZE'
	PLOT, FINDGEN((*(*info).loopsdata).loopsize), $
    *(*(*info).dispparams).tarr_main, /NODATA, $
    YR=[(*(*info).dispparams).t_low_main,(*(*info).dispparams).t_upp_main], $
    /YS, POS=[(*(*info).plotpos).loopx0,(*(*info).plotpos).loopy0,$
    (*(*info).plotpos).loopx1,(*(*info).plotpos).loopy1],$
		YTICKLEN=(*(*info).plotaxes).loopyticklen, $
    XTICKLEN=(*(*info).plotaxes).loopxticklen, /XS, $
    YTITLE=(*(*info).plottitles).spytitle, XTITLE='Pixel along loop',$
		BACKGROUND = (*(*info).plotparams).bgplotcol, $
    COLOR=(*(*info).plotparams).plotcol
	(*(*info).winids).looptlb = tlb		&	(*(*info).winids).loopwid = wid		
  (*(*info).winids).loopdrawid = loopdrawid
	(*(*info).winids).loopwintitle = title 
	WIDGET_CONTROL, (*(*info).winids).looptlb, SET_UVALUE = info
	IF ~KEYWORD_SET(NO_DRAW) THEN BEGIN
		CRISPEX_UPDATE_LP, event
		CRISPEX_ZOOM_LOOP, event
		CRISPEX_DRAW, event
	ENDIF
	WIDGET_CONTROL, (*(*info).ctrlscp).save_loop_pts, SENSITIVE = 1
	WIDGET_CONTROL, (*(*info).ctrlscp).timeslicemenu, SENSITIVE = 1
	WIDGET_CONTROL, (*(*info).ctrlscp).loop_slice_but, SENSITIVE = 0
	IF (((*(*info).feedbparams).verbosity)[3] EQ 1) THEN $
    CRISPEX_VERBOSE_GET, event, [(*(*info).winids).looptlb,$
      (*(*info).winids).loopwid,(*(*info).winids).loopdrawid], $
      labels=['looptlb','loopwid','loopdrawid']
END

PRO CRISPEX_DISPLAYS_REFLOOPSLAB_REPLOT_AXES, event					
; Updates reference loopslab display window plot axes range according to set 
; parameters
	WIDGET_CONTROL, event.TOP, GET_UVALUE = info
	IF (TOTAL(((*(*info).feedbparams).verbosity)[2:3]) GE 1) THEN $
    CRISPEX_VERBOSE_GET_ROUTINE, event
	WSET, (*(*info).winids).refloopwid
	PLOT, FINDGEN((*(*info).loopsdata).refloopsize), $
    *(*(*info).dispparams).tarr_ref, /NODATA, /YS, $
    YR=[(*(*info).dispparams).t_low_ref,(*(*info).dispparams).t_upp_ref], $
    POS=[(*(*info).plotpos).refloopx0,(*(*info).plotpos).refloopy0, $
    (*(*info).plotpos).refloopx1,(*(*info).plotpos).refloopy1], $
		YTICKLEN=(*(*info).plotaxes).refloopyticklen, $
    XTICKLEN=(*(*info).plotaxes).refloopxticklen, /XS, $
    YTITLE=(*(*info).plottitles).spytitle, XTITLE='Pixel along loop', $
		BACKGROUND=(*(*info).plotparams).bgplotcol, $
    COLOR=(*(*info).plotparams).plotcol
	IF (((*(*info).feedbparams).verbosity)[3] EQ 1) THEN $
    CRISPEX_VERBOSE_GET, event, [(*(*info).winids).refloopwid], $
      labels=['Window ID for replot']
END

PRO CRISPEX_DISPLAYS_REFLOOPSLAB_RESIZE, event
; Reference loopslab window resize handler, gets new window dimensions and calls (re)display routines
	WIDGET_CONTROL, event.TOP, GET_UVALUE = info
	IF (TOTAL(((*(*info).feedbparams).verbosity)[2:3]) GE 1) THEN $
    CRISPEX_VERBOSE_GET_ROUTINE, event
	CRISPEX_DISPLAYS_PLOT_RESIZE, event, event.X, event.Y, (*(*info).winsizes).refloopxres, (*(*info).winsizes).refloopyres, (*(*info).plotpos).refloopxmargin_init, (*(*info).plotpos).refloopxwall_init, $
		refloopxres, refloopyres, refloopwidth, refloopheight, refloopx0, refloopx1, refloopy0, $
  refloopy1, ERROR=error, /SLICE
	IF error THEN CRISPEX_DISPLAYS_RESIZE_ERROR, event ELSE BEGIN
		(*(*info).winsizes).refloopxres = refloopxres			& 	(*(*info).winsizes).refloopyres = refloopyres
		(*(*info).plotpos).refloopx0 = refloopx0			&	(*(*info).plotpos).refloopx1 = refloopx1
		(*(*info).plotpos).refloopy0 = refloopy0			&	(*(*info).plotpos).refloopy1 = refloopy1
		(*(*info).plotpos).refloopxplspw = refloopx1 - refloopx0	&	(*(*info).plotpos).refloopyplspw = refloopy1 - refloopy0
		(*(*info).plotaxes).refloopxticklen = -1 * (*(*info).plotaxes).ticklen / refloopheight
		(*(*info).plotaxes).refloopyticklen = -1 * (*(*info).plotaxes).ticklen / refloopwidth
		(*(*info).dispparams).refloopnlxreb = (*(*info).plotpos).refloopxplspw * (*(*info).winsizes).refloopxres 
		(*(*info).dispparams).refloopntreb = (*(*info).plotpos).refloopyplspw * (*(*info).winsizes).refloopyres 
	ENDELSE
	IF (((*(*info).feedbparams).verbosity)[3] EQ 1) THEN $
    CRISPEX_VERBOSE_GET, event, [error,(*(*info).winsizes).refloopxres,(*(*info).winsizes).refloopyres,(*(*info).plotpos).refloopx0,(*(*info).plotpos).refloopx1,$
		(*(*info).plotpos).refloopy0,(*(*info).plotpos).refloopy1], labels=['error','refloopxres','refloopyres','refloopx0','refloopx1','refloopy0','refloopy1']
	WIDGET_CONTROL, (*(*info).winids).refloopdrawid, DRAW_XSIZE = (*(*info).winsizes).refloopxres, DRAW_YSIZE = (*(*info).winsizes).refloopyres
	WIDGET_CONTROL, event.TOP, SET_UVALUE = info
	CRISPEX_DISPLAYS_REFLOOPSLAB_REPLOT_AXES, event
	CRISPEX_DRAW_REFLOOPSLAB, event
END

PRO CRISPEX_DISPLAYS_REFLOOPSLAB, event, NO_DRAW=no_draw
; Reference, loopslab window creation procedure
	WIDGET_CONTROL, event.TOP, GET_UVALUE = info
	IF (TOTAL(((*(*info).feedbparams).verbosity)[2:3]) GE 1) THEN $
    CRISPEX_VERBOSE_GET_ROUTINE, event
	(*(*info).winswitch).showrefloop = 1
	WIDGET_CONTROL,/HOURGLASS
	CRISPEX_LOOP_GET_REFSLAB, event		
	title = 'CRISPEX'+(*(*info).sesparams).instance_label+$
    ': Reference space-time plot'
	CRISPEX_WINDOW, (*(*info).winsizes).refloopxres, $
    (*(*info).winsizes).refloopyres, (*(*info).winids).root, title, tlb, wid, $
    (*(*info).winsizes).xywinx+(*(*info).winsizes).xdelta, $
		((*(*info).winswitch).showsp + (*(*info).winswitch).showphis) * $
    (*(*info).winsizes).ydelta, DRAWID=refloopdrawid, RESIZING=1, $
    RES_HANDLER='CRISPEX_DISPLAYS_REFLOOPSLAB_RESIZE'
	PLOT, FINDGEN((*(*info).loopsdata).refloopsize), $
    *(*(*info).dispparams).tarr_ref, /NODATA, $
    YR=[(*(*info).dispparams).t_low_ref, (*(*info).dispparams).t_upp_ref], $
		/YS, POS=[(*(*info).plotpos).refloopx0,(*(*info).plotpos).refloopy0,$
    (*(*info).plotpos).refloopx1,(*(*info).plotpos).refloopy1],$
		YTICKLEN=(*(*info).plotaxes).refloopyticklen, $
    XTICKLEN=(*(*info).plotaxes).refloopxticklen, /XS, $
    YTITLE=(*(*info).plottitles).spytitle, XTITLE='Pixel along loop',$
		BACKGROUND=(*(*info).plotparams).bgplotcol, $
    COLOR=(*(*info).plotparams).plotcol
	(*(*info).winids).reflooptlb = tlb		&	(*(*info).winids).refloopwid = wid		
  (*(*info).winids).refloopdrawid = refloopdrawid
	(*(*info).winids).refloopwintitle = title 
	WIDGET_CONTROL, (*(*info).winids).reflooptlb, SET_UVALUE = info
	IF ~KEYWORD_SET(NO_DRAW) THEN BEGIN
		CRISPEX_UPDATE_LP, event
		CRISPEX_ZOOM_LOOP, event
		CRISPEX_DRAW, event
	ENDIF
	IF (((*(*info).feedbparams).verbosity)[3] EQ 1) THEN $
    CRISPEX_VERBOSE_GET, event, [(*(*info).winids).reflooptlb,$
      (*(*info).winids).refloopwid,(*(*info).winids).refloopdrawid], $
      labels=['reflooptlb','refloopwid','refloopdrawid']
END

PRO CRISPEX_DISPLAYS_SJILOOPSLAB_REPLOT_AXES, event, IDX_SJI=idx_sji
; Updates SJI loopslab display window plot axes range according to set 
; parameters
	WIDGET_CONTROL, event.TOP, GET_UVALUE = info
	IF (TOTAL(((*(*info).feedbparams).verbosity)[2:3]) GE 1) THEN $
    CRISPEX_VERBOSE_GET_ROUTINE, event
  IF (N_ELEMENTS(IDX_SJI) LT 1) THEN idx_sji = 0
	WSET, (*(*info).winids).sjiloopwid[idx_sji]
	PLOT, FINDGEN((*(*info).loopsdata).sjiloopsize[idx_sji]), $
    *(*(*info).dispparams).tarr_sji[idx_sji], /NODATA, /YS, $
    POS=[(*(*info).plotpos).sjiloopx0,(*(*info).plotpos).sjiloopy0, $
    (*(*info).plotpos).sjiloopx1,(*(*info).plotpos).sjiloopy1], $
		YTICKLEN=(*(*info).plotaxes).sjiloopyticklen, $
    XTICKLEN=(*(*info).plotaxes).sjiloopxticklen, /XS, $
    YTITLE=(*(*info).plottitles).spytitle, XTITLE='Pixel along loop', $
		BACKGROUND=(*(*info).plotparams).bgplotcol, $
    COLOR=(*(*info).plotparams).plotcol
	IF (((*(*info).feedbparams).verbosity)[3] EQ 1) THEN $
    CRISPEX_VERBOSE_GET, event, [(*(*info).winids).sjiloopwid[idx_sji]], $
      labels=['Window ID for replot']
END

PRO CRISPEX_DISPLAYS_SJILOOPSLAB_RESIZE, event
; Reference loopslab window resize handler, gets new window dimensions and calls
; (re)display routines
  WIDGET_CONTROL, event.TOP, GET_UVALUE = info
	IF (TOTAL(((*(*info).feedbparams).verbosity)[2:3]) GE 1) THEN $
    CRISPEX_VERBOSE_GET_ROUTINE, event
	CRISPEX_DISPLAYS_PLOT_RESIZE, event, event.X, event.Y, $
    (*(*info).winsizes).sjiloopxres, (*(*info).winsizes).sjiloopyres, $
    (*(*info).plotpos).sjiloopxmargin_init, (*(*info).plotpos).sjiloopxwall_init, $
		sjiloopxres, sjiloopyres, sjiloopwidth, sjiloopheight, sjiloopx0, $
    sjiloopx1, sjiloopy0, sjiloopy1, ERROR=error, /SLICE
	IF error THEN CRISPEX_DISPLAYS_RESIZE_ERROR, event ELSE BEGIN
		(*(*info).winsizes).sjiloopxres = sjiloopxres			& 	(*(*info).winsizes).sjiloopyres = sjiloopyres
		(*(*info).plotpos).sjiloopx0 = sjiloopx0			&	(*(*info).plotpos).sjiloopx1 = sjiloopx1
		(*(*info).plotpos).sjiloopy0 = sjiloopy0			&	(*(*info).plotpos).sjiloopy1 = sjiloopy1
		(*(*info).plotpos).sjiloopxplspw = sjiloopx1 - sjiloopx0	&	(*(*info).plotpos).sjiloopyplspw = sjiloopy1 - sjiloopy0
		(*(*info).plotaxes).sjiloopxticklen = -1 * (*(*info).plotaxes).ticklen / sjiloopheight
		(*(*info).plotaxes).sjiloopyticklen = -1 * (*(*info).plotaxes).ticklen / sjiloopwidth
		(*(*info).dispparams).sjiloopnlxreb = (*(*info).plotpos).sjiloopxplspw * (*(*info).winsizes).sjiloopxres 
		(*(*info).dispparams).sjiloopntreb = (*(*info).plotpos).sjiloopyplspw * (*(*info).winsizes).sjiloopyres 
	ENDELSE
	IF (((*(*info).feedbparams).verbosity)[3] EQ 1) THEN $
    CRISPEX_VERBOSE_GET, event, [error,(*(*info).winsizes).sjiloopxres,(*(*info).winsizes).sjiloopyres,(*(*info).plotpos).sjiloopx0,(*(*info).plotpos).sjiloopx1,$
		(*(*info).plotpos).sjiloopy0,(*(*info).plotpos).sjiloopy1], labels=['error','sjiloopxres','sjiloopyres','sjiloopx0','sjiloopx1','sjiloopy0','sjiloopy1']
	WIDGET_CONTROL, (*(*info).winids).sjiloopdrawid, DRAW_XSIZE = (*(*info).winsizes).sjiloopxres, DRAW_YSIZE = (*(*info).winsizes).sjiloopyres
	WIDGET_CONTROL, event.TOP, SET_UVALUE = info
	CRISPEX_DISPLAYS_SJILOOPSLAB_REPLOT_AXES, event
	CRISPEX_DRAW_SJILOOPSLAB, event
END

PRO CRISPEX_DISPLAYS_SJILOOPSLAB, event, NO_DRAW=no_draw, IDX_SJI=idx_sji
; SJI, loopslab window creation procedure
	WIDGET_CONTROL, event.TOP, GET_UVALUE = info
	IF (TOTAL(((*(*info).feedbparams).verbosity)[2:3]) GE 1) THEN $
    CRISPEX_VERBOSE_GET_ROUTINE, event
	(*(*info).winswitch).showsjiloop = 1
	WIDGET_CONTROL,/HOURGLASS
  IF (N_ELEMENTS(IDX_SJI) LT 1) THEN $
    idx_sji_sel = *(*(*info).winswitch).whereshowsji $
  ELSE $
    idx_sji_sel = idx_sji
  nidx_sji_sel = N_ELEMENTS(idx_sji_sel)
  FOR i=0,nidx_sji_sel-1 DO BEGIN
  	CRISPEX_LOOP_GET_SJISLAB, event, IDX_SJI=idx_sji_sel[i]
  	title = 'CRISPEX'+(*(*info).sesparams).instance_label+': Slit-jaw '+$
      STRJOIN((*(*info).dataparams).sji_labels[*,idx_sji_sel[i]],' ')+$
      ' Space-time plot'
  	CRISPEX_WINDOW, (*(*info).winsizes).sjiloopxres, $
      (*(*info).winsizes).sjiloopyres, (*(*info).winids).root, title, tlb, wid, $
      (*(*info).winsizes).xywinx+(*(*info).winsizes).xdelta, $
  		((*(*info).winswitch).showsp + (*(*info).winswitch).showphis) * $
      (*(*info).winsizes).ydelta, DRAWID=sjiloopdrawid, RESIZING=1, $
      RES_HANDLER='CRISPEX_DISPLAYS_SJILOOPSLAB_RESIZE'
  	PLOT, FINDGEN((*(*info).loopsdata).sjiloopsize[idx_sji_sel[i]]), $
      *(*(*info).dispparams).tarr_sji[idx_sji_sel[i]], /NODATA, $
      YR=[(*(*info).dispparams).t_low_sji[idx_sji_sel[i]], $
          (*(*info).dispparams).t_upp_sji[idx_sji_sel[i]]], $
  		/YS, POS=[(*(*info).plotpos).sjiloopx0,(*(*info).plotpos).sjiloopy0,$
      (*(*info).plotpos).sjiloopx1,(*(*info).plotpos).sjiloopy1],$
  		YTICKLEN=(*(*info).plotaxes).sjiloopyticklen, $
      XTICKLEN=(*(*info).plotaxes).sjiloopxticklen, /XS, $
      YTITLE=(*(*info).plottitles).spytitle, XTITLE='Pixel along loop',$
  		BACKGROUND=(*(*info).plotparams).bgplotcol, $
      COLOR=(*(*info).plotparams).plotcol
  	(*(*info).winids).sjilooptlb[idx_sji_sel[i]] = tlb		
    (*(*info).winids).sjiloopwid[idx_sji_sel[i]] = wid		
    (*(*info).winids).sjiloopdrawid[idx_sji_sel[i]] = sjiloopdrawid
  	(*(*info).winids).sjiloopwintitle = title 
  	WIDGET_CONTROL, (*(*info).winids).sjilooptlb[idx_sji_sel[i]], SET_UVALUE = info
  	IF (~KEYWORD_SET(NO_DRAW) AND (i EQ (*(*info).winswitch).nwhereshowsji-1)) THEN BEGIN
  		CRISPEX_UPDATE_LP, event
  		CRISPEX_ZOOM_LOOP, event
  		CRISPEX_DRAW, event
  	ENDIF
  	IF (((*(*info).feedbparams).verbosity)[3] EQ 1) THEN $
      CRISPEX_VERBOSE_GET, event, [(*(*info).winids).sjilooptlb[idx_sji_sel[i]],$
        (*(*info).winids).sjiloopwid[idx_sji_sel[i]],$
        (*(*info).winids).sjiloopdrawid[idx_sji_sel[i]]], $
        labels=['reflooptlb','refloopwid','refloopdrawid']
  ENDFOR
END

PRO CRISPEX_DISPLAYS_PLOT_RESIZE, event, new_xres_tmp, new_yres_tmp, $
  init_xres, init_yres, init_xmargin, init_xwall, new_xres, new_yres, $
  new_width, new_height, x0, x1, y0, y1, v_dop_set, $
  INX0=inx0, INX1=inx1, INY0=iny0, INY1=iny1, ERROR=error, $
  SLICE=slice, DETSPECT=detspect, STOKES_SELECT=stokes_select, $
  REFERENCE=reference
; Handles the display plot resizing
	WIDGET_CONTROL, event.TOP, GET_UVALUE = info
	IF (TOTAL(((*(*info).feedbparams).verbosity)[2:3]) GE 1) THEN $
    CRISPEX_VERBOSE_GET_ROUTINE, event
	IF (N_ELEMENTS(v_dop_set) NE 1) THEN v_dop_set = 0
	IF KEYWORD_SET(DETSPECT) THEN BEGIN												; If considering main detailed spectrum
    IF ~KEYWORD_SET(REFERENCE) THEN $
  		curns = TOTAL((*(*info).stokesparams).select_sp) $
    ELSE $
  		curns = TOTAL((*(*info).stokesparams).select_refsp) 
		IF KEYWORD_SET(STOKES_SELECT) THEN BEGIN
      IF ~KEYWORD_SET(REFERENCE) THEN $
			  prevns = TOTAL((*(*info).stokesparams).prev_select_sp) $
      ELSE $
			  prevns = TOTAL((*(*info).stokesparams).prev_select_refsp) 
			new_xres_tmp = init_xres											; Default: no change in xsize
			new_yres_tmp = init_yres											; Default: no change in ysize
			IF (v_dop_set EQ 1) THEN offset = init_xmargin ELSE offset = init_xwall
			IF (prevns GT curns) THEN BEGIN											; If reducing the selected Stokes
        ; If new number is 2, prev was 3
				IF (curns EQ 2) THEN $
          new_yres_tmp = (init_yres + offset - v_dop_set*init_xwall) / 2. $
        ELSE IF (curns EQ 1) THEN $
          new_xres_tmp = (init_xres + init_xwall) / 2. 				;If new number is 1, prev was 2
			ENDIF ELSE BEGIN												; If increasing the selected Stokes
        ; If new number is 3, prev was 2
				IF (curns EQ 3) THEN $
          new_yres_tmp = 2. * init_yres - offset + v_dop_set*init_xwall $
        ELSE IF (curns EQ 2) THEN $
          new_xres_tmp = 2. * init_xres - init_xwall					; If new number is 2, prev was 1
			ENDELSE
		ENDIF
		IF (curns LE 2) THEN BEGIN
			npanels = curns	&	cols = curns
			rowarr = REPLICATE(0,curns)
		ENDIF ELSE BEGIN
			npanels = 4	&	cols = 2
			rowarr = [1,1,0,0]
		ENDELSE
		rows = CEIL(npanels / FLOAT(cols))
		x0 = FLTARR(npanels)
		x1 = FLTARR(npanels)
		y0 = FLTARR(npanels)
		y1 = FLTARR(npanels)
	ENDIF ELSE BEGIN														; All other plot windows
		rows = 1	&	cols = 1
	ENDELSE
	dx = ABS(new_xres_tmp - init_xres)
	dy = ABS(new_yres_tmp - init_yres)
  ; Actual recalculation of plot area
	IF ((dx NE 0) OR (dy NE 0)) THEN BEGIN
		new_margin = init_xmargin/new_xres_tmp
		new_wall = init_xwall/new_xres_tmp
		new_xres = new_xres_tmp
		new_yres = new_yres_tmp
		new_width = (1 - (cols*new_margin + new_wall))/FLOAT(cols)
			IF ((v_dop_set EQ 1) OR $
        (KEYWORD_SET(SLICE) AND ((*(*info).dataparams).ns GT 1))) THEN $
        new_height = (new_yres/FLOAT(new_xres) - (new_margin*(rows+1) + new_wall*(rows-1))) / $
          FLOAT(rows) $
      ELSE $
        new_height = (new_yres/FLOAT(new_xres) - (new_wall + rows*new_margin) ) / FLOAT(rows)
		IF KEYWORD_SET(DETSPECT) THEN BEGIN
      plotpos = CRISPEX_GET_PLOTPOS(curns, new_xres, new_margin, new_wall, $
                  V_DOP_SET=(v_dop_set EQ 1))
      x0 = plotpos.x0 & x1 = plotpos.x1
      y0 = plotpos.y0 & y1 = plotpos.y1
;			x0 = new_margin + (INDGEN(npanels) MOD cols) * (new_width + new_margin) 
;			x1 = x0 + new_width 
;			y0 = (new_margin + rowarr * (new_height + new_margin + v_dop_set*new_wall)) * new_xres/new_yres
;			y1 = y0 + new_height * new_xres/new_yres
		ENDIF ELSE BEGIN
			x0 = new_margin 
			x1 = x0 + new_width
			y0 = new_margin * new_xres/new_yres
			y1 = y0 + new_height * new_xres/new_yres 
		ENDELSE
	ENDIF ELSE BEGIN															; If no change in size (Stokes select)
		x0 = inx0	&	x1 = inx1
		y0 = iny0	&	y1 = iny1
		new_xres = new_xres_tmp
		new_yres = new_yres_tmp
		new_width = inx1[0] - inx0[0]
		new_height = iny1[0] - iny0[0]
	ENDELSE
	dxpl = x1[0] - x0[0]	&	dypl = y1[0] - y0[0]
	IF ((dxpl LE 0) OR (dypl LE 0) OR (x0[0] LE 0) OR (y0[0] LE 0)) THEN error = 1 ELSE error = 0
END

PRO CRISPEX_DISPLAYS_PLOT_NOISE_SELECT, event
; Handles display of average subtracted spectrum in detailed spectrum window
	WIDGET_CONTROL, event.TOP, GET_UVALUE = info
	IF (TOTAL(((*(*info).feedbparams).verbosity)[2:3]) GE 1) THEN $
    CRISPEX_VERBOSE_GET_ROUTINE, event
	IF (*(*info).stokesparams).mainref_select THEN BEGIN
    (*(*info).plotswitch).ref_noise = event.SELECT 
	  CRISPEX_DRAW_SPECTRAL_REF, event, /LS_ONLY
  ENDIF ELSE BEGIN
    (*(*info).plotswitch).noise = event.SELECT
	  CRISPEX_DRAW_SPECTRAL_MAIN, event, /LS_ONLY
  ENDELSE
END

PRO CRISPEX_DISPLAYS_LS_RESIZE, event, STOKES_SELECT=stokes_select
; Detailed spectrum window resize handler, gets new window dimensions and calls (re)display routines
	WIDGET_CONTROL, event.TOP, GET_UVALUE = info
	IF (TOTAL(((*(*info).feedbparams).verbosity)[2:3]) GE 1) THEN $
    CRISPEX_VERBOSE_GET_ROUTINE, event
	IF KEYWORD_SET(STOKES_SELECT) THEN BEGIN
		newlsxres = (*(*info).winsizes).lsxres	&	newlsyres = (*(*info).winsizes).lsyres
	ENDIF ELSE BEGIN
		newlsxres = event.X		&	newlsyres = event.Y
	ENDELSE
	CRISPEX_DISPLAYS_PLOT_RESIZE, event, newlsxres, newlsyres, $
    (*(*info).winsizes).lsxres, (*(*info).winsizes).lsyres, $
    (*(*info).plotpos).lsxmargin_init, (*(*info).plotpos).lsxwall_init, $
    lsxres, lsyres, lswidth, lsheight, lsx0, lsx1, lsy0, lsy1, $
    (*(*info).plotswitch).v_dop_set, $
    INX0=(*(*info).plotpos).lsx0, INX1=(*(*info).plotpos).lsx1, $
    INY0=(*(*info).plotpos).lsy0, INY1=(*(*info).plotpos).lsy1, $
    ERROR=error, /DETSPECT, STOKES_SELECT=stokes_select
	IF error THEN CRISPEX_DISPLAYS_RESIZE_ERROR, event ELSE BEGIN
		(*(*info).winsizes).lsxres = lsxres	& 	(*(*info).winsizes).lsyres = lsyres
		(*(*info).plotpos).lsx0 = lsx0		&	(*(*info).plotpos).lsx1 = lsx1
		(*(*info).plotpos).lsy0 = lsy0		&	(*(*info).plotpos).lsy1 = lsy1
		(*(*info).plotaxes).lsxticklen = (*(*info).plotaxes).ticklen / lsheight
		(*(*info).plotaxes).lsyticklen = (*(*info).plotaxes).ticklen / lswidth
	ENDELSE
	IF (((*(*info).feedbparams).verbosity)[3] EQ 1) THEN BEGIN
		nstokes_sel = TOTAL((*(*info).stokesparams).select_sp)
		CRISPEX_VERBOSE_GET, event, [error,(*(*info).winsizes).lsxres,(*(*info).winsizes).lsyres,(*(*info).plotpos).lsx0,(*(*info).plotpos).lsx1,(*(*info).plotpos).lsy0,(*(*info).plotpos).lsy1], $
			labels=['error','lsxres','lsyres',REPLICATE('lsx0',nstokes_sel),REPLICATE('lsx1',nstokes_sel),REPLICATE('lsy0',nstokes_sel),REPLICATE('lsy1',nstokes_sel)]
	ENDIF
	WIDGET_CONTROL, (*(*info).winids).lsdrawid, DRAW_XSIZE = (*(*info).winsizes).lsxres, DRAW_YSIZE = (*(*info).winsizes).lsyres
	WIDGET_CONTROL, event.TOP, SET_UVALUE = info
  CRISPEX_DRAW_SPECTRAL_MAIN, event, /LS_ONLY
END

PRO CRISPEX_DISPLAYS_IMREFBLINK_TOGGLE, event
; Sets the playback mode to blink of main and reference image
	WIDGET_CONTROL, event.TOP, GET_UVALUE = info
	IF (TOTAL(((*(*info).feedbparams).verbosity)[2:3]) GE 1) THEN $
    CRISPEX_VERBOSE_GET_ROUTINE, event, /IGNORE_LAST
	(*(*info).winswitch).showimref = event.SELECT
	(*(*info).pbparams).imrefmode = event.SELECT
	WIDGET_CONTROL, (*(*info).ctrlscp).lp_blink_but, SENSITIVE=ABS((*(*info).pbparams).imrefmode-1)
	IF (*(*info).winswitch).showimref THEN BEGIN
		title = 'CRISPEX'+(*(*info).sesparams).instance_label+': Main vs. reference image blink'
		CRISPEX_WINDOW, (*(*info).winsizes).xywinx, (*(*info).winsizes).xywiny, $
      (*(*info).winids).root, title, imreftlb, imrefwid, $
			(*(*info).winsizes).imrefxoffset,(*(*info).winsizes).imrefyoffset, $
      DRAWID = imrefdrawid, DRAWBASE = imrefdrawbase
		(*(*info).winids).imreftlb = imreftlb		&	(*(*info).winids).imrefwid = imrefwid	&	(*(*info).winids).imrefdrawid = imrefdrawid
		(*(*info).winids).imrefdrawbase = imrefdrawbase	&	(*(*info).winids).imrefwintitle = title
		IF ((*(*info).feedbparams).count_pbstats EQ 0) THEN (*(*info).feedbparams).pbstats = SYSTIME(/SECONDS)
		WIDGET_CONTROL, (*(*info).pbparams).bg, TIMER = 0.0
		WIDGET_CONTROL, imrefdrawid, EVENT_PRO = 'CRISPEX_CURSOR', /SENSITIVE, /DRAW_MOTION_EVENTS, /TRACKING_EVENTS,/DRAW_BUTTON_EVENTS
		WIDGET_CONTROL, imreftlb, SET_UVALUE = info
		XMANAGER, 'CRISPEX', imreftlb, /NO_BLOCK
	ENDIF ELSE BEGIN
		WIDGET_CONTROL, (*(*info).winids).imreftlb, /DESTROY
		(*(*info).scaling).imrefscaling = 0
		(*(*info).winids).imreftlb = 0
		IF ((*(*info).winids).feedbacktlb NE 0) THEN BEGIN
			(*(*info).feedbparams).count_pbstats = 0
			WIDGET_CONTROL, (*(*info).ctrlsfeedb).close_button, /SENSITIVE
		ENDIF
	ENDELSE
	IF (((*(*info).feedbparams).verbosity)[3] EQ 1) THEN $
    CRISPEX_VERBOSE_GET, event, [(*(*info).winids).imreftlb,(*(*info).winids).imrefwid,(*(*info).winids).imrefdrawid], labels=['imreftlb','imrefwid','imrefdrawid']
END

PRO CRISPEX_DISPLAYS_IMREF_LS_TOGGLE, event, DISP=disp, KILL=kill, $
  NO_DRAW=no_draw, REFERENCE=reference, NO_FEEDBPARAMS=no_feedbparams
; Detailed spectrum window creation procedure
	WIDGET_CONTROL, event.TOP, GET_UVALUE = info
	IF (TOTAL(((*(*info).feedbparams).verbosity)[2:3]) GE 1) THEN $
    CRISPEX_VERBOSE_GET_ROUTINE, event, /IGNORE_LAST
  IF KEYWORD_SET(REFERENCE) THEN BEGIN
    IF (KEYWORD_SET(DISP) OR KEYWORD_SET(KILL)) THEN BEGIN
      (*(*info).winswitch).showrefls = KEYWORD_SET(DISP)
    ENDIF ELSE $
    	(*(*info).winswitch).showrefls = event.SELECT
		IF (*(*info).winswitch).showrefls THEN BEGIN
			title = 'CRISPEX'+(*(*info).sesparams).instance_label+': '+$
        ((*(*info).plottitles).reflswintitle)[(*(*info).plotswitch).refheightset]
			CRISPEX_WINDOW, (*(*info).winsizes).reflsxres, $
        (*(*info).winsizes).reflsyres, (*(*info).winids).root, title, tlb, wid,$
        (*(*info).winsizes).reflsxoffset, (*(*info).winsizes).reflsyoffset, $
        DRAWID=lsdrawid, RESIZING=1, RES_HANDLER='CRISPEX_DISPLAYS_REFLS_RESIZE'
			(*(*info).winids).reflstlb = tlb		
      (*(*info).winids).reflswid = wid	
			(*(*info).winids).reflsdrawid = lsdrawid	
      (*(*info).winids).reflswintitle = title
			WIDGET_CONTROL, (*(*info).winids).reflstlb, SET_UVALUE = info
      CRISPEX_UPDATE_REFSSP, event
			IF ~KEYWORD_SET(NO_DRAW) THEN CRISPEX_DRAW_SPECTRAL_REF, event, /LS_ONLY
		ENDIF ELSE BEGIN
			WIDGET_CONTROL, (*(*info).winids).reflstlb, /DESTROY
			(*(*info).winids).reflstlb = 0
		ENDELSE
    IF ~KEYWORD_SET(NO_FEEDBPARAMS) THEN $
      CRISPEX_DRAW_FEEDBPARAMS, event, UPDATE_REFDATAVALS=($
        ((*(*info).winswitch).showref EQ 0) AND $
        ((*(*info).winswitch).showrefsp EQ 0))
		IF (((*(*info).feedbparams).verbosity)[3] EQ 1) THEN $
      CRISPEX_VERBOSE_GET, event, [(*(*info).winids).reflstlb,$
        (*(*info).winids).reflswid,(*(*info).winids).reflsdrawid], $
        labels=['reflstlb','reflswid','reflsdrawid']
	ENDIF ELSE BEGIN
		IF ((*(*info).winswitch).showls EQ 0) THEN BEGIN
			title = 'CRISPEX'+(*(*info).sesparams).instance_label+': '+$
        ((*(*info).plottitles).lswintitle)[(*(*info).plotswitch).heightset]
			CRISPEX_WINDOW, (*(*info).winsizes).lsxres, (*(*info).winsizes).lsyres, $
        (*(*info).winids).root, title, tlb, wid, $
        (*(*info).winsizes).lsxoffset, (*(*info).winsizes).lsyoffset, $
        DRAWID=lsdrawid, RESIZING=1, RES_HANDLER='CRISPEX_DISPLAYS_LS_RESIZE'
			(*(*info).winids).lstlb = tlb		
      (*(*info).winids).lswid = wid	
      (*(*info).winswitch).showls = 1
			(*(*info).winids).lsdrawid = lsdrawid	
      (*(*info).winids).lswintitle = title
			WIDGET_CONTROL, (*(*info).winids).lstlb, SET_UVALUE = info
      CRISPEX_UPDATE_SSP, event
			IF ~KEYWORD_SET(NO_DRAW) THEN CRISPEX_DRAW_SPECTRAL_MAIN, event, /LS_ONLY
		ENDIF ELSE BEGIN
			WIDGET_CONTROL, (*(*info).winids).lstlb, /DESTROY
			(*(*info).winids).lstlb = 0
			(*(*info).winswitch).showls = 0
		ENDELSE
		IF (((*(*info).feedbparams).verbosity)[3] EQ 1) THEN $
      CRISPEX_VERBOSE_GET, event, [(*(*info).winids).lstlb,$
        (*(*info).winids).lswid,(*(*info).winids).lsdrawid], $
        labels=['lstlb','lswid','lsdrawid']
	ENDELSE
END

PRO CRISPEX_DISPLAYS_PHIS_REPLOT_AXES, event, NO_AXES=no_axes
; Updates temporal spectrum display window plot axes range according to set parameters
	WIDGET_CONTROL, event.TOP, GET_UVALUE = info
	IF (TOTAL(((*(*info).feedbparams).verbosity)[2:3]) GE 1) THEN $
    CRISPEX_VERBOSE_GET_ROUTINE, event
	WSET, (*(*info).winids).phiswid
	IF (*(*info).plotswitch).v_dop_set THEN extratitle = '!C' ELSE extratitle = ''
	IF (*(*info).plotswitch).multichannel THEN $
    title = 'Stokes '+((*(*info).stokesparams).labels)[$
      (*(*info).dataparams).s]+extratitle $
  ELSE $
    title = ''
  ytitle = 'Position along slit'
  IF (*(*info).dataswitch).wcs_set THEN $
    ytitle += ' ['+(*(*info).dataparams).xunit+']' $
  ELSE $
    ytitle += ' [pixel]'
  ; Set axes parameters depending on # of diagnostics
  IF ((*(*info).intparams).ndisp_diagnostics GT 1) THEN BEGIN
    xticklen = 1E-9   & xtitle = ''
    xtickname = REPLICATE(' ',60)
    xtlen_basic_fac = 0.5
    xtlen_major_fac = 0.8
    IF KEYWORD_SET(NO_AXES) THEN BEGIN
      yticklen = 1E-9 & ytitle = ''
      ytickname = REPLICATE(' ',60)
    ENDIF ELSE BEGIN
      yticklen = (*(*info).plotaxes).phisyticklen
      ytickname = ''
    ENDELSE
  ENDIF ELSE BEGIN
    xticklen = (*(*info).plotaxes).phisxticklen
    xtitle = (*(*info).plottitles).spxtitle
    xtlen_basic_fac = 1.
    yticklen = (*(*info).plotaxes).phisyticklen
    xtickname = ''  & ytickname = ''
  ENDELSE
  topxtitle = title
  IF (*(*info).plotswitch).v_dop_set THEN topxtitle += 'Doppler velocity [km/s]'
  ; Determine plot ranges
  sel_idx = [0,(*(*info).phiparams).nw_cur-1]
  IF (*(*info).dataswitch).wcs_set THEN BEGIN
    xy_pts_wcs = CRISPEX_TRANSFORM_GET_WCS($
              REFORM((*(*(*info).phiparams).x_pts)[sel_idx,0]),$
              REFORM((*(*(*info).phiparams).y_pts)[sel_idx,0]), $
              (*(*info).dataparams).wcs_main, /COORD, /NO_ROUND)
    xy_wcs = CRISPEX_TRANSFORM_GET_WCS((*(*info).dataparams).x, $
      (*(*info).dataparams).y, (*(*info).dataparams).wcs_main, /COORD,$
      /NO_ROUND)
    (*(*info).plotaxes).phis_yrange = $
      [ -SQRT((xy_pts_wcs.x[0]-xy_wcs.x[0])^2.+$
              (xy_pts_wcs.y[0]-xy_wcs.y[0])^2.),$
         SQRT((xy_pts_wcs.x[1]-xy_wcs.x[0])^2.+$
              (xy_pts_wcs.y[1]-xy_wcs.y[0])^2.)]
  ENDIF ELSE BEGIN
    x_pts = REFORM((*(*(*info).phiparams).x_pts)[sel_idx,0])
    y_pts = REFORM((*(*(*info).phiparams).y_pts)[sel_idx,0])
    (*(*info).plotaxes).phis_yrange = $
      [ -SQRT((x_pts[0]-(*(*info).dataparams).x)^2.+$
              (y_pts[0]-(*(*info).dataparams).y)^2.),$
         SQRT((x_pts[1]-(*(*info).dataparams).x[0])^2.+$
              (y_pts[1]-(*(*info).dataparams).y[0])^2.)]
  ENDELSE
  lp_low_overall = (*(*info).dispparams).lp_low_tmp[$
                    (*(*(*info).intparams).wheredispdiag)[0]] 
  lp_upp_overall = (*(*info).dispparams).lp_upp_tmp[$
                    (*(*(*info).intparams).wheredispdiag)[$
                    (*(*info).intparams).ndisp_diagnostics-1]] 
  phis_xrange = [(*(*info).dataparams).lps[lp_low_overall], $
            (*(*info).dataparams).lps[lp_upp_overall]]
  ; Plot basic axes box
	PLOT, (*(*info).dataparams).lps, FINDGEN((*(*info).phiparams).nw_cur), /NODATA, $
    YRANGE = (*(*info).plotaxes).phis_yrange, /YS, XRANGE=phis_xrange, $
		XSTYLE = (*(*info).plotswitch).v_dop_set * 8 + 1,  $
    YTICKLEN = yticklen, YTITLE=ytitle, YTICKNAME=ytickname, $
    XTICKLEN = xticklen, XTITLE=xtitle, XTICKNAME=xtickname, $
		POS = [(*(*info).plotpos).phisx0,(*(*info).plotpos).phisy0,$
             (*(*info).plotpos).phisx1,(*(*info).plotpos).phisy1], $
    BACKGROUND = (*(*info).plotparams).bgplotcol, $
    COLOR = (*(*info).plotparams).plotcol, $
    NOERASE=KEYWORD_SET(NO_AXES)
  IF ~KEYWORD_SET(NO_AXES) THEN BEGIN
    ; Plot xtitle(s)
    IF ((*(*info).intparams).ndiagnostics GT 1) THEN $
        XYOUTS,(*(*info).plotpos).phisxplspw/2.+(*(*info).plotpos).phisx0,$
          (*(*info).plotpos).phisy0/5.,(*(*info).plottitles).spxtitle,ALIGNMENT=0.5, $
          COLOR = (*(*info).plotparams).plotcol,/NORMAL
    diag_range = *(*(*info).plotaxes).diag_ratio * (*(*info).plotpos).phisxplspw 
    ; Loop over all diagnostics for plotting of detailed spectrum
    FOR d=0,(*(*info).intparams).ndisp_diagnostics-1 DO BEGIN
      ; No need to check for count: there is always at least one diagnostic displayed 
      disp_idx = (WHERE((*(*info).intparams).disp_diagnostics EQ 1))[d]
      ; Determine xrange to display
      lp_low_loc = (*(*info).dispparams).lp_low_tmp[disp_idx]+$
        (*(*info).intparams).diag_start[disp_idx]
      lp_upp_loc = (*(*info).dispparams).lp_upp_tmp[disp_idx]+$
        (*(*info).intparams).diag_start[disp_idx]
      phis_xrange = (*(*info).dataparams).lps[[lp_low_loc,lp_upp_loc]]
      vdop_xrange = $
        (*(*(*info).plotaxes).v_dop[disp_idx])[[$
        (*(*info).dispparams).lp_low_tmp[disp_idx], $
        (*(*info).dispparams).lp_upp_tmp[disp_idx]]]
      IF (d EQ 0) THEN offset = 0 ELSE offset = TOTAL(diag_range[0:(d-1)])
      ; Determine lower left corner position of plot
      phisx0 = (*(*info).plotpos).phisx0 + offset
      phisx1 = diag_range[d] + phisx0
      ; Plot axes sub-box
  	  PLOT, (*(*info).dataparams).lps, FINDGEN((*(*info).phiparams).nw_cur), /NODATA, $
        YRANGE=(*(*info).plotaxes).phis_yrange, /YS, XRANGE=phis_xrange, $
        XSTYLE = (*(*info).plotswitch).v_dop_set * 8 + 1, $
        POS = [phisx0,(*(*info).plotpos).phisy0,phisx1,(*(*info).plotpos).phisy1], $
        YTICKLEN=1E-9, XTICKLEN=xticklen, $
        YTICKNAME=REPLICATE(' ',60), XTICKNAME=xtickname, $
        XTICKINTERVAL=(*(*(*info).plotaxes).xtickinterval)[0], $
        XTICK_GET=xtickvals, XMINOR=(0-((*(*info).intparams).ndisp_diagnostics GT 1)), $
        BACKGROUND = (*(*info).plotparams).bgplotcol, COLOR = (*(*info).plotparams).plotcol,$
        /NOERASE
      ; In case of multiple diagnostics
      IF ((*(*info).intparams).ndisp_diagnostics GT 1) THEN BEGIN
        ; Redraw x-axis with custom labelling
        IF (*(*info).plotswitch).xtick_reset THEN BEGIN
          (*(*info).plotaxes).xtickvals[d] = $
            PTR_NEW(CRISPEX_PLOTAXES_XTICKVALS_SELECT(xtickvals, $
            TICKSEP=(*(*(*info).plotaxes).xtickinterval)[1]))
          IF (d EQ ((*(*info).intparams).ndisp_diagnostics-1)) THEN $
            (*(*info).plotswitch).xtick_reset = 0
        ENDIF
        wherenonempty = WHERE(*(*(*info).plotaxes).xtickvals[d] NE ' ', count)
        IF (count GT 0) THEN BEGIN
          FOR k=0,N_ELEMENTS(wherenonempty)-1 DO BEGIN
            PLOTS,[1.,1.]*FLOAT((*(*(*info).plotaxes).xtickvals[d])[wherenonempty[k]]), $
              [(*(*info).plotaxes).phis_yrange[0], xtlen_major_fac*$
              ((*(*info).plotaxes).phis_yrange[1]-(*(*info).plotaxes).phis_yrange[0])*$
              (*(*info).plotaxes).phisxticklen+(*(*info).plotaxes).phis_yrange[0]], $
              COLOR=(*(*info).plotparams).plotcol
          ENDFOR
        ENDIF
        AXIS, XAXIS=0, XTICKLEN=xtlen_basic_fac*(*(*info).plotaxes).phisxticklen, $
          XRANGE=phis_xrange, /XS, $
          XTICKNAME=*(*(*info).plotaxes).xtickvals[d], XMINOR=-1, $
          COLOR=(*(*info).plotparams).plotcol, $
          XTICKINTERVAL=(*(*(*info).plotaxes).xtickinterval)[0]
      ENDIF
      ; Display Doppler top axis if Doppler set, else regular top axis
  		IF ((*(*info).plotswitch).v_dop_set EQ 1) THEN BEGIN
        IF (d EQ 0) THEN $
          XYOUTS,((*(*info).plotpos).phisx1-(*(*info).plotpos).phisx0)/2.+$
            (*(*info).plotpos).phisx0,$
            (*(*info).plotpos).phisy0/5.*3+(*(*info).plotpos).phisy1, topxtitle, $
            ALIGNMENT=0.5, COLOR = (*(*info).plotparams).plotcol,/NORMAL
        topxtitle = ''
        ;Draw top axis
        IF ((*(*info).intparams).ndisp_diagnostics GT 1) THEN BEGIN
          ; Plot the initial tick marks and get the tick vals
          AXIS, XAXIS=1, XRANGE=vdop_xrange, $
            XSTYLE=1, XTITLE = topxtitle, COLOR = (*(*info).plotparams).plotcol,$
            XTICKINTERVAL=(*(*(*info).plotaxes).xdoptickinterval)[0], $
            XTICKNAME=REPLICATE(' ',60), $
            XTICK_GET=xdoptickvals, XTICKLEN=1E-9
          ; Redraw x-axis with custom labelling
          IF (*(*info).plotswitch).xdoptick_reset THEN BEGIN
            (*(*info).plotaxes).xdoptickvals[d] = $
              PTR_NEW(CRISPEX_PLOTAXES_XTICKVALS_SELECT(xdoptickvals, $
              TICKSEP=(*(*(*info).plotaxes).xdoptickinterval)[1],$
              /DOPPLER))
            wherenonempty = WHERE(*(*(*info).plotaxes).xdoptickvals[d] NE ' ')
            ; Determine Doppler tick mark locations
            (*(*info).plotaxes).xdoptickloc[d] = $
              PTR_NEW(CRISPEX_PLOTAXES_XDOPTICKLOC(xdoptickvals, wherenonempty, $
              vdop_xrange, phis_xrange))
            IF (d EQ ((*(*info).intparams).ndisp_diagnostics-1)) THEN $
              (*(*info).plotswitch).xdoptick_reset = 0
          ENDIF
          FOR k=0,N_ELEMENTS(*(*(*info).plotaxes).xdoptickloc[d])-1 DO BEGIN
            PLOTS,[1.,1.]*(*(*(*info).plotaxes).xdoptickloc[d])[k], $
              [(*(*info).plotaxes).phis_yrange[1], -xtlen_major_fac*$
              ((*(*info).plotaxes).phis_yrange[1]-(*(*info).plotaxes).phis_yrange[0])*$
              (*(*info).plotaxes).phisxticklen+(*(*info).plotaxes).phis_yrange[1]], $
              COLOR=(*(*info).plotparams).plotcol
          ENDFOR
          ; Add the labels      
          AXIS, XAXIS=1, XRANGE=vdop_xrange, /XS, $
            XTICKNAME=*(*(*info).plotaxes).xdoptickvals[d], $
            COLOR=(*(*info).plotparams).plotcol, $
            XTICKLEN=xtlen_basic_fac*(*(*info).plotaxes).phisxticklen, $
            XTICKINTERVAL=(*(*(*info).plotaxes).xdoptickinterval)[0], XMINOR=-1
        ENDIF ELSE $
          ; Else plot Doppler axis with automatic tick mark settings
        	AXIS, XAXIS=1, XTICKLEN=(*(*info).plotaxes).phisxticklen, XRANGE=vdop_xrange, $
            XSTYLE=1, XTITLE=topxtitle, COLOR=(*(*info).plotparams).plotcol
      ENDIF ELSE $
  			AXIS, XAXIS=1, XTICKLEN = (*(*info).plotaxes).phisxticklen, XRANGE = xrange, XSTYLE=1, $
          XTITLE = topxtitle, COLOR = (*(*info).plotparams).plotcol, $
          XTICKNAME=REPLICATE(' ',60)
    ENDFOR
  ENDIF
END

PRO CRISPEX_DISPLAYS_PHIS_RESIZE, event							
; Spectral phi slice window resize handler, gets new window dimensions and calls (re)display routines
	WIDGET_CONTROL, event.TOP, GET_UVALUE = info
	IF (TOTAL(((*(*info).feedbparams).verbosity)[2:3]) GE 1) THEN $
    CRISPEX_VERBOSE_GET_ROUTINE, event
	CRISPEX_DISPLAYS_PLOT_RESIZE, event, event.X, event.Y, (*(*info).winsizes).phisxres, (*(*info).winsizes).phisyres, (*(*info).plotpos).phisxmargin_init, (*(*info).plotpos).phisxwall_init, $
		phisxres, phisyres, phiswidth, phisheight, phisx0, phisx1, phisy0, phisy1, $
  (*(*info).plotswitch).v_dop_set, ERROR=error, /SLICE
	IF error THEN CRISPEX_DISPLAYS_RESIZE_ERROR, event ELSE BEGIN
		(*(*info).winsizes).phisxres = phisxres			& 	(*(*info).winsizes).phisyres = phisyres
		(*(*info).plotpos).phisx0 = phisx0			&	(*(*info).plotpos).phisx1 = phisx1
		(*(*info).plotpos).phisy0 = phisy0			&	(*(*info).plotpos).phisy1 = phisy1
		(*(*info).plotpos).phisxplspw = phisx1 - phisx0		&	(*(*info).plotpos).phisyplspw = phisy1 - phisy0
		(*(*info).plotaxes).phisxticklen = -1 * (*(*info).plotaxes).ticklen / phisheight
		(*(*info).plotaxes).phisyticklen = -1 * (*(*info).plotaxes).ticklen / phiswidth
		(*(*info).dispparams).phisnlpreb = (*(*info).plotpos).phisxplspw * (*(*info).winsizes).phisxres 
		(*(*info).dispparams).nphireb = (*(*info).plotpos).phisyplspw * (*(*info).winsizes).phisyres 
	ENDELSE
	IF (((*(*info).feedbparams).verbosity)[3] EQ 1) THEN $
    CRISPEX_VERBOSE_GET, event, [error,(*(*info).winsizes).phisxres,(*(*info).winsizes).phisyres,(*(*info).plotpos).phisx0,(*(*info).plotpos).phisx1,$
		(*(*info).plotpos).phisy0,(*(*info).plotpos).phisy1], labels=['error','phisxres','phisyres','phisx0','phisx1','phisy0','phisy1']
	WIDGET_CONTROL, (*(*info).winids).phisdrawid, DRAW_XSIZE = (*(*info).winsizes).phisxres, DRAW_YSIZE = (*(*info).winsizes).phisyres
	WIDGET_CONTROL, event.TOP, SET_UVALUE = info
  CRISPEX_DRAW_GET_SPECTRAL_AXES, event, /MAIN
  CRISPEX_DISPLAYS_PHIS_REPLOT_AXES, event
	CRISPEX_DRAW_PHIS, event
END

PRO CRISPEX_DISPLAYS_PHIS_TOGGLE, event, NO_DRAW=no_draw
; Spectral phi slice window creation procedure
	WIDGET_CONTROL, event.TOP, GET_UVALUE = info
	IF (TOTAL(((*(*info).feedbparams).verbosity)[2:3]) GE 1) THEN $
    CRISPEX_VERBOSE_GET_ROUTINE, event, /IGNORE_LAST
	IF ((*(*info).winswitch).showphis EQ 0) THEN BEGIN
		WIDGET_CONTROL,/HOURGLASS
		wintitle = 'CRISPEX'+(*(*info).sesparams).instance_label+': '+$
      ((*(*info).plottitles).phiswintitle)[(*(*info).plotswitch).heightset]
		CRISPEX_WINDOW, (*(*info).winsizes).phisxres, (*(*info).winsizes).phisyres, $
      (*(*info).winids).root, wintitle, tlb, wid, $
      (*(*info).winsizes).phisxoffset, (*(*info).winsizes).phisyoffset, $
      DRAWID = phisdrawid, RESIZING = 1, RES_HANDLER = 'CRISPEX_DISPLAYS_PHIS_RESIZE'
		(*(*info).winids).phistlb = tlb			&	(*(*info).winids).phiswid = wid
		(*(*info).winids).phisdrawid = phisdrawid	&	(*(*info).winids).phiswintitle = wintitle 
		WIDGET_CONTROL, (*(*info).winids).phistlb, SET_UVALUE = info
		(*(*info).ctrlsswitch).bwd_insensitive = 0	
		(*(*info).ctrlsswitch).fwd_insensitive = 0
		(*(*info).winswitch).showphis = 1
    CRISPEX_DISPRANGE_LP_RANGE, event, /NO_DRAW
	ENDIF ELSE BEGIN
		WIDGET_CONTROL, (*(*info).winids).phistlb, /DESTROY
		(*(*info).winids).phistlb = 0
		(*(*info).winswitch).showphis = 0
	ENDELSE
	WIDGET_CONTROL, (*(*info).ctrlscp).phi_slider, $
    SENSITIVE=((*(*info).winswitch).showphis AND (*(*info).dataparams).nx GT 1)
	WIDGET_CONTROL, (*(*info).ctrlscp).nphi_slider, SENSITIVE = (*(*info).winswitch).showphis
;	WIDGET_CONTROL, (*(*info).ctrlscp).bwd_move_slit, SENSITIVE = (*(*info).winswitch).showphis
;	WIDGET_CONTROL, (*(*info).ctrlscp).fwd_move_slit, SENSITIVE = (*(*info).winswitch).showphis
  IF (*(*info).winswitch).showphis THEN BEGIN
  	CRISPEX_PHISLIT_DIRECTION, event
    CRISPEX_UPDATE_PHISLIT_COORDS, event
    CRISPEX_DISPLAYS_PHIS_REPLOT_AXES, event
    CRISPEX_UPDATE_SLICES, event, NO_DRAW=no_draw
  ENDIF ELSE $
    ; "Clear" phiscan from memory
    (*(*info).data).phiscan = PTR_NEW(0)
	WIDGET_CONTROL, (*(*info).ctrlscp).slice_button, SENSITIVE = 0
	IF (((*(*info).feedbparams).verbosity)[3] EQ 1) THEN $
    CRISPEX_VERBOSE_GET, event, [(*(*info).winids).phistlb,(*(*info).winids).phiswid,$
      (*(*info).winids).phisdrawid], labels=['phistlb','phiswid','phisdrawid']
END

PRO CRISPEX_DISPLAYS_REF_TOGGLE, event, DISP=disp, KILL=kill, NO_DRAW=no_draw, $
  NO_FEEDBPARAMS=no_feedbparams
; Reference image window creation procedure
	WIDGET_CONTROL, event.TOP, GET_UVALUE = info
	IF (TOTAL(((*(*info).feedbparams).verbosity)[2:3]) GE 1) THEN $
    CRISPEX_VERBOSE_GET_ROUTINE, event, /IGNORE_LAST
  IF (KEYWORD_SET(DISP) OR KEYWORD_SET(KILL)) THEN BEGIN
    (*(*info).winswitch).showref = KEYWORD_SET(DISP)
  ENDIF ELSE $
  	(*(*info).winswitch).showref = event.SELECT
	IF (*(*info).winswitch).showref THEN BEGIN
		title = 'CRISPEX'+(*(*info).sesparams).instance_label+': Reference image'
		CRISPEX_WINDOW, (*(*info).winsizes).refwinx, (*(*info).winsizes).refwiny, $
      (*(*info).winids).root, title, reftlb, refwid, $
      (*(*info).winsizes).refxoffset, (*(*info).winsizes).refyoffset, $
      DRAWID = refdrawid, DRAWBASE = refdrawbase, $
      /SCROLL, XSCROLL=xscroll, YSCROLL=yscroll, /REFERENCE, /CTBAR_SHOW, $
      CTBAR_DRAWID=ctbar_drawid
    (*(*info).ctrlsref).xrefpos_slider = xscroll
    (*(*info).ctrlsref).yrefpos_slider = yscroll
    WIDGET_CONTROL, (*(*info).ctrlsref).xrefpos_slider, $
      SET_VALUE=(*(*info).zooming).xrefpos, $
      SENSITIVE=((*(*info).dataparams).d_nx NE (*(*info).dataparams).nx-1)
    WIDGET_CONTROL, (*(*info).ctrlsref).yrefpos_slider, $
      SET_VALUE=(*(*info).zooming).yrefpos, $
      SENSITIVE=((*(*info).dataparams).d_ny NE (*(*info).dataparams).ny-1)
		(*(*info).winids).reftlb = reftlb		
    (*(*info).winids).refwid = refwid	
    (*(*info).winids).refdrawid = refdrawid
		(*(*info).winids).refdrawbase = refdrawbase	
    (*(*info).winids).refwintitle = title
		WIDGET_CONTROL, refdrawid, EVENT_PRO = 'CRISPEX_CURSOR', /SENSITIVE, $
      /DRAW_MOTION_EVENTS, /TRACKING_EVENTS,/DRAW_BUTTON_EVENTS
    WIDGET_CONTROL, ctbar_drawid, GET_VALUE=refdrawid_ctbar
    (*(*info).winids).refdrawid_ctbar = [refdrawid_ctbar, ctbar_drawid]
		WIDGET_CONTROL, reftlb, SET_UVALUE = info
		IF ~KEYWORD_SET(NO_DRAW) THEN BEGIN
			CRISPEX_UPDATE_T, event
      CRISPEX_DRAW_CTBAR, event, /REFERENCE
			CRISPEX_DRAW_REF, event
		ENDIF
	ENDIF ELSE BEGIN
		WIDGET_CONTROL, (*(*info).winids).reftlb, /DESTROY
		(*(*info).winids).reftlb = 0
	ENDELSE
  IF ~KEYWORD_SET(NO_FEEDBPARAMS) THEN $
    CRISPEX_DRAW_FEEDBPARAMS, event, UPDATE_REFDATAVALS=($
      ((*(*info).winswitch).showrefls EQ 0) AND $
      ((*(*info).winswitch).showrefsp EQ 0))
	WIDGET_CONTROL, (*(*info).ctrlscp).lp_ref_but, SENSITIVE = $
    (((*(*info).dataparams).nlp EQ (*(*info).dataparams).refnlp) AND $
     ((*(*info).dataparams).refnlp GT 1))
	WIDGET_CONTROL, (*(*info).ctrlscp).lp_ref_slider, $
    SENSITIVE = (((*(*info).dataparams).refnlp GT 1) AND $
    ABS((*(*info).ctrlsswitch).lp_ref_lock-1))
	IF (((*(*info).feedbparams).verbosity)[3] EQ 1) THEN $
    CRISPEX_VERBOSE_GET, event, $
      [(*(*info).winids).reftlb,(*(*info).winids).refwid, $
      (*(*info).winids).refdrawid], labels=['reftlb','refwid','refdrawid']
END

PRO CRISPEX_DISPLAYS_RESIZE_ERROR, event
; Opens error window on resize error
	WIDGET_CONTROL, event.TOP, GET_UVALUE = info
	CRISPEX_WINDOW_OK, event,'ERROR!',$
    'Window resize request cannot be completed: '+$
    'resize values beyond boundaries. Reverted to old window size.',$
		OK_EVENT='CRISPEX_CLOSE_EVENT_WINDOW', BASE=tlb
	(*(*info).winids).errtlb = tlb
	IF (((*(*info).feedbparams).verbosity)[3] EQ 1) THEN $
    CRISPEX_VERBOSE_GET, event, [(*(*info).winids).errtlb], labels=['errtlb']
END

PRO CRISPEX_DISPLAYS_RESTORE_LOOPSLAB_REPLOT_AXES, event				
; Updates restored loopslab display window plot axes range according to set parameters
	WIDGET_CONTROL, event.TOP, GET_UVALUE = info
	IF (TOTAL(((*(*info).feedbparams).verbosity)[2:3]) GE 1) THEN $
    CRISPEX_VERBOSE_GET_ROUTINE, event
	FOR i=0,N_ELEMENTS(*(*(*info).winids).restloopwid)-1 DO BEGIN
		WSET, (*(*(*info).winids).restloopwid)[i]
    sel_idx = (*(*(*info).restoreparams).disp_loopnr)[i]
		PLOT, FINDGEN(N_ELEMENTS(*(*(*(*info).restoreparams).xr)[sel_idx])),$
      *(*(*info).dispparams).tarr_main, $
      /NODATA, YR=[(*(*info).dispparams).t_low_main, (*(*info).dispparams).t_upp_main], $
			/YS, POS=[(*(*info).plotpos).restloopx0,(*(*info).plotpos).restloopy0,	$
      (*(*info).plotpos).restloopx1,(*(*info).plotpos).restloopy1], $
			YTICKLEN = (*(*info).plotaxes).restloopyticklen, XTICKLEN = (*(*info).plotaxes).restloopxticklen, /XS, YTITLE = (*(*info).plottitles).spytitle, XTITLE = 'Pixel along loop', $
			BACKGROUND = (*(*info).plotparams).bgplotcol, COLOR = (*(*info).plotparams).plotcol
		IF (((*(*info).feedbparams).verbosity)[3] EQ 1) THEN $
      CRISPEX_VERBOSE_GET, event, [(*(*(*info).winids).restloopwid)[i]], labels=['Window ID for replot']
	ENDFOR
END

PRO CRISPEX_DISPLAYS_RESTORE_LOOPSLAB_RESIZE, event				
; Restored loopslab window resize handler, gets new window dimensions and calls (re)display routines
	WIDGET_CONTROL, event.TOP, GET_UVALUE = info
	IF (TOTAL(((*(*info).feedbparams).verbosity)[2:3]) GE 1) THEN $
    CRISPEX_VERBOSE_GET_ROUTINE, event
	CRISPEX_DISPLAYS_PLOT_RESIZE, event, event.X, event.Y, (*(*info).winsizes).restloopxres, (*(*info).winsizes).restloopyres, (*(*info).plotpos).restloopxmargin_init, (*(*info).plotpos).restloopxwall_init, $
		restloopxres, restloopyres, restloopwidth, restloopheight, restloopx0, restloopx1, restloopy0, $
  restloopy1, ERROR=error, /SLICE
	IF error THEN CRISPEX_DISPLAYS_RESIZE_ERROR, event ELSE BEGIN
		(*(*info).winsizes).restloopxres = restloopxres			& 	(*(*info).winsizes).restloopyres = restloopyres
		(*(*info).plotpos).restloopx0 = restloopx0			&	(*(*info).plotpos).restloopx1 = restloopx1
		(*(*info).plotpos).restloopy0 = restloopy0			&	(*(*info).plotpos).restloopy1 = restloopy1
		(*(*info).plotpos).restloopxplspw = restloopx1 - restloopx0	&	(*(*info).plotpos).restloopyplspw = restloopy1 - restloopy0
		(*(*info).plotaxes).restloopxticklen = -1 * (*(*info).plotaxes).ticklen / restloopheight
		(*(*info).plotaxes).restloopyticklen = -1 * (*(*info).plotaxes).ticklen / restloopwidth
		(*(*info).dispparams).restloopnlxreb = (*(*info).plotpos).restloopxplspw * (*(*info).winsizes).restloopxres 
		(*(*info).dispparams).restloopntreb = (*(*info).plotpos).restloopyplspw * (*(*info).winsizes).restloopyres 
	ENDELSE
	IF (((*(*info).feedbparams).verbosity)[3] EQ 1) THEN $
    CRISPEX_VERBOSE_GET, event, [error,(*(*info).winsizes).loopxres,(*(*info).winsizes).loopyres,(*(*info).plotpos).loopx0,(*(*info).plotpos).loopx1,$
		(*(*info).plotpos).loopy0,(*(*info).plotpos).loopy1], labels=['error','loopxres','loopyres','loopx0','loopx1','loopy0','loopy1']
	FOR i=0,N_ELEMENTS(*(*(*info).winids).restloopdrawid)-1 DO WIDGET_CONTROL, (*(*(*info).winids).restloopdrawid)[i], DRAW_XSIZE = (*(*info).winsizes).restloopxres, DRAW_YSIZE = (*(*info).winsizes).restloopyres
	WIDGET_CONTROL, event.TOP, SET_UVALUE = info
	CRISPEX_DISPLAYS_RESTORE_LOOPSLAB_REPLOT_AXES, event
	CRISPEX_DRAW_REST_LOOP, event
END

PRO CRISPEX_DISPLAYS_RESTORE_LOOPSLAB_SELECT, event						
; Restored loopslab display window creation procedure
	WIDGET_CONTROL, event.TOP, GET_UVALUE = info
	IF (TOTAL(((*(*info).feedbparams).verbosity)[2:3]) GE 1) THEN $
    CRISPEX_VERBOSE_GET_ROUTINE, event
	WIDGET_CONTROL, (*(*info).ctrlsrestore).disp_list, GET_VALUE = list_values
	IF (event.INDEX GT 0) THEN BEGIN
		(*(*info).winswitch).showrestloop = 1
		sel_disp_loop = WHERE(*(*(*info).restoreparams).disp_loopnr EQ (event.INDEX-1), count)
    IF (count GT 0) THEN BEGIN 
      ; If the selected loop is being displayed, it should be destroyed
			WIDGET_CONTROL, (*(*(*info).winids).restlooptlb)[sel_disp_loop], /DESTROY
      ; Change dropdown selection field accordingly
			list_values[event.INDEX] = 'Display time slice '+STRTRIM(event.INDEX-1,2)
			WIDGET_CONTROL, (*(*info).ctrlsrestore).disp_list, $
        SET_VALUE = list_values, SET_COMBOBOX_SELECT = event.INDEX
      ; Change dropdown selection field accordingly
			(*(*(*info).winids).restlooptlb)[sel_disp_loop] = 0
      ; Check what loops are displayed
			wherenot0 = WHERE(*(*(*info).winids).restlooptlb NE 0, count, $
        COMPLEMENT=where0)
			where0 = where0[0]
			old_restricted_t_range = $
        TOTAL(*(*(*info).dispswitch).restricted_t_range)
			old_restricted_lp_range = $
        TOTAL(*(*(*info).dispswitch).restricted_lp_range)
			old_restricted_lp_ref_range = $
        TOTAL(*(*(*info).dispswitch).restricted_lp_ref_range)
      ; If there are still loops being displayed, adjust selection made for
      ; variables
      IF (count GT 0) THEN BEGIN
				*(*(*info).winids).restlooptlb = $
          (*(*(*info).winids).restlooptlb)[wherenot0]
				*(*(*info).winids).restloopwid = $
          (*(*(*info).winids).restloopwid)[wherenot0]
				*(*(*info).winids).restloopdrawid = $
          (*(*(*info).winids).restloopdrawid)[wherenot0]
				*(*(*info).restoreparams).disp_loopnr = $
          (*(*(*info).restoreparams).disp_loopnr)[wherenot0]
				*(*(*info).restoreparams).disp_imref = $
          (*(*(*info).restoreparams).disp_imref)[wherenot0]
				*(*(*info).dispswitch).restricted_t_range = $
          (*(*(*info).dispswitch).restricted_t_range)[wherenot0]
				*(*(*info).dispswitch).restricted_lp_range = $
          (*(*(*info).dispswitch).restricted_lp_range)[wherenot0]
				*(*(*info).dispswitch).restricted_lp_ref_range = $
          (*(*(*info).dispswitch).restricted_lp_ref_range)[wherenot0]
				*(*(*info).restoreparams).disp_slices = $
					(*(*(*info).restoreparams).disp_slices)[wherenot0]
				*(*(*info).restoreparams).disp_ref_slices = $
          (*(*(*info).restoreparams).disp_ref_slices)[wherenot0]
				sel_reorder = WHERE(wherenot0 GT where0, count)
        ; If there were loop indices above the one closed, the indices need to
        ; be reordered
        IF (count GT 0) THEN BEGIN
					FOR k=0,N_ELEMENTS(sel_reorder)-1 DO BEGIN
						*(*(*(*info).loopsdata).rest_loopslice[where0+k]) = $
              *(*(*(*info).loopsdata).rest_loopslice[wherenot0[sel_reorder[k]]])
						*(*(*(*info).loopsdata).rest_loopslab[where0+k]) = $
              *(*(*(*info).loopsdata).rest_loopslab[wherenot0[sel_reorder[k]]])
						*(*(*(*info).loopsdata).rest_crossloc[where0+k]) = $
              *(*(*(*info).loopsdata).rest_crossloc[wherenot0[sel_reorder[k]]])
					ENDFOR
				ENDIF ELSE k=0
				*(*(*(*info).loopsdata).rest_loopslice[where0+k]) = 0
				*(*(*(*info).loopsdata).rest_loopslab[where0+k]) = 0
				*(*(*(*info).loopsdata).rest_crossloc[where0+k]) = 0
			ENDIF ELSE BEGIN
        ; If there are no more loops being displayed, reset all variables
				*(*(*info).restoreparams).disp_loopnr = -1
				*(*(*info).restoreparams).disp_imref = -1
				(*(*info).restoreparams).disp_slices = PTR_NEW(0)
				(*(*info).restoreparams).disp_ref_slices = PTR_NEW(0)
				(*(*info).winids).restlooptlb = PTR_NEW(0)
				(*(*info).dispswitch).restricted_t_range = PTR_NEW(0)
				(*(*info).dispswitch).restricted_lp_range = PTR_NEW(0)
				(*(*info).dispswitch).restricted_lp_ref_range = PTR_NEW(0)
				(*(*info).winswitch).showrestloop = 0
				*(*(*(*info).loopsdata).rest_loopslice[0]) = 0 
				*(*(*(*info).loopsdata).rest_loopslab[0]) = 0
				*(*(*(*info).loopsdata).rest_crossloc[0]) = 0
			ENDELSE
			IF ((TOTAL(*(*(*info).dispswitch).restricted_t_range) EQ 0) AND $
        old_restricted_t_range) THEN CRISPEX_DISPRANGE_T_RESET, event
			IF ((TOTAL(*(*(*info).dispswitch).restricted_lp_range) EQ 0) AND $
        old_restricted_lp_range) THEN CRISPEX_DISPRANGE_LP_RESET, event
			IF ((TOTAL(*(*(*info).dispswitch).restricted_lp_ref_range) EQ 0) AND $
        old_restricted_lp_ref_range) THEN $
        CRISPEX_DISPRANGE_LP_RESET, event, /REFERENCE
			WIDGET_CONTROL, (*(*info).ctrlscp).lp_slider, $
        SENSITIVE = (TOTAL(*(*(*info).restoreparams).disp_slices) EQ 0) 
			WIDGET_CONTROL, (*(*info).ctrlscp).lp_ref_slider, $
        SENSITIVE = (TOTAL(*(*(*info).restoreparams).disp_ref_slices) EQ 0) 
		ENDIF ELSE BEGIN
      ; If displaying a new loop, change the display filename
			(*(*info).restoreparams).disp_loopfile = $
        (*(*(*info).restoreparams).cfiles)[event.INDEX-1]
			refbase = FILE_BASENAME(STRMID((*(*info).dataparams).refimfilename,0,$
                  STRPOS((*(*info).dataparams).refimfilename,'.',/REVERSE_SEARCH)))
      IF ((*(*info).dataparams).nsjifiles GE 1) THEN BEGIN
        sjibase = STRARR((*(*info).dataparams).nsjifiles)
        FOR idx_sji=0,(*(*info).dataparams).nsjifiles-1 DO $
    			sjibase[idx_sji] = $
            FILE_BASENAME(STRMID((*(*info).dataparams).sjifilename[idx_sji],0,$
                          STRPOS((*(*info).dataparams).sjifilename[idx_sji],$
                          '.',/REVERSE_SEARCH)))
      ENDIF ELSE sjibase = ''
      ; Check whether it is a main, reference or SJI loop
      disp_imref = 0  
			IF (STRLEN(refbase) GT 0) THEN $
        disp_imref += STRCMP(refbase,FILE_BASENAME($
          (*(*info).restoreparams).disp_loopfile),STRLEN(refbase)) 
      IF (TOTAL(STRLEN(sjibase)) GT 0) THEN $
        disp_imref += (TOTAL(STRCMP(sjibase,FILE_BASENAME($
          (*(*info).restoreparams).disp_loopfile),STRLEN(sjibase)) GE 1))*2
      ; If there are already loops being displayed, append variables to current
      ; selection
			IF (TOTAL(*(*(*info).restoreparams).disp_loopnr) GE 0) THEN BEGIN
				*(*(*info).restoreparams).disp_loopnr = $
          [*(*(*info).restoreparams).disp_loopnr,event.INDEX-1] 
				*(*(*info).restoreparams).disp_imref = $
          [*(*(*info).restoreparams).disp_imref,disp_imref]
			ENDIF ELSE BEGIN
        ; Else initialise variables
				*(*(*info).restoreparams).disp_loopnr = event.INDEX-1
				*(*(*info).restoreparams).disp_imref = disp_imref
			ENDELSE
      ; Adjust dropdown menu labels
			list_values[event.INDEX] = 'Hide time slice '+STRTRIM(event.INDEX-1,2)
			WIDGET_CONTROL, (*(*info).ctrlsrestore).disp_list, SET_VALUE=list_values,$
        SET_COMBOBOX_SELECT = event.INDEX
      ; Start displaying corresponding loopslab
			CRISPEX_DISPLAYS_RESTORE_LOOPSLAB, event
		ENDELSE
	ENDIF ELSE BEGIN
		(*(*info).restoreparams).disp_loopfile = '0'
		IF (*(*info).winswitch).showrestloop THEN BEGIN
			(*(*info).winswitch).showrestloop = 0
			CRISPEX_DISPRANGE_T_RESET, event
			CRISPEX_DISPRANGE_LP_RESET, event
			CRISPEX_DISPRANGE_LP_RESET, event, /REFERENCE
			FOR i=0,N_ELEMENTS(*(*(*info).winids).restlooptlb)-1 DO BEGIN
				WIDGET_CONTROL, (*(*(*info).winids).restlooptlb)[i], /DESTROY
				list_values[(*(*(*info).restoreparams).disp_loopnr)[i]+1] = $
          'Display time slice '+STRTRIM((*(*(*info).restoreparams).disp_loopnr)[i],2)
				*(*(*(*info).loopsdata).rest_loopslice[i]) = 0
				*(*(*(*info).loopsdata).rest_loopslab[i]) = 0
				*(*(*(*info).loopsdata).rest_crossloc[i]) = 0
			ENDFOR
			WIDGET_CONTROL, (*(*info).ctrlsrestore).disp_list, SET_VALUE=list_values,$
        SET_COMBOBOX_SELECT = event.INDEX
			(*(*info).winids).restlooptlb = PTR_NEW(0)
			(*(*info).dispswitch).restricted_t_range = PTR_NEW(0)
			(*(*info).dispswitch).restricted_lp_range = PTR_NEW(0)
			*(*(*info).restoreparams).disp_loopnr = -1
			(*(*info).restoreparams).disp_slices = PTR_NEW(0)
			(*(*info).restoreparams).disp_ref_slices = PTR_NEW(0)
		ENDIF
		WIDGET_CONTROL,(*(*info).ctrlscp).lp_slider,/SENSITIVE
	ENDELSE
END

PRO CRISPEX_DISPLAYS_RESTORE_LOOPSLAB, event, NO_DRAW=no_draw, INDEX=index
; Restored loopslab display window creation procedure
	WIDGET_CONTROL, event.TOP, GET_UVALUE = info
	IF (TOTAL(((*(*info).feedbparams).verbosity)[2:3]) GE 1) THEN $
    CRISPEX_VERBOSE_GET_ROUTINE, event
		update_t_range = 0
		update_lp_range = 0
		restricted_t_range = 0
		restricted_lp_range = 0
		restricted_lp_ref_range = 0
		ref_slice_only = 0
		WIDGET_CONTROL,/HOURGLASS
		RESTORE, (*(*info).restoreparams).disp_loopfile
		IF (N_ELEMENTS(INDEX) EQ 1) THEN $
      idx = index $
    ELSE $
      idx = N_ELEMENTS(*(*(*info).restoreparams).disp_loopnr)-1
    sel_idx = (*(*(*info).restoreparams).disp_loopnr)[idx]
		*(*(*(*info).loopsdata).rest_crossloc[idx]) = vertices
		IF (N_ELEMENTS(loop_slab) GT 0) THEN $
      loopslab = loop_slab $
    ELSE $
      loopslab = loop_slice
		*(*(*(*info).loopsdata).rest_loopslab[idx]) = loopslab
    ; Initialise empty slice 
    *(*(*(*info).loopsdata).rest_empty_slice)[sel_idx] = $
      MAKE_ARRAY(N_ELEMENTS(*(*(*(*info).restoreparams).xr)[sel_idx]),$
      (SIZE(loopslab))[2], TYPE=SIZE(loopslab, /TYPE))
    ; Arbitrary, but consistent, minimum value such that the gaps are really
    ; black compared to the data values
    min_dispslice_data = -(1+(MIN(loopslab) LT 0)*2) * ABS(MIN(loopslab))
    IF ((*(*(*(*info).loopsdata).rest_empty_slice)[sel_idx])[0,0] NE $
      min_dispslice_data) THEN $
      REPLICATE_INPLACE, *(*(*(*info).loopsdata).rest_empty_slice)[sel_idx], min_dispslice_data
		slice_only = (SIZE(*(*(*(*info).loopsdata).rest_loopslab[idx]),/N_DIMENSIONS) LT 3)
		IF slice_only THEN BEGIN			; Only a slice
			*(*(*(*info).loopsdata).rest_loopslice[idx]) = *(*(*(*info).loopsdata).rest_loopslab[idx])
			IF ((SIZE(*(*(*(*info).loopsdata).rest_loopslice[idx])))[2] NE $
        (*(*info).dataparams).nt) THEN BEGIN
				IF (N_ELEMENTS(t_low) EQ 0) THEN BEGIN
					CRISPEX_WINDOW_OK, event, 'WARNING!', $
						'The slice to be loaded has a reduced temporal range,'+$
            'however the format in which it was saved does not '+$
						'allow for correct slice restoration. If display '+$
            'is required, please save the slice again.', $
            OK_EVENT='CRISPEX_CLOSE_EVENT_WINDOW', BASE=tlb
					(*(*info).winids).warntlb = tlb
					RETURN
				ENDIF ELSE BEGIN
					IF ((t_low GE (*(*info).dispparams).t_upp) OR $
              (t_upp LT (*(*info).dispparams).t_low)) THEN BEGIN
						CRISPEX_WINDOW_OK, event, 'WARNING!', $
							'The temporal range of the loaded slice falls outside '+$
              'the range set by the currently loaded slices. If '+$
							'display is required, please close all currently '+$
              'loaded slices before proceeding.', $
              OK_EVENT='CRISPEX_CLOSE_EVENT_WINDOW', BASE=tlb
						(*(*info).winids).warntlb = tlb
						WIDGET_CONTROL, (*(*info).ctrlsrestore).disp_list, GET_VALUE = list_values
						caseidx = (*(*(*info).restoreparams).disp_loopnr)[idx]
						list_values[caseidx+1] = 'Display time slice '+STRTRIM(caseidx,2)
						WIDGET_CONTROL, (*(*info).ctrlsrestore).disp_list, SET_VALUE = list_values, $
              SET_COMBOBOX_SELECT = caseidx+1
						*(*(*info).restoreparams).disp_loopnr = (*(*(*info).restoreparams).disp_loopnr)[0:idx-1]
						*(*(*info).restoreparams).disp_imref = (*(*(*info).restoreparams).disp_imref)[0:idx-1]
            (*(*info).winswitch).showrestloop = 0
						RETURN
					ENDIF ELSE BEGIN
						update_t_range = 1
						restricted_t_range = 1
						(*(*info).dispparams).t_low = t_low
						(*(*info).dispparams).t_upp = t_upp
						IF (N_ELEMENTS(t_saved) EQ 0) THEN $
              (*(*info).dispparams).t = (*(*info).dispparams).t_low $
            ELSE $
              (*(*info).dispparams).t = t_saved
						WIDGET_CONTROL, (*(*info).ctrlscp).reset_trange_but, SENSITIVE = 0
						WIDGET_CONTROL, (*(*info).ctrlscp).lower_t_text, $
              SET_VALUE = STRTRIM((*(*info).dispparams).t_low,2), SENSITIVE = 0
						WIDGET_CONTROL, (*(*info).ctrlscp).upper_t_text, $
              SET_VALUE = STRTRIM((*(*info).dispparams).t_upp,2), SENSITIVE = 0
					ENDELSE
				ENDELSE
			ENDIF
			IF (*(*(*info).restoreparams).disp_imref)[idx] THEN BEGIN
				restricted_lp_ref_range = 1
				(*(*info).dataparams).lp_ref = spect_pos > (*(*info).dispparams).lp_ref_low < (*(*info).dispparams).lp_ref_upp 
				WIDGET_CONTROL,(*(*info).ctrlscp).lp_ref_slider, SENSITIVE = 0, $
          SET_VALUE = (*(*info).dataparams).lp_ref
				ref_slice_only = 1	&	slice_only = 0
			ENDIF ELSE BEGIN
				restricted_lp_range = 1
				(*(*info).dataparams).lp = spect_pos > (*(*info).dispparams).lp_low < (*(*info).dispparams).lp_upp
				WIDGET_CONTROL,(*(*info).ctrlscp).lp_slider,SENSITIVE = 0, SET_VALUE = (*(*info).dataparams).lp
			ENDELSE
			CRISPEX_UPDATE_T, event
		ENDIF ELSE BEGIN										; A full or partial slab
			IF ((SIZE(*(*(*(*info).loopsdata).rest_loopslab[idx])))[2] NE (*(*info).dataparams).nt) THEN BEGIN
				IF (N_ELEMENTS(t_saved) EQ 0) THEN $
          (*(*info).dispparams).t = (*(*info).dispparams).t_low $
        ELSE $
          (*(*info).dispparams).t = t_saved
				IF (N_ELEMENTS(t_low) EQ 0) THEN BEGIN
					CRISPEX_WINDOW_OK, event, 'WARNING!', $
						'The slice to be loaded has a reduced temporal range, '+$
            'however the format in which it was saved does not '+$
						'allow for correct slice restoration. If display '+$
            'is required, please save the slice again.', $
            OK_EVENT='CRISPEX_CLOSE_EVENT_WINDOW', BASE=tlb
					(*(*info).winids).warntlb = tlb
					RETURN
				ENDIF ELSE BEGIN
					IF ((t_low GE (*(*info).dispparams).t_upp) OR $
            (t_upp LT (*(*info).dispparams).t_low)) THEN BEGIN
						CRISPEX_WINDOW_OK, event, 'WARNING!', $
							'The temporal range of the loaded slice falls outside '+$
              'the range set by the currently loaded slices. If '+$
							'display is required, please close all currently '+$
              'loaded slices before proceeding.', $
              OK_EVENT='CRISPEX_CLOSE_EVENT_WINDOW', BASE=tlb
						(*(*info).winids).warntlb = tlb
						WIDGET_CONTROL, (*(*info).ctrlsrestore).disp_list, GET_VALUE = list_values
						caseidx = (*(*(*info).restoreparams).disp_loopnr)[idx]
						list_values[caseidx+1] = 'Display time slice '+STRTRIM(caseidx,2)
						WIDGET_CONTROL, (*(*info).ctrlsrestore).disp_list, SET_VALUE = list_values, $
              SET_COMBOBOX_SELECT = caseidx+1
						*(*(*info).restoreparams).disp_loopnr = (*(*(*info).restoreparams).disp_loopnr)[0:idx-1]
						*(*(*info).restoreparams).disp_imref = (*(*(*info).restoreparams).disp_imref)[0:idx-1]
						RETURN
					ENDIF ELSE BEGIN
						update_t_range = 1
						restricted_t_range = 1
						(*(*info).dispparams).t_low = t_low
						(*(*info).dispparams).t_upp = t_upp
						IF (N_ELEMENTS(t) EQ 0) THEN $
              (*(*info).dispparams).t = (*(*info).dispparams).t_low $
            ELSE $
              (*(*info).dispparams).t = t
						WIDGET_CONTROL, (*(*info).ctrlscp).lower_t_text, $
              SET_VALUE = STRTRIM((*(*info).dispparams).t_low,2), SENSITIVE = 0
						WIDGET_CONTROL, (*(*info).ctrlscp).upper_t_text, $
              SET_VALUE = STRTRIM((*(*info).dispparams).t_upp,2), SENSITIVE = 0
					ENDELSE
				ENDELSE
			ENDIF
			IF (*(*(*info).restoreparams).disp_imref)[idx] THEN nlp_comp = (*(*info).dataparams).refnlp ELSE nlp_comp = (*(*info).dataparams).nlp
			IF ((SIZE(*(*(*(*info).loopsdata).rest_loopslab[idx])))[3] NE nlp_comp) THEN BEGIN
				update_lp_range = 1
				IF (*(*(*info).restoreparams).disp_imref)[idx] THEN BEGIN	; Reference
					restricted_lp_ref_range = 1
					(*(*info).dispparams).lp_ref_low = spect_pos_low > (*(*info).dispparams).lp_ref_low
					(*(*info).dispparams).lp_ref_upp = spect_pos_upp < (*(*info).dispparams).lp_ref_upp
					(*(*info).dispparams).lp_ref_range = (*(*info).dispparams).lp_ref_upp - (*(*info).dispparams).lp_ref_low + 1
					(*(*info).dataparams).lp_ref = spect_pos > (*(*info).dispparams).lp_ref_low < (*(*info).dispparams).lp_ref_upp
					WIDGET_CONTROL,(*(*info).ctrlscp).lp_ref_slider, SET_SLIDER_MIN = (*(*info).dispparams).lp_ref_low, SET_SLIDER_MAX = (*(*info).dispparams).lp_ref_upp, $
						SET_VALUE = (*(*info).dataparams).lp_ref
				ENDIF ELSE BEGIN						; Main
					restricted_lp_range = 1
					(*(*info).dispparams).lp_low = spect_pos_low > (*(*info).dispparams).lp_low
					(*(*info).dispparams).lp_upp = spect_pos_upp < (*(*info).dispparams).lp_upp
					(*(*info).dataparams).lp = spect_pos > (*(*info).dispparams).lp_low < (*(*info).dispparams).lp_upp
					WIDGET_CONTROL, (*(*info).ctrlscp).lower_lp_text, SET_VALUE = STRTRIM((*(*info).dispparams).lp_low,2), SENSITIVE = 0
					WIDGET_CONTROL, (*(*info).ctrlscp).upper_lp_text, SET_VALUE = STRTRIM((*(*info).dispparams).lp_upp,2), SENSITIVE = 0
					WIDGET_CONTROL,(*(*info).ctrlscp).lp_slider,SET_SLIDER_MIN = (*(*info).dispparams).lp_low, SET_SLIDER_MAX = (*(*info).dispparams).lp_upp, SET_VALUE = (*(*info).dataparams).lp
				ENDELSE
			ENDIF
			CRISPEX_UPDATE_LP, event
		ENDELSE
    (*(*info).intparams).lp_diag_all = $
      TOTAL((*(*info).dataparams).lp GE (*(*info).intparams).diag_start)-1
    (*(*info).intparams).lp_ref_diag_all = $
      TOTAL((*(*info).dataparams).lp_ref GE (*(*info).intparams).refdiag_start)-1
		IF (loop_size GT 0) THEN (*(*(*info).loopsdata).rest_loopsize)[idx] = loop_size ELSE (*(*(*info).loopsdata).rest_loopsize)[idx] = (SIZE(loopslab))[1]
		wintitle = 'CRISPEX'+(*(*info).sesparams).instance_label+': Space-time plot'
		CRISPEX_WINDOW, (*(*info).winsizes).restloopxres, (*(*info).winsizes).restloopyres, (*(*info).winids).root, wintitle+STRTRIM((*(*(*info).restoreparams).disp_loopnr)[idx],2), tlb, wid, $
			(*(*info).winsizes).xywinx+(*(*info).winsizes).xdelta,((*(*info).winswitch).showsp + (*(*info).winswitch).showphis) * (*(*info).winsizes).ydelta, DRAWID = disp_rest_loopdrawid, RESIZING = 1, $
			RES_HANDLER = 'CRISPEX_DISPLAYS_RESTORE_LOOPSLAB_RESIZE'
		PLOT, FINDGEN(N_ELEMENTS(*(*(*(*info).restoreparams).xr)[idx])), $
      *(*(*info).dispparams).tarr_main, $
      /NODATA, YR=[(*(*info).dispparams).t_low_main, (*(*info).dispparams).t_upp_main], $
			/YS, POS=[(*(*info).plotpos).restloopx0,(*(*info).plotpos).restloopy0,$
      (*(*info).plotpos).restloopx1,(*(*info).plotpos).restloopy1], $
			YTICKLEN = (*(*info).plotaxes).restloopyticklen, XTICKLEN = (*(*info).plotaxes).restloopxticklen, /XS, YTITLE = (*(*info).plottitles).spytitle, XTITLE = 'Pixel along loop',$
			BACKGROUND = (*(*info).plotparams).bgplotcol, COLOR = (*(*info).plotparams).plotcol
		IF ((*(*(*info).winids).restlooptlb)[0] NE 0) THEN BEGIN
			*(*(*info).winids).restlooptlb = [*(*(*info).winids).restlooptlb,tlb]
			*(*(*info).winids).restloopwid = [*(*(*info).winids).restloopwid,wid]
			*(*(*info).winids).restloopdrawid = [*(*(*info).winids).restloopdrawid,disp_rest_loopdrawid]
			*(*(*info).winids).restloopwintitle = [*(*(*info).winids).restloopwintitle,wintitle]
			*(*(*info).dispswitch).restricted_t_range = [*(*(*info).dispswitch).restricted_t_range,restricted_t_range]
			*(*(*info).dispswitch).restricted_lp_range = [*(*(*info).dispswitch).restricted_lp_range,restricted_lp_range]
			*(*(*info).dispswitch).restricted_lp_ref_range = [*(*(*info).dispswitch).restricted_lp_ref_range,restricted_lp_ref_range]
			*(*(*info).restoreparams).disp_slices = [*(*(*info).restoreparams).disp_slices,slice_only]
			*(*(*info).restoreparams).disp_ref_slices = [*(*(*info).restoreparams).disp_ref_slices,ref_slice_only]
		ENDIF ELSE BEGIN
			*(*(*info).winids).restlooptlb = tlb
			*(*(*info).winids).restloopwid = wid
			*(*(*info).winids).restloopdrawid = disp_rest_loopdrawid
			*(*(*info).winids).restloopwintitle = wintitle
			*(*(*info).dispswitch).restricted_t_range = restricted_t_range
			*(*(*info).dispswitch).restricted_lp_range = restricted_lp_range
			*(*(*info).dispswitch).restricted_lp_ref_range = restricted_lp_ref_range
			*(*(*info).restoreparams).disp_slices = slice_only
			*(*(*info).restoreparams).disp_ref_slices = ref_slice_only
		ENDELSE
		WIDGET_CONTROL, (*(*(*info).winids).restlooptlb)[N_ELEMENTS(*(*(*info).winids).restlooptlb)-1], SET_UVALUE = info
		IF update_t_range THEN BEGIN
			CRISPEX_DISPRANGE_T_RANGE, event
			WIDGET_CONTROL, (*(*info).ctrlscp).reset_trange_but, SENSITIVE = 0
		ENDIF
		IF update_lp_range THEN BEGIN
			CRISPEX_DISPRANGE_LP_RANGE, event
			WIDGET_CONTROL, (*(*info).ctrlscp).reset_lprange_but, SENSITIVE = 0
		ENDIF
		IF ((update_t_range EQ 0) AND (update_lp_range EQ 0) AND ~KEYWORD_SET(NO_DRAW)) THEN CRISPEX_DRAW, event
		IF (((*(*info).feedbparams).verbosity)[3] EQ 1) THEN $
      CRISPEX_VERBOSE_GET, event, [*(*(*info).winids).restlooptlb,*(*(*info).winids).restloopwid,*(*(*info).winids).restloopdrawid], $
			labels=['restlooptlb','restloopwid','restloopdrawid']
END

PRO CRISPEX_DISPLAYS_RETRIEVE_DET_LOOPSLAB_REPLOT_AXES, event
; Updates retrieved detection loopslab display window plot axes range according to set parameters
	WIDGET_CONTROL, event.TOP, GET_UVALUE = info
	IF (TOTAL(((*(*info).feedbparams).verbosity)[2:3]) GE 1) THEN $
    CRISPEX_VERBOSE_GET_ROUTINE, event
	WSET, (*(*info).winids).retrdetwid
	PLOT, FINDGEN(N_ELEMENTS((*(*(*(*info).detparams).xlr)[$
    (*(*info).detparams).idx])[*,0])), *(*(*info).dispparams).tarr_main, $
    /NODATA, YR=[(*(*info).dispparams).t_low_main, (*(*info).dispparams).t_upp_main], $
    /YS, POS=[(*(*info).plotpos).retrdetx0,(*(*info).plotpos).retrdety0,$
    (*(*info).plotpos).retrdetx1,(*(*info).plotpos).retrdety1], $
		YTICKLEN = (*(*info).plotaxes).retrdetyticklen, XTICKLEN = (*(*info).plotaxes).retrdetxticklen, /XS, YTITLE = (*(*info).plottitles).spytitle, XTITLE = 'Pixel along loop', $
		BACKGROUND = (*(*info).plotparams).bgplotcol, COLOR = (*(*info).plotparams).plotcol
	IF (((*(*info).feedbparams).verbosity)[3] EQ 1) THEN $
    CRISPEX_VERBOSE_GET, event, [(*(*info).winids).retrdetwid], labels=['Window ID for replot']
END

PRO CRISPEX_DISPLAYS_RETRIEVE_DET_LOOPSLAB_RESIZE, event	
; Retrieved detection loopslab window resize handler, gets new window dimensions and calls (re)display routines
	WIDGET_CONTROL, event.TOP, GET_UVALUE = info
	IF (TOTAL(((*(*info).feedbparams).verbosity)[2:3]) GE 1) THEN $
    CRISPEX_VERBOSE_GET_ROUTINE, event
	CRISPEX_DISPLAYS_PLOT_RESIZE, event, event.X, event.Y, (*(*info).winsizes).retrdetxres, (*(*info).winsizes).retrdetyres, (*(*info).plotpos).retrdetxmargin_init, (*(*info).plotpos).retrdetxwall_init, $
		retrdetxres, retrdetyres, retrdetwidth, retrdetheight, retrdetx0, retrdetx1, retrdety0, $
  retrdety1, ERROR=error, /SLICE
	IF error THEN CRISPEX_DISPLAYS_RESIZE_ERROR, event ELSE BEGIN
		(*(*info).winsizes).retrdetxres = retrdetxres			& 	(*(*info).winsizes).retrdetyres = retrdetyres
		(*(*info).plotpos).retrdetx0 = retrdetx0			&	(*(*info).plotpos).retrdetx1 = retrdetx1
		(*(*info).plotpos).retrdety0 = retrdety0			&	(*(*info).plotpos).retrdety1 = retrdety1
		(*(*info).plotpos).retrdetxplspw = retrdetx1 - retrdetx0	&	(*(*info).plotpos).retrdetyplspw = retrdety1 - retrdety0
		(*(*info).plotaxes).retrdetxticklen = -1 * (*(*info).plotaxes).ticklen / retrdetheight
		(*(*info).plotaxes).retrdetyticklen = -1 * (*(*info).plotaxes).ticklen / retrdetwidth
		(*(*info).dispparams).retrdetnlxreb = (*(*info).plotpos).retrdetxplspw * (*(*info).winsizes).retrdetxres 
		(*(*info).dispparams).retrdetntreb = (*(*info).plotpos).retrdetyplspw * (*(*info).winsizes).retrdetyres 
	ENDELSE
	IF (((*(*info).feedbparams).verbosity)[3] EQ 1) THEN $
    CRISPEX_VERBOSE_GET, event, [error,(*(*info).winsizes).loopxres,(*(*info).winsizes).loopyres,(*(*info).plotpos).loopx0,(*(*info).plotpos).loopx1,$
		(*(*info).plotpos).loopy0,(*(*info).plotpos).loopy1], labels=['error','loopxres','loopyres','loopx0','loopx1','loopy0','loopy1']
	WIDGET_CONTROL, (*(*info).winids).retrdetdrawid, DRAW_XSIZE = (*(*info).winsizes).retrdetxres, DRAW_YSIZE = (*(*info).winsizes).retrdetyres
	WIDGET_CONTROL, event.TOP, SET_UVALUE = info
	CRISPEX_DISPLAYS_RETRIEVE_DET_LOOPSLAB_REPLOT_AXES, event
	CRISPEX_DRAW_RETR_DET, event
END

PRO CRISPEX_DISPLAYS_RETRIEVE_DET_LOOPSLAB, event, NO_DRAW=no_draw
; Retrieved detection loopslab display window creation procedure
	WIDGET_CONTROL, event.TOP, GET_UVALUE = info
	IF (TOTAL(((*(*info).feedbparams).verbosity)[2:3]) GE 1) THEN $
    CRISPEX_VERBOSE_GET_ROUTINE, event
	IF ~KEYWORD_SET(NO_DRAW) THEN (*(*info).detparams).idx = event.INDEX-1
	IF ((*(*info).detparams).idx GE 0) THEN BEGIN
    ; If a detection is already being displayed, close that window
		IF ((*(*info).winids).retrdettlb GT 0) THEN $
      WIDGET_CONTROL, (*(*info).winids).retrdettlb, /DESTROY
		(*(*info).winswitch).showretrdet = 1
		WIDGET_CONTROL,/HOURGLASS
    ; Gather input parameters
    maxpass = ((*(*info).detparams).lp_up-(*(*info).detparams).lp_dn+1) * $
      (*(*info).detparams).width
    t_0 = SYSTIME(/SECONDS)
    inparams = {xlp:*(*(*(*info).detparams).xlp)[(*(*info).detparams).idx], $
      ylp:*(*(*(*info).detparams).ylp)[(*(*info).detparams).idx], $
      xlr:*(*(*(*info).detparams).xlr)[(*(*info).detparams).idx], $
      ylr:*(*(*(*info).detparams).ylr)[(*(*info).detparams).idx], $
      nx:(*(*info).dataparams).nx, ny:(*(*info).dataparams).ny, $
      lp_dn:(*(*info).detparams).lp_dn, lp_up:(*(*info).detparams).lp_up, $
      no_nlp:((*(*info).dataparams).nlp LE 1), idx:(*(*info).detparams).idx, $
      detimref:1, data:(*(*info).data).imagedata, t_0:t_0, maxpass:maxpass}
    ; Get the detection slab
		CRISPEX_RETRIEVE_DET_GET_SLAB, event, inparams, w_lpts_out, gapresult_out, $
      loopslab_out, crossloc_out, loopsize_out, t_det_out, t_low_out, $
      t_upp_out
    (*(*info).detparams).ngaps = gapresult_out.ngaps
    *(*(*info).detparams).databounds = gapresult_out.databounds
    *(*(*info).detparams).wdatabounds = gapresult_out.wdatabounds
	  *(*(*info).loopsdata).det_loopslab = loopslab_out
	  *(*(*info).loopsdata).det_crossloc = crossloc_out
	  (*(*info).loopsdata).det_loopsize = loopsize_out
    (*(*info).dispparams).t_low = t_low_out
    (*(*info).dispparams).t_upp = t_upp_out
    (*(*info).dispparams).t = t_det_out
		IF ~KEYWORD_SET(NO_DRAW) THEN CRISPEX_UPDATE_LP, event
    ; Set window title and create window
		title = 'CRISPEX'+(*(*info).sesparams).instance_label+$
      ': Detection space-time plot'
		CRISPEX_WINDOW, (*(*info).winsizes).retrdetxres, $
      (*(*info).winsizes).retrdetyres, (*(*info).winids).root, $
      title+STRTRIM((*(*info).detparams).idx,2), tlb, wid, $
			(*(*info).winsizes).xywinx+(*(*info).winsizes).xdelta,$
      ((*(*info).winswitch).showsp + (*(*info).winswitch).showphis) * $
      (*(*info).winsizes).ydelta, DRAWID = disp_retr_detdrawid, RESIZING = 1, $
			RES_HANDLER = 'CRISPEX_DISPLAYS_RETRIEVE_DET_LOOPSLAB_RESIZE'
    ; Plot basic axes box
		PLOT, FINDGEN(N_ELEMENTS((*(*(*(*info).detparams).xlr)[$
      (*(*info).detparams).idx])[*,0])), *(*(*info).dispparams).tarr_main, $
      /NODATA, YR=[(*(*info).dispparams).t_low_main, $
      (*(*info).dispparams).t_upp_main], $
      /YS, POS=[(*(*info).plotpos).retrdetx0,(*(*info).plotpos).retrdety0,$
      (*(*info).plotpos).retrdetx1,(*(*info).plotpos).retrdety1], $
			YTICKLEN = (*(*info).plotaxes).retrdetyticklen, $
      XTICKLEN = (*(*info).plotaxes).retrdetxticklen, /XS, $
      YTITLE = (*(*info).plottitles).spytitle, XTITLE = 'Pixel along loop', $
			BACKGROUND = (*(*info).plotparams).bgplotcol, $
      COLOR = (*(*info).plotparams).plotcol
		(*(*info).winids).retrdettlb = tlb	
    (*(*info).winids).retrdetwid = wid	
    (*(*info).winids).retrdetdrawid = disp_retr_detdrawid
		(*(*info).winids).retrdetwintitle = title
    ; Pass on the info pointer
		WIDGET_CONTROL, (*(*info).winids).retrdettlb, SET_UVALUE = info
    ; Adjust temporal range depending on the selected detection and delta time
		IF ~KEYWORD_SET(NO_DRAW) THEN CRISPEX_DISPRANGE_T_RANGE, event
		WIDGET_CONTROL, (*(*info).ctrlscp).lower_t_text, $
      SET_VALUE=STRTRIM((*(*info).dispparams).t_low,2), SENSITIVE=0
		WIDGET_CONTROL, (*(*info).ctrlscp).upper_t_text, $
      SET_VALUE=STRTRIM((*(*info).dispparams).t_upp,2), SENSITIVE=0 
	ENDIF ELSE BEGIN
		IF (*(*info).winswitch).showretrdet THEN BEGIN
			(*(*info).winswitch).showretrdet = 0
			WIDGET_CONTROL, (*(*info).winids).retrdettlb, /DESTROY
			(*(*info).winids).retrdettlb = 0
		ENDIF
	ENDELSE
	IF (((*(*info).feedbparams).verbosity)[3] EQ 1) THEN $
    CRISPEX_VERBOSE_GET, event, [(*(*info).winids).retrdettlb,$
      (*(*info).winids).retrdetwid,(*(*info).winids).retrdetdrawid], $
	  	labels=['retrdettlb','retrdetwid','retrdetdrawid']
END
	
PRO CRISPEX_DISPLAYS_REFLS_RESIZE, event, STOKES_SELECT=stokes_select							
; Detailed spectrum window resize handler, gets new window dimensions and calls (re)display routines
	WIDGET_CONTROL, event.TOP, GET_UVALUE = info
	IF (TOTAL(((*(*info).feedbparams).verbosity)[2:3]) GE 1) THEN $
    CRISPEX_VERBOSE_GET_ROUTINE, event
	IF KEYWORD_SET(STOKES_SELECT) THEN BEGIN
		newlsxres = (*(*info).winsizes).reflsxres	
    newlsyres = (*(*info).winsizes).reflsyres
	ENDIF ELSE BEGIN
		newlsxres = event.X		&	newlsyres = event.Y
	ENDELSE
	CRISPEX_DISPLAYS_PLOT_RESIZE, event, newlsxres, newlsyres, $
    (*(*info).winsizes).reflsxres, (*(*info).winsizes).reflsyres, $
    (*(*info).plotpos).reflsxmargin_init, (*(*info).plotpos).reflsxwall_init, $
    reflsxres, reflsyres, reflswidth, reflsheight, reflsx0, reflsx1, reflsy0, $
    reflsy1, (*(*info).plotswitch).v_dop_set_ref, $
    INX0=(*(*info).plotpos).reflsx0, INX1=(*(*info).plotpos).reflsx1, $
    INY0=(*(*info).plotpos).reflsy0, INY1=(*(*info).plotpos).reflsy1, $
    ERROR=error, /DETSPECT, /REFERENCE, STOKES_SELECT=stokes_select
	IF error THEN CRISPEX_DISPLAYS_RESIZE_ERROR, event ELSE BEGIN
		(*(*info).winsizes).reflsxres = reflsxres	& 	(*(*info).winsizes).reflsyres = reflsyres
		(*(*info).plotpos).reflsx0 = reflsx0		&	(*(*info).plotpos).reflsx1 = reflsx1
		(*(*info).plotpos).reflsy0 = reflsy0		&	(*(*info).plotpos).reflsy1 = reflsy1
		(*(*info).plotaxes).reflsxticklen = (*(*info).plotaxes).ticklen / reflsheight
		(*(*info).plotaxes).reflsyticklen = (*(*info).plotaxes).ticklen / reflswidth
	ENDELSE
	IF (((*(*info).feedbparams).verbosity)[3] EQ 1) THEN $
    CRISPEX_VERBOSE_GET, event, [error,(*(*info).winsizes).reflsxres,(*(*info).winsizes).reflsyres,(*(*info).plotpos).reflsx0,(*(*info).plotpos).reflsx1,$
		(*(*info).plotpos).reflsy0,(*(*info).plotpos).reflsy1], labels=['error','reflsxres','reflsyres','reflsx0','reflsx1','reflsy0','reflsy1']
	WIDGET_CONTROL, (*(*info).winids).reflsdrawid, DRAW_XSIZE = (*(*info).winsizes).reflsxres, DRAW_YSIZE = (*(*info).winsizes).reflsyres
	WIDGET_CONTROL, event.TOP, SET_UVALUE = info
  CRISPEX_DRAW_SPECTRAL_REF, event, /LS_ONLY
END

PRO CRISPEX_DISPLAYS_REFSP_REPLOT_AXES, event, NO_AXES=no_axes
; Updates reference temporal spectrum display window plot axes range according to set parameters
	WIDGET_CONTROL, event.TOP, GET_UVALUE = info
	IF (TOTAL(((*(*info).feedbparams).verbosity)[2:3]) GE 1) THEN $
    CRISPEX_VERBOSE_GET_ROUTINE, event
	WSET, (*(*info).winids).refspwid
  IF ((*(*info).dispswitch).scalestokes[1] AND $
      ((*(*info).dataparams).s_ref NE 0)) THEN $
    extratitle = '/I' $
  ELSE $
    extratitle = ''
	IF (*(*info).plotswitch).v_dop_set_ref THEN $
    extratitle += '!C' $
  ELSE $
    extratitle += ''
	IF (*(*info).plotswitch).refmultichannel THEN $
    title = 'Stokes '+((*(*info).stokesparams).labels_ref)[$
      (*(*info).dataparams).s_ref]+extratitle $
  ELSE $
    title = ''
  ; Set axes parameters depending on # of diagnostics
  IF ((*(*info).intparams).ndisp_refdiagnostics GT 1) THEN BEGIN
    xticklen = 1E-9   & xtitle = ''
    xtickname = REPLICATE(' ',60)
    xtlen_basic_fac = 0.5
    xtlen_major_fac = 0.8
    IF KEYWORD_SET(NO_AXES) THEN BEGIN
      yticklen = 1E-9 & ytitle = ''
      ytickname = REPLICATE(' ',60)
    ENDIF ELSE BEGIN
      yticklen = (*(*info).plotaxes).refspyticklen
      ytitle = (*(*info).plottitles).spytitle
      ytickname = ''
    ENDELSE
  ENDIF ELSE BEGIN
    xticklen = (*(*info).plotaxes).refspxticklen
    xtitle = (*(*info).plottitles).refspxtitle
    yticklen = (*(*info).plotaxes).refspyticklen
    ytitle = (*(*info).plottitles).spytitle
    xtlen_basic_fac = 1.
    xtickname = ''  & ytickname = ''
  ENDELSE
  xticklen = xtlen_basic_fac * (*(*info).plotaxes).spxticklen
  t_low_y = (*(*info).dispparams).t_low_ref
  t_upp_y = (*(*info).dispparams).t_upp_ref
  lp_low_overall = (*(*info).dispparams).lp_ref_low_tmp[$
                    (*(*(*info).intparams).wheredisprefdiag)[0]] 
  lp_upp_overall = (*(*info).dispparams).lp_ref_upp_tmp[$
                    (*(*(*info).intparams).wheredisprefdiag)[$
                    (*(*info).intparams).ndisp_refdiagnostics-1]] 
  xrange = [(*(*info).dataparams).reflps[lp_low_overall], $
            (*(*info).dataparams).reflps[lp_upp_overall]]
  correct_axes = (FLOOR(ALOG10(ABS(t_upp_y))) GE 3)
  IF ((t_low_y NE 0.) AND ~KEYWORD_SET(correct_axes)) THEN $
    correct_axes = (FLOOR(ALOG10(ABS(t_low_y))) LE -2) 
  IF correct_axes THEN BEGIN
 	  order_corr = FLOOR(ALOG10(ABS(t_upp_y)))
 	  IF ~KEYWORD_SET(NO_AXES) THEN ytitle += ' (x10!U'+STRTRIM(order_corr,2)+'!N)'
    t_low_y /= (10.^(order_corr))
    t_upp_y /= (10.^(order_corr))
  ENDIF 
  topxtitle = title
  IF (*(*info).plotswitch).v_dop_set_ref THEN topxtitle += 'Doppler velocity [km/s]'
  ; Plot basic axes box
  PLOT, (*(*info).dataparams).lps, *(*(*info).dispparams).tarr_ref, $
    YR = [t_low_y,t_upp_y], /YS, XR=xrange, $
    XSTYLE = (*(*info).plotswitch).v_dop_set_ref * 8 + 1, $
  	YTICKLEN = yticklen, YTITLE = ytitle, YTICKNAME = ytickname, $
    XTICKLEN = 1E-9, XTITLE = xtitle, XTICKNAME = REPLICATE(' ',60), $
    POS = [(*(*info).plotpos).refspx0,(*(*info).plotpos).refspy0,$
           (*(*info).plotpos).refspx1,(*(*info).plotpos).refspy1], $
    BACKGROUND=(*(*info).plotparams).bgplotcol, $
    COLOR=(*(*info).plotparams).plotcol, /NODATA, NOERASE=KEYWORD_SET(NO_AXES)
  ; In case of multiple diagnostics and regular replotting of axes
  ; Determine proportional spectral window sizes
  diag_widths = (*(*info).dispparams).lp_ref_upp_tmp[$
                  *(*(*info).intparams).wheredisprefdiag] - $
                (*(*info).dispparams).lp_ref_low_tmp[$
                  *(*(*info).intparams).wheredisprefdiag] ;+ 1
  diag_range = *(*(*info).plotaxes).refdiag_ratio * (*(*info).plotpos).refxplspw 
  IF ~KEYWORD_SET(NO_AXES) THEN BEGIN
    ; Plot xtitle(s)
    IF ((*(*info).intparams).ndisp_refdiagnostics GT 1) THEN $
      XYOUTS,(*(*info).plotpos).refxplspw/2.+(*(*info).plotpos).refspx0,$
        (*(*info).plotpos).refspy0/5.,(*(*info).plottitles).refspxtitle,ALIGNMENT=0.5,$
        COLOR = (*(*info).plotparams).plotcol,/NORMAL
    ; Loop over all diagnostics for plotting of axes boxes
    FOR d=0,(*(*info).intparams).ndisp_refdiagnostics-1 DO BEGIN
      disp_idx = (WHERE((*(*info).intparams).disp_refdiagnostics EQ 1))[d]
      ; Determine xrange to display
      lp_low_loc = (*(*info).dispparams).lp_ref_low_tmp[disp_idx]+$
        (*(*info).intparams).refdiag_start[disp_idx]
      lp_upp_loc = (*(*info).dispparams).lp_ref_upp_tmp[disp_idx]+$
        (*(*info).intparams).refdiag_start[disp_idx]
      xrange = (*(*info).dataparams).reflps[[lp_low_loc,lp_upp_loc]]
      vdop_xrange = $
        (*(*(*info).plotaxes).v_dop_ref[disp_idx])[[$
        (*(*info).dispparams).lp_ref_low_tmp[disp_idx], $
        (*(*info).dispparams).lp_ref_upp_tmp[disp_idx]]]
      IF (d EQ 0) THEN offset = 0 ELSE offset = TOTAL(diag_range[0:(d-1)])
      ; Determine lower left corner position of plot
      refspx0 = (*(*info).plotpos).refspx0 + offset
      refspx1 = diag_range[d] + refspx0
      PLOT, (*(*info).dataparams).lps, *(*(*info).dispparams).tarr_ref, $
        /NODATA, YR=[t_low_y,t_upp_y], /YS, $
  			XRANGE=xrange, XSTYLE = (*(*info).plotswitch).v_dop_set_ref * 8 + 1, $
        POS = [refspx0,(*(*info).plotpos).refspy0,$
               refspx1,(*(*info).plotpos).refspy1], $
        YTICKLEN=(*(*info).plotaxes).refspyticklen, $
        XTICKLEN=xticklen, YTICKNAME=REPLICATE(' ',60), XTICKNAME=xtickname, $
        XTICKINTERVAL=(*(*(*info).plotaxes).xreftickinterval)[0], $
        BACKGROUND=(*(*info).plotparams).bgplotcol, $
        COLOR=(*(*info).plotparams).plotcol,/NOERASE, XTICK_GET=xtickvals, $
        XMINOR=(0-((*(*info).intparams).ndisp_refdiagnostics GT 1))
      ; In case of multiple diagnostics
      IF ((*(*info).intparams).ndisp_refdiagnostics GT 1) THEN BEGIN
        ; Redraw x-axis with custom labelling
        IF (*(*info).plotswitch).xreftick_reset THEN BEGIN
          (*(*info).plotaxes).xreftickvals[d] = $
            PTR_NEW(CRISPEX_PLOTAXES_XTICKVALS_SELECT(xtickvals, $
            TICKSEP=(*(*(*info).plotaxes).xreftickinterval)[1]))
          IF (d EQ ((*(*info).intparams).ndisp_refdiagnostics-1)) THEN $
            (*(*info).plotswitch).xreftick_reset = 0
        ENDIF
        wherenonempty = WHERE(*(*(*info).plotaxes).xreftickvals[d] NE ' ', count)
        IF (count GT 0) THEN BEGIN
          FOR k=0,N_ELEMENTS(wherenonempty)-1 DO BEGIN
            PLOTS,[1.,1.]*FLOAT((*(*(*info).plotaxes).xreftickvals[d])[wherenonempty[k]]), $
              [t_low_y,xtlen_major_fac*(t_upp_y-t_low_y)*(*(*info).plotaxes).refspxticklen+$
              t_low_y], $
              COLOR=(*(*info).plotparams).plotcol
          ENDFOR
        ENDIF
        AXIS, XAXIS=0, XTICKLEN=xtlen_basic_fac*(*(*info).plotaxes).refspxticklen, $
          XRANGE=xrange, /XS, $
          XTICKNAME=*(*(*info).plotaxes).xreftickvals[d], XMINOR=-1, $
          COLOR=(*(*info).plotparams).plotcol, $
          XTICKINTERVAL=(*(*(*info).plotaxes).xreftickinterval)[0]
      ENDIF
      ; Display Doppler top axis if Doppler set, else regular top axis
  		IF ((*(*info).plotswitch).v_dop_set_ref EQ 1) THEN BEGIN
        IF (d EQ 0) THEN $
          XYOUTS,((*(*info).plotpos).refspx1-(*(*info).plotpos).refspx0)/2.+$
            (*(*info).plotpos).refspx0,$
            (*(*info).plotpos).refspy0/5.*3+(*(*info).plotpos).refspy1, topxtitle, $
            ALIGNMENT=0.5, COLOR = (*(*info).plotparams).plotcol,/NORMAL
        topxtitle = ''
        ;Draw top axis
        IF ((*(*info).intparams).ndisp_refdiagnostics GT 1) THEN BEGIN
          ; Plot the initial tick marks and get the tick vals
          AXIS, XAXIS=1, XRANGE=vdop_xrange, $
            XSTYLE=1, XTITLE = topxtitle, COLOR = (*(*info).plotparams).plotcol,$
            XTICKINTERVAL=(*(*(*info).plotaxes).xrefdoptickinterval)[0], $
            XTICKNAME=REPLICATE(' ',60), $
            XTICK_GET=xdoptickvals, XTICKLEN=1E-9
          ; Redraw x-axis with custom labelling
          IF (*(*info).plotswitch).xrefdoptick_reset THEN BEGIN
            (*(*info).plotaxes).xrefdoptickvals[d] = $
              PTR_NEW(CRISPEX_PLOTAXES_XTICKVALS_SELECT(xdoptickvals, $
              TICKSEP=(*(*(*info).plotaxes).xrefdoptickinterval)[1],$
              /DOPPLER))
            wherenonempty = WHERE(*(*(*info).plotaxes).xrefdoptickvals[d] NE ' ')
            ; Determine Doppler tick mark locations
            (*(*info).plotaxes).xrefdoptickloc[d] = $
              PTR_NEW(CRISPEX_PLOTAXES_XDOPTICKLOC(xdoptickvals, wherenonempty, $
              vdop_xrange, xrange))
            IF (d EQ ((*(*info).intparams).ndisp_refdiagnostics-1)) THEN $
              (*(*info).plotswitch).xrefdoptick_reset = 0
          ENDIF
          FOR k=0,N_ELEMENTS(*(*(*info).plotaxes).xrefdoptickloc[d])-1 DO BEGIN
            PLOTS,[1.,1.]*(*(*(*info).plotaxes).xrefdoptickloc[d])[k], $
              [t_upp_y,-xtlen_major_fac*(*(*info).plotaxes).refspxticklen*(t_upp_y-t_low_y)+$
              t_upp_y], $
              COLOR=(*(*info).plotparams).plotcol
          ENDFOR
          ; Add the labels
          AXIS, XAXIS=1, XRANGE=vdop_xrange, /XS, $
            XTICKNAME=*(*(*info).plotaxes).xrefdoptickvals[d], $
            COLOR=(*(*info).plotparams).plotcol, $
            XTICKLEN=xtlen_basic_fac*(*(*info).plotaxes).refspxticklen, $
            XTICKINTERVAL=(*(*(*info).plotaxes).xrefdoptickinterval)[0], XMINOR=-1
        ENDIF ELSE $
          ; Else plot Doppler axis with automatic tick mark settings
        	AXIS, XAXIS=1, XTICKLEN=(*(*info).plotaxes).refspxticklen, XRANGE=vdop_xrange, $
            XSTYLE=1, XTITLE=topxtitle, COLOR = (*(*info).plotparams).plotcol
      ENDIF ELSE $
  			AXIS, XAXIS=1, XTICKLEN = (*(*info).plotaxes).refspxticklen, XRANGE = xrange, XSTYLE=1, $
          XTITLE = topxtitle, COLOR = (*(*info).plotparams).plotcol, $
          XTICKNAME=REPLICATE(' ',60)
    ENDFOR
  ENDIF
	IF (((*(*info).feedbparams).verbosity)[3] EQ 1) THEN $
    CRISPEX_VERBOSE_GET, event, [(*(*info).winids).refspwid], labels=['Window ID for replot']
END

PRO CRISPEX_DISPLAYS_REFSP_RESIZE, event
; Reference temporal spectrum window resize handler, gets new window dimensions and calls (re)display routines
	WIDGET_CONTROL, event.TOP, GET_UVALUE = info
	IF (TOTAL(((*(*info).feedbparams).verbosity)[2:3]) GE 1) THEN $
    CRISPEX_VERBOSE_GET_ROUTINE, event
	CRISPEX_DISPLAYS_PLOT_RESIZE, event, event.X, event.Y, (*(*info).winsizes).refspxres, (*(*info).winsizes).refspyres, (*(*info).plotpos).refspxmargin_init, (*(*info).plotpos).refspxwall_init, $
		refspxres, refspyres, refspwidth, refspheight, refspx0, refspx1, refspy0, refspy1, $
  (*(*info).plotswitch).v_dop_set_ref, ERROR=error, /SLICE
	IF error THEN CRISPEX_DISPLAYS_RESIZE_ERROR, event ELSE BEGIN
		(*(*info).winsizes).refspxres = refspxres		& 	(*(*info).winsizes).refspyres = refspyres
		(*(*info).plotpos).refspx0 = refspx0			&	(*(*info).plotpos).refspx1 = refspx1
		(*(*info).plotpos).refspy0 = refspy0			&	(*(*info).plotpos).refspy1 = refspy1
		(*(*info).plotpos).refxplspw = refspx1 - refspx0	&	(*(*info).plotpos).refyplspw = refspy1 - refspy0
		(*(*info).plotaxes).refspxticklen = -1 * (*(*info).plotaxes).ticklen / refspheight
		(*(*info).plotaxes).refspyticklen = -1 * (*(*info).plotaxes).ticklen / refspwidth
		(*(*info).dispparams).refnlpreb = (*(*info).plotpos).refxplspw * (*(*info).winsizes).refspxres 
		(*(*info).dispparams).refntreb = (*(*info).plotpos).refyplspw * (*(*info).winsizes).refspyres 
	ENDELSE
	IF (((*(*info).feedbparams).verbosity)[3] EQ 1) THEN $
    CRISPEX_VERBOSE_GET, event, [error, (*(*info).winsizes).refspxres,(*(*info).winsizes).refspyres,(*(*info).plotpos).refspx0,(*(*info).plotpos).refspx1,$
		(*(*info).plotpos).refspy0,(*(*info).plotpos).refspy1], labels=['error','refspxres','refspyres','refspx0','refspx1','refspy0','refspy1']
	WIDGET_CONTROL, (*(*info).winids).refspdrawid, DRAW_XSIZE = (*(*info).winsizes).refspxres, DRAW_YSIZE = (*(*info).winsizes).refspyres
	WIDGET_CONTROL, event.TOP, SET_UVALUE = info
	CRISPEX_DISPLAYS_REFSP_REPLOT_AXES, event
  *(*(*info).data).refspslice_congrid = CONGRID( *(*(*info).data).refspslice, $
    (*(*info).dispparams).refnlpreb, (*(*info).dispparams).refntreb, $
    INTERP=(*(*info).dispparams).interpspslice, /CENTER)
  CRISPEX_DRAW_SPECTRAL_REF, event, /SP_ONLY
END

PRO CRISPEX_DISPLAYS_REFSP_TOGGLE, event, DISP=disp, KILL=kill, NO_DRAW=no_draw, $
  NO_FEEDBPARAMS=no_feedbparams
; Reference temporal spectrum display window creation procedure
	WIDGET_CONTROL, event.TOP, GET_UVALUE = info
	IF (TOTAL(((*(*info).feedbparams).verbosity)[2:3]) GE 1) THEN $
    CRISPEX_VERBOSE_GET_ROUTINE, event, /IGNORE_LAST
  IF (KEYWORD_SET(DISP) OR KEYWORD_SET(KILL)) THEN BEGIN
    (*(*info).winswitch).showrefsp = KEYWORD_SET(DISP)
  ENDIF ELSE $
  	(*(*info).winswitch).showrefsp = event.SELECT
  ; If window doesn't exist, create it
	IF (*(*info).winswitch).showrefsp THEN BEGIN
		title = 'CRISPEX'+(*(*info).sesparams).instance_label+': '+$
      ((*(*info).plottitles).refspwintitle)[(*(*info).plotswitch).refheightset]
    ; Create window
		CRISPEX_WINDOW, (*(*info).winsizes).refspxres, (*(*info).winsizes).refspyres, $
      (*(*info).winids).root, title, refsptlb, refspwid, $
      (*(*info).winsizes).refspxoffset, (*(*info).winsizes).refspyoffset, $
      DRAWID=refspdrawid, RESIZING=1, RES_HANDLER='CRISPEX_DISPLAYS_REFSP_RESIZE'
    ; Save window variables
		(*(*info).winids).refsptlb = refsptlb		
    (*(*info).winids).refspwid = refspwid	
		(*(*info).winids).refspdrawid = refspdrawid	
    (*(*info).winids).refspwintitle = title 
		WIDGET_CONTROL, (*(*info).winids).refsptlb, SET_UVALUE = info
    ; Fill window
    CRISPEX_DISPLAYS_REFSP_REPLOT_AXES, event
    CRISPEX_UPDATE_REFSPSLICE, event
		IF ~KEYWORD_SET(NO_DRAW) THEN CRISPEX_DRAW_SPECTRAL_REF, event, /SP_ONLY
  ; If window exists, destroy it
	ENDIF ELSE BEGIN
		WIDGET_CONTROL, (*(*info).winids).refsptlb, /DESTROY
		(*(*info).winids).refsptlb = 0
	ENDELSE
  IF ~KEYWORD_SET(NO_FEEDBPARAMS) THEN $
    CRISPEX_DRAW_FEEDBPARAMS, event, UPDATE_REFDATAVALS=($
      ((*(*info).winswitch).showrefls EQ 0) AND $
      ((*(*info).winswitch).showref EQ 0))
	IF (((*(*info).feedbparams).verbosity)[3] EQ 1) THEN $
    CRISPEX_VERBOSE_GET, event, [(*(*info).winids).refsptlb,$
      (*(*info).winids).refspwid,(*(*info).winids).refspdrawid], $
      labels=['refsptlb','refspwid','refspdrawid']
END

PRO CRISPEX_DISPLAYS_SJI_TOGGLE, event, DISP=disp, KILL=kill, $
  IDX_SJI=idx_sji, NO_DRAW=no_draw
; Reference image window creation procedure
	WIDGET_CONTROL, event.TOP, GET_UVALUE = info
	IF (TOTAL(((*(*info).feedbparams).verbosity)[2:3]) GE 1) THEN $
    CRISPEX_VERBOSE_GET_ROUTINE, event, /IGNORE_LAST
  IF (KEYWORD_SET(DISP) OR KEYWORD_SET(KILL)) THEN BEGIN
    (*(*info).winswitch).showsji[idx_sji] = KEYWORD_SET(DISP)
  ENDIF ELSE $
  	(*(*info).winswitch).showsji[idx_sji] = event.SELECT
  *(*(*info).winswitch).whereshowsji = $
    WHERE((*(*info).winswitch).showsji EQ 1, nwhereshowsji)
  (*(*info).winswitch).nwhereshowsji = nwhereshowsji
	IF (*(*info).winswitch).showsji[idx_sji] THEN BEGIN
		title = 'CRISPEX'+(*(*info).sesparams).instance_label+': Slit-jaw image '+$
      STRJOIN((*(*info).dataparams).sji_labels[*,idx_sji],' ')
		CRISPEX_WINDOW, (*(*info).winsizes).sjiwinx[idx_sji], $
      (*(*info).winsizes).sjiwiny[idx_sji], $
      (*(*info).winids).root, title, sjitlb, sjiwid, $
      (*(*info).winsizes).sjixoffset[idx_sji],$
      (*(*info).winsizes).sjiyoffset[idx_sji],$
      DRAWID = sjidrawid, DRAWBASE = sjidrawbase, $
      /SCROLL, XSCROLL=xscroll, YSCROLL=yscroll, /SJI, /CTBAR_SHOW, $
      CTBAR_DRAWID=ctbar_drawid
    (*(*info).ctrlssji).xsjipos_slider[idx_sji] = xscroll
    (*(*info).ctrlssji).ysjipos_slider[idx_sji] = yscroll
    WIDGET_CONTROL, (*(*info).ctrlssji).xsjipos_slider[idx_sji], $
      SET_VALUE=(*(*info).zooming).xsjipos[idx_sji], $
      SENSITIVE=((*(*info).dataparams).d_sjinx[idx_sji] NE $
      (*(*info).dataparams).sjinx[idx_sji]-1)
    WIDGET_CONTROL, (*(*info).ctrlssji).ysjipos_slider[idx_sji], $
      SET_VALUE=(*(*info).zooming).ysjipos[idx_sji], $
      SENSITIVE=((*(*info).dataparams).d_sjiny[idx_sji] NE $
      (*(*info).dataparams).sjiny[idx_sji]-1)
		(*(*info).winids).sjitlb[idx_sji] = sjitlb		
    (*(*info).winids).sjiwid[idx_sji] = sjiwid	
    (*(*info).winids).sjidrawid[idx_sji] = sjidrawid
		(*(*info).winids).sjidrawbase[idx_sji] = sjidrawbase	
    (*(*info).winids).sjiwintitle[idx_sji] = title
		WIDGET_CONTROL, sjidrawid, EVENT_PRO = 'CRISPEX_CURSOR', /SENSITIVE, $
      /DRAW_MOTION_EVENTS, /TRACKING_EVENTS,/DRAW_BUTTON_EVENTS
    WIDGET_CONTROL, ctbar_drawid, GET_VALUE=sjidrawid_ctbar
    *(*(*info).winids).sjidrawid_ctbar[idx_sji] = [sjidrawid_ctbar, ctbar_drawid]
    WIDGET_CONTROL, sjitlb, SET_UVALUE=info
    IF (*(*info).overlayswitch).loopslit THEN BEGIN
      IF ((*(*info).dataswitch).wcs_set AND $
        (*(*info).dataswitch).sji_wcs_set[idx_sji]) THEN BEGIN
        xyp = CRISPEX_TRANSFORM_GET_WCS($
          *(*(*info).loopparams).xp, *(*(*info).loopparams).yp, $
          (*(*info).dataparams).wcs_main, *(*(*info).dataparams).wcs_sji[idx_sji], $
          /PIXEL, /COORD)
      ENDIF ELSE BEGIN
        xyp = CRISPEX_TRANSFORM_COORDS($
          *(*(*info).loopparams).xp, *(*(*info).loopparams).yp, $
          (*(*info).dataparams).dx, (*(*info).dataparams).sjidx[idx_sji], $
          (*(*info).dataparams).dy, (*(*info).dataparams).sjidy[idx_sji], $
          (*(*info).dataparams).xval, (*(*info).dataparams).xval_sji[idx_sji], $
          (*(*info).dataparams).yval, (*(*info).dataparams).yval_sji[idx_sji], $
          (*(*info).dataparams).xpix, (*(*info).dataparams).xpix_sji[idx_sji], $
          (*(*info).dataparams).ypix, (*(*info).dataparams).ypix_sji[idx_sji])
      ENDELSE
      *(*(*info).loopparams).xp_sji[idx_sji] = xyp.x
      *(*(*info).loopparams).yp_sji[idx_sji] = xyp.y
      CRISPEX_LOOP_GET_PATH, event, /SJI, /ADD_REMOVE
      CRISPEX_DISPLAYS_SJILOOPSLAB, event, NO_DRAW=no_draw, IDX_SJI=idx_sji
    ENDIF
		IF ~KEYWORD_SET(NO_DRAW) THEN BEGIN
			CRISPEX_UPDATE_T, event
      CRISPEX_DRAW_CTBAR, event, /SJI
			CRISPEX_DRAW_SJI, event
		ENDIF
	ENDIF ELSE IF ((*(*info).winids).sjitlb[idx_sji] NE 0) THEN BEGIN
		WIDGET_CONTROL, (*(*info).winids).sjitlb[idx_sji], /DESTROY
		(*(*info).winids).sjitlb[idx_sji] = 0
  ENDIF
  CRISPEX_DRAW_FEEDBPARAMS, event, /UPDATE_SJI
	IF (((*(*info).feedbparams).verbosity)[3] EQ 1) THEN $
    CRISPEX_VERBOSE_GET, event, [(*(*info).winids).sjitlb[idx_sji],$
      (*(*info).winids).sjiwid[idx_sji], (*(*info).winids).sjidrawid[idx_sji]], $
      labels=['sjitlb','sjiwid','sjidrawid']
END

PRO CRISPEX_DISPLAYS_SP_REPLOT_AXES, event, NO_AXES=no_axes
; Updates temporal spectrum display window plot axes range according to set parameters
	WIDGET_CONTROL, event.TOP, GET_UVALUE = info
	IF (TOTAL(((*(*info).feedbparams).verbosity)[2:3]) GE 1) THEN $
    CRISPEX_VERBOSE_GET_ROUTINE, event
	WSET, (*(*info).winids).spwid   
  IF ((*(*info).dispswitch).scalestokes[0] AND $
      ((*(*info).dataparams).s NE 0)) THEN $
    extratitle = '/I' $
  ELSE $
    extratitle = ''
	IF (*(*info).plotswitch).v_dop_set THEN extratitle += '!C' ELSE extratitle += ''
	IF (*(*info).plotswitch).multichannel THEN $
    title = 'Stokes '+((*(*info).stokesparams).labels)[$
      (*(*info).dataparams).s]+extratitle $
  ELSE $
    title = ''
  ; Set axes parameters depending on # of diagnostics
  IF ((*(*info).intparams).ndisp_diagnostics GT 1) THEN BEGIN
    xticklen = 1E-9   & xtitle = ''
    xtickname = REPLICATE(' ',60)
    xtlen_basic_fac = 0.5
    xtlen_major_fac = 0.8
    IF KEYWORD_SET(NO_AXES) THEN BEGIN
      yticklen = 1E-9 & ytitle = ''
      ytickname = REPLICATE(' ',60)
    ENDIF ELSE BEGIN
      yticklen = (*(*info).plotaxes).spyticklen
      ytitle = (*(*info).plottitles).spytitle
      ytickname = ''
    ENDELSE
  ENDIF ELSE BEGIN
    xticklen = (*(*info).plotaxes).spxticklen
    xtitle = (*(*info).plottitles).spxtitle
    yticklen = (*(*info).plotaxes).spyticklen
    ytitle = (*(*info).plottitles).spytitle
    xtlen_basic_fac = 1.
    xtickname = ''  & ytickname = ''
  ENDELSE
  xticklen = xtlen_basic_fac * (*(*info).plotaxes).spxticklen
  t_low_y = (*(*info).dispparams).t_low_main
  t_upp_y = (*(*info).dispparams).t_upp_main
  lp_low_overall = (*(*info).dispparams).lp_low_tmp[$
                    (*(*(*info).intparams).wheredispdiag)[0]] 
  lp_upp_overall = (*(*info).dispparams).lp_upp_tmp[$
                    (*(*(*info).intparams).wheredispdiag)[$
                    (*(*info).intparams).ndisp_diagnostics-1]] 
  xrange = [(*(*info).dataparams).lps[lp_low_overall], $
            (*(*info).dataparams).lps[lp_upp_overall]]
  correct_axes = (FLOOR(ALOG10(ABS(t_upp_y))) GE 3)
  IF ((t_low_y NE 0.) AND ~KEYWORD_SET(correct_axes)) THEN $
    correct_axes = (FLOOR(ALOG10(ABS(t_low_y))) LE -2) 
  IF correct_axes THEN BEGIN
 	  order_corr = FLOOR(ALOG10(ABS(t_upp_y)))
 	  IF ~KEYWORD_SET(NO_AXES) THEN ytitle += ' (x10!U'+STRTRIM(order_corr,2)+'!N)'
    t_low_y /= (10.^(order_corr))
    t_upp_y /= (10.^(order_corr))
  ENDIF 
  topxtitle = title
  IF (*(*info).plotswitch).v_dop_set THEN topxtitle += 'Doppler velocity [km/s]'
  ; Plot basic axes box
  PLOT, (*(*info).dataparams).lps, *(*(*info).dispparams).tarr_main, $
    YR = [t_low_y,t_upp_y], /YS, XR=xrange, $
    XSTYLE = (*(*info).plotswitch).v_dop_set * 8 + 1, $
  	YTICKLEN = yticklen, YTITLE = ytitle, YTICKNAME = ytickname, $
    XTICKLEN = 1E-9, XTITLE = xtitle, XTICKNAME = REPLICATE(' ',60), $
    POS = [(*(*info).plotpos).spx0,(*(*info).plotpos).spy0,$
           (*(*info).plotpos).spx1,(*(*info).plotpos).spy1], $
    BACKGROUND=(*(*info).plotparams).bgplotcol, COLOR=(*(*info).plotparams).plotcol, $
    /NODATA, NOERASE=KEYWORD_SET(NO_AXES)
  ; In case of multiple diagnostics and regular replotting of axes
  IF ~KEYWORD_SET(NO_AXES) THEN BEGIN
    ; Determine proportional spectral window sizes
    diag_widths = (*(*info).dispparams).lp_upp_tmp[$
                    *(*(*info).intparams).wheredispdiag] - $
                  (*(*info).dispparams).lp_low_tmp[$
                    *(*(*info).intparams).wheredispdiag] ;+ 1
    diag_range = *(*(*info).plotaxes).diag_ratio * (*(*info).plotpos).xplspw 
    ; Plot xtitle(s)
    IF ((*(*info).intparams).ndisp_diagnostics GT 1) THEN $
      XYOUTS,(*(*info).plotpos).xplspw/2.+(*(*info).plotpos).spx0,$
        (*(*info).plotpos).spy0/5.,(*(*info).plottitles).spxtitle,ALIGNMENT=0.5, $
        COLOR = (*(*info).plotparams).plotcol,/NORMAL
    ; Loop over all diagnostics for plotting of axes boxes
    FOR d=0,(*(*info).intparams).ndisp_diagnostics-1 DO BEGIN
      disp_idx = (WHERE((*(*info).intparams).disp_diagnostics EQ 1))[d]
      ; Determine xrange to display
      lp_low_loc = (*(*info).dispparams).lp_low_tmp[disp_idx]+$
        (*(*info).intparams).diag_start[disp_idx]
      lp_upp_loc = (*(*info).dispparams).lp_upp_tmp[disp_idx]+$
        (*(*info).intparams).diag_start[disp_idx]
      xrange = (*(*info).dataparams).lps[[lp_low_loc,lp_upp_loc]]
      vdop_xrange = $
        (*(*(*info).plotaxes).v_dop[disp_idx])[[$
        (*(*info).dispparams).lp_low_tmp[disp_idx], $
        (*(*info).dispparams).lp_upp_tmp[disp_idx]]]
      IF (d EQ 0) THEN offset = 0 ELSE offset = TOTAL(diag_range[0:(d-1)])
      ; Determine lower left corner position of plot
      spx0 = (*(*info).plotpos).spx0 + offset
      spx1 = diag_range[d] + spx0
  		PLOT, (*(*info).dataparams).lps, *(*(*info).dispparams).tarr_main, $
        /NODATA, YR=[t_low_y,t_upp_y], $
  			/YS, XRANGE=xrange, XSTYLE = (*(*info).plotswitch).v_dop_set * 8 + 1, $
        POS=[spx0,(*(*info).plotpos).spy0,spx1,(*(*info).plotpos).spy1], $
        YTICKLEN=(*(*info).plotaxes).spyticklen, $
        XTICKLEN=xticklen, YTICKNAME=REPLICATE(' ',60), XTICKNAME=xtickname, $
        XTICKINTERVAL=(*(*(*info).plotaxes).xtickinterval)[0], $
        BACKGROUND=(*(*info).plotparams).bgplotcol, $
        COLOR=(*(*info).plotparams).plotcol,/NOERASE, XTICK_GET=xtickvals, $
        XMINOR=(0-((*(*info).intparams).ndisp_diagnostics GT 1))
      ; In case of multiple diagnostics
      IF ((*(*info).intparams).ndisp_diagnostics GT 1) THEN BEGIN
        ; Redraw x-axis with custom labelling
        IF (*(*info).plotswitch).xtick_reset THEN BEGIN
          (*(*info).plotaxes).xtickvals[d] = $
            PTR_NEW(CRISPEX_PLOTAXES_XTICKVALS_SELECT(xtickvals, $
            TICKSEP=(*(*(*info).plotaxes).xtickinterval)[1]))
          IF (d EQ ((*(*info).intparams).ndisp_diagnostics-1)) THEN $
            (*(*info).plotswitch).xtick_reset = 0
        ENDIF
        wherenonempty = WHERE(*(*(*info).plotaxes).xtickvals[d] NE ' ', count)
        IF (count GT 0) THEN BEGIN
          FOR k=0,N_ELEMENTS(wherenonempty)-1 DO BEGIN
            PLOTS,[1.,1.]*FLOAT((*(*(*info).plotaxes).xtickvals[d])[wherenonempty[k]]), $
              [t_low_y,xtlen_major_fac*(t_upp_y-t_low_y)*(*(*info).plotaxes).spxticklen+$
              t_low_y], $
              COLOR=(*(*info).plotparams).plotcol
          ENDFOR
        ENDIF
        AXIS, XAXIS=0, XTICKLEN=xtlen_basic_fac*(*(*info).plotaxes).spxticklen, $
          XRANGE=xrange, /XS, $
          XTICKNAME=*(*(*info).plotaxes).xtickvals[d], XMINOR=-1, $
          COLOR=(*(*info).plotparams).plotcol, $
          XTICKINTERVAL=(*(*(*info).plotaxes).xtickinterval)[0]
      ENDIF
      ; Display Doppler top axis if Doppler set, else regular top axis
  		IF ((*(*info).plotswitch).v_dop_set EQ 1) THEN BEGIN
        IF (d EQ 0) THEN $
          XYOUTS,((*(*info).plotpos).spx1-(*(*info).plotpos).spx0)/2.+$
            (*(*info).plotpos).spx0,$
            (*(*info).plotpos).spy0/5.*3+(*(*info).plotpos).spy1, topxtitle, $
            ALIGNMENT=0.5, COLOR = (*(*info).plotparams).plotcol,/NORMAL
        topxtitle = ''
        ;Draw top axis
        IF ((*(*info).intparams).ndisp_diagnostics GT 1) THEN BEGIN
          ; Plot the initial tick marks and get the tick vals
          AXIS, XAXIS=1, XRANGE=vdop_xrange, $
            XSTYLE=1, XTITLE=topxtitle, COLOR=(*(*info).plotparams).plotcol,$
            XTICKINTERVAL=(*(*(*info).plotaxes).xdoptickinterval)[0], $
            XTICKNAME=REPLICATE(' ',60), XTICK_GET=xdoptickvals, XTICKLEN=1E-9
          ; Redraw x-axis with custom labelling
          IF (*(*info).plotswitch).xdoptick_reset THEN BEGIN
            (*(*info).plotaxes).xdoptickvals[d] = $
              PTR_NEW(CRISPEX_PLOTAXES_XTICKVALS_SELECT(xdoptickvals, $
              TICKSEP=(*(*(*info).plotaxes).xdoptickinterval)[1],$
              /DOPPLER))
            wherenonempty = WHERE(*(*(*info).plotaxes).xdoptickvals[d] NE ' ')
            ; Determine Doppler tick mark locations
            (*(*info).plotaxes).xdoptickloc[d] = $
              PTR_NEW(CRISPEX_PLOTAXES_XDOPTICKLOC(xdoptickvals, wherenonempty, $
              vdop_xrange, xrange))
            IF (d EQ ((*(*info).intparams).ndisp_diagnostics-1)) THEN $
              (*(*info).plotswitch).xdoptick_reset = 0
          ENDIF
          FOR k=0,N_ELEMENTS(*(*(*info).plotaxes).xdoptickloc[d])-1 DO BEGIN
            PLOTS,[1.,1.]*(*(*(*info).plotaxes).xdoptickloc[d])[k], $
              [t_upp_y,-xtlen_major_fac*(*(*info).plotaxes).spxticklen*(t_upp_y-t_low_y)+$
              t_upp_y], COLOR=(*(*info).plotparams).plotcol
          ENDFOR
          ; Add the labels
          AXIS, XAXIS=1, XRANGE=vdop_xrange, /XS, $
            XTICKNAME=*(*(*info).plotaxes).xdoptickvals[d], $
            COLOR=(*(*info).plotparams).plotcol, $
            XTICKLEN=xtlen_basic_fac*(*(*info).plotaxes).spxticklen, $
            XTICKINTERVAL=(*(*(*info).plotaxes).xdoptickinterval)[0], XMINOR=-1
        ENDIF ELSE $
          ; Else plot Doppler axis with automatic tick mark settings
        	AXIS, XAXIS=1, XTICKLEN=(*(*info).plotaxes).spxticklen, XRANGE=vdop_xrange, $
            XSTYLE=1, XTITLE=topxtitle, COLOR = (*(*info).plotparams).plotcol
      ENDIF ELSE $
  			AXIS, XAXIS=1, XTICKLEN=(*(*info).plotaxes).spxticklen, XRANGE=xrange, XSTYLE=1, $
          XTITLE=topxtitle, COLOR=(*(*info).plotparams).plotcol, $
          XTICKNAME=REPLICATE(' ',60)
    ENDFOR
  ENDIF
	IF (((*(*info).feedbparams).verbosity)[3] EQ 1) THEN $
    CRISPEX_VERBOSE_GET, event, [(*(*info).winids).spwid], labels=['Window ID for replot']
END

PRO CRISPEX_DISPLAYS_SP_RESIZE, event
; Temporal spectrum window resize handler, gets new window dimensions and calls (re)display routines
	WIDGET_CONTROL, event.TOP, GET_UVALUE = info
	IF (TOTAL(((*(*info).feedbparams).verbosity)[2:3]) GE 1) THEN $
    CRISPEX_VERBOSE_GET_ROUTINE, event
	CRISPEX_DISPLAYS_PLOT_RESIZE, event, event.X, event.Y, (*(*info).winsizes).spxres, (*(*info).winsizes).spyres, (*(*info).plotpos).spxmargin_init, (*(*info).plotpos).spxwall_init, $
		spxres, spyres, spwidth, spheight, spx0, spx1, spy0, spy1, (*(*info).plotswitch).v_dop_set, $
  ERROR=error, /SLICE
	IF error THEN CRISPEX_DISPLAYS_RESIZE_ERROR, event ELSE BEGIN
		(*(*info).winsizes).spxres = spxres		& 	(*(*info).winsizes).spyres = spyres
		(*(*info).plotpos).spx0 = spx0			&	(*(*info).plotpos).spx1 = spx1
		(*(*info).plotpos).spy0 = spy0			&	(*(*info).plotpos).spy1 = spy1
		(*(*info).plotpos).xplspw = spx1 - spx0		&	(*(*info).plotpos).yplspw = spy1 - spy0
		(*(*info).plotaxes).spxticklen = -1 * (*(*info).plotaxes).ticklen / spheight
		(*(*info).plotaxes).spyticklen = -1 * (*(*info).plotaxes).ticklen / spwidth
		(*(*info).dispparams).nlpreb = (*(*info).plotpos).xplspw * (*(*info).winsizes).spxres 
		(*(*info).dispparams).ntreb = (*(*info).plotpos).yplspw * (*(*info).winsizes).spyres 
	ENDELSE
	IF (((*(*info).feedbparams).verbosity)[3] EQ 1) THEN $
    CRISPEX_VERBOSE_GET, event, [error,(*(*info).winsizes).spxres,(*(*info).winsizes).spyres,(*(*info).plotpos).spx0,(*(*info).plotpos).spx1,$
		(*(*info).plotpos).spy0,(*(*info).plotpos).spy1], labels=['error','spxres','spyres','spx0','spx1','spy0','spy1']
	WIDGET_CONTROL, (*(*info).winids).spdrawid, DRAW_XSIZE = (*(*info).winsizes).spxres, DRAW_YSIZE = (*(*info).winsizes).spyres
	WIDGET_CONTROL, event.TOP, SET_UVALUE = info
  CRISPEX_DRAW_GET_SPECTRAL_AXES, event, /MAIN
	CRISPEX_DISPLAYS_SP_REPLOT_AXES, event
  *(*(*info).data).spslice_congrid = CONGRID( *(*(*info).data).spslice, (*(*info).dispparams).nlpreb, $
    (*(*info).dispparams).ntreb, INTERP = (*(*info).dispparams).interpspslice, /CENTER)
  CRISPEX_DRAW_SPECTRAL_MAIN, event,/SP_ONLY
END

PRO CRISPEX_DISPLAYS_SP_TOGGLE, event, NO_DRAW=no_draw
; Temporal spectrum display window creation procedure
	WIDGET_CONTROL, event.TOP, GET_UVALUE = info
	IF (TOTAL(((*(*info).feedbparams).verbosity)[2:3]) GE 1) THEN $
    CRISPEX_VERBOSE_GET_ROUTINE, event, /IGNORE_LAST
  ; If window doesn't exist, create it
	IF ((*(*info).winswitch).showsp EQ 0) THEN BEGIN
		wintitle = 'CRISPEX'+(*(*info).sesparams).instance_label+': '+$
      ((*(*info).plottitles).spwintitle)[(*(*info).plotswitch).heightset]
    ; Create window
		CRISPEX_WINDOW, (*(*info).winsizes).spxres, (*(*info).winsizes).spyres, $
      (*(*info).winids).root, wintitle, tlb, wid, (*(*info).winsizes).spxoffset, $
      (*(*info).winsizes).spyoffset, DRAWID = spdrawid, RESIZING = 1, $
      RES_HANDLER = 'CRISPEX_DISPLAYS_SP_RESIZE'
    ; Save window variables
		(*(*info).winids).sptlb = tlb		&	(*(*info).winids).spwid = wid	&	(*(*info).winswitch).showsp = 1
		(*(*info).winids).spdrawid = spdrawid	&	(*(*info).winids).spwintitle = wintitle
		WIDGET_CONTROL, (*(*info).winids).sptlb, SET_UVALUE=info
    ; Fill window
    CRISPEX_DISPLAYS_SP_REPLOT_AXES, event
    CRISPEX_UPDATE_SPSLICE, event
		IF ~KEYWORD_SET(NO_DRAW) THEN CRISPEX_DRAW_SPECTRAL_MAIN, event,/SP_ONLY
  ; If window does exist, destroy it
	ENDIF ELSE BEGIN
		WIDGET_CONTROL, (*(*info).winids).sptlb, /DESTROY
		(*(*info).winids).sptlb = 0
		(*(*info).winswitch).showsp = 0
	ENDELSE
	IF (((*(*info).feedbparams).verbosity)[3] EQ 1) THEN $
    CRISPEX_VERBOSE_GET, event, [(*(*info).winids).sptlb,(*(*info).winids).spwid,$
      (*(*info).winids).spdrawid], labels=['sptlb','spwid','spdrawid']
END

PRO CRISPEX_DISPLAYS_STOKES_SELECT_XY_RECOVER_YRANGE, event
; Restores lower/upper y-values of specific Stokes component detailed spectrum
; plot for input
  WIDGET_CONTROL, event.TOP, GET_UVALUE = info
	IF (TOTAL(((*(*info).feedbparams).verbosity)[2:3]) GE 1) THEN $
    CRISPEX_VERBOSE_GET_ROUTINE, event
  IF ((*(*info).stokesparams).mainref_select EQ 0) THEN BEGIN
    ls_low_y = (*(*(*info).plotaxes).ls_low_y)[(*(*info).dataparams).s]
    ls_upp_y = (*(*(*info).plotaxes).ls_upp_y)[(*(*info).dataparams).s]
  ENDIF ELSE BEGIN
    ls_low_y = (*(*(*info).plotaxes).ls_low_y_ref)[(*(*info).dataparams).s_ref]
    ls_upp_y = (*(*(*info).plotaxes).ls_upp_y_ref)[(*(*info).dataparams).s_ref]
  ENDELSE
	WIDGET_CONTROL, (*(*info).ctrlscp).lower_y_text, SET_VALUE=STRTRIM(ls_low_y,2)
	WIDGET_CONTROL, (*(*info).ctrlscp).upper_y_text, SET_VALUE=STRTRIM(ls_upp_y,2)
	IF (((*(*info).feedbparams).verbosity)[3] EQ 1) THEN $
    CRISPEX_VERBOSE_GET, event, [ls_low_y,ls_upp_y], $
      labels=['Lower detspect y-value','Upper detspect y-value']
	IF (((*(*info).stokesparams).mainref_select EQ 0) AND $
       (*(*info).winswitch).showint) THEN BEGIN
		WIDGET_CONTROL, (*(*info).ctrlsint).lower_y_int_text, $
      SET_VALUE=STRTRIM((*(*(*info).plotaxes).int_low_y)[(*(*info).dataparams).s],2)
		WIDGET_CONTROL, (*(*info).ctrlsint).upper_y_int_text, $
      SET_VALUE=STRTRIM((*(*(*info).plotaxes).int_upp_y)[(*(*info).dataparams).s],2)
		IF (((*(*info).feedbparams).verbosity)[3] EQ 1) THEN $
      CRISPEX_VERBOSE_GET, event, $
        [(*(*(*info).plotaxes).int_low_y)[(*(*info).dataparams).s],$
        (*(*(*info).plotaxes).int_upp_y)[(*(*info).dataparams).s]], $
        labels=['Lower int y-value','Upper int y-value']
	ENDIF
END

;========================= DISPLAY RANGE PROCEDURES
PRO CRISPEX_DISPRANGE_INT_LOW, event
; Handles change in lower y-value of intensity versus time display window
	WIDGET_CONTROL, event.TOP, GET_UVALUE = info
	IF (TOTAL(((*(*info).feedbparams).verbosity)[2:3]) GE 1) THEN $
    CRISPEX_VERBOSE_GET_ROUTINE, event
	WIDGET_CONTROL, (*(*info).ctrlsint).lower_y_int_text, GET_VALUE = textvalue
	(*(*(*info).plotaxes).int_low_y)[(*(*info).dataparams).s] = FLOAT(textvalue[0])
	IF ((*(*(*info).plotaxes).int_low_y)[(*(*info).dataparams).s] GE (*(*(*info).plotaxes).int_upp_y)[(*(*info).dataparams).s]) THEN $
		(*(*(*info).plotaxes).int_upp_y)[(*(*info).dataparams).s] = (*(*(*info).plotaxes).int_low_y)[(*(*info).dataparams).s] + 1 
	WIDGET_CONTROL, (*(*info).ctrlsint).upper_y_int_text, SET_VALUE = STRTRIM((*(*(*info).plotaxes).int_upp_y)[(*(*info).dataparams).s],2)
	IF (((*(*info).feedbparams).verbosity)[3] EQ 1) THEN $
    CRISPEX_VERBOSE_GET, event, [(*(*(*info).plotaxes).int_low_y)[(*(*info).dataparams).s],(*(*(*info).plotaxes).int_upp_y)[(*(*info).dataparams).s]], $
		labels=['Lower int y-value','Upper int y-value']
	CRISPEX_DRAW_INT, event
END

PRO CRISPEX_DISPRANGE_INT_UPP, event
; Handles change in upper y-value of intensity versus time display window
	WIDGET_CONTROL, event.TOP, GET_UVALUE = info
	IF (TOTAL(((*(*info).feedbparams).verbosity)[2:3]) GE 1) THEN $
    CRISPEX_VERBOSE_GET_ROUTINE, event
	WIDGET_CONTROL, (*(*info).ctrlsint).upper_y_int_text, GET_VALUE = textvalue
	(*(*(*info).plotaxes).int_upp_y)[(*(*info).dataparams).s] = FLOAT(textvalue[0]) 
	IF ((*(*(*info).plotaxes).int_upp_y)[(*(*info).dataparams).s] LE (*(*(*info).plotaxes).int_low_y)[(*(*info).dataparams).s]) THEN $
		(*(*(*info).plotaxes).int_low_y)[(*(*info).dataparams).s] = (*(*(*info).plotaxes).int_upp_y)[(*(*info).dataparams).s] - 1 
	WIDGET_CONTROL, (*(*info).ctrlsint).lower_y_int_text, SET_VALUE = STRTRIM((*(*(*info).plotaxes).int_low_y)[(*(*info).dataparams).s],2)
	IF (((*(*info).feedbparams).verbosity)[3] EQ 1) THEN $
    CRISPEX_VERBOSE_GET, event, [(*(*(*info).plotaxes).int_low_y)[(*(*info).dataparams).s],(*(*(*info).plotaxes).int_upp_y)[(*(*info).dataparams).s]], $
		labels=['Lower int y-value','Upper int y-value']
	CRISPEX_DRAW_INT, event
END

PRO CRISPEX_DISPRANGE_INT_T_LOW, event
; Handles change in lower t-value of intensity versus time display window
	WIDGET_CONTROL, event.TOP, GET_UVALUE = info
	IF (TOTAL(((*(*info).feedbparams).verbosity)[2:3]) GE 1) THEN $
    CRISPEX_VERBOSE_GET_ROUTINE, event
	WIDGET_CONTROL, (*(*info).ctrlsint).lower_t_int_text, GET_VALUE = textvalue
	(*(*info).plotaxes).int_low_t = FLOAT(textvalue[0])
	IF ((*(*info).plotaxes).int_low_t GE (*(*info).plotaxes).int_upp_t) THEN (*(*info).plotaxes).int_low_t = (*(*info).plotaxes).int_upp_t - 1
	IF ((*(*info).plotaxes).int_low_t LT (*(*info).dispparams).t_first) THEN (*(*info).plotaxes).int_low_t = (*(*info).dispparams).t_first
	WIDGET_CONTROL, (*(*info).ctrlsint).lower_t_int_text, SET_VALUE = STRTRIM((*(*info).plotaxes).int_low_t,2)
	CRISPEX_DISPRANGE_INT_T_RANGE, event
	CRISPEX_DRAW_INT, event
END

PRO CRISPEX_DISPRANGE_INT_T_UPP, event
; Handles change in upper t-value of intensity versus time display window
	WIDGET_CONTROL, event.TOP, GET_UVALUE = info
	IF (TOTAL(((*(*info).feedbparams).verbosity)[2:3]) GE 1) THEN $
    CRISPEX_VERBOSE_GET_ROUTINE, event
	WIDGET_CONTROL, (*(*info).ctrlsint).upper_t_int_text, GET_VALUE = textvalue
	(*(*info).plotaxes).int_upp_t = FLOAT(textvalue[0]) 
	IF ((*(*info).plotaxes).int_upp_t LE (*(*info).plotaxes).int_low_t) THEN (*(*info).plotaxes).int_upp_t = (*(*info).plotaxes).int_low_t + 1
	IF ((*(*info).plotaxes).int_upp_t GT (*(*info).dispparams).t_last) THEN (*(*info).plotaxes).int_upp_t = (*(*info).dispparams).t_last
	WIDGET_CONTROL, (*(*info).ctrlsint).upper_t_int_text, SET_VALUE = STRTRIM((*(*info).plotaxes).int_upp_t,2)
	CRISPEX_DISPRANGE_INT_T_RANGE, event
	CRISPEX_DRAW_INT, event
END

PRO CRISPEX_DISPRANGE_INT_LOCK_T, event
; Locks main temporal range to intensity versus time display temporal range
	WIDGET_CONTROL, event.TOP, GET_UVALUE = info
	IF (TOTAL(((*(*info).feedbparams).verbosity)[2:3]) GE 1) THEN $
    CRISPEX_VERBOSE_GET_ROUTINE, event
	(*(*info).intparams).lock_t = event.SELECT
	IF (((*(*info).feedbparams).verbosity)[3] EQ 1) THEN $
    CRISPEX_VERBOSE_GET, event, [(*(*info).intparams).lock_t], labels=['Lock main to int temporal range']
	CRISPEX_DISPRANGE_INT_T_RANGE, event
END

PRO CRISPEX_DISPRANGE_INT_T_RANGE, event
; Locks main temporal range to intensity versus time display temporal range
	WIDGET_CONTROL, event.TOP, GET_UVALUE = info
	IF (TOTAL(((*(*info).feedbparams).verbosity)[2:3]) GE 1) THEN $
    CRISPEX_VERBOSE_GET_ROUTINE, event
	IF (*(*info).intparams).lock_t THEN BEGIN
		(*(*info).dispparams).t_low = (*(*info).plotaxes).int_low_t
		(*(*info).dispparams).t_upp = (*(*info).plotaxes).int_upp_t
	ENDIF ELSE BEGIN
		(*(*info).dispparams).t_low = (*(*info).dispparams).t_first
		(*(*info).dispparams).t_upp = (*(*info).dispparams).t_last
	ENDELSE
	IF (((*(*info).feedbparams).verbosity)[3] EQ 1) THEN $
    CRISPEX_VERBOSE_GET, event, [(*(*info).plotaxes).int_low_t,(*(*info).plotaxes).int_upp_t,(*(*info).dispparams).t_low,(*(*info).dispparams).t_upp], $
		labels=['Lower int t-value','Upper int t-value','Lower t-value','Upper t-value']
	CRISPEX_DISPRANGE_T_RANGE, event
	WIDGET_CONTROL, (*(*info).ctrlscp).lower_t_text, SET_VALUE = STRTRIM((*(*info).dispparams).t_low,2)
	WIDGET_CONTROL, (*(*info).ctrlscp).upper_t_text, SET_VALUE = STRTRIM((*(*info).dispparams).t_upp,2)
END

PRO CRISPEX_DISPRANGE_INT_T_RESET, event
; Handles reset of temporal boundaries and calls (re)display routine
	WIDGET_CONTROL, event.TOP, GET_UVALUE = info
	IF (TOTAL(((*(*info).feedbparams).verbosity)[2:3]) GE 1) THEN $
    CRISPEX_VERBOSE_GET_ROUTINE, event
	(*(*info).plotaxes).int_upp_t = (*(*info).dispparams).t_last
	(*(*info).plotaxes).int_low_t = (*(*info).dispparams).t_first
	CRISPEX_DISPRANGE_INT_T_RANGE, event
END

PRO CRISPEX_DISPRANGE_LS_LOW, event
; Handles change in lower y-value of detailed spectrum display window
	WIDGET_CONTROL, event.TOP, GET_UVALUE = info
	IF (TOTAL(((*(*info).feedbparams).verbosity)[2:3]) GE 1) THEN $
    CRISPEX_VERBOSE_GET_ROUTINE, event
	WIDGET_CONTROL, (*(*info).ctrlscp).lower_y_text, GET_VALUE = textvalue
	IF (*(*info).ctrlsswitch).imrefdetspect THEN BEGIN
		(*(*(*info).plotaxes).ls_low_y_ref)[(*(*info).dataparams).s_ref] = $
      FLOAT(textvalue[0]) 
		IF ((*(*(*info).plotaxes).ls_low_y_ref)[(*(*info).dataparams).s_ref] GE $
        (*(*(*info).plotaxes).ls_upp_y_ref)[(*(*info).dataparams).s_ref]) THEN $
			(*(*(*info).plotaxes).ls_upp_y_ref)[(*(*info).dataparams).s_ref] = $
        (*(*(*info).plotaxes).ls_low_y_ref)[(*(*info).dataparams).s_ref] + 1 
		WIDGET_CONTROL, (*(*info).ctrlscp).upper_y_text, $
      SET_VALUE=STRTRIM((*(*(*info).plotaxes).ls_upp_y_ref)[$
      (*(*info).dataparams).s_ref],2)
	ENDIF ELSE BEGIN
		(*(*(*info).plotaxes).ls_low_y)[(*(*info).dataparams).s] = FLOAT(textvalue[0]) 
		IF ((*(*(*info).plotaxes).ls_low_y)[(*(*info).dataparams).s] GE $
        (*(*(*info).plotaxes).ls_upp_y)[(*(*info).dataparams).s]) THEN $
			(*(*(*info).plotaxes).ls_upp_y)[(*(*info).dataparams).s] = $
        (*(*(*info).plotaxes).ls_low_y)[(*(*info).dataparams).s] + 1 
		WIDGET_CONTROL, (*(*info).ctrlscp).upper_y_text, $
      SET_VALUE=STRTRIM((*(*(*info).plotaxes).ls_upp_y)[(*(*info).dataparams).s],2)
	ENDELSE
	CRISPEX_DISPRANGE_LS_RANGE, event
END

PRO CRISPEX_DISPRANGE_LS_UPP, event
; Handles change in upper y-value of detailed spectrum display window
	WIDGET_CONTROL, event.TOP, GET_UVALUE = info
	IF (TOTAL(((*(*info).feedbparams).verbosity)[2:3]) GE 1) THEN $
    CRISPEX_VERBOSE_GET_ROUTINE, event
	WIDGET_CONTROL, (*(*info).ctrlscp).upper_y_text, GET_VALUE = textvalue
	IF (*(*info).ctrlsswitch).imrefdetspect THEN BEGIN
		(*(*(*info).plotaxes).ls_upp_y_ref)[(*(*info).dataparams).s_ref] = $
      FLOAT(textvalue[0])
		IF ((*(*(*info).plotaxes).ls_upp_y_ref)[(*(*info).dataparams).s_ref] LE $
        (*(*(*info).plotaxes).ls_low_y_ref)[(*(*info).dataparams).s_ref]) THEN $
			(*(*(*info).plotaxes).ls_low_y_ref)[(*(*info).dataparams).s_ref] = $
        (*(*(*info).plotaxes).ls_upp_y_ref)[(*(*info).dataparams).s_ref] - 1 
		WIDGET_CONTROL, (*(*info).ctrlscp).lower_y_text, $
      SET_VALUE=STRTRIM((*(*(*info).plotaxes).ls_low_y_ref)[$
      (*(*info).dataparams).s_ref],2)
	ENDIF ELSE BEGIN
		(*(*(*info).plotaxes).ls_upp_y)[(*(*info).dataparams).s] = FLOAT(textvalue[0])
		IF ((*(*(*info).plotaxes).ls_upp_y)[(*(*info).dataparams).s] LE $
        (*(*(*info).plotaxes).ls_low_y)[(*(*info).dataparams).s]) THEN $
			(*(*(*info).plotaxes).ls_low_y)[(*(*info).dataparams).s] = $
        (*(*(*info).plotaxes).ls_upp_y)[(*(*info).dataparams).s] - 1 
		WIDGET_CONTROL, (*(*info).ctrlscp).lower_y_text, $
      SET_VALUE=STRTRIM((*(*(*info).plotaxes).ls_low_y)[(*(*info).dataparams).s],2)
	ENDELSE
	CRISPEX_DISPRANGE_LS_RANGE, event
END

PRO CRISPEX_DISPRANGE_LS_RANGE, event, NO_DRAW=no_draw
; Determines range from change in lower or upper y-value of detailed spectrum
; display window and calls (re)display routine
  WIDGET_CONTROL, event.TOP, GET_UVALUE = info
	IF (TOTAL(((*(*info).feedbparams).verbosity)[2:3]) GE 1) THEN $
    CRISPEX_VERBOSE_GET_ROUTINE, event
	IF (*(*info).ctrlsswitch).imrefdetspect THEN $
		(*(*(*info).plotaxes).ls_yrange_ref)[(*(*info).dataparams).s_ref] = $
      (*(*(*info).plotaxes).ls_upp_y_ref)[(*(*info).dataparams).s_ref] - $
      (*(*(*info).plotaxes).ls_low_y_ref)[(*(*info).dataparams).s_ref] $
  ELSE $
		(*(*(*info).plotaxes).ls_yrange)[(*(*info).dataparams).s] = $
      (*(*(*info).plotaxes).ls_upp_y)[(*(*info).dataparams).s] - $
      (*(*(*info).plotaxes).ls_low_y)[(*(*info).dataparams).s] 
	IF (((*(*info).feedbparams).verbosity)[3] EQ 1) THEN $
    CRISPEX_VERBOSE_GET, event, $
      [(*(*(*info).plotaxes).ls_low_y)[(*(*info).dataparams).s],$
       (*(*(*info).plotaxes).ls_upp_y)[(*(*info).dataparams).s],$
       (*(*(*info).plotaxes).ls_low_y_ref)[(*(*info).dataparams).s_ref],$
       (*(*(*info).plotaxes).ls_upp_y_ref)[(*(*info).dataparams).s_ref]],$
       labels=['Lower main y-value','Upper main y-value','Lower ref y-value',$
       'Upper ref y-value']
	IF ~KEYWORD_SET(NO_DRAW) THEN CRISPEX_DRAW, event
END

PRO CRISPEX_DISPRANGE_LS_SCALE_SELECT, event
; Handles the selection of scaling (or not) of the detailed spectrum to the maximum of the average spectrum
	WIDGET_CONTROL, event.TOP, GET_UVALUE=info
	IF (TOTAL(((*(*info).feedbparams).verbosity)[2:3]) GE 1) THEN $
    CRISPEX_VERBOSE_GET_ROUTINE, event
	IF (*(*info).ctrlsswitch).imrefdetspect THEN $
    (*(*info).dispswitch).ref_detspect_scale = event.SELECT $
  ELSE $
    (*(*info).dispswitch).detspect_scale = event.SELECT
	IF (((*(*info).feedbparams).verbosity)[3] EQ 1) THEN $
    CRISPEX_VERBOSE_GET, event, [(*(*info).dispswitch).detspect_scale,$
      (*(*info).dispswitch).ref_detspect_scale], $
      labels=['Scale main detspect','Scale ref detspect']
	CRISPEX_DISPRANGE_LS_SCALE, event
END

PRO CRISPEX_DISPRANGE_LS_SCALE, event
; Handles the scaling (or not) of the detailed spectrum to the maximum of the
; average spectrum 
  WIDGET_CONTROL, event.TOP, GET_UVALUE=info
	IF (TOTAL(((*(*info).feedbparams).verbosity)[2:3]) GE 1) THEN $
    CRISPEX_VERBOSE_GET_ROUTINE, event
	IF (*(*info).ctrlsswitch).imrefdetspect THEN $
    CRISPEX_DISPRANGE_LS_SCALE_REF, event $
  ELSE $
    CRISPEX_DISPRANGE_LS_SCALE_MAIN, event
	CRISPEX_DISPRANGE_LS_RANGE, event
END

PRO CRISPEX_DISPRANGE_LS_SCALE_MAIN, event, OVERRIDE_SCALE=override_scale, $
  NO_UPDATE_TEXT=no_update_text
; Handles the scaling (or not) of the main detailed spectrum to the maximum of
; the average spectrum 
  WIDGET_CONTROL, event.TOP, GET_UVALUE=info
	IF (TOTAL(((*(*info).feedbparams).verbosity)[2:3]) GE 1) THEN $
    CRISPEX_VERBOSE_GET_ROUTINE, event
  factor = (*(*info).dataparams).ms * ((*(*info).paramparams).scale_cubes)[0]
  IF (N_ELEMENTS(OVERRIDE_SCALE) EQ 1) THEN $
    scaling_set = override_scale $
  ELSE $
    scaling_set = (*(*info).dispswitch).detspect_scale 
	IF scaling_set THEN BEGIN
		*(*(*info).plotaxes).ls_low_y /= factor
		*(*(*info).plotaxes).ls_upp_y /= factor
	ENDIF ELSE BEGIN
		*(*(*info).plotaxes).ls_low_y *= factor
		*(*(*info).plotaxes).ls_upp_y *= factor
	ENDELSE
  IF ~KEYWORD_SET(NO_UPDATE_TEXT) THEN BEGIN
  	WIDGET_CONTROL, (*(*info).ctrlscp).lower_y_text, $
      SET_VALUE=STRTRIM((*(*(*info).plotaxes).ls_low_y)[$
      (*(*info).dataparams).s],2)
  	WIDGET_CONTROL, (*(*info).ctrlscp).upper_y_text, $
      SET_VALUE=STRTRIM((*(*(*info).plotaxes).ls_upp_y)[$
      (*(*info).dataparams).s],2)
  ENDIF
END

PRO CRISPEX_DISPRANGE_LS_SCALE_REF, event, OVERRIDE_SCALE=override_scale, $
  NO_UPDATE_TEXT=no_update_text
; Handles the scaling (or not) of the reference detailed spectrum to the maximum
; of the average spectrum 
  WIDGET_CONTROL, event.TOP, GET_UVALUE=info
	IF (TOTAL(((*(*info).feedbparams).verbosity)[2:3]) GE 1) THEN $
    CRISPEX_VERBOSE_GET_ROUTINE, event
  factor = (*(*info).dataparams).refms * ((*(*info).paramparams).scale_cubes)[1] 
  IF (N_ELEMENTS(OVERRIDE_SCALE) EQ 1) THEN $
    scaling_set = override_scale $
  ELSE $
    scaling_set = (*(*info).dispswitch).ref_detspect_scale 
	IF scaling_set THEN BEGIN
		*(*(*info).plotaxes).ls_low_y_ref /= factor
		*(*(*info).plotaxes).ls_upp_y_ref /= factor
	ENDIF ELSE BEGIN
		*(*(*info).plotaxes).ls_low_y_ref *= factor
		*(*(*info).plotaxes).ls_upp_y_ref *= factor
	ENDELSE
  IF ~KEYWORD_SET(NO_UPDATE_TEXT) THEN BEGIN
  	WIDGET_CONTROL, (*(*info).ctrlscp).lower_y_text, $
      SET_VALUE=STRTRIM((*(*(*info).plotaxes).ls_low_y_ref)[$
      (*(*info).dataparams).s_ref],2)
  	WIDGET_CONTROL, (*(*info).ctrlscp).upper_y_text, $
      SET_VALUE=STRTRIM((*(*(*info).plotaxes).ls_upp_y_ref)[$
      (*(*info).dataparams).s_ref],2)
  ENDIF
END

PRO CRISPEX_DISPRANGE_LS_SUBTRACT, event
; Handles display of average subtracted spectrum in detailed spectrum window
	WIDGET_CONTROL, event.TOP, GET_UVALUE = info
	IF (TOTAL(((*(*info).feedbparams).verbosity)[2:3]) GE 1) THEN $
    CRISPEX_VERBOSE_GET_ROUTINE, event
	IF (*(*info).ctrlsswitch).imrefdetspect THEN $
    (*(*info).plotswitch).ref_subtract = event.SELECT $
  ELSE $
    (*(*info).plotswitch).subtract = event.SELECT
	IF (((*(*info).feedbparams).verbosity)[3] EQ 1) THEN $
    CRISPEX_VERBOSE_GET, event, $
      [(*(*info).plotswitch).subtract,(*(*info).plotswitch).ref_subtract], $
      labels=['Subtract from main','Subtract from ref']
	CRISPEX_DRAW, event
END

PRO CRISPEX_DISPRANGE_T_LOW, event
; Handles change in lower t-value of accessed data cube
	WIDGET_CONTROL, event.TOP, GET_UVALUE = info
	IF (TOTAL(((*(*info).feedbparams).verbosity)[2:3]) GE 1) THEN $
    CRISPEX_VERBOSE_GET_ROUTINE, event
	WIDGET_CONTROL, (*(*info).ctrlscp).lower_t_text, GET_VALUE = textvalue
	(*(*info).dispparams).t_low = FLOAT(textvalue[0])
	IF ((*(*info).dispparams).t_low GE (*(*info).dispparams).t_upp) THEN (*(*info).dispparams).t_low = (*(*info).dispparams).t_upp - 1
	IF ((*(*info).dispparams).t_low LT (*(*info).dispparams).t_first) THEN (*(*info).dispparams).t_low = (*(*info).dispparams).t_first
	WIDGET_CONTROL, (*(*info).ctrlscp).lower_t_text, SET_VALUE = STRTRIM((*(*info).dispparams).t_low,2)
	IF ((*(*info).winswitch).showint AND (*(*info).intparams).lock_t) THEN BEGIN
		(*(*info).plotaxes).int_low_t = (*(*info).dispparams).t_low
		CRISPEX_DISPRANGE_INT_T_RANGE, event
	ENDIF ELSE CRISPEX_DISPRANGE_T_RANGE, event
END

PRO CRISPEX_DISPRANGE_T_UPP, event
; Handles change in upper t-value of accessed data cube
	WIDGET_CONTROL, event.TOP, GET_UVALUE = info
	IF (TOTAL(((*(*info).feedbparams).verbosity)[2:3]) GE 1) THEN $
    CRISPEX_VERBOSE_GET_ROUTINE, event
	WIDGET_CONTROL, (*(*info).ctrlscp).upper_t_text, GET_VALUE = textvalue
	(*(*info).dispparams).t_upp = FLOAT(textvalue[0])
	IF ((*(*info).dispparams).t_upp LE (*(*info).dispparams).t_low) THEN (*(*info).dispparams).t_upp = (*(*info).dispparams).t_low + 1
	IF ((*(*info).dispparams).t_upp GT (*(*info).dispparams).t_last) THEN (*(*info).dispparams).t_upp = (*(*info).dispparams).t_last
	WIDGET_CONTROL, (*(*info).ctrlscp).upper_t_text, SET_VALUE = STRTRIM((*(*info).dispparams).t_upp,2)
	IF ((*(*info).winswitch).showint AND (*(*info).intparams).lock_t) THEN BEGIN
		(*(*info).plotaxes).int_upp_t = (*(*info).dispparams).t_upp
		CRISPEX_DISPRANGE_INT_T_RANGE, event
	ENDIF ELSE CRISPEX_DISPRANGE_T_RANGE, event
END

PRO CRISPEX_DISPRANGE_T_RANGE, event, NO_DRAW=no_draw, T_SET=t_set, RESET=reset
; Determines range from change in lower or upper t-value and calls (re)display routine
	WIDGET_CONTROL, event.TOP, GET_UVALUE = info
	IF (TOTAL(((*(*info).feedbparams).verbosity)[2:3]) GE 1) THEN $
    CRISPEX_VERBOSE_GET_ROUTINE, event
	IF (*(*info).winswitch).showretrdet THEN BEGIN
		(*(*info).dispparams).t_low = (*(*(*info).detparams).t)[(*(*info).detparams).idx] - $
      (*(*info).detparams).delta_t_dn > (*(*info).dispparams).t_first
		(*(*info).dispparams).t_upp = (*(*(*info).detparams).t)[(*(*info).detparams).idx] + $
      (*(*info).detparams).delta_t_up < (*(*info).dispparams).t_last
	ENDIF
	(*(*info).dispparams).t_range = (*(*info).dispparams).t_upp - (*(*info).dispparams).t_low + 1
	IF ((*(*info).dispparams).t_range NE (*(*info).dataparams).nt) THEN $
    WIDGET_CONTROL, (*(*info).ctrlscp).reset_trange_but, /SENSITIVE $
  ELSE $
    WIDGET_CONTROL, (*(*info).ctrlscp).reset_trange_but, SENSITIVE = 0
  IF (N_ELEMENTS(T_SET) EQ 1) THEN $
    (*(*info).dispparams).t = t_set $
  ELSE IF (~KEYWORD_SET(RESET) AND ((*(*info).winswitch).showretrdet EQ 0)) THEN BEGIN
    IF ((*(*info).dispparams).t LT (*(*info).dispparams).t_low) THEN $
      (*(*info).dispparams).t = (*(*info).dispparams).t_low $
    ELSE IF ((*(*info).dispparams).t GT (*(*info).dispparams).t_upp) THEN $
      (*(*info).dispparams).t = (*(*info).dispparams).t_upp
  ENDIF
	WIDGET_CONTROL, (*(*info).ctrlscp).t_slider, SET_SLIDER_MIN=(*(*info).dispparams).t_low, $
    SET_SLIDER_MAX=(*(*info).dispparams).t_upp, SET_VALUE=(*(*info).dispparams).t, $
    SENSITIVE=((*(*info).dispparams).t_upp NE (*(*info).dispparams).t_low)
	IF ((*(*info).dispparams).t_range - 1 LE 1) THEN BEGIN
		t_step = 1
		t_sens = 0 
	ENDIF ELSE BEGIN
		t_step = (*(*info).pbparams).t_step
		t_sens = 1
	ENDELSE
  ; Set real lower/upper time values for main
  IF ((*(*info).dataparams).mainnt GT 1) THEN BEGIN
    (*(*info).dispparams).t_low_main = $
      (*(*(*info).dispparams).tarr_main)[(*(*info).dispparams).t_low]
    tarr_main_sel = (*(*(*info).dispparams).tarr_main)[$
      (*(*info).dispparams).t_low:(*(*info).dispparams).t_upp]
    wherene0 = WHERE(tarr_main_sel NE 0, count)
    IF (count NE 0) THEN $
      t_sel = wherene0[count-1] $
    ELSE $
      t_sel = 0
    (*(*info).dispparams).t_upp_main = tarr_main_sel[t_sel] ;Fix tarr[-1]=0
  ENDIF
  IF ((*(*info).dataparams).refnt GT 1) THEN BEGIN
    ; Set real lower/upper time values for reference
    (*(*info).dispparams).t_low_ref = $
      (*(*(*info).dispparams).tarr_ref)[(*(*info).dispparams).t_low]
    tarr_ref = (*(*(*info).dispparams).tarr_ref)[$
      (*(*info).dispparams).t_low:(*(*info).dispparams).t_upp]
    wherene0 = WHERE(tarr_ref NE 0, count)
    IF (count NE 0) THEN $
      t_sel = wherene0[count-1] $
    ELSE $
      t_sel = 0
    (*(*info).dispparams).t_upp_ref = tarr_ref[t_sel] ;Fix tarr[-1]=0
  ENDIF
  IF (TOTAL((*(*info).dataparams).sjint) GT (*(*info).dataparams).nsjifiles) THEN BEGIN
    FOR idx_sji=0,(*(*info).dataparams).nsjifiles-1 DO BEGIN
      ; Set real lower/upper time values for SJI
      (*(*info).dispparams).t_low_sji[idx_sji] = $
        (*(*(*info).dispparams).tarr_sji[idx_sji])[(*(*info).dispparams).t_low]
      tarr_sji = (*(*(*info).dispparams).tarr_sji[idx_sji])[$
        (*(*info).dispparams).t_low:(*(*info).dispparams).t_upp]
      wherene0 = WHERE(tarr_sji NE 0, count)
      IF (count NE 0) THEN $
        t_sel = wherene0[count-1] $
      ELSE $
        t_sel = 0
      (*(*info).dispparams).t_upp_sji[idx_sji] = tarr_sji[t_sel] ;Fix tarr[-1]=0
    ENDFOR
  ENDIF
	IF (((*(*info).feedbparams).verbosity)[3] EQ 1) THEN $
    CRISPEX_VERBOSE_GET, event, [(*(*info).dispparams).t_low,(*(*info).dispparams).t_upp], $
      labels=['Lower t-value','Upper t-value']
	WIDGET_CONTROL, (*(*info).ctrlscp).t_step_slider, $
    SET_SLIDER_MAX=((*(*info).dispparams).t_range-1)>2,$
    SET_VALUE=t_step, SENSITIVE=t_sens
	IF ~KEYWORD_SET(NO_DRAW) THEN BEGIN
		CRISPEX_UPDATE_T, event
		IF (*(*info).winswitch).showsp THEN BEGIN
      CRISPEX_UPDATE_SPSLICE, event
      CRISPEX_DISPLAYS_SP_REPLOT_AXES, event
    ENDIF
		IF (*(*info).winswitch).showrefsp THEN BEGIN
      CRISPEX_UPDATE_REFSPSLICE, event
      CRISPEX_DISPLAYS_REFSP_REPLOT_AXES, event
    ENDIF
    CRISPEX_UPDATE_SLICES, event, /NO_DRAW, $
      NO_PHIS=((*(*info).winswitch).showphis EQ 0)
		IF (*(*info).winswitch).showloop THEN CRISPEX_DISPLAYS_LOOPSLAB_REPLOT_AXES, event
		IF (*(*info).winswitch).showrefloop THEN CRISPEX_DISPLAYS_REFLOOPSLAB_REPLOT_AXES, event
		IF (*(*info).winswitch).showrestloop THEN CRISPEX_DISPLAYS_RESTORE_LOOPSLAB_REPLOT_AXES, event
		IF (*(*info).winswitch).showretrdet THEN CRISPEX_DISPLAYS_RETRIEVE_DET_LOOPSLAB_REPLOT_AXES, event
		CRISPEX_DRAW, event
	ENDIF
END

PRO CRISPEX_DISPRANGE_T_RESET, event, NO_DRAW=no_draw, T_SET=t_set
; Handles reset of temporal boundaries and calls (re)display routine
	WIDGET_CONTROL, event.TOP, GET_UVALUE = info
	IF (TOTAL(((*(*info).feedbparams).verbosity)[2:3]) GE 1) THEN $
    CRISPEX_VERBOSE_GET_ROUTINE, event
	(*(*info).dispparams).t_upp = (*(*info).dispparams).t_last
	(*(*info).dispparams).t_low = (*(*info).dispparams).t_first
	WIDGET_CONTROL, (*(*info).ctrlscp).upper_t_text, $
    SET_VALUE=STRTRIM((*(*info).dispparams).t_upp,2), SENSITIVE=((*(*info).dataparams).nt GT 1)
	WIDGET_CONTROL, (*(*info).ctrlscp).lower_t_text, $
    SET_VALUE=STRTRIM((*(*info).dispparams).t_low,2), SENSITIVE=((*(*info).dataparams).nt GT 1)
	WIDGET_CONTROL, (*(*info).ctrlscp).reset_trange_but, SENSITIVE = 0
	IF ((*(*info).winswitch).showint AND (*(*info).intparams).lock_t) THEN $
    CRISPEX_DISPRANGE_INT_T_RESET, event $
  ELSE $
    CRISPEX_DISPRANGE_T_RANGE, event, NO_DRAW=no_draw, T_SET=t_set, /RESET
END

PRO CRISPEX_DISPRANGE_GET_WARP, event, PHIS=phis, REFERENCE=reference
; Handles determining warping tie points
	WIDGET_CONTROL, event.TOP, GET_UVALUE = info
	IF (TOTAL(((*(*info).feedbparams).verbosity)[2:3]) GE 1) THEN $
    CRISPEX_VERBOSE_GET_ROUTINE, event
  IF ~KEYWORD_SET(REFERENCE) THEN BEGIN
    IF KEYWORD_SET(PHIS) THEN WIDGET_CONTROL, /HOURGLASS
    ndisp_diagnostics = (*(*info).intparams).ndisp_diagnostics
    wheredispdiag = *(*(*info).intparams).wheredispdiag
    lps = (*(*info).dataparams).lps
    lp_low = (*(*info).intparams).diag_start + (*(*info).dispparams).lp_low_tmp  
    lp_upp = (*(*info).intparams).diag_start + (*(*info).dispparams).lp_upp_tmp
    lp_range = (*(*info).dispparams).lp_range
    ts = *(*(*info).dispparams).tarr_main
  ENDIF ELSE BEGIN
    ndisp_diagnostics = (*(*info).intparams).ndisp_refdiagnostics
    wheredispdiag = *(*(*info).intparams).wheredisprefdiag
    lps = (*(*info).dataparams).reflps
    lp_low = (*(*info).intparams).refdiag_start + $
      (*(*info).dispparams).lp_ref_low_tmp
    lp_upp = (*(*info).intparams).refdiag_start + $
      (*(*info).dispparams).lp_ref_upp_tmp
    lp_range = (*(*info).dispparams).lp_ref_range
    ts = *(*(*info).dispparams).tarr_ref
  ENDELSE
  nt = (*(*info).dataparams).nt
  ts_loc = ts[(*(*info).dispparams).t_low:(*(*info).dispparams).t_upp]
  nt_loc = (*(*info).dispparams).t_upp - (*(*info).dispparams).t_low + 1
  IF (KEYWORD_SET(PHIS) AND $
      ((*(*info).phiparams).nphi GT (*(*info).dataparams).nt)) THEN $
    nt = (*(*info).phiparams).nphi 
  FOR dd=0,ndisp_diagnostics-1 DO BEGIN
    disp_idx = wheredispdiag[dd]
    lps_loc = lps[lp_low[disp_idx]:lp_upp[disp_idx]]
    nlp_loc = lp_upp[disp_idx] - lp_low[disp_idx] + 1
    warp = CRISPEX_GET_WARP(lps_loc, nlp_loc, ts_loc, nt_loc) 
    IF ~KEYWORD_SET(REFERENCE) THEN BEGIN
      *(*(*info).dispparams).xytri[0,disp_idx] = warp.xtri
      *(*(*info).dispparams).xytri[1,disp_idx] = warp.ytri 
      IF KEYWORD_SET(PHIS) THEN BEGIN
      *(*(*info).dispparams).phisxytri[0,disp_idx] = warp.xtri
      *(*(*info).dispparams).phisxytri[1,disp_idx] = warp.ytri[*,$
        0:(*(*info).phiparams).nphi-1]
      ENDIF 
    ENDIF ELSE BEGIN
      *(*(*info).dispparams).xytri_ref[0,disp_idx] = warp.xtri
      *(*(*info).dispparams).xytri_ref[1,disp_idx] = warp.ytri
    ENDELSE
  ENDFOR
END

PRO CRISPEX_DISPRANGE_LP_RANGE, event, NO_DRAW=no_draw
; Determines range from change in lower or upper s-value and calls (re)display
; routine
  WIDGET_CONTROL, event.TOP, GET_UVALUE = info
	IF (TOTAL(((*(*info).feedbparams).verbosity)[2:3]) GE 1) THEN $
    CRISPEX_VERBOSE_GET_ROUTINE, event
  lp_low_overall = (*(*info).dispparams).lp_low_bounds[$
                    (*(*(*info).intparams).wheredispdiag)[0]]
  lp_upp_overall = (*(*info).dispparams).lp_upp_bounds[$
                    (*(*(*info).intparams).wheredispdiag)[$
                    (*(*info).intparams).ndisp_diagnostics-1]]
	(*(*info).dispparams).lp_range = lp_upp_overall - lp_low_overall + 1
  ; Adjust lp depending on changing boundaries
  lp_diag = $
    TOTAL((*(*info).dataparams).lp GE (*(*info).intparams).diag_start)-1
  lp_low_loc = (*(*info).dispparams).lp_low_bounds[lp_diag]
  lp_upp_loc = (*(*info).dispparams).lp_upp_bounds[lp_diag]
	IF ((*(*info).dataparams).lp LT $
    (*(*info).dispparams).lp_low_bounds[lp_diag]) THEN $
      (*(*info).dataparams).lp = (*(*info).dispparams).lp_low_bounds[lp_diag] $
  ELSE IF ((*(*info).dataparams).lp GT $
    (*(*info).dispparams).lp_upp_bounds[lp_diag]) THEN $
      (*(*info).dataparams).lp = (*(*info).dispparams).lp_upp_bounds[lp_diag]
  CRISPEX_SLIDER_LP_UPDATE, event, /NO_DRAW
	WIDGET_CONTROL, (*(*info).ctrlscp).lp_slider, SET_SLIDER_MIN=lp_low_overall, $
                  SET_SLIDER_MAX=lp_upp_overall, SET_VALUE=(*(*info).dataparams).lp
	WIDGET_CONTROL, (*(*info).ctrlscp).lp_blink_slider, SET_SLIDER_MIN=lp_low_overall, $
    SET_SLIDER_MAX=lp_upp_overall, SET_VALUE=(*(*info).dataparams).lp, $
    SENSITIVE=(((*(*info).dispparams).lp_range-1) NE 1)
  IF (TOTAL((*(*info).dispswitch).warpspslice) GT 0) THEN $
    CRISPEX_DISPRANGE_GET_WARP, event, PHIS=(*(*info).winswitch).showphis
	IF ~KEYWORD_SET(NO_DRAW) THEN BEGIN
    CRISPEX_DRAW_GET_SPECTRAL_AXES, event, /MAIN
		CRISPEX_UPDATE_T, event
    CRISPEX_UPDATE_LP, event
		IF (*(*info).winswitch).showsp THEN BEGIN
      CRISPEX_UPDATE_SPSLICE, event
      CRISPEX_DISPLAYS_SP_REPLOT_AXES, event
    ENDIF
		IF (*(*info).winswitch).showphis THEN BEGIN
      CRISPEX_UPDATE_PHISLICE, event, /NO_DRAW
      CRISPEX_DISPLAYS_PHIS_REPLOT_AXES, event
    ENDIF
		CRISPEX_DRAW, event
	ENDIF
	IF (*(*info).winswitch).showphis THEN BEGIN
		IF (*(*info).dataswitch).onecube THEN $
      WIDGET_CONTROL, (*(*info).ctrlscp).slice_button, $
        SET_VALUE = 'Update spectral windows', SENSITIVE = 1  $
    ELSE $
      WIDGET_CONTROL, (*(*info).ctrlscp).slice_button, SENSITIVE = 1
	ENDIF
	IF (((*(*info).feedbparams).verbosity)[3] EQ 1) THEN $
    CRISPEX_VERBOSE_GET, event, [(*(*info).dispparams).lp_low,$
      (*(*info).dispparams).lp_upp], $
      labels=['Lower lp-value','Upper lp-value']
END

PRO CRISPEX_DISPRANGE_LP_RESET, event, REFERENCE=reference, NO_DRAW=no_draw, $
  VALIDX=validx
; Handles reset of spectral boundaries and calls (re)display routine
	WIDGET_CONTROL, event.TOP, GET_UVALUE=info
	IF (TOTAL(((*(*info).feedbparams).verbosity)[2:3]) GE 1) THEN $
    CRISPEX_VERBOSE_GET_ROUTINE, event
  IF KEYWORD_SET(REFERENCE) THEN $
    ; idx override in case /REFERENCE is set
    idx = 1 $
  ELSE $
    idx = ((*(*info).dispswitch).lp_restrict[1] EQ 1)
  CASE idx OF
   0:  BEGIN
          IF (N_ELEMENTS(validx) LT 1) THEN $
            validx = ([0,(*(*info).intparams).lp_diag_all+1])[$
              (*(*info).dispswitch).lp_restrict_globloc[idx]]
          FOR i=0,N_ELEMENTS(validx)-1 DO BEGIN
            (*(*info).dispparams).v_dop_low[validx[i]] = $
              (*(*info).dataparams).v_dop_low_min[validx[i]]
            (*(*info).dispparams).v_dop_upp[validx[i]] = $
              (*(*info).dataparams).v_dop_upp_max[validx[i]]
          ENDFOR
        END
    1:  BEGIN
          IF (N_ELEMENTS(validx) LT 1) THEN $
            validx = ([0,(*(*info).intparams).lp_ref_diag_all+1])[$
              (*(*info).dispswitch).lp_restrict_globloc[idx]]
          FOR i=0,N_ELEMENTS(validx)-1 DO BEGIN
            (*(*info).dispparams).v_dop_ref_low[validx[i]] = $
              (*(*info).dataparams).v_dop_ref_low_min[validx[i]]
            (*(*info).dispparams).v_dop_ref_upp[validx[i]] = $
              (*(*info).dataparams).v_dop_ref_upp_max[validx[i]]
          ENDFOR
        END
  ENDCASE
  CRISPEX_SLIDER_LP_RESTRICT_SETRANGE, event, idx
  CRISPEX_SLIDER_LP_RESTRICT, event, REFERENCE=reference, NO_DRAW=no_draw
END

PRO CRISPEX_DISPRANGE_LP_REF_RANGE, event, NO_DRAW=no_draw, $
  LP_LOW_SET=lp_low_set, LP_UPP_SET=lp_upp_set
; Determines range from change in lower or upper s-value and calls (re)display
; routine
  WIDGET_CONTROL, event.TOP, GET_UVALUE = info
	IF (TOTAL(((*(*info).feedbparams).verbosity)[2:3]) GE 1) THEN $
    CRISPEX_VERBOSE_GET_ROUTINE, event
  IF (N_ELEMENTS(LP_LOW_SET) EQ 1) THEN $
    (*(*info).dispparams).lp_ref_low = lp_low_set
  IF (N_ELEMENTS(LP_UPP_SET) EQ 1) THEN $
    (*(*info).dispparams).lp_ref_upp = lp_upp_set
  lp_low_overall = (*(*info).dispparams).lp_ref_low_bounds[$
                    (*(*(*info).intparams).wheredisprefdiag)[0]]
  lp_upp_overall = (*(*info).dispparams).lp_ref_upp_bounds[$
                    (*(*(*info).intparams).wheredisprefdiag)[$
                    (*(*info).intparams).ndisp_refdiagnostics-1]]
	(*(*info).dispparams).lp_ref_range = lp_upp_overall - lp_low_overall + 1
  ; Adjust lp depending on changing boundaries
  lp_diag = $
    TOTAL((*(*info).dataparams).lp_ref GE (*(*info).intparams).refdiag_start)-1
  lp_low_loc = (*(*info).dispparams).lp_ref_low_bounds[lp_diag]
  lp_upp_loc = (*(*info).dispparams).lp_ref_upp_bounds[lp_diag]
	IF ((*(*info).dataparams).lp_ref LT $
    (*(*info).dispparams).lp_ref_low_bounds[lp_diag]) THEN $
      (*(*info).dataparams).lp_ref = $
        (*(*info).dispparams).lp_ref_low_bounds[lp_diag] $
  ELSE IF ((*(*info).dataparams).lp_ref GT $
    (*(*info).dispparams).lp_upp_bounds[lp_diag]) THEN $
      (*(*info).dataparams).lp_ref = $
        (*(*info).dispparams).lp_ref_upp_bounds[lp_diag]
  CRISPEX_SLIDER_LP_UPDATE, event, /NO_DRAW, /REFERENCE
	WIDGET_CONTROL, (*(*info).ctrlscp).lp_ref_slider, SET_SLIDER_MIN=lp_low_overall, $
                  SET_SLIDER_MAX=lp_upp_overall, $
                  SET_VALUE=(*(*info).dataparams).lp_ref
  IF (TOTAL((*(*info).dispswitch).warprefspslice) GT 0) THEN $
    CRISPEX_DISPRANGE_GET_WARP, event, /REFERENCE
	IF ~KEYWORD_SET(NO_DRAW) THEN BEGIN
    CRISPEX_DRAW_GET_SPECTRAL_AXES, event, /REFERENCE
		CRISPEX_UPDATE_T, event
		CRISPEX_UPDATE_LP, event
		IF (*(*info).winswitch).showrefsp THEN BEGIN
      CRISPEX_UPDATE_REFSPSLICE, event
      CRISPEX_DISPLAYS_REFSP_REPLOT_AXES, event
    ENDIF
		CRISPEX_DRAW, event
	ENDIF
	IF (((*(*info).feedbparams).verbosity)[3] EQ 1) THEN $
    CRISPEX_VERBOSE_GET, event, [(*(*info).dispparams).lp_ref_low,$
    (*(*info).dispparams).lp_ref_upp], labels=['Lower lp-value','Upper lp-value']
END

;========================= DISPLAY DRAW PROCEDURES
PRO CRISPEX_DRAW_CURSCROSS_PLOT, event, curscolor, no_cursor=no_cursor, $
  no_number=no_number,thick=thick, no_endpoints=no_endpoints, $
  symsize=symsize, draw_mask=draw_mask, SJI=sji, REFERENCE=reference, $
  IDX_SJI=idx_sji
  ; Handles overplotting of the cursor, slits and loop paths
	WIDGET_CONTROL, event.TOP, GET_UVALUE = info
	IF (TOTAL(((*(*info).feedbparams).verbosity)[2:3]) GE 1) THEN $
    CRISPEX_VERBOSE_GET_ROUTINE, event
  IF (N_ELEMENTS(SYMSIZE) NE 1) THEN symsize = (*(*info).overlayparams).symsize
  IF (N_ELEMENTS(THICK) NE 1) THEN thick = (*(*info).overlayparams).thick
	(*(*info).phiparams).d_nphi_set = $
    (*(*info).zooming).factor * (*(*info).phiparams).nphi_set
  main_wid = 0
  ref_wid = 0
  sji_wid = 0
  IF KEYWORD_SET(SJI) THEN BEGIN
    sji_wid = ((*(*info).winids).current_wid EQ $
      (*(*info).winids).sjidrawid[idx_sji])
    sx_loc = (*(*info).curs).sxsji[idx_sji]
    sy_loc = (*(*info).curs).sysji[idx_sji]
    IF (*(*info).overlayswitch).sjiraster THEN $
      CRISPEX_DRAW_RASTER_OVERLAYS, event, /SJI, IDX_SJI=idx_sji
    IF (*(*info).overlayswitch).rastertiming[2] THEN $
      CRISPEX_DRAW_RASTER_TIMING_OVERLAYS, event, /SJI, $
        IDX_SJI=idx_sji 
  ENDIF ELSE IF KEYWORD_SET(REFERENCE) THEN BEGIN
    ref_wid = ((*(*info).winids).current_wid EQ (*(*info).winids).refdrawid)
    sx_loc = (*(*info).curs).sxref
    sy_loc = (*(*info).curs).syref
    IF (*(*info).overlayswitch).refraster THEN $
      CRISPEX_DRAW_RASTER_OVERLAYS, event, /REFERENCE
    IF (*(*info).overlayswitch).rastertiming[1] THEN $
      CRISPEX_DRAW_RASTER_TIMING_OVERLAYS, event, /REFERENCE, $
        IDX_SJI=(*(*info).dispswitch).sji_select
  ENDIF ELSE BEGIN
    main_wid = ((*(*info).winids).current_wid EQ (*(*info).winids).xydrawid)
    sx_loc = (*(*info).curs).sx
    sy_loc = (*(*info).curs).sy
    IF (*(*info).overlayswitch).rastertiming[0] THEN $
      CRISPEX_DRAW_RASTER_TIMING_OVERLAYS, event, /MAIN, $
        IDX_SJI=(*(*info).dispswitch).sji_select
  ENDELSE
  ; Get current colour table arrays
  TVLCT, r_cur, g_cur, b_cur, /GET
  eqtc0 = (ARRAY_EQUAL(r_cur,BINDGEN(256)) AND ARRAY_EQUAL(g_cur,BINDGEN(256)) $
      AND ARRAY_EQUAL(b_cur,BINDGEN(256)))
  IF (eqtc0 EQ 0) THEN LOADCT,0,/SILENT
  ; Overplot phi-slit...
	IF ((*(*info).winswitch).showphis AND $
    ((*(*info).dispswitch).xy_out_of_range EQ 0)) THEN BEGIN
    ; ... in reference window
    IF KEYWORD_SET(REFERENCE) THEN BEGIN
      PLOTS, [(*(*(*info).overlayparams).sx_pts_ref)[0],$
        (*(*(*info).overlayparams).sx_pts_ref)[(*(*info).phiparams).nw_cur-1]],$
        [(*(*(*info).overlayparams).sy_pts_ref)[0],$
        (*(*(*info).overlayparams).sy_pts_ref)[(*(*info).phiparams).nw_cur-1]],$
        /DEVICE, COLOR=!P.COLOR
    ; ... in slit-jaw window
    ENDIF ELSE IF KEYWORD_SET(SJI) THEN BEGIN
      PLOTS, [(*(*(*info).overlayparams).sx_pts_sji[idx_sji])[0],$
        (*(*(*info).overlayparams).sx_pts_sji[idx_sji])[(*(*info).phiparams).nw_cur-1]],$
        [(*(*(*info).overlayparams).sy_pts_sji[idx_sji])[0],$
        (*(*(*info).overlayparams).sy_pts_sji[idx_sji])[(*(*info).phiparams).nw_cur-1]],$
        /DEVICE, COLOR=!P.COLOR
    ; ... in main window
    ENDIF ELSE BEGIN
      PLOTS, [(*(*(*info).overlayparams).sx_pts)[0],$
        (*(*(*info).overlayparams).sx_pts)[(*(*info).phiparams).nw_cur-1]],$
        [(*(*(*info).overlayparams).sy_pts)[0],$
        (*(*(*info).overlayparams).sy_pts)[(*(*info).phiparams).nw_cur-1]],$
        /DEVICE, COLOR=!P.COLOR
    ENDELSE
  ENDIF
  ; Overplot loop paths...
	IF ((*(*info).overlayswitch).loopslit AND $
    (((*(*info).loopparams).np GT 0) OR $
     ((*(*info).loopparams).np_ref GT 0) OR $
     ((*(*info).loopparams).np_sji GT 0))) THEN BEGIN
		CRISPEX_ZOOM_LOOP, event, REFERENCE=KEYWORD_SET(REFERENCE), $
      SJI=KEYWORD_SET(SJI), IDX_SJI=idx_sji
    ; ... in reference window
    IF KEYWORD_SET(REFERENCE) THEN BEGIN
  		IF ~KEYWORD_SET(NO_ENDPOINTS) THEN $
        PLOTS, *(*(*info).overlayparams).sxp_ref, $
          *(*(*info).overlayparams).syp_ref, /DEVICE, COLOR=!P.COLOR, PSYM=1, $
          THICK=thick, SYMSIZE=symsize
  		IF ((*(*info).overlayparams).loop_linestyle EQ 1) THEN $
        PLOTS,*(*(*info).overlayparams).sxr_ref,$
          *(*(*info).overlayparams).syr_ref, /DEVICE, COLOR=!P.COLOR, PSYM=3, $
          THICK=thick $
  		ELSE $
        PLOTS,*(*(*info).overlayparams).sxr_ref,$
          *(*(*info).overlayparams).syr_ref,/DEVICE, COLOR=!P.COLOR, $
          LINESTYLE=(*(*info).overlayparams).loop_linestyle, THICK=thick
    ; ... in SJI window
    ENDIF ELSE IF KEYWORD_SET(SJI) THEN BEGIN
  		IF ~KEYWORD_SET(NO_ENDPOINTS) THEN $
        PLOTS, *(*(*info).overlayparams).sxp_sji[idx_sji], $
          *(*(*info).overlayparams).syp_sji[idx_sji], /DEVICE, COLOR=!P.COLOR, PSYM=1, $
          THICK=thick, SYMSIZE=symsize
  		IF ((*(*info).overlayparams).loop_linestyle EQ 1) THEN $
        PLOTS,*(*(*info).overlayparams).sxr_sji[idx_sji],$
          *(*(*info).overlayparams).syr_sji[idx_sji], /DEVICE, COLOR=!P.COLOR, PSYM=3, $
          THICK=thick $
  		ELSE $
        PLOTS,*(*(*info).overlayparams).sxr_sji[idx_sji],$
          *(*(*info).overlayparams).syr_sji[idx_sji],/DEVICE, COLOR=!P.COLOR, $
          LINESTYLE=(*(*info).overlayparams).loop_linestyle, THICK=thick
    ; ... in main window
    ENDIF ELSE BEGIN
  		IF ~KEYWORD_SET(NO_ENDPOINTS) THEN $
        PLOTS, *(*(*info).overlayparams).sxp, *(*(*info).overlayparams).syp, $
          /DEVICE, COLOR=!P.COLOR, PSYM=1, THICK=thick, SYMSIZE=symsize
  		IF ((*(*info).overlayparams).loop_linestyle EQ 1) THEN $
        PLOTS,*(*(*info).overlayparams).sxr,*(*(*info).overlayparams).syr, $
          /DEVICE, COLOR=!P.COLOR, PSYM=3, THICK=thick $
  		ELSE $
        PLOTS,*(*(*info).overlayparams).sxr,*(*(*info).overlayparams).syr, $
          /DEVICE, COLOR=!P.COLOR, THICK=thick, $
          LINESTYLE=(*(*info).overlayparams).loop_linestyle
    ENDELSE
	ENDIF ELSE IF ((*(*info).meas).np GE 1) THEN BEGIN
    ; Draw measurement
		CRISPEX_ZOOM_MEAS, event, REFERENCE=KEYWORD_SET(REFERENCE), $
      SJI=KEYWORD_SET(SJI), IDX_SJI=idx_sji
    ; ... in reference window
    IF KEYWORD_SET(REFERENCE) THEN BEGIN
  		IF ~KEYWORD_SET(NO_ENDPOINTS) THEN BEGIN
  			PLOTS, *(*(*info).meas).sxp_ref,*(*(*info).meas).syp_ref, /DEVICE, $
          COLOR=!P.COLOR, PSYM=1, THICK=thick, SYMSIZE=symsize
  			PLOTS, *(*(*info).meas).sxp_ref,*(*(*info).meas).syp_ref, /DEVICE, $
          COLOR=!P.COLOR, LINESTYLE=0, THICK=thick, SYMSIZE=symsize
  		ENDIF
    ; ... in SJI window
    ENDIF ELSE IF KEYWORD_SET(SJI) THEN BEGIN
  		IF ~KEYWORD_SET(NO_ENDPOINTS) THEN BEGIN
  			PLOTS, *(*(*info).meas).sxp_sji[idx_sji],$
          *(*(*info).meas).syp_sji[idx_sji], /DEVICE, $
          COLOR=!P.COLOR, PSYM=1, THICK=thick, SYMSIZE=symsize
  			PLOTS, *(*(*info).meas).sxp_sji[idx_sji],$
          *(*(*info).meas).syp_sji[idx_sji], /DEVICE, $
          COLOR=!P.COLOR, LINESTYLE=0, THICK=thick, SYMSIZE=symsize
  		ENDIF
    ; ... in main window
    ENDIF ELSE BEGIN
  		IF ~KEYWORD_SET(NO_ENDPOINTS) THEN BEGIN
  			PLOTS, *(*(*info).meas).sxp,*(*(*info).meas).syp, /DEVICE, $
          COLOR=!P.COLOR, PSYM=1, THICK=thick, SYMSIZE=symsize
  			PLOTS, *(*(*info).meas).sxp,*(*(*info).meas).syp, /DEVICE, $
          COLOR=!P.COLOR, LINESTYLE=0, THICK=thick, SYMSIZE=symsize
  		ENDIF
    ENDELSE
	ENDIF 
;  IF (~KEYWORD_SET(NO_CURSOR) AND (*(*info).curs).panselect) THEN $
  IF ~KEYWORD_SET(NO_CURSOR) THEN $
    ; Overplot cursor location
    PLOTS, sx_loc, sy_loc, /DEVICE, PSYM=1, COLOR=curscolor, THICK=thick, $
      SYMSIZE=symsize
	IF (((*(*info).feedbparams).verbosity)[3] EQ 1) THEN $
    CRISPEX_VERBOSE_GET, event, $
      [(*(*info).curs).sx,(*(*info).curs).sy,(*(*info).winsizes).xywinx,$
       (*(*info).winsizes).xywiny], labels=['sx','sy','xywinx','xywiny']
	CRISPEX_DRAW_LOOP_OVERLAYS, event, NO_NUMBER=no_number, THICK=thick, $
    NO_ENDPOINTS=no_endpoints, SYMSIZE=symsize, SJI=SJI, REFERENCE=reference
	IF draw_mask THEN CRISPEX_DRAW_MASK_OVERLAYS, event, REFERENCE=reference
  TVLCT, r_cur, g_cur, b_cur
END

PRO CRISPEX_DRAW_CTBAR, event, MAIN=main, REFERENCE=reference, DOPPLER=doppler,$
  SJI=sji, IDX_SJI=idx_sji, INIT=init, MINIMUM=minimum, MAXIMUM=maximum
	WIDGET_CONTROL, event.TOP, GET_UVALUE = info
	IF (TOTAL(((*(*info).feedbparams).verbosity)[2:3]) GE 1) THEN $
    CRISPEX_VERBOSE_GET_ROUTINE, event
  force_minmax = ((N_ELEMENTS(MINIMUM) EQ 1) AND (N_ELEMENTS(MAXIMUM) EQ 1))
  ; Handle setting of specific SJI index
  IF (N_ELEMENTS(IDX_SJI) EQ 1) THEN BEGIN
    showsji = BYTARR((*(*info).dataparams).nsjifiles)
    showsji[idx_sji] = 1B
  ENDIF ELSE showsji = (*(*info).winswitch).showsji
  ; Determine scale_idx 
  IF KEYWORD_SET(INIT) THEN $
    selarr_tmp = [1,(*(*info).winswitch).showref,0,showsji] $
  ELSE $
    selarr_tmp = [KEYWORD_SET(MAIN), KEYWORD_SET(REFERENCE), KEYWORD_SET(DOPPLER), $
      KEYWORD_SET(SJI)*showsji]
  selarr = WHERE(selarr_tmp EQ 1, count)
  ; (Re)draw all requested color table bars
  FOR i=0,N_ELEMENTS(selarr)-1 DO BEGIN
    sel = selarr[i]
    units = 'counts]'
    CASE sel OF 
      0:  BEGIN
            drawid = (*(*info).winids).imdrawid_ctbar
            rgb_table = (*(*info).plotparams).rgb_main
            IF (STRCOMPRESS((*(*info).dataparams).bunit[0]) NE '') THEN $
              units = (*(*info).dataparams).bunit[0]+']'
          END
      1:  BEGIN
            drawid = (*(*info).winids).refdrawid_ctbar
            rgb_table = (*(*info).plotparams).rgb_ref
            IF (STRCOMPRESS((*(*info).dataparams).bunit[1]) NE '') THEN $
              units = (*(*info).dataparams).bunit[1]+']'
          END
      2:  BEGIN
            drawid = (*(*info).winids).dopdrawid_ctbar
            rgb_table = (*(*info).plotparams).rgb_dop
            IF (STRCOMPRESS((*(*info).dataparams).bunit[0]) NE '') THEN $
              units = (*(*info).dataparams).bunit[0]+']'
          END
      ELSE: BEGIN  ; 3 or higher is the SJIs
              idx_sji = sel - 3 
              drawid = *(*(*info).winids).sjidrawid_ctbar[idx_sji]
              rgb_table = *(*(*info).plotparams).rgb_sji[idx_sji]
              IF (STRCOMPRESS((*(*info).dataparams).bunit[2+idx_sji]) NE '') THEN $
                units = (*(*info).dataparams).bunit[2+idx_sji]+']'
          END
    ENDCASE
    scale_idx = ((sel EQ 0) OR (sel EQ 2)) * (*(*info).intparams).lp_diag_all + $
      ((sel GT 0) + (sel GT 2)) * (*(*info).intparams).ndiagnostics + $
      (sel EQ 1) * (*(*info).intparams).lp_ref_diag_all + $
      (sel GT 1) * (*(*info).intparams).nrefdiagnostics 
    ; Get mininum and maximum, but failsafe for Doppler 
    IF (force_minmax EQ 0) THEN BEGIN
      IF (sel NE 2) THEN $
        CRISPEX_DRAW_SCALING, event, disp, minimum, maximum, MAIN=(sel EQ 0), $
          REFERENCE=(sel EQ 1), SJI=(sel GE 3), IDX_SJI=idx_sji $
      ELSE BEGIN
        IF (*(*info).dispswitch).drawdop THEN $
          CRISPEX_DRAW_SCALING, event, disp, minimum, maximum, /DOPPLER $
        ELSE BEGIN
          minimum = !VALUES.F_NAN
          maximum = !VALUES.F_NAN
        ENDELSE
      ENDELSE
    ENDIF
    ; Create color bar and draw
  	ctbar = BINDGEN(256) # REPLICATE(1B, 10) 
  	WSET, drawid[0]
    ; Get geometry and determine orientation
    ctbar_geometry = WIDGET_INFO(drawid[1], /GEOMETRY)
    top_bar = (ctbar_geometry.xsize GT ctbar_geometry.ysize) 
    IF top_bar THEN BEGIN
      xc = [0.0125,0.9875]
      yc = [0.1,0.4]
    ENDIF ELSE BEGIN
      ; If not top_bar, it's a side bar
      xc = [0.1,0.3]
      yc = [0.0125,0.9875]
  	  ctbar = TRANSPOSE(ctbar)
    ENDELSE
    xfact = xc[1]-xc[0]
    yfact = yc[1]-yc[0]
  	LOADCT, 0, /SILENT
  	PLOT, [0,1], [0,1], /NODATA, POSITION=[xc[0],yc[0],xc[1],yc[1]], XS=4, YS=4
    TVLCT, rgb_table
  	TV, CONGRID(ctbar, CEIL(ctbar_geometry.xsize*xfact), $
      CEIL(ctbar_geometry.ysize*yfact)), xc[0], yc[0], /NORMAL
  	LOADCT, 0, /SILENT
  	PLOTS,[xc[0],xc[0],xc[1],xc[1],xc[0]], [yc[0],yc[1],yc[1],yc[0],yc[0]], /NORMAL
    minmax = [minimum,maximum]
    IF (TOTAL(FINITE(minmax)) GE 1) THEN BEGIN
      wherelt0 = WHERE(minmax LT 0, count)
      IF (count LE 0) THEN $
        minmax = minmax^(1./(*(*info).scaling).gamma[scale_idx]) $
      ELSE BEGIN
        minmax = ABS(minmax)^(1./(*(*info).scaling).gamma[scale_idx]) 
        minmax[wherelt0] *= -1
      ENDELSE
      ; Fix for powers of ten
      IF (ALOG10(MAX(ABS(minmax))) GE 3) THEN BEGIN
        power = FLOOR(ALOG10(MAX(ABS(minmax))))
        minmax /= 10^FLOAT(power)
        units = ' [10!U'+STRTRIM(power,2)+'!N '+units
      ENDIF ELSE $
        units = ' ['+units
    ENDIF ELSE BEGIN
      minmax = [0,0]
      units = ' ['+units
    ENDELSE
    IF top_bar THEN $
    	AXIS, /XAXIS, XTITLE='Color table scaling'+units, XRANGE=minmax, /XSTYLE, $
        XTICKLEN=-0.25 $
    ELSE $
    	AXIS, /YAXIS, YTITLE='Color table scaling'+units, YRANGE=minmax, /YSTYLE, $
        YTICKLEN=-0.25
  ENDFOR
END

PRO CRISPEX_DRAW_LOOP_OVERLAYS, event, NO_NUMBER=no_number, THICK=thick, $
  NO_ENDPOINTS=no_endpoints, SYMSIZE=symsize, SJI=sji, REFERENCE=reference
; Handles overplotting of loop paths from the restored and retrieved loops as well as from the retrieved detections
	WIDGET_CONTROL, event.TOP, GET_UVALUE = info
	IF (TOTAL(((*(*info).feedbparams).verbosity)[2:3]) GE 1) THEN $
    CRISPEX_VERBOSE_GET_ROUTINE, event
  ; Draw restored loop overlays if any are restored
	IF (((*(*info).loopswitch).restore_loops EQ 1) AND $
      ((*(*info).restoreparams).cfilecount GT 0)) THEN $
    CRISPEX_DRAW_LOOP_OVERLAYS_GET_LOOPS, event, NO_NUMBER=no_number, $
      THICK=thick, NO_ENDPOINTS=no_endpoints, SYMSIZE=symsize, SJI=sji, $
      REFERENCE=reference, /RESTORED
  ; Draw retrieved loop overlays if any are restored
	IF (((*(*info).retrparams).clfilecount GT 0) AND $
      ((*(*info).loopswitch).retrieve_loops EQ 1)) THEN $
      CRISPEX_DRAW_LOOP_OVERLAYS_GET_LOOPS, event, NO_NUMBER=no_number, $
        THICK=thick, NO_ENDPOINTS=no_endpoints, SYMSIZE=symsize, SJI=sji, $
        REFERENCE=reference, /RETRIEVED
	IF ((*(*info).loopswitch).retrieve_detfile EQ 1) THEN BEGIN
		condition = WHERE(*(*(*info).detparams).sel_dets EQ 1, conditioncount)
		IF (*(*info).overlayswitch).det_overlay_all THEN BEGIN
			detdrawn = (*(*info).detparams).nr_dets
      CRISPEX_DRAW_LOOP_OVERLAYS_GET_LOOPS, event, NO_NUMBER=no_number, $
        THICK=thick, NO_ENDPOINTS=no_endpoints, SYMSIZE=symsize, SJI=sji, $
        REFERENCE=reference, /DETECTION
		ENDIF ELSE IF (((*(*info).overlayswitch).det_overlay_all EQ 0) AND $
                    (conditioncount GT 0)) THEN BEGIN
				indices = WHERE((*(*(*info).detparams).sel_dets) EQ 1, count)
        IF (count GT 0) THEN BEGIN
          CRISPEX_DRAW_LOOP_OVERLAYS_GET_LOOPS, event, NO_NUMBER=no_number, $
            THICK=thick, NO_ENDPOINTS=no_endpoints, SYMSIZE=symsize, SJI=sji, $
            REFERENCE=reference, /DETECTION
  				detdrawn = N_ELEMENTS(indices)
        ENDIF ELSE detdrawn = 0
		ENDIF ELSE detdrawn = 0
		IF (((*(*info).feedbparams).verbosity)[3] EQ 1) THEN $
      CRISPEX_VERBOSE_GET, event, $
        [(*(*info).detparams).nr_dets,conditioncount,detdrawn], $
        labels=['Detections retrieved','Detections selected','Detections drawn']
	ENDIF ELSE RETURN
END

PRO CRISPEX_DRAW_LOOP_OVERLAYS_GET_LOOPS, event, NO_NUMBER=no_number, THICK=thick, $
  NO_ENDPOINTS=no_endpoints, SYMSIZE=symsize, SJI=sji, REFERENCE=reference, $
  RESTORED=restored, RETRIEVED=retrieved, DETECTION=detection
; Handles overplotting of restored or retrieved loop paths
	WIDGET_CONTROL, event.TOP, GET_UVALUE = info
	IF (TOTAL(((*(*info).feedbparams).verbosity)[2:3]) GE 1) THEN $
    CRISPEX_VERBOSE_GET_ROUTINE, event
  IF KEYWORD_SET(RESTORED) THEN BEGIN
    cfilecount = (*(*info).restoreparams).cfilecount
    overlalways = REPLICATE((*(*info).overlayswitch).overlalways, cfilecount)
    sel_loops = WHERE( ((overlalways EQ 1) OR $
      (*(*(*info).restoreparams).lp EQ (*(*info).dataparams).lp)) AND $
      (*(*(*info).restoreparams).sel_loops EQ 1), sel_count)
    xp = *(*(*info).restoreparams).xp
    yp = *(*(*info).restoreparams).yp
    xr = *(*(*info).restoreparams).xr
    yr = *(*(*info).restoreparams).yr
    imref = *(*(*info).restoreparams).imref
    sel_labels = ['Loops restored','Loops drawn']
  ENDIF ELSE IF KEYWORD_SET(RETRIEVED) THEN BEGIN
    sel_loops = WHERE(*(*(*info).retrparams).sel_loops EQ 1, sel_count)
    xp = *(*(*info).retrparams).xlp
    yp = *(*(*info).retrparams).ylp
    xr = *(*(*info).retrparams).xlr
    yr = *(*(*info).retrparams).ylr
    imref = REPLICATE(1,(*(*info).retrparams).clfilecount)
    sel_labels = ['Loops retrieved','Retrieved loops drawn']
  ENDIF ELSE IF KEYWORD_SET(DETECTION) THEN BEGIN
    sel_loops = WHERE(*(*(*info).detparams).overlay_dets EQ 1, sel_count)
    xp = *(*(*info).detparams).xlp
    yp = *(*(*info).detparams).ylp
		low = (*(*info).detparams).mid-FLOOR((*(*info).detparams).width/2.)
		upp = (*(*info).detparams).mid+FLOOR((*(*info).detparams).width/2.)
    xr = *(*(*info).detparams).xlr
    yr = *(*(*info).detparams).ylr
    imref = REPLICATE(1,(*(*info).detparams).nr_dets)
  ENDIF
  IF (sel_count GT 0) THEN BEGIN
    FOR i=0,sel_count-1 DO BEGIN
			xp_orig = *(xp)[sel_loops[i]]
			yp_orig = *(yp)[sel_loops[i]]
			xr_orig = *(xr)[sel_loops[i]]
			yr_orig = *(yr)[sel_loops[i]]
      IF KEYWORD_SET(DETECTION) THEN BEGIN
        xr_orig = xr_orig[*,low:upp]
        yr_orig = yr_orig[*,low:upp]
      ENDIF
      ; Convert main coordinates to device as default
      sxyp = CRISPEX_TRANSFORM_DATA2DEVICE(info, X=xp_orig, Y=yp_orig, $
        MAIN=((imref)[sel_loops[i]] EQ 1), REF=((imref)[sel_loops[i]] EQ 2), $
        SJI=((imref)[sel_loops[i]] EQ 3))
      sxyr = CRISPEX_TRANSFORM_DATA2DEVICE(info, X=xr_orig, Y=yr_orig, $
        MAIN=((imref)[sel_loops[i]] NE 2), REF=((imref)[sel_loops[i]] EQ 2), $
        SJI=((imref)[sel_loops[i]] EQ 3))
      IF ((imref)[sel_loops[i]] EQ 3) THEN BEGIN
        ; imref=3: slit-jaw
        wcs_from = *(*(*info).dataparams).wcs_sji
        wcs_from_set = (TOTAL((*(*info).dataswitch).sji_wcs_set) GE 1)
        pix_from2main = *(*(*info).dataparams).pix_sji2main
        pix_from2ref = *(*(*info).dataparams).pix_sji2ref
        dx_from = (*(*info).dataparams).sjidx
        dy_from = (*(*info).dataparams).sjidy
        xval_from = (*(*info).dataparams).xval_sji
        yval_from = (*(*info).dataparams).yval_sji
        xpix_from = (*(*info).dataparams).xpix_sji
        ypix_from = (*(*info).dataparams).ypix_sji
        nx = (*(*info).dataparams).sjinx
        ny = (*(*info).dataparams).sjiny
      ENDIF ELSE IF ((imref)[sel_loops[i]] EQ 2) THEN BEGIN
        ; imref=2: reference
        wcs_from = *(*(*info).dataparams).wcs_ref
        wcs_from_set = (*(*info).dataswitch).ref_wcs_set
        pix_from2main = *(*(*info).dataparams).pix_ref2main
        pix_from2sji = (*(*info).dataparams).pix_ref2sji
        dx_from = (*(*info).dataparams).refdx
        dy_from = (*(*info).dataparams).refdy
        xval_from = (*(*info).dataparams).xval_ref
        yval_from = (*(*info).dataparams).yval_ref
        xpix_from = (*(*info).dataparams).xpix_ref
        ypix_from = (*(*info).dataparams).ypix_ref
        nx = (*(*info).dataparams).refnx
        ny = (*(*info).dataparams).refny
      ENDIF ELSE BEGIN
        ; imref=1: main
        wcs_from = (*(*info).dataparams).wcs_main
        wcs_from_set = (*(*info).dataswitch).wcs_set
        pix_from2ref = *(*(*info).dataparams).pix_main2ref
        pix_from2sji = (*(*info).dataparams).pix_main2sji
        dx_from = (*(*info).dataparams).dx
        dy_from = (*(*info).dataparams).dy
        xval_from = (*(*info).dataparams).xval
        yval_from = (*(*info).dataparams).yval
        xpix_from = (*(*info).dataparams).xpix
        ypix_from = (*(*info).dataparams).ypix
        nx = (*(*info).dataparams).nx
        ny = (*(*info).dataparams).ny
      ENDELSE
      IF KEYWORD_SET(SJI) THEN BEGIN
        FOR i_sji=0,(*(*info).winswitch).nwhereshowsji-1 DO BEGIN
          idx_sji = (*(*(*info).winswitch).whereshowsji)[i_sji]
          IF ((*(*info).dataswitch).wcs_set AND $
            (*(*info).dataswitch).sji_wcs_set[idx_sji]) THEN BEGIN
            ; If WCS info available, use that for the transform
            IF (TOTAL(xp_orig LT 0) AND TOTAL(xp_orig GE nx) AND $
              TOTAL(yp_orig LT 0) AND TOTAL(yp_orig GE ny)) THEN BEGIN
              xp_sji = REFORM(((*pix_from2sji[idx_sji])[*,xp_orig,0])[0,*])
              yp_sji = REFORM(((*pix_from2sji[idx_sji])[*,0,yp_orig])[1,0,*])
              xyp_sji = {x:xp_sji, y:yp_sji}
            ENDIF ELSE $
              xyp_sji = CRISPEX_TRANSFORM_GET_WCS(xp_orig, yp_orig, $
                wcs_from, *(*(*info).dataparams).wcs_sji[idx_sji], /PIXEL, /COORD)
            xyr_sji = CRISPEX_TRANSFORM_GET_WCS(xr_orig, yr_orig, $
              wcs_from, *(*(*info).dataparams).wcs_sji[idx_sji], /PIXEL, /COORD, /NO_ROUND)
          ENDIF ELSE BEGIN
            ; Else, use header information for transform
            xyp_sji = CRISPEX_TRANSFORM_COORDS(xp_orig, yp_orig, $
              dx_from, (*(*info).dataparams).sjidx[idx_sji], $
              dy_from, (*(*info).dataparams).sjidy[idx_sji], $
              xval_from, (*(*info).dataparams).xval_sji[idx_sji], $
              yval_from, (*(*info).dataparams).yval_sji[idx_sji], $
              xpix_from, (*(*info).dataparams).xpix_sji[idx_sji], $
              ypix_from, (*(*info).dataparams).ypix_sji[idx_sji])
            xyr_sji = CRISPEX_TRANSFORM_COORDS(xr_orig, yr_orig, $
              dx_from, (*(*info).dataparams).sjidx[idx_sji], $
              dy_from, (*(*info).dataparams).sjidy[idx_sji], $
              xval_from, (*(*info).dataparams).xval_sji[idx_sji], $
              yval_from, (*(*info).dataparams).yval_sji[idx_sji], $
              xpix_from, (*(*info).dataparams).xpix_sji[idx_sji], $
              ypix_from, (*(*info).dataparams).ypix_sji[idx_sji])
          ENDELSE
          sxyp = CRISPEX_TRANSFORM_DATA2DEVICE(info, X=xyp_sji.x, $
            Y=xyp_sji.y, /SJI, IDX_SJI=idx_sji)
          sxyr = CRISPEX_TRANSFORM_DATA2DEVICE(info, X=xyr_sji.x, $
            Y=xyr_sji.y, /SJI, IDX_SJI=idx_sji)
        ENDFOR
      ENDIF ELSE IF KEYWORD_SET(REFERENCE) THEN BEGIN
        IF ((imref)[sel_loops[i]] NE 2) THEN BEGIN
          IF ((*(*info).dataswitch).ref_wcs_set AND wcs_from_set) THEN BEGIN
            ; If WCS info available, use that for the transform
            IF (TOTAL(xp_orig LT 0) AND TOTAL(xp_orig GE nx) AND $
              TOTAL(yp_orig LT 0) AND TOTAL(yp_orig GE ny)) THEN BEGIN
              xp_ref = REFORM((pix_from2ref[*,xp_orig,0])[0,*])
              yp_ref = REFORM((pix_from2ref[*,0,yp_orig])[1,0,*])
              xyp_ref = {x:xp_ref, y:yp_ref}
            ENDIF ELSE $
              xyp_ref = CRISPEX_TRANSFORM_GET_WCS(xp_orig, yp_orig, $
                wcs_from, *(*(*info).dataparams).wcs_ref, /PIXEL, /COORD)
            xyr_ref = CRISPEX_TRANSFORM_GET_WCS(xr_orig, yr_orig, $
              wcs_from, *(*(*info).dataparams).wcs_ref, $
              /PIXEL, /COORD, /NO_ROUND)
          ENDIF ELSE IF ((*(*info).dispswitch).main2ref_no_map EQ 0) THEN BEGIN
            ; Else, use header information for transform
            xyp_ref = CRISPEX_TRANSFORM_COORDS(xp_orig, yp_orig, $
              dx_from, (*(*info).dataparams).refdx, $
              dy_from, (*(*info).dataparams).refdy, $
              xval_from, (*(*info).dataparams).xval_ref, $
              yval_from, (*(*info).dataparams).yval_ref, $
              xpix_from, (*(*info).dataparams).xpix_ref, $
              ypix_from, (*(*info).dataparams).ypix_ref)
            xyr_ref = CRISPEX_TRANSFORM_COORDS(xr_orig, yr_orig, $
              dx_from, (*(*info).dataparams).refdx, $
              dy_from, (*(*info).dataparams).refdy, $
              xval_from, (*(*info).dataparams).xval_ref, $
              yval_from, (*(*info).dataparams).yval_ref, $
              xpix_from, (*(*info).dataparams).xpix_ref, $
              ypix_from, (*(*info).dataparams).ypix_ref)
          ENDIF ELSE BEGIN
            ; Else no mapping is occuring, so use main values
            xyp_ref = {x:xp_orig, y:yp_orig}
            xyr_ref = {x:xr_orig, y:yr_orig}
          ENDELSE
          sxyp = CRISPEX_TRANSFORM_DATA2DEVICE(info, X=xyp_ref.x, $
            Y=xyp_ref.y, /REF)
          sxyr = CRISPEX_TRANSFORM_DATA2DEVICE(info, X=xyr_ref.x, $
            Y=xyr_ref.y, /REF)
        ENDIF 
      ENDIF ELSE BEGIN
        ; Else converting to main from ref, or directly from main
        IF ((imref)[sel_loops[i]] GE 2) THEN BEGIN
          IF ((*(*info).dataswitch).wcs_set AND wcs_from_set) THEN BEGIN
            ; If WCS info available, use that for the transform
            IF (TOTAL(xp_orig LT 0) AND TOTAL(xp_orig GE nx) AND $
              TOTAL(yp_orig LT 0) AND TOTAL(yp_orig GE ny)) THEN BEGIN
              xp_main = REFORM((pix_from2main[*,xp_orig,0])[0,*])
              yp_main = REFORM((pix_from2main[*,0,yp_orig])[1,0,*])
              xyp = {x:xp_main, y:yp_main}
            ENDIF ELSE $
              xyp = CRISPEX_TRANSFORM_GET_WCS(xp_orig, yp_orig, $
                wcs_from, (*(*info).dataparams).wcs_main, /PIXEL, /COORD)
            xyr = CRISPEX_TRANSFORM_GET_WCS(xr_orig, yr_orig, $
              wcs_from, (*(*info).dataparams).wcs_main, $
              /PIXEL, /COORD, /NO_ROUND)
          ENDIF ELSE IF ((*(*info).dispswitch).main2ref_no_map EQ 0) THEN BEGIN
            ; Else, use header information for transform
            xyp = CRISPEX_TRANSFORM_COORDS(xp_orig, yp_orig, $
              dx_from, (*(*info).dataparams).dx, $
              dy_from, (*(*info).dataparams).dy, $
              xval_from, (*(*info).dataparams).xval, $
              yval_from, (*(*info).dataparams).yval, $
              xpix_from, (*(*info).dataparams).xpix, $
              ypix_from, (*(*info).dataparams).ypix)
            xyr = CRISPEX_TRANSFORM_COORDS(xr_orig, yr_orig, $
              dx_from, (*(*info).dataparams).dx, $
              dy_from, (*(*info).dataparams).dy, $
              xval_from, (*(*info).dataparams).xval, $
              yval_from, (*(*info).dataparams).yval, $
              xpix_from, (*(*info).dataparams).xpix, $
              ypix_from, (*(*info).dataparams).ypix)
          ENDIF ELSE BEGIN
            ; Else no mapping is occuring, so use main values
            xyp = {x:xp_orig, y:yp_orig}
            xyr = {x:xr_orig, y:yr_orig}
          ENDELSE
          sxyp = CRISPEX_TRANSFORM_DATA2DEVICE(info, X=xyp.x, $
            Y=xyp.y, /MAIN)
          sxyr = CRISPEX_TRANSFORM_DATA2DEVICE(info, X=xyr.x, $
            Y=xyr.y, /MAIN)
        ENDIF
      ENDELSE
			sxp_last = sxyp.x[(SIZE(sxyp.x))[1]-1]-1.5*(*(*info).zooming).factor
			syp_last = sxyp.y[(SIZE(sxyp.y))[1]-1]+1.5*(*(*info).zooming).factor
			IF ~KEYWORD_SET(NO_ENDPOINTS) THEN BEGIN
				PLOTS, sxyp.x, sxyp.y, PSYM = 1, COLOR = !P.COLOR, /DEVICE, $
          THICK=thick, SYMSIZE=symsize
				PLOTS, sxyp.x, sxyp.y, PSYM = 4, COLOR = !P.COLOR, /DEVICE, $
          THICK=thick, SYMSIZE=symsize
			ENDIF
			IF ~KEYWORD_SET(NO_NUMBER) THEN BEGIN
        text_out = STRTRIM(sel_loops[i],2)
        IF KEYWORD_SET(RETRIEVED) THEN $
          text_out = 'L'+text_out $
        ELSE IF KEYWORD_SET(DETECTION) THEN $
          text_out = 'D'+text_out
        XYOUTS,sxp_last,syp_last,text_out, /DEVICE
      ENDIF
			IF ((*(*info).overlayparams).loop_linestyle EQ 1) THEN $
        PLOTS, sxyr.x, sxyr.y, PSYM = 3, COLOR = !P.COLOR, /DEVICE, THICK=thick $
			ELSE $
        PLOTS, sxyr.x, sxyr.y, $
          LINESTYLE = (*(*info).overlayparams).loop_linestyle, COLOR = !P.COLOR,$
          /DEVICE, THICK=thick
    ENDFOR
  ENDIF
	IF (((*(*info).feedbparams).verbosity)[3] EQ 1) THEN $
    CRISPEX_VERBOSE_GET, event, [cfilecount, sel_count], labels=sel_labels
END

PRO CRISPEX_DRAW_MASK_OVERLAYS, event, REFERENCE=reference
; Handles the overlay of a mask
; Assumption throughout is that the mask has positional parameters (i.e.,
; nx/ny, dx/dy, xval/yval, etc.) identical to those of the main data
	WIDGET_CONTROL, event.TOP, GET_UVALUE = info
	IF (TOTAL(((*(*info).feedbparams).verbosity)[2:3]) GE 1) THEN $
    CRISPEX_VERBOSE_GET_ROUTINE, event
  IF KEYWORD_SET(REFERENCE) THEN BEGIN
    xcoords =[(*(*info).zooming).xrefpos,(*(*info).zooming).xrefpos + $
              (*(*info).dataparams).d_refnx]
    ycoords = [(*(*info).zooming).yrefpos,(*(*info).zooming).yrefpos + $
               (*(*info).dataparams).d_refny]
    ; Convert boundaries of reference display to main coordinate system
    IF ((*(*info).dataswitch).wcs_set AND $
      (*(*info).dataswitch).ref_wcs_set) THEN BEGIN
      ; If WCS info available, use that for the transform
      xp = REFORM(((*(*(*info).dataparams).pix_ref2main)[*,xcoords,0])[0,*])
      yp = REFORM(((*(*(*info).dataparams).pix_ref2main)[*,0,ycoords])[1,0,*])
      xy_low_upp = {x:xp, y:yp}
    ENDIF ELSE BEGIN
      ; Else use header information for transform
      xy_low_upp = CRISPEX_TRANSFORM_COORDS(xcoords, ycoords, $
        (*(*info).dataparams).refdx, (*(*info).dataparams).dx, $
        (*(*info).dataparams).refdy, (*(*info).dataparams).dy, $
        (*(*info).dataparams).xval_ref, (*(*info).dataparams).xval, $
        (*(*info).dataparams).yval_ref, (*(*info).dataparams).yval, $
        (*(*info).dataparams).xpix_ref, (*(*info).dataparams).xpix, $
        (*(*info).dataparams).ypix_ref, (*(*info).dataparams).ypix)
    ENDELSE
    ; Determine boundaries of mask to be displayed
    xcoords_new = [ROUND(xy_low_upp.x[0] > 0), $
                   ROUND(xy_low_upp.x[1] < ((*(*info).dataparams).nx-1))]
    ycoords_new = [ROUND(xy_low_upp.y[0] > 0), $
                   ROUND(xy_low_upp.y[1] < ((*(*info).dataparams).ny-1))]
    ; Convert boundaries back to reference coordinate system
    IF ((*(*info).dataswitch).wcs_set AND $
      (*(*info).dataswitch).ref_wcs_set) THEN BEGIN
      ; If WCS info available, use that for the transform
      xp = REFORM(((*(*(*info).dataparams).pix_ref2main)[*,xcoords_new,0])[0,*])
      yp = REFORM(((*(*(*info).dataparams).pix_ref2main)[*,0,ycoords_new])[1,0,*])
      xypos_low_upp = {x:xp, y:yp}
    ENDIF ELSE BEGIN
      ; Else use header information for transform
      xypos_low_upp = CRISPEX_TRANSFORM_COORDS(xcoords_new, ycoords_new, $
        (*(*info).dataparams).dx, (*(*info).dataparams).refdx, $
        (*(*info).dataparams).dy, (*(*info).dataparams).refdy, $
        (*(*info).dataparams).xval, (*(*info).dataparams).xval_ref, $
        (*(*info).dataparams).yval, (*(*info).dataparams).yval_ref, $
        (*(*info).dataparams).xpix, (*(*info).dataparams).xpix_ref, $
        (*(*info).dataparams).ypix, (*(*info).dataparams).ypix_ref)
    ENDELSE
    ; Determine offset positioning of subset of mask slice
    position = [$
      (ROUND(xypos_low_upp.x[0])-(*(*info).zooming).xrefpos) / $
        FLOAT((*(*info).dataparams).d_refnx), $
      (ROUND(xypos_low_upp.y[0])-(*(*info).zooming).yrefpos) / $
        FLOAT((*(*info).dataparams).d_refny), $
      (ROUND(xypos_low_upp.x[1])-(*(*info).zooming).xrefpos) / $
        FLOAT((*(*info).dataparams).d_refnx), $
      (ROUND(xypos_low_upp.y[1])-(*(*info).zooming).yrefpos) / $
        FLOAT((*(*info).dataparams).d_refny)]
  ENDIF ELSE BEGIN
    ; If main data, use defaults
  	xcoords_new = [(*(*info).zooming).xpos, $
  	               (*(*info).zooming).xpos + (*(*info).dataparams).d_nx]
  	ycoords_new = [(*(*info).zooming).ypos, $
  	               (*(*info).zooming).ypos + (*(*info).dataparams).d_ny]
    position = [0,0,1,1]
  ENDELSE
  TVLCT, r_cur, g_cur, b_cur, /GET
	LOADCT, (*(*info).overlayparams).maskct, /SILENT
	CONTOUR, (*(*(*info).data).maskslice)[xcoords_new[0]:xcoords_new[1],$
    ycoords_new[0]:ycoords_new[1]], LEVELS=1, $
    /ISOTROPIC, XS=13, YS=13, COLOR=(*(*info).overlayparams).maskcolor, $
    POSITION=position, /NORMAL, /NOERASE
  TVLCT, r_cur, g_cur, b_cur
END

PRO CRISPEX_DRAW_RASTER_OVERLAYS, event, REFERENCE=reference, SJI=sji, $
  IDX_SJI=idx_sji
; Handles the overlay of raster contours on REFERENCE or SJI
	WIDGET_CONTROL, event.TOP, GET_UVALUE = info
	IF (TOTAL(((*(*info).feedbparams).verbosity)[2:3]) GE 1) THEN $
    CRISPEX_VERBOSE_GET_ROUTINE, event
	LOADCT, (*(*info).overlayparams).maskct, /SILENT
  FOR i=0,(*(*info).dataparams).nx-1 DO BEGIN
    IF KEYWORD_SET(REFERENCE) THEN $
      sxyraster = CRISPEX_TRANSFORM_DATA2DEVICE(info, $
        X=(*(*(*info).dataparams).pix_main2ref)[0,i,*], $
        Y=(*(*(*info).dataparams).pix_main2ref)[1,i,*], /REF) $
    ELSE IF KEYWORD_SET(SJI) THEN $
      sxyraster = CRISPEX_TRANSFORM_DATA2DEVICE(info, $
        X=(*(*(*info).dataparams).pix_main2sji[idx_sji])[0,i,*], $
        Y=(*(*(*info).dataparams).pix_main2sji[idx_sji])[1,i,*], /SJI, $
        IDX_SJI=idx_sji)
    PLOTS, sxyraster.x, sxyraster.y, COLOR=(*(*info).overlayparams).maskcolor, /DEVICE
  ENDFOR
	LOADCT, 0, /SILENT
END

PRO CRISPEX_DRAW_RASTER_TIMING_OVERLAYS, event, MAIN=main, REFERENCE=reference,$
  SJI=sji, IDX_SJI=idx_sji
; Handles the overlay of timing raster markers on MAIN, REFERENCE or SJI
	WIDGET_CONTROL, event.TOP, GET_UVALUE = info
	IF (TOTAL(((*(*info).feedbparams).verbosity)[2:3]) GE 1) THEN $
    CRISPEX_VERBOSE_GET_ROUTINE, event
  ; Get main time array
  IF ((*(*info).dataparams).tfull_dims_main[0] GE 1) THEN $
    tarr_raster_main = REFORM((*(*info).dataparams).tarr_full_main[*, $
      (*(*info).dataparams).lp< (*(*info).dataparams).tfull_dims_main[1], $
      (*(*info).dataparams).s < (*(*info).dataparams).tfull_dims_main[2], $
      (*(*info).dispparams).t_main]) $
  ELSE $
    tarr_raster_main = (*(*info).dispparams).tarr_main
  ; Get lower and upper y-position depending on display window
  IF KEYWORD_SET(MAIN) THEN BEGIN
    ypos_low = (*(*info).zooming).ypos
    ypos_upp = (*(*info).zooming).ypos+(*(*info).dataparams).d_ny
  ENDIF
  IF KEYWORD_SET(REFERENCE) THEN BEGIN
    ypos_low = (*(*info).zooming).yrefpos
    ypos_upp = (*(*info).zooming).yrefpos+(*(*info).dataparams).d_refny
  ENDIF
  IF KEYWORD_SET(SJI) THEN BEGIN
    ypos_low = (*(*info).zooming).ysjipos[idx_sji]
    ypos_upp = (*(*info).zooming).ysjipos[idx_sji]+$
      (*(*info).dataparams).d_sjiny[idx_sji]
  ENDIF
  ; Get main x-position based on which display is master timer
  CASE (*(*info).dispparams).master_time OF
    0:  BEGIN   ; Main is master timer
          xpos_low = (*(*info).dispparams).toffset_main
        END
    1:  BEGIN   ; Reference is master timer
          IF (SIZE((*(*info).dataparams).tarr_full_ref, /N_DIMENSIONS) GT 0) THEN $
            tval_ref_sel = REFORM((*(*info).dataparams).tarr_full_ref[$
              (*(*info).dispparams).toffset_ref < $
                (*(*info).dataparams).tfull_dims_ref[0], $
              (*(*info).dataparams).lp_ref< $
                (*(*info).dataparams).tfull_dims_ref[1], $
              (*(*info).dataparams).s_ref < $
                (*(*info).dataparams).tfull_dims_ref[2], $
                (*(*info).dispparams).t_ref])
          tdiff = ABS(tarr_raster_main - tval_ref_sel)
          xpos_low = (WHERE(tdiff EQ MIN(tdiff, /NAN)))[0]
        END
    2:  BEGIN   ; SJI is master timer
          tval_sji_sel = $
            (*(*(*info).dataparams).tarr_sji[idx_sji])[(*(*info).dispparams).t_sji[idx_sji]]
          tdiff = ABS(tarr_raster_main - tval_sji_sel)
          xpos_low = (WHERE(tdiff EQ MIN(tdiff, /NAN)))[0]
        END
  ENDCASE
  xpos_upp = xpos_low
  sel_color = (*(*info).overlayparams).maskcolor
  ; Convert main x-position to REF/SJI depending on display
  IF KEYWORD_SET(REFERENCE) THEN BEGIN
    xpos_low = (*(*(*info).dataparams).pix_main2ref)[0,xpos_low,0]
    xpos_upp = (*(*(*info).dataparams).pix_main2ref)[0,xpos_upp,0]
    IF (*(*info).overlayswitch).refraster THEN $
      sel_color = (((*(*info).overlayparams).maskcolor - 200) MOD 255)
  ENDIF ELSE IF KEYWORD_SET(SJI) THEN BEGIN
    xpos_low = (*(*(*info).dataparams).pix_main2sji[idx_sji])[0,xpos_low,0]
    xpos_upp = (*(*(*info).dataparams).pix_main2sji[idx_sji])[0,xpos_upp,0]
    IF (*(*info).overlayswitch).sjiraster THEN $
      sel_color = (((*(*info).overlayparams).maskcolor - 200) MOD 255)
  ENDIF 
  ; Convert pixel coordinates to device coordinates
  xyout_low = CRISPEX_TRANSFORM_DATA2DEVICE(info, X_IN=xpos_low, $
    Y_IN=ypos_low, MAIN=KEYWORD_SET(MAIN), REF=KEYWORD_SET(REFERENCE), $
    SJI=KEYWORD_SET(SJI), IDX_SJI=idx_sji)
  xyout_upp = CRISPEX_TRANSFORM_DATA2DEVICE(info, X_IN=xpos_low, $
    Y_IN=ypos_upp, MAIN=KEYWORD_SET(MAIN), REF=KEYWORD_SET(REFERENCE), $
    SJI=KEYWORD_SET(SJI), IDX_SJI=idx_sji)
  ; Create overplot arrays and overplot
  x0 = [xyout_low.x, xyout_upp.x]
  y0 = [xyout_low.y, xyout_upp.y]
  x1 = x0
  y1 = y0 + [20,-20]
	LOADCT, (*(*info).overlayparams).maskct, /SILENT
  PLOTS,x0,[y0[0],y1[1]], COLOR=sel_color, LINE=1, /DEVICE
  FOR i=0,N_ELEMENTS(x0)-1 DO $
    ARROW, x0[i], y0[i], x1[i], y1[i], HSIZE=7, HTHICK=7, COLOR=sel_color, $
    THICK=2, /SOLID
	LOADCT, 0, /SILENT
END

PRO CRISPEX_DRAW_GET_SPECTRAL_AXES, event, MAIN=main, REFERENCE=reference
; Handles determination of TICKINTERVAL of spectral axes
  ; should be called whenever changing the number of displayed diagnostics
  ; AND on startup
	WIDGET_CONTROL, event.TOP, GET_UVALUE = info
	IF (TOTAL(((*(*info).feedbparams).verbosity)[2:3]) GE 1) THEN $
    CRISPEX_VERBOSE_GET_ROUTINE, event
  ; Write current variables to dummy variables depending on case
  IF KEYWORD_SET(MAIN) THEN BEGIN
    disp_diagnostics = (*(*info).intparams).disp_diagnostics
    ndisp_diagnostics = (*(*info).intparams).ndisp_diagnostics
    diag_width = (*(*info).intparams).diag_width
    diag_start = (*(*info).intparams).diag_start
    lp_low = (*(*info).dispparams).lp_low_tmp
    lp_upp = (*(*info).dispparams).lp_upp_tmp
    lps = (*(*info).dataparams).lps
    v_dop = (*(*info).plotaxes).v_dop
  ENDIF ELSE IF KEYWORD_SET(REFERENCE) THEN BEGIN
    disp_diagnostics = (*(*info).intparams).disp_refdiagnostics
    ndisp_diagnostics = (*(*info).intparams).ndisp_refdiagnostics
    diag_width = (*(*info).intparams).refdiag_width
    diag_start = (*(*info).intparams).refdiag_start
    lp_low = (*(*info).dispparams).lp_ref_low_tmp
    lp_upp = (*(*info).dispparams).lp_ref_upp_tmp
    lps = (*(*info).dataparams).reflps
    v_dop = (*(*info).plotaxes).v_dop_ref
  ENDIF 
  ; Determine settings from displayed diagnostics
  ; disp_diagnostics will always have at least 1 element non-zero
  wheredisp = WHERE(disp_diagnostics EQ 1)
  diag_widths = diag_width[wheredisp]
  diag_starts = diag_start[wheredisp]
  diag_ratio = diag_widths / FLOAT(TOTAL(diag_widths))
  lp_low_loc = lp_low[wheredisp]+diag_starts
  lp_upp_loc = lp_upp[wheredisp]+diag_starts
  IF (ndisp_diagnostics GT 1) THEN BEGIN
    lambda_widths = FLTARR(ndisp_diagnostics)
    dop_widths = FLTARR(ndisp_diagnostics)
    diag_widths_tmp = FLTARR(ndisp_diagnostics)
    FOR d=0,ndisp_diagnostics-1 DO BEGIN
      lambda_widths[d] = lps[lp_upp_loc[d]] - lps[lp_low_loc[d]]
      dop_widths[d] = (*v_dop[wheredisp[d]])[lp_upp[wheredisp[d]]-1] - $
                      (*v_dop[wheredisp[d]])[lp_low[wheredisp[d]]]
    ENDFOR
    diag_widths_tmp = lp_upp[wheredisp] - lp_low[wheredisp] ;+ 1
    diag_ratio = diag_widths_tmp / FLOAT(TOTAL(diag_widths_tmp))
    order = FLOOR(ALOG10(lambda_widths))
    int_widths = ROUND(lambda_widths/10^FLOAT(order))*10^FLOAT(order)
    wheremin = WHERE(int_widths EQ MIN(int_widths, /NAN, MAX=int_widths_max))
    wheremax = WHERE(int_widths EQ int_widths_max)
    ; Have at least two major tickmarks per range for the smallest range
    xtickint_def = (int_widths[wheremin]/2.)[0]
    xtickinterval = [xtickint_def, (int_widths[wheremax])[0]]
    doporder = FLOOR(ALOG10(dop_widths))
    int_dopwidths = ROUND(dop_widths/10^FLOAT(doporder))*10^FLOAT(doporder)
    wheredopmin = WHERE(int_dopwidths EQ MIN(int_dopwidths, /NAN, $
      MAX=int_dopwidths_max))
    wheredopmax = WHERE(int_dopwidths EQ int_dopwidths_max)
    ; Have at least two major tickmarks per range for the smallest range
    xdoptickint_def = (int_dopwidths[wheredopmin]/2.)[0]
    xdoptickinterval = [xdoptickint_def, (int_dopwidths[wheredopmax])[0]]
    IF (ABS((xtickinterval[0]*2.)/xtickinterval[1]) GT 0.3) THEN BEGIN
      xtickinterval /= 2.
      xdoptickinterval[0] /= 2.
    ENDIF
    ; Convert xtickinterval[1] to number of tickmarks, instead of tick value
    ; difference
    xtickinterval[1] = ROUND(xtickinterval[1]/(xtickinterval[0] > 1.))
    xdoptickinterval[1] = ROUND(xdoptickinterval[1]/((2.*xdoptickinterval[0]) > 1.))
  ENDIF ELSE BEGIN
    xtickinterval = 0
    xdoptickinterval = 0
  ENDELSE
  ; Save results to appropriate variables
  IF KEYWORD_SET(MAIN) THEN BEGIN
    *(*(*info).plotaxes).xtickinterval = xtickinterval
    *(*(*info).plotaxes).xdoptickinterval = xdoptickinterval
    ; Determine proportional spectral window sizes
    *(*(*info).intparams).wheredispdiag = wheredisp
    *(*(*info).intparams).diag_widths = diag_widths
    *(*(*info).intparams).diag_starts = diag_starts 
    *(*(*info).plotaxes).diag_ratio = diag_ratio 
    IF ((*(*info).dataparams).nlp GT 1) THEN BEGIN
      *(*(*info).plotaxes).diag_range_sp = *(*(*info).plotaxes).diag_ratio * $
        (*(*info).plotpos).xplspw 
      *(*(*info).plotaxes).diag_range_phis = *(*(*info).plotaxes).diag_ratio * $
        (*(*info).plotpos).phisxplspw
    ENDIF
    (*(*info).plotswitch).xtick_reset = 1
    (*(*info).plotswitch).xdoptick_reset = 1
  ENDIF ELSE IF KEYWORD_SET(REFERENCE) THEN BEGIN
    *(*(*info).plotaxes).xreftickinterval = xtickinterval
    *(*(*info).plotaxes).xrefdoptickinterval = xdoptickinterval
    ; Determine proportional spectral window sizes
    *(*(*info).intparams).wheredisprefdiag = wheredisp 
    *(*(*info).intparams).refdiag_widths = diag_widths
    *(*(*info).intparams).refdiag_starts = diag_starts 
    *(*(*info).plotaxes).refdiag_ratio = diag_ratio 
    IF ((*(*info).dataparams).refnlp GT 1) THEN $
      *(*(*info).plotaxes).refdiag_range_sp = *(*(*info).plotaxes).refdiag_ratio * $
        (*(*info).plotpos).refxplspw 
    (*(*info).plotswitch).xreftick_reset = 1
    (*(*info).plotswitch).xrefdoptick_reset = 1
  ENDIF
END

PRO CRISPEX_DRAW, event, NO_MAIN=no_main, NO_REF=no_ref, NO_SJI=no_sji, $
  NO_PHIS=no_phis, LS_NO_MAIN=ls_no_main, LS_NO_REF=ls_no_ref, $
  NO_TIMESLICES=no_timeslices, $
  UPDATE_MAINDATAVALS=update_maindatavals, UPDATE_REFDATAVALS=updaterefdatavals
; Handles the actual drawing of the data into the respective open display windows
	WIDGET_CONTROL, event.TOP, GET_UVALUE = info
	IF (TOTAL(((*(*info).feedbparams).verbosity)[2:3]) GE 1) THEN $
    CRISPEX_VERBOSE_GET_ROUTINE, event
	IF ((*(*info).curs).lockset AND ((*(*info).overlayswitch).loopslit NE 1) AND $
     ((*(*info).meas).spatial_measurement EQ 0)) THEN BEGIN
		(*(*info).curs).sx = (*(*info).curs).sxlock	
    (*(*info).curs).sy = (*(*info).curs).sylock
    IF ((*(*info).winids).reftlb NE 0) THEN BEGIN
      (*(*info).curs).sxref = (*(*info).curs).sxreflock
      (*(*info).curs).syref = (*(*info).curs).syreflock
    ENDIF
    IF (TOTAL((*(*info).winids).sjitlb) NE 0) THEN BEGIN
      FOR i=0,(*(*info).winswitch).nwhereshowsji-1 DO BEGIN
        idx_sji = (*(*(*info).winswitch).whereshowsji)[i]
        (*(*info).curs).sxsji[idx_sji] = (*(*info).curs).sxsjilock[idx_sji]
        (*(*info).curs).sysji[idx_sji] = (*(*info).curs).sysjilock[idx_sji]
      ENDFOR
    ENDIF
	ENDIF 
	CRISPEX_DRAW_IMREF, event, NO_MAIN=no_main, NO_REF=no_ref, NO_SJI=no_sji
	IF ((*(*info).winswitch).showls OR (*(*info).winswitch).showsp OR $
    (*(*info).winswitch).showrefls OR (*(*info).winswitch).showrefsp) OR $
    (*(*info).winswitch).showphis THEN $
      CRISPEX_DRAW_SPECTRAL, event, NO_MAIN=ls_no_main, NO_REF=ls_no_ref, $
        NO_PHIS=no_phis
	IF ((*(*info).winswitch).showloop OR (*(*info).winswitch).showrefloop OR $
    (*(*info).winswitch).showsjiloop OR (*(*info).winswitch).showrestloop OR $
    (*(*info).winswitch).showretrdet AND ~KEYWORD_SET(NO_TIMESLICES)) THEN $
      CRISPEX_DRAW_TIMESLICES, event
	IF (*(*info).winswitch).showint THEN CRISPEX_DRAW_INT, event
  CRISPEX_DRAW_FEEDBPARAMS, event, UPDATE_MAINDATAVALS=update_maindatavals, $
    UPDATE_REFDATAVALS=update_refdatavals
END

PRO CRISPEX_DRAW_FEEDBPARAMS, event, UPDATE_SJI=update_sji, $
  UPDATE_MAINDATAVALS=update_maindatavals, UPDATE_REFDATAVALS=update_refdatavals
; Prints all feedback parameters to appropriate fields
	WIDGET_CONTROL, event.TOP, GET_UVALUE = info
	IF (TOTAL(((*(*info).feedbparams).verbosity)[2:3]) GE 1) THEN $
    CRISPEX_VERBOSE_GET_ROUTINE, event
  ; Determine which reference windows are showing; if any
  showref_any = $
    ((*(*info).winswitch).showref OR (*(*info).winswitch).showrefls OR $
    (*(*info).winswitch).showrefsp)
  ; Determine which fields to update
  update_xycoords_main = ($
    ((*(*info).dataparams).x NE (*(*info).dispparams).x_old) OR $
    ((*(*info).dataparams).y NE (*(*info).dispparams).y_old))
  update_xycoords_ref = ($
    ((*(*info).dataparams).xref NE (*(*info).dispparams).xref_old) OR $
    ((*(*info).dataparams).yref NE (*(*info).dispparams).yref_old)) AND $
    showref_any
  update_xycoords_sji = ($
    (((*(*info).dataparams).xsji NE (*(*info).dispparams).xsji_old) OR $
     ((*(*info).dataparams).ysji NE (*(*info).dispparams).ysji_old)) AND $
     (*(*info).winswitch).showsji)[(*(*info).dispswitch).sji_select]
  update_lpcoords_main = $
    ((*(*info).dataparams).lp NE (*(*info).dispparams).lp_old)
  update_lpcoords_ref = $
    ((*(*info).dataparams).lp_ref NE (*(*info).dispparams).lp_ref_old) AND $
    showref_any
  update_tcoords_main = $
    ((*(*info).dispparams).t_main NE (*(*info).dispparams).t_main_old) 
  update_traster_main = (*(*info).paramswitch).t_raster AND $
    ((((*(*info).dataparams).x NE (*(*info).dispparams).x_old) AND $
      (*(*info).paramswitch).update_tfull_main[0]) OR $
     (((*(*info).dataparams).lp NE (*(*info).dispparams).lp_old) AND $
      (*(*info).paramswitch).update_tfull_main[1]) OR $
     (((*(*info).dataparams).s NE (*(*info).dispparams).s_old) AND $
      (*(*info).paramswitch).update_tfull_main[2]) OR $
     ((*(*info).dispparams).t_main NE (*(*info).dispparams).t_main_old) OR $
      ((*(*info).dispswitch).xy_out_of_range NE $
       (*(*info).dispparams).xy_out_of_range_old))
  update_tcoords_ref = showref_any AND $
    ((*(*info).dispparams).t_ref NE (*(*info).dispparams).t_ref_old) 
  update_traster_ref = (showref_any AND (*(*info).paramswitch).t_raster_ref AND $
    ((((*(*info).dataparams).xref NE (*(*info).dispparams).xref_old) AND $
      (*(*info).paramswitch).update_tfull_ref[0]) OR $
     (((*(*info).dataparams).lp_ref NE (*(*info).dispparams).lp_ref_old) AND $
      (*(*info).paramswitch).update_tfull_ref[1]) OR $
     (((*(*info).dataparams).s_ref NE (*(*info).dispparams).s_ref_old) AND $
      (*(*info).paramswitch).update_tfull_ref[2]) OR $
     ((*(*info).dispparams).t_ref NE (*(*info).dispparams).t_ref_old) OR $
      ((*(*info).dispswitch).xyref_out_of_range NE $
       (*(*info).dispparams).xyref_out_of_range_old)))
  update_tcoords_sji = $
    (((*(*info).dispparams).t_sji NE (*(*info).dispparams).t_sji_old) AND $
     (*(*info).winswitch).showsji)[(*(*info).dispswitch).sji_select]
  update_zoomfactor = $
    ((*(*info).zooming).factor NE (*(*info).zooming).factor_old)
  update_date = $
    ((*(*(*info).dispparams).date_arr)[(*(*info).dispparams).t] NE $
      (*(*info).dispparams).date_old)
  ; Switch to check whether anything has to be updated at all
  update_fields = ( ($
    update_xycoords_main+update_xycoords_ref+update_xycoords_sji+$
    update_lpcoords_main+update_lpcoords_ref+update_zoomfactor+$
    update_tcoords_main+update_tcoords_ref+update_tcoords_sji+$
    update_date + KEYWORD_SET(UPDATE_SJI)+KEYWORD_SET(UPDATE_MAINDATAVALS)+$
    KEYWORD_SET(UPDATE_REFDATAVALS)) GT 0)
  ; Proceed updating (or not)
  IF update_fields THEN BEGIN
    ; Get SJI idx, just in case
    idx_sji = (*(*info).dispswitch).sji_select
    ; Position parameters
    ; Main
    IF (update_xycoords_main OR KEYWORD_SET(UPDATE_MAINDATAVALS)) THEN BEGIN
      IF ((*(*info).dispswitch).xy_out_of_range EQ 0) THEN BEGIN
        xval = STRING(LONG((*(*info).dataparams).x), $
          FORMAT=(*(*info).paramparams).xcoord_format)
        yval = STRING(LONG((*(*info).dataparams).y), $
          FORMAT=(*(*info).paramparams).ycoord_format)
        IF (*(*info).dataswitch).wcs_set THEN BEGIN
          xy_real = CRISPEX_TRANSFORM_GET_WCS((*(*info).dataparams).x, $
            (*(*info).dataparams).y, (*(*info).dataparams).wcs_main, $
            /COORD, /NO_ROUND)
          xreal_val = xy_real.x
          yreal_val = xy_real.y
        ENDIF ELSE BEGIN
          xreal_val = FLOAT(xval*(*(*info).dataparams).dx)
          yreal_val = FLOAT(yval*(*(*info).dataparams).dy)
        ENDELSE
        xval_real = STRING(xreal_val, $
          FORMAT=(*(*info).paramparams).xcoord_real_format)
        yval_real = STRING(yreal_val, $
          FORMAT=(*(*info).paramparams).ycoord_real_format)
      ENDIF ELSE BEGIN
        xval = 'N/A'
        yval = xval
        xval_real = xval 
        yval_real = xval
      ENDELSE
      WIDGET_CONTROL, (*(*info).ctrlsparam).xycoord_val, $
        SET_VALUE='('+xval+','+yval+')'
      WIDGET_CONTROL, (*(*info).ctrlsparam).xycoord_real_val, $
        SET_VALUE='('+xval_real+','+yval_real+')'
    ENDIF
    ; Reference
    IF (update_xycoords_ref OR KEYWORD_SET(UPDATE_REFDATAVALS)) THEN BEGIN
      xrefval = 'N/A'
      yrefval = xrefval
      xrefval_real = xrefval 
      yrefval_real = xrefval
      IF (showref_any AND $
        ((*(*info).dispswitch).xyref_out_of_range EQ 0)) THEN BEGIN
        xrefval = STRING(LONG((*(*info).dataparams).xref), $
          FORMAT=(*(*info).paramparams).refxcoord_format)
        yrefval = STRING(LONG((*(*info).dataparams).yref), $
          FORMAT=(*(*info).paramparams).refycoord_format)
        IF (*(*info).dataswitch).ref_wcs_set THEN BEGIN
          xyref_real = CRISPEX_TRANSFORM_GET_WCS((*(*info).dataparams).xref, $
            (*(*info).dataparams).yref, *(*(*info).dataparams).wcs_ref, $
            /COORD, /NO_ROUND)
          xreal_val = xyref_real.x
          yreal_val = xyref_real.y
        ENDIF ELSE BEGIN
          xreal_val = FLOAT(xrefval*(*(*info).dataparams).refdx)
          yreal_val = FLOAT(yrefval*(*(*info).dataparams).refdy)
        ENDELSE
        xrefval_real = STRING(xreal_val, $
          FORMAT=(*(*info).paramparams).refxcoord_real_format)
        yrefval_real = STRING(yreal_val, $
          FORMAT=(*(*info).paramparams).refycoord_real_format)
      ENDIF 
      WIDGET_CONTROL, (*(*info).ctrlsparam).refxycoord_val, $
        SET_VALUE='('+xrefval+','+yrefval+')'
      WIDGET_CONTROL, (*(*info).ctrlsparam).refxycoord_real_val, $
        SET_VALUE='('+xrefval_real+','+yrefval_real+')'
    ENDIF
    ; SJI
    IF (update_xycoords_sji OR KEYWORD_SET(UPDATE_SJI)) THEN BEGIN
      xsjival = 'N/A'
      ysjival = xsjival
      xsjival_real = xsjival 
      ysjival_real = xsjival
      IF ((*(*info).winswitch).showsji[idx_sji] AND $
        ((*(*info).dispswitch).xysji_out_of_range[idx_sji] EQ 0)) THEN BEGIN
        xsjival = STRING(LONG((*(*info).dataparams).xsji[idx_sji]), $
          FORMAT=(*(*info).paramparams).sjixcoord_format)
        ysjival = STRING(LONG((*(*info).dataparams).ysji[idx_sji]), $
          FORMAT=(*(*info).paramparams).sjiycoord_format)
        IF (*(*info).dataswitch).sji_wcs_set[idx_sji] THEN BEGIN
          xysji_real = CRISPEX_TRANSFORM_GET_WCS(/COORD, /NO_ROUND, $
            (*(*info).dataparams).xsji[idx_sji], $
            (*(*info).dataparams).ysji[idx_sji], $
            *(*(*info).dataparams).wcs_sji[idx_sji])
          xreal_val = xysji_real.x
          yreal_val = xysji_real.y
        ENDIF ELSE BEGIN
          xreal_val = FLOAT(xsjival*(*(*info).dataparams).sjidx[idx_sji])
          yreal_val = FLOAT(ysjival*(*(*info).dataparams).sjidy[idx_sji])
        ENDELSE
        xsjival_real = STRING(xreal_val, $
          FORMAT=(*(*info).paramparams).sjixcoord_real_format)
        ysjival_real = STRING(yreal_val, $
          FORMAT=(*(*info).paramparams).sjiycoord_real_format)
      ENDIF 
      WIDGET_CONTROL, (*(*info).ctrlsparam).sjixycoord_val, $
        SET_VALUE='('+xsjival+','+ysjival+')'
      WIDGET_CONTROL, (*(*info).ctrlsparam).sjixycoord_real_val, $
        SET_VALUE='('+xsjival_real+','+ysjival_real+')'
    ENDIF
  
    ; Spectral parameters
    ; Main
    IF (update_lpcoords_main OR KEYWORD_SET(UPDATE_MAINDATAVALS)) THEN BEGIN
      lp_idx_txt = STRING((*(*info).dataparams).lp, $
        FORMAT=(*(*info).paramparams).lp_idx_format)
      WIDGET_CONTROL, (*(*info).ctrlsparam).lp_idx_val, SET_VALUE=lp_idx_txt
      IF ((*(*info).plotswitch).heightset OR $
          (*(*info).plotswitch).v_dop_set) THEN BEGIN
        lp_real_txt = STRING((*(*info).dataparams).lps[(*(*info).dataparams).lp], $
          FORMAT=(*(*info).paramparams).lp_real_format)
        WIDGET_CONTROL, (*(*info).ctrlsparam).lp_real_val, SET_VALUE=lp_real_txt
      ENDIF
      IF (*(*info).plotswitch).v_dop_set THEN BEGIN
        lp_vdop_txt = STRING((*(*(*info).plotaxes).v_dop[$
          (*(*info).intparams).lp_diag_all])[$
          (*(*info).dataparams).lp-(*(*info).intparams).diag_start[$
          (*(*info).intparams).lp_diag_all]], $
          FORMAT=(*(*info).paramparams).lp_vdop_format)
        WIDGET_CONTROL, (*(*info).ctrlsparam).lp_vdop_val, SET_VALUE=lp_vdop_txt
      ENDIF
    ENDIF
    ; Reference
    IF showref_any THEN BEGIN
      lp_ref_idx_txt = 'N/A'
      lp_ref_real_txt = lp_ref_idx_txt
      lp_ref_vdop_txt = lp_ref_idx_txt
      IF (update_lpcoords_ref OR KEYWORD_SET(UPDATE_REFDATAVALS)) THEN BEGIN
        lp_ref_idx_txt = STRING((*(*info).dataparams).lp_ref, $
          FORMAT=(*(*info).paramparams).lp_ref_idx_format)
      IF ((*(*info).plotswitch).refheightset OR $
          (*(*info).plotswitch).v_dop_set_ref) THEN BEGIN
        WIDGET_CONTROL, (*(*info).ctrlsparam).lp_ref_idx_val, $
          SET_VALUE=lp_ref_idx_txt
          lp_ref_real_txt = STRING((*(*info).dataparams).reflps[$
            (*(*info).dataparams).lp_ref], $
            FORMAT=(*(*info).paramparams).lp_ref_real_format)
          WIDGET_CONTROL, (*(*info).ctrlsparam).lp_ref_real_val, $
            SET_VALUE=lp_ref_real_txt
        ENDIF
        IF (*(*info).plotswitch).v_dop_set_ref THEN BEGIN
          lp_ref_vdop_txt = STRING((*(*(*info).plotaxes).v_dop_ref[$
            (*(*info).intparams).lp_ref_diag_all])[(*(*info).dataparams).lp_ref-$
            (*(*info).intparams).refdiag_start[$
            (*(*info).intparams).lp_ref_diag_all]], $
            FORMAT=(*(*info).paramparams).lp_ref_vdop_format)
          WIDGET_CONTROL, (*(*info).ctrlsparam).lp_ref_vdop_val, $
            SET_VALUE=lp_ref_vdop_txt
        ENDIF
      ENDIF
    ENDIF
  
    ; Time parameters
    ; Main
    IF (update_tcoords_main OR KEYWORD_SET(UPDATE_MAINDATAVALS)) THEN BEGIN
      t_idx_txt = STRING(LONG((*(*info).dispparams).t_main),$
        FORMAT=(*(*info).paramparams).t_idx_format)
      WIDGET_CONTROL, (*(*info).ctrlsparam).t_idx_val, SET_VALUE=t_idx_txt
      IF ((*(*info).paramswitch).dt_set AND $
         ((*(*info).dataparams).mainnt GT 1)) THEN BEGIN
        t_real_txt = STRING((*(*(*info).dispparams).utc_main)[$
          (*(*info).dispparams).t],FORMAT=(*(*info).paramparams).t_real_format)
        WIDGET_CONTROL, (*(*info).ctrlsparam).t_real_val, SET_VALUE=t_real_txt
      ENDIF
    ENDIF
    IF (update_traster_main OR (KEYWORD_SET(UPDATE_MAINDATAVALS) AND $
      (*(*info).paramswitch).t_raster)) THEN BEGIN
      ; Raster time
      IF ((*(*info).dispswitch).xy_out_of_range EQ 0) THEN $
        t_raster_real_txt = STRING((*(*info).dataparams).utc_full_main[$
          (*(*info).dataparams).x < (*(*info).dataparams).tfull_dims_main[0], $
          (*(*info).dataparams).lp< (*(*info).dataparams).tfull_dims_main[1], $
          (*(*info).dataparams).s < (*(*info).dataparams).tfull_dims_main[2], $
          (*(*info).dispparams).t_main < (*(*info).dataparams).tfull_dims_main[3]], $
          FORMAT=(*(*info).paramparams).t_raster_real_format) $
      ELSE $
        t_raster_real_txt = 'N/A'
      WIDGET_CONTROL, (*(*info).ctrlsparam).t_raster_real_val, $
        SET_VALUE=t_raster_real_txt
    ENDIF
    ; Reference
    IF showref_any THEN BEGIN
      t_ref_idx_txt = 'N/A'
      t_ref_real_txt = t_ref_idx_txt
      t_raster_ref_real_txt = t_ref_idx_txt
      IF (update_tcoords_ref OR KEYWORD_SET(UPDATE_REFDATAVALS)) THEN BEGIN
        ; Closest to master time
        t_ref_idx_txt = STRING(LONG((*(*info).dispparams).t_ref),$
          FORMAT=(*(*info).paramparams).t_ref_idx_format)
        WIDGET_CONTROL, (*(*info).ctrlsparam).t_ref_idx_val, $
          SET_VALUE=t_ref_idx_txt
        IF (*(*info).paramswitch).dt_set THEN BEGIN
          t_ref_real_txt = $
            STRING((*(*(*info).dispparams).utc_ref)[(*(*info).dispparams).t],$
            FORMAT=(*(*info).paramparams).t_ref_real_format)
          WIDGET_CONTROL, (*(*info).ctrlsparam).t_ref_real_val, $
            SET_VALUE=t_ref_real_txt
        ENDIF
      ENDIF
      IF ((update_traster_ref OR KEYWORD_SET(UPDATE_REFDATAVALS)) AND $
          ((*(*info).ctrlsparam).t_raster_ref_real_val NE 0)) THEN BEGIN
        ; Raster time
        IF ((*(*info).dispswitch).xyref_out_of_range EQ 0) THEN $
          t_raster_ref_real_txt = STRING((*(*info).dataparams).utc_full_ref[$
            (*(*info).dataparams).xref  < (*(*info).dataparams).tfull_dims_ref[0], $
            (*(*info).dataparams).lp_ref< (*(*info).dataparams).tfull_dims_ref[1], $
            (*(*info).dataparams).s_ref < (*(*info).dataparams).tfull_dims_ref[2], $
            (*(*info).dispparams).t_ref < (*(*info).dataparams).tfull_dims_ref[3]], $
            FORMAT=(*(*info).paramparams).t_raster_ref_real_format) 
        WIDGET_CONTROL, (*(*info).ctrlsparam).t_raster_ref_real_val, $
          SET_VALUE=t_raster_ref_real_txt
      ENDIF
    ENDIF
    ; SJI
    IF (update_tcoords_sji OR KEYWORD_SET(UPDATE_SJI)) THEN BEGIN
      t_sji_idx_txt = 'N/A'
      t_sji_real_txt = t_sji_idx_txt
      IF ((*(*info).winswitch).showsji[idx_sji] AND $
          ((*(*info).dataparams).sjint[idx_sji] GT 1)) THEN BEGIN
        t_sji_idx_txt = STRING(LONG((*(*info).dispparams).t_sji[idx_sji]), $
          FORMAT=(*(*info).paramparams).t_sji_idx_format)
        IF (*(*info).paramswitch).dt_set THEN $
          t_sji_real_txt = STRING((*(*(*info).dispparams).utc_sji[idx_sji])[$
            (*(*info).dispparams).t],$
            FORMAT=(*(*info).paramparams).t_sji_real_format)
      ENDIF
      WIDGET_CONTROL, (*(*info).ctrlsparam).t_sji_idx_val, $
        SET_VALUE=t_sji_idx_txt
      WIDGET_CONTROL, (*(*info).ctrlsparam).t_sji_real_val, $
        SET_VALUE=t_sji_real_txt
    ENDIF
  
    ; Data values parameters
    ; Main
    IF (update_xycoords_main OR update_lpcoords_main OR $
      update_tcoords_main OR KEYWORD_SET(UPDATE_MAINDATAVALS)) THEN BEGIN
      IF ((*(*info).dispswitch).xy_out_of_range EQ 0) THEN BEGIN 
        datadims = SIZE(*(*(*info).data).xyslice,/N_DIMENSIONS)
        IF (datadims EQ 2) THEN $
          act_dataval = (*(*(*info).data).xyslice)[LONG((*(*info).dataparams).x), $
            LONG((*(*info).dataparams).y)] $
        ELSE $  ; Failsafe for IRIS sit-and-stare
          act_dataval = (*(*(*info).data).xyslice)[LONG((*(*info).dataparams).y)]
        IF ((FINITE(act_dataval) EQ 1) AND (act_dataval NE 0)) THEN $
          order = FLOOR(ALOG10(ABS(act_dataval))) $
        ELSE $
          order = 0
        IF ((order LE -2) OR (order GE 3)) THEN $
          ; Will use E-notation, so need more digits
          format = '(E11.4)' $
        ELSE $
          format = '(F10.2)'
        dataval_real_txt = STRING(act_dataval, FORMAT=format) 
      ENDIF ELSE $
        dataval_real_txt = 'N/A'
      WIDGET_CONTROL, (*(*info).ctrlsparam).dataval_real_val, $
        SET_VALUE=dataval_real_txt
    ENDIF
    ; Reference
    IF ((update_xycoords_ref OR update_lpcoords_ref OR update_tcoords_ref) OR $
      KEYWORD_SET(UPDATE_REFDATAVALS)) THEN BEGIN
      dataval_ref_real_txt = 'N/A'
      IF (showref_any AND ((*(*info).dispswitch).xyref_out_of_range EQ 0)) THEN BEGIN
        datadims = SIZE(*(*(*info).data).refslice,/N_DIMENSIONS)
        IF (datadims EQ 2) THEN $
          act_ref_dataval = (*(*(*info).data).refslice)[$
            LONG((*(*info).dataparams).xref), LONG((*(*info).dataparams).yref)] $
        ELSE $  ; Failsafe for IRIS sit-and-stare
          act_ref_dataval = (*(*(*info).data).refslice)[$
            LONG((*(*info).dataparams).yref)]
        IF ((FINITE(act_ref_dataval) EQ 1) AND (act_ref_dataval NE 0)) THEN $
          order = FLOOR(ALOG10(ABS(act_ref_dataval))) $
        ELSE $
          order = 0
        IF ((order LE -2) OR (order GE 3)) THEN $
          ; Will use E-notation, so need more digits
          format = '(E11.4)' $
        ELSE $
          format = '(F10.2)'
        dataval_ref_real_txt = STRING(act_ref_dataval, FORMAT=format)
      ENDIF
      WIDGET_CONTROL, (*(*info).ctrlsparam).dataval_ref_real_val, $
        SET_VALUE=dataval_ref_real_txt
    ENDIF
    ; SJI
    IF ((update_xycoords_sji OR update_tcoords_sji) OR $
      KEYWORD_SET(UPDATE_SJI)) THEN BEGIN
      dataval_sji_real_txt = 'N/A'
      IF ((*(*info).winswitch).showsji[idx_sji] AND $
        ((*(*info).dispswitch).xysji_out_of_range[idx_sji] EQ 0)) THEN BEGIN
        act_sji_dataval = (*(*(*info).data).sjislice[idx_sji])[$
          LONG((*(*info).dataparams).xsji[idx_sji]), $
          LONG((*(*info).dataparams).ysji[idx_sji])]
        IF ((FINITE(act_sji_dataval) EQ 1) AND (act_sji_dataval NE 0)) THEN $
          order = FLOOR(ALOG10(ABS(act_sji_dataval))) $
        ELSE $
          order = 0
        IF ((order LE -2) OR (order GE 3)) THEN $
          ; Will use E-notation, so need more digits
          format = '(E11.4)' $
        ELSE $
          format = '(F10.2)'
        dataval_sji_real_txt = STRING(act_sji_dataval, FORMAT=format)
      ENDIF 
      WIDGET_CONTROL, (*(*info).ctrlsparam).dataval_sji_real_val, $
        SET_VALUE=dataval_sji_real_txt
    ENDIF
  
    ; Date value
    IF update_date THEN $
      WIDGET_CONTROL, (*(*info).ctrlsparam).date_val, $
        SET_VALUE=(*(*(*info).dispparams).date_arr)[(*(*info).dispparams).t]
  
    ; Zoom value
    IF update_zoomfactor THEN $
    	WIDGET_CONTROL, (*(*info).ctrlsparam).zoom_val, $
        SET_VALUE = STRING((*(*info).zooming).factor*100.,FORMAT='(I4)')+'%'
  ENDIF
  ; Set new "old" dispparams
  (*(*info).dispparams).x_old = (*(*info).dataparams).x 
  (*(*info).dispparams).y_old = (*(*info).dataparams).y 
  (*(*info).dispparams).xref_old = (*(*info).dataparams).xref 
  (*(*info).dispparams).yref_old = (*(*info).dataparams).yref 
  (*(*info).dispparams).xsji_old = (*(*info).dataparams).xsji 
  (*(*info).dispparams).ysji_old = (*(*info).dataparams).ysji 
  (*(*info).dispparams).lp_old = (*(*info).dataparams).lp 
  (*(*info).dispparams).lp_ref_old = (*(*info).dataparams).lp_ref 
  (*(*info).dispparams).s_old = (*(*info).dataparams).s
  (*(*info).dispparams).s_ref_old = (*(*info).dataparams).s_ref
  (*(*info).dispparams).t_main_old = (*(*info).dispparams).t_main 
  (*(*info).dispparams).t_ref_old = (*(*info).dispparams).t_ref 
  (*(*info).dispparams).t_sji_old = (*(*info).dispparams).t_sji
  (*(*info).dispparams).date_old = $
    (*(*(*info).dispparams).date_arr)[(*(*info).dispparams).t]
  (*(*info).dispparams).xy_out_of_range_old = $
    (*(*info).dispswitch).xy_out_of_range
  (*(*info).dispparams).xyref_out_of_range_old = $
    (*(*info).dispswitch).xyref_out_of_range
END

PRO CRISPEX_DRAW_IMREF, event, NO_MAIN=no_main, NO_REF=no_ref, NO_SJI=no_sji
; (Re)draw main and reference image window procedure
	WIDGET_CONTROL, event.TOP, GET_UVALUE = info
	IF (TOTAL(((*(*info).feedbparams).verbosity)[2:3]) GE 1) THEN $
    CRISPEX_VERBOSE_GET_ROUTINE, event
	IF ~KEYWORD_SET(NO_MAIN) THEN $
    CRISPEX_DRAW_XY, event
	IF (~KEYWORD_SET(NO_REF) AND (*(*info).winswitch).showref) THEN $
    CRISPEX_DRAW_REF, event
	IF (*(*info).winswitch).showimref THEN CRISPEX_DRAW_IMREF_BLINK, event
	IF (*(*info).winswitch).showdop THEN CRISPEX_DRAW_DOPPLER, event
  IF (~KEYWORD_SET(NO_SJI) AND (TOTAL((*(*info).winswitch).showsji) GT 0)) THEN $
    CRISPEX_DRAW_SJI, event
END

PRO CRISPEX_DRAW_SPECTRAL, event, NO_MAIN=no_main, NO_REF=no_ref, NO_PHIS=no_phis
; (Re)draw spectral windows procedure
	WIDGET_CONTROL, event.TOP, GET_UVALUE = info
	IF (TOTAL(((*(*info).feedbparams).verbosity)[2:3]) GE 1) THEN $
    CRISPEX_VERBOSE_GET_ROUTINE, event
  IF (~KEYWORD_SET(NO_MAIN) AND $
    ((*(*info).winswitch).showls OR (*(*info).winswitch).showsp)) THEN $
      CRISPEX_DRAW_SPECTRAL_MAIN, event
	IF (~KEYWORD_SET(NO_REF) AND $
    ((*(*info).winswitch).showrefls OR (*(*info).winswitch).showrefsp)) THEN $
      CRISPEX_DRAW_SPECTRAL_REF, event
	IF (~KEYWORD_SET(NO_PHIS) AND $
      ((*(*info).winswitch).showphis AND (((*(*info).pbparams).mode EQ 'PAUSE') OR $
      (*(*info).dispparams).phislice_update))) THEN CRISPEX_DRAW_PHIS, event		
END

PRO CRISPEX_DRAW_TIMESLICES, event
; (Re)draw timeslices procedure
	WIDGET_CONTROL, event.TOP, GET_UVALUE = info
	IF (TOTAL(((*(*info).feedbparams).verbosity)[2:3]) GE 1) THEN $
    CRISPEX_VERBOSE_GET_ROUTINE, event
	IF (*(*info).winswitch).showloop THEN CRISPEX_DRAW_LOOPSLAB, event 
	IF (*(*info).winswitch).showrefloop THEN CRISPEX_DRAW_REFLOOPSLAB, event 
	IF (*(*info).winswitch).showsjiloop THEN CRISPEX_DRAW_SJILOOPSLAB, event 
	IF (*(*info).winswitch).showrestloop THEN CRISPEX_DRAW_REST_LOOP, event
	IF (*(*info).winswitch).showretrdet THEN CRISPEX_DRAW_RETR_DET, event
END

PRO CRISPEX_DRAW_SUBCOLOR, event, dispdata, subcolor, $ 
  XYRANGE=xyrange, SJI=sji, REFERENCE=reference, IDX_SJI=idx_sji
; Determines the color beneath the cursor to get the cursor color
	WIDGET_CONTROL, event.TOP, GET_UVALUE = info
	IF (TOTAL(((*(*info).feedbparams).verbosity)[2:3]) GE 1) THEN $
    CRISPEX_VERBOSE_GET_ROUTINE, event
	IF (N_ELEMENTS(XYRANGE) EQ 0) THEN BEGIN
    IF KEYWORD_SET(SJI) THEN BEGIN
      xcurs = LONG((*(*info).dataparams).xsji[idx_sji] - $
                   (*(*info).zooming).xsjipos[idx_sji])
      ycurs = LONG((*(*info).dataparams).ysji[idx_sji] - $
                   (*(*info).zooming).ysjipos[idx_sji])
    ENDIF ELSE IF KEYWORD_SET(REFERENCE) THEN BEGIN
      xcurs = LONG((*(*info).dataparams).xref - (*(*info).zooming).xrefpos)
      ycurs = LONG((*(*info).dataparams).yref - (*(*info).zooming).yrefpos)
    ENDIF ELSE BEGIN
      xcurs = LONG((*(*info).dataparams).x - (*(*info).zooming).xpos)
      ycurs = LONG((*(*info).dataparams).y - (*(*info).zooming).ypos)
    ENDELSE
    sizedata = SIZE(dispdata)
    xfirst = 0          & xlast = sizedata[1] - 1
    yfirst = 0          & ylast = sizedata[2] - 1
    dxy = 1
    x_upp = xcurs+dxy > xfirst < xlast
    x_low = xcurs-dxy > xfirst < xlast
    y_upp = ycurs+dxy > yfirst < ylast
    y_low = ycurs-dxy > yfirst < ylast
	ENDIF ELSE BEGIN
		x_low = xyrange[0]	&	x_upp = xyrange[1]
		y_low = xyrange[2]	&	y_upp = xyrange[3]
	ENDELSE
	subcolor = MEAN(dispdata[x_low:x_upp, y_low:y_upp], /NAN)
	IF (((*(*info).feedbparams).verbosity)[3] EQ 1) THEN $
    CRISPEX_VERBOSE_GET, event, [x_low,x_upp,y_low,y_upp,subcolor], $
      labels=['x_low','x_upp','y_low','y_upp','subcolor']
END

PRO CRISPEX_DRAW_SCALING, event, finalimage, minimum, maximum, $
  MAIN=main, DOPPLER=doppler, REFERENCE=reference, SJI=sji, $
  SELECTED_DATA=selected_data, IDX_SJI=idx_sji
; Determines the minimum and maximum value for the image scaling
	WIDGET_CONTROL, event.TOP, GET_UVALUE = info
	IF (TOTAL(((*(*info).feedbparams).verbosity)[2:3]) GE 1) THEN $
    CRISPEX_VERBOSE_GET_ROUTINE, event
	x_low = (*(*info).zooming).xpos
	y_low = (*(*info).zooming).ypos
  x_upp = (*(*info).zooming).xpos + (*(*info).dataparams).d_nx
  y_upp = (*(*info).zooming).ypos + (*(*info).dataparams).d_ny
  IF (KEYWORD_SET(SJI) AND (*(*info).dataswitch).sjifile) THEN BEGIN
  	xsji_low = (*(*info).zooming).xsjipos[idx_sji] 
  	ysji_low = (*(*info).zooming).ysjipos[idx_sji]
    xsji_upp = (*(*info).zooming).xsjipos[idx_sji] + $
                (*(*info).dataparams).d_sjinx[idx_sji]
    ysji_upp = (*(*info).zooming).ysjipos[idx_sji] + $
                (*(*info).dataparams).d_sjiny[idx_sji]
  ENDIF
  IF (KEYWORD_SET(REFERENCE) AND (*(*info).dataswitch).reffile) THEN BEGIN
  	xref_low = (*(*info).zooming).xrefpos
  	yref_low = (*(*info).zooming).yrefpos
    xref_upp = (*(*info).zooming).xrefpos + (*(*info).dataparams).d_refnx
    yref_upp = (*(*info).zooming).yrefpos + (*(*info).dataparams).d_refny
  ENDIF
  ; sel = 0 -> main
  ; sel = 1 -> reference
  ; sel = 2 -> doppler
  ; sel = 3 -> sji
  ; imagescale = 0 -> based on first
  ; imagescale = 1 -> based on current
  ; imagescale = 2 -> per time step
  IF KEYWORD_SET(MAIN) THEN sel = 0 $
    ELSE IF KEYWORD_SET(REFERENCE) THEN sel = 1 $
    ELSE IF KEYWORD_SET(DOPPLER) THEN sel = 2 $
    ELSE IF KEYWORD_SET(SJI) THEN sel = 3
  scale_idx = ((sel EQ 0) OR (sel EQ 2)) * (*(*info).intparams).lp_diag_all + $
    ((sel GT 0) + (sel GT 2)) * (*(*info).intparams).ndiagnostics + $
    (sel EQ 1) * (*(*info).intparams).lp_ref_diag_all + $
    (sel GT 1) * (*(*info).intparams).nrefdiagnostics 
  IF KEYWORD_SET(MAIN) THEN BEGIN
   ; sel = 0
    datadims = SIZE(*(*(*info).data).xyslice,/N_DIMENSIONS)
    IF (N_ELEMENTS(SELECTED_DATA) LT 1) THEN BEGIN
      IF (datadims EQ 2) THEN $
        selected_data = (*(*(*info).data).xyslice)[x_low:x_upp,y_low:y_upp] $
      ELSE $
        selected_data = (*(*(*info).data).xyslice)[y_low:y_upp]
    ENDIF
		IF ((*(*(*info).scaling).imagescale)[sel] EQ 0) THEN BEGIN
      minimum = (*(*info).scaling).imagemin
      maximum = (*(*info).scaling).imagemax
    ENDIF ELSE IF ((*(*(*info).scaling).imagescale)[sel] EQ 1) THEN BEGIN
      minimum = (*(*info).scaling).imagemin_curr
      maximum = (*(*info).scaling).imagemax_curr
    ENDIF
  ENDIF ELSE IF KEYWORD_SET(REFERENCE) THEN BEGIN
    ; sel = 1
    datadims = SIZE(*(*(*info).data).refslice,/N_DIMENSIONS)
    IF (N_ELEMENTS(SELECTED_DATA) LT 1) THEN BEGIN
      IF (datadims EQ 2) THEN $
        selected_data = (*(*(*info).data).refslice)[$
          xref_low:xref_upp,yref_low:yref_upp] $
      ELSE $
        selected_data = (*(*(*info).data).refslice)[yref_low:yref_upp]
    ENDIF
  	IF ((*(*(*info).scaling).imagescale)[sel] EQ 0) THEN BEGIN
      minimum = (*(*info).scaling).refmin
      maximum = (*(*info).scaling).refmax
    ENDIF ELSE IF ((*(*(*info).scaling).imagescale)[sel] EQ 1) THEN BEGIN
      minimum = (*(*info).scaling).refmin_curr
      maximum = (*(*info).scaling).refmax_curr
    ENDIF 
  ENDIF ELSE IF KEYWORD_SET(DOPPLER) THEN BEGIN
    ; sel = 2
    datadims = SIZE(*(*(*info).data).dopslice,/N_DIMENSIONS)
    IF (N_ELEMENTS(SELECTED_DATA) LT 1) THEN BEGIN
      IF (datadims EQ 2) THEN $
        selected_data = (*(*(*info).data).dopslice)[x_low:x_upp,y_low:y_upp] $
      ELSE $
        selected_data = (*(*(*info).data).dopslice)[y_low:y_upp]
    ENDIF
		IF ((*(*(*info).scaling).imagescale)[sel] EQ 0) THEN BEGIN
      minimum = (*(*info).scaling).dopmin
      maximum = (*(*info).scaling).dopmax
    ENDIF ELSE IF ((*(*(*info).scaling).imagescale)[sel] EQ 1) THEN BEGIN
      minimum = (*(*info).scaling).dopmin_curr
      maximum = (*(*info).scaling).dopmax_curr
    ENDIF
  ENDIF ELSE IF KEYWORD_SET(SJI) THEN BEGIN
   ; sel = 3
    scale_idx += idx_sji
    IF (N_ELEMENTS(SELECTED_DATA) LT 1) THEN $
      selected_data = (*(*(*info).data).sjislice[idx_sji])[$
        xsji_low:xsji_upp,ysji_low:ysji_upp]
    IF ((*(*(*info).scaling).imagescale)[sel] EQ 0) THEN BEGIN
      minimum = (*(*info).scaling).sjimin[idx_sji]
      maximum = (*(*info).scaling).sjimax[idx_sji]
    ENDIF ELSE IF ((*(*(*info).scaling).imagescale)[sel] EQ 1) THEN BEGIN
      minimum = (*(*info).scaling).sjimin_curr[idx_sji]
      maximum = (*(*info).scaling).sjimax_curr[idx_sji]
    ENDIF
  ENDIF
  IF ((*(*info).scaling).gamma[scale_idx] NE 1.) THEN BEGIN
    wherelt0 = WHERE(selected_data LT 0, count)
    IF (count LE 0) THEN $
      selected_data = $
        (TEMPORARY(selected_data))^(*(*info).scaling).gamma[scale_idx] $
    ELSE BEGIN
      selected_data = $
        (TEMPORARY(ABS(selected_data)))^(*(*info).scaling).gamma[scale_idx]
      selected_data[wherelt0] *= -1
    ENDELSE
  ENDIF
  IF ((*(*(*info).scaling).imagescale)[sel] EQ 2) THEN BEGIN
    selected_data = IRIS_HISTO_OPT(TEMPORARY(selected_data), $
      (*(*info).scaling).histo_opt_val[scale_idx], MISSING=-32768, /SILENT)
    minimum = MIN(selected_data, MAX=maximum, /NAN)
  ENDIF
  minmax = CRISPEX_SCALING_CONTRAST(minimum,maximum,$
    (*(*info).scaling).minimum[scale_idx],(*(*info).scaling).maximum[scale_idx])
  minimum = minmax[0]
  maximum = minmax[1]
	finalimage = BYTSCL(selected_data, MIN=minimum, MAX=maximum, /NAN) 
	IF (((*(*info).feedbparams).verbosity)[3] EQ 1) THEN $
    CRISPEX_VERBOSE_GET, event, [minimum,maximum], labels=['minimum','maximum']
END

PRO CRISPEX_DRAW_XY, event, no_cursor=no_cursor, no_number=no_number, $
  thick=thick, no_endpoints=no_endpoints, symsize=symsize, asecbar=asecbar
; (Re)draw main image procedure
	WIDGET_CONTROL, event.TOP, GET_UVALUE = info
	IF (TOTAL(((*(*info).feedbparams).verbosity)[2:3]) GE 1) THEN $
    CRISPEX_VERBOSE_GET_ROUTINE, event
	CRISPEX_DRAW_SCALING, event, imdisp, minimum, maximum, /MAIN
  IF ((*(*(*info).scaling).imagescale)[0] EQ 2) AND $
     ((*(*info).dispparams).t_main NE (*(*info).dispparams).t_main_old) THEN $
    CRISPEX_DRAW_CTBAR, event, /MAIN, MINIMUM=minimum, MAXIMUM=maximum
	WSET, (*(*info).winids).imwid
  TVLCT, (*(*info).plotparams).rgb_main
  TV, CONGRID(imdisp,(*(*info).winsizes).xywinx, (*(*info).winsizes).xywiny)
	CRISPEX_DRAW_SUBCOLOR, event, imdisp, subcolor
	IF (subcolor GE 122) THEN curscolor = 0 ELSE curscolor = 255
	CRISPEX_DRAW_CURSCROSS_PLOT, event, curscolor, NO_CURSOR=no_cursor, $
    NO_NUMBER=no_number, THICK=thick, NO_ENDPOINTS=no_endpoints, SYMSIZE=symsize, $
		DRAW_MASK=((*(*info).overlayswitch).mask AND $
              ((*(*info).overlayswitch).maskim)[0])
	IF KEYWORD_SET(ASECBAR) THEN BEGIN
		xlow = 25							& 	ylow = 25 
		xupp = xlow + (*(*info).savparams).overlays_asecbar_pix		
    yupp = ylow + 15 + (*(*info).savparams).overlays_thick
		asecbarcol = 255
    LOADCT,0,/SILENT
		PLOTS, [xlow,xupp],[ylow,ylow], THICK=(*(*info).savparams).overlays_thick, $
      COLOR=asecbarcol, /DEVICE
		XYOUTS, (xupp-xlow)/2.+xlow, ylow+5, $
      STRTRIM((*(*info).savparams).overlays_asecbar_length,2)+'"', /DEVICE, $
      COLOR=asecbarcol, ALIGN=0.5, CHARSIZE=(*(*info).savparams).overlays_symsize, $
      CHARTHICK=(*(*info).savparams).overlays_thick
	ENDIF
  IF ((*(*info).plotparams).imct[0] NE 0) THEN LOADCT, 0, /SILENT
	IF (((*(*info).feedbparams).verbosity)[3] EQ 1) THEN $
    CRISPEX_VERBOSE_GET, event, [(*(*info).winids).imwid,curscolor], $
      labels=['Window ID for draw','Main curscolor']
END

PRO CRISPEX_DRAW_DOPPLER, event
; (Re)draw Doppler-image procedure
	WIDGET_CONTROL, event.TOP, GET_UVALUE = info
	IF (TOTAL(((*(*info).feedbparams).verbosity)[2:3]) GE 1) THEN $
    CRISPEX_VERBOSE_GET_ROUTINE, event
  dopcurscolor = 255
	IF (*(*info).dispswitch).drawdop THEN BEGIN
		CRISPEX_DRAW_SCALING, event, dopdisp, dopminimum, dopmaximum, /DOPPLER
    IF ((*(*(*info).scaling).imagescale)[2] EQ 2) AND $
       ((*(*info).dispparams).t_main NE (*(*info).dispparams).t_main_old) THEN $
      CRISPEX_DRAW_CTBAR, event, /DOPPLER, MINIMUM=minimum, MAXIMUM=maximum
	  WSET, (*(*info).winids).dopwid
    TVLCT, r_cur, g_cur, b_cur, /GET
    TVLCT, (*(*info).plotparams).rgb_dop
    TV, CONGRID(dopdisp,(*(*info).winsizes).xywinx, (*(*info).winsizes).xywiny)
    TVLCT, r_cur, g_cur, b_cur
		CRISPEX_DRAW_SUBCOLOR, event, dopdisp, dopsubcolor
		IF (dopsubcolor GE 122) THEN $
      dopcurscolor = 0 
		CRISPEX_DRAW_CURSCROSS_PLOT, event, dopcurscolor, $
      DRAW_MASK=((*(*info).overlayswitch).mask AND $
                ((*(*info).overlayswitch).maskim)[2])
	ENDIF ELSE BEGIN
	  WSET, (*(*info).winids).dopwid
		TV, CONGRID(*(*(*info).data).emptydopslice,(*(*info).winsizes).xywinx, $
      (*(*info).winsizes).xywiny)
		IF ((*(*info).dataparams).lp GT (*(*info).dataparams).lp_dop) THEN BEGIN
			lp_blue = (*(*info).dataparams).lp_dop		&	lp_red = (*(*info).dataparams).lp
		ENDIF ELSE BEGIN
			lp_blue = (*(*info).dataparams).lp		&	lp_red = (*(*info).dataparams).lp_dop
		ENDELSE
		IF (lp_red EQ lp_blue) THEN $
      extramessage = 'Same spectral position' $
    ELSE $
      extramessage = 'Spectral position outside set spectral range'
		XYOUTS,(*(*info).winsizes).xywinx/2.,(*(*info).winsizes).xywiny/2.,$
      'Could not create Doppler image for selected spectral positions.!C'+$
      extramessage+': (lp_blue,lp_red)=('+$
			STRTRIM(lp_blue,2)+','+STRTRIM(lp_red,2)+')', CHARSIZE=1.2, COLOR=255, $
      ALIGNMENT=0.5, /DEVICE
	ENDELSE
	IF (((*(*info).feedbparams).verbosity)[3] EQ 1) THEN $
    CRISPEX_VERBOSE_GET, event, [(*(*info).winids).dopwid,$
      (*(*info).dispswitch).drawdop,dopcurscolor], $
		  labels=['Window ID for draw','Drawing Doppler image','Doppler curscolor']
END

PRO CRISPEX_DRAW_REF, event
; (Re)draw reference image procedure
	WIDGET_CONTROL, event.TOP, GET_UVALUE = info
	IF (TOTAL(((*(*info).feedbparams).verbosity)[2:3]) GE 1) THEN $
    CRISPEX_VERBOSE_GET_ROUTINE, event
	CRISPEX_DRAW_SCALING, event, refdisp, refmin, refmax, /REFERENCE
  IF ((*(*(*info).scaling).imagescale)[1] EQ 2) AND $
     ((*(*info).dispparams).t_ref NE (*(*info).dispparams).t_ref_old) THEN $
    CRISPEX_DRAW_CTBAR, event, /REFERENCE, MINIMUM=minimum, MAXIMUM=maximum
	WSET, (*(*info).winids).refwid
  TVLCT, (*(*info).plotparams).rgb_ref
  TV, CONGRID(refdisp,(*(*info).winsizes).refwinx, (*(*info).winsizes).refwiny) 
	CRISPEX_DRAW_SUBCOLOR, event, refdisp, subcolor_ref, /REFERENCE
	IF (subcolor_ref GE 122) THEN curscolor_ref = 0 ELSE curscolor_ref = 255
	CRISPEX_DRAW_CURSCROSS_PLOT, event, curscolor_ref, $
    DRAW_MASK=((*(*info).overlayswitch).mask AND $
              ((*(*info).overlayswitch).maskim)[1]), /REFERENCE
	IF (((*(*info).feedbparams).verbosity)[3] EQ 1) THEN $
    CRISPEX_VERBOSE_GET, event, [(*(*info).winids).refwid,curscolor_ref], $
      labels=['Window ID for draw','Reference curscolor']
END

PRO CRISPEX_DRAW_IMREF_BLINK, event
; Handles the blinking of the main and reference image
	WIDGET_CONTROL, event.TOP, GET_UVALUE = info
	IF (TOTAL(((*(*info).feedbparams).verbosity)[2:3]) GE 1) THEN $
    CRISPEX_VERBOSE_GET_ROUTINE, event
	WSET,(*(*info).winids).imrefwid
	IF (((*(*info).feedbparams).verbosity)[3] EQ 1) THEN $
    CRISPEX_VERBOSE_GET, event, [(*(*info).winids).imrefwid], $
      labels=['Window ID for draw']
	IF (*(*info).winids).imrefdisp THEN BEGIN
		CRISPEX_DRAW_SCALING, event, refdisp, refmin, refmax, /REFERENCE
    refdisp_sel = refdisp[$
      (*(*info).dispparams).x_ref[0]:(*(*info).dispparams).x_ref[1], $
      (*(*info).dispparams).y_ref[0]:(*(*info).dispparams).y_ref[1]]
    TVLCT, (*(*info).plotparams).rgb_ref
    TV, CONGRID(refdisp_sel,(*(*info).winsizes).imrefwinx, $
      (*(*info).winsizes).imrefwiny) 
		CRISPEX_DRAW_SUBCOLOR, event, refdisp, subcolor_ref, /REFERENCE
		IF (subcolor_ref GE 122) THEN curscolor_ref = 0 ELSE curscolor_ref = 255
		CRISPEX_DRAW_CURSCROSS_PLOT, event, curscolor_ref, $
      DRAW_MASK=((*(*info).overlayswitch).mask AND $
                ((*(*info).overlayswitch).maskim)[1])
		CRISPEX_DRAW_SUBCOLOR, event, refdisp, color_reftxt, /REFERENCE, $
      XYRANGE=[10,100,10,20]
		IF (color_reftxt GE 122) THEN reftxtcol = 0 ELSE reftxtcol = 255
    label = 'Reference'
    time_val = (*(*(*info).dispparams).tarr_ref)[(*(*info).dispparams).t]
	ENDIF ELSE BEGIN
		CRISPEX_DRAW_SCALING, event, imdisp, minimum, maximum, /MAIN
    imdisp_sel = imdisp[$
      (*(*info).dispparams).x_main[0]:(*(*info).dispparams).x_main[1], $
      (*(*info).dispparams).y_main[0]:(*(*info).dispparams).y_main[1]]
    TVLCT, (*(*info).plotparams).rgb_main
    TV, CONGRID(imdisp_sel,(*(*info).winsizes).imrefwinx, $
      (*(*info).winsizes).imrefwiny) 
		CRISPEX_DRAW_SUBCOLOR, event, imdisp, subcolor
		IF (subcolor GE 122) THEN curscolor = 0 ELSE curscolor = 255
		CRISPEX_DRAW_CURSCROSS_PLOT, event, curscolor, $
      DRAW_MASK=((*(*info).overlayswitch).mask AND $
                ((*(*info).overlayswitch).maskim)[0])
		CRISPEX_DRAW_SUBCOLOR, event, imdisp, color_txt, XYRANGE=[10,100,10,20]
		IF (color_txt GE 122) THEN txtcol = 0 ELSE txtcol = 255
    label = 'Main'
    time_val = (*(*(*info).dispparams).tarr_main)[(*(*info).dispparams).t]
	ENDELSE
	IF (SIZE((*(*info).plotaxes).dt,/TYPE) NE 2) THEN BEGIN
    IF (time_val EQ 0.) THEN $
      ndigits = 4 $
    ELSE $
      ndigits = FLOOR(ALOG10(time_val))+4
    time = STRING(time_val, FORMAT='(F'+STRTRIM(ndigits,2)+'.2)')+' s'
  ENDIF ELSE $
    time = STRTRIM(time_val, 2)
  XYOUTS, 10, 10, label+' image, t='+time,/DEVICE, COLOR=txtcol
END

PRO CRISPEX_DRAW_SJI, event, IDX_SJI=idx_sji
; (Re)draw reference image procedure
	WIDGET_CONTROL, event.TOP, GET_UVALUE = info
	IF (TOTAL(((*(*info).feedbparams).verbosity)[2:3]) GE 1) THEN $
    CRISPEX_VERBOSE_GET_ROUTINE, event
  ; Handle setting of specific SJI index
  IF (N_ELEMENTS(IDX_SJI) EQ 1) THEN BEGIN
    showsji = BYTARR((*(*info).dataparams).nsjifiles)
    showsji[idx_sji] = 1B
  ENDIF ELSE showsji = (*(*info).winswitch).showsji
  whereshowsji_loc = WHERE(showsji EQ 1, nwhereshowsji)
  FOR i=0,nwhereshowsji-1 DO BEGIN
    idx_sji = whereshowsji_loc[i]
	  CRISPEX_DRAW_SCALING, event, sjidisp, minimum, maximum, /SJI, IDX_SJI=idx_sji
    IF ((*(*(*info).scaling).imagescale)[3] EQ 2) AND $
       ((*(*info).dispparams).t_sji[idx_sji] NE $
       (*(*info).dispparams).t_sji_old[idx_sji]) THEN $
      CRISPEX_DRAW_CTBAR, event, /SJI, MINIMUM=minimum, MAXIMUM=maximum
	  WSET, (*(*info).winids).sjiwid[idx_sji]
    TVLCT, *(*(*info).plotparams).rgb_sji[idx_sji]
    TV, CONGRID(sjidisp,(*(*info).winsizes).sjiwinx[idx_sji], $
      (*(*info).winsizes).sjiwiny[idx_sji])
    ; Determine cursor colour and overplot cursors and masks
	  CRISPEX_DRAW_SUBCOLOR, event, sjidisp, subcolor_sji, /SJI, $
      IDX_SJI=idx_sji
	  IF (subcolor_sji GE 122) THEN curscolor_sji = 0 ELSE curscolor_sji = 255
	  CRISPEX_DRAW_CURSCROSS_PLOT, event, curscolor_sji, $
      DRAW_MASK=((*(*info).overlayswitch).mask AND $
                ((*(*info).overlayswitch).maskim)[1]), /SJI, IDX_SJI=idx_sji
	  IF (((*(*info).feedbparams).verbosity)[3] EQ 1) THEN $
      CRISPEX_VERBOSE_GET, event, [(*(*info).winids).sjiwid[idx_sji],curscolor_sji], $
                            labels=['Window ID for draw','Slit-jaw image curscolor']
  ENDFOR
END

PRO CRISPEX_DRAW_INT, event
; (Re)draw intensity versus time plot procedure
	WIDGET_CONTROL, event.TOP, GET_UVALUE = info
	IF (TOTAL(((*(*info).feedbparams).verbosity)[2:3]) GE 1) THEN $
    CRISPEX_VERBOSE_GET_ROUTINE, event
	WSET, (*(*info).winids).intwid
	int_low_y = (*(*(*info).plotaxes).int_low_y)[(*(*info).dataparams).s] 
	int_upp_y = (*(*(*info).plotaxes).int_upp_y)[(*(*info).dataparams).s]
	condition = WHERE(*(*(*info).intparams).seldisp_diagnostics EQ 1, count)
  ; Create plot box axes
  PLOT, *(*(*info).dispparams).tarr_main, *(*(*info).dispparams).tarr_main, $
    /NODATA, /NORM, CHARSIZE=1, YR=[int_low_y, int_upp_y], $
    XR = [(*(*info).dispparams).t_low_main,(*(*info).dispparams).t_upp_main], /YS, /XS, $
    XTITLE = (*(*info).plottitles).spytitle, YTITLE = 'Counts/Mean Counts', $
    BACKGROUND = (*(*info).plotparams).bgplotcol, COLOR = (*(*info).plotparams).plotcol, $
    LINESTYLE = 0, $
    POSITION = [(*(*info).plotpos).intx0,(*(*info).plotpos).inty0,$
                (*(*info).plotpos).intx1,(*(*info).plotpos).inty1], $
    XTICKLEN = (*(*info).plotaxes).intxticklen, YTICKLEN = (*(*info).plotaxes).intyticklen
  IF (count GT 0) THEN BEGIN
		selcol = (*(*(*info).intparams).selcol_diagnostics)[condition]
    ; For each lightcurve to be plotted, get lightcurve
		FOR i=0,N_ELEMENTS(condition)-1 DO BEGIN
			IF (*(*info).dataswitch).spfile THEN BEGIN
				ssp = REFORM( ( ( *(*(*info).data).spdata)[ $
          FIX((*(*info).dataparams).y) * (*(*info).dataparams).nx * (*(*info).dataparams).ns + $
          FIX((*(*info).dataparams).x) * (*(*info).dataparams).ns + $
					(*(*info).dataparams).s ] )[$
          (*(*(*info).intparams).sellp_diagnostics)[condition[i]],*] )
			ENDIF ELSE BEGIN
				ssp = FLTARR((*(*info).dataparams).mainnt)
				FOR t=0,(*(*info).dataparams).mainnt-1 DO BEGIN
					ssp[t] = ((*(*(*info).data).imagedata)[$
            t * (*(*info).dataparams).nlp * (*(*info).dataparams).ns + $
            (*(*info).dataparams).s * (*(*info).dataparams).nlp + $
						(*(*(*info).intparams).sellp_diagnostics)[condition[i]]])[$
            (*(*info).dataparams).x,(*(*info).dataparams).y]
				ENDFOR
			ENDELSE
			avgdint = ssp / ABS(MEAN(ssp, /NAN))
      tarr_main = $
        (*(*(*info).dispparams).tarr_main)[UNIQ(*(*(*info).dispparams).tarr_main)]
			LOADCT, 12, /SILENT
			plotcol = ((*(*info).intparams).colors_diagnostics)[selcol[i]]
      ; Plot lightcurve
			OPLOT, tarr_main, avgdint, COLOR=plotcol, $
        LINESTYLE=(*(*(*info).intparams).sellines_diagnostics)[condition[i]], $
        THICK=(*(*info).plotparams).plotthick
			LOADCT, 0, /SILENT
		ENDFOR
	ENDIF
  IF (*(*info).plotswitch).multichannel THEN $
	  XYOUTS,0.1*( (*(*(*info).dispparams).tarr_main)[(*(*info).dispparams).t_upp] - $
      (*(*(*info).dispparams).tarr_main)[(*(*info).dispparams).t_low] + 1 ) + $
      (*(*(*info).dispparams).tarr_main)[(*(*info).dispparams).t_low], $
      (int_upp_y-int_low_y)*0.9+int_low_y, $
      'Stokes '+((*(*info).stokesparams).labels)[(*(*info).dataparams).s], $
      COLOR = (*(*info).plotparams).plotcol
  ; Overplot time indicator
	IF (((*(*info).dispparams).t GE (*(*info).dispparams).t_low) AND $
      ((*(*info).dispparams).t LE (*(*info).dispparams).t_upp)) THEN $
    PLOTS, [1,1] * (*(*(*info).dispparams).tarr_main)[(*(*info).dispparams).t], $
      [int_upp_y, int_low_y], COLOR=(*(*info).plotparams).plotcol, $
      THICK=(*(*info).plotparams).plotthick
	IF (((*(*info).feedbparams).verbosity)[3] EQ 1) THEN $
    CRISPEX_VERBOSE_GET, event, [(*(*info).winids).intwid,int_low_y,int_upp_y], $
                          labels=['Window ID for draw','Lower y-value','Upper y-value']
END

PRO CRISPEX_DRAW_SPECTRAL_MAIN, event, LS_ONLY=ls_only, SP_ONLY=sp_only
; (Re)draw detailed spectrum procedure
	WIDGET_CONTROL, event.TOP, GET_UVALUE = info
	IF (TOTAL(((*(*info).feedbparams).verbosity)[2:3]) GE 1) THEN $
    CRISPEX_VERBOSE_GET_ROUTINE, event
  ; Determine current diagnostic window LP is in
  lp_diag = $
    TOTAL((*(*info).dataparams).lp GE *(*(*info).intparams).diag_starts)-1
  IF (~KEYWORD_SET(SP_ONLY) AND (*(*info).winswitch).showls) THEN BEGIN
    ; Pre-draw procedures: detailed spectrum (LS)
    ; Set loop-independent parameters
    ; Set x-axes parameters depending on # of diagnostics
    IF ((*(*info).intparams).ndisp_diagnostics GT 1) THEN BEGIN
      xtlen_basic_fac = 0.5
      xtlen_major_fac = 0.8
      xtickname = REPLICATE(' ',60)
      xtitle = ''
    ENDIF ELSE BEGIN
      xtlen_basic_fac = 1.
      xtickname = ''
    ENDELSE
    ; Scaling of xticklen
    xticklen = xtlen_basic_fac * (*(*info).plotaxes).lsxticklen
    ; Loop over all selected Stokes parameters (will always be at least 1) for
    ; detailed spectrum plots
    FOR i=0,TOTAL((*(*info).stokesparams).select_sp)-1 DO BEGIN
      IF (~KEYWORD_SET(SP_ONLY) AND (*(*info).winswitch).showls) THEN BEGIN
     		s = (WHERE((*(*info).stokesparams).select_sp EQ 1))[i]
     		spec = ((*(*info).dataparams).spec)[*,s]
  		  IF ((*(*info).dataswitch).spfile EQ 1) THEN $
          ssp = (*(*(*info).data).ssp_cur[s])[*,(*(*info).dispparams).t_main] $
        ELSE $
          ssp = (*(*(*info).data).ssp_cur[s]) 
        ms = ((*(*info).dataparams).ms)[s]
        noise = (*(*info).stokesparams).noise[s]
     		ls_low_y = (*(*(*info).plotaxes).ls_low_y)[s] 
     		ls_upp_y = (*(*(*info).plotaxes).ls_upp_y)[s]
     		order_corr=0.
     		IF (*(*info).dispswitch).detspect_scale THEN BEGIN
          lsytitle = 'Scaled '+STRLOWCASE((*(*info).plottitles).lsytitle) 
          spec /= ms
          ssp /= ms
          noise /= ms
        ENDIF ELSE BEGIN
     			IF ((FLOOR(ALOG10(ABS(ls_low_y))) LE -2) OR $
            (FLOOR(ALOG10(ABS(ls_upp_y))) GE 3)) THEN BEGIN
     				order_corr = FLOOR(ALOG10(ABS(ls_upp_y)))
     				lsytitle = $
              (*(*info).plottitles).lsytitle+' (x10!U'+STRTRIM(order_corr,2)+'!N)'
     			ENDIF ELSE lsytitle = (*(*info).plottitles).lsytitle
     			ls_low_y /= (10.^(order_corr))
     			ls_upp_y /= (10.^(order_corr))
     			spec *= ((*(*info).paramparams).scale_cubes)[0] / (10.^(order_corr))
          ssp *= ((*(*info).paramparams).scale_cubes)[0] / (10.^(order_corr))
          noise *= ((*(*info).paramparams).scale_cubes)[0] / (10.^(order_corr))
     		ENDELSE
      ENDIF
      IF ((*(*info).intparams).ndisp_diagnostics EQ 1) THEN BEGIN
        xtitle = (*(*info).plottitles).lsxtitles[i]
        lsxtickname=*(*(*info).plotaxes).lsxticknames[i]
      ENDIF ELSE $
        lsxtickname = REPLICATE(' ',60)
      ; Determine proportional spectral window size for LS
      diag_range_ls = *(*(*info).plotaxes).diag_ratio * $
        (((*(*info).plotpos).lsx1)[i] - ((*(*info).plotpos).lsx0)[i])
      FOR d=0,(*(*info).intparams).ndisp_diagnostics-1 DO BEGIN
        IF (~KEYWORD_SET(SP_ONLY) AND (*(*info).winswitch).showls) THEN BEGIN
          WSET, (*(*info).winids).lswid
          disp_idx = (*(*(*info).intparams).wheredispdiag)[d]
          lp_lower = (*(*info).dispparams).lp_low_tmp[disp_idx]+$
            (*(*info).intparams).diag_start[disp_idx]
          lp_upper = (*(*info).dispparams).lp_upp_tmp[disp_idx]+$
            (*(*info).intparams).diag_start[disp_idx]
          ; Determine xrange to display and xticklen
          xrange = (*(*info).dataparams).lps[[lp_lower,lp_upper]] 
          ; Set y-axes parameters based on diagnostic plot
          IF (d EQ 0) THEN BEGIN
            offset = 0 
            ytickname=*(*(*info).plotaxes).lsyticknames[i]
            ytitle = (*(*info).plottitles).lsytitles[i]
          ENDIF ELSE BEGIN
            offset = TOTAL(diag_range_ls[0:(d-1)])
            ytickname = REPLICATE(' ',60)
            ytitle = ''
          ENDELSE
          ; Determine lower left corner position of plot
          lsx0 = ((*(*info).plotpos).lsx0)[i] + offset
          lsx1 = diag_range_ls[d] + lsx0
          ; Plot basic window 
       		PLOT, (*(*info).dataparams).lps[lp_lower:lp_upper], $
            spec[lp_lower:lp_upper]*(*(*info).scaling).mult_val[disp_idx], $
            /NODATA, /NORM, CHARSIZE=1, YS=1, YR=[ls_low_y,ls_upp_y], $
            XR=xrange,  $
            XMINOR=(0-((*(*info).intparams).ndisp_diagnostics GT 1)), $
            XTICKINTERVAL=(*(*(*info).plotaxes).xtickinterval)[0], $
            XTICKNAME=lsxtickname, YTICKNAME=ytickname, XTICK_GET=xtickvals, $
            XSTYLE=(*(*info).plotswitch).v_dop_set * 8 + 1, $
            BACKGROUND=(*(*info).plotparams).bgplotcol, $
            XTITLE=xtitle, YTITLE=ytitle, $
            POSITION=[lsx0,((*(*info).plotpos).lsy0)[i],lsx1,$
            ((*(*info).plotpos).lsy1)[i]], XTICKLEN=xticklen, $
            YTICKLEN=(*(*info).plotaxes).lsyticklen, $
            COLOR=(*(*info).plotparams).plotcol, LINE=3, $
            NOERASE=((((*(*info).intparams).ndiagnostics GT 1) AND (d GT 0)) OR $
            (i GT 0))
          ; Overplot average spectrum
      		OPLOT, (*(*info).dataparams).lps[lp_lower:lp_upper], $
            spec[lp_lower:lp_upper]*(*(*info).scaling).mult_val[disp_idx], $
            LINE=3, COLOR=(*(*info).plotparams).plotcol, $
            THICK=(*(*info).plotparams).plotthick
          IF ((*(*info).scaling).mult_val[disp_idx] NE 1) THEN BEGIN
            XYOUTS,0.1*(xrange[1]-xrange[0])+xrange[0], $
              0.9*(ls_upp_y-ls_low_y)+ls_low_y, $
              STRING((*(*info).scaling).mult_val[disp_idx], FORMAT='(F'+$
              STRTRIM(FLOOR(ALOG10(ABS((*(*info).scaling).mult_val[disp_idx])))+$
              3+((*(*info).scaling).mult_val[disp_idx] LT 0),2)+'.1)')+'x',$
              COLOR=(*(*info).plotparams).plotcol, /DATA
          ENDIF
          ; In case of multiple diagnostics
          IF ((*(*info).intparams).ndiagnostics GT 1) THEN BEGIN
            ; Draw x-title centered on plot box on first pass
            IF (d EQ 0) THEN $
              XYOUTS,((*(*info).plotpos).lsx1-(*(*info).plotpos).lsx0)/2.+$
                (*(*info).plotpos).lsx0, (*(*info).plotpos).lsy0/5., $
                (*(*info).plottitles).spxtitle,ALIGNMENT=0.5, $
                COLOR = (*(*info).plotparams).plotcol,/NORMAL
            ; Set range for Doppler axis
            vdop_xrange = (*(*(*info).plotaxes).v_dop[disp_idx])[$
              [(*(*info).dispparams).lp_low_tmp[disp_idx], $
               (*(*info).dispparams).lp_upp_tmp[disp_idx]]]
            IF ((*(*info).intparams).ndisp_diagnostics GT 1) THEN BEGIN
              ; Redraw x-axis with custom labelling
              IF (*(*info).plotswitch).xtick_reset THEN BEGIN
                (*(*info).plotaxes).xtickvals[d] = $
                  PTR_NEW(CRISPEX_PLOTAXES_XTICKVALS_SELECT(xtickvals, $
                  TICKSEP=(*(*(*info).plotaxes).xtickinterval)[1]))
                IF (d EQ ((*(*info).intparams).ndisp_diagnostics-1)) THEN $
                  (*(*info).plotswitch).xtick_reset = 0
              ENDIF
              wherenonempty = $
                WHERE(*(*(*info).plotaxes).xtickvals[d] NE ' ', count)
              IF (count GT 0) THEN BEGIN
                FOR k=0,N_ELEMENTS(wherenonempty)-1 DO BEGIN
                  PLOTS,[1.,1.]*FLOAT((*(*(*info).plotaxes).xtickvals[d])[$
                    wherenonempty[k]]), [ls_low_y,xtlen_major_fac*$
                    (ls_upp_y-ls_low_y)*(*(*info).plotaxes).lsxticklen+ls_low_y],$
                    COLOR=(*(*info).plotparams).plotcol
                ENDFOR
              ENDIF
              AXIS, XAXIS=0, XTICKLEN=1E-9, XRANGE=xrange, /XS, $
                XTICKNAME=*(*(*info).plotaxes).xtickvals[d], $
                COLOR=(*(*info).plotparams).plotcol, $
                XTICKINTERVAL=(*(*(*info).plotaxes).xtickinterval)[0]
            ENDIF
          ENDIF ELSE $
            vdop_xrange = (*(*(*info).plotaxes).v_dop[0])[$
              [(*(*info).dispparams).lp_low_tmp,(*(*info).dispparams).lp_upp_tmp]]
          ; Display Stokes label if Stokes data
          IF (*(*info).plotswitch).multichannel THEN BEGIN
            label = ((*(*info).stokesparams).labels)[s]
            IF ((*(*info).dispswitch).scalestokes[0] AND $
                (s NE 0)) THEN label += '/I'
      		  XYOUTS, ABS((*(*info).dataparams).lps[(*(*info).dispparams).lp_upp_tmp[d]]-$
                     (*(*info).dataparams).lps[(*(*info).dispparams).lp_low_tmp[d]])*0.1+$
                     (*(*info).dataparams).lps[(*(*info).dispparams).lp_low_tmp[d]], $
      			        (ls_upp_y-ls_low_y)*0.8+ls_low_y, label, $
                    COLOR = (*(*info).plotparams).plotcol
          ENDIF
          ; Display Doppler velocities on top axis if info available
      	  IF ((*(*info).plotswitch).v_dop_set EQ 1) THEN BEGIN
            ; Draw top axis
            IF ((*(*info).intparams).ndisp_diagnostics GT 1) THEN BEGIN
              ; Plot the initial tick marks and get the tick vals
        	  	AXIS, XAXIS=1, XRANGE=vdop_xrange, $
                XSTYLE=1, COLOR=(*(*info).plotparams).plotcol,$
                XTICKINTERVAL=(*(*(*info).plotaxes).xdoptickinterval)[0], $
                XTICKNAME=REPLICATE(' ',60), XTICK_GET=xdoptickvals, $
                XTICKLEN=xtlen_basic_fac*(*(*info).plotaxes).lsxticklen, $
                XMINOR=-1
              ; Redraw x-axis with custom labelling
              IF (*(*info).plotswitch).xdoptick_reset THEN BEGIN
                (*(*info).plotaxes).xdoptickvals[d] = $
                  PTR_NEW(CRISPEX_PLOTAXES_XTICKVALS_SELECT(xdoptickvals, $
                  TICKSEP=(*(*(*info).plotaxes).xdoptickinterval)[1],$
                  /DOPPLER))
                wherenonempty = WHERE(*(*(*info).plotaxes).xdoptickvals[d] NE ' ')
                ; Determine Doppler tick mark locations
                (*(*info).plotaxes).xdoptickloc[d] = $
                  PTR_NEW(CRISPEX_PLOTAXES_XDOPTICKLOC(xdoptickvals, $
                  wherenonempty, vdop_xrange, $
                  [(*(*info).dataparams).lps[lp_lower], $
                  (*(*info).dataparams).lps[lp_upper]]))
                IF (d EQ ((*(*info).intparams).ndisp_diagnostics-1)) THEN $
                  (*(*info).plotswitch).xdoptick_reset = 0
              ENDIF
              wherenonempty = $
                WHERE(*(*(*info).plotaxes).xdoptickvals[d] NE ' ', count)
              IF (count GT 0) THEN BEGIN
                FOR k=0,N_ELEMENTS(wherenonempty)-1 DO BEGIN
                  PLOTS,[1.,1.]*(*(*(*info).plotaxes).xdoptickloc[d])[k], $
                    [ls_upp_y,-xtlen_major_fac*(ls_upp_y-ls_low_y)*$
                    (*(*info).plotaxes).lsxticklen+ls_upp_y], $
                    COLOR=(*(*info).plotparams).plotcol
                ENDFOR
              ENDIF
              ; Add the labels
              AXIS, XAXIS=1, XTICKLEN=1E-9, XRANGE=vdop_xrange, /XS, $
                XTICKNAME=*(*(*info).plotaxes).xdoptickvals[d], $
                COLOR=(*(*info).plotparams).plotcol, $
                XTICKINTERVAL=(*(*(*info).plotaxes).xdoptickinterval)[0], XMINOR=-1
            ENDIF ELSE $
        	  	AXIS, XAXIS=1, XTICKLEN = (*(*info).plotaxes).lsxticklen, $
                XRANGE=vdop_xrange, XSTYLE=1, $
                XTITLE=(*(*info).plottitles).lsdopxtitles[1], $
                XTICKNAME=*(*(*info).plotaxes).lsdopxticknames[i GE 2], $
                COLOR=(*(*info).plotparams).plotcol;,$
          ENDIF 
          TVLCT, r_cur, g_cur, b_cur, /GET
          ; Draw line through y=0
      		IF ((ls_low_y LT 0.) AND (ls_upp_y GT 0.)) THEN $
            PLOTS, xrange, [0.,0.], COLOR=(*(*info).plotparams).plotcol
          ; Only overplot detailed spectrum if x/y is not out of range
          IF ((*(*info).dispswitch).xy_out_of_range EQ 0) THEN BEGIN
            ; Overplot detailed spectrum
        		OPLOT, (*(*info).dataparams).lps[lp_lower:lp_upper], $
              ssp[lp_lower:lp_upper]*(*(*info).scaling).mult_val[disp_idx], $
              LINE=0, COLOR=(*(*info).plotparams).plotcol, $
              THICK=(*(*info).plotparams).plotthick
            ; Overplot average minus detailed spectrum
        		IF (*(*info).plotswitch).subtract THEN $
        			OPLOT, (*(*info).dataparams).lps[lp_lower:lp_upper], $
                (spec[lp_lower:lp_upper]-ssp[lp_lower:lp_upper])*$
                (*(*info).scaling).mult_val[disp_idx], $
                COLOR=(*(*info).plotparams).plotcol, LINE=2, $
                THICK=(*(*info).plotparams).plotthick
            ; Overplot noise levels 
            IF (*(*info).plotswitch).noise THEN BEGIN
              OPLOT, (*(*info).dataparams).lps[[lp_lower,lp_upper]], $
                REPLICATE(noise,2), LINESTYLE=2, $
                COLOR=(*(*info).plotparams).plotcol, $
                THICK=(*(*info).plotparams).plotthick
              OPLOT, (*(*info).dataparams).lps[[lp_lower,lp_upper]], $
                REPLICATE(-1*noise,2), LINESTYLE=2, $
                COLOR=(*(*info).plotparams).plotcol, $
                THICK=(*(*info).plotparams).plotthick
            ENDIF
            IF (d EQ lp_diag) THEN BEGIN
	            LOADCT, (*(*info).overlayparams).maskct, /SILENT
              ; Overplot spectral indicator
        		  PLOTS, [1,1] * (*(*info).dataparams).lps[(*(*info).dataparams).lp],$
                [ls_low_y,ls_upp_y], COLOR=(*(*info).overlayparams).maskcolor, $
                THICK=(*(*info).plotparams).plotthick
              ; Overplot 2nd spectral indicator in case of Doppler image display
          		IF (*(*info).dispswitch).drawdop THEN $
                PLOTS, [1,1] * (*(*info).dataparams).lps[$
                  (*(*info).dataparams).lp_dop],[ls_low_y,ls_upp_y], $
                  COLOR=(*(*info).overlayparams).maskcolor, $
                  THICK=(*(*info).plotparams).plotthick
            ENDIF
            ; Overplot reference spectral indicator if same number of spectral 
            ; positions
        		IF ((*(*info).winswitch).showref AND $
               ((*(*info).ctrlsswitch).lp_ref_lock EQ 0) AND $
               ((*(*info).dataswitch).refspfile EQ 0) AND $
               ((*(*info).dataparams).refnlp GT 1)) THEN BEGIN
	            LOADCT, (*(*info).overlayparams).maskct, /SILENT
        			PLOTS, [1,1] * (*(*info).dataparams).reflps[$
                (*(*info).dataparams).lp_ref],[ls_low_y,ls_upp_y], $
                COLOR=(*(*info).overlayparams).maskcolor, $
                THICK=(*(*info).plotparams).plotthick
        		ENDIF
          ENDIF 
          TVLCT, r_cur, g_cur, b_cur
        ENDIF
      ENDFOR
      IF (*(*info).dispswitch).xy_out_of_range THEN $
        XYOUTS, ((*(*info).plotpos).lsx1[i]-(*(*info).plotpos).lsx0[i])/2.+$
          (*(*info).plotpos).lsx0[i], ((*(*info).plotpos).lsy1[i]-$
          (*(*info).plotpos).lsy0[i])/2.+(*(*info).plotpos).lsy0[i], $
          'No data availabe for!Cselected pixel position', $
          COLOR=(*(*info).plotparams).plotcol, ALIGN=0.5, CHARSIZE=1.2, /NORMAL
    ENDFOR
    IF (*(*info).plotswitch).v_dop_set THEN $
      XYOUTS,((*(*info).plotpos).lsx1_all-(*(*info).plotpos).lsx0_all)/2.+$
              (*(*info).plotpos).lsx0_all,(*(*info).plotpos).lsy0_all/5.*3+$
              (*(*info).plotpos).lsy1_all, $
              (*(*info).plottitles).lsdopxtitles[0], ALIGNMENT=0.5, $
              COLOR=(*(*info).plotparams).plotcol,/NORMAL
  ENDIF
  ; Pre-draw procedures: spectrum-time diagram (SP)
  IF (~KEYWORD_SET(LS_ONLY) AND (*(*info).winswitch).showsp) THEN BEGIN
  	IF (*(*info).dispparams).slices_imscale THEN BEGIN
      CRISPEX_DRAW_SCALING,event,imdisp,minimum,maximum, /MAIN
      minmax = CRISPEX_SCALING_CONTRAST(minimum,maximum,$
        (*(*info).scaling).minimum[(*(*info).intparams).lp_diag_all],$
        (*(*info).scaling).maximum[(*(*info).intparams).lp_diag_all])
    ENDIF 
    WSET, (*(*info).winids).spwid
    TVLCT, r_cur, g_cur, b_cur, /GET
    TVLCT, (*(*info).plotparams).rgb_main
    TV, *(*(*info).data).spslice_congrid, (*(*info).plotpos).spx0, $
      (*(*info).plotpos).spy0, /NORM
    TVLCT, r_cur, g_cur, b_cur
    !X.WINDOW = [(*(*info).plotpos).spx0,(*(*info).plotpos).spx1]
    !Y.WINDOW = [(*(*info).plotpos).spy0,(*(*info).plotpos).spy1]
    ; In case of multiple diagnostics, overplot separator axes
    IF ((*(*info).intparams).ndiagnostics GT 1) THEN BEGIN
      ; Loop over all but the first diagnostic for plotting separators
      FOR d=1,(*(*info).intparams).ndisp_diagnostics-1 DO BEGIN
        AXIS,(d GE 1)*TOTAL((*(*(*info).plotaxes).diag_range_sp)[0:(d-1)])+$
          (*(*info).plotpos).spx0, YAXIS=0, $
          YTICKLEN=(*(*info).plotaxes).spyticklen, YTICKNAME=REPLICATE(' ',60), $
          COLOR=100,/NORMAL, $
          YRANGE=[(*(*info).dispparams).t_low_main, $
          (*(*info).dispparams).t_upp_main], YSTYLE=1, /NOERASE
        AXIS,(d GE 1)*TOTAL((*(*(*info).plotaxes).diag_range_sp)[0:(d-1)])+$
          (*(*info).plotpos).spx0, YAXIS=1, $
          YTICKLEN=(*(*info).plotaxes).spyticklen, YTICKNAME=REPLICATE(' ',60), $
          COLOR=100,/NORMAL,YRANGE=[(*(*info).dispparams).t_low_main, $
          (*(*info).dispparams).t_upp_main], YSTYLE=1, /NOERASE
      ENDFOR
    ENDIF
    IF ((*(*info).dispswitch).xy_out_of_range EQ 0) THEN BEGIN
      TVLCT, r_cur, g_cur, b_cur, /GET
      LOADCT, (*(*info).overlayparams).maskct, /SILENT
      ; Overplot time indicator
      PLOTS, [(*(*info).plotpos).spx0,(*(*info).plotpos).spx1], $
              [1,1]*( ((*(*(*info).dispparams).tarr_main)[$
              (*(*info).dispparams).t]-(*(*info).dispparams).t_low_main) / $
              FLOAT((*(*info).dispparams).t_upp_main-$
              (*(*info).dispparams).t_low_main) * (*(*info).plotpos).yplspw + $
              (*(*info).plotpos).spy0), /NORMAL, $  
              COLOR=(*(*info).overlayparams).maskcolor, $
              THICK=(*(*info).plotparams).plotthick
      ; Overplot lp indicator
      IF (lp_diag EQ 0) THEN $
        offset = 0 $
      ELSE $
        offset = TOTAL((*(*(*info).plotaxes).diag_range_sp)[0:(lp_diag-1)])
      spx0 = (*(*info).plotpos).spx0 + offset
      xplspw = (*(*(*info).plotaxes).diag_range_sp)[lp_diag]
      ; Get the corresponding lp_disprange
      lp_disprange = (*(*info).dataparams).lps[$
                      (*(*info).dispparams).lp_upp_tmp[$
                      (*(*info).intparams).lp_diag_all]+$
                      (*(*(*info).intparams).diag_starts)[lp_diag]] - $
                     (*(*info).dataparams).lps[$
                      (*(*info).dispparams).lp_low_tmp[$
                      (*(*info).intparams).lp_diag_all]+$
                      (*(*(*info).intparams).diag_starts)[lp_diag]]
      lp_lower = (*(*info).dataparams).lps[$
        (*(*info).dispparams).lp_low_bounds[(*(*info).intparams).lp_diag_all]]
      PLOTS, [1,1] * ( ((*(*info).dataparams).lps[(*(*info).dataparams).lp] - $
                        lp_lower) / lp_disprange * xplspw + spx0 ), $
      	[(*(*info).plotpos).spy0, (*(*info).plotpos).spy1], /NORMAL, $ 
        COLOR=(*(*info).overlayparams).maskcolor, $
        THICK=(*(*info).plotparams).plotthick
      ; If drawing Doppler, overplot lp_dop indicator
      IF (*(*info).dispswitch).drawdop THEN $         
        PLOTS, [1,1] * (((*(*info).dataparams).lps[$
                          (*(*info).dataparams).lp_dop]-lp_lower) / $
                        lp_disprange * xplspw + spx0 ), $
      	  [(*(*info).plotpos).spy0, (*(*info).plotpos).spy1], /NORMAL, $ 
          COLOR=(*(*info).overlayparams).maskcolor, $
          THICK=(*(*info).plotparams).plotthick
      ; If drawing reference, and refnlp=nlp but lp_ref != lp, then overplot 
      ; lp_ref indicator
      IF ((*(*info).winswitch).showref AND $
         ((*(*info).ctrlsswitch).lp_ref_lock EQ 0) AND $
         ((*(*info).dataswitch).refspfile EQ 0) AND $
         ((*(*info).dataparams).refnlp GT 1)) THEN BEGIN
        lp_ref_diag = TOTAL((*(*info).dataparams).lp_ref GE $
          *(*(*info).intparams).refdiag_starts)-1
      	PLOTS, [1,1] * ( $
          ; Current lp_ref minus lower lp_ref value
          ((*(*info).dataparams).reflps[(*(*info).dataparams).lp_ref] - $
            (*(*info).dataparams).reflps[(*(*info).dispparams).lp_ref_low_bounds[$
            (*(*info).intparams).lp_ref_diag_all]]) / $
          ; Divided by lp_ref_disprange
            ((*(*info).dataparams).reflps[(*(*info).dispparams).lp_ref_upp_tmp[$
            (*(*info).intparams).lp_ref_diag_all]+$
            (*(*(*info).intparams).refdiag_starts)[lp_ref_diag]] - $
            (*(*info).dataparams).reflps[(*(*info).dispparams).lp_ref_low_tmp[$
            (*(*info).intparams).lp_ref_diag_all]+$
            (*(*(*info).intparams).refdiag_starts)[lp_ref_diag]]) * $
          (*(*info).plotpos).xplspw + (*(*info).plotpos).spx0 ), $
      		[(*(*info).plotpos).spy0, (*(*info).plotpos).spy1], /NORMAL, $ 
          COLOR=(*(*info).overlayparams).maskcolor,$
          THICK=(*(*info).plotparams).plotthick
      ENDIF
      TVLCT, r_cur, g_cur, b_cur
    ENDIF ELSE $
  		XYOUTS, (*(*info).plotpos).xplspw/2.+(*(*info).plotpos).spx0,$
              (*(*info).plotpos).yplspw/2.+(*(*info).plotpos).spy0,$
              'No data available for!Cselected pixel position', COLOR=255, $
              ALIGNMENT = 0.5, CHARSIZE=1.2, /NORMAL
  ENDIF
END

PRO CRISPEX_DRAW_SPECTRAL_REF, event, LS_ONLY=ls_only, SP_ONLY=sp_only
; (Re)draw detailed spectrum procedure
	WIDGET_CONTROL, event.TOP, GET_UVALUE = info
	IF (TOTAL(((*(*info).feedbparams).verbosity)[2:3]) GE 1) THEN $
    CRISPEX_VERBOSE_GET_ROUTINE, event
  ; Determine current diagnostic window LP_REF is in
  lp_ref_diag = $
    TOTAL((*(*info).dataparams).lp_ref GE *(*(*info).intparams).refdiag_starts)-1
  IF (~KEYWORD_SET(SP_ONLY) AND (*(*info).winswitch).showrefls) THEN BEGIN
    ; Pre-draw procedures: detailed spectrum (LS)
    ; Set x-axes parameters depending on # of diagnostics
    IF ((*(*info).intparams).ndisp_refdiagnostics GT 1) THEN BEGIN
      xtlen_basic_fac = 0.5
      xtlen_major_fac = 0.8
      xtickname = REPLICATE(' ',60)
      xtitle = ''
    ENDIF ELSE BEGIN
      xtlen_basic_fac = 1.
      xtickname = ''
      xtitle = (*(*info).plottitles).refspxtitle
    ENDELSE
    xticklen = xtlen_basic_fac * (*(*info).plotaxes).reflsxticklen
    ; Loop over all selected Stokes parameters (will always be at least 1) for
    ; detailed spectrum plots
    FOR i=0,TOTAL((*(*info).stokesparams).select_refsp)-1 DO BEGIN
      s = (WHERE((*(*info).stokesparams).select_refsp EQ 1))[i]
	    refspec = ((*(*info).dataparams).refspec)[*,s]
      IF ((*(*info).dataswitch).refspfile EQ 1) THEN $
        refssp = $
          ((*(*(*info).data).refssp_cur[s])[*,(*(*info).dispparams).t_ref]) $
      ELSE $
        refssp = (*(*(*info).data).refssp_cur[s])
      refms = ((*(*info).dataparams).refms)[s]
      refnoise = (*(*info).stokesparams).noise_ref[s]
	    ls_low_y = (*(*(*info).plotaxes).ls_low_y_ref)[s]
	    ls_upp_y = (*(*(*info).plotaxes).ls_upp_y_ref)[s]
	    order_corr=0.
	    IF (*(*info).dispswitch).ref_detspect_scale THEN BEGIN
        reflsytitle = 'Scaled '+STRLOWCASE((*(*info).plottitles).reflsytitle)
        refspec /= refms
        refssp /= refms
        refnoise /= refms
      ENDIF ELSE BEGIN
	    	IF ((FLOOR(ALOG10(ABS(ls_low_y))) LE -2) OR $
            (FLOOR(ALOG10(ABS(ls_upp_y))) GE 3)) THEN BEGIN
	    		order_corr = FLOOR(ALOG10(ABS(ls_upp_y)))
	    		reflsytitle = $
            (*(*info).plottitles).reflsytitle+' (x10!U'+STRTRIM(order_corr,2)+'!N)'
	    	ENDIF ELSE reflsytitle = (*(*info).plottitles).reflsytitle
	    	ls_low_y /= (10.^(order_corr))
	    	ls_upp_y /= (10.^(order_corr))
	    	refspec *= ((*(*info).paramparams).scale_cubes)[1] / $
          (10.^(order_corr))
        refssp *= ((*(*info).paramparams).scale_cubes)[1] / (10.^(order_corr))
        refnoise *= ((*(*info).paramparams).scale_cubes)[1] / (10.^(order_corr))
	    ENDELSE
      IF ((*(*info).intparams).ndisp_refdiagnostics EQ 1) THEN BEGIN
        xtitle = (*(*info).plottitles).reflsxtitles[i]
        lsxtickname=*(*(*info).plotaxes).reflsxticknames[i]
      ENDIF ELSE $
        lsxtickname = REPLICATE(' ',60)
      ; Determine proportional spectral window size for LS
      diag_range_ls = *(*(*info).plotaxes).refdiag_ratio * $
        (((*(*info).plotpos).reflsx1)[i] - ((*(*info).plotpos).reflsx0)[i])
      FOR d=0,(*(*info).intparams).ndisp_refdiagnostics-1 DO BEGIN
        disp_idx = (*(*(*info).intparams).wheredisprefdiag)[d]
        mult_idx = (*(*info).intparams).ndiagnostics+disp_idx
        lp_lower = (*(*info).dispparams).lp_ref_low_tmp[disp_idx]+$
          (*(*info).intparams).refdiag_start[disp_idx]
        lp_upper = (*(*info).dispparams).lp_ref_upp_tmp[disp_idx]+$
          (*(*info).intparams).refdiag_start[disp_idx]
        ; Draw REFLS window
	      WSET, (*(*info).winids).reflswid
        ; Determine xrange to display
        xrange = (*(*info).dataparams).reflps[[lp_lower,lp_upper]] 
        lp_ref_lower = (*(*info).intparams).refdiag_start[$
          (*(*(*info).intparams).wheredisprefdiag)[d]]
        lp_ref_upper = lp_ref_lower+(*(*info).intparams).refdiag_width[$
          (*(*(*info).intparams).wheredisprefdiag)[d]]-1
        ; Set y-axes parameters based on diagnostic plot
        IF (d EQ 0) THEN BEGIN
          offset = 0 
          ytickname=*(*(*info).plotaxes).reflsyticknames[i]
          ytitle = (*(*info).plottitles).reflsytitles[i]
        ENDIF ELSE BEGIN
          offset = TOTAL(diag_range_ls[0:(d-1)])
          ytickname = REPLICATE(' ',60)
          ytitle = ''
        ENDELSE
        ; Determine lower left corner position of plot
        reflsx0 = ((*(*info).plotpos).reflsx0)[i] + offset
        reflsx1 = diag_range_ls[d] + reflsx0
        ; Plot basic window 
        PLOT, (*(*info).dataparams).reflps[lp_ref_lower:lp_ref_upper],$
          refspec[lp_ref_lower:lp_ref_upper]*$
          (*(*info).scaling).mult_val[mult_idx], $
          /NORM, CHARSIZE=1, YS=1, YR=[ls_low_y,ls_upp_y], $
          XR=xrange, YTICKNAME=ytickname, $
          XMINOR=(0-((*(*info).intparams).ndisp_refdiagnostics GT 1)), $
          XTICKINTERVAL=(*(*(*info).plotaxes).xreftickinterval)[0], $
          XTICKNAME=lsxtickname, XSTYLE=(*(*info).plotswitch).v_dop_set_ref*8+1, $
          XTICK_GET=xtickvals, BACKGROUND=(*(*info).plotparams).bgplotcol, $
          XTITLE = xtitle, YTITLE=ytitle, $
          POSITION=[reflsx0,((*(*info).plotpos).reflsy0)[i],$
          reflsx1,((*(*info).plotpos).reflsy1)[i]], $
          XTICKLEN = xticklen, YTICKLEN = (*(*info).plotaxes).reflsyticklen, $
          COLOR = (*(*info).plotparams).plotcol, LINE=3, $
          NOERASE=(((*(*info).intparams).nrefdiagnostics GT 1) AND (d GT 0) OR $
          (i GT 0))
          ; Overplot average spectrum
        	OPLOT, (*(*info).dataparams).reflps[lp_ref_lower:lp_ref_upper], $
            refspec[lp_ref_lower:lp_ref_upper]*(*(*info).scaling).mult_val[$
            mult_idx], LINE=3, COLOR=(*(*info).plotparams).plotcol, $
            THICK=(*(*info).plotparams).plotthick
          IF ((*(*info).scaling).mult_val[mult_idx] NE 1) THEN BEGIN
            XYOUTS,0.1*(xrange[1]-xrange[0])+xrange[0], $
              0.9*(ls_upp_y-ls_low_y)+ls_low_y, $
              STRING((*(*info).scaling).mult_val[mult_idx], $
              FORMAT='(F'+STRTRIM(FLOOR(ALOG10(ABS((*(*info).scaling).mult_val[$
              mult_idx])))+3+((*(*info).scaling).mult_val[mult_idx] LT 0),2)+$
              '.1)')+'x',COLOR=(*(*info).plotparams).plotcol, /DATA
          ENDIF
        ; In case of multiple diagnostics
        IF ((*(*info).intparams).nrefdiagnostics GT 1) THEN BEGIN
          ; Draw x-title centered on plot box on first pass
          IF (d EQ 0) THEN $
            XYOUTS,((*(*info).plotpos).reflsx1-(*(*info).plotpos).reflsx0)/2.+$
              (*(*info).plotpos).reflsx0, (*(*info).plotpos).reflsy0/5.,$
              (*(*info).plottitles).refspxtitle,ALIGNMENT=0.5, $
              COLOR=(*(*info).plotparams).plotcol, /NORMAL
          ; Set range for Doppler axis
          vdop_xrange = (*(*(*info).plotaxes).v_dop_ref[disp_idx])[$
            [(*(*info).dispparams).lp_ref_low_tmp[disp_idx], $
             (*(*info).dispparams).lp_ref_upp_tmp[disp_idx]]]
          IF ((*(*info).intparams).ndisp_refdiagnostics GT 1) THEN BEGIN
            ; Redraw x-axis with custom labelling
            IF (*(*info).plotswitch).xreftick_reset THEN BEGIN
              (*(*info).plotaxes).xreftickvals[d] = $
                PTR_NEW(CRISPEX_PLOTAXES_XTICKVALS_SELECT(xtickvals, $
                TICKSEP=(*(*(*info).plotaxes).xreftickinterval)[1]))
              IF (d EQ ((*(*info).intparams).ndisp_refdiagnostics-1)) THEN $
                (*(*info).plotswitch).xreftick_reset = 0
            ENDIF
            wherenonempty = $
              WHERE(*(*(*info).plotaxes).xreftickvals[d] NE ' ', count)
            IF (count GT 0) THEN BEGIN
              FOR k=0,N_ELEMENTS(wherenonempty)-1 DO BEGIN
                PLOTS,[1.,1.]*FLOAT((*(*(*info).plotaxes).xreftickvals[d])[$
                  wherenonempty[k]]), [ls_low_y,xtlen_major_fac*$
                  (ls_upp_y-ls_low_y)*(*(*info).plotaxes).reflsxticklen+ls_low_y],$
                  COLOR=(*(*info).plotparams).plotcol
              ENDFOR
            ENDIF
            AXIS, XAXIS=0, XTICKLEN=1E-9, XRANGE=xrange, /XS, $
              XTICKNAME=*(*(*info).plotaxes).xreftickvals[d], $
              COLOR=(*(*info).plotparams).plotcol, $
              XTICKINTERVAL=(*(*(*info).plotaxes).xreftickinterval)[0]
          ENDIF
        ENDIF ELSE $
          vdop_xrange = (*(*(*info).plotaxes).v_dop_ref[0])[$
            [(*(*info).dispparams).lp_ref_low_tmp,$
            (*(*info).dispparams).lp_ref_upp_tmp]]
        ; Display Stokes label if Stokes data
        IF (*(*info).plotswitch).refmultichannel THEN BEGIN
          label = ((*(*info).stokesparams).labels_ref)[s]
          IF ((*(*info).dispswitch).scalestokes[1] AND $
              (s NE 0)) THEN label += '/I'
    		  XYOUTS, $
            ABS((*(*info).dataparams).reflps[(*(*info).dispparams).lp_ref_upp_tmp[d]]-$
            (*(*info).dataparams).reflps[(*(*info).dispparams).lp_ref_low_tmp[d]])*0.1+$
            (*(*info).dataparams).reflps[(*(*info).dispparams).lp_ref_low_tmp[d]], $
    			  (ls_upp_y-ls_low_y)*0.8+ls_low_y, label, $
            COLOR=(*(*info).plotparams).plotcol
        ENDIF
        ; Display Doppler velocities on top axis if info available
        IF ((*(*info).plotswitch).v_dop_set_ref EQ 1) THEN BEGIN
          ; Draw top axis
          IF ((*(*info).intparams).ndisp_refdiagnostics GT 1) THEN BEGIN
            ; Plot the initial tick marks and get the tick vals
    	    	AXIS, XAXIS=1, XRANGE=vdop_xrange, $
              XSTYLE=1, XTITLE = topxtitle, COLOR = (*(*info).plotparams).plotcol,$
              XTICKINTERVAL=(*(*(*info).plotaxes).xrefdoptickinterval)[0], $
              XTICKNAME=REPLICATE(' ',60), XTICK_GET=xdoptickvals, $
              XTICKLEN=xtlen_basic_fac*(*(*info).plotaxes).reflsxticklen, $
              XMINOR=-1
            ; Redraw x-axis with custom labelling
            IF (*(*info).plotswitch).xrefdoptick_reset THEN BEGIN
              (*(*info).plotaxes).xrefdoptickvals[d] = $
                PTR_NEW(CRISPEX_PLOTAXES_XTICKVALS_SELECT(xdoptickvals, $
                TICKSEP=(*(*(*info).plotaxes).xrefdoptickinterval)[1],$
                /DOPPLER))
              wherenonempty = WHERE(*(*(*info).plotaxes).xrefdoptickvals[d] NE ' ')
              ; Determine Doppler tick mark locations
              (*(*info).plotaxes).xrefdoptickloc[d] = $
                PTR_NEW(CRISPEX_PLOTAXES_XDOPTICKLOC(xdoptickvals, wherenonempty, $
                vdop_xrange, [(*(*info).dataparams).reflps[lp_ref_lower], $
                (*(*info).dataparams).reflps[lp_ref_upper]]))
              IF (d EQ ((*(*info).intparams).ndisp_refdiagnostics-1)) THEN $
                (*(*info).plotswitch).xrefdoptick_reset = 0
            ENDIF
            wherenonempty = $
              WHERE(*(*(*info).plotaxes).xrefdoptickvals[d] NE ' ', count)
            IF (count GT 0) THEN BEGIN
              FOR k=0,N_ELEMENTS(wherenonempty)-1 DO BEGIN
                PLOTS,[1.,1.]*(*(*(*info).plotaxes).xrefdoptickloc[d])[k], $
                  [ls_upp_y,-xtlen_major_fac*(ls_upp_y-ls_low_y)*$
                  (*(*info).plotaxes).reflsxticklen+ls_upp_y], $
                  COLOR=(*(*info).plotparams).plotcol
              ENDFOR
            ENDIF
            ; Add the labels
            AXIS, XAXIS=1, XTICKLEN=1E-9, XRANGE=vdop_xrange, /XS, $
              XTICKNAME=*(*(*info).plotaxes).xrefdoptickvals[d], $
              COLOR=(*(*info).plotparams).plotcol, XMINOR=-1, $
              XTICKINTERVAL=(*(*(*info).plotaxes).xrefdoptickinterval)[0]
          ENDIF ELSE $
        	  AXIS, XAXIS=1, XTICKLEN = (*(*info).plotaxes).lsxticklen, $
              XRANGE=vdop_xrange, XSTYLE=1, $
              XTITLE=(*(*info).plottitles).reflsdopxtitles[1], $
              XTICKNAME=*(*(*info).plotaxes).reflsdopxticknames[i GE 2], $
              COLOR = (*(*info).plotparams).plotcol;,$
        ENDIF 
        ; Draw line through y=0
    	  IF ((ls_low_y LT 0.) AND (ls_upp_y GT 0.)) THEN $
          PLOTS, xrange, [0.,0.], COLOR = (*(*info).plotparams).plotcol
        ; Only overplot detailed spectrum if x/y is not out of range
        IF ((*(*info).dispswitch).xyref_out_of_range EQ 0) THEN BEGIN
          ; Overplot detailed spectrum
        	OPLOT, (*(*info).dataparams).reflps[lp_ref_lower:lp_ref_upper], $
            refssp[lp_ref_lower:lp_ref_upper]*(*(*info).scaling).mult_val[$
            mult_idx], LINE=0, COLOR = (*(*info).plotparams).plotcol, $
            THICK=(*(*info).plotparams).plotthick
          ; Overplot average minus detailed spectrum
        	IF (*(*info).plotswitch).ref_subtract THEN $
        		OPLOT, (*(*info).dataparams).reflps[lp_ref_lower:lp_ref_upper], $
              (refspec[lp_ref_lower:lp_ref_upper]-refssp[$
              lp_ref_lower:lp_ref_upper])*(*(*info).scaling).mult_val[mult_idx], $
              COLOR=(*(*info).plotparams).plotcol, LINE=2, $
              THICK=(*(*info).plotparams).plotthick
            ; Overplot noise levels 
            IF (*(*info).plotswitch).ref_noise THEN BEGIN
              OPLOT, (*(*info).dataparams).reflps[[lp_lower,lp_upper]], $
                REPLICATE(refnoise,2), LINESTYLE=2, $
                COLOR=(*(*info).plotparams).plotcol, $
                THICK=(*(*info).plotparams).plotthick
              OPLOT, (*(*info).dataparams).reflps[[lp_lower,lp_upper]], $
                REPLICATE(-1*refnoise,2), LINESTYLE=2, $
                COLOR=(*(*info).plotparams).plotcol, $
                THICK=(*(*info).plotparams).plotthick
            ENDIF
          IF (d EQ lp_ref_diag) THEN BEGIN
            TVLCT, r_cur, g_cur, b_cur, /GET
	          LOADCT, (*(*info).overlayparams).maskct, /SILENT
            ; Overplot spectral indicator
          	PLOTS, [1,1] * (*(*info).dataparams).reflps[$
              (*(*info).dataparams).lp_ref],[ls_low_y,ls_upp_y],$
              COLOR=(*(*info).overlayparams).maskcolor,$
              THICK=(*(*info).plotparams).plotthick
            TVLCT, r_cur, g_cur, b_cur
          ENDIF
        ENDIF
      ENDFOR
      IF (*(*info).dispswitch).xyref_out_of_range THEN $
        XYOUTS, ((*(*info).plotpos).reflsx1[i]-(*(*info).plotpos).reflsx0[i])/2.+$
          (*(*info).plotpos).reflsx0[i], ((*(*info).plotpos).reflsy1[i]-$
          (*(*info).plotpos).reflsy0[i])/2.+(*(*info).plotpos).reflsy0[i], $
          'No data availabe for!Cselected pixel position', $
          COLOR=(*(*info).plotparams).plotcol, ALIGN=0.5, CHARSIZE=1.2, /NORMAL
    ENDFOR
    IF (*(*info).plotswitch).v_dop_set_ref THEN $
      XYOUTS,((*(*info).plotpos).reflsx1_all-(*(*info).plotpos).reflsx0_all)/2.+$
              (*(*info).plotpos).reflsx0_all,(*(*info).plotpos).reflsy0_all/5.*3+$
              (*(*info).plotpos).reflsy1_all, $
              (*(*info).plottitles).reflsdopxtitles[0], ALIGNMENT=0.5, $
              COLOR=(*(*info).plotparams).plotcol,/NORMAL
  ENDIF
  ; Pre-draw procedures: spectrum-time diagram (SP)
  IF (~KEYWORD_SET(LS_ONLY) AND (*(*info).winswitch).showrefsp) THEN BEGIN
  	IF (*(*info).dispparams).slices_imscale THEN BEGIN
      sel_idx = (*(*info).intparams).lp_ref_diag_all+$
        (*(*info).intparams).ndiagnostics
      CRISPEX_DRAW_SCALING,event,refdisp,minimum,maximum, /REF
      refminmax = CRISPEX_SCALING_CONTRAST(minimum,maximum,$
        (*(*info).scaling).minimum[sel_idx], (*(*info).scaling).maximum[sel_idx])
    ENDIF
    WSET, (*(*info).winids).refspwid
    TVLCT, r_cur, g_cur, b_cur, /GET
    TVLCT, (*(*info).plotparams).rgb_ref
    TV, *(*(*info).data).refspslice_congrid, (*(*info).plotpos).refspx0, $
      (*(*info).plotpos).refspy0, /NORM
    TVLCT, r_cur, g_cur, b_cur
    !X.WINDOW = [(*(*info).plotpos).refspx0,(*(*info).plotpos).refspx1]
    !Y.WINDOW = [(*(*info).plotpos).refspy0,(*(*info).plotpos).refspy1]
    ; In case of multiple diagnostics, overplot separator axes
    IF ((*(*info).intparams).nrefdiagnostics GT 1) THEN BEGIN
      ; Loop over all but the last diagnostic for plotting separators
      FOR d=1,(*(*info).intparams).ndisp_refdiagnostics-1 DO BEGIN
        AXIS,(d GE 1)*TOTAL((*(*(*info).plotaxes).refdiag_range_sp)[0:(d-1)])+$
          (*(*info).plotpos).refspx0, YAXIS=0, $
          YTICKLEN=(*(*info).plotaxes).refspyticklen, $
          YTICKNAME=REPLICATE(' ',60), COLOR=100,/NORMAL, $
          YRANGE=[(*(*info).dispparams).t_low_ref, $
          (*(*info).dispparams).t_upp_ref], YSTYLE=1, /NOERASE
        AXIS,(d GE 1)*TOTAL((*(*(*info).plotaxes).refdiag_range_sp)[0:(d-1)])+$
          (*(*info).plotpos).refspx0, YAXIS=1, $
          YTICKLEN=(*(*info).plotaxes).refspyticklen, $
          YTICKNAME=REPLICATE(' ',60), COLOR=100,/NORMAL,$
          YRANGE = [(*(*info).dispparams).t_low_ref, $
          (*(*info).dispparams).t_upp_ref], YSTYLE=1, /NOERASE
      ENDFOR
    ENDIF
    IF ((*(*info).dispswitch).xyref_out_of_range EQ 0) THEN BEGIN
      TVLCT, r_cur, g_cur, b_cur, /GET
      LOADCT, (*(*info).overlayparams).maskct, /SILENT
      ; Overplot time indicator
    	PLOTS, [(*(*info).plotpos).refspx0,(*(*info).plotpos).refspx1], $
              [1,1]*( ((*(*(*info).dispparams).tarr_ref)[$
              (*(*info).dispparams).t]-(*(*info).dispparams).t_low_ref) / $
              FLOAT((*(*info).dispparams).t_upp_ref-$
              (*(*info).dispparams).t_low_ref) * (*(*info).plotpos).refyplspw +$
              (*(*info).plotpos).refspy0), /NORMAL, $ 
              COLOR=(*(*info).overlayparams).maskcolor, $
              THICK=(*(*info).plotparams).plotthick
      ; Overplot lp indicator
      ; Determine in which diagnostic the current LP lies
      IF (lp_ref_diag EQ 0) THEN $
        offset = 0 $
      ELSE $
        offset = $
          TOTAL((*(*(*info).plotaxes).refdiag_range_sp)[0:(lp_ref_diag-1)])
      refspx0 = (*(*info).plotpos).refspx0 + offset
      refxplspw = (*(*(*info).plotaxes).refdiag_range_sp)[lp_ref_diag]
      ; Get the corresponding lp_disprange
      lp_ref_disprange = (*(*info).dataparams).reflps[$
                      (*(*info).dispparams).lp_ref_upp_tmp[$
                      (*(*info).intparams).lp_ref_diag_all]+$
                      (*(*(*info).intparams).refdiag_starts)[lp_ref_diag]] - $
                     (*(*info).dataparams).reflps[$
                      (*(*info).dispparams).lp_ref_low_tmp[$
                      (*(*info).intparams).lp_ref_diag_all]+$
                      (*(*(*info).intparams).refdiag_starts)[lp_ref_diag]]
      lp_ref_lower = (*(*info).dataparams).reflps[$
        (*(*info).dispparams).lp_ref_low_bounds[$
        (*(*info).intparams).lp_ref_diag_all]]
      PLOTS, [1,1] * (((*(*info).dataparams).reflps[(*(*info).dataparams).lp_ref]-$
                        lp_ref_lower) / lp_ref_disprange * refxplspw + refspx0 ), $
    		[(*(*info).plotpos).refspy0, (*(*info).plotpos).refspy1], /NORMAL, $
        COLOR=(*(*info).overlayparams).maskcolor, $
        THICK=(*(*info).plotparams).plotthick
        TVLCT, r_cur, g_cur, b_cur
    ENDIF ELSE $
  		XYOUTS, (*(*info).plotpos).refxplspw/2.+(*(*info).plotpos).refspx0,$
              (*(*info).plotpos).refyplspw/2.+(*(*info).plotpos).refspy0,$
              'No data available for!Cselected pixel position', COLOR=255, $
              ALIGNMENT = 0.5, CHARSIZE=1.2, /NORMAL
  ENDIF
END

PRO CRISPEX_DRAW_PHIS, event
; (Re)draw spectral slice along a slit procedure
	WIDGET_CONTROL, event.TOP, GET_UVALUE = info
	IF (TOTAL(((*(*info).feedbparams).verbosity)[2:3]) GE 1) THEN $
    CRISPEX_VERBOSE_GET_ROUTINE, event
	WSET, (*(*info).winids).phiswid
  ; If 2D, then display
  IF (((SIZE(*(*(*info).data).phislice))[0] EQ 2) AND $
    ((*(*info).dispswitch).xy_out_of_range EQ 0)) THEN BEGIN
    ; Display full spectrum-slit diagram at once
    TVLCT, r_cur, g_cur, b_cur, /GET
    TVLCT, (*(*info).plotparams).rgb_main
    TV,(CONGRID( *(*(*info).data).phislice, (*(*info).dispparams).phisnlpreb, $
      (*(*info).dispparams).nphireb, $
      INTERP=(*(*info).dispparams).interpspslice, /CENTER) ), $
      (*(*info).plotpos).phisx0, (*(*info).plotpos).phisy0, /NORMAL
    !X.WINDOW = [(*(*info).plotpos).phisx0,(*(*info).plotpos).phisx1]
    !Y.WINDOW = [(*(*info).plotpos).phisy0,(*(*info).plotpos).phisy1]
    TVLCT, r_cur, g_cur, b_cur
    IF ((*(*info).intparams).ndiagnostics GT 1) THEN BEGIN
      ; Loop over all but the last diagnostic for plotting separators
      FOR d=1,(*(*info).intparams).ndisp_diagnostics-1 DO BEGIN
        AXIS,TOTAL((*(*(*info).plotaxes).diag_range_phis)[0:(d-1)])+$
          (*(*info).plotpos).phisx0, YAXIS=0, $
          YTICKLEN=(*(*info).plotaxes).phisyticklen, $
          YTICKNAME=REPLICATE(' ',60), COLOR=100,/NORMAL,$
          YRANGE=(*(*info).plotaxes).phis_yrange, /YSTYLE, /NOERASE
        AXIS,TOTAL((*(*(*info).plotaxes).diag_range_phis)[0:(d-1)])+$
          (*(*info).plotpos).phisx0, YAXIS=1, $
          YTICKLEN=(*(*info).plotaxes).phisyticklen, $
          YTICKNAME=REPLICATE(' ',60), COLOR=100,/NORMAL,$
          YRANGE=(*(*info).plotaxes).phis_yrange, /YSTYLE, /NOERASE
      ENDFOR
    ENDIF
    TVLCT, r_cur, g_cur, b_cur, /GET
    LOADCT, (*(*info).overlayparams).maskct, /SILENT
    ; Overplot slit center indicator
  	PLOTS, [(*(*info).plotpos).phisx0, (*(*info).plotpos).phisx1], $
      [1,1] * ( (((*(*info).phiparams).nw_cur - (*(*info).phiparams).nphi)/2. + $
                  (*(*info).phiparams).sphi+0.5)/FLOAT((*(*info).phiparams).nw_cur)*$
                  (*(*info).plotpos).phisyplspw + (*(*info).plotpos).phisy0), $
                  /NORMAL, COLOR=(*(*info).overlayparams).maskcolor, $
                  THICK=(*(*info).plotparams).plotthick
    ; Overplot lp indicator
    lp_diag = TOTAL((*(*info).dataparams).lp GE *(*(*info).intparams).diag_starts)-1
    ; Determine in which diagnostic the current LP lies
    IF (lp_diag EQ 0) THEN $
      offset = 0 $
    ELSE $
      offset = TOTAL((*(*(*info).plotaxes).diag_range_phis)[0:(lp_diag-1)])
    phisx0 = (*(*info).plotpos).phisx0 + offset
    phisxplspw = (*(*(*info).plotaxes).diag_range_phis)[lp_diag]
    ; Get the corresponding lp_disprange
    lp_disprange = (*(*info).dataparams).lps[$
                    (*(*info).dispparams).lp_upp_tmp[$
                    (*(*info).intparams).lp_diag_all]+$
                    (*(*(*info).intparams).diag_starts)[lp_diag]] - $
                   (*(*info).dataparams).lps[$
                    (*(*info).dispparams).lp_low_tmp[$
                    (*(*info).intparams).lp_diag_all]+$
                    (*(*(*info).intparams).diag_starts)[lp_diag]]
    lp_lower = (*(*info).dataparams).lps[$
      (*(*info).dispparams).lp_low_bounds[(*(*info).intparams).lp_diag_all]]
  	PLOTS, [1,1] * ( ((*(*info).dataparams).lps[(*(*info).dataparams).lp] - $
                      lp_lower) / lp_disprange * phisxplspw + phisx0 ), $
  		[(*(*info).plotpos).phisy0, (*(*info).plotpos).phisy1], /NORMAL, $
      COLOR=(*(*info).overlayparams).maskcolor, $
      THICK=(*(*info).plotparams).plotthick
      TVLCT, r_cur, g_cur, b_cur
  ; If not 2D, then show black screen and "error" message
  ENDIF ELSE BEGIN
    TV, CONGRID(*(*(*info).data).emptydopslice,(*(*info).dispparams).phisnlpreb, $
      (*(*info).dispparams).nphireb), (*(*info).plotpos).phisx0, $
      (*(*info).plotpos).phisy0, /NORMAL
		XYOUTS, (*(*info).plotpos).phisxplspw/2.+(*(*info).plotpos).phisx0,$
            (*(*info).plotpos).phisyplspw/2.+(*(*info).plotpos).phisy0,$
            'No Phi-slice availabe for !C selected pixel position', $
            COLOR=255, ALIGNMENT=0.5, CHARSIZE=1.2, /NORMAL
  ENDELSE
END

PRO CRISPEX_DRAW_LOOPSLAB, event
; (Re)draw loop timeslice procedure
	WIDGET_CONTROL, event.TOP, GET_UVALUE = info
	IF (TOTAL(((*(*info).feedbparams).verbosity)[2:3]) GE 1) THEN $
    CRISPEX_VERBOSE_GET_ROUTINE, event
	WSET, (*(*info).winids).loopwid
	IF (((*(*info).feedbparams).verbosity)[3] EQ 1) THEN $
    CRISPEX_VERBOSE_GET, event, [(*(*info).winids).loopwid], $
    labels=['Window ID for draw']
  IF ((*(*info).loopparams).nw_lpts NE 0) THEN BEGIN
  	dispslice = (*(*(*info).loopsdata).loopslice)[*,$
      (*(*(*info).dispparams).tsel_main)[(*(*info).dispparams).t_low]:$
      (*(*(*info).dispparams).tsel_main)[(*(*info).dispparams).t_upp]]
  	IF (*(*info).dispparams).slices_imscale THEN BEGIN
      CRISPEX_DRAW_SCALING,event,imdisp,minimum,maximum,/MAIN 
      minmax = CRISPEX_SCALING_CONTRAST(minimum,maximum,$
        (*(*info).scaling).minimum[(*(*info).intparams).lp_diag_all],$
        (*(*info).scaling).maximum[(*(*info).intparams).lp_diag_all])
    ENDIF ELSE BEGIN
      minimum = MIN(dispslice,MAX=maximum)
      minmax = [minimum, maximum]
    ENDELSE
    IF ((*(*info).loopparams).ngaps GE 1) THEN BEGIN
      dispslice_data = dispslice
      ; Arbitrary, but consistent, minimum value such that the gaps are really
      ; black compared to the data values
      min_dispslice_data = $
        -(1+(MIN(dispslice_data) LT 0)*2) * ABS(MIN(dispslice_data))
      IF ((*(*(*info).loopsdata).empty_slice)[0,0] NE min_dispslice_data) THEN $
        REPLICATE_INPLACE, *(*(*info).loopsdata).empty_slice, min_dispslice_data
      dispslice = (*(*(*info).loopsdata).empty_slice)[*, $
        (*(*(*info).dispparams).tsel_main)[(*(*info).dispparams).t_low]:$
        (*(*(*info).dispparams).tsel_main)[(*(*info).dispparams).t_upp]]
      idx_out = $
        (*(*(*info).loopparams).w_lpts)[*(*(*info).loopparams).databounds]
      FOR i=0,N_ELEMENTS(*(*(*info).loopparams).databounds)/2-1 DO $
        dispslice[idx_out[2*i]:idx_out[2*i+1], *] = $
          dispslice_data[$
            (*(*(*info).loopparams).databounds)[2*i]:$
            (*(*(*info).loopparams).databounds)[2*i+1],*]
    ENDIF
  ENDIF ELSE BEGIN
    REPLICATE_INPLACE, *(*(*info).loopsdata).empty_slice, 0
    dispslice = *(*(*info).loopsdata).empty_slice
    minmax = [0,1]
  ENDELSE
  TVLCT, r_cur, g_cur, b_cur, /GET
  TVLCT, (*(*info).plotparams).rgb_main
	TV, CONGRID( BYTSCL(dispslice, MIN=minmax[0], MAX=minmax[1], /NAN), $
    (*(*info).dispparams).loopnlxreb, (*(*info).dispparams).loopntreb, $
    /INTERP), (*(*info).plotpos).loopx0, (*(*info).plotpos).loopy0, /NORM
  TVLCT, r_cur, g_cur, b_cur
  IF ((*(*info).loopparams).nw_lpts NE 0) THEN BEGIN
    LOADCT, (*(*info).overlayparams).maskct, /SILENT
    ; Overplot time indicator
  	PLOTS, [(*(*info).plotpos).loopx0,(*(*info).plotpos).loopx1], $
            [1,1]*( ((*(*(*info).dispparams).tarr_main)[(*(*info).dispparams).t]-$
            (*(*info).dispparams).t_low_main) / $
            FLOAT((*(*info).dispparams).t_upp_main-(*(*info).dispparams).t_low_main) * $
  	        (*(*info).plotpos).loopyplspw + (*(*info).plotpos).loopy0), /NORMAL, $
            COLOR=(*(*info).overlayparams).maskcolor, $
            THICK=(*(*info).plotparams).plotthick
    TVLCT, r_cur, g_cur, b_cur
    ; Overplot crossloc indicators
  	FOR i=0,(*(*info).loopparams).np-1 DO BEGIN
  		PLOTS, [1,1] * ( FLOAT((*(*(*info).loopsdata).crossloc)[i]) / $
        FLOAT((*(*info).loopsdata).loopsize-1) * (*(*info).plotpos).loopxplspw + $
        (*(*info).plotpos).loopx0 ), $
  			[(*(*info).plotpos).loopy0, (*(*info).plotpos).loopy1], /NORMAL, COLOR = 100
  		IF (((*(*info).feedbparams).verbosity)[3] EQ 1) THEN $
        CRISPEX_VERBOSE_GET, event, (*(*(*info).loopsdata).crossloc)[i], $
          labels='crossloc['+STRTRIM(i,2)+']'
  	ENDFOR
  ENDIF ELSE $
		XYOUTS, (*(*info).plotpos).loopxplspw/2.+(*(*info).plotpos).loopx0,$
            (*(*info).plotpos).loopyplspw/2.+(*(*info).plotpos).loopy0,$
            'No space-time diagram availabe !C for current path', COLOR = 255, $
            ALIGNMENT = 0.5, CHARSIZE=1.2, /NORMAL
END

PRO CRISPEX_DRAW_REFLOOPSLAB, event
; (Re)draw reference loop timeslice procedure
	WIDGET_CONTROL, event.TOP, GET_UVALUE = info
	IF (TOTAL(((*(*info).feedbparams).verbosity)[2:3]) GE 1) THEN $
    CRISPEX_VERBOSE_GET_ROUTINE, event
	WSET, (*(*info).winids).refloopwid
	IF (((*(*info).feedbparams).verbosity)[3] EQ 1) THEN $
    CRISPEX_VERBOSE_GET, event, [(*(*info).winids).refloopwid], $
    labels=['Window ID for draw']
  IF ((*(*info).loopparams).nw_lpts_ref NE 0) THEN BEGIN
  	dispslice = (*(*(*info).loopsdata).refloopslice)[*,$
      (*(*(*info).dispparams).tsel_ref)[(*(*info).dispparams).t_low]:$
      (*(*(*info).dispparams).tsel_ref)[(*(*info).dispparams).t_upp]]
    sel_idx = (*(*info).intparams).lp_ref_diag_all+(*(*info).intparams).ndiagnostics
  	IF (*(*info).dispparams).slices_imscale THEN BEGIN
      CRISPEX_DRAW_SCALING,event,refdisp,minimum,maximum,/REFERENCE 
      minmax = CRISPEX_SCALING_CONTRAST(minimum,maximum,$
        (*(*info).scaling).minimum[sel_idx], (*(*info).scaling).maximum[sel_idx])
    ENDIF ELSE BEGIN
      minimum = MIN(dispslice,MAX=maximum)
      minmax = [minimum, maximum]
    ENDELSE
    IF ((*(*info).loopparams).ngaps_ref GE 1) THEN BEGIN
      dispslice_data = dispslice
      ; Arbitrary, but consistent, minimum value such that the gaps are really
      ; black compared to the data values
      min_dispslice_data = $
        -(1+(MIN(dispslice_data) LT 0)*2) * ABS(MIN(dispslice_data))
      IF ((*(*(*info).loopsdata).empty_refslice)[0,0] NE min_dispslice_data) THEN $
        REPLICATE_INPLACE, *(*(*info).loopsdata).empty_refslice, min_dispslice_data
      dispslice = (*(*(*info).loopsdata).empty_refslice)[*, $
        (*(*(*info).dispparams).tsel_ref)[(*(*info).dispparams).t_low]:$
        (*(*(*info).dispparams).tsel_ref)[(*(*info).dispparams).t_upp]]
      idx_out = $
        (*(*(*info).loopparams).w_lpts_ref)[*(*(*info).loopparams).databounds_ref]
      FOR i=0,N_ELEMENTS(*(*(*info).loopparams).databounds_ref)/2-1 DO $
        dispslice[idx_out[2*i]:idx_out[2*i+1], *] = $
          dispslice_data[$
            (*(*(*info).loopparams).databounds_ref)[2*i]:$
            (*(*(*info).loopparams).databounds_ref)[2*i+1],*]
    ENDIF
  ENDIF ELSE BEGIN
    dispslice = *(*(*info).loopsdata).empty_refslice
    minmax = [0,1]
  ENDELSE
  TVLCT, r_cur, g_cur, b_cur, /GET
  TVLCT, (*(*info).plotparams).rgb_ref
	TV, CONGRID( BYTSCL(dispslice, MIN=minmax[0], MAX=minmax[1], /NAN), $
    (*(*info).dispparams).refloopnlxreb, $
    (*(*info).dispparams).refloopntreb, /INTERP), $
		(*(*info).plotpos).refloopx0, (*(*info).plotpos).refloopy0,/NORM
  TVLCT, r_cur, g_cur, b_cur
  IF ((*(*info).loopparams).nw_lpts_ref NE 0) THEN BEGIN
    LOADCT, (*(*info).overlayparams).maskct, /SILENT
    ; Overplot time indicator
  	PLOTS, [(*(*info).plotpos).refloopx0,(*(*info).plotpos).refloopx1], $
            [1,1]*( ((*(*(*info).dispparams).tarr_ref)[(*(*info).dispparams).t]-$
            (*(*info).dispparams).t_low_ref) / $
            FLOAT((*(*info).dispparams).t_upp_ref-(*(*info).dispparams).t_low_ref) * $
  	        (*(*info).plotpos).refloopyplspw + (*(*info).plotpos).refloopy0), $
            /NORMAL, COLOR=(*(*info).overlayparams).maskcolor, $
            THICK=(*(*info).plotparams).plotthick
    TVLCT, r_cur, g_cur, b_cur
    ; Overplot crossloc indicators
  	FOR i=0,(*(*info).loopparams).np_ref-1 DO BEGIN
  		PLOTS, [1,1] * ( FLOAT((*(*(*info).loopsdata).refcrossloc)[i]) / $
        FLOAT((*(*info).loopsdata).refloopsize-1) * (*(*info).plotpos).refloopxplspw + $
        (*(*info).plotpos).refloopx0 ), $
  			[(*(*info).plotpos).refloopy0, (*(*info).plotpos).refloopy1], /NORMAL, $
        COLOR = 100
  		IF (((*(*info).feedbparams).verbosity)[3] EQ 1) THEN $
        CRISPEX_VERBOSE_GET, event, (*(*(*info).loopsdata).refcrossloc)[i], $
          labels='crossloc['+STRTRIM(i,2)+']'
  	ENDFOR
  ENDIF ELSE $
		XYOUTS, (*(*info).plotpos).refloopxplspw/2.+(*(*info).plotpos).refloopx0,$
            (*(*info).plotpos).refloopyplspw/2.+(*(*info).plotpos).refloopy0,$
            'No space-time diagram availabe !C for current path', COLOR = 255, $
            ALIGNMENT = 0.5, CHARSIZE=1.2, /NORMAL
END

PRO CRISPEX_DRAW_SJILOOPSLAB, event
; (Re)draw slit-jaw loop timeslice procedure
	WIDGET_CONTROL, event.TOP, GET_UVALUE = info
	IF (TOTAL(((*(*info).feedbparams).verbosity)[2:3]) GE 1) THEN $
    CRISPEX_VERBOSE_GET_ROUTINE, event
  FOR ii=0,(*(*info).winswitch).nwhereshowsji-1 DO BEGIN
    idx_sji = (*(*(*info).winswitch).whereshowsji)[ii]
  	WSET, (*(*info).winids).sjiloopwid[idx_sji]
  	IF (((*(*info).feedbparams).verbosity)[3] EQ 1) THEN $
      CRISPEX_VERBOSE_GET, event, [(*(*info).winids).sjiloopwid[idx_sji]], $
      labels=['Window ID for draw']
    IF ((*(*info).loopparams).nw_lpts_sji[idx_sji] NE 0) THEN BEGIN
    	dispslice = (*(*(*info).loopsdata).sjiloopslice[idx_sji])[*,$
        (*(*(*info).dispparams).tsel_sji[idx_sji])[(*(*info).dispparams).t_low]:$
        (*(*(*info).dispparams).tsel_sji[idx_sji])[(*(*info).dispparams).t_upp]]
      dispslice += MIN(dispslice)
      sel_idx = 2*(*(*info).intparams).ndiagnostics+$
        (*(*info).intparams).nrefdiagnostics
      scale_idx = sel_idx + idx_sji
    	IF (*(*info).dispparams).slices_imscale THEN BEGIN
        CRISPEX_DRAW_SCALING,event,sjidisp,minimum,maximum,/SJI
        minmax = CRISPEX_SCALING_CONTRAST(minimum,maximum,$
          (*(*info).scaling).minimum[sel_idx], (*(*info).scaling).maximum[sel_idx])
      ENDIF ELSE BEGIN
        minmax = CRISPEX_SCALING_SLICES(dispslice, $
          (*(*info).scaling).gamma[sel_idx],$
          (*(*info).scaling).histo_opt_val[sel_idx], $
          (*(*info).scaling).minimum[sel_idx],$
          (*(*info).scaling).maximum[sel_idx])
      ENDELSE
      IF ((*(*info).loopparams).ngaps_sji[idx_sji] GE 1) THEN BEGIN
        dispslice_data = dispslice
        ; Arbitrary, but consistent, minimum value such that the gaps are really
        ; black compared to the data values
        min_dispslice_data = $
          -(1+(MIN(dispslice_data) LT 0)*2) * ABS(MIN(dispslice_data))
        IF ((*(*(*info).loopsdata).empty_sjislice)[0,0] NE min_dispslice_data) THEN $
          REPLICATE_INPLACE, *(*(*info).loopsdata).empty_sjislice, min_dispslice_data
        dispslice = (*(*(*info).loopsdata).empty_sjislice)[*, $
          (*(*(*info).dispparams).tsel_sji[idx_sji])[(*(*info).dispparams).t_low]:$
          (*(*(*info).dispparams).tsel_sji[idx_sji])[(*(*info).dispparams).t_upp]]
        idx_out = $
          (*(*(*info).loopparams).w_lpts_sji[idx_sji])[*(*(*info).loopparams).databounds_sji[idx_sji]]
        FOR i=0,N_ELEMENTS(*(*(*info).loopparams).databounds_sji[idx_sji])/2-1 DO $
          dispslice[idx_out[2*i]:idx_out[2*i+1], *] = $
            dispslice_data[$
              (*(*(*info).loopparams).databounds_sji[idx_sji])[2*i]:$
              (*(*(*info).loopparams).databounds_sji[idx_sji])[2*i+1],*]
      ENDIF
    ENDIF ELSE BEGIN
      dispslice = *(*(*info).loopsdata).empty_sjislice
      minmax = [0,1]
    ENDELSE
    TVLCT, r_cur, g_cur, b_cur, /GET
    TVLCT, *(*(*info).plotparams).rgb_sji[idx_sji]
  	TV, CONGRID( BYTSCL(dispslice, MIN=minmax[0], MAX=minmax[1], /NAN), $
      (*(*info).dispparams).sjiloopnlxreb, $
      (*(*info).dispparams).sjiloopntreb, /INTERP), $
  		(*(*info).plotpos).sjiloopx0, (*(*info).plotpos).sjiloopy0,/NORM
    TVLCT, r_cur, g_cur, b_cur
    IF ((*(*info).loopparams).nw_lpts_sji[idx_sji] NE 0) THEN BEGIN
      LOADCT, (*(*info).overlayparams).maskct, /SILENT
      ; Overplot time indicator
    	PLOTS, [(*(*info).plotpos).sjiloopx0,(*(*info).plotpos).sjiloopx1], $
              [1,1]*( ((*(*(*info).dispparams).tarr_sji[idx_sji])[(*(*info).dispparams).t]-$
              (*(*info).dispparams).t_low_sji[idx_sji]) / $
              FLOAT((*(*info).dispparams).t_upp_sji[idx_sji]-$
              (*(*info).dispparams).t_low_sji[idx_sji]) * $
    	        (*(*info).plotpos).sjiloopyplspw + (*(*info).plotpos).sjiloopy0), $
              /NORMAL, COLOR=(*(*info).overlayparams).maskcolor, $
              THICK=(*(*info).plotparams).plotthick
      TVLCT, r_cur, g_cur, b_cur
      ; Overplot crossloc indicators
    	FOR i=0,(*(*info).loopparams).np_sji-1 DO BEGIN
    		PLOTS, [1,1] * ( FLOAT((*(*(*info).loopsdata).sjicrossloc[idx_sji])[i]) / $
          FLOAT((*(*info).loopsdata).sjiloopsize[idx_sji]-1) * (*(*info).plotpos).sjiloopxplspw + $
          (*(*info).plotpos).sjiloopx0 ), $
    			[(*(*info).plotpos).sjiloopy0, (*(*info).plotpos).sjiloopy1], /NORMAL, $
          COLOR = 100
    		IF (((*(*info).feedbparams).verbosity)[3] EQ 1) THEN $
          CRISPEX_VERBOSE_GET, event, $
            (*(*(*info).loopsdata).sjicrossloc[idx_sji])[i], $
            labels='crossloc['+STRTRIM(i,2)+']'
    	ENDFOR
    ENDIF ELSE $
  		XYOUTS, (*(*info).plotpos).sjiloopxplspw/2.+(*(*info).plotpos).sjiloopx0,$
              (*(*info).plotpos).sjiloopyplspw/2.+(*(*info).plotpos).sjiloopy0,$
              'No space-time diagram availabe !C for current path', COLOR = 255, $
              ALIGNMENT = 0.5, CHARSIZE=1.2, /NORMAL
  ENDFOR
END

PRO CRISPEX_DRAW_REST_LOOP, event
; (Re)draw restored loop timeslice procedure
	WIDGET_CONTROL, event.TOP, GET_UVALUE = info
	IF (TOTAL(((*(*info).feedbparams).verbosity)[2:3]) GE 1) THEN $
    CRISPEX_VERBOSE_GET_ROUTINE, event
	FOR k=0,N_ELEMENTS(*(*(*info).winids).restlooptlb)-1 DO BEGIN
		WSET, (*(*(*info).winids).restloopwid)[k]
		IF (((*(*info).feedbparams).verbosity)[3] EQ 1) THEN $
      CRISPEX_VERBOSE_GET, event, [(*(*(*info).winids).restloopwid)[k]], $
      labels=['Window ID for draw']
    IF (*(*(*info).restoreparams).disp_imref)[k] THEN BEGIN
      tsel = *(*(*info).dispparams).tsel_ref 
      tarr = *(*(*info).dispparams).tarr_ref 
      rgb_table = (*(*info).plotparams).rgb_ref
    ENDIF ELSE IF ((*(*(*info).restoreparams).disp_imref)[k] EQ 2) THEN BEGIN
      tsel = *(*(*info).dispparams).tsel_sji
      tarr = *(*(*info).dispparams).tarr_sji
      rgb_table = (*(*info).plotparams).rgb_sji
    ENDIF ELSE BEGIN
      tsel = *(*(*info).dispparams).tsel_main
      tarr = *(*(*info).dispparams).tarr_main
      rgb_table = (*(*info).plotparams).rgb_main
    ENDELSE
		IF (*(*(*info).dispswitch).restricted_t_range)[k] THEN BEGIN
			lower_t = 0
			upper_t = tsel[(*(*info).dispparams).t_upp] - tsel[(*(*info).dispparams).t_low]
		ENDIF ELSE BEGIN
			lower_t = tsel[(*(*info).dispparams).t_low]
			upper_t = tsel[(*(*info).dispparams).t_upp]
		ENDELSE
    lower_t_val = tarr[(*(*info).dispparams).t_low]
    upper_t_val = tarr[(*(*info).dispparams).t_upp]
    ; Get dispslice
		dispslice = (*(*(*(*info).loopsdata).rest_loopslice[k]))[*,lower_t:upper_t]
		IF ((*(*(*info).restoreparams).disp_imref)[k] EQ 1) THEN $
      ; Reference scaling
      int_idx = (*(*info).intparams).lp_ref_diag_all+$
        (*(*info).intparams).ndiagnostics $
    ELSE IF ((*(*(*info).restoreparams).disp_imref)[k] EQ 2) THEN $
      ; SJI scaling
      int_idx = 2*(*(*info).intparams).ndiagnostics+$
        (*(*info).intparams).nrefdiagnostics $
		ELSE $
      ; Main scaling
      int_idx = (*(*info).intparams).lp_diag_all
  	IF (*(*info).dispparams).slices_imscale THEN BEGIN
      CRISPEX_DRAW_SCALING,event,seldisp,minimum,maximum,$
        MAIN=((*(*(*info).restoreparams).disp_imref)[k] EQ 0), $
        REFERENCE=((*(*(*info).restoreparams).disp_imref)[k] EQ 1), $
        SJI=((*(*(*info).restoreparams).disp_imref)[k] EQ 2)
      minmax = CRISPEX_SCALING_CONTRAST(minimum,maximum,$
        (*(*info).scaling).minimum[int_idx], (*(*info).scaling).maximum[int_idx])
    ENDIF ELSE BEGIN
      minmax = CRISPEX_SCALING_SLICES(dispslice, $
        (*(*info).scaling).gamma[int_idx],$
        (*(*info).scaling).histo_opt_val[int_idx], $
        (*(*info).scaling).minimum[int_idx],$
        (*(*info).scaling).maximum[int_idx])
    ENDELSE
    minimum = minmax[0]
    maximum = minmax[1]
    sel_idx = (*(*(*info).restoreparams).disp_loopnr)[k]
    IF ((*(*(*info).restoreparams).ngaps)[sel_idx] GE 1) THEN BEGIN
      sel_databounds = $
        *(*(*(*info).restoreparams).databounds)[sel_idx]
      sel_wdatabounds = $
        *(*(*(*info).restoreparams).wdatabounds)[sel_idx]
      dispslice_data = dispslice
      ; Select subset of rest_empty_slice if necessary
      dispslice = (*(*(*(*info).loopsdata).rest_empty_slice)[sel_idx])[*,$
        lower_t:upper_t]
      ; Fill dispslice with empty and actual data
      FOR i=0,N_ELEMENTS(sel_databounds)/2-1 DO $
        dispslice[sel_wdatabounds[2*i]:sel_wdatabounds[2*i+1], *] = $
          dispslice_data[sel_databounds[2*i]:sel_databounds[2*i+1],*]
    ENDIF
    ; Display slice
    TVLCT, r_cur, g_cur, b_cur, /GET
;    LOADCT, ct_sel, /SILENT 
    TVLCT, rgb_table
		TV, CONGRID( BYTSCL(dispslice, MIN=minimum, MAX=maximum, /NAN), $
      (*(*info).dispparams).restloopnlxreb,$
      (*(*info).dispparams).restloopntreb, /INTERP), $
			(*(*info).plotpos).restloopx0, (*(*info).plotpos).restloopy0, /NORM
    ; Overplot time indicator
    LOADCT, (*(*info).overlayparams).maskct, /SILENT
		PLOTS, [(*(*info).plotpos).restloopx0, (*(*info).plotpos).restloopx1], $
      [1,1]*( (tarr[(*(*info).dispparams).t]-lower_t_val) / $
      FLOAT(upper_t_val-lower_t_val) * (*(*info).plotpos).restloopyplspw + $
      (*(*info).plotpos).restloopy0), /NORMAL, $
      COLOR=(*(*info).overlayparams).maskcolor, $
      THICK=(*(*info).plotparams).plotthick
		FOR i=0,(SIZE(*(*(*(*info).loopsdata).rest_crossloc[k])))[1]-1 DO BEGIN
			PLOTS, [1,1] * ( FLOAT((*(*(*(*info).loopsdata).rest_crossloc[k]))[i]) /$
		    FLOAT(N_ELEMENTS(*(*(*(*info).restoreparams).xr)[sel_idx])-1) * $
;        FLOAT((*(*(*info).loopsdata).rest_loopsize)[k]-1) * $
        (*(*info).plotpos).restloopxplspw + (*(*info).plotpos).restloopx0 ),$
				[(*(*info).plotpos).restloopy0, (*(*info).plotpos).restloopy1], $
        /NORMAL, COLOR=(*(*info).overlayparams).maskcolor
    TVLCT, r_cur, g_cur, b_cur
		ENDFOR
	ENDFOR
END

PRO CRISPEX_DRAW_RETR_DET, event
; (Re)draw restreived detection procedure
	WIDGET_CONTROL, event.TOP, GET_UVALUE = info
	IF (TOTAL(((*(*info).feedbparams).verbosity)[2:3]) GE 1) THEN $
    CRISPEX_VERBOSE_GET_ROUTINE, event
	WSET, (*(*info).winids).retrdetwid
	IF (((*(*info).feedbparams).verbosity)[3] EQ 1) THEN $
    CRISPEX_VERBOSE_GET, event, [(*(*info).winids).retrdetwid], labels=['Window ID for draw']
  ; Get dispslice
 	dispslice = (*(*(*info).loopsdata).det_loopslice)[*,$
    (*(*info).dispparams).t_low_main:(*(*info).dispparams).t_upp_main]
	IF (*(*info).dispparams).slices_imscale THEN $
    CRISPEX_DRAW_SCALING,event,imdisp,minimum,maximum,/MAIN $
  ELSE $
    minimum = MIN(dispslice,MAX=maximum, /NAN)
  IF ((*(*info).detparams).ngaps GE 1) THEN BEGIN
    dispslice_data = dispslice
    ; Select subset of det_empty_slice if necessary
    dispslice = (*(*(*info).loopsdata).det_empty_slice)[*, $
      (*(*info).dispparams).t_low_main:(*(*info).dispparams).t_upp_main]
    ; Fill dispslice with empty and actual data
    FOR i=0,N_ELEMENTS(*(*(*info).detparams).databounds)/2-1 DO $
      dispslice[(*(*(*info).detparams).wdatabounds)[2*i]:$
                (*(*(*info).detparams).wdatabounds)[2*i+1],*] = $
        dispslice_data[(*(*(*info).detparams).databounds)[2*i]:$
                       (*(*(*info).detparams).databounds)[2*i+1],*]
  ENDIF
  ; Display slice
  TVLCT, r_cur, g_cur, b_cur, /GET
  TVLCT, (*(*info).plotparams).rgb_main
	TV, CONGRID( BYTSCL(dispslice, MIN=minimum, MAX=maximum, /NAN), $
    (*(*info).dispparams).retrdetnlxreb, (*(*info).dispparams).retrdetntreb, /INTERP), $
		(*(*info).plotpos).retrdetx0, (*(*info).plotpos).retrdety0, /NORM
  ; Overplot time indicator
  LOADCT, (*(*info).overlayparams).maskct, /SILENT
	PLOTS, [(*(*info).plotpos).retrdetx0, (*(*info).plotpos).retrdetx1], $
    [1,1]*( ((*(*(*info).dispparams).tarr_main)[(*(*info).dispparams).t]-$
    (*(*info).dispparams).t_low_main) / $
    FLOAT((*(*info).dispparams).t_upp_main-(*(*info).dispparams).t_low_main) * $
    (*(*info).plotpos).retrdetyplspw + (*(*info).plotpos).retrdety0), /NORMAL, $
    COLOR=(*(*info).overlayparams).maskcolor
  TVLCT, r_cur, g_cur, b_cur
END

;========================= ESTIMATE SAVING TIME PROCEDURES
PRO CRISPEX_ESTIMATE_TIME_WINDOW, event
; Opens the calculating saving time estimate window
	WIDGET_CONTROL, event.TOP, GET_UVALUE = info
	IF (TOTAL(((*(*info).feedbparams).verbosity)[2:3]) GE 1) THEN $
    CRISPEX_VERBOSE_GET_ROUTINE, event
	base = WIDGET_BASE(TITLE = 'CRISPEX'+(*(*info).sesparams).instance_label+': CALCULATING...', GROUP_LEADER = (*(*info).winids).root, TLB_FRAME_ATTR = 1, /TLB_KILL_REQUEST_EVENTS)
	disp = WIDGET_BASE(base, /COLUMN)
	message_base = WIDGET_BASE(disp, /COLUMN)
	(*(*info).ctrlsfeedb).estimate_label = WIDGET_LABEL(message_base, VALUE = 'Calculating time required for save procedure. Please wait...', /ALIGN_LEFT)
	label2	= WIDGET_LABEL(message_base, VALUE = ' ')
	WIDGET_CONTROL, base, /REALIZE, TLB_SET_XOFFSET = 500, TLB_SET_YOFFSET = 500
	WIDGET_CONTROL, base, SET_UVALUE = info
	XMANAGER, 'CRISPEX', base, /NO_BLOCK
	(*(*info).winids).estimatetlb = base
	(*(*info).winswitch).estimate_win = 1
	IF (((*(*info).feedbparams).verbosity)[3] EQ 1) THEN $
    CRISPEX_VERBOSE_GET, event, [(*(*info).winids).estimatetlb], labels=['estimatetlb']
END

PRO CRISPEX_ESTIMATE_TIME_CALCULATION, event
; Performs the actual saving time estimate calculation
	WIDGET_CONTROL, event.TOP, GET_UVALUE = info
	IF (TOTAL(((*(*info).feedbparams).verbosity)[2:3]) GE 1) THEN $
    CRISPEX_VERBOSE_GET_ROUTINE, event
	IF (*(*info).loopswitch).retrieve_loops THEN BEGIN
		RESTORE,(*(*(*info).retrparams).retrieve_files)[0]
		*(*(*info).loopparams).xr = x_loop_pts		&	*(*(*info).loopparams).yr = y_loop_pts
		*(*(*info).loopparams).w_lpts = w_loop_pts	&	(*(*info).dataparams).lp = spect_pos
	ENDIF 
	IF ((*(*info).dataparams).nt LT 100) THEN BEGIN
		endt = (*(*info).dataparams).nt & modulus = FIX((*(*info).dataparams).nt/3.) & result2 = FIX((*(*info).dataparams).nt/9.) & result3 = FIX((*(*info).dataparams).nt/9.*2.)
	ENDIF ELSE BEGIN
		endt = 100 & modulus = 30 & result2 = 10 & result3 = 20
	ENDELSE
	t_0 = SYSTIME(/SECONDS)
	FOR t=0,endt-1 DO BEGIN
			IF (t EQ 0) THEN tmp = INTERPOLATE( (*(*(*info).data).imagedata)[t*(*(*info).dataparams).nlp + (*(*info).dataparams).lp], (*(*(*info).loopparams).xr)[*(*(*info).loopparams).w_lpts],$
				(*(*(*info).loopparams).yr)[*(*(*info).loopparams).w_lpts]) $
			ELSE tmp = [[tmp], [INTERPOLATE( (*(*(*info).data).imagedata)[t*(*(*info).dataparams).nlp + (*(*info).dataparams).lp], (*(*(*info).loopparams).xr)[*(*(*info).loopparams).w_lpts],$
				(*(*(*info).loopparams).yr)[*(*(*info).loopparams).w_lpts])]]
		IF (t mod modulus EQ 0) THEN WIDGET_CONTROL, (*(*info).ctrlsfeedb).estimate_label, SET_VALUE = 'Calculating time required for save procedure. Please wait.'
		IF (t mod modulus EQ result2) THEN WIDGET_CONTROL, (*(*info).ctrlsfeedb).estimate_label, SET_VALUE = 'Calculating time required for save procedure. Please wait..'
		IF (t mod modulus EQ result3) THEN WIDGET_CONTROL, (*(*info).ctrlsfeedb).estimate_label, SET_VALUE = 'Calculating time required for save procedure. Please wait...'
	ENDFOR
	(*(*info).feedbparams).estimate_lx = N_ELEMENTS(*(*(*info).loopparams).w_lpts)
	(*(*info).feedbparams).estimate_time = (SYSTIME(/SECONDS) - t_0) / FLOAT(endt)
	(*(*info).feedbparams).estimate_run = 1
	WIDGET_CONTROL, (*(*info).ctrlscp).clear_current_estimate, /SENSITIVE
	IF (*(*info).loopswitch).retrieve_loops THEN BEGIN
		*(*(*info).loopparams).xr = 0	&	*(*(*info).loopparams).yr = 0	&	*(*(*info).loopparams).w_lpts = 0
	ENDIF
END

PRO CRISPEX_ESTIMATE_FULL_TIME, time, denom, units
  unitarr = [' seconds.',' minutes.',' hours.',' days.']
  denomarr = [1.,60.,3600.,86400.]
  caseid = FIX(TOTAL(time GT denomarr[1:3]))
  units = unitarr[caseid]
  denom = denomarr[caseid]
END

PRO CRISPEX_ESTIMATE_FULL_TIME_RUNNING, pass, totalpasses, t0, t1, denom, $
  units, accumsectime, totalsectime
; Gets the units and denominator for the saving time running estimate
	accumsectime = t1-t0
	totalsectime = accumsectime/pass*totalpasses
  CRISPEX_ESTIMATE_FULL_TIME, totalsectime, denom, units
END

;========================= TAB EVENT PROCEDURE
PRO CRISPEX_EVENT, event
; Handles tab events
	WIDGET_CONTROL, event.TOP, GET_UVALUE=info
	IF (TOTAL(((*(*info).feedbparams).verbosity)[2:3]) GE 1) THEN $
    CRISPEX_VERBOSE_GET_ROUTINE, event, /IGNORE_LAST
END

;========================= FIND CRISPEX OUTPUT FILE PROCEDURES
PRO CRISPEX_FIND_CLSAV, event, FORCE_PATH=force_path, $
  ALLOW_SELECT_DIR=allow_select_dir, ALL_FILES=all_files
; Finds CLSAV output files (i.e. saved loop points files)
	WIDGET_CONTROL, event.TOP, GET_UVALUE = info
	IF (TOTAL(((*(*info).feedbparams).verbosity)[2:3]) GE 1) THEN $
    CRISPEX_VERBOSE_GET_ROUTINE, event
  IF (N_ELEMENTS(FORCE_PATH) NE 1) THEN $
    path = (*(*info).paths).ipath $
  ELSE $
    path = force_path
	imagefilename = STRMID((*(*info).dataparams).imfilename, $
    STRPOS((*(*info).dataparams).imfilename,PATH_SEP(),/REVERSE_SEARCH)+1,$
    STRLEN((*(*info).dataparams).imfilename))
	firstsplit = STRMID(imagefilename,0,STRPOS(imagefilename,'.',/REVERSE_SEARCH))
	fstr = STRSPLIT(firstsplit[0],'_',/EXTRACT)
	IF (N_ELEMENTS(fstr) GE 2) THEN $
    filename = fstr[0]+'_'+fstr[1] $
  ELSE $
    filename = fstr[0]
	clfiles = FILE_SEARCH(path+filename+"*clsav", COUNT=clfilecount)
  refclfilecount = 0
  sjiclfilecount = 0
  IF KEYWORD_SET(ALL_FILES) THEN BEGIN
  	IF (*(*info).dataswitch).reffile THEN BEGIN
      refimfilename = FILE_BASENAME((*(*info).dataparams).refimfilename)
  		reffirstsplit = STRMID(refimfilename,0,STRPOS(refimfilename,'.',$
        /REVERSE_SEARCH))
  		refclfiles = FILE_SEARCH(path+reffirstsplit+"*clsav", $
        COUNT = refclfilecount)
    ENDIF 
  	IF (*(*info).dataswitch).sjifile THEN BEGIN
      FOR idx_sji=0,(*(*info).dataparams).nsjifiles-1 DO BEGIN
        sjifilename = FILE_BASENAME((*(*info).dataparams).sjifilename[idx_sji])
    		sjifirstsplit = STRMID(sjifilename,0,STRPOS(sjifilename,'.',$
          /REVERSE_SEARCH))
    		sjiclfiles_tmp = FILE_SEARCH(path+sjifirstsplit+"*clsav", $
          COUNT = sjiclfilecount_tmp)
        IF (idx_sji GE 1) THEN BEGIN
          sjiclfiles = [sjiclfiles,sjiclfiles_tmp]
          sjiclfilecount += sjiclfilecount_tmp
        ENDIF ELSE BEGIN
          sjiclfiles = sjiclfiles_tmp
          sjiclfilecount = sjiclfilecount_tmp
        ENDELSE
      ENDFOR
    ENDIF
  ENDIF
  ; If no *clsav files found, allow selection of new path and redo the search
  IF ((clfilecount EQ 0) AND (refclfilecount EQ 0) AND $
    (sjiclfilecount EQ 0) AND KEYWORD_SET(ALLOW_SELECT_DIR)) THEN BEGIN
		CRISPEX_WINDOW_OK, event,'ERROR!',$
      'No saved loop points (*.clsav) files found corresponding '+$
      'to the current data file. Please select an alternative input path.',$
			OK_EVENT='CRISPEX_CLOSE_EVENT_WINDOW', BASE=tlb, /BLOCK
		(*(*info).winids).errtlb = tlb
    newpath = DIALOG_PICKFILE(TITLE='CRISPEX'+(*(*info).sesparams).instance_label+$
      ': Select input path', /DIRECTORY, $
      PATH=(*(*info).paths).ipath,/MUST_EXIST)
    ; Failsafe against searching in workdir when cancelling
    IF (newpath EQ '') THEN newpath = ' ' 
    ; Redo the search at the new path
  	clfiles = FILE_SEARCH(newpath+firstsplit+"*clsav", $
      COUNT = clfilecount)
  	IF (*(*info).dataswitch).reffile THEN $
  		refclfiles = FILE_SEARCH(newpath+reffirstsplit+"*clsav", $
        COUNT = refclfilecount)
  	IF (*(*info).dataswitch).sjifile THEN BEGIN
      FOR idx_sji=0,(*(*info).dataparams).nsjifiles-1 DO BEGIN
        sjifilename = FILE_BASENAME((*(*info).dataparams).sjifilename[idx_sji])
    		sjifirstsplit = STRMID(sjifilename,0,STRPOS(sjifilename,'.',$
          /REVERSE_SEARCH))
    		sjiclfiles_tmp = FILE_SEARCH(path+sjifirstsplit+"*clsav", $
          COUNT = sjiclfilecount_tmp)
        IF (idx_sji GE 1) THEN BEGIN
          sjiclfiles = [sjiclfiles,sjiclfiles_tmp]
          sjiclfilecount += sjiclfilecount_tmp
        ENDIF ELSE BEGIN
          sjiclfiles = sjiclfiles_tmp
          sjiclfilecount = sjiclfilecount_tmp
        ENDELSE
      ENDFOR
    ENDIF
  ENDIF
  ; Save variables
  clfiles_tmp = ''
  clfilecount_tmp = 0
  IF (clfilecount NE 0) THEN BEGIN
    clfiles_tmp = clfiles
    clfilecount_tmp += clfilecount
  ENDIF
	IF ((*(*info).dataswitch).reffile AND (refclfilecount NE 0)) THEN BEGIN
    IF (clfilecount_tmp EQ 0) THEN $
      clfiles_tmp = refclfiles $
    ELSE $
      clfiles_tmp = [clfiles_tmp,refclfiles]
    clfilecount_tmp += refclfilecount
	ENDIF 
	IF ((*(*info).dataswitch).sjifile AND (sjiclfilecount NE 0)) THEN BEGIN
    IF (clfilecount_tmp EQ 0) THEN $
      clfiles_tmp = sjiclfiles $
    ELSE $
      clfiles_tmp = [clfiles_tmp,sjiclfiles]
    clfilecount_tmp += sjiclfilecount
	ENDIF 
	*(*(*info).retrparams).clfiles  = clfiles_tmp
	(*(*info).retrparams).clfilecount = clfilecount_tmp
	IF (((*(*info).feedbparams).verbosity)[3] EQ 1) THEN $
    CRISPEX_VERBOSE_GET, event, $
      [imagefilename, filename, STRTRIM((*(*info).retrparams).clfilecount,2)], $
      labels=['filename','basename','clfilecount']
END

PRO CRISPEX_FIND_CSAV, event, ALLOW_SELECT_DIR=allow_select_dir, $
  FORCE_PATH=force_path
; Finds CSAV output files (i.e. saved loopslice/slab files)
	WIDGET_CONTROL, event.TOP, GET_UVALUE = info
	IF (TOTAL(((*(*info).feedbparams).verbosity)[2:3]) GE 1) THEN $
    CRISPEX_VERBOSE_GET_ROUTINE, event
  IF (N_ELEMENTS(FORCE_PATH) NE 1) THEN $
    path = (*(*info).paths).ipath $
  ELSE $
    path = force_path
  refcfilecount = 0
	imagefilename = FILE_BASENAME((*(*info).dataparams).imfilename)
	firstsplit = STRMID(imagefilename,0,STRPOS(imagefilename,'.',/REVERSE_SEARCH))
  ; Do initial search
	cfiles = FILE_SEARCH(path+firstsplit+"*csav", $
    COUNT = cfilecount)
	IF (*(*info).dataswitch).reffile THEN BEGIN
    refimfilename = FILE_BASENAME((*(*info).dataparams).refimfilename)
		reffirstsplit = STRMID(refimfilename,0,STRPOS(refimfilename,'.',$
      /REVERSE_SEARCH))
		refcfiles = FILE_SEARCH(path+reffirstsplit+"*csav", $
      COUNT = refcfilecount)
  ENDIF ELSE $
    refcfilecount = 0
	IF (*(*info).dataswitch).sjifile THEN BEGIN
    FOR idx_sji=0,(*(*info).dataparams).nsjifiles-1 DO BEGIN
      sjifilename = FILE_BASENAME((*(*info).dataparams).sjifilename[idx_sji])
  		sjifirstsplit = STRMID(sjifilename,0,STRPOS(sjifilename,'.',$
        /REVERSE_SEARCH))
  		sjicfiles_tmp = FILE_SEARCH(path+sjifirstsplit+"*csav", $
        COUNT = sjicfilecount_tmp)
      IF (idx_sji GE 1) THEN BEGIN
        sjicfiles = [sjicfiles,sjicfiles_tmp]
        sjicfilecount += sjicfilecount_tmp
      ENDIF ELSE BEGIN
        sjicfiles = sjicfiles_tmp
        sjicfilecount = sjicfilecount_tmp
      ENDELSE
    ENDFOR
  ENDIF ELSE $
    sjicfilecount = 0
  ; If no *csav files found, allow selection of new path and redo the search
  IF ((cfilecount EQ 0) AND (refcfilecount EQ 0) AND $
    (sjicfilecount EQ 0) AND KEYWORD_SET(ALLOW_SELECT_DIR)) THEN BEGIN
		CRISPEX_WINDOW_OK, event,'ERROR!',$
      'No saved time slice (*.csav) files found corresponding '+$
      'to the current data file. Please select an alternative input path.',$
			OK_EVENT='CRISPEX_CLOSE_EVENT_WINDOW', BASE=tlb, /BLOCK
		(*(*info).winids).errtlb = tlb
    newpath = DIALOG_PICKFILE(TITLE='CRISPEX'+(*(*info).sesparams).instance_label+$
      ': Select input path', /DIRECTORY, $
      PATH=(*(*info).paths).ipath,/MUST_EXIST)
    ; Failsafe against searching in workdir when cancelling
    IF (newpath EQ '') THEN newpath = ' ' 
    ; Redo the search at the new path
  	cfiles = FILE_SEARCH(newpath+firstsplit+"*csav", $
      COUNT = cfilecount)
  	IF (*(*info).dataswitch).reffile THEN $
  		refcfiles = FILE_SEARCH(newpath+reffirstsplit+"*csav", $
        COUNT = refcfilecount)
  	IF (*(*info).dataswitch).sjifile THEN BEGIN
      FOR idx_sji=0,(*(*info).dataparams).nsjifiles-1 DO BEGIN
        sjifilename = FILE_BASENAME((*(*info).dataparams).sjifilename[idx_sji])
    		sjifirstsplit = STRMID(sjifilename,0,STRPOS(sjifilename,'.',$
          /REVERSE_SEARCH))
    		sjicfiles_tmp = FILE_SEARCH(path+sjifirstsplit+"*csav", $
          COUNT = sjicfilecount_tmp)
        IF (idx_sji GE 1) THEN BEGIN
          sjicfiles = [sjicfiles,sjicfiles_tmp]
          sjicfilecount += sjicfilecount_tmp
        ENDIF ELSE BEGIN
          sjicfiles = sjicfiles_tmp
          sjicfilecount = sjicfilecount_tmp
        ENDELSE
      ENDFOR
    ENDIF
  ENDIF
  ; Save variables
  cfiles_tmp = ''
  cfilecount_tmp = 0
  IF (cfilecount NE 0) THEN BEGIN
    cfiles_tmp = cfiles
    cfilecount_tmp += cfilecount
  ENDIF
	IF ((*(*info).dataswitch).reffile AND (refcfilecount NE 0)) THEN BEGIN
    IF (cfilecount_tmp EQ 0) THEN $
      cfiles_tmp = refcfiles $
    ELSE $
      cfiles_tmp = [cfiles_tmp,refcfiles]
    cfilecount_tmp += refcfilecount
	ENDIF 
	IF ((*(*info).dataswitch).sjifile AND (sjicfilecount NE 0)) THEN BEGIN
    IF (cfilecount_tmp EQ 0) THEN $
      cfiles_tmp = sjicfiles $
    ELSE $
      cfiles_tmp = [cfiles_tmp,sjicfiles]
    cfilecount_tmp += sjicfilecount
	ENDIF 
  *(*(*info).restoreparams).cfiles = cfiles_tmp
  (*(*info).restoreparams).cfilecount = cfilecount_tmp
	IF (((*(*info).feedbparams).verbosity)[3] EQ 1) THEN $
    CRISPEX_VERBOSE_GET, event, [imagefilename, filename, $
      STRTRIM((*(*info).restoreparams).cfilecount,2)], $
      labels=['filename','basename','cfilecount']
END

;========================= HELP PROCEDURE
PRO CRISPEX_HELP, event
; Opens the CRISPEX Reference Pages
	WIDGET_CONTROL, event.TOP, GET_UVALUE = info
	IF (TOTAL(((*(*info).feedbparams).verbosity)[2:3]) GE 1) THEN $
    CRISPEX_VERBOSE_GET_ROUTINE, event
	tempfile = FILEPATH('temp_crispex_redirect.html', /TMP)
	OPENW, lun, tempfile, /GET_LUN
	PRINTF, lun, '<HTML><HEADER><TITLE>CRISPEX help pages</TITLE><META HTTP-EQUIV="REFRESH" CONTENT="0;URL=http://folk.uio.no/gregal/crispex">'+$
		'</HEADER><BODY></BODY></HTML>'
	FREE_LUN, lun
	ONLINE_HELP, BOOK=tempfile
	WAIT, 10.0
	FILE_DELETE, tempfile
END

PRO CRISPEX_HELP_MAIL_BUG, event
; Opens a new message for bug reporting
	WIDGET_CONTROL, event.TOP, GET_UVALUE = info
	IF (TOTAL(((*(*info).feedbparams).verbosity)[2:3]) GE 1) THEN $
    CRISPEX_VERBOSE_GET_ROUTINE, event
	tempfile = FILEPATH('temp_crispex_report_bug.html', /TMP)
	subject = 'CRISPEX:%20Reporting%20bug%20in%20v'+(*(*info).versioninfo).version_number+'%20(rev%20'+(*(*info).versioninfo).revision_number+')'
	OPENW, lun, tempfile, /GET_LUN
	PRINTF, lun, '<HTML><HEADER><TITLE>CRISPEX: Report a bug</TITLE><META HTTP-EQUIV="REFRESH" CONTENT="0;URL=mailto:g.j.m.vissers@astro.uio.no?SUBJECT='+subject+'">'+$
		'</HEADER><BODY>If your e-mail client does not automatically open up a new message window, you may also send your bug report manually to: g.j.m.vissers@astro.uio.no, '+$
		'preferrably with <i>"CRISPEX: Reporting bug in v'+(*(*info).versioninfo).version_number+' (rev '+(*(*info).versioninfo).revision_number+')"</i> as subject heading.</BODY></HTML>'
	FREE_LUN, lun
	ONLINE_HELP, BOOK=tempfile
	WAIT, 10.0
	FILE_DELETE, tempfile
END

PRO CRISPEX_HELP_MAIL_SUGGESTION, event
; Opens a new message for suggestion reporting
	WIDGET_CONTROL, event.TOP, GET_UVALUE = info
	IF (TOTAL(((*(*info).feedbparams).verbosity)[2:3]) GE 1) THEN $
    CRISPEX_VERBOSE_GET_ROUTINE, event
	tempfile = FILEPATH('temp_crispex_report_suggestion.html', /TMP)
	subject = 'CRISPEX:%20Suggestion%20after%20v'+(*(*info).versioninfo).version_number+'%20(rev%20'+(*(*info).versioninfo).revision_number+')'
	OPENW, lun, tempfile, /GET_LUN
	PRINTF, lun, '<HTML><HEADER><TITLE>CRISPEX: Send a suggestion</TITLE><META HTTP-EQUIV="REFRESH" CONTENT="0;URL=mailto:g.j.m.vissers@astro.uio.no?SUBJECT='+subject+'">'+$
		'</HEADER><BODY>If your e-mail client does not automatically open up a new message window, you may also send your suggestion manually to: g.j.m.vissers@astro.uio.no, '+$
		'preferrably with <i>"CRISPEX: Suggestion after v'+(*(*info).versioninfo).version_number+' (rev '+(*(*info).versioninfo).revision_number+')"</i> as subject heading.</BODY></HTML>'
	FREE_LUN, lun
	ONLINE_HELP, BOOK=tempfile
	WAIT, 10.0
	FILE_DELETE, tempfile
END

PRO CRISPEX_HELP_SHORTCUTS, event
; Opens a window with an overview over the shortcuts
	WIDGET_CONTROL, event.TOP, GET_UVALUE = info
	IF (TOTAL(((*(*info).feedbparams).verbosity)[2:3]) GE 1) THEN $
    CRISPEX_VERBOSE_GET_ROUTINE, event
  ; Populate shortcut elements
  kb_shortcuts = [{sh:'Ctrl+Shift+I', label:'Zoom in'}, $
                  {sh:'Ctrl+Shift+O', label:'Zoom out'}, $
                  {sh:'Shift+B', label:'Step to previous frame'}, $
                  {sh:'Shift+Backspace', label:'Play backwards'}, $
                  {sh:'Shift+Spacebar', label:'Pause'}, $
                  {sh:'Shift+Tab', label:'Play forwards'}, $
                  {sh:'Shift+F', label:'Step to next frame'}, $
                  {sh:'Shift+A', label:'Decrease main '+$
                    STRLOWCASE((*(*info).paramparams).sp_h[(*(*info).plotswitch).heightset])+$
                    ' position'}, $
                  {sh:'Shift+S', label:'Increase main '+$
                    STRLOWCASE((*(*info).paramparams).sp_h[(*(*info).plotswitch).heightset])+$
                    ' position'}, $
                  {sh:'Ctrl+A', label:'Decrease reference '+$
                    STRLOWCASE((*(*info).paramparams).sp_h[(*(*info).plotswitch).refheightset])+$
                    ' position'}, $
                  {sh:'Ctrl+S', label:'Increase reference '+$
                    STRLOWCASE((*(*info).paramparams).sp_h[(*(*info).plotswitch).refheightset])+$
                    ' position'} ]
  ms_shortcuts = [{sh:'Left click', label:'Lock cursor to current position /'}, $
                  {sh:' ', label:'Add current position to path'}, $
                  {sh:'Middle click', label:'Fix cursor position for measurement'}, $
                  {sh:'Right click', label:'Unlock cursor'} ]
	title = 'CRISPEX'+(*(*info).sesparams).instance_label+': Shortcuts'
  base  = WIDGET_BASE(TITLE=title, GROUP_LEADER=(*(*info).winids).root, $
            /TLB_FRAME_ATTR, /TLB_KILL_REQUEST_EVENTS)
  disp  = WIDGET_BASE(base, /COLUMN)
  cols  = WIDGET_BASE(disp, /GRID_LAYOUT, COLUMN=2)
  col1  = WIDGET_BASE(cols, /COLUMN);, /FRAME)
  kb_lab= WIDGET_LABEL(col1, VALUE='Keyboard shortcuts:', /ALIGN_LEFT)
  bases1 = WIDGET_BASE(col1, /ROW)
  sh_base1 = WIDGET_BASE(bases1, /COLUMN)
  lb_base1 = WIDGET_BASE(bases1, /COLUMN)
  FOR i=0,N_ELEMENTS(kb_shortcuts.sh)-1 DO BEGIN
    kb_label= WIDGET_LABEL(sh_base1, VALUE=(kb_shortcuts.sh)[i], /ALIGN_LEFT)
    lb_label= WIDGET_LABEL(lb_base1, VALUE=(kb_shortcuts.label)[i], /ALIGN_LEFT)
  ENDFOR
  col2  = WIDGET_BASE(cols, /COLUMN);, /FRAME)
  ms_lab= WIDGET_LABEL(col2, VALUE='Mouse shortcuts:', /ALIGN_LEFT)
  bases2 = WIDGET_BASE(col2, /ROW)
  sh_base2 = WIDGET_BASE(bases2, /COLUMN)
  lb_base2 = WIDGET_BASE(bases2, /COLUMN)
  FOR i=0,N_ELEMENTS(ms_shortcuts.sh)-1 DO BEGIN
    ms_label= WIDGET_LABEL(sh_base2, VALUE=(ms_shortcuts.sh)[i], /ALIGN_LEFT)
    lb_label= WIDGET_LABEL(lb_base2, VALUE=(ms_shortcuts.label)[i], /ALIGN_LEFT)
  ENDFOR
  close_base = WIDGET_BASE(disp, /ALIGN_CENTER)
  close_button = WIDGET_BUTTON(close_base, VALUE='Close', EVENT_PRO='CRISPEX_CLOSE_EVENT_WINDOW')
  WIDGET_CONTROL, base, /REALIZE, TLB_SET_XOFFSET=(*(*info).winsizes).aboutxoffset, $
    TLB_SET_YOFFSET=(*(*info).winsizes).aboutyoffset
  (*(*info).winids).shorttlb = base
  WIDGET_CONTROL, base, SET_UVALUE=info
  XMANAGER, 'CRISPEX', base, /NO_BLOCK
END

;========================= LIGHTCURVE SAVE PROCEDURES
PRO CRISPEX_INT_SAVE, event
; Handles the actual saving of the lightcurve plots
	WIDGET_CONTROL, event.TOP, GET_UVALUE = info
	IF (TOTAL(((*(*info).feedbparams).verbosity)[2:3]) GE 1) THEN $
    CRISPEX_VERBOSE_GET_ROUTINE, event
	CRISPEX_SAVE_CHECK_PATH_WRITE, event
	CRISPEX_SAVE_DETERMINE_FILENAME, event, outfilename=intfilename, /tlab, ext='cint'
	condition = WHERE(*(*(*info).intparams).seldisp_diagnostics EQ 1, count)
  IF (count GT 0) THEN BEGIN
  	lightcurve = FLTARR((*(*info).dispparams).t_range,N_ELEMENTS(condition))
  	avg_intensity = FLTARR(N_ELEMENTS(condition))
  	FOR i=0,N_ELEMENTS(condition)-1 DO BEGIN
			IF (*(*info).dataswitch).spfile THEN BEGIN
  		  lightcurve[0,i] = REFORM( ( ( *(*(*info).data).spdata)[ $
          FIX((*(*info).dataparams).y) * (*(*info).dataparams).nx * (*(*info).dataparams).ns + $
          FIX((*(*info).dataparams).x) * (*(*info).dataparams).ns + $
  		  	(*(*info).dataparams).s ] )[$
          (*(*(*info).intparams).sellp_diagnostics)[condition[i]],$
            (*(*info).dispparams).t_low:(*(*info).dispparams).t_upp] )
      ENDIF ELSE BEGIN
				FOR t=0,(*(*info).dataparams).nt-1 DO BEGIN
					lightcurve[t,i] = ((*(*(*info).data).imagedata)[$
            t * (*(*info).dataparams).nlp * (*(*info).dataparams).ns + $
            (*(*info).dataparams).s * (*(*info).dataparams).nlp + $
						(*(*(*info).intparams).sellp_diagnostics)[condition[i]]])[$
            (*(*info).dataparams).x,(*(*info).dataparams).y]
				ENDFOR
      ENDELSE
  		avg_intensity[i] = MEAN(lightcurve[*,i], /NAN)
  	ENDFOR
    diagnostics = (*(*info).intparams).diagnostics[(*(*(*info).intparams).sel_diagnostics)[condition]]
  	x = (*(*info).dataparams).x		                &	y = (*(*info).dataparams).y
  	nt = (*(*info).dispparams).t_range	          & dt = (*(*info).plotaxes).dt
  	t_low_idx = (*(*info).dispparams).t_low	      &	t_upp_idx = (*(*info).dispparams).t_upp
    t_array_full = *(*(*info).dispparams).tarr_main
  	t_saved_idx = (*(*info).dispparams).t	  
    crispex_version = [(*(*info).versioninfo).version_number, (*(*info).versioninfo).revision_number]
  	SAVE, crispex_version, lightcurve, avg_intensity, diagnostics, nt, dt, $
      t_low_idx, t_upp_idx, t_array_full, t_saved_idx, x, y, $
      FILENAME=(*(*info).paths).opath+intfilename
  	PRINT, 'Written: '+(*(*info).paths).opath+intfilename
  ENDIF
END

;========================= INTERRUPT PROCEDURE
PRO CRISPEX_INTERRUPT, event
; Handles interrupting at runtime
	WIDGET_CONTROL, event.TOP, GET_UVALUE = info
	IF (TOTAL(((*(*info).feedbparams).verbosity)[2:3]) GE 1) THEN $
    CRISPEX_VERBOSE_GET_ROUTINE, event, /IGNORE_LAST
	PRINT,'Interrupted CRISPEX at runtime. Type [.c] to continue...'
	STOP
END

;========================= INPUT/OUTPUT PROCEDURES
PRO CRISPEX_IO_FAILSAFES_MAIN, imcube, spcube, input_single_cube, $
                               HDR_IN=hdr_in, HDR_OUT=hdr_out, $
                               STARTUPTLB=startuptlb, $
                               IO_FAILSAFE_ERROR=io_failsafe_error
  hdr_out = hdr_in
  io_failsafe_error = 0
  ; If SPCUBE has been supplied, check IMCUBE and SPCUBE compatibility
	IF hdr_out.spfile THEN BEGIN         
    ; Check whether SPCUBE and IMCUBE are actually the same
		IF ((spcube EQ imcube) OR ((hdr_in.nlp EQ hdr_in.nx) AND $
       (hdr_in.mainnt EQ hdr_in.ny) AND (hdr_in.spnt EQ hdr_in.imnt))) THEN BEGIN
      CRISPEX_UPDATE_STARTUP_SETUP_FEEDBACK, 'IMCUBE and SPCUBE must be different. Please check '+$
        'input (you seem to have provided the same file twice).',/ERROR,/NO_ROUTINE
			IF (N_ELEMENTS(STARTUPTLB) EQ 1) THEN WIDGET_CONTROL, startuptlb, /DESTROY
      io_failsafe_error = 1
			RETURN
		ENDIF
    ; Check whether condensed third dimensions of SPCUBE and IMCUBE are incompatible
		IF ((hdr_in.nx*hdr_in.ny*hdr_in.ns NE hdr_in.spnt) OR $
       (hdr_in.mainnt*hdr_in.nlp*hdr_in.ns NE hdr_in.imnt)) THEN BEGIN							
      CRISPEX_UPDATE_STARTUP_SETUP_FEEDBACK, 'IMCUBE and SPCUBE have incompatible dimensions and '+$
        'seem to belong to different datasets. Please check whether the input is correct (you '+$
        'provided IMCUBE='+STRTRIM(imcube,2)+' and SPCUBE='+STRTRIM(spcube,2)+').',/ERROR,$
        /NO_ROUTINE
			IF (N_ELEMENTS(STARTUPTLB) EQ 1) THEN WIDGET_CONTROL, startuptlb, /DESTROY
      io_failsafe_error = 1
			RETURN
		ENDIF
    ; Check, for multichannel cube, whether channels are incompatible
		IF hdr_out.multichannel THEN BEGIN
			IF ((hdr_in.spstokes NE hdr_in.imstokes) OR (hdr_in.spns NE hdr_in.imns)) THEN BEGIN
        CRISPEX_UPDATE_STARTUP_SETUP_FEEDBACK, 'IMCUBE and SPCUBE have incompatible number of '+$
          'channels and seem to belong to different datasets. Please check whether the input is '+$
          'correct (you provided IMCUBE='+STRTRIM(imcube,2)+' and SPCUBE='+STRTRIM(spcube,2)+').',$
          /ERROR,/NO_ROUTINE
				IF (N_ELEMENTS(STARTUPTLB) EQ 1) THEN WIDGET_CONTROL, startuptlb, /DESTROY
        io_failsafe_error = 1
				RETURN
			ENDIF ELSE $
        hdr_out.ns = hdr_in.imns  ; If they are compatible, set general number of channels
		ENDIF ELSE hdr_out.ns = 1L       ; If not multiple channels, set general number channels to 1
    ; Check whether SINGLE_CUBE keyword has been set in combination with provided SPCUBE
		IF (N_ELEMENTS(INPUT_SINGLE_CUBE) GT 0) THEN BEGIN
      CRISPEX_UPDATE_STARTUP_SETUP_FEEDBACK, 'Calling CRISPEX with SINGLE_CUBE, while SPCUBE is '+$
        'provided, is not allowed. SINGLE_CUBE keyword will be ignored.', /WARNING, /NO_ROUTINE
      io_failsafe_error = 2
			hdr_out.onecube = 0
		ENDIF
		hdr_out.single_cube[0] = 0
	ENDIF 
END

PRO CRISPEX_IO_FAILSAFES_MAIN_REF, HDR_IN=hdr_in, HDR_OUT=hdr_out, $
                                   STARTUPTLB=startuptlb, $
                                   IO_FAILSAFE_ERROR=io_failsafe_error
  hdr_out = hdr_in    
  ; Check dimensions of main and reference cubes
  ; Same nx, ny, dx, dy, crpix, crval -> must be same data, no mapping functions
  nxypix_eq = ((hdr_out.refnx EQ hdr_out.nx) AND (hdr_out.refny EQ hdr_out.ny))
  dxypix_eq = ((hdr_out.refdx EQ hdr_out.dx) AND (hdr_out.refdy EQ hdr_out.dy))
  refpix_eq = ((hdr_out.xpix_ref EQ hdr_out.xpix) AND $
    (hdr_out.ypix_ref EQ hdr_out.ypix))
  refval_eq = ((hdr_out.xval_ref EQ hdr_out.xval) AND $
    (hdr_out.yval_ref EQ hdr_out.yval)) 
  hdr_out.main2ref_no_map = (nxypix_eq AND dxypix_eq AND refpix_eq AND refval_eq)

  ; If mapping is necessary, check whether there is overlap at all
  IF (hdr_out.main2ref_no_map EQ 0) THEN BEGIN
    xref_low_main = hdr_out.xval_ref-hdr_out.xval
    yref_low_main = hdr_out.yval_ref-hdr_out.yval
    xref_upp_main = (hdr_out.refnx-1)*hdr_out.refdx/hdr_out.dx + $
                    (hdr_out.xval_ref-hdr_out.xval)
    yref_upp_main = (hdr_out.refny-1)*hdr_out.refdy/hdr_out.dy + $
                    (hdr_out.yval_ref-hdr_out.yval) 
    IF (((xref_upp_main LT 0) AND (yref_upp_main LT 0)) OR $
        ((xref_low_main GT (hdr_out.nx-1)) AND $
         (yref_low_main GT (hdr_out.ny-1)))) THEN BEGIN
      CRISPEX_UPDATE_STARTUP_SETUP_FEEDBACK, $
        'The fields of view of the main and reference data do not seem to '+$
        'overlap. Please check that you have provided compatible data sets '+$
        'and that their headers are correct.', /ERROR, /NO_ROUTINE, /NEWLINE
  		IF (N_ELEMENTS(STARTUPTLB) EQ 1) THEN WIDGET_CONTROL, startuptlb, /DESTROY
      io_failsafe_error = 1
  		RETURN
    ENDIF 
  ENDIF
END

PRO CRISPEX_IO_FAILSAFES_REF, refcube, input_single_cube, HDR_IN=hdr_in, HDR_OUT=hdr_out, $
                              STARTUPTLB=startuptlb, $
                              IO_FAILSAFE_ERROR=io_failsafe_error
; Handles failsafes against wrongly supplied reference image and spectral cubes
  hdr_out = hdr_in
  io_failsafe_error = 0
  IF (N_ELEMENTS(REFCUBE) EQ 2) THEN BEGIN
    ; Failsafe against providing the same file as REFIMCUBE and REFSPCUBE
    ; Check whether input cube names are the same, or
  	IF ((refcube[1] EQ refcube[0]) OR $         
      ; the cubes have same first dimensions
      (hdr_out.refnlp EQ hdr_out.refspnx) AND $        
      ; the cubes have same second dimenions
      (hdr_out.refnt EQ hdr_out.refspny) AND $          
      ; the cubes have same third dimensions
      (hdr_out.refspnt EQ hdr_out.refimnt)) THEN BEGIN  
      CRISPEX_UPDATE_STARTUP_SETUP_FEEDBACK, 'The reference image and spectral cubes must be '+$
        'different. Please check input (you seem to have provided the same file twice).', /ERROR, $
        /NO_ROUTINE, /NEWLINE
  		IF (N_ELEMENTS(STARTUPTLB) EQ 1) THEN WIDGET_CONTROL, startuptlb, /DESTROY
      io_failsafe_error = 1
  		RETURN
  	ENDIF
    ; Failsafe against providing incompatible REFIMCUBE and REFSPCUBE
  	IF ((hdr_out.refnx*hdr_out.refny*hdr_out.refns NE hdr_out.refspnt) OR $
        (hdr_out.refnt*hdr_out.refnlp*hdr_out.refns NE hdr_out.refimnt)) THEN BEGIN
      CRISPEX_UPDATE_STARTUP_SETUP_FEEDBACK, 'The reference image and spectral cubes have '+$
        'incompatible dimensions and seem to belong to different datasets. Please check whether '+$
        'the input is correct (you provided REFCUBE[0]='+STRTRIM(refcube[0],2)+' and REFCUBE[1]='+$
        STRTRIM(refcube[1],2)+').', /ERROR, /NO_ROUTINE, /NEWLINE
  	  IF (N_ELEMENTS(STARTUPTLB) EQ 1) THEN WIDGET_CONTROL, startuptlb, /DESTROY
      io_failsafe_error = 1
  		RETURN
  	ENDIF
    ; Check, for multichannel cube, whether channels are incompatible
		IF hdr_out.refmultichannel THEN BEGIN
			IF ((hdr_out.refspstokes NE hdr_out.refimstokes) OR $
          (hdr_out.refspns NE hdr_out.refimns)) THEN BEGIN
        CRISPEX_UPDATE_STARTUP_SETUP_FEEDBACK, $
          'The reference image and spectral cubes have incompatible number of '+$
          'channels and seem to belong to different datasets. Please check '+$
          'whether the input is correct (you provided REFCUBE[0]='+$
          STRTRIM(refcube[0],2)+' and REFCUBE[1]='+STRTRIM(refcube[1],2)+').',$
          /ERROR,/NO_ROUTINE
				IF (N_ELEMENTS(STARTUPTLB) EQ 1) THEN WIDGET_CONTROL, startuptlb, /DESTROY
        io_failsafe_error = 1
				RETURN
			ENDIF ELSE $
        hdr_out.refns = hdr_in.refimns  ; If they are compatible, set general number of channels
		ENDIF ELSE hdr_out.refns = 1L       ; If not multiple channels, set general number channels to 1
    ; Check whether SINGLE_CUBE keyword has been set in combination with provided SPCUBE
		IF (N_ELEMENTS(INPUT_SINGLE_CUBE) GT 0) THEN BEGIN
      CRISPEX_UPDATE_STARTUP_SETUP_FEEDBACK, 'Calling CRISPEX with SINGLE_CUBE with a 2-element '+$
        'array, while a reference SPCUBE is provided, is not allowed. SINGLE_CUBE keyword will '+$
        'be ignored.', /WARNING, /NO_ROUTINE
      io_failsafe_error = 2
		ENDIF
		hdr_out.single_cube[1] = 0
	ENDIF 
END

PRO CRISPEX_IO_FAILSAFES_MASK, maskcube, HDR=hdr, STARTUPTLB=startuptlb, $
                              IO_FAILSAFE_ERROR=io_failsafe_error
; Handles failsafes against wrongly supplied mask cube
  IF ((hdr.masknx EQ hdr.nx) AND (hdr.maskny EQ hdr.ny) AND $ ; Require same xy-dimensions as main
    ((hdr.masknt EQ hdr.mainnt) OR (hdr.masknt EQ 1))) THEN BEGIN ; Require same as main or 1 timestep
    io_failsafe_error = 0
	ENDIF ELSE BEGIN
	  IF ((hdr.masknx NE hdr.nx) OR (hdr.maskny NE hdr.ny)) THEN BEGIN
      CRISPEX_UPDATE_STARTUP_SETUP_FEEDBACK, 'Dimensions of the mask cube (['+$
        STRTRIM(hdr.masknx,2)+','+STRTRIM(hdr.maskny,2)+','+STRTRIM(hdr.masknt,2)+']) are not '+$
        'compatible with those of the main image cube (['+STRTRIM(hdr.nx,2)+','+STRTRIM(hdr.ny,2)+$
        ','+STRTRIM(hdr.mainnt,2)+'])! Number of pixels in the x- and y-dimension must be equal to '+$
        'those of the main image cube.', /ERROR, /NO_ROUTINE, /NEWLINE
	  ENDIF ELSE IF ((hdr.masknt NE hdr.mainnt) AND (hdr.masknt NE 1)) THEN BEGIN
      CRISPEX_UPDATE_STARTUP_SETUP_FEEDBACK, 'Dimensions of the mask cube (['+$
        STRTRIM(hdr.masknx,2)+','+STRTRIM(hdr.maskny,2)+','+STRTRIM(hdr.masknt,2)+']) are not '+$
        'compatible with those of the main image cube (['+STRTRIM(hdr.nx,2)+','+STRTRIM(hdr.ny,2)+$
        ','+STRTRIM(hdr.mainnt,2)+'])! Number of timesteps must be either equal to that of the main '+$
        'image cube ('+STRTRIM(hdr.mainnt,2)+') or to 1.', /ERROR, /NO_ROUTINE, /NEWLINE
	  ENDIF
    IF (N_ELEMENTS(STARTUPTLB) EQ 1) THEN WIDGET_CONTROL, startuptlb, /DESTROY
    io_failsafe_error = 1
		RETURN
  ENDELSE
END

PRO CRISPEX_IO_FAILSAFES_MNSPEC, mnspec, hdr, STARTUPTLB=startuptlb, $
                                 IO_FAILSAFE_ERROR=io_failsafe_error
; Handles failsafes against wrongly supplied MNSPEC values                                 
  extra_text = ''
  cumulative_error = (mnspec[0] LT 0)                               ; Check whether lower value >= 0
  cumulative_error += (mnspec[(N_ELEMENTS(MNSPEC) EQ 2)] GE hdr.mainnt) ; Check whether upper value < nt
  IF (N_ELEMENTS(MNSPEC) EQ 2) THEN BEGIN
    feedback_text = 's (['+STRTRIM(mnspec[0],2)+','+STRTRIM(mnspec[1],2)+'])'
    IF (mnspec[0] GT mnspec[1]) THEN $                     ; Check whether upper value > lower value
      extra_text = ' and be ordered from lower to higher value'
  ENDIF ELSE feedback_text = ' ('+STRTRIM(mnspec[0],2)+')' 
  io_failsafe_error = (TOTAL(cumulative_error) NE 0)
  IF io_failsafe_error THEN BEGIN
    CRISPEX_UPDATE_STARTUP_SETUP_FEEDBACK, 'MNSPEC value'+feedback_text+' must fall within '+$
      'allowed range [0,'+STRTRIM(LONG(hdr.mainnt-1),2)+']'+extra_text+'!',/ERROR,/NO_ROUTINE,/NEWLINE
	  IF (N_ELEMENTS(STARTUPTLB) EQ 1) THEN WIDGET_CONTROL, startuptlb, /DESTROY
	  RETURN
  ENDIF
END

PRO CRISPEX_IO_FAILSAFES_LINE_CENTER, line_center, hdr, NFILES=nfiles, STARTUPTLB=startuptlb, $
                                      SPECTFILE_SET=spectfile_set, $
                                      REFSPECTFILE_SET=refspectfile_set, $
                                      IO_FAILSAFE_ERROR=io_failsafe_error
; Handles failsafes against wrongly supplied LINE_CENTER values or formatting
  ndims = SIZE(LINE_CENTER,/N_DIMENSIONS) > 1
  nelem = N_ELEMENTS(LINE_CENTER)
  lcase = nelem / ndims
  nlp_select = [hdr.nlp,hdr.refnlp] & feedback_text = ['Main','Reference']
  io_failsafe_error = 0
  ; Check whether conflicting with SPECTFILE
  IF ((spectfile_set AND (ndims GE 1)) OR (refspectfile_set AND (ndims EQ 2))) THEN BEGIN
    idx = (refspectfile_set AND (ndims EQ 2))
    CRISPEX_UPDATE_STARTUP_SETUP_FEEDBACK, 'Detailed '+STRLOWCASE(feedback_text[idx])+$
      ' information may not be specified in both SPECTFILE and LINE_CENTER! Settings from '+$
      'LINE_CENTER will be ignored.',/WARNING,/NO_ROUTINE
    io_failsafe_error = 2
		RETURN
  ENDIF
  ; Check proper setting of LINE_CENTER
  IF (((lcase EQ 1) OR (lcase EQ 3)) AND (ndims LE nfiles)) THEN BEGIN
  ; lcase of 1: LINE_CENTER = lc or [[lc],[lc]]
  ; lcase of 3: LINE_CENTER = [lc,cwav,dwav] or [[lc,cwav,dwav],[lc,cwav,dwav]]
    FOR d=0,ndims-1 DO BEGIN
      IF ((line_center[0,d] GE nlp_select[d]) OR (line_center[0,d] LT 0)) THEN BEGIN
        CRISPEX_UPDATE_STARTUP_SETUP_FEEDBACK, feedback_text[d]+' linecentre index value '+$
          STRTRIM(line_center[0,d],2)+' falls outside of allowed range [0,'+$
          STRTRIM(nlp_select[d]-1,2)+']!',/ERROR,/NO_ROUTINE,NEWLINE=(io_failsafe_error EQ 2)
        IF (N_ELEMENTS(STARTUPTLB) EQ 1) THEN WIDGET_CONTROL, startuptlb, /DESTROY
        io_failsafe_error = 1
        RETURN
      ENDIF
    ENDFOR
  ENDIF ELSE IF (lcase NE 2) THEN BEGIN
  ; lcase of 2: LINE_CENTER = [cwav,dwav] or [[cwav,dwav],[cwav,dwav]]
    CRISPEX_UPDATE_STARTUP_SETUP_FEEDBACK, 'LINE_CENTER keyword contains too many elements for '+$
      'the number of cubes provided!', /ERROR, /NO_ROUTINE, NEWLINE=(io_failsafe_error EQ 2)
    IF (N_ELEMENTS(STARTUPTLB) EQ 1) THEN WIDGET_CONTROL, startuptlb, /DESTROY
    io_failsafe_error = 1
    RETURN
  ENDIF
END

PRO CRISPEX_IO_MULTICHANNEL, CUBE_COMPATIBILITY=cube_compatibility, CHANNELS_LABELS=channels_labels
; Handles setting of parameters in case of multichannel input
  IF KEYWORD_SET(CUBE_COMPATIBILITY) THEN BEGIN
  ENDIF
END

PRO CRISPEX_IO_FEEDBACK, verbosity, hdr, IMCUBE=imcube, SPCUBE=spcube, REFIMCUBE=refimcube, $
                         REFSPCUBE=refspcube, MASKCUBE=maskcube, SJICUBE=sjicube
	multichannel = (hdr.ns GE 2)
	IF (TOTAL(verbosity[0:1]) GE 1) THEN BEGIN
    IF (N_ELEMENTS(IMCUBE) EQ 1) THEN BEGIN
      IF ((SIZE(IMCUBE,/TYPE) NE 0) AND (STRCOMPRESS(IMCUBE) NE '')) THEN BEGIN
		    IF multichannel THEN $
          CRISPEX_UPDATE_STARTUP_SETUP_FEEDBACK, 'Read Stokes image cube: '+imcube+$
            '. Dimensions: (nx,ny,nt*nlp*ns) = ('+STRTRIM(hdr.nx,2)+','+STRTRIM(hdr.ny,2)+','+$
            STRTRIM(hdr.imnt,2)+').' $
        ELSE $
          CRISPEX_UPDATE_STARTUP_SETUP_FEEDBACK, 'Read image cube: '+imcube+$
            '. Dimensions: (nx,ny,nt*nlp*ns) = ('+STRTRIM(hdr.nx,2)+','+STRTRIM(hdr.ny,2)+','+$
            STRTRIM(hdr.imnt,2)+').'
		    IF (verbosity[1] EQ 1) THEN $
          CRISPEX_UPDATE_STARTUP_SETUP_FEEDBACK, 'Main cube(s) dimensions: (nx,ny,nt,nlp,ns) = ('+$
            STRTRIM(hdr.nx,2)+','+STRTRIM(hdr.ny,2)+','+STRTRIM(hdr.mainnt,2)+','+STRTRIM(hdr.nlp,2)+$
            ','+STRTRIM(hdr.ns,2)+')'
	    ENDIF ELSE CRISPEX_UPDATE_STARTUP_SETUP_FEEDBACK, 'No main image cube supplied.'
    ENDIF ELSE IF (N_ELEMENTS(SPCUBE) EQ 1) THEN BEGIN
      IF ((SIZE(SPCUBE,/TYPE) NE 0) AND (STRCOMPRESS(SPCUBE) NE '')) THEN $
        CRISPEX_UPDATE_STARTUP_SETUP_FEEDBACK, 'Read main spectral cube: '+spcube+$
              '. Dimensions: (nlp,nt,nx*ny*ns) = ('+STRTRIM(hdr.nlp,2)+','+STRTRIM(hdr.mainnt,2)+$
              ','+STRTRIM(hdr.spnt,2)+').' $
      ELSE CRISPEX_UPDATE_STARTUP_SETUP_FEEDBACK, 'No main spectral cube supplied.'
    ENDIF ELSE IF (N_ELEMENTS(REFIMCUBE) EQ 1) THEN BEGIN
      IF ((SIZE(REFIMCUBE,/TYPE) NE 0) AND (STRCOMPRESS(REFIMCUBE) NE '')) THEN BEGIN
        CRISPEX_UPDATE_STARTUP_SETUP_FEEDBACK, 'Read reference image cube: '+refimcube+$
              '. Dimensions: (nx,ny,nt*nlp*ns) = ('+STRTRIM(hdr.refnx,2)+','+STRTRIM(hdr.refny,2)+$
              ','+STRTRIM(hdr.refnt*hdr.refnlp*hdr.refns,2)+').'  
			  IF (verbosity[1] EQ 1) THEN $
          CRISPEX_UPDATE_STARTUP_SETUP_FEEDBACK, 'Reference cubes dimensions: (nx,ny,nt,nlp,ns) = ('+$
                STRTRIM(hdr.refnx,2)+','+STRTRIM(hdr.refny,2)+','+STRTRIM(hdr.refnt,2)+','+$
                STRTRIM(hdr.refnlp,2)+','+STRTRIM(hdr.refns,2)+')'
      ENDIF ELSE CRISPEX_UPDATE_STARTUP_SETUP_FEEDBACK, 'No reference image cube supplied.'
    ENDIF ELSE IF (N_ELEMENTS(REFSPCUBE) EQ 1) THEN BEGIN
      IF ((SIZE(REFSPCUBE,/TYPE) NE 0) AND (STRCOMPRESS(REFSPCUBE) NE '')) THEN $
        CRISPEX_UPDATE_STARTUP_SETUP_FEEDBACK, 'Read reference spectral cube: '+refspcube+$
              '. Dimensions: (nlp,nt,nx*ny) = ('+STRTRIM(hdr.refnlp,2)+','+STRTRIM(hdr.refnt,2)+$
              ','+STRTRIM(hdr.refspnt,2)+').' $
      ELSE CRISPEX_UPDATE_STARTUP_SETUP_FEEDBACK, 'No reference spectral cube supplied.'
    ENDIF ELSE IF (N_ELEMENTS(MASKCUBE) EQ 1) THEN BEGIN
      IF ((SIZE(MASKCUBE,/TYPE) NE 0) AND (STRCOMPRESS(MASKCUBE) NE '')) THEN $
        CRISPEX_UPDATE_STARTUP_SETUP_FEEDBACK, 'Read mask cube: '+maskcube+$
          '. Dimensions: (nx,ny,nt) = ('+STRTRIM(hdr.masknx,2)+','+STRTRIM(hdr.maskny,2)+','+$
          STRTRIM(hdr.masknt,2)+').' $
      ELSE CRISPEX_UPDATE_STARTUP_SETUP_FEEDBACK, 'No mask cube supplied.'
    ENDIF ELSE IF (N_ELEMENTS(SJICUBE) EQ 1) THEN BEGIN
      IF ((SIZE(SJICUBE,/TYPE) NE 0) AND (STRCOMPRESS(SJICUBE) NE '')) THEN $
        CRISPEX_UPDATE_STARTUP_SETUP_FEEDBACK, 'Read slit-jaw image cube: '+sjicube+$
          '. Dimensions: (nx,ny,nt) = ('+STRTRIM(hdr.sjinx,2)+','+STRTRIM(hdr.sjiny,2)+','+$
          STRTRIM(hdr.sjint,2)+').' $
      ELSE CRISPEX_UPDATE_STARTUP_SETUP_FEEDBACK, 'No slit-jaw image cube supplied.'
    ENDIF
  ENDIF
END

PRO CRISPEX_IO_OPEN_MAINCUBE, IMCUBE=imcube, SPCUBE=spcube, $
                              SINGLE_CUBE=single_cube, HDR_IN=hdr_in, $
                              HDR_OUT=hdr_out, STARTUPTLB=startuptlb, $
                              IO_FAILSAFE_MAIN_ERROR=io_failsafe_main_error, $
                              RESTORE_FROM_SESSION=restore_from_session
  io_failsafe_main_error = 0
  hdr_out = hdr_in
  ipath = hdr_out.ipath
  instance_label = hdr_out.instance_label
  hdr_out.imfilename = FILE_EXPAND_PATH(imcube)
  ; Check existence of file, else throw error message
  IF (FILE_TEST(hdr_out.imfilename) EQ 0) THEN BEGIN
    CRISPEX_UPDATE_STARTUP_SETUP_FEEDBACK, 'The main image file "'+$
      hdr_out.imfilename+'" does not exist. Please check your input.', $
      /ERROR,/NO_ROUTINE
    io_failsafe_main_error = 1
    RETURN
  ENDIF
  ; Determine cube compatibility mode for inputfiles (0: running FITS cubes, 1: running old cubes)
  imext = STRMID(hdr_out.imfilename,STRPOS(hdr_out.imfilename,'.',$
    /REVERSE_SEARCH)+1,STRLEN(hdr_out.imfilename))  ; Process extension
  hdr_out.imcube_compatibility = ABS(STRMATCH(imext,'fits',/FOLD_CASE)-1)             ; Determine comp mode
  IF (N_ELEMENTS(SPCUBE) EQ 1) THEN BEGIN
    hdr_out.spfilename = FILE_EXPAND_PATH(spcube)
    ; Check existence of file, else throw error message
    IF (FILE_TEST(hdr_out.spfilename) EQ 0) THEN BEGIN
      CRISPEX_UPDATE_STARTUP_SETUP_FEEDBACK, 'The main spectral file "'+$
        hdr_out.spfilename+'" does not exist. Please check your input.', $
        /ERROR,/NO_ROUTINE
      io_failsafe_main_error = 1
      RETURN
    ENDIF
    spext = STRMID(hdr_out.spfilename,STRPOS(hdr_out.spfilename,'.',$
      /REVERSE_SEARCH)+1,STRLEN(hdr_out.spfilename))
    hdr_out.spcube_compatibility = ABS(STRMATCH(spext,'fits',/FOLD_CASE)-1)
    hdr_out.spfile = 1
    IF ~KEYWORD_SET(RESTORE_FROM_SESSION) THEN $
      CRISPEX_IO_PARSE_HEADER, hdr_out.spfilename, HDR_IN=hdr_out, HDR_OUT=hdr_out, $
                              CUBE_COMPATIBILITY=hdr_out.spcube_compatibility, $
                              EXTEN_NO=0, /SPCUBE
  ENDIF ELSE hdr_out.onecube = 1                       ; onecube switch if no SPCUBE has been provided
  IF ~KEYWORD_SET(RESTORE_FROM_SESSION) THEN BEGIN
    ; If single_cube value has been set from single FITS cube, use that
    IF ((hdr_out.imcube_compatibility EQ 0) AND (N_ELEMENTS(SPCUBE) NE 1)) THEN $
      main_single_cube = hdr_out.single_cube[0] $
    ELSE IF (N_ELEMENTS(SINGLE_CUBE) GE 1) THEN $
      main_single_cube = single_cube[0]
    CRISPEX_IO_PARSE_HEADER, hdr_out.imfilename, HDR_IN=hdr_out, HDR_OUT=hdr_out, $
                              CUBE_COMPATIBILITY=hdr_out.imcube_compatibility, $
                              EXTEN_NO=0, /IMCUBE, $
                              SINGLE_CUBE=main_single_cube
    hdr_out.multichannel = (hdr_out.ns GE 2)
    CRISPEX_IO_FAILSAFES_MAIN, hdr_out.imfilename, hdr_out.spfilename, $
                               main_single_cube, $
                               HDR_IN=hdr_out, HDR_OUT=hdr_out, $
                               STARTUPTLB=startuptlb, $
                               IO_FAILSAFE_ERROR=io_failsafe_main_error
    IF (io_failsafe_main_error EQ 1) THEN RETURN
    ; Define axes titles based on IMCUBE and SPCUBE headers
    IF (STRCOMPRESS(hdr_out.bunit,/REMOVE_ALL) NE '') THEN $
      ytitle_unit = ' ['+hdr_out.bunit+']' ELSE ytitle_unit = ''
    IF (STRCOMPRESS(hdr_out.lpunit,/REMOVE_ALL) NE '') THEN $
      xtitle_unit = ' ['+hdr_out.lpunit+']' ELSE xtitle_unit = ''
    IF (STRCOMPRESS(hdr_out.tunit,/REMOVE_ALL) NE '') THEN $
      spytitle_unit = ' ['+hdr_out.tunit+']' ELSE spytitle_unit = ''
    hdr_out.ytitle[0] = hdr_out.blabel+ytitle_unit
    hdr_out.xtitle[0] = hdr_out.lplabel+xtitle_unit
    hdr_out.spytitle = hdr_out.tlabel+spytitle_unit
    ; Handle Stokes 
    IF hdr_out.multichannel THEN BEGIN
      stokes_labels = STRSPLIT(STRMID(hdr_out.imstokes,1,$
        STRLEN(hdr_out.imstokes)-2),',',/EXTRACT)
    	IF (N_ELEMENTS(stokes_labels) NE hdr_out.imns) THEN BEGIN
    		PRINT,'ERROR: The number of Stokes components ('+$
          STRTRIM(hdr_out.imns,2)+') does not '+$
          'correspond to the number of Stokes labels ('+$
          STRTRIM(N_ELEMENTS(stokes_labels),2)+').'
    		PRINT,'       Please check whether the Stokes cube production has proceded correctly.'
    		WIDGET_CONTROL, startuptlb, /DESTROY
        io_failsafe_main_error = 1
    		RETURN
    	ENDIF ELSE BEGIN
    		stokes_select_sp = INTARR(hdr_out.ns)
        wherestokesi = WHERE(stokes_labels EQ 'I', icount)
        wherestokesq = WHERE(stokes_labels EQ 'Q', qcount)
        wherestokesu = WHERE(stokes_labels EQ 'U', ucount)
        wherestokesv = WHERE(stokes_labels EQ 'V', vcount)
        IF (icount GT 0) THEN BEGIN
    			hdr_out.stokes_enabled[0] = 1 
    			stokes_select_sp[wherestokesi] = 1
    		ENDIF
        IF (qcount GT 0) THEN BEGIN
    			hdr_out.stokes_enabled[1] = 1 
    			stokes_select_sp[wherestokesq] = 1
    		ENDIF 
        IF (ucount GT 0) THEN BEGIN
    			hdr_out.stokes_enabled[2] = 1 
    			stokes_select_sp[wherestokesu] = 1
    		ENDIF 
        IF (vcount GT 0) THEN BEGIN
    			hdr_out.stokes_enabled[3] = 1 
    			stokes_select_sp[wherestokesv] = 1
    		ENDIF
    	ENDELSE
    ENDIF ELSE BEGIN
      stokes_labels = ['I']
      stokes_select_sp = 1
    ENDELSE
    hdr_out = CREATE_STRUCT(hdr_out, $
      'stokes_labels', stokes_labels, $
      'stokes_select_sp', stokes_select_sp)
    IF (hdr_out.verbosity[1] EQ 1) THEN $
      CRISPEX_UPDATE_STARTUP_SETUP_FEEDBACK, 'Stokes parameters: '+$
        STRJOIN(hdr_out.stokes_labels,' ')
    ; Handle diagnostics
    IF (WHERE(TAG_NAMES(hdr_out) EQ 'DIAG_START') EQ -1) THEN BEGIN
      wstart = 0
      wwidth = hdr_out.nlp
      hdr_out = CREATE_STRUCT(hdr_out, 'diag_start', wstart, 'diag_width', wwidth)
    ENDIF
    sel_diagnostics = INDGEN(1)
    sellines_diagnostics = INDGEN(1)
    selcol_diagnostics = INDGEN(1)
    sellp_diagnostics = LINDGEN(1)
    tsel_main = LINDGEN(hdr_out.mainnt)
    hdr_out = CREATE_STRUCT(hdr_out, $
      'sel_diagnostics', sel_diagnostics, $
      'sellines_diagnostics', sellines_diagnostics, $
      'selcol_diagnostics', selcol_diagnostics, $
      'sellp_diagnostics', sellp_diagnostics, $
      'tsel_main', tsel_main)
  ENDIF
  CRISPEX_IO_OPEN_MAINCUBE_READ, HDR_IN=hdr_out, HDR_OUT=hdr_out
END

PRO CRISPEX_IO_OPEN_MAINCUBE_READ, HDR_IN=hdr_in, HDR_OUT=hdr_out
  hdr_out = hdr_in
  ; Actual read-in of the data cubes  
  ; Read in main image cube 
	OPENR, lunim, hdr_out.imfilename, /get_lun, $
         SWAP_ENDIAN = ((hdr_out.imtype GT 1) AND (hdr_out.endian NE hdr_out.imendian))									
	imagefile = ASSOC(lunim,MAKE_ARRAY(hdr_out.nx,hdr_out.ny, $
                TYPE=hdr_out.imtype,/NOZERO),hdr_out.imoffset)
  ; Re-read in of the image cube for slices
	hdr_out.imdata	= PTR_NEW(imagefile, /NO_COPY)
  hdr_out.lunim = lunim
  hdr_out.dx_fixed = ABS(KEYWORD_SET(hdr_out.imcube_compatibility)-1)
  CRISPEX_IO_FEEDBACK, hdr_out.verbosity, hdr_out, IMCUBE=hdr_out.imfilename
  ; Read in main spectral cube 
  IF hdr_out.spfile THEN BEGIN
    OPENR, lunsp, hdr_out.spfilename, /get_lun, $
           SWAP_ENDIAN = ((hdr_out.sptype GT 1) AND (hdr_out.endian NE hdr_out.spendian))
    spectra = ASSOC(lunsp,MAKE_ARRAY(hdr_out.nlp,hdr_out.mainnt,$
                TYPE=hdr_out.sptype,/NOZERO),hdr_out.spoffset)
    hdr_out.lunsp = lunsp
    hdr_out.spdata = PTR_NEW(spectra, /NO_COPY) 
  ENDIF
  ; Define scan regardless of whether spfile is supplied; is needed for spectrum
  ; along a slit
  scanfile = ASSOC(lunim,MAKE_ARRAY(hdr_out.nx,hdr_out.ny,hdr_out.nlp*hdr_out.ns, $
                      TYPE=hdr_out.imtype,/NOZERO),hdr_out.imoffset)			
  hdr_out.scan = PTR_NEW(scanfile, /NO_COPY)
  CRISPEX_IO_FEEDBACK, hdr_out.verbosity, hdr_out, SPCUBE=hdr_out.spfilename
END

PRO CRISPEX_IO_OPEN_REFCUBE, event, REFCUBE=refcube, HDR_IN=hdr_in, $
      HDR_OUT=hdr_out, SINGLE_CUBE=single_cube, $
      IO_FAILSAFE_REF_ERROR=io_failsafe_ref_error, $
      IO_FAILSAFE_MAIN_REF_ERROR=io_failsafe_main_ref_error, $
      RESTORE_FROM_SESSION=restore_from_session
  io_failsafe_ref_error = 0
  io_failsafe_main_ref_error = 0
  IF ((N_ELEMENTS(event) EQ 1) AND (N_ELEMENTS(REFCUBE) LT 1)) THEN BEGIN
    ; If called from file menu, event is created and passed, load variables
    WIDGET_CONTROL, event.TOP, GET_UVALUE=info
    WIDGET_CONTROL, /HOURGLASS
    ; Use current reference file directory instead of input path
    IF ((*(*info).dataparams).refimfilename NE '') THEN $
      file_for_path = (*(*info).dataparams).refimfilename $
    ELSE $
      file_for_path = (*(*info).dataparams).imfilename
    ipath = FILE_DIRNAME(file_for_path)+PATH_SEP() 
    instance_label = (*(*info).sesparams).instance_label
    hdr_out = *(*(*info).ioparams).hdr
    filters = ['*fits','*cube']
  	refext = STRMID(file_for_path, STRPOS(file_for_path,'.',/REVERSE_SEARCH)+1,$
      STRLEN(file_for_path))
    title = 'Select reference image'
    IF (event.ID EQ (*(*info).ctrlscp).openrefimsp) THEN $
      title += ' and spectral files' $
    ELSE $
      title += ' file'
  	IF ABS(STRMATCH(refext,'fits',/FOLD_CASE)-1) THEN $
      filters = REVERSE(filters)
	  refcube = DIALOG_PICKFILE(/READ, /MUST_EXIST, PATH=ipath, $
      TITLE='CRISPEX'+instance_label+': '+title, FILTER=filters, $
      MULTIPLE_FILES=(event.ID EQ (*(*info).ctrlscp).openrefimsp))
    ; Failsafe against canceling
    IF (refcube[0] EQ '') THEN RETURN
    IF (N_ELEMENTS(refcube) EQ 1) THEN BEGIN
      ; Handle single file select and failsafe against selecting only 1 file
      ; when called from openrefimsp
      hdr_out.refspfilename = ''
      hdr_out.refspfile = 0
    ENDIF ELSE $
      ; Failsafe against selecting more than two files
      refcube = refcube[0:1]
  ENDIF ELSE $ 
    hdr_out = hdr_in
	IF ((N_ELEMENTS(REFCUBE) GE 1) AND (SIZE(REFCUBE,/TYPE) EQ 7)) THEN BEGIN					
    hdr_out.refimfilename = FILE_EXPAND_PATH(refcube[0])
    ; Check existence of file, else throw error message
    IF (FILE_TEST(hdr_out.refimfilename) EQ 0) THEN BEGIN
      IF (N_ELEMENTS(event) NE 1) THEN $
        CRISPEX_UPDATE_STARTUP_SETUP_FEEDBACK, 'The reference image file "'+$
          hdr_out.refimfilename+'" does not exist. Please check your input.', $
          /ERROR,/NO_ROUTINE 
      io_failsafe_ref_error = 1
      RETURN
    ENDIF
  	refimext = STRMID(hdr_out.refimfilename,STRPOS(hdr_out.refimfilename,'.',$
      /REVERSE_SEARCH)+1,STRLEN(hdr_out.refimfilename))
  	hdr_out.refimcube_compatibility = ABS(STRMATCH(refimext,'fits',/FOLD_CASE)-1)
    ; If single_cube value has been set from single FITS cube, use that
    IF ((hdr_out.refimcube_compatibility EQ 0) AND $
        (N_ELEMENTS(REFCUBE) NE 2)) THEN $
      ref_single_cube = hdr_out.single_cube[1] $
    ELSE IF (N_ELEMENTS(SINGLE_CUBE) EQ 2) THEN $
      ref_single_cube = single_cube[1]
  ; Handle reference image cube first, only after that check for reference
  ; spectral cube
    IF ~KEYWORD_SET(RESTORE_FROM_SESSION) THEN $
      CRISPEX_IO_PARSE_HEADER, hdr_out.refimfilename, HDR_IN=hdr_out, $
        HDR_OUT=hdr_out, CUBE_COMPATIBILITY=hdr_out.refimcube_compatibility, $
        EXTEN_NO=0, /REFIMCUBE
    IF (N_ELEMENTS(REFCUBE) EQ 2) THEN BEGIN
      hdr_out.refspfilename = FILE_EXPAND_PATH(refcube[1])
      ; Check existence of file, else throw error message
      IF (FILE_TEST(hdr_out.refspfilename) EQ 0) THEN BEGIN
        CRISPEX_UPDATE_STARTUP_SETUP_FEEDBACK, 'The reference spectral file "'+$
          hdr_out.refspfilename+'" does not exist. Please check your input.', $
          /ERROR,/NO_ROUTINE
        io_failsafe_ref_error = 1
        RETURN
      ENDIF
     	refspext = STRMID(hdr_out.refspfilename,STRPOS(hdr_out.refspfilename,'.',$
        /REVERSE_SEARCH)+1,STRLEN(hdr_out.refspfilename))
    	hdr_out.refspcube_compatibility = ABS(STRMATCH(refspext,'fits',/FOLD_CASE)-1)
      IF ~KEYWORD_SET(RESTORE_FROM_SESSION) THEN $
        CRISPEX_IO_PARSE_HEADER, hdr_out.refspfilename, HDR_IN=hdr_out, $
          HDR_OUT=hdr_out, CUBE_COMPATIBILITY=hdr_out.refspcube_compatibility, $
          EXTEN_NO=0, /REFSPCUBE
    ENDIF 
    IF ~KEYWORD_SET(RESTORE_FROM_SESSION) THEN BEGIN
      hdr_out.refmultichannel = (hdr_out.refns GE 2)
      CRISPEX_IO_FAILSAFES_REF, refcube, ref_single_cube, HDR_IN=hdr_out, $
        HDR_OUT=hdr_out, STARTUPTLB=startuptlb, $
        IO_FAILSAFE_ERROR=io_failsafe_ref_error
      IF (io_failsafe_ref_error EQ 1) THEN RETURN
      CRISPEX_IO_FAILSAFES_MAIN_REF, HDR_IN=hdr_out, HDR_OUT=hdr_out, $
                              STARTUPTLB=startuptlb, $
                              IO_FAILSAFE_ERROR=io_failsafe_main_ref_error
      IF (io_failsafe_main_ref_error EQ 1) THEN RETURN
      ; Add reference axes titles based on REFIMCUBE and REFSPCUBE headers
      IF (STRCOMPRESS(hdr_out.refbunit,/REMOVE_ALL) NE '') THEN $
        refytitle_unit = ' ['+hdr_out.refbunit+']' ELSE refytitle_unit = ''
      IF (STRCOMPRESS(hdr_out.reflpunit,/REMOVE_ALL) NE '') THEN $
        refxtitle_unit = ' ['+hdr_out.reflpunit+']' ELSE refxtitle_unit = ''
      hdr_out.ytitle[1] = hdr_out.refblabel+refytitle_unit
      hdr_out.xtitle[1] = hdr_out.reflplabel+refxtitle_unit
    ENDIF
  ENDIF
  IF ~KEYWORD_SET(RESTORE_FROM_SESSION) THEN BEGIN
    IF hdr_out.refmultichannel THEN BEGIN
      stokes_labels = STRSPLIT(STRMID(hdr_out.refimstokes,1,$
        STRLEN(hdr_out.refimstokes)-2),',',/EXTRACT)
    	IF (N_ELEMENTS(stokes_labels) NE hdr_out.refimns) THEN BEGIN
    		PRINT,'ERROR: The number of reference Stokes components ('+$
          STRTRIM(hdr_out.refimns,2)+') does not '+$
          'correspond to the number of Stokes labels ('+$
          STRTRIM(N_ELEMENTS(stokes_labels),2)+').'
    		PRINT,'       Please check whether the reference Stokes cube '+$
          'production has proceded correctly.'
    		WIDGET_CONTROL, startuptlb, /DESTROY
        io_failsafe_main_error = 1
    		RETURN
    	ENDIF ELSE BEGIN
    		stokes_select_sp = INTARR(hdr_out.refns)
        wherestokesi = WHERE(stokes_labels EQ 'I', icount)
        wherestokesq = WHERE(stokes_labels EQ 'Q', qcount)
        wherestokesu = WHERE(stokes_labels EQ 'U', ucount)
        wherestokesv = WHERE(stokes_labels EQ 'V', vcount)
        IF (icount GT 0) THEN BEGIN
    			hdr_out.refstokes_enabled[0] = 1 
    			stokes_select_sp[wherestokesi] = 1
    		ENDIF
        IF (qcount GT 0) THEN BEGIN
    			hdr_out.refstokes_enabled[1] = 1 
    			stokes_select_sp[wherestokesq] = 1
    		ENDIF 
        IF (ucount GT 0) THEN BEGIN
    			hdr_out.refstokes_enabled[2] = 1 
    			stokes_select_sp[wherestokesu] = 1
    		ENDIF 
        IF (vcount GT 0) THEN BEGIN
    			hdr_out.refstokes_enabled[3] = 1 
    			stokes_select_sp[wherestokesv] = 1
    		ENDIF
    	ENDELSE
    ENDIF ELSE BEGIN
      stokes_labels = ['I']
      stokes_select_sp = 1
    ENDELSE
    hdr_out = CREATE_STRUCT(hdr_out, $
      'stokes_labels_ref', stokes_labels, $
      'stokes_select_refsp', stokes_select_sp)
    IF (hdr_out.verbosity[1] EQ 1) THEN $
      CRISPEX_UPDATE_STARTUP_SETUP_FEEDBACK, 'Stokes parameters: '+$
        STRJOIN(hdr_out.stokes_labels_ref,' ')
    IF (hdr_out.refnt GT 1) THEN BEGIN
      tsel_ref = LONARR(hdr_out.mainnt)
      FOR tt=0,hdr_out.mainnt-1 DO BEGIN
        tdiff = ABS(hdr_out.tarr_ref - hdr_out.tarr_main[tt])
        tsel_ref[tt] = (WHERE(tdiff EQ MIN(tdiff, /NAN)))[0]
      ENDFOR
      hdr_out = CREATE_STRUCT(hdr_out, 'tsel_ref', tsel_ref)
    ENDIF ELSE $
      hdr_out = CREATE_STRUCT(hdr_out, 'tsel_ref', 0)
    IF (N_ELEMENTS(event) EQ 1) THEN BEGIN
      ; If called from file menu, parse header and parameters
      ; Read reference parameters
      text = 'Reading reference cube file'
      title = 'Loading reference cube'
      IF (N_ELEMENTS(REFCUBE) EQ 2) THEN BEGIN
        text += 's...' 
        title += 's'
      ENDIF ELSE text += '...'
      CRISPEX_WINDOW_USER_FEEDBACK, event, title, text
      no_prev_ref = ((*(*info).data).lunrefim EQ 0) 
      IF (no_prev_ref EQ 0) THEN FREE_LUN, (*(*info).data).lunrefim
      IF ((*(*info).data).lunrefsp NE 0) THEN FREE_LUN, (*(*info).data).lunrefsp
      *(*(*info).ioparams).hdr = hdr_out
      CRISPEX_IO_OPEN_REFCUBE_READ, event, REFCUBE=refcube, HDR_OUT=hdr_out
      *(*(*info).ioparams).hdr = hdr_out
      refwinx_old = (*(*info).winsizes).refwinx
      refwiny_old = (*(*info).winsizes).refwiny
      refmaster_t = ((*(*info).dispparams).master_time EQ 1) 
      IF refmaster_t THEN BEGIN
        t_old = (*(*(*info).dispparams).tarr_ref)[(*(*info).dispparams).t_sji]
        nt_old = (*(*info).dataparams).sjint
      ENDIF
      ; Handle the header
      WIDGET_CONTROL, (*(*info).ctrlsfeedb).feedback_text, $
        SET_VALUE='Parsing header information...'
      CRISPEX_IO_HANDLE_HDR, event, /REFERENCE
      ; Kill reference SP and LS windows
      WIDGET_CONTROL, (*(*info).ctrlsfeedb).feedback_text, $
        SET_VALUE='Resetting windows...'
      IF ((*(*info).winids).refsptlb NE 0) THEN $
        CRISPEX_DISPLAYS_REFSP_TOGGLE, event, /KILL, /NO_DRAW, /NO_FEEDBPARAMS
      IF ((*(*info).winids).reflstlb NE 0) THEN $
        CRISPEX_DISPLAYS_IMREF_LS_TOGGLE, event, /REFERENCE, /KILL, /NO_DRAW, $
          /NO_FEEDBPARAMS
     ; Only kill the reference window if the sizes have changed
      IF (((*(*info).winsizes).refwinx NE refwinx_old) OR $
          ((*(*info).winsizes).refwiny NE refwiny_old)) THEN BEGIN
        IF ((*(*info).winids).reftlb NE 0) THEN $
          CRISPEX_DISPLAYS_REF_TOGGLE, event, /KILL, /NO_DRAW, /NO_FEEDBPARAMS
        ; Re-draw the reference window
        CRISPEX_DISPLAYS_REF_TOGGLE, event, /DISP, /NO_DRAW, /NO_FEEDBPARAMS
      ENDIF
      ; Spawn reference SP and LS windows as required
      ; Draw LS if refnlp > 1
      IF ((*(*info).dataparams).refnlp GT 1) THEN BEGIN
        CRISPEX_DRAW_GET_SPECTRAL_AXES, event, /REFERENCE
        CRISPEX_DISPLAYS_IMREF_LS_TOGGLE, event, /REFERENCE, /DISP, /NO_DRAW, $
          /NO_FEEDBPARAMS
        IF ((*(*info).dispswitch).ref_detspect_scale EQ 0) THEN BEGIN
          CRISPEX_DISPRANGE_LS_SCALE_REF, event
          CRISPEX_DISPRANGE_LS_RANGE, event, /NO_DRAW
        ENDIF
        ; Draw SP if refnlp > 1 AND refnt > 1
        IF (((*(*info).dataparams).refnt GT 1) AND $
             (*(*info).dataswitch).refspfile) THEN $
          CRISPEX_DISPLAYS_REFSP_TOGGLE, event, /DISP, /NO_DRAW, $
            /NO_FEEDBPARAMS
      ENDIF
      main_is_raster = (*(*info).dataparams).tfull_dims_main[0] GE 1
      IF no_prev_ref THEN (*(*info).overlayswitch).refraster = $
         (main_is_raster OR ((*(*info).dataparams).nx EQ 1))
      ; Set zooming sliders correctly
    	WIDGET_CONTROL, (*(*info).ctrlsref).xrefpos_slider, $
        SENSITIVE=((*(*info).dataparams).d_refnx NE $
        (*(*info).dataparams).refnx-1), SET_VALUE=(*(*info).zooming).xrefpos
    	WIDGET_CONTROL, (*(*info).ctrlsref).yrefpos_slider, $
        SENSITIVE=((*(*info).dataparams).d_refny NE $
        (*(*info).dataparams).refny-1), SET_VALUE=(*(*info).zooming).yrefpos
      ; Reset timing
      IF refmaster_t THEN BEGIN
        CRISPEX_COORDS_TRANSFORM_T, event, T_OLD=t_old, NT_OLD=nt_old
        CRISPEX_UPDATE_T, event
      ENDIF ELSE $
        result = CRISPEX_BGROUP_MASTER_TIME(event, /NO_DRAW)
      CRISPEX_SCALING_APPLY_SELECTED, event
      ; Change color table if tables are available
      IF (hdr_out.refimcube_compatibility EQ 0) THEN $
        ref_instr = $
          (FITSHEAD2STRUCT(*(*(*(*info).dataparams).hdrs[1])[0])).instrume $
      ELSE $
        ref_instr = ''
      IF ((STRTRIM(ref_instr,2) EQ 'IRIS') AND $
          (*(*info).plotswitch).iris_lct_exist) THEN BEGIN
        (*(*info).plotparams).rgb_ref = CRISPEX_GET_RGB_TABLE(event, $
          TABLE_NAME='FUV', /IRIS, /SET_CT_CBOX, CT_SEL=1) 
      ENDIF
      CRISPEX_DRAW_CTBAR, event, /REFERENCE
      ; Only redraw the Reference windows
      CRISPEX_DRAW, event, NO_MAIN=(refmaster_t EQ 0), $
        NO_PHIS=(refmaster_t EQ 0), LS_NO_MAIN=(refmaster_t EQ 0), $
        NO_SJI=(refmaster_t EQ 0)
      ; Reset control panel elements where necessary
      WIDGET_CONTROL, (*(*info).ctrlsfeedb).feedback_text, $
        SET_VALUE='Resetting control panel...'
      ; Spectral tab
      WIDGET_CONTROL, (*(*info).ctrlscp).lp_restrict_button_ids[1], $
        SENSITIVE=(((*(*info).dataparams).refnlp GT 1) AND $
        ((*(*info).intparams).refsinglewav_windows EQ 0))
      lp_ref_but_condition = (((*(*info).dataparams).refnlp GT 1) AND $
        ((*(*info).dataparams).refnlp EQ (*(*info).dataparams).nlp))
      WIDGET_CONTROL, (*(*info).ctrlscp).lp_ref_but, $
        SET_BUTTON=lp_ref_but_condition, SENSITIVE=lp_ref_but_condition
      WIDGET_CONTROL, (*(*info).ctrlscp).lp_ref_slider, $
        SET_VALUE=(*(*info).dataparams).lp_ref, $
        SET_SLIDER_MAX=(*(*info).dataparams).refnlp-1, $
        SENSITIVE=(((*(*info).dataparams).refnlp GT 1) AND $
          ((*(*info).dataparams).refnlp NE (*(*info).dataparams).nlp))
      ; Spatial tab
      WIDGET_CONTROL, (*(*info).ctrlscp).xref_slider, $
        SET_VALUE=(*(*info).dataparams).xref, $
        SET_SLIDER_MAX=(*(*info).dataparams).refnx-1, /SENSITIVE
      WIDGET_CONTROL, (*(*info).ctrlscp).yref_slider, $
        SET_VALUE=(*(*info).dataparams).yref, $
        SET_SLIDER_MAX=(*(*info).dataparams).refny-1, /SENSITIVE
      ; Scaling tab
      ls_mult_list = [REPLICATE('Main ',(*(*info).intparams).ndiagnostics)+$
                      (*(*info).intparams).diagnostics, $
                      REPLICATE('Reference ',(*(*info).intparams).nrefdiagnostics)+$
                      (*(*info).intparams).refdiagnostics]
      WIDGET_CONTROL, (*(*info).ctrlscp).ls_mult_cbox, SET_VALUE=ls_mult_list
      ; Diagnostics tab
      IF ((*(*info).intparams).nrefdiagnostics GT 1) THEN $
        list_values = ['Display all', $
          REPLICATE('Hide ',(*(*info).intparams).nrefdiagnostics)+$
                (*(*info).intparams).refdiagnostics] $
      ELSE $
        list_values = 'N/A'
      WIDGET_CONTROL, (*(*info).ctrlscp).ref_specwin_label, $
        SET_VALUE='Reference: Displaying all'
      WIDGET_CONTROl, (*(*info).ctrlscp).ref_specwin_cbox, SET_VALUE=list_values,$
        SENSITIVE=((*(*info).intparams).nrefdiagnostics GT 1)
      ; Displays tab
      reset_detspect_imref = $
        CRISPEX_BGROUP_DETSPECT_IMREF(event, /SESSION_RESTORE)
	  	CRISPEX_DISPLAYS_DETSPECT_SET_BUTTONS, event
      reset_refdisplays_select = $
        CRISPEX_BGROUP_REFDISPLAYS_SELECT(event, /SESSION_RESTORE)
      ; Enable control panel buttons and sliders if no ref was previously loaded
      IF no_prev_ref THEN BEGIN
        ; Temporal tab
        WIDGET_CONTROL, (*(*info).ctrlscp).master_time_ids[0], /SENSITIVE
        WIDGET_CONTROL, (*(*info).ctrlscp).master_time_ids[1], /SENSITIVE
        ; Scaling tab
        CRISPEX_SCALING_SET_BOXBUTTONS, event
        CRISPEX_SCALING_SET_SLIDERS, event
        ; Overlays tab
        raster_sensitive = ((*(*info).dataswitch).reffile AND $
          (main_is_raster OR ((*(*info).dataparams).nx EQ 1)))
        WIDGET_CONTROL, (*(*info).ctrlscp).raster_label, $
          SENSITIVE=raster_sensitive
        WIDGET_CONTROL, (*(*info).ctrlscp).raster_button_ids[0], $
          SENSITIVE=raster_sensitive, $
          SET_BUTTON=((*(*info).overlayswitch).refraster AND $
          (main_is_raster OR ((*(*info).dataparams).nx EQ 1)))
        WIDGET_CONTROL, (*(*info).ctrlscp).raster_timing_label, $
          SENSITIVE=main_is_raster
        WIDGET_CONTROL, (*(*info).ctrlscp).raster_timing_button_ids[2], $
          SENSITIVE=main_is_raster, SET_BUTTON=main_is_raster
      ENDIF
      CRISPEX_DRAW_FEEDBPARAMS, event, /UPDATE_REFDATAVALS
      CRISPEX_WINDOW_USER_FEEDBACK_CLOSE, event
    ENDIF ELSE $
      CRISPEX_IO_OPEN_REFCUBE_READ, REFCUBE=refcube, HDR_IN=hdr_out, HDR_OUT=hdr_out
  ENDIF ELSE $
    CRISPEX_IO_OPEN_REFCUBE_READ, REFCUBE=refcube, HDR_IN=hdr_out, HDR_OUT=hdr_out
END

PRO CRISPEX_IO_OPEN_REFCUBE_READ, event, REFCUBE=refcube, HDR_IN=hdr_in, $
  HDR_OUT=hdr_out
  IF (N_ELEMENTS(event) EQ 1) THEN BEGIN
    WIDGET_CONTROL, event.TOP, GET_UVALUE=info
    hdr_out = *(*(*info).ioparams).hdr
  ENDIF ELSE hdr_out = hdr_in
  ; Read in reference image cube
	IF ((N_ELEMENTS(REFCUBE) GE 1) AND (SIZE(REFCUBE,/TYPE) EQ 7)) THEN BEGIN	
    ; REFIMCUBE as filename
		OPENR, lunrefim, refcube[0], /get_lun, $
           SWAP_ENDIAN=((hdr_out.refimtype GT 1) AND $
                        (hdr_out.endian NE hdr_out.refimendian))
    referencefile = ASSOC(lunrefim,MAKE_ARRAY(hdr_out.refnx,hdr_out.refny,$
                      TYPE=hdr_out.refimtype,/NOZERO),hdr_out.refimoffset)
		hdr_out.showref = 1
    hdr_out.lunrefim = lunrefim
    CRISPEX_IO_FEEDBACK, hdr_out.verbosity, hdr_out, REFIMCUBE=hdr_out.refimfilename
    ; Read in reference spectral cube if so provided
    IF (N_ELEMENTS(REFCUBE) EQ 2) THEN BEGIN                                
      ; REFSPCUBE as filename
			OPENR, lunrefsp, refcube[1], /get_lun, $
             SWAP_ENDIAN=((hdr_out.refsptype GT 1) AND $
                          (hdr_out.endian NE hdr_out.refspendian))						
      referencespectra = ASSOC(lunrefsp,MAKE_ARRAY(hdr_out.refnlp,hdr_out.refnt, $
                            TYPE=hdr_out.refsptype,/NOZERO),hdr_out.refspoffset)
			hdr_out.refspfile = 1	
      hdr_out.lunrefsp = lunrefsp
      CRISPEX_IO_FEEDBACK, hdr_out.verbosity, hdr_out, $
        REFSPCUBE=hdr_out.refspfilename
    ENDIF 
	ENDIF ELSE BEGIN
    IF (N_ELEMENTS(REFCUBE) GT 1) THEN BEGIN								                
      ; REFCUBE as image array
		  hdr_out.refnx = LONG((SIZE(refcube))[1])
		  hdr_out.refny = LONG((SIZE(refcube))[2])
		  IF (SIZE(REFCUBE,/N_DIMENSIONS) EQ 3) THEN $
        hdr_out.refnt = LONG((SIZE(refcube))[3]) $
      ELSE $
        hdr_out.refnt = 1L
		  IF (hdr_out.refnx EQ hdr_out.nx) AND (hdr_out.refny EQ hdr_out.ny) THEN BEGIN
			  referencefile = refcube
			  hdr_out.showref = 1
			  hdr_out.refnlp = 1
			  hdr_out.refns = 1
		  ENDIF ELSE BEGIN
        CRISPEX_UPDATE_STARTUP_SETUP_FEEDBACK, 'Dimensions of the reference cube (['+$
          STRTRIM(hdr_out.refnx,2)+','+STRTRIM(hdr_out.refny,2)+','+STRTRIM(hdr_out.refnt,2)+']) are not '+$
          'compatible with those of the main image cube (['+STRTRIM(hdr_out.nx,2)+','+$
          STRTRIM(hdr_out.ny,2)+','+STRTRIM(hdr_out.mainnt,2)+'])! Number of pixels in the x- and '+$
          'y-direction must be the same for both.', /ERROR, /NO_ROUTINE, /NEWLINE
			WIDGET_CONTROL, startuptlb, /DESTROY
			RETURN
		  ENDELSE
	  ENDIF 
	ENDELSE
  ; Create pointers to data
	IF (hdr_out.showref EQ 1) THEN BEGIN
		hdr_out.refdata	= PTR_NEW(referencefile, /NO_COPY)
		hdr_out.refslice= PTR_NEW(BYTARR(hdr_out.nx,hdr_out.ny))
		IF ((hdr_out.refnlp GT 1) AND (hdr_out.refspfile EQ 0)) THEN BEGIN
      refscanfile = ASSOC(lunrefim,MAKE_ARRAY(hdr_out.refnx,hdr_out.refny,$
                      hdr_out.refnlp*hdr_out.refns, TYPE=hdr_out.refimtype,$
                      /NOZERO),hdr_out.refimoffset)
			hdr_out.refscan = PTR_NEW(refscanfile, /NO_COPY)
      *hdr_out.refsspscan = (*hdr_out.refscan)[0]
		ENDIF 
	  IF (hdr_out.refspfile EQ 1) THEN $
      hdr_out.refspdata = PTR_NEW(referencespectra, /NO_COPY) 
	ENDIF 
END

PRO CRISPEX_IO_OPEN_SJICUBE, event, SJICUBE=sjicube, HDR_IN=hdr_in, $
      HDR_OUT=hdr_out, OFFSET_SJI=offset_sji, STARTUPTLB=startuptlb, $
      IO_FAILSAFE_SJI_ERROR=io_failsafe_sji_error, $
      RESTORE_FROM_SESSION=restore_from_session
  io_failsafe_sji_error = 0
  io_failsafe_main_ref_error = 0
  nsjicube = N_ELEMENTS(SJICUBE)
  IF ((N_ELEMENTS(event) EQ 1) AND (nsjicube LT 1)) THEN BEGIN
    ; If called from file menu, event is created and passed, load variables
    WIDGET_CONTROL, event.TOP, GET_UVALUE=info
    WIDGET_CONTROL, /HOURGLASS
    ; Use current SJI file directory instead of input path
    IF ((*(*info).dataparams).sjifilename[0] NE '') THEN $
      ipath = FILE_DIRNAME((*(*info).dataparams).sjifilename[0])+PATH_SEP() $
    ELSE $
      ipath = FILE_DIRNAME((*(*info).dataparams).imfilename)+PATH_SEP() 
    instance_label = (*(*info).sesparams).instance_label
    hdr_out = *(*(*info).ioparams).hdr
	  sjicube = DIALOG_PICKFILE(/READ, /MUST_EXIST, PATH=ipath, $
      TITLE='CRISPEX'+instance_label+': Select slit-jaw image file', $
      FILTER=['*SJI*fits','*fits'], /MULTIPLE_FILES)
    ; Failsafe against canceling
    IF (sjicube[0] EQ '') THEN RETURN
    ; Check whether any SJI previously loaded and if so, add filenames to
    ; SJICUBE
    no_prev_sji = (TOTAL((*(*info).data).lunsji) EQ 0) 
    IF (no_prev_sji EQ 0) THEN BEGIN
      whereempty = WHERE(hdr_out.sjifilename EQ '', count)
      IF (count NE 0) THEN BEGIN
        nsjicube = N_ELEMENTS(sjicube)
        max_overflow = (whereempty[0]+nsjicube GT hdr_out.nsjifiles_max)
        IF max_overflow THEN BEGIN
          CRISPEX_WINDOW_OK, event, 'ERROR!', $
            'CRISPEX can not '+$
            'load '+STRTRIM(nsjicube,2)+' extra SJICUBE file(s) as this '+$
            'would exceed the current maximum of 6 SJICUBE files. '+$
            'Please close one or more SJICUBE file(s) first.', $
            OK_EVENT='CRISPEX_CLOSE_EVENT_WINDOW', BASE=tlb, /BLOCK
          (*(*info).winids).errtlb = tlb
          io_failsafe_sji_error = 1
          RETURN
        ENDIF
      ENDIF ELSE BEGIN
        CRISPEX_WINDOW_OK, event, 'ERROR!', $
          'CRISPEX has currently '+$
          'already loaded the maximum number (6) of simultaneous SJICUBE '+$
          'files. Please close one or more SJICUBE file(s) first.', $
          OK_EVENT='CRISPEX_CLOSE_EVENT_WINDOW', BASE=tlb, /BLOCK
        (*(*info).winids).errtlb = tlb
        io_failsafe_sji_error = 1
        RETURN
      ENDELSE
    ENDIF
  ENDIF ELSE BEGIN
    hdr_out = hdr_in
  ENDELSE
  ; Handle xy-offsets in SJI coordinates
  IF (N_ELEMENTS(OFFSET_SJI) GT 0) THEN BEGIN
    IF (N_ELEMENTS(OFFSET_SJI) EQ 2) THEN $
      offset_sji = REBIN(offset_sji, 2, nsjicube)
    hdr_out.xyoffset_sji[*,0:nsjicube-1] = offset_sji
  ENDIF
  nsjicube = N_ELEMENTS(SJICUBE)
  whereempty = WHERE(hdr_out.sjifilename EQ '', count)
	IF ((nsjicube GE 1) AND (SIZE(SJICUBE,/TYPE) EQ 7)) THEN BEGIN					
    FOR i=0,nsjicube-1 DO BEGIN
      IF ~KEYWORD_SET(RESTORE_FROM_SESSION) THEN BEGIN
        hdr_out.nsjifiles += 1 
        idx_sji = whereempty[0]+i
        idx_sji_list = idx_sji-whereempty[0]
      ENDIF ELSE BEGIN
        idx_sji = i
        idx_sji_list = idx_sji
      ENDELSE
      hdr_out.sjifilename[idx_sji] = FILE_EXPAND_PATH(sjicube[idx_sji_list])
      ; Check existence of file, else throw error message
      IF (FILE_TEST(hdr_out.sjifilename[idx_sji]) EQ 0) THEN BEGIN
        CRISPEX_UPDATE_STARTUP_SETUP_FEEDBACK, 'The slit-jaw image file "'+$
          hdr_out.sjifilename[idx_sji]+'" does not exist. Please check your input.', $
          /ERROR,/NO_ROUTINE
        io_failsafe_sji_error = 1
        RETURN
      ENDIF
    	sjiext = STRMID(hdr_out.sjifilename[idx_sji],STRPOS(hdr_out.sjifilename[idx_sji],'.',$
        /REVERSE_SEARCH)+1,STRLEN(hdr_out.sjifilename[idx_sji]))
    	sjicube_compatibility = ABS(STRMATCH(sjiext,'fits',/FOLD_CASE)-1)
      IF ~KEYWORD_SET(RESTORE_FROM_SESSION) THEN BEGIN
        IF sjicube_compatibility THEN BEGIN
          CRISPEX_UPDATE_STARTUP_SETUP_FEEDBACK, $
            'The slit-jaw image cube must be in FITS format.', $
            /ERROR, /NO_ROUTINE, /NEWLINE
    	  	IF (N_ELEMENTS(STARTUPTLB) EQ 1) THEN WIDGET_CONTROL, startuptlb, /DESTROY
          io_failsafe_sji_error = 1
        ENDIF ELSE $
          ; Parse the SJICUBE header
          CRISPEX_IO_PARSE_HEADER, hdr_out.sjifilename[idx_sji], HDR_IN=hdr_out, $
            HDR_OUT=hdr_out, CUBE_COMPATIBILITY=sjicube_compatibility, $
            EXTEN_NO=0, /SJICUBE, IDX_SJI=idx_sji
        IF (hdr_out.sjint[idx_sji] GE 1) THEN BEGIN
          tsel_sji = LONARR(hdr_out.mainnt)
          FOR tt=0,hdr_out.mainnt-1 DO BEGIN
            tdiff = ABS(*hdr_out.tarr_sji[idx_sji] - hdr_out.tarr_main[tt])
            tsel_sji[tt] = (WHERE(tdiff EQ MIN(tdiff, /NAN)))[0]
          ENDFOR
          *hdr_out.tsel_sji[idx_sji] = tsel_sji
          ; Correct WCS information if necessary
          ; Check version of main FITS files
          ver_rf3 = SXPAR(*hdr_out.hdrs_main[0],'VER_RF3')
          IF (ver_rf3 NE 0) THEN BEGIN
            tai_ver_rf3 = ANYTIM2TAI(STRMID(ver_rf3,4,12))
            tai0_ver_rf3 = ANYTIM2TAI('2014-06-13')
            IF (tai_ver_rf3 LE tai0_ver_rf3) THEN BEGIN
              IF (tai_ver_rf3 EQ tai0_ver_rf3) THEN $
                ; Main FITS created with iris_make_fits_level3 r1.41
                main_tsel_idx = hdr_out.mainnt/2 $
              ELSE $
                ; Main FITS created with iris_make_fits_level3 < r1.41
                main_tsel_idx = 0 
              ; Get mid-point timing at which main CRVALs have been determined
              ; with failsafe against non-raster sit-and-stare
              t_sel_main = REFORM((*(*info).dataparams).tarr_full_main[$
                hdr_out.nx/2  < hdr_out.tfull_dims_main[0], 0, 0, $
                main_tsel_idx < hdr_out.tfull_dims_main[3]])
            ENDIF ELSE BEGIN
              ; Main FITS created with iris_make_fits_level3 > r1.41
              t_sel_main = (SXPAR(*hdr_out.hdrs_main[0],'CRVAL4'))
              IF (hdr_out.startobs_main NE '0') THEN $
                orig_str = STR2UTC(hdr_out.startobs_main) $
              ELSE $
                orig_str = STR2UTC(hdr_out.date_obs_main)
              t_sel_main += orig_str.time/1000.
            ENDELSE
            offsetarray = READFITS(hdr_out.sjifilename[idx_sji], sjihdr, EXTEN_NO=1, /SILENT)
            pc_ix_exist = (SXPAR(sjihdr,'PC1_1IX') NE 0)
            sjihdr = FITSHEAD2STRUCT(sjihdr)
            ; Get time-dependent slit XCEN,YCEN
            xcensjit = REFORM(offsetarray[sjihdr.xcenix,*])
            ycensjit = REFORM(offsetarray[sjihdr.ycenix,*])
            ; Populate time-dependent SJI PC-matrix variables
            IF (pc_ix_exist) THEN BEGIN
              sji_pc11 = REFORM(offsetarray[sjihdr.PC1_1IX,*])
              sji_pc12 = REFORM(offsetarray[sjihdr.PC1_2IX,*])
              sji_pc21 = REFORM(offsetarray[sjihdr.PC2_1IX,*])
              sji_pc22 = REFORM(offsetarray[sjihdr.PC2_2IX,*])
            ENDIF ELSE BEGIN
              nt_loc = N_ELEMENTS(xcensjit)
              sji_pc11 = REPLICATE((*hdr_out.wcs_sji[idx_sji]).pc[0,0],nt_loc)
              sji_pc12 = REPLICATE((*hdr_out.wcs_sji[idx_sji]).pc[0,1],nt_loc)
              sji_pc21 = REPLICATE((*hdr_out.wcs_sji[idx_sji]).pc[1,0],nt_loc)
              sji_pc22 = REPLICATE((*hdr_out.wcs_sji[idx_sji]).pc[1,1],nt_loc)
            ENDELSE
            ; Get time-dependent slit pixels
            sji_crpix1 = REFORM(offsetarray[sjihdr.SLTPX1IX,*])
            sji_crpix2 = REFORM(offsetarray[sjihdr.SLTPX2IX,*])
            ; Failsafe against zero values in variables
            wherenozero = WHERE(REFORM(offsetarray[sjihdr.dsrcsix,*]) GT 0., $
              nwherenozero)
            IF ((nwherenozero NE hdr_out.sjint[idx_sji]) AND $
                (nwherenozero GT 0)) THEN BEGIN
              it = INDGEN(hdr_out.sjint[idx_sji])
              xcensjit = INTERPOL(xcensjit[wherenozero],wherenozero,it)
              ycensjit = INTERPOL(ycensjit[wherenozero],wherenozero,it)
              sji_pc11 = INTERPOL(sji_pc11[wherenozero],wherenozero,it)
              sji_pc12 = INTERPOL(sji_pc12[wherenozero],wherenozero,it)
              sji_pc21 = INTERPOL(sji_pc21[wherenozero],wherenozero,it)
              sji_pc22 = INTERPOL(sji_pc22[wherenozero],wherenozero,it)
              sji_crpix1 = INTERPOL(sji_crpix1[wherenozero],wherenozero,it)
              sji_crpix2 = INTERPOL(sji_crpix2[wherenozero],wherenozero,it)
            ENDIF
            ; Compute time-dependent slit position (Solar X,Y)
            sji_crval1 = xcensjit + (*hdr_out.wcs_sji[idx_sji]).cdelt[0] * $
                        (sji_pc11*(sji_crpix1 - (*hdr_out.wcs_sji[idx_sji]).crpix[0]) + $
                         sji_pc12*(sji_crpix2 - (*hdr_out.wcs_sji[idx_sji]).crpix[1]))
            sji_crval2 = ycensjit + (*hdr_out.wcs_sji[idx_sji]).cdelt[1] * $
                        (sji_pc21*(sji_crpix1 - (*hdr_out.wcs_sji[idx_sji]).crpix[0]) + $
                         sji_pc22*(sji_crpix2 - (*hdr_out.wcs_sji[idx_sji]).crpix[1]))
            ; Get closest SJI timestep to t_sel_main
            diff_time = ABS(*hdr_out.tarr_sji[idx_sji] - t_sel_main)
            t_sel_sji = WHERE(diff_time EQ MIN(diff_time))
            ; Update WCS structure parameters
            (*hdr_out.wcs_sji[idx_sji]).crval = $
                [sji_crval1[t_sel_sji],sji_crval2[t_sel_sji]] $
              + hdr_out.xyoffset_sji[*,idx_sji]
            (*hdr_out.wcs_sji[idx_sji]).crpix = $
              [sji_crpix1[t_sel_sji],sji_crpix2[t_sel_sji]]
            (*hdr_out.wcs_sji[idx_sji]).pc = $
              [[sji_pc11[t_sel_sji],sji_pc21[t_sel_sji]],$
                [sji_pc12[t_sel_sji],sji_pc22[t_sel_sji]]]
          ENDIF
        ENDIF 
        IF (N_ELEMENTS(event) EQ 1) THEN BEGIN
          ; If called from file menu, parse header and parameters
          ; Read SJI parameters
          CRISPEX_IO_OPEN_SJICUBE_READ, HDR_IN=hdr_out, HDR_OUT=hdr_out, $
            IDX_SJI=idx_sji
          *(*(*info).ioparams).hdr = hdr_out
          sjiwinx_old = (*(*info).winsizes).sjiwinx[idx_sji]
          sjiwiny_old = (*(*info).winsizes).sjiwiny[idx_sji]
          sjimaster_t = ((*(*info).dispparams).master_time EQ 2) 
          IF sjimaster_t THEN BEGIN
            t_old = (*(*(*info).dispparams).tarr_sji[$
              (*(*info).dispswitch).sji_select])[$
              (*(*info).dispparams).t_sji[(*(*info).dispswitch).sji_select]]
            nt_old = (*(*info).dataparams).sjint[(*(*info).dispswitch).sji_select]
          ENDIF
          ; Handle the header
          CRISPEX_IO_HANDLE_HDR, event, /SJI, IDX_SJI=idx_sji
          ; Parse instrument and channel labels
          (*(*info).dataparams).sji_labels[0,idx_sji] = STRTRIM((FITSHEAD2STRUCT($
            *(*(*(*info).dataparams).hdrs[2+idx_sji])[0])).telescop,2)
          sji_channel = $
            (FITSHEAD2STRUCT(*(*(*(*info).dataparams).hdrs[2+idx_sji])[0])).tdesc1
          splitchannel = STRSPLIT(sji_channel,'_',/EXTRACT)
          is_iris_sji = (splitchannel[0] EQ 'SJI')
          IF is_iris_sji THEN $
            ; If IRIS SJI then TDESC1 is of type SJI_1400
            (*(*info).dataparams).sji_labels[1,idx_sji] = STRTRIM(splitchannel[1],2) $
          ELSE $
            ; If SDO SJI then TDESC1 is of type 131_THIN
            (*(*info).dataparams).sji_labels[1,idx_sji] = STRTRIM(splitchannel[0],2) 
          ; Change color table if tables are available
          *(*(*info).plotparams).rgb_sji[idx_sji] = $
              CRISPEX_GET_RGB_TABLE(event, TABLE_NAME=sji_channel, $
              IRIS=(is_iris_sji AND (*(*info).plotswitch).iris_lct_exist), $
              SDO=((is_iris_sji EQ 0) AND (*(*info).plotswitch).aia_lct_exist), $
              /SET_CT_CBOX, CT_SEL=3)
          ; Failsafe against duplicate sji_labels
          sji_comb_labels = $
            (*(*info).dataparams).sji_labels[0,*]+(*(*info).dataparams).sji_labels[1,*]
          uniq_labels = UNIQ(sji_comb_labels, SORT(sji_comb_labels))
          FOR idx=0,N_ELEMENTS(uniq_labels)-1 DO BEGIN
            ; Exclude N/A labels
            IF (sji_comb_labels[uniq_labels[idx]] NE 'N/A') THEN BEGIN
              where_label = WHERE(sji_comb_labels EQ sji_comb_labels[uniq_labels[idx]], $
                count)
              IF (count GT 1) THEN BEGIN
                FOR cc=0,count-1 DO BEGIN
                  (*(*info).dataparams).sji_labels[2,where_label[cc]] = '('+STRTRIM(cc+1,2)+')'
                  IF (N_ELEMENTS(mod_labelidx) GE 1) THEN $   ; Only way for pre-IDL8
                    mod_labelidx = [mod_labelidx, where_label[cc]] $
                  ELSE $
                    mod_labelidx = where_label[cc]
                ENDFOR
              ENDIF
            ENDIF
          ENDFOR
          IF (N_ELEMENTS(mod_labelidx) GT 0) THEN $
            mod_labelidx = mod_labelidx[WHERE(mod_labelidx NE idx_sji)]
          ; Open window to display new SJI file in
          CRISPEX_DISPLAYS_SJI_TOGGLE, event, /DISP, /NO_DRAW, IDX_SJI=idx_sji
          *(*(*info).winswitch).whereshowsji = $
            WHERE((*(*info).winswitch).showsji EQ 1, nwhereshowsji)
          (*(*info).winswitch).nwhereshowsji = nwhereshowsji
          IF no_prev_sji THEN (*(*info).overlayswitch).sjiraster = 1
          ; Set zooming sliders correctly
        	WIDGET_CONTROL, (*(*info).ctrlssji).xsjipos_slider[idx_sji], $
            SENSITIVE=((*(*info).dataparams).d_sjinx[idx_sji] NE $
            (*(*info).dataparams).sjinx[idx_sji]-1), $
            SET_VALUE=(*(*info).zooming).xsjipos[idx_sji]
        	WIDGET_CONTROL, (*(*info).ctrlssji).ysjipos_slider[idx_sji], $
            SENSITIVE=((*(*info).dataparams).d_sjiny[idx_sji] NE $
            (*(*info).dataparams).sjiny[idx_sji]-1), $
            SET_VALUE=(*(*info).zooming).ysjipos[idx_sji]
          ; Reset timing
          IF sjimaster_t THEN BEGIN
            CRISPEX_COORDS_TRANSFORM_T, event, T_OLD=t_old, NT_OLD=nt_old
            CRISPEX_UPDATE_T, event
          ENDIF ELSE $
            result = CRISPEX_BGROUP_MASTER_TIME(event, /NO_DRAW)
          CRISPEX_SCALING_APPLY_SELECTED, event, UPDATE_MAIN=0, UPDATE_REF=0, $
            UPDATE_DOP=0, /UPDATE_SJI
          CRISPEX_DRAW_CTBAR, event, /SJI
          ; Only redraw the SJI window
          CRISPEX_DRAW, event, NO_MAIN=(sjimaster_t EQ 0), $
            NO_REF=(sjimaster_t EQ 0), NO_PHIS=(sjimaster_t EQ 0), $
            LS_NO_MAIN=(sjimaster_t EQ 0), LS_NO_REF=(sjimaster_t EQ 0)
          new_sjilabel = STRJOIN((*(*info).dataparams).sji_labels[*,idx_sji],' ')
          ; Enable control panel buttons and sliders if no SJI was previously loaded
          IF no_prev_sji THEN BEGIN
            ; Temporal tab
            WIDGET_CONTROL, (*(*info).ctrlscp).master_time_ids[0], /SENSITIVE
            WIDGET_CONTROL, (*(*info).ctrlscp).master_time_ids[2], /SENSITIVE
            ; Scaling tab
            CRISPEX_SCALING_SET_BOXBUTTONS, event
            CRISPEX_SCALING_SET_SLIDERS, event
            ; Overlays tab
            main_is_raster = (*(*info).dataparams).tfull_dims_main[0] GE 1
            raster_sensitive = ((*(*info).dataswitch).sjifile AND $
              (main_is_raster OR ((*(*info).dataparams).nx EQ 1)))
            WIDGET_CONTROL, (*(*info).ctrlscp).raster_label, $
              SENSITIVE=raster_sensitive
            WIDGET_CONTROL, (*(*info).ctrlscp).raster_button_ids[1], $
              SENSITIVE=raster_sensitive, $
              SET_BUTTON=((*(*info).overlayswitch).sjiraster AND $
              (main_is_raster OR ((*(*info).dataparams).nx EQ 1)))
            WIDGET_CONTROL, (*(*info).ctrlscp).raster_timing_label, $
              SENSITIVE=main_is_raster
            WIDGET_CONTROL, (*(*info).ctrlscp).raster_timing_button_ids[2], $
              SENSITIVE=main_is_raster, SET_BUTTON=main_is_raster
            WIDGET_CONTROL, (*(*info).ctrlscp).master_time_sjicbox, $
              SET_VALUE=new_sjilabel, COMBOBOX_INDEX=idx_sji
            ; Delete placeholders before replacing by correct values
            WIDGET_CONTROL, (*(*info).ctrlscp).scaling_cbox, $
              COMBOBOX_DELETEITEM=idx_sji+3   ; offset due to previous elements
            WIDGET_CONTROL, (*(*info).ctrlscp).displays_ct_disp, $
              COMBOBOX_DELETEITEM=idx_sji+4
            ; Displays tab
            WIDGET_CONTROL, (*(*info).ctrlscp).sjidisplays_button_ids[idx_sji], $
              SET_BUTTON=(*(*info).winswitch).showsji[idx_sji], $
              SENSITIVE=(*(*info).dataswitch).sjifile
          ENDIF ELSE $
          ; Update drop down boxes where need be
            ; Temporal tab
            WIDGET_CONTROL, (*(*info).ctrlscp).master_time_sjicbox, $
              COMBOBOX_ADDITEM=new_sjilabel
          ; Scaling tab
          WIDGET_CONTROL, (*(*info).ctrlscp).scaling_cbox, COMBOBOX_ADDITEM=$
            'Slit-jaw image: '+new_sjilabel
          WIDGET_CONTROL, (*(*info).ctrlscp).displays_ct_disp, $
            COMBOBOX_ADDITEM='Slit-jaw image: '+new_sjilabel
          ; Displays tab
          sjidisp_geometry = $
            WIDGET_INFO((*(*info).ctrlscp).sjidisplays_button_ids[0],$
              /GEOMETRY)
          ; Need to call twice to get correct label display. I don't know why...
          FOR dummy=0,1 DO $
            WIDGET_CONTROL, (*(*info).ctrlscp).sjidisplays_button_ids[idx_sji],$
              SET_VALUE=new_sjilabel, XSIZE=sjidisp_geometry.xsize, /SENSITIVE, $
              /SET_BUTTON
          ; Update modified SJI labels where necessary
          IF (N_ELEMENTS(mod_labelidx) GT 0) THEN BEGIN
            FOR idx=0,N_ELEMENTS(mod_labelidx)-1 DO BEGIN
              mod_idx = mod_labelidx[idx]
              mod_label = STRJOIN((*(*info).dataparams).sji_labels[*,mod_idx],$
                ' ') 
              WIDGET_CONTROL, (*(*info).ctrlscp).master_time_sjicbox, $
                COMBOBOX_DELETEITEM=mod_idx
              WIDGET_CONTROL, (*(*info).ctrlscp).master_time_sjicbox, $
                COMBOBOX_ADDITEM=mod_label, COMBOBOX_INDEX=mod_idx
              WIDGET_CONTROL, (*(*info).ctrlscp).scaling_cbox, $
                COMBOBOX_DELETEITEM=mod_idx+3
              WIDGET_CONTROL, (*(*info).ctrlscp).scaling_cbox, $
                COMBOBOX_ADDITEM='Slit-jaw image: '+mod_label, $
                COMBOBOX_INDEX=mod_idx+3
              WIDGET_CONTROL, (*(*info).ctrlscp).displays_ct_disp, $
                COMBOBOX_DELETEITEM=mod_idx+4
              WIDGET_CONTROL, (*(*info).ctrlscp).displays_ct_disp, $
                COMBOBOX_ADDITEM='Slit-jaw image: '+mod_label, $
                COMBOBOX_INDEX=mod_idx+4
              ; Need to call twice to get correct label display. Still don't know why...
              FOR dummy=0,1 DO WIDGET_CONTROL, $
                (*(*info).ctrlscp).sjidisplays_button_ids[mod_idx],$
                SET_VALUE=mod_label, XSIZE=sjidisp_geometry.xsize, /SENSITIVE
              WIDGET_CONTROL, (*(*info).winids).sjitlb[mod_idx], $
                BASE_SET_TITLE='CRISPEX'+(*(*info).sesparams).instance_label+$
                ': Slit-jaw image '+mod_label
            ENDFOR
          ENDIF
        ENDIF ELSE $
          CRISPEX_IO_OPEN_SJICUBE_READ, HDR_IN=hdr_out, HDR_OUT=hdr_out, $
            IDX_SJI=idx_sji
      ENDIF ELSE $
        CRISPEX_IO_OPEN_SJICUBE_READ, HDR_IN=hdr_out, HDR_OUT=hdr_out, $
          IDX_SJI=idx_sji
    ENDFOR
  ENDIF
END

PRO CRISPEX_IO_OPEN_SJICUBE_READ, event, HDR_IN=hdr_in, HDR_OUT=hdr_out, $
  IDX_SJI=idx_sji
  IF (N_ELEMENTS(event) EQ 1) THEN BEGIN
    WIDGET_CONTROL, event.TOP, GET_UVALUE=info 
    hdr_out = *(*(*info).ioparams).hdr 
  ENDIF ELSE $
    hdr_out = hdr_in
	OPENR, lunsji, hdr_out.sjifilename[idx_sji], /get_lun, $
         SWAP_ENDIAN = ((hdr_out.sjitype[idx_sji] GT 1) AND $
         (hdr_out.endian NE hdr_out.sjiendian[idx_sji]))
  sji = ASSOC(lunsji,MAKE_ARRAY(hdr_out.sjinx[idx_sji],hdr_out.sjiny[idx_sji], $
          TYPE=hdr_out.sjitype[idx_sji],/NOZERO),hdr_out.sjioffset[idx_sji])
	hdr_out.sjifile = 1	
  hdr_out.lunsji[idx_sji] = lunsji
  *hdr_out.sjidata[idx_sji] = sji
  *hdr_out.sjislice[idx_sji]	= BYTARR(hdr_out.sjinx[idx_sji],hdr_out.sjiny[idx_sji])
  IF (N_ELEMENTS(event) EQ 1) THEN $
    *(*(*info).ioparams).hdr = hdr_out $
  ELSE $
    CRISPEX_IO_FEEDBACK, hdr_out.verbosity, hdr_out, $
      SJICUBE=hdr_out.sjifilename[idx_sji]
END

PRO CRISPEX_IO_OPEN_MASKCUBE, MASKCUBE=maskcube, HDR_IN=hdr_in, HDR_OUT=hdr_out, $
                              STARTUPTLB=startuptlb, $
                              IO_FAILSAFE_MASK_ERROR=io_failsafe_mask_error, $
                              RESTORE_FROM_SESSION=restore_from_session
  io_failsafe_mask_error = 0
  hdr_out = hdr_in
  IF (N_ELEMENTS(MASKCUBE) GE 1) THEN BEGIN
    hdr_out.maskfilename = FILE_EXPAND_PATH(maskcube[0])
    ; Check existence of file, else throw error message
    IF (FILE_TEST(hdr_out.maskfilename) EQ 0) THEN BEGIN
      CRISPEX_UPDATE_STARTUP_SETUP_FEEDBACK, 'The mask file "'+hdr_out.maskfilename+$
        '" does not exist. Please check your input.', /ERROR,/NO_ROUTINE
      io_failsafe_mask_error = 1
      RETURN
    ENDIF
    IF ~KEYWORD_SET(RESTORE_FROM_SESSION) THEN BEGIN
  	  maskext = STRMID(hdr_out.maskfilename,STRPOS(hdr_out.maskfilename,'.',/REVERSE_SEARCH)+1,$
                        STRLEN(hdr_out.maskfilename))
  	  hdr_out.maskcube_compatibility = ABS(STRMATCH(maskext,'fits',/FOLD_CASE)-1)
      CRISPEX_IO_PARSE_HEADER, hdr_out.maskfilename, HDR_IN=hdr_out, HDR_OUT=hdr_out, $
                              CUBE_COMPATIBILITY=hdr_out.maskcube_compatibility, EXTEN_NO=0, /MASKCUBE
      CRISPEX_IO_FAILSAFES_MASK, HDR=hdr_out, STARTUPTLB=startuptlb, $
                                  IO_FAILSAFE_ERROR=io_failsafe_mask_error
      IF (io_failsafe_mask_error EQ 1) THEN RETURN
    ENDIF
    CRISPEX_IO_OPEN_MASKCUBE_READ, HDR_IN=hdr_out, HDR_OUT=hdr_out
  ENDIF 
END

PRO CRISPEX_IO_OPEN_MASKCUBE_READ, HDR_IN=hdr_in, HDR_OUT=hdr_out
  hdr_out = hdr_in
		OPENR, lunmask, hdr_out.maskfilename, /get_lun, $
           SWAP_ENDIAN = ((hdr_out.masktype GT 1) AND (hdr_out.endian NE hdr_out.maskendian))
    mask = ASSOC(lunmask,MAKE_ARRAY(hdr_out.masknx,hdr_out.maskny, $
              TYPE=hdr_out.masktype,/NOZERO),hdr_out.maskoffset)
		hdr_out.maskfile = 1	
	  hdr_out.maskdata = PTR_NEW(mask, /NO_COPY)
    hdr_out.lunmask = lunmask
    CRISPEX_IO_FEEDBACK, hdr_out.verbosity, hdr_out, MASKCUBE=hdr_out.maskfilename
END

PRO CRISPEX_IO_HANDLE_HDR, event, REFERENCE=reference, SJI=sji, IDX_SJI=idx_sji
  WIDGET_CONTROL, event.TOP, GET_UVALUE = info
  hdr = *(*(*info).ioparams).hdr
  IF (N_ELEMENTS(IDX_SJI) NE 1) THEN idx_sji = 0
  IF KEYWORD_SET(REFERENCE) THEN BEGIN
    ; ctrlsswitch pointer
    (*(*info).ctrlsswitch).lp_ref_lock = (hdr.refnlp EQ hdr.nlp)
    ; data pointer
    *(*info).data = CRISPEX_TAG_DELETE(*(*info).data, 'REFSSP_CUR')
    *(*info).data = CREATE_STRUCT(*(*info).data, 'refssp_cur', PTRARR(hdr.refns))
    (*(*info).data).refdata = hdr.refdata
    (*(*info).data).refspdata = hdr.refspdata
    IF ((hdr.refnlp GT 1) AND (hdr.refspfile EQ 0)) THEN BEGIN
      (*(*info).data).refscan = hdr.refscan
      (*(*info).data).refsspscan = hdr.refsspscan
    ENDIF
    (*(*info).data).refslice = hdr.refslice
    (*(*info).data).lunrefim = hdr.lunrefim
    (*(*info).data).lunrefsp = hdr.lunrefsp
    ; dataparams pointer
    (*(*info).dataparams).refimfilename = hdr.refimfilename
    (*(*info).dataparams).refspfilename = hdr.refspfilename
    (*(*info).dataparams).hdrs[1] = PTR_NEW(hdr.hdrs_ref)
    (*(*info).dataparams).next[1] = N_ELEMENTS(hdr.hdrs_ref)
    (*(*info).dataparams).date_obs_ref = hdr.date_obs_ref
    (*(*info).dataparams).refnx = hdr.refnx
    (*(*info).dataparams).refny = hdr.refny
    (*(*info).dataparams).refdx = hdr.refdx
    (*(*info).dataparams).refdy = hdr.refdy
    (*(*info).dataparams).xval_ref = hdr.xval_ref
    (*(*info).dataparams).yval_ref = hdr.yval_ref
    (*(*info).dataparams).xpix_ref = hdr.xpix_ref
    (*(*info).dataparams).ypix_ref = hdr.ypix_ref
    IF (hdr.wcs_set AND hdr.ref_wcs_set) THEN BEGIN
      pix_main2ref = ROUND(WCS_GET_PIXEL(hdr.wcs_ref, WCS_GET_COORD(hdr.wcs_main)))
      pix_ref2main = ROUND(WCS_GET_PIXEL(hdr.wcs_main, WCS_GET_COORD(hdr.wcs_ref)))
    ENDIF ELSE BEGIN
      result = CRISPEX_TRANSFORM_GET_COORDMAPS(hdr, /MAINREF)
      pix_main2ref = ROUND(result.pix_a2b)
      pix_ref2main = ROUND(result.pix_b2a)
    ENDELSE
    *(*(*info).dataparams).pix_main2ref = pix_main2ref
    *(*(*info).dataparams).pix_ref2main = pix_ref2main
    IF hdr.sjifile THEN BEGIN
      FOR idx_sji=0,hdr.nsjifiles-1 DO BEGIN
        IF (hdr.sji_wcs_set[idx_sji] AND hdr.ref_wcs_set) THEN BEGIN
          pix_ref2sji = ROUND(WCS_GET_PIXEL(*hdr.wcs_sji[idx_sji], $
            WCS_GET_COORD(hdr.wcs_ref)))
          pix_sji2ref = ROUND(WCS_GET_PIXEL(hdr.wcs_ref, $
            WCS_GET_COORD(*hdr.wcs_sji[idx_sji])))
        ENDIF ELSE BEGIN
          result = CRISPEX_TRANSFORM_GET_COORDMAPS(hdr, /REFSJI)
          pix_ref2sji = ROUND(result.pix_a2b)
          pix_sji2ref = ROUND(result.pix_b2a)
        ENDELSE
        *(*(*info).dataparams).pix_ref2sji[idx_sji] = pix_ref2sji
        *(*(*info).dataparams).pix_sji2ref[idx_sji] = pix_sji2ref
      ENDFOR
    ENDIF 
    *(*(*info).dataparams).wcs_ref = hdr.wcs_ref
    ; Default xyref to middle of display, but override by conversion from Main
    ; or SJI display if possible
    (*(*info).dataparams).xref = FLOAT(FLOOR(hdr.refnx/2.))
    (*(*info).dataparams).yref = FLOAT(FLOOR(hdr.refny/2.))
    IF ((*(*info).dispswitch).xy_out_of_range EQ 0) THEN BEGIN
      (*(*info).dataparams).xref = $
        pix_main2ref[0,(*(*info).dataparams).x,(*(*info).dataparams).y]
      (*(*info).dataparams).yref = $
        pix_main2ref[1,(*(*info).dataparams).x,(*(*info).dataparams).y]
    ENDIF ELSE IF (TOTAL((*(*info).winswitch).showsji) GT 0) THEN BEGIN
      wherenot_outofrange = $
        WHERE((*(*info).dispswitch).xysji_out_of_range EQ 0, count)
      IF (count NE 0) THEN BEGIN
        ; Just pick the first SJI where xysji is not out of range
        (*(*info).dataparams).xref = $
          pix_sji2ref[0,(*(*info).dataparams).xsji[wherenot_outofrange[0]],$
                        (*(*info).dataparams).ysji[wherenot_outofrange[0]]]
        (*(*info).dataparams).yref = $
          pix_sji2ref[1,(*(*info).dataparams).xsji[wherenot_outofrange[0]],$
                        (*(*info).dataparams).ysji[wherenot_outofrange[0]]]
      ENDIF 
    ENDIF 
    ; Process spectral parameters
    *(*info).dataparams = CRISPEX_TAG_DELETE(*(*info).dataparams, $
      ['REFLPS', 'REFSPEC', 'REFMS', 'TARR_FULL_REF', 'UTC_FULL_REF', $
      'DATE_FULL_REF', 'TFULL_DIMS_REF', $
      'V_DOP_REF_LOW_MIN', 'V_DOP_REF_LOW_MAX', $
      'V_DOP_REF_UPP_MIN', 'V_DOP_REF_UPP_MAX'])
    CRISPEX_IO_SETTINGS_SPECTRAL, event, HDR_OUT=hdr, /REFERENCE 
    *(*info).dataparams = CREATE_STRUCT(*(*info).dataparams, $
      'reflps', hdr.reflps, 'refspec', hdr.refspec, 'refms', hdr.refms, $
      'tarr_full_ref', hdr.tarr_full_ref, 'tfull_dims_ref', hdr.tfull_dims_ref, $
      'utc_full_ref', hdr.utc_full_ref, 'date_full_ref', hdr.date_full_ref)
    (*(*info).dataparams).lp_ref = hdr.reflc
    (*(*info).dataparams).refnlp = hdr.refnlp
    (*(*info).dataparams).refnt = hdr.refnt
    (*(*info).dataparams).refns = hdr.refns
    (*(*info).dataparams).bunit[1] = hdr.refbunit
    (*(*info).dataparams).lpunit[1] = hdr.reflpunit
    ; dataswitch pointer
    (*(*info).dataswitch).reffile = hdr.showref
    (*(*info).dataswitch).refspfile = hdr.refspfile
    (*(*info).dataswitch).ref_wcs_set = hdr.ref_wcs_set
    ; dispparams pointer
    (*(*info).dispparams).refimbscale = hdr.refimbscale
    (*(*info).dispparams).refimbzero = hdr.refimbzero
    (*(*info).dispparams).refspbscale = hdr.refspbscale
    (*(*info).dispparams).refspbzero = hdr.refspbzero
    (*(*info).dispparams).xref_first = 0L
    (*(*info).dispparams).yref_first = 0L
    (*(*info).dispparams).xref_last = hdr.refnx-1
    (*(*info).dispparams).yref_last = hdr.refny-1
    (*(*info).dispparams).lp_ref_first = 0L
    (*(*info).dispparams).lp_ref_last = hdr.refnlp-1
    (*(*info).dispparams).lp_ref_low = 0L
    (*(*info).dispparams).lp_ref_upp = hdr.refnlp-1
    (*(*info).dispparams).lp_ref_range = hdr.refnlp
    *(*info).dispparams = CRISPEX_TAG_DELETE(*(*info).dispparams, $
      ['LP_REF_LOW_TMP','LP_REF_UPP_TMP','LP_REF_LOW_BOUNDS',$
       'LP_REF_UPP_BOUNDS','V_DOP_REF_LOW','V_DOP_REF_UPP', 'XYTRI_REF'])
     *(*info).dispparams = CREATE_STRUCT(*(*info).dispparams, $
       'lp_ref_low_tmp', REPLICATE(0,hdr.nrefdiagnostics), $
       'lp_ref_upp_tmp', hdr.refdiag_width-1, $
       'lp_ref_low_bounds', hdr.refdiag_start, $
       'lp_ref_upp_bounds', hdr.refdiag_start+(hdr.refdiag_width-1),$
       'xytri_ref', hdr.xytri_ref)
    refheightset = 0
		IF (N_ELEMENTS(hdr.xtitle) EQ 2) THEN BEGIN
			IF (STRCOMPRESS(hdr.xtitle[1]) NE '') THEN BEGIN
				refheightset = (STRCMP(hdr.xtitle[1],'Height',6,/FOLD_CASE) OR $
                        STRCMP(hdr.xtitle[1],'z',1,/FOLD_CASE))
        IF refheightset THEN BEGIN
				  hdr.v_dop_set[1] = 0
				  hdr.refspxtitle = hdr.xtitle[1]
        ENDIF
			ENDIF
		ENDIF
    CRISPEX_IO_PARSE_VDOP, hdr.nrefdiagnostics, INDGEN(hdr.nrefdiagnostics), $
      hdr.v_dop_ref, hdr.refnlp, hdr.reflps, hdr.refdiag_start, $
      hdr.refdiag_width, refheightset, result
    *(*info).dispparams = CREATE_STRUCT(*(*info).dispparams, $
      'v_dop_ref_low', result.v_dop_low_min, $
      'v_dop_ref_upp', result.v_dop_upp_max)
    *(*info).dataparams = CREATE_STRUCT(*(*info).dataparams, $
      'v_dop_ref_low_min', result.v_dop_low_min, $
      'v_dop_ref_low_max', result.v_dop_low_max, $
      'v_dop_ref_upp_min', result.v_dop_upp_min, $
      'v_dop_ref_upp_max', result.v_dop_upp_max)
    (*(*info).dispparams).tsel_ref = PTR_NEW(hdr.tsel_ref)
    (*(*info).dispparams).tarr_ref = PTR_NEW(hdr.tarr_ref[hdr.tsel_ref])
    (*(*info).dispparams).utc_ref = PTR_NEW(hdr.utc_ref[hdr.tsel_ref])
    (*(*info).dispparams).t_ref = hdr.tsel_ref[0]
    (*(*info).dispparams).t_low_ref = hdr.tarr_ref[0]
    (*(*info).dispparams).t_upp_ref = hdr.tarr_ref[(hdr.refnt-1)>0]
    ; dispswitch pointer
    (*(*info).dispswitch).xyref_out_of_range = $
      (((*(*info).dataparams).xref LT 0) OR $
       ((*(*info).dataparams).yref LT 0) OR $
       ((*(*info).dataparams).xref GE hdr.refnx) OR $
       ((*(*info).dataparams).yref GE hdr.refny))
    ; Failsafe for REFSSP_CUR when xyref_out_of_range is true
    IF (*(*info).dispswitch).xyref_out_of_range THEN BEGIN
      FOR i=0,(*(*info).dataparams).refns-1 DO $
        (*(*info).data).refssp_cur[i] = PTR_NEW($
          FLTARR((*(*info).dataparams).refnlp, (*(*info).dataparams).refnt))
    ENDIF
    (*(*info).dispswitch).main2ref_no_map = hdr.main2ref_no_map
    (*(*info).dispswitch).warprefspslice = hdr.warprefspslice
    (*(*info).dispswitch).refimscaled = hdr.refimscaled
    (*(*info).dispswitch).refspscaled = hdr.refspscaled
    ; intparams pointer
    ; First remove potentially conflicting tags and re-add
    *(*info).intparams = CRISPEX_TAG_DELETE(*(*info).intparams, $
      ['REFDIAGNOSTICS','DISP_REFDIAGNOSTICS','REFDIAG_START','REFDIAG_WIDTH'])
    *(*info).intparams = CREATE_STRUCT(*(*info).intparams, $
      'refdiagnostics', hdr.refdiagnostics, $
      'disp_refdiagnostics', REPLICATE(1,hdr.nrefdiagnostics),$
      'refdiag_start', hdr.refdiag_start, 'refdiag_width', hdr.refdiag_width)
    (*(*info).intparams).nrefdiagnostics = hdr.nrefdiagnostics
    (*(*info).intparams).refdiag_starts = PTR_NEW(hdr.refdiag_start)
    (*(*info).intparams).refdiag_widths = PTR_NEW(hdr.refdiag_width)
    (*(*info).intparams).wheredisprefdiag = $
      PTR_NEW(LINDGEN(hdr.nrefdiagnostics))
    (*(*info).intparams).ndisp_refdiagnostics = hdr.nrefdiagnostics
    (*(*info).intparams).lp_ref_diag_all = $
      TOTAL((*(*info).dataparams).lp_ref GE (*(*info).intparams).refdiag_start)-1
    (*(*info).intparams).refsinglewav_windows = $
      (FIX(TOTAL(hdr.refdiag_width)) EQ hdr.nrefdiagnostics)
    ; overlayswitch pointer -> use old values
    ; paramswitch pointer
    (*(*info).paramswitch).t_raster_ref = ((N_ELEMENTS(hdr.tarr_full_ref) NE $
        N_ELEMENTS(hdr.tarr_ref)))
    *(*info).paramswitch = CRISPEX_TAG_DELETE(*(*info).paramswitch, $
      'UPDATE_TFULL_REF') 
    *(*info).paramswitch = CREATE_STRUCT(*(*info).paramswitch, $
      'update_tfull_ref', hdr.update_tfull_ref)
    ; paramparams pointer
    ; Spatial coordinates
    (*(*info).paramparams).refxcoord_format = $
      '(I'+STRTRIM(FLOOR(ALOG10(hdr.refnx))+1,2)+')'
    (*(*info).paramparams).refycoord_format = $
      '(I'+STRTRIM(FLOOR(ALOG10(hdr.refny))+1,2)+')'
    IF hdr.ref_wcs_set THEN BEGIN
      (*(*info).paramparams).refxcoord_real_format = '(F6.1)'
      (*(*info).paramparams).refycoord_real_format = '(F6.1)'
    ENDIF ELSE BEGIN
      (*(*info).paramparams).refxcoord_real_format = $
        '(F'+STRTRIM(FLOOR(ALOG10(hdr.refnx*hdr.refdx))+3,2)+'.1)'
      (*(*info).paramparams).refycoord_real_format = $
        '(F'+STRTRIM(FLOOR(ALOG10(hdr.refny*hdr.refdy))+3,2)+'.1)'
    ENDELSE
    ; Wavelength coordinates
    IF (hdr.refnlp GT 1) THEN $
      (*(*info).paramparams).lp_ref_idx_format = $
        '(I'+STRTRIM(FLOOR(ALOG10(hdr.refnlp))+1,2)+')' $
    ELSE $
      (*(*info).paramparams).lp_ref_idx_format = ''
    IF ((hdr.refnlp GT 1) AND hdr.v_dop_set[1]) THEN BEGIN
      (*(*info).paramparams).lp_ref_real_format = $
        '(F'+STRTRIM(FLOOR(ALOG10(hdr.reflps[hdr.refnlp-1]))+3,2)+'.1)'
      (*(*info).paramparams).lp_ref_vdop_format = $
        '(F'+STRTRIM(FLOOR(ALOG10(MAX(ABS((*hdr.v_dop_ref[0])[$
        [0,hdr.refnlp-1]]))))+5,2)+'.2)'
    ENDIF ELSE BEGIN
      (*(*info).paramparams).lp_ref_real_format = ''
      (*(*info).paramparams).lp_ref_vdop_format = ''
    ENDELSE
    ; Time coordinates
    (*(*info).paramparams).t_ref_idx_format = $
      '(I'+STRTRIM(FLOOR(ALOG10(hdr.refnt))+1,2)+')'
    IF ((hdr.refnt GT 1) AND (hdr.dt NE 0)) THEN BEGIN
      tmax = MAX(hdr.tarr_ref, wheretmax, /NAN)
      IF ((hdr.date_obs_ref NE '0') OR (hdr.startobs_ref NE '0')) THEN $
        (*(*info).paramparams).t_ref_real_format = $
          '(A'+STRTRIM(STRLEN(hdr.utc_ref[wheretmax]),2)+')'  $
      ELSE $
        (*(*info).paramparams).t_ref_real_format = $
          '(F'+STRTRIM(FLOOR(ALOG10(hdr.tarr_ref[wheretmax]))+3,2)+'.1)' 
      ; Check reference raster timing feedback
      IF (*(*info).paramswitch).t_raster_ref THEN BEGIN
        tmax = MAX(hdr.tarr_full_ref, wheretmax, /NAN)
        IF ((hdr.date_obs_ref NE '0') OR (hdr.startobs_ref NE '0')) THEN BEGIN
          dumval = hdr.utc_full_ref[wheretmax]
          (*(*info).paramparams).t_raster_ref_real_format = $
            '(A'+STRTRIM(STRLEN(dumval),2)+')' 
        ENDIF ELSE BEGIN
          dumval = hdr.tarr_full_ref[wheretmax]
          (*(*info).paramparams).t_raster_ref_real_format = $
            '(F'+STRTRIM(FLOOR(ALOG10(dumval))+3,2)+'.1)'
        ENDELSE
      ENDIF ELSE BEGIN
        (*(*info).paramparams).t_raster_ref_real_format = ''
        IF ((*(*info).ctrlsparam).t_raster_ref_real_val NE 0) THEN $
          WIDGET_CONTROL, (*(*info).ctrlsparam).t_raster_ref_real_val, $
            SET_VALUE='N/A'
      ENDELSE
    ENDIF
    ; plotaxes pointer
    (*(*info).plotaxes).xreftickinterval = PTR_NEW(0.)
    (*(*info).plotaxes).xrefdoptickinterval = PTR_NEW(0.)
    *(*info).plotaxes = CRISPEX_TAG_DELETE(*(*info).plotaxes, $
      ['XREFTICKVALS','XREFDOPTICKVALS','XREFDOPTICKLOC','V_DOP_REF'])
    *(*info).plotaxes = CREATE_STRUCT(*(*info).plotaxes, $
      'xreftickvals', PTRARR(hdr.nrefdiagnostics), $
      'xrefdoptickvals', PTRARR(hdr.nrefdiagnostics), $
      'xrefdoptickloc', PTRARR(hdr.nrefdiagnostics), $
      'v_dop_ref', hdr.v_dop_ref)
    (*(*info).plotaxes).refdiag_ratio = $
      PTR_NEW(hdr.refdiag_width/FLOAT(hdr.refdiag_width))
    (*(*info).plotaxes).refdiag_range_sp = $
      PTR_NEW((hdr.refdiag_width/FLOAT(TOTAL(hdr.refdiag_width)))*$
      (*(*info).plotpos).xplspw)
    (*(*info).plotaxes).v_dop_ref = hdr.v_dop_ref
    ; plotpos pointer 
    *(*info).plotpos = CRISPEX_TAG_DELETE(*(*info).plotpos, $
      ['REFLSX0', 'REFLSX1', 'REFLSY0', 'REFLSY1'])
    plotpos = CRISPEX_GET_PLOTPOS(hdr.refns, (*(*info).winsizes).lswinx, $
      (*(*info).plotpos).lsxmargin_init / (*(*info).winsizes).lswinx, $
      (*(*info).plotpos).lsxwall_init / (*(*info).winsizes).lswinx, $
      V_DOP_SET=hdr.v_dop_set[1])
    *(*info).plotpos = CREATE_STRUCT(*(*info).plotpos, $
      'reflsx0', plotpos.x0, 'reflsx1', plotpos.x1, 'reflsy0', plotpos.y0, $
      'reflsy1', plotpos.y1)
  	IF ((hdr.v_dop_set[1] EQ 1) OR (hdr.refns GT 1)) THEN $
      refspheight = (1. - $
        ((*(*info).plotpos).spxmargin_init/(*(*info).winsizes).spwinx * 2.) * $
        (*(*info).winsizes).spwinx/(*(*info).winsizes).spwiny) $
    ELSE $
      refspheight = (1. - $
        ((*(*info).plotpos).spxmargin_init/(*(*info).winsizes).spwinx) + $
        (*(*info).plotpos).spxwall_init/(*(*info).winsizes).spwinx * $
        (*(*info).winsizes).spwinx/(*(*info).winsizes).spwiny)
    (*(*info).plotpos).refspy1 = (*(*info).plotpos).refspy0 + refspheight
    (*(*info).plotpos).refyplspw = $
      (*(*info).plotpos).refspy1 - (*(*info).plotpos).refspy0
    (*(*info).dispparams).refntreb = (*(*info).plotpos).refyplspw * $
      (*(*info).winsizes).spwiny
    ; plotswitch pointer
    (*(*info).plotswitch).refmultichannel = hdr.refmultichannel
    (*(*info).plotswitch).v_dop_set_ref = hdr.v_dop_set[1]
    ; plottitles pointer
    (*(*info).plottitles).refspxtitle = hdr.xtitle[1]
    (*(*info).plottitles).reflsytitle = hdr.ytitle[1]
    ; scaling pointer
    CRISPEX_IO_PARSE_SCALING_INIT, hdr, (*(*info).prefs).histo_opt_val, result,$
      /REFERENCE, SCALE_STOKES=(*(*info).dispswitch).scalestokes, $
      SHOWLS=((hdr.refspfile OR (hdr.refnlp GT 1)) AND $
              ((FIX(TOTAL(hdr.refdiag_width)) EQ hdr.nrefdiagnostics) EQ 0))
    ; Adjust for different number of refdiagnostics
    nscaling_current = N_ELEMENTS((*(*info).scaling).gamma)
    gamma = (*(*info).scaling).gamma
    minimum = (*(*info).scaling).minimum
    maximum = (*(*info).scaling).maximum
    histo_opt_val = (*(*info).scaling).histo_opt_val
    main_mult_val = $
      (*(*info).scaling).mult_val[0:((*(*info).intparams).ndiagnostics-1)]
    *(*info).scaling = CRISPEX_TAG_DELETE(*(*info).scaling, $
      ['MULT_VAL', 'GAMMA', 'MINIMUM', 'MAXIMUM', 'HISTO_OPT_VAL'])
    gamma = $
      [gamma[0:2*(*(*info).intparams).ndiagnostics-1], $
      REPLICATE(gamma[2*(*(*info).intparams).ndiagnostics],$
      (*(*info).intparams).nrefdiagnostics), gamma[nscaling_current-1]]
    minimum = [minimum[0:2*(*(*info).intparams).ndiagnostics-1], $
      REPLICATE(0,(*(*info).intparams).nrefdiagnostics), $
      minimum[nscaling_current-1]]
    maximum = [maximum[0:2*(*(*info).intparams).ndiagnostics-1], $
      REPLICATE(100,(*(*info).intparams).nrefdiagnostics), $
      maximum[nscaling_current-1]]
    histo_opt_val = $
      [histo_opt_val[0:2*(*(*info).intparams).ndiagnostics-1], $
      REPLICATE(histo_opt_val[2*(*(*info).intparams).ndiagnostics], $
      (*(*info).intparams).nrefdiagnostics), histo_opt_val[nscaling_current-1]]
    *(*info).scaling = CREATE_STRUCT(*(*info).scaling, $
      'mult_val', [main_mult_val, result.mult_val], 'gamma', gamma, $
      'minimum', minimum, 'maximum', maximum, 'histo_opt_val', histo_opt_val)
    *(*(*info).plotaxes).ls_low_y_ref = result.ls_low_y
    *(*(*info).plotaxes).ls_upp_y_ref = result.ls_upp_y
    *(*(*info).plotaxes).ls_yrange_ref = result.ls_yrange
    (*(*info).scaling).refmin = result.immin[hdr.reflc]
    (*(*info).scaling).refmax = result.immax[hdr.reflc]
    ; stokesparams pointer
    *(*info).stokesparams = CRISPEX_TAG_DELETE(*(*info).stokesparams, $
      ['LABELS_REF','SELECT_REFSP','PREV_SELECT_REFSP'])
    *(*info).stokesparams = CREATE_STRUCT(*(*info).stokesparams, $
      'labels_ref', hdr.stokes_labels_ref, $
      'select_refsp', hdr.stokes_select_refsp, $
      'prev_select_refsp', hdr.stokes_select_refsp)
    ; refwid pointer -> simply use same ones, or overwrite if window is toggled
    ;                   off and on in CRISPEX_IO_OPEN_REFCUBE
    ; winsizes pointer
    (*(*info).winsizes).reflsyres = plotpos.winy
    (*(*info).winsizes).reflsxres = (*(*info).winsizes).lswinx
    (*(*info).winsizes).refspyres = (*(*info).winsizes).spwiny
    (*(*info).winsizes).refspxres = (*(*info).winsizes).spwinx
    ; Determine image and pixel aspect ratio
    screeninfo  = OBJ_NEW('IDLsysMonitorInfo')
    nmonitors   = screeninfo -> GetNumberOfMonitors()
    screensizes = screeninfo -> GetRectangles()
    IF (nmonitors GT 1) THEN $
	    monitor_order = (INDGEN(nmonitors))[SORT(screensizes[0,0:1])] $
    ELSE $ 
      monitor_order = 0
    y_scr_size = screensizes[3,monitor_order[0]]
    refpixelratio = FLOAT(ABS(hdr.refdx)) / FLOAT(ABS(hdr.refdy))
    refwinx_default = hdr.refnx
    refwiny_default = hdr.refny
    ; Handle pixel aspect ratio
    IF (refpixelratio GT 1) THEN refwinx_default *= refpixelratio ELSE $
      IF (refpixelratio LT 1) THEN refwiny_default /= refpixelratio
    ; Size refwiny according to the y-pixelsize
    refwiny = refwiny_default*(*(*info).dataparams).refdy / $
              FLOAT((*(*info).winsizes).xywiny*(*(*info).dataparams).dy) * $
              (*(*info).winsizes).xywiny
    ; If refwiny becomes too big (i.e., because FOV is bigger than y-extent of
    ; main data) OR if refwiny and imwiny should be the same because of
    ; respective ny*dy, but aren't, then resize to the final main y-window
    IF ((refwiny GT y_scr_size) OR $
      (((*(*info).dataparams).ny*(*(*info).dataparams).dy EQ $
        (*(*info).dataparams).refny*(*(*info).dataparams).refdy) AND $
        (refwiny NE (*(*info).winsizes).xywiny))) THEN $
        refwiny = (*(*info).winsizes).xywiny
    refwinx = refwinx_default/FLOAT(refwiny_default)*refwiny
    (*(*info).winsizes).refwiny = refwiny
    (*(*info).winsizes).refwinx = refwinx_default/FLOAT(refwiny_default)*$
      (*(*info).winsizes).refwiny
    ; winsizes.offsets -> use old ones
    ; zooming pointer
  	(*(*info).dataparams).d_refnx = ((*(*info).dataparams).refnx / $
      ((*(*info).zooming).factor/ ((*(*info).winsizes).refwinx / $
      (*(*info).dataparams).refpixelratio / $
      FLOAT((*(*info).dataparams).refnx)))) < $
        ((*(*info).dataparams).refnx-1)
  	(*(*info).dataparams).d_refny = ((*(*info).dataparams).refny / $
      ((*(*info).zooming).factor/ ((*(*info).winsizes).refwiny / $
      FLOAT((*(*info).dataparams).refny)))) < $
        ((*(*info).dataparams).refny-1)
  	(*(*info).zooming).xrefpos = ((*(*info).dataparams).xref - $
      (*(*info).dataparams).d_refnx / 2.) > 0
  	(*(*info).zooming).yrefpos = ((*(*info).dataparams).yref - $
      (*(*info).dataparams).d_refny / 2.) > 0
  	IF (((*(*info).zooming).xrefpos+(*(*info).dataparams).d_refnx) GE $
      (*(*info).dataparams).refnx) THEN $
      (*(*info).zooming).xrefpos = $
        (((*(*info).dataparams).refnx-1) - (*(*info).dataparams).d_refnx) > 0
  	IF (((*(*info).zooming).yrefpos+(*(*info).dataparams).d_refny) GE $
      (*(*info).dataparams).refny) THEN $
      (*(*info).zooming).yrefpos = (((*(*info).dataparams).refny-1) - $
        (*(*info).dataparams).d_refny) > 0
  	(*(*info).zooming).xrefpos = LONG((*(*info).zooming).xrefpos)
  	(*(*info).zooming).yrefpos = LONG((*(*info).zooming).yrefpos)
  ENDIF
  IF KEYWORD_SET(SJI) THEN BEGIN
    ; data pointer
    *(*(*info).data).sjidata[idx_sji] = *hdr.sjidata[idx_sji]
    *(*(*info).data).sjislice[idx_sji] = *hdr.sjislice[idx_sji]
    (*(*info).data).lunsji[idx_sji] = hdr.lunsji[idx_sji]
    ; dataparams pointer
    (*(*info).dataparams).sjifilename[idx_sji] = hdr.sjifilename[idx_sji]
    (*(*info).dataparams).hdrs = $
      [(*(*info).dataparams).hdrs[0:1+idx_sji], PTR_NEW(*hdr.hdrs_sji[idx_sji])]
    (*(*info).dataparams).next = $
      [(*(*info).dataparams).next[0:1+idx_sji], N_ELEMENTS(*hdr.hdrs_sji[idx_sji])]
    (*(*info).dataparams).date_obs_sji[idx_sji] = hdr.date_obs_sji[idx_sji]
    (*(*info).dataparams).sjinx[idx_sji] = hdr.sjinx[idx_sji]
    (*(*info).dataparams).sjiny[idx_sji] = hdr.sjiny[idx_sji]
    (*(*info).dataparams).sjidx[idx_sji] = hdr.sjidx[idx_sji]
    (*(*info).dataparams).sjidy[idx_sji] = hdr.sjidy[idx_sji]
    (*(*info).dataparams).xval_sji[idx_sji] = hdr.xval_sji[idx_sji]
    (*(*info).dataparams).yval_sji[idx_sji] = hdr.yval_sji[idx_sji]
    (*(*info).dataparams).xpix_sji[idx_sji] = hdr.xpix_sji[idx_sji]
    (*(*info).dataparams).ypix_sji[idx_sji] = hdr.ypix_sji[idx_sji]
    IF (hdr.wcs_set AND hdr.sji_wcs_set[idx_sji]) THEN BEGIN
      pix_main2sji = $
        ROUND(WCS_GET_PIXEL(*hdr.wcs_sji[idx_sji], WCS_GET_COORD(hdr.wcs_main)))
      pix_sji2main = $
        ROUND(WCS_GET_PIXEL(hdr.wcs_main, WCS_GET_COORD(*hdr.wcs_sji[idx_sji])))
    ENDIF ELSE BEGIN
      result = CRISPEX_TRANSFORM_GET_COORDMAPS(hdr, /MAINSJI)
      pix_main2sji = ROUND(result.pix_a2b)
      pix_sji2main = ROUND(result.pix_b2a)
    ENDELSE
    *(*(*info).dataparams).pix_main2sji[idx_sji] = pix_main2sji
    *(*(*info).dataparams).pix_sji2main[idx_sji] = pix_sji2main
    IF hdr.showref THEN BEGIN
      IF (hdr.ref_wcs_set AND hdr.sji_wcs_set[idx_sji]) THEN BEGIN
        pix_ref2sji = $
          ROUND(WCS_GET_PIXEL(*hdr.wcs_sji[idx_sji], WCS_GET_COORD(hdr.wcs_ref)))
        pix_sji2ref = $
          ROUND(WCS_GET_PIXEL(hdr.wcs_ref, WCS_GET_COORD(*hdr.wcs_sji[idx_sji])))
      ENDIF ELSE BEGIN
        result = CRISPEX_TRANSFORM_GET_COORDMAPS(hdr, /REFSJI)
        pix_ref2sji = ROUND(result.pix_a2b)
        pix_sji2ref = ROUND(result.pix_b2a)
      ENDELSE
      *(*(*info).dataparams).pix_ref2sji[idx_sji] = pix_ref2sji
      *(*(*info).dataparams).pix_sji2ref[idx_sji] = pix_sji2ref
    ENDIF ELSE BEGIN
      pix_ref2sji = 0.
      pix_sji2ref = 0.
    ENDELSE
    FOR idx_tmp_sji=0,(*(*info).dataparams).nsjifiles-1 DO BEGIN
      *(*(*info).dataparams).pix_sji2sji[idx_sji,idx_tmp_sji] = $
        ROUND(WCS_GET_PIXEL(*hdr.wcs_sji[idx_tmp_sji], $
              WCS_GET_COORD(*hdr.wcs_sji[idx_sji]))) 
      *(*(*info).dataparams).pix_sji2sji[idx_tmp_sji,idx_sji] = $
        ROUND(WCS_GET_PIXEL(*hdr.wcs_sji[idx_sji], $
              WCS_GET_COORD(*hdr.wcs_sji[idx_tmp_sji]))) 
    ENDFOR
    *(*(*info).dataparams).pix_sji2sji[idx_sji,idx_sji] = $
      ROUND(WCS_GET_PIXEL(*hdr.wcs_sji[idx_sji], $
            WCS_GET_COORD(*hdr.wcs_sji[idx_sji]))) 
    *(*(*info).dataparams).wcs_sji[idx_sji] = *hdr.wcs_sji[idx_sji]
    IF ((*(*info).dispswitch).xy_out_of_range EQ 0) THEN BEGIN
      (*(*info).dataparams).xsji[idx_sji] = $
        pix_main2sji[0,(*(*info).dataparams).x,(*(*info).dataparams).y]
      (*(*info).dataparams).ysji[idx_sji] = $
        pix_main2sji[1,(*(*info).dataparams).x,(*(*info).dataparams).y]
    ENDIF 
    *(*(*info).dataparams).tarr_sji[idx_sji] = *hdr.tarr_sji[idx_sji]
    *(*(*info).dataparams).utc_sji[idx_sji] = *hdr.utc_sji[idx_sji]
    *(*(*info).dataparams).date_sji[idx_sji] = *hdr.date_sji[idx_sji]
    (*(*info).dataparams).sjint[idx_sji] = hdr.sjint[idx_sji]
    (*(*info).dataparams).bunit[2+idx_sji] = hdr.sjibunit[idx_sji]
    ; dataswitch pointer
    (*(*info).dataswitch).sjifile = hdr.sjifile
    (*(*info).dataswitch).sji_wcs_set[idx_sji] = hdr.sji_wcs_set[idx_sji]
    ; dispparams pointer
    (*(*info).dispparams).xsji_first[idx_sji] = 0L
    (*(*info).dispparams).ysji_first[idx_sji] = 0L
    (*(*info).dispparams).xsji_last[idx_sji] = hdr.sjinx[idx_sji]-1
    (*(*info).dispparams).ysji_last[idx_sji] = hdr.sjiny[idx_sji]-1
    (*(*info).dispparams).tsel_sji[idx_sji] = PTR_NEW(*hdr.tsel_sji[idx_sji])
    (*(*info).dispparams).tarr_sji[idx_sji] = $
      PTR_NEW((*hdr.tarr_sji[idx_sji])[*hdr.tsel_sji[idx_sji]])
    (*(*info).dispparams).utc_sji[idx_sji] = $
      PTR_NEW((*hdr.utc_sji[idx_sji])[*hdr.tsel_sji[idx_sji]])
    (*(*info).dispparams).t_sji[idx_sji] = (*hdr.tsel_sji[idx_sji])[0]
    (*(*info).dispparams).t_low_sji[idx_sji] = (*hdr.tarr_sji[idx_sji])[0]
    (*(*info).dispparams).t_upp_sji[idx_sji] = $
      (*hdr.tarr_sji[idx_sji])[(hdr.sjint[idx_sji]-1)>0]
    (*(*info).dispparams).sjibscale[idx_sji] = hdr.sjibscale[idx_sji]
    (*(*info).dispparams).sjibzero[idx_sji] = hdr.sjibzero[idx_sji]
    ; dispswitch pointer
    (*(*info).dispswitch).sjiscaled[idx_sji] = hdr.sjiscaled[idx_sji]
    (*(*info).dispswitch).xysji_out_of_range[idx_sji] = $
      (((*(*info).dataparams).xsji[idx_sji] LT 0) OR $
       ((*(*info).dataparams).ysji[idx_sji] LT 0) OR $
       ((*(*info).dataparams).xsji[idx_sji] GE hdr.sjinx[idx_sji]) OR $
       ((*(*info).dataparams).ysji[idx_sji] GE hdr.sjiny[idx_sji]))
    ; overlayswitch pointer -> use old values
    ; paramparams pointer
    (*(*info).paramparams).sjixcoord_format = $
      '(I'+STRTRIM(FLOOR(ALOG10(hdr.sjinx[idx_sji]))+1,2)+')'
    (*(*info).paramparams).sjiycoord_format = $
      '(I'+STRTRIM(FLOOR(ALOG10(hdr.sjiny[idx_sji]))+1,2)+')'
    IF hdr.sji_wcs_set[idx_sji] THEN BEGIN
      (*(*info).paramparams).sjixcoord_real_format = '(F6.1)'
      (*(*info).paramparams).sjiycoord_real_format = '(F6.1)'
    ENDIF ELSE BEGIN
      (*(*info).paramparams).sjixcoord_real_format = $
        '(F'+STRTRIM(FLOOR(ALOG10(hdr.sjinx[idx_sji]*hdr.sjidx[idx_sji]))+3,2)+'.1)'
      (*(*info).paramparams).sjiycoord_real_format = $
        '(F'+STRTRIM(FLOOR(ALOG10(hdr.sjiny[idx_sji]*hdr.sjidy[idx_sji]))+3,2)+'.1)'
    ENDELSE
    (*(*info).paramparams).t_sji_idx_format = $
      '(I'+STRTRIM(FLOOR(ALOG10(hdr.sjint[idx_sji]))+1,2)+')'
    IF ((hdr.sjint[idx_sji] GT 1) AND (hdr.dt NE 0)) THEN BEGIN
      wheretgt0 = WHERE(*hdr.tarr_sji[idx_sji] GT 0, count)
      IF (count GT 0) THEN $
        t_sel = wheretgt0[count-1] $
      ELSE $
        t_sel = 0
      IF (hdr.date_obs_sji[idx_sji] NE '0') THEN $
        (*(*info).paramparams).t_sji_real_format = $
          '(A'+STRTRIM(STRLEN((*hdr.utc_sji[idx_sji])[t_sel]),2)+')'  $
      ELSE $
        (*(*info).paramparams).t_sji_real_format = $
          '(F'+STRTRIM(FLOOR(ALOG10((*hdr.tarr_sji[idx_sji])[t_sel]))+3,2)+'.1)'
    ENDIF
    ; scaling pointer
    sjidata_tmp = (*hdr.sjidata[idx_sji])[0]
    ; If SJI data is scaled integer, descale and convert to float
    IF hdr.sjiscaled[idx_sji] THEN $
      sjidata_tmp = CRISPEX_SCALING_DESCALE(sjidata_tmp, $
        hdr.sjibscale[idx_sji], hdr.sjibzero[idx_sji])
    (*(*info).scaling).sjimin[idx_sji] = MIN(sjidata_tmp, MAX=sjimax_val, /NAN)
    (*(*info).scaling).sjimax[idx_sji] = sjimax_val
    ; sjiwid pointer -> simply use same ones, or overwrite if window is toggled
    ;                   off and on in CRISPEX_IO_OPEN_SJICUBE
    ; winsizes pointer
    ; Determine image and pixel aspect ratio
    screeninfo  = OBJ_NEW('IDLsysMonitorInfo')
    nmonitors   = screeninfo -> GetNumberOfMonitors()
    screensizes = screeninfo -> GetRectangles()
    IF (nmonitors GT 1) THEN $
	    monitor_order = (INDGEN(nmonitors))[SORT(screensizes[0,0:1])] $
    ELSE $ 
      monitor_order = 0
    y_scr_size = screensizes[3,monitor_order[0]]
    sjipixelratio = FLOAT(ABS(hdr.sjidx[idx_sji])) / $
                    FLOAT(ABS(hdr.sjidy[idx_sji]))
    sjiwinx_default = hdr.sjinx[idx_sji]
    sjiwiny_default = hdr.sjiny[idx_sji]
    ; Handle pixel aspect ratio
    IF (sjipixelratio GT 1) THEN sjiwinx_default *= sjipixelratio ELSE $
      IF (sjipixelratio LT 1) THEN sjiwiny_default /= sjipixelratio
    ; Size sjiwiny according to the y-pixelsize
    sjiwiny = sjiwiny_default*(*(*info).dataparams).sjidy[idx_sji] / $
              FLOAT((*(*info).winsizes).xywiny*(*(*info).dataparams).dy) * $
              (*(*info).winsizes).xywiny
    ; If sjiwiny becomes too big (i.e., because FOV is bigger than y-extent of
    ; main data) OR if sjiwiny and imwiny should be the same because of
    ; respective ny*dy, but aren't, then resize to the final main y-window
    IF ((sjiwiny GT y_scr_size) OR $
      (((*(*info).dataparams).ny*(*(*info).dataparams).dy EQ $
        (*(*info).dataparams).sjiny[idx_sji]*(*(*info).dataparams).sjidy[idx_sji]) AND $
        (sjiwiny NE (*(*info).winsizes).xywiny))) THEN $
        sjiwiny = (*(*info).winsizes).xywiny
    sjiwinx = sjiwinx_default/FLOAT(sjiwiny_default)*sjiwiny
    (*(*info).winsizes).sjiwiny[idx_sji] = sjiwiny
    (*(*info).winsizes).sjiwinx[idx_sji] = sjiwinx_default/FLOAT(sjiwiny_default)*$
      (*(*info).winsizes).sjiwiny[idx_sji]
    ; winsizes.offsets -> use old ones
  	(*(*info).dataparams).d_sjinx[idx_sji] = $
      ((*(*info).dataparams).sjinx[idx_sji] / ((*(*info).zooming).factor/ $
      ((*(*info).winsizes).sjiwinx[idx_sji] / $
      (*(*info).dataparams).sjipixelratio[idx_sji] / $
      FLOAT((*(*info).dataparams).sjinx[idx_sji])))) < $
        ((*(*info).dataparams).sjinx[idx_sji]-1)
  	(*(*info).dataparams).d_sjiny[idx_sji] = $
      ((*(*info).dataparams).sjiny[idx_sji] / ((*(*info).zooming).factor/ $
      ((*(*info).winsizes).sjiwiny[idx_sji] / $
      FLOAT((*(*info).dataparams).sjiny[idx_sji])))) < $
        ((*(*info).dataparams).sjiny[idx_sji]-1)
    ; zooming pointer
  	(*(*info).zooming).xsjipos[idx_sji] = ((*(*info).dataparams).xsji[idx_sji] - $
      (*(*info).dataparams).d_sjinx[idx_sji] / 2.) > 0
  	(*(*info).zooming).ysjipos[idx_sji] = ((*(*info).dataparams).ysji[idx_sji] - $
      (*(*info).dataparams).d_sjiny[idx_sji] / 2.) > 0
  	IF (((*(*info).zooming).xsjipos[idx_sji]+(*(*info).dataparams).d_sjinx[idx_sji]) GE $
      (*(*info).dataparams).sjinx[idx_sji]) THEN $
      (*(*info).zooming).xsjipos[idx_sji] = $
        (((*(*info).dataparams).sjinx[idx_sji]-1) - $
        (*(*info).dataparams).d_sjinx[idx_sji]) > 0
  	IF (((*(*info).zooming).ysjipos[idx_sji]+$
      (*(*info).dataparams).d_sjiny[idx_sji]) GE $
      (*(*info).dataparams).sjiny[idx_sji]) THEN $
      (*(*info).zooming).ysjipos[idx_sji] = $
        (((*(*info).dataparams).sjiny[idx_sji]-1) - $
        (*(*info).dataparams).d_sjiny[idx_sji]) > 0
  	(*(*info).zooming).xsjipos[idx_sji] = $
      LONG((*(*info).zooming).xsjipos[idx_sji])
  	(*(*info).zooming).ysjipos[idx_sji] = $
      LONG((*(*info).zooming).ysjipos[idx_sji])
    ; Set nsjifiles at the very end to prevent issues in earlier loops
    (*(*info).dataparams).nsjifiles = hdr.nsjifiles
  ENDIF
END

PRO CRISPEX_IO_SETTINGS_SPECTRAL, event, HDR_IN=hdr_in, HDR_OUT=hdr_out, $
      MAIN=main, REFERENCE=reference, $
      MNSPEC=mnspec, SPECTFILE=spectfile, LINE_CENTER=line_center, NO_WARP=no_warp, $
      STARTUPTLB=startuptlb, IO_FAILSAFE_MNSPEC_ERROR=io_failsafe_mnspec_error, $
      IO_FAILSAFE_IMSPECTFILE_ERROR=io_failsafe_imspectfile_error,$
      IO_FAILSAFE_REFSPECTFILE_ERROR=io_failsafe_refspectfile_error, $
      IO_FAILSAFE_LINE_CENTER_ERROR=io_failsafe_line_center_error
  ; Handles spectral settings on loading cubes
  IF (N_ELEMENTS(event) EQ 1) THEN BEGIN
    WIDGET_CONTROL, event.TOP, GET_UVALUE=info 
    hdr_out = *(*(*info).ioparams).hdr 
  ENDIF ELSE $
    hdr_out = hdr_in

  ; Check for setting of MAIN or REFERENCE; if neither supplied, set both
  IF (~KEYWORD_SET(MAIN) AND ~KEYWORD_SET(REFERENCE)) THEN BEGIN
    main = 1B
    reference = 1B
  ENDIF
 
  ; Initialise failsafe switches
  io_failsafe_mnspec_error = 0
  io_failsafe_imspectfile_error = 0
  io_failsafe_refspectfile_error = 0
  io_failsafe_line_center_error = 0

  ; Check whether SPECTFILE has been provided with save files
  spectfile_set = 0
  refspectfile_set = 0
  IF ((N_ELEMENTS(SPECTFILE) GE 1) AND (SIZE(SPECTFILE,/TYPE) EQ 7)) THEN BEGIN
    spectfile_set = (spectfile[0] NE '') 
    ; Check reference
    refspectfile_set = $
      ((N_ELEMENTS(SPECTFILE) EQ 2) AND (SIZE(SPECTFILE,/TYPE) EQ 7)) 
  ENDIF 

  IF KEYWORD_SET(MAIN) THEN BEGIN
    ; Check for correct MNSPEC setting
    IF (N_ELEMENTS(MNSPEC) NE 0) THEN BEGIN
      CRISPEX_IO_FAILSAFES_MNSPEC, mnspec, hdr_out, STARTUPTLB=startuptlb, $
                                   IO_FAILSAFE_ERROR=io_failsafe_mnspec_error
      IF io_failsafe_mnspec_error THEN RETURN
    ENDIF 
  
    ; Handle SPECTFILE input; will only be done when cube is read in compatibility 
    ; mode (i.e., for non-FITS cubes). 
    IF spectfile_set THEN BEGIN
      hdr_out.spectfile[0] = spectfile[0]
      ; Check existence of file, else throw error message
      IF (FILE_TEST(spectfile[0]) EQ 0) THEN BEGIN
        CRISPEX_UPDATE_STARTUP_SETUP_FEEDBACK, 'The main spectral save file "'+$
          spectfile[0]+'" does not exist. Please check your input.', $
          /ERROR,/NO_ROUTINE
        io_failsafe_imspectfile_error = 1
        RETURN
      ENDIF
    ENDIF
    CRISPEX_IO_PARSE_SPECTFILE, spectfile, *hdr_out.imdata, hdr_out.verbosity, $
      SCANFILE=(*hdr_out.scan)[hdr_out.tsel_main[0]], $
      HDR_IN=hdr_out, HDR_OUT=hdr_out, MNSPEC=mnspec, /IMCUBE, $
      CUBE_COMPATIBILITY=hdr_out.imcube_compatibility, $
      STARTUPTLB=startuptlb, IO_FAILSAFE_ERROR=io_failsafe_imspectfile_error
    IF (io_failsafe_imspectfile_error EQ 1) THEN RETURN 
  ENDIF

  IF KEYWORD_SET(REFERENCE) THEN BEGIN
    IF refspectfile_set THEN BEGIN
      hdr_out.spectfile[1] = spectfile[1]
      ; Check existence of file, else throw error message
      IF (FILE_TEST(spectfile[1]) EQ 0) THEN BEGIN
        CRISPEX_UPDATE_STARTUP_SETUP_FEEDBACK, $
          'The reference spectral save file "'+spectfile[1]+$
          '" does not exist. Please check your input.', /ERROR,/NO_ROUTINE
        io_failsafe_refspectfile_error = 1
        RETURN
      ENDIF
    ENDIF
    IF (STRCOMPRESS(hdr_out.refimfilename) NE '') THEN BEGIN
      IF ((N_ELEMENTS(SPECTFILE) EQ 1) AND (refspectfile_set EQ 0)) THEN $
        spectfile = [spectfile, '']
      CRISPEX_IO_PARSE_SPECTFILE, spectfile, *hdr_out.refdata, hdr_out.verbosity,$
        HDR_IN=hdr_out, HDR_OUT=hdr_out, MNSPEC=mnspec, /REFCUBE, $
        STARTUPTLB=startuptlb, CUBE_COMPATIBILITY=hdr_out.refimcube_compatibility, $
        IO_FAILSAFE_ERROR=io_failsafe_refspectfile_error
      IF io_failsafe_refspectfile_error THEN RETURN
    ENDIF 
  ENDIF
  IF (~KEYWORD_SET(REFERENCE) OR (STRCOMPRESS(hdr_out.refimfilename) EQ '')) THEN $
    hdr_out = CREATE_STRUCT(hdr_out, 'refspec', 0., 'refms', 0., 'reflps', 0., $
      'refspectrum', 0., 'tsel_scaling_ref', 0)

  ; Handle LINE_CENTER input
  IF (N_ELEMENTS(LINE_CENTER) NE 0) THEN BEGIN
    CRISPEX_IO_FAILSAFES_LINE_CENTER, line_center, hdr_out, $
      NFILES=(hdr_out.showref+1), STARTUPTLB=startuptlb, $
      SPECTFILE_SET=spectfile_set, REFSPECTFILE_SET=refspectfile_set,$
      IO_FAILSAFE_ERROR=io_failsafe_line_center_error
  ENDIF 
  cube_compatibility = [hdr_out.imcube_compatibility,hdr_out.refimcube_compatibility]
  IF (io_failsafe_line_center_error EQ 1) THEN $
    RETURN $
  ELSE $
    CRISPEX_IO_PARSE_LINE_CENTER, line_center, NFILES=(hdr_out.refnlp GT 1)+1, $
      MAIN=KEYWORD_SET(MAIN), $
      REFERENCE=KEYWORD_SET(REFERENCE), $
      HDR_IN=hdr_out, HDR_OUT=hdr_out,SPECTFILE_SET=spectfile_set, $
      REFSPECTFILE_SET=refspectfile_set,$
      CUBE_COMPATIBILITY=cube_compatibility, DLAMBDA_VAL=dlambda, $
      DLAMBDA_SET=dlambda_set, V_DOP_SET=v_dop_set, $
      IO_FAILSAFE_ERROR=io_failsafe_line_center_error
  IF (N_ELEMENTS(event) NE 1) THEN $
    hdr_out = CREATE_STRUCT(hdr_out, 'dlambda', dlambda, $
                'dlambda_set', dlambda_set, 'v_dop_set', v_dop_set) $
  ELSE BEGIN
    hdr_out.dlambda = dlambda
    hdr_out.dlambda_set = dlambda_set
    hdr_out.v_dop_set = v_dop_set
  ENDELSE
               
  ; Process settings from LINE_CENTER parsing 
  IF (hdr_out.refnlp GT 1) THEN BEGIN
    IF hdr_out.refimcube_compatibility THEN $
      hdr_out.refspxtitle = $
        (['Spectral position','Wavelength'])[hdr_out.v_dop_set[1]] $
    ELSE $
      hdr_out.refspxtitle = hdr_out.xtitle[1]
  ENDIF ELSE BEGIN
    wheretag = WHERE(TAG_NAMES(hdr_out) EQ 'REFLC', count)
    IF (count EQ 0) THEN $
      hdr_out = CREATE_STRUCT(hdr_out, 'reflc', 0L)
    wheretag = WHERE(TAG_NAMES(hdr_out) EQ 'V_DOP_REF', count)
    IF (count EQ 0) THEN $
    hdr_out = CREATE_STRUCT(hdr_out, 'v_dop_ref', 0)
  ENDELSE
  IF hdr_out.imcube_compatibility THEN $
    hdr_out.spxtitle = (['Spectral position','Wavelength'])[hdr_out.v_dop_set[0]] $
  ELSE $
    hdr_out.spxtitle = hdr_out.xtitle[0]
 
  IF KEYWORD_SET(MAIN) THEN BEGIN
    ; Process settings based on LPS variable and NO_WARP keyword to (not) warp of
    ; spectral slices
    ; Disable warp by default for IRIS data if NO_WARP keyword is not specified
    IF ~KEYWORD_SET(NO_WARP) THEN no_warp = STRCMP(hdr_out.instr_main, 'IRIS')
    CRISPEX_IO_PARSE_WARPSLICE, hdr_out, WARPSPSLICE=warpspslice, $
                                NO_WARP=no_warp, XYTRI=xytri
  ENDIF

  IF KEYWORD_SET(REFERENCE) THEN BEGIN
    ; Process settings based on REFLPS variable and NO_WARP keyword to (not) warp of
    ; spectral slices
    ; Disable warp by default for IRIS data if NO_WARP keyword is not specified
    IF ~KEYWORD_SET(NO_WARP) THEN no_warp = STRCMP(hdr_out.instr_ref, 'IRIS')
    CRISPEX_IO_PARSE_WARPSLICE, hdr_out, WARPSPSLICE=warprefspslice, $
                                NO_WARP=no_warp, XYTRI=xytri_ref, /REFERENCE
  ENDIF ELSE BEGIN
    xytri_ref = PTR_NEW(0)  &   warprefspslice = BYTARR(hdr_out.nrefdiagnostics)
  ENDELSE
  IF (N_ELEMENTS(event) NE 1) THEN $
    hdr_out = CREATE_STRUCT(hdr_out, 'xytri', xytri, 'xytri_ref', xytri_ref, $
      'warpspslice', warpspslice, 'warprefspslice', warprefspslice) $
  ELSE BEGIN
    ; Only need to handle reference since only reference will be changed when
    ; called with event
    hdr_out = CRISPEX_TAG_DELETE(hdr_out, 'XYTRI_REF') 
    hdr_out = CREATE_STRUCT(hdr_out, 'xytri_ref', xytri_ref)
    hdr_out.warprefspslice = warprefspslice
  ENDELSE
END

PRO CRISPEX_IO_PARSE_LINE_CENTER, line_center, NFILES=nfiles, HDR_IN=hdr_in, $
      MAIN=main, REFERENCE=reference, $
      HDR_OUT=hdr_out, SPECTFILE_SET=spectfile_set, $
      REFSPECTFILE_SET=refspectfile_set, CUBE_COMPATIBILITY=cube_compatibility,$
      DLAMBDA_VAL=dlambda_val, DLAMBDA_SET=dlambda_set, V_DOP_SET=v_dop_set, $
      IO_FAILSAFE_ERROR=io_failsafe_error
; Handles parsing of LINE_CENTER keyword
  ; lcase of 0: LINE_CENTER = <Undefined>
  ; lcase of 1: LINE_CENTER = lc or [[lc],[lc]]
  ; lcase of 2: LINE_CENTER = [cwav,dwav] or [[cwav,dwav],[cwav,dwav]]
  ; lcase of 3: LINE_CENTER = [lc,cwav,dwav] or [[lc,cwav,dwav],[lc,cwav,dwav]]
  hdr_out = hdr_in	
  IF (N_ELEMENTS(LINE_CENTER) GT 0) THEN BEGIN
    *hdr_out.line_center = line_center
    ndims = SIZE(LINE_CENTER,/N_DIMENSIONS) > 1
    nelem = N_ELEMENTS(LINE_CENTER)
    IF (io_failsafe_error NE 2) THEN lcase = nelem / ndims ELSE lcase = 0
  ENDIF ELSE BEGIN
    ndims = 1
    lcase = 0
  ENDELSE
  c_speed	= 2.99792458D5													; Speed of light in km/s
;  lc = LONARR(nfiles)   &  
  dlambda_val = FLTARR(2)  &  lambda_c = FLTARR(2)
	v_dop_set = BYTARR(2) &  dlambda_set = BYTARR(2)
  nlp_select = [hdr_out.nlp,hdr_out.refnlp]
  spectfile_set = [spectfile_set,refspectfile_set]
  IF (KEYWORD_SET(MAIN) OR KEYWORD_SET(REFERENCE)) THEN BEGIN
    d_low = (KEYWORD_SET(REFERENCE)-KEYWORD_SET(MAIN)) > 0
    d_upp = KEYWORD_SET(REFERENCE)
  ENDIF ELSE BEGIN
    d_low = 0
    d_upp = nfiles-1
  ENDELSE
 
  FOR d=d_low,d_upp DO BEGIN
    IF (d EQ 0) THEN tag2 = 'lc' ELSE tag2 = 'reflc'
    IF ((cube_compatibility[d] NE 1) AND (N_ELEMENTS(LINE_CENTER) GT 0) AND $
      (d NE ndims-1)) THEN BEGIN
      CRISPEX_UPDATE_STARTUP_SETUP_FEEDBACK, $
        'Calling CRISPEX with LINE_CENTER, while FITS cubes are provided, '+$
        'is not allowed. Settings from LINE_CENTER will be ignored.', /WARNING, $
        /NO_ROUTINE
        lcase = 0
    ENDIF 
    IF (d EQ 0) THEN BEGIN
      lps_select = hdr_out.lps    &   spec_select = hdr_out.spectrum 
    ENDIF ELSE BEGIN
      IF ((nfiles EQ 2) AND (ndims NE 2)) THEN lcase = 0
      lps_select = hdr_out.reflps &   spec_select = hdr_out.refspectrum
    ENDELSE
    IF ((lcase EQ 1) OR (lcase EQ 3)) THEN $            ; First read parameters from LINE_CENTER
      lc = line_center[0,d] $
    ELSE BEGIN              ; Or determine from mean spectrum if line centre position is not supplied
      wheretag2 = WHERE(TAG_NAMES(hdr_out) EQ STRUPCASE(tag2), count)
      IF (count LE 0) THEN BEGIN    ; Check whether tag2 exists, if non-existent
        wheremin = ( WHERE( spec_select EQ MIN(spec_select, /NAN) ) )[0] 
        ; Failsafe against only NaN in spec_select
        IF (wheremin NE -1) THEN $
          lc = wheremin $
        ELSE $
          lc = 0
      ENDIF ELSE BEGIN
        IF (d EQ 0) THEN lc = hdr_out.lc ELSE lc = hdr_out.reflc
      ENDELSE
    ENDELSE
    IF (lcase GE 2) THEN BEGIN
      lambda_c[d]    = line_center[(lcase EQ 3),d]
      dlambda_val[d] = line_center[1+(lcase EQ 3),d]
      dlambda_set[d] = 1
    ENDIF 
    ; Next determine whether LPS needs to be recalculated, only when in compatibility mode
    IF cube_compatibility[d] THEN BEGIN
      v_dop_set[d] = ((spectfile_set[d] EQ 1) OR (lcase GT 2))
      IF (v_dop_set[d] EQ 0) THEN lps_select -= lps_select[LONG(lc)]
      IF (lcase GE 2) THEN lps_select = lps_select*dlambda_val[d] + lambda_c[d]
      ndiagnostics = 1
      diag_width = nlp_select[d]
      diag_start = 0
    ENDIF ELSE BEGIN
      IF (d EQ 0) THEN BEGIN
        ndiagnostics = hdr_out.ndiagnostics 
        twave = hdr_out.twave
        diag_start = hdr_out.diag_start
        diag_width = hdr_out.diag_width
      ENDIF ELSE BEGIN
        ndiagnostics = hdr_out.nrefdiagnostics
        twave = hdr_out.twave_ref
        diag_start = hdr_out.refdiag_start
        diag_width = hdr_out.refdiag_width
      ENDELSE
      v_dop_set[d] = ((lps_select[LONG(lc)] NE 0) AND $
                      (N_ELEMENTS(lps_select) GT 1))
    ENDELSE
    v_dop = PTRARR(ndiagnostics)
    FOR dd=0,ndiagnostics-1 DO BEGIN
  	  IF v_dop_set[d] THEN BEGIN
        lps_select_loc = lps_select[diag_start[dd]:(diag_start[dd]+$
          (diag_width[dd]-1))]
        IF cube_compatibility[d] THEN $
          v_dop_loc = c_speed*(lps_select_loc/lps_select_loc[LONG(lc)]-1) $
        ELSE BEGIN
          ; Failsafe against not supplied TWAVE; get the middle wavelength
          ; position (as determined by diag_width)
          IF (twave[dd] EQ 0) THEN $
            lc = lps_select_loc[FLOOR(diag_width/2.)] $
          ELSE $
            lc = twave[dd]
          v_dop_loc = c_speed*(lps_select_loc/FLOAT(lc)-1)
        ENDELSE
      ENDIF ELSE BEGIN
        nlp_select_loc = diag_width[dd]
        wavearr = FINDGEN(nlp_select_loc)					
        IF (cube_compatibility[d] EQ 0) THEN BEGIN
          lc = twave[dd]
          ; Failsafe against derived data cubes where 
          IF ((lc LT 0) OR (lc GE nlp_select_loc)) THEN $
            lc = 0
        ENDIF
        v_dop_loc = wavearr - wavearr[LONG(lc)] 
      ENDELSE
      v_dop[dd] = PTR_NEW(v_dop_loc)
    ENDFOR
    IF (d EQ 0) THEN BEGIN      ; Fill hdr tags with main results
      hdr_out.lps = lps_select
      tag = 'v_dop'
    ENDIF ELSE BEGIN            ; Fill hdr tags with reference results
      hdr_out.reflps = lps_select   
      tag = 'v_dop_ref'
    ENDELSE
    wheretag2 = WHERE(TAG_NAMES(hdr_out) EQ STRUPCASE(tag2), count)
    IF (count LE 0) THEN BEGIN
      lc_sel = lc
      hdr_out = CREATE_STRUCT(hdr_out, tag, v_dop, tag2, lc_sel)
    ENDIF ELSE hdr_out = CREATE_STRUCT(hdr_out, tag, v_dop)
  ENDFOR
END

PRO CRISPEX_IO_PARSE_SINGLE_CUBE, input_single_cube, HDR_IN=hdr_in, HDR_OUT=hdr_out, $
  MAIN=main, REFERENCE=reference
  hdr_out = hdr_in
  ; Check setting of SINGLE_CUBE keyword
  IF KEYWORD_SET(MAIN) THEN BEGIN
  	IF (N_ELEMENTS(INPUT_SINGLE_CUBE) EQ 1) THEN BEGIN  ; If SINGLE_CUBE properly set, set nlp and nt
  		hdr_out.nlp = LONG(INPUT_SINGLE_CUBE)
  		hdr_out.onecube = 1
      hdr_out.single_cube[0] = hdr_out.nlp
  		hdr_out.mainnt = hdr_in.imnt / hdr_in.nlp / hdr_in.ns
  	ENDIF ELSE IF (hdr_out.spfile EQ 0) THEN BEGIN  
      ; If no SPCUBE or SINGLE_CUBE are set, we are dealing with a snapshot
  		hdr_out.nlp = hdr_in.imnt / hdr_in.ns
  		hdr_out.single_cube[0] = 0
    ENDIF
  ENDIF ELSE IF KEYWORD_SET(REFERENCE) THEN BEGIN
		IF (N_ELEMENTS(INPUT_SINGLE_CUBE) EQ 1) THEN BEGIN  ; If SINGLE_CUBE properly set, set refnlp 
			hdr_out.refnlp = LONG(INPUT_SINGLE_CUBE)
			hdr_out.onecube = 1
      hdr_out.single_cube[1] = hdr_out.refnlp
		ENDIF 
  ENDIF
END

PRO CRISPEX_IO_PARSE_SPECTFILE, spectfile, datafile, verbosity, $
      SCANFILE=scanfile, HDR_IN=hdr_in, HDR_OUT=hdr_out, $
      MNSPEC=mnspec, IMCUBE=imcube, REFCUBE=refcube, $
      CUBE_COMPATIBILITY=cube_compatibility, STARTUPTLB=startuptlb, $
      IO_FAILSAFE_ERROR=io_failsafe_error
; Handles parsing the spectral save files into the appropriate variables
  hdr_out = hdr_in
  io_failsafe_error = 0 &  calc_from_cubes = 0
  spectfile_set = 0     &  refspectfile_set = 0
  tsel_scaling = 0
  IF KEYWORD_SET(IMCUBE) THEN BEGIN
    nlp_select = hdr_out.nlp
    ns_select = hdr_out.ns
    nt_select = hdr_out.mainnt
    scaled = hdr_out.imscaled
    bscale = hdr_out.imbscale
    bzero = hdr_out.imbzero
    feedback_text = 'main '
  ENDIF 
  IF KEYWORD_SET(REFCUBE) THEN BEGIN
    nlp_select = hdr_out.refnlp
    ns_select = hdr_out.refns
    nt_select = hdr_out.refnt
    scaled = hdr_out.refimscaled
    bscale = hdr_out.refimbscale
    bzero = hdr_out.refimbzero
    feedback_text = 'reference '
  ENDIF
  IF (N_ELEMENTS(SPECTFILE) NE 0) THEN BEGIN
    IF KEYWORD_SET(CUBE_COMPATIBILITY) THEN BEGIN
      spectfile_set = KEYWORD_SET(IMCUBE)
      refspectfile_set = KEYWORD_SET(REFCUBE)
      IF (spectfile[refspectfile_set] NE '') THEN BEGIN ; Check whether SPECTFILE even has been given
  		  IF (N_ELEMENTS(MNSPEC) GT 0) THEN CRISPEX_UPDATE_STARTUP_SETUP_FEEDBACK, $
          'WARNING: Calling CRISPEX with MNSPEC, while SPECTFILE is provided, is not allowed.'+$
          ' Using SPECTFILE for mean spectrum determination.', /NO_ROUTINE
          io_failsafe_error = 2
        RESTORE, spectfile[refspectfile_set];,VERBOSE=(TOTAL(verbosity[0:1]) GE 1) 
  			IF (verbosity[1] EQ 1) THEN CRISPEX_UPDATE_STARTUP_SETUP_FEEDBACK, 'Restored '+feedback_text+$
                                           'spectral file: '+spectfile[refspectfile_set]+'.'
        IF (N_ELEMENTS(norm_factor) LT 1) THEN BEGIN   ; Failsafe against old spectfiles; convert vars
          spect_pos = ll
          norm_factor = 1/mn
          spectrum = spec * norm_factor
  				CRISPEX_UPDATE_STARTUP_SETUP_FEEDBACK, 'WARNING: The restored '+feedback_text+$
            'spectral file ('+spectfile[refspectfile_set]+$
            ') has a format pre-dating CRISPEX v1.6. If possible, please update the '+$
            feedback_text+'spectral file to the newest format. Reading spectral file in '+$
            'compatibility mode.', /NO_ROUTINE, NEWLINE=(io_failsafe_error NE 2)
          io_failsafe_error = 2
        ENDIF ELSE BEGIN                       
          ; Else, dealing with new spectfile, check title labels
  				IF (N_ELEMENTS(xtitle_label) EQ 1) THEN BEGIN                     
  					IF ((STRCOMPRESS(xtitle_label) NE '') AND $                     
                (STRCOMPRESS(hdr_out.xtitle[refspectfile_set]) EQ '')) THEN $ 
              hdr_out.xtitle[refspectfile_set] = xtitle_label
  				ENDIF
  				IF (N_ELEMENTS(ytitle_label) EQ 1) THEN BEGIN                     
  					IF ((STRCOMPRESS(ytitle_label) NE '') AND $                     
                (STRCOMPRESS(hdr_out.ytitle[refspectfile_set]) EQ '')) THEN $ 
              hdr_out.ytitle[refspectfile_set] = ytitle_label
  				ENDIF
          spectrum = norm_spect * norm_factor
        ENDELSE
        ; Failsafe against data-incompatible SPECTFILE
        IF (N_ELEMENTS(spect_pos[*,0]) NE nlp_select) THEN BEGIN  
          CRISPEX_UPDATE_STARTUP_SETUP_FEEDBACK, 'ERROR: Number of spectral positions in '+$
            feedback_text+'SPECTFILE (nlp='+STRTRIM(N_ELEMENTS(spect_pos[*,0]),2)+$
            ') is incompatible with that in the '+feedback_text+'datacubes (nlp='+$
            STRTRIM(nlp_select,2)+'). Please load the correct '+feedback_text+'spectral file.', $
            /NO_ROUTINE, NEWLINE=(io_failsafe_error NE 2)
  					IF (N_ELEMENTS(STARTUPTLB) EQ 1) THEN WIDGET_CONTROL, startuptlb, /DESTROY
            io_failsafe_error = 1
  					RETURN
        ENDIF
        IF KEYWORD_SET(IMCUBE) THEN tag = 'lps'
        IF KEYWORD_SET(REFCUBE) THEN tag = 'reflps'
        hdr_out = CREATE_STRUCT(hdr_out, tag, spect_pos)
      ENDIF ELSE calc_from_cubes = 1
    ENDIF ELSE BEGIN
      IF ((KEYWORD_SET(IMCUBE) AND (N_ELEMENTS(SPECTFILE) EQ 1)) OR $
          (KEYWORD_SET(REFCUBE) AND (N_ELEMENTS(SPECTFILE) EQ 2))) THEN $
          CRISPEX_UPDATE_STARTUP_SETUP_FEEDBACK, 'WARNING: Calling CRISPEX with SPECTFILE, while'+$
            ' FITS cubes are provided, is not allowed. Settings from SPECTFILE will be ignored.', $
            /NO_ROUTINE, NEWLINE=(io_failsafe_error NE 2)
        io_failsafe_error = 2
      calc_from_cubes = 1
    ENDELSE
  ENDIF ELSE calc_from_cubes = 1
  IF calc_from_cubes THEN BEGIN
    IF (N_ELEMENTS(MNSPEC) GE 1) THEN BEGIN                       ; If MNSPEC set
      t_lower = mnspec[0]                                         ; Set lower t-value to mnspec[0]
      IF (N_ELEMENTS(MNSPEC) EQ 1) THEN t_upper = mnspec[0] ELSE t_upper = mnspec[1]
    ENDIF ELSE BEGIN                                              ; If not MNSPEC set, default to 0
      t_lower = 0 & t_upper = 0
    ENDELSE
    hdr_out.mnspec = [t_lower,t_upper]
    spectrum = DBLARR(nlp_select,ns_select)
;    norm_spect = DBLARR(nlp_select,ns_select)
    IF ((ns_select GT 1) AND (N_ELEMENTS(scale_stokes) EQ 1)) THEN $  ; If ns>1 and scale_stokes set
      norm_factor = REPLICATE(scale_stokes,ns_select) $               ; fill norm_factor with those
    ELSE $
      norm_factor = FLTARR(ns_select)
    FOR s=0,ns_select-1 DO BEGIN        ; Loop over all "Stokes" positions
      finite_count = 0
      WHILE (finite_count EQ 0) DO BEGIN
        ; Failsafe while-loop against empty/NaN-only first image(s)
        FOR lp=0,nlp_select-1 DO BEGIN    ; Loop over all "spectral" positions
          FOR t=t_lower,t_upper DO BEGIN      ; Loop over all time steps
            tmp_data = datafile[t*nlp_select*ns_select + s*nlp_select + lp]
            IF scaled THEN $
              tmp_data = CRISPEX_SCALING_DESCALE(tmp_data, bscale, bzero)
            spectrum[lp,s] += MEAN(tmp_data, /NAN)
          ENDFOR
        ENDFOR
        spectrum[*,s] /= FLOAT(t_upper - t_lower + 1)
        wherefinite = WHERE(FINITE(spectrum[*,s]) EQ 1, finite_count)
        IF (finite_count EQ 0) THEN BEGIN
          ; If all spectrum values are NaN, go to later timestep if possible
          t_lower += 1
          t_upper += 1
          ; Failsafe against overshooting time domain
          t_lower = t_lower < (nt_select-1)
          t_upper = t_upper < (nt_select-1)
          ; Reset spectrum variable 
          spectrum[*,s] = REPLICATE(0D,nlp_select)
        ENDIF ELSE $
          tsel_scaling = t_lower
      ENDWHILE
      IF (ns_select GT 1) THEN BEGIN                                  
        IF (N_ELEMENTS(scale_stokes) NE 1) THEN BEGIN 
          ; If ns>1 & not scale_stokes, find norm_factor
          min_spectrum = MIN(spectrum[*,s], MAX=max_spectrum, /NAN)
          norm_factor[s] = (ABS([min_spectrum,max_spectrum]))[$
            ABS(max_spectrum) GE ABS(min_spectrum)]
        ENDIF
;        norm_spect[*,s] = spectrum[*,s] / norm_factor[s]              ; Determine norm_spect
      ENDIF 
    ENDFOR
    IF (ns_select EQ 1) THEN BEGIN      ; If ns=1, norm_factor and norm_spect follow easily
      norm_factor = MAX(spectrum, /NAN)
;      norm_spect = spectrum / FLOAT(norm_factor)
    ENDIF
  ENDIF
  reform_spectrum = REFORM(spectrum[*,0])
  IF KEYWORD_SET(IMCUBE) THEN BEGIN     
    ; Fill the related IMCUBE variables with results
    hdr_out = CREATE_STRUCT(hdr_out, 'mainspec', spectrum, 'spectrum', $
                reform_spectrum, 'ms', norm_factor, 'tsel_scaling_main',$
                tsel_scaling)
    wherelps = WHERE(TAG_NAMES(hdr_out) EQ 'LPS', count)
    IF (count GT 0) THEN BEGIN
      IF (TOTAL(hdr_out.lps) EQ 0) THEN hdr_out.lps = FINDGEN(hdr_out.nlp)
    ENDIF ELSE hdr_out = CREATE_STRUCT(hdr_out, 'lps', FINDGEN(hdr_out.nlp))
  ENDIF
  IF KEYWORD_SET(REFCUBE) THEN BEGIN    
    ; Fill the related REFCUBE variables with results
    hdr_out = CREATE_STRUCT(hdr_out, 'refspec', spectrum, 'refspectrum', $
                reform_spectrum, 'refms', norm_factor, 'tsel_scaling_ref',$
                tsel_scaling)
    wherereflps = WHERE(TAG_NAMES(hdr_out) EQ 'REFLPS', count) 
    IF (count GT 0) THEN BEGIN
      IF (TOTAL(hdr_out.reflps) EQ 0) THEN hdr_out.reflps = FINDGEN(hdr_out.refnlp)
    ENDIF ELSE hdr_out = CREATE_STRUCT(hdr_out, 'reflps', FINDGEN(hdr_out.refnlp))
  ENDIF
END

PRO CRISPEX_IO_PARSE_VDOP, ndiagnostics, wheredispdiag, v_dop, nlp, lps, $
  diag_start, diag_width, heightset, result, SINGLEWAV_WINDOWS=singlewav_windows
  IF ((nlp GT 1) AND ~KEYWORD_SET(SINGLEWAV_WINDOWS)) THEN BEGIN
    IF (heightset EQ 0) THEN BEGIN
      FOR d=0,ndiagnostics-1 DO BEGIN
        dd = wheredispdiag[d]
        nv_dop = N_ELEMENTS(*v_dop[dd])
        IF (d EQ 0) THEN BEGIN
          v_dop_low_min = (*v_dop[dd])[0]
          v_dop_low_max = (*v_dop[dd])[nv_dop-2]
          v_dop_upp_min = (*v_dop[dd])[1]
          v_dop_upp_max = (*v_dop[dd])[nv_dop-1]
          v_dop_incr = MAX((ABS(SHIFT(*v_dop[dd],-1)-*v_dop[dd]))[0:nv_dop-2], /NAN)
        ENDIF ELSE BEGIN
          v_dop_low_min = [v_dop_low_min, (*v_dop[dd])[0]]
          v_dop_low_max = [v_dop_low_max, (*v_dop[dd])[nv_dop-2]]
          v_dop_upp_min = [v_dop_upp_min, (*v_dop[dd])[1]]
          v_dop_upp_max = [v_dop_upp_max, (*v_dop[dd])[nv_dop-1]]
          v_dop_incr = [v_dop_incr, $
            MAX((ABS(SHIFT(*v_dop[dd],-1)-*v_dop[dd]))[0:nv_dop-2], /NAN)]
        ENDELSE   
      ENDFOR
    ENDIF ELSE BEGIN
      ; If heightset (and thus v_dop_set = 0), use lps instead
      FOR d=0,ndiagnostics-1 DO BEGIN
        dd = wheredispdiag[d]
        v_dop_tmp = lps[diag_start[dd]:diag_start[dd]+diag_width[dd]-1]
        v_dop_low_min_tmp = v_dop_tmp[0]
        v_dop_low_max_tmp = v_dop_tmp[diag_width[dd]-2]
        v_dop_upp_min_tmp = v_dop_tmp[1]
        v_dop_upp_max_tmp = v_dop_tmp[diag_width[dd]-1]
        IF (d EQ 0) THEN BEGIN
          v_dop_low_min = v_dop_low_min_tmp
          v_dop_low_max = v_dop_low_max_tmp
          v_dop_upp_min = v_dop_upp_min_tmp
          v_dop_upp_max = v_dop_upp_max_tmp
          v_dop_incr = MAX((ABS(SHIFT(v_dop_tmp,-1)-v_dop_tmp))[0:diag_width-2], /NAN)
        ENDIF ELSE BEGIN
          v_dop_low_min = [v_dop_low_min, v_dop_low_min_tmp]
          v_dop_low_max = [v_dop_low_max, v_dop_low_max_tmp]
          v_dop_upp_min = [v_dop_upp_min, v_dop_upp_min_tmp]
          v_dop_upp_max = [v_dop_upp_max, v_dop_upp_max_tmp]
          v_dop_incr = [v_dop_incr, $
            MAX((ABS(SHIFT(v_dop_tmp,-1)-v_dop_tmp))[0:diag_width-2], /NAN)]
        ENDELSE
      ENDFOR
    ENDELSE
    ; Set the overall values as first element, then add full array
    v_dop_low_min = [FLOOR(MIN(v_dop_low_min,/NAN)), v_dop_low_min]
    v_dop_low_max = [FLOOR(MIN(v_dop_low_max,/NAN)), v_dop_low_max]
    v_dop_upp_min = [CEIL(MAX(v_dop_upp_min,/NAN)), v_dop_upp_min]
    v_dop_upp_max = [CEIL(MAX(v_dop_upp_max,/NAN)), v_dop_upp_max]
    v_dop_incr = [MAX(v_dop_incr, /NAN), v_dop_incr]  ; Minimum Doppler slider increment
    IF (v_dop_low_min[0] EQ v_dop_low_max[0]) THEN $
      v_dop_low_min[0] -= v_dop_incr[0]
    IF (v_dop_upp_min[0] EQ v_dop_upp_max[0]) THEN $
      v_dop_upp_max[0] += v_dop_incr[0]
  ENDIF ELSE BEGIN
    v_dop_low_min = [0,0]
    v_dop_low_max = [1,1]
    v_dop_upp_min = [0,0]
    v_dop_upp_max = [1,1]
    v_dop_incr = [1,1]
  ENDELSE

  result = {v_dop_low_min:v_dop_low_min, v_dop_low_max:v_dop_low_max, $
    v_dop_upp_min:v_dop_upp_min, v_dop_upp_max:v_dop_upp_max, $
    v_dop_incr:v_dop_incr}
END

PRO CRISPEX_IO_PARSE_SCALING_INIT, hdr, histo_opt_val, result, $
  REFERENCE=reference, SCALE_STOKES=scale_stokes, SHOWLS=showls
  ; scalestokes?
  ; scfactor
  ; showrefls
  scfactor = 2. ; Plot-range accomodates mean ± scfactor * stdev
  IF ~KEYWORD_SET(REFERENCE) THEN BEGIN
    ns = hdr.ns
    nt = hdr.mainnt
    nlp = hdr.nlp
    lc = hdr.lc
    ms = hdr.ms
    nt_other = hdr.mainnt
    tsel_scaling = hdr.tsel_scaling_main
    data = *hdr.imdata
    ndiagnostics = hdr.ndiagnostics
    diag_start = hdr.diag_start
    diag_width = hdr.diag_width
    scaled = hdr.imscaled
    bscale = hdr.imbscale
    bzero = hdr.imbzero
  ENDIF ELSE BEGIN
    ns = hdr.refns
    nt = hdr.refnt
    nlp = hdr.refnlp
    lc = hdr.reflc
    ms = hdr.refms
    nt_other = hdr.mainnt
    tsel_scaling = hdr.tsel_scaling_ref
    data = *hdr.refdata
    ndiagnostics = hdr.nrefdiagnostics
    diag_start = hdr.refdiag_start
    diag_width = hdr.refdiag_width
    scaled = hdr.refimscaled
    bscale = hdr.refimbscale
    bzero = hdr.refimbzero
  ENDELSE
	ls_low_y = DBLARR(ns,/NOZERO)
	ls_upp_y = DBLARR(ns,/NOZERO)
  ls_yrange = DBLARR(ns,/NOZERO)
  int_low_y = FLTARR(ns,/NOZERO)
  int_upp_y = FLTARR(ns,/NOZERO)
	immin = DBLARR(nlp,ns,/NOZERO)
	immax = DBLARR(nlp,ns,/NOZERO)
	immean = DBLARR(nlp,ns,/NOZERO)
	imsdev = DBLARR(nlp,ns,/NOZERO)
  dopplermin = DBLARR(nlp,ns,/NOZERO)
  dopplermax = DBLARR(nlp,ns,/NOZERO)
  tmp_ms = ms
  FOR s=0,ns-1 DO BEGIN
		FOR lp=0,nlp-1 DO BEGIN
			temp_image = data[tsel_scaling*ns*nlp + s*nlp + lp]
      IF scaled THEN $
        temp_image = CRISPEX_SCALING_DESCALE(temp_image, bscale, bzero)
			immean[lp,s] = MEAN(temp_image, /NAN)
			temp_image = IRIS_HISTO_OPT(temp_image,histo_opt_val, $
        MISSING=-32768, /SILENT)
			imsdev[lp,s] = STDDEV(temp_image, /NAN)
			immin[lp,s] = MIN(temp_image, MAX=max_val, /NAN)
			immax[lp,s] = max_val
  		temp_lp = 2*lc - lp
  		IF ((temp_lp GE 0) AND (temp_lp LT nlp-1)) THEN BEGIN
  			mirror_temp_image = data[s*nlp + temp_lp]
        IF scaled THEN mirror_temp_image = $
          CRISPEX_SCALING_DESCALE(mirror_temp_image, bscale, bzero)
  			IF (temp_lp LT lc) THEN $
          dopplerim = temp_image - mirror_temp_image $
  			ELSE $
          dopplerim = mirror_temp_image - temp_image
  			dopplermin[lp,s] = MIN(dopplerim, MAX=max_val, /NAN)
  			dopplermax[lp,s] = max_val
      ENDIF
		ENDFOR
		IF KEYWORD_SET(SHOWLS) THEN BEGIN
			ls_low_y[s] = MIN((immean[*,s]-scfactor*imsdev[*,s])/tmp_ms[s], /NAN)
			ls_upp_y[s] = MAX((immean[*,s]+scfactor*imsdev[*,s])/tmp_ms[s], /NAN)
	    ls_yrange[s] = ls_upp_y[s] - ls_low_y[s] 
		ENDIF 
    dopplermin[lc,s] = 0.
    dopplermax[lc,s] = 0.
  	max_imsdev = MAX(imsdev[*,s], /NAN)
  	int_low_y[s] = (MEAN(immean[*,s], /NAN)-$
      scfactor*max_imsdev)/ABS(MEAN(immean[*,s], /NAN))
  	int_upp_y[s] = (MEAN(immean[*,s], /NAN)+$
      scfactor*max_imsdev)/ABS(MEAN(immean[*,s], /NAN))
  ENDFOR
  IF (ndiagnostics GT 1) THEN BEGIN
    ; Determine multiplicative factors
    mult_val = FLTARR(ndiagnostics, ns, /NOZERO)
    ls_upp_tmp = FLTARR(ndiagnostics, ns, /NOZERO)
    FOR s=0,ns-1 DO BEGIN
      FOR d=0,ndiagnostics-1 DO $
        ls_upp_tmp[d,s] = MAX((immean[diag_start[d]:$
                            (diag_start[d]+(diag_width[d]-1)),s]+$
                            scfactor*imsdev[diag_start[d]:(diag_start[d]+$
                            (diag_width[d]-1)),s])/ms[s], /NAN)
      mult_val[*,s] = ls_upp_y[s] / ls_upp_tmp[*,s]
    ENDFOR
    ; Failsafe against NaNs. Set to 1 by default.
    wherenonfinite = WHERE(FINITE(mult_val) EQ 0, count)
    IF (count GT 0) THEN $
      mult_val[wherenonfinite] = 1.
  ENDIF ELSE mult_val = REPLICATE(1.,ns)

    result = {ls_low_y:ls_low_y, ls_upp_y:ls_upp_y, ls_yrange:ls_yrange, $
      mult_val:mult_val, immin:immin, immax:immax, $
      int_low_y:int_low_y, int_upp_y:int_upp_y, $
      dopplermin:dopplermin, dopplermax:dopplermax}
END

PRO CRISPEX_IO_PARSE_WARPSLICE, hdr, NO_WARP=no_warp, WARPSPSLICE=warpspslice, $
                                XYTRI=xytri, REFERENCE=reference
; Handles warping of the slice, also given keyword NO_WARP
  feedback_text = ['main','reference']  &  warp_text = ['No warp','Warp']
  warpspslice_set = ABS(KEYWORD_SET(NO_WARP)-1) ; initial warpspslice setting
  ; Process REFERENCE keyword setting
  IF ~KEYWORD_SET(REFERENCE) THEN BEGIN
    lps = hdr.lps       &   nlp = hdr.nlp     
    ts = hdr.tarr_main  &   nt = hdr.mainnt
    ndiagnostics = hdr.ndiagnostics
    wstarts = hdr.diag_start    &   wwidths = hdr.diag_width
  ENDIF ELSE BEGIN
    lps = hdr.reflps    &   nlp = hdr.refnlp   
    ts = hdr.tarr_ref   &   nt = hdr.refnt
    ndiagnostics = hdr.nrefdiagnostics
    wstarts = hdr.refdiag_start  &   wwidths = hdr.refdiag_width
  ENDELSE
  ; Define empty output and defaults
  warpspslice = BYTARR(ndiagnostics)
  xytri = PTRARR(2, ndiagnostics, /ALLOCATE_HEAP)
  ts_equidist = 1
  ; Fill output if need be
  IF warpspslice_set THEN BEGIN
  	IF (nlp GT 1) THEN BEGIN
      FOR dd=0,ndiagnostics-1 DO BEGIN
        lps_loc = lps[wstarts[dd]:wstarts[dd]+wwidths[dd]-1]
        nlp_loc = wwidths[dd]
  		  equidist = STRING((SHIFT(DOUBLE(lps_loc),-1) - $
          DOUBLE(lps_loc))[0:nlp_loc-2], FORMAT='(F8.3)')
        IF (nt GE 2) THEN $
    		  ts_equidist = STRING((SHIFT(DOUBLE(ts),-1) - $
            DOUBLE(ts))[0:nt-2], FORMAT='(F8.3)')
        ; Check for non-equidistant spectral positions and 
        ; allowed consequential warping
  		  warpspslice[dd] = ( ((WHERE(equidist NE equidist[0]))[0] NE -1) $
                     		  OR ((WHERE(ts_equidist NE ts_equidist[0]))[0] NE -1) )
        IF warpspslice[dd] THEN BEGIN
          warp = CRISPEX_GET_WARP(lps_loc, nlp_loc, ts, nt)
          *xytri[0,dd] = warp.xtri   
          *xytri[1,dd] = warp.ytri
  		  ENDIF 
      ENDFOR
    ENDIF
    IF hdr.verbosity[1] THEN CRISPEX_UPDATE_STARTUP_SETUP_FEEDBACK, $
        warp_text[TOTAL(warpspslice) GT 0]+' applied to '+$
        feedback_text[KEYWORD_SET(REFERENCE)]+' spectral slice.', /NO_ROUTINE
  ENDIF 
END

;========================= LOOP PROCEDURES
PRO CRISPEX_LOOP_DEFINE, event
; Handles the start of loop definition procedures
	WIDGET_CONTROL, event.TOP, GET_UVALUE = info
	IF (TOTAL(((*(*info).feedbparams).verbosity)[2:3]) GE 1) THEN $
    CRISPEX_VERBOSE_GET_ROUTINE, event
	(*(*info).overlayswitch).loopslit = event.SELECT
	IF ((*(*info).overlayswitch).loopslit EQ 0) THEN BEGIN
		IF ((*(*info).winids).looptlb GT 0) THEN $
      WIDGET_CONTROL, (*(*info).winids).looptlb, /DESTROY
		*(*(*info).loopparams).xp = 0		  &	*(*(*info).loopparams).yp = 0		
    *(*(*info).overlayparams).sxp = 0.  & *(*(*info).overlayparams).syp = 0.	
    *(*(*info).loopparams).xr = 0.		  &	*(*(*info).loopparams).yr = 0.
		*(*(*info).overlayparams).sxr = 0.	&	*(*(*info).overlayparams).syr = 0.	
		*(*(*info).loopparams).xpdisp = 0	&	*(*(*info).loopparams).ypdisp = 0		
    *(*(*info).loopparams).xrdisp = 0.	&	*(*(*info).loopparams).yrdisp = 0.
		*(*(*info).loopparams).xp_ref = 0.		  &	*(*(*info).loopparams).yp_ref = 0.		
    *(*(*info).overlayparams).sxp_ref = 0.  & *(*(*info).overlayparams).syp_ref = 0.	
    *(*(*info).loopparams).xr_ref = 0.		  &	*(*(*info).loopparams).yr_ref = 0.
		*(*(*info).overlayparams).sxr_ref = 0.	&	*(*(*info).overlayparams).syr_ref = 0.	
		*(*(*info).loopparams).xpdisp_ref = 0	  &	*(*(*info).loopparams).ypdisp_ref = 0		
    *(*(*info).loopparams).xrdisp_ref = 0.	&	*(*(*info).loopparams).yrdisp_ref = 0.
    (*(*info).loopparams).np_ref = 0        & (*(*info).loopparams).np = 0
    FOR idx_sji=0,(*(*info).dataparams).nsjifiles-1 DO BEGIN
  		*(*(*info).loopparams).xp_sji[idx_sji] = 0.		  
      *(*(*info).loopparams).yp_sji[idx_sji] = 0.		
      *(*(*info).loopparams).xr_sji[idx_sji] = 0.		  
      *(*(*info).loopparams).yr_sji[idx_sji] = 0.
      (*(*info).loopparams).ngaps_sji[idx_sji] = 0  
      *(*(*info).loopparams).databounds_sji[idx_sji] = 0 
  		*(*(*info).loopparams).xpdisp_sji[idx_sji] = 0	  
      *(*(*info).loopparams).ypdisp_sji[idx_sji] = 0		
      *(*(*info).loopparams).xrdisp_sji[idx_sji] = 0.	
      *(*(*info).loopparams).yrdisp_sji[idx_sji] = 0.
      *(*(*info).overlayparams).sxp_sji[idx_sji] = 0.  
      *(*(*info).overlayparams).syp_sji[idx_sji] = 0.	
  		*(*(*info).overlayparams).sxr_sji[idx_sji] = 0.	
      *(*(*info).overlayparams).syr_sji[idx_sji] = 0.	
    ENDFOR
    (*(*info).loopparams).np_sji = 0        & (*(*info).loopsdata).sjiloopsize = 0
    (*(*info).loopsdata).loopsize = 0	    & (*(*info).loopsdata).refloopsize = 0
    (*(*info).loopparams).ngaps           = 0  
    *(*(*info).loopparams).databounds     = 0 
    (*(*info).loopparams).ngaps_ref       = 0  
    *(*(*info).loopparams).databounds_ref = 0 
    (*(*info).winids).looptlb = 0		    &	(*(*info).overlayswitch).loopslit = 0
		(*(*info).winswitch).showloop = 0
		IF (*(*info).winswitch).showrefloop THEN BEGIN
			IF ((*(*info).winids).reflooptlb GT 0) THEN $
        WIDGET_CONTROL, (*(*info).winids).reflooptlb, /DESTROY
			(*(*info).winids).reflooptlb = 0	&	(*(*info).winswitch).showrefloop = 0
		ENDIF
		IF (*(*info).winswitch).showsjiloop THEN BEGIN
			IF (TOTAL((*(*info).winids).sjilooptlb) GT 0) THEN BEGIN
        FOR idx_sji=0,(*(*info).dataparams).nsjifiles-1 DO BEGIN
          WIDGET_CONTROL, (*(*info).winids).sjilooptlb[idx_sji], /DESTROY
  			  (*(*info).winids).sjilooptlb[idx_sji] = 0	
        ENDFOR
      ENDIF
      (*(*info).winswitch).showsjiloop = 0
		ENDIF
		WIDGET_CONTROL, (*(*info).ctrlscp).loop_slice_but, SENSITIVE = 0
		WIDGET_CONTROL, (*(*info).ctrlscp).rem_loop_pt_but, SENSITIVE = 0
		WIDGET_CONTROL, (*(*info).ctrlscp).save_loop_pts, SENSITIVE = 0
		WIDGET_CONTROL, (*(*info).ctrlscp).timeslicemenu, SENSITIVE = 0
		WIDGET_CONTROL, (*(*info).ctrlscp).loop_slit_but, SET_VALUE = 'Draw path'
    CRISPEX_CURSOR_LOCKBUTTON_SET, event, /NO_DRAW
		(*(*info).curs).lockset = event.SELECT
		CRISPEX_COORDSLIDERS_SET, 1, 1, event
		CRISPEX_DRAW, event
	ENDIF
	WIDGET_CONTROL, (*(*info).ctrlscp).measure_but, SENSITIVE = ABS(event.SELECT-1)
	IF (((*(*info).feedbparams).verbosity)[3] EQ 1) THEN $
    CRISPEX_VERBOSE_GET, event, [(*(*info).overlayswitch).loopslit], $
      labels=['Draw loop path']
END

PRO CRISPEX_LOOP_FEEDBACK, event
; Loop path feedback selection procedure
	WIDGET_CONTROL, event.TOP, GET_UVALUE = info
	IF (TOTAL(((*(*info).feedbparams).verbosity)[2:3]) GE 1) THEN $
    CRISPEX_VERBOSE_GET_ROUTINE, event, /IGNORE_LAST
	(*(*info).overlayswitch).looppath_feedback = event.SELECT
	IF (((*(*info).feedbparams).verbosity)[3] EQ 1) THEN $
    CRISPEX_VERBOSE_GET, event, [(*(*info).overlayswitch).looppath_feedback], $
      labels=['Loop path feedback']
END

PRO CRISPEX_LOOP_GET, event, ADD_REMOVE=add_remove
; Gets the loop path and (if the loop display window is open) also the loopslab for display
	WIDGET_CONTROL, event.TOP, GET_UVALUE = info
	IF (TOTAL(((*(*info).feedbparams).verbosity)[2:3]) GE 1) THEN $
    CRISPEX_VERBOSE_GET_ROUTINE, event
	CRISPEX_LOOP_GET_PATH, event, ADD_REMOVE=add_remove, /MAIN, /REFERENCE, /SJI
	IF (*(*info).winswitch).showloop THEN BEGIN
		CRISPEX_LOOP_GET_SLAB, event
		CRISPEX_DISPLAYS_LOOPSLAB_REPLOT_AXES, event					
    ; If ngaps >= 1 create empty slice for display purposes
    IF ((*(*info).loopparams).ngaps GE 1) THEN $
      *(*(*info).loopsdata).empty_slice = $
        MAKE_ARRAY(N_ELEMENTS(*(*(*info).loopparams).xr), $
        (*(*info).dataparams).mainnt, $
        TYPE=SIZE(*(*(*info).data).imagedata, /TYPE))
	ENDIF
	IF (*(*info).winswitch).showrefloop THEN BEGIN
		CRISPEX_LOOP_GET_REFSLAB, event
		CRISPEX_DISPLAYS_REFLOOPSLAB_REPLOT_AXES, event					
    ; If ngaps >= 1 create empty slice for display purposes
    IF ((*(*info).loopparams).ngaps_ref GE 1) THEN $
      *(*(*info).loopsdata).empty_refslice = $
        MAKE_ARRAY(N_ELEMENTS(*(*(*info).loopparams).xr), $
        (*(*info).dataparams).refnt, $
        TYPE=SIZE(*(*(*info).data).refdata, /TYPE))
	ENDIF
	IF (*(*info).winswitch).showsjiloop THEN BEGIN
    FOR i=0,(*(*info).winswitch).nwhereshowsji-1 DO BEGIN
      idx_sji = (*(*(*info).winswitch).whereshowsji)[i]
  		CRISPEX_LOOP_GET_SJISLAB, event, IDX_SJI=idx_sji
  		CRISPEX_DISPLAYS_SJILOOPSLAB_REPLOT_AXES, event, IDX_SJI=idx_sji					
      ; If ngaps >= 1 create empty slice for display purposes
      IF ((*(*info).loopparams).ngaps_sji[idx_sji] GE 1) THEN $
        *(*(*info).loopsdata).empty_sjislice = $
          MAKE_ARRAY(N_ELEMENTS(*(*(*info).loopparams).xr), $
          (*(*info).dataparams).sjint[idx_sji], $
          TYPE=SIZE(*(*(*info).data).sjidata[idx_sji], /TYPE))
    ENDFOR
	ENDIF
END

PRO CRISPEX_LOOP_GET_PATH, event, ADD_REMOVE=add_remove, MAIN=main, $
  REFERENCE=reference, SJI=sji
; Gets the actual loop path from spline interpolation
	WIDGET_CONTROL, event.TOP, GET_UVALUE = info
	IF (TOTAL(((*(*info).feedbparams).verbosity)[2:3]) GE 1) THEN $
    CRISPEX_VERBOSE_GET_ROUTINE, event
  IF KEYWORD_SET(MAIN) THEN BEGIN
    IF KEYWORD_SET(ADD_REMOVE) THEN BEGIN
      xp = *(*(*info).loopparams).xp
      yp = *(*(*info).loopparams).yp
    ENDIF ELSE BEGIN
      xp = *(*(*info).loopparams).xpdisp
      yp = *(*(*info).loopparams).ypdisp
    ENDELSE
    np_local = N_ELEMENTS(xp)
    IF (np_local GE 2) THEN BEGIN
      ; Check for identical coordinates, ignore if so
    	IF ((xp)[np_local-1] EQ (xp)[np_local-2]) AND $
         ((yp)[np_local-1] EQ (yp)[np_local-2]) THEN RETURN
    ENDIF
    main = CRISPEX_GET_PATH(xp, yp, np_local, $
      (*(*info).dataparams).nx, (*(*info).dataparams).ny)
    xp = main.xp
    yp = main.yp
    ; Once all is set, save variables 
    ; Always adjust the temporary display path variables
    sp_result = CRISPEX_TRANSFORM_DATA2DEVICE(info, X=xp, Y=yp, /MAIN)
    sr_result = CRISPEX_TRANSFORM_DATA2DEVICE(info, X=main.xr, Y=main.yr, /MAIN)
    *(*(*info).loopparams).xpdisp = xp
    *(*(*info).loopparams).ypdisp = yp
    *(*(*info).loopparams).xrdisp = main.xr
    *(*(*info).loopparams).yrdisp = main.yr
	  *(*(*info).overlayparams).sxp = sp_result.x
	  *(*(*info).overlayparams).syp = sp_result.y
	  *(*(*info).overlayparams).sxr = sr_result.x
	  *(*(*info).overlayparams).syr = sr_result.y
    ; If changed by adding or removing a point, adjust the definitive path
    ; variables
    IF KEYWORD_SET(ADD_REMOVE) THEN BEGIN
      *(*(*info).loopparams).xp = xp
      *(*(*info).loopparams).yp = yp
      *(*(*info).loopparams).xr = main.xr
      *(*(*info).loopparams).yr = main.yr
    ENDIF
  ENDIF

  IF ((*(*info).winswitch).showref AND KEYWORD_SET(REFERENCE)) THEN BEGIN
    IF KEYWORD_SET(ADD_REMOVE) THEN BEGIN
      xp_ref = *(*(*info).loopparams).xp_ref
      yp_ref = *(*(*info).loopparams).yp_ref
    ENDIF ELSE BEGIN
      xp_ref = *(*(*info).loopparams).xpdisp_ref
      yp_ref = *(*(*info).loopparams).ypdisp_ref
    ENDELSE
	  np_ref_local = (SIZE(xp_ref))[1] 
  	IF (np_ref_local GE 2) THEN BEGIN
      ; Check for identical coordinates, ignore if so
  		IF ((xp_ref)[np_ref_local-1] EQ (xp_ref)[np_ref_local-2]) AND $
         ((yp_ref)[np_ref_local-1] EQ (yp_ref)[np_ref_local-2]) THEN RETURN
  	ENDIF
    ref = CRISPEX_GET_PATH(xp_ref, yp_ref, np_ref_local, $
      (*(*info).dataparams).refnx, (*(*info).dataparams).refny)
    xp_ref = ref.xp
    yp_ref = ref.yp
    sp_result = CRISPEX_TRANSFORM_DATA2DEVICE(info, X=xp_ref, Y=yp_ref, /REF)
    sr_result = CRISPEX_TRANSFORM_DATA2DEVICE(info, X=ref.xr, Y=ref.yr, /REF)
    *(*(*info).loopparams).xpdisp_ref = xp_ref
    *(*(*info).loopparams).ypdisp_ref = yp_ref
    *(*(*info).loopparams).xrdisp_ref = ref.xr
    *(*(*info).loopparams).yrdisp_ref = ref.yr
  	*(*(*info).overlayparams).sxp_ref = sp_result.x
  	*(*(*info).overlayparams).syp_ref = sp_result.y
  	*(*(*info).overlayparams).sxr_ref = sr_result.x
  	*(*(*info).overlayparams).syr_ref = sr_result.y
    ; If changed by adding or removing a point, adjust the definitive path
    ; variables
    IF KEYWORD_SET(ADD_REMOVE) THEN BEGIN
      *(*(*info).loopparams).xp_ref = xp_ref
      *(*(*info).loopparams).yp_ref = yp_ref
      *(*(*info).loopparams).xr_ref = ref.xr
      *(*(*info).loopparams).yr_ref = ref.yr
    ENDIF
  ENDIF

  IF ((TOTAL((*(*info).winswitch).showsji) GE 1) AND KEYWORD_SET(SJI)) THEN BEGIN
    FOR i=0,(*(*info).winswitch).nwhereshowsji-1 DO BEGIN
      idx_sji = (*(*(*info).winswitch).whereshowsji)[i]
      IF KEYWORD_SET(ADD_REMOVE) THEN BEGIN
        xp_sji = *(*(*info).loopparams).xp_sji[idx_sji]
        yp_sji = *(*(*info).loopparams).yp_sji[idx_sji]
      ENDIF ELSE BEGIN
        xp_sji = *(*(*info).loopparams).xpdisp_sji[idx_sji]
        yp_sji = *(*(*info).loopparams).ypdisp_sji[idx_sji]
      ENDELSE
  	  np_sji_local = (SIZE(xp_sji))[1] 
    	IF (np_sji_local GE 2) THEN BEGIN
        ; Check for identical coordinates, ignore if so
    		IF ((xp_sji)[np_sji_local-1] EQ (xp_sji)[np_sji_local-2]) AND $
           ((yp_sji)[np_sji_local-1] EQ (yp_sji)[np_sji_local-2]) THEN RETURN
    	ENDIF
      sji = CRISPEX_GET_PATH(xp_sji, yp_sji, np_sji_local, $
        (*(*info).dataparams).sjinx[idx_sji], (*(*info).dataparams).sjiny[idx_sji])
      xp_sji = sji.xp
      yp_sji = sji.yp
      ; Now save results
      sp_result = CRISPEX_TRANSFORM_DATA2DEVICE(info, X=xp_sji, Y=yp_sji, $
        /SJI, IDX_SJI=idx_sji)
      sr_result = CRISPEX_TRANSFORM_DATA2DEVICE(info, X=sji.xr, Y=sji.yr, $
        /SJI, IDX_SJI=idx_sji)
      *(*(*info).loopparams).xpdisp_sji[idx_sji] = xp_sji
      *(*(*info).loopparams).ypdisp_sji[idx_sji] = yp_sji
      *(*(*info).loopparams).xrdisp_sji[idx_sji] = sji.xr
      *(*(*info).loopparams).yrdisp_sji[idx_sji] = sji.yr
    	*(*(*info).overlayparams).sxp_sji[idx_sji] = sp_result.x
    	*(*(*info).overlayparams).syp_sji[idx_sji] = sp_result.y
    	*(*(*info).overlayparams).sxr_sji[idx_sji] = sr_result.x
    	*(*(*info).overlayparams).syr_sji[idx_sji] = sr_result.y
      IF KEYWORD_SET(ADD_REMOVE) THEN BEGIN
        ; If changed by adding or removing a point, adjust the definitive path 
        ; variables
        *(*(*info).loopparams).xp_sji[idx_sji] = xp_sji
        *(*(*info).loopparams).yp_sji[idx_sji] = yp_sji
        *(*(*info).loopparams).xr_sji[idx_sji] = sji.xr
        *(*(*info).loopparams).yr_sji[idx_sji] = sji.yr
      ENDIF
    ENDFOR
  ENDIF
END

PRO CRISPEX_LOOP_GET_SLAB, event
; Handles the extraction of the loopslab for display
	WIDGET_CONTROL, event.TOP, GET_UVALUE = info
	IF (TOTAL(((*(*info).feedbparams).verbosity)[2:3]) GE 1) THEN $
    CRISPEX_VERBOSE_GET_ROUTINE, event
  ; Get selected displayed xr/yr indices
	*(*(*info).loopparams).w_lpts = $
    WHERE((*(*(*info).loopparams).xr GE 0) AND $
      (*(*(*info).loopparams).xr LT ((*(*info).dataparams).nx)) AND $
      (*(*(*info).loopparams).yr GE 0) AND $
      (*(*(*info).loopparams).yr LT ((*(*info).dataparams).ny)), nw_lpts)
  (*(*info).loopparams).nw_lpts = nw_lpts
  ; Check for gaps
  IF (nw_lpts NE 0) THEN $
    result = CRISPEX_ARRAY_GET_GAP(*(*(*info).loopparams).w_lpts, $
      N_ELEMENTS(*(*(*info).loopparams).xr)) $
  ELSE $
    result = {ngaps:0, databounds:0, wdatabounds:0}
  (*(*info).loopparams).ngaps = result.ngaps
  *(*(*info).loopparams).databounds = result.databounds
  *(*(*info).loopparams).wdatabounds = result.wdatabounds
  IF ((*(*(*info).loopparams).w_lpts)[0] NE -1) THEN BEGIN
  	IF (*(*info).dispswitch).exts THEN BEGIN
  		WIDGET_CONTROL, /HOURGLASS
  		lp_orig = (*(*info).dataparams).lp
  		FOR i=(*(*info).dispparams).lp_low,(*(*info).dispparams).lp_upp DO BEGIN
  			(*(*info).dataparams).lp = i
  			CRISPEX_LOOP_GET_EXACT_SLICE, event, *(*(*info).data).imagedata, $
          *(*(*info).loopparams).xr, *(*(*info).loopparams).yr, $
          *(*(*info).loopparams).xp, *(*(*info).loopparams).yp, $
  				*(*(*info).loopparams).w_lpts, loopslice, crossloc, loopsize,/im
  			IF (i EQ (*(*info).dispparams).lp_low) THEN $
          loopslab = loopslice $
        ELSE $
          loopslab = [[[loopslab]], [[loopslice]]]
  		ENDFOR
  		(*(*info).dataparams).lp = lp_orig
  	ENDIF ELSE BEGIN
  		CRISPEX_LOOP_GET_APPROX_SLAB, event, *(*(*info).loopparams).xr, $
        *(*(*info).loopparams).yr, *(*(*info).loopparams).xp, $
        *(*(*info).loopparams).yp, *(*(*info).loopparams).w_lpts, $
        loopslab, crossloc, loopsize
  	ENDELSE
  	*(*(*info).loopsdata).loopslab = loopslab
  	*(*(*info).loopsdata).crossloc = crossloc
  ENDIF
	(*(*info).loopsdata).loopsize = N_ELEMENTS(*(*(*info).loopparams).xr) ;loopsize
	IF (((*(*info).feedbparams).verbosity)[3] EQ 1) THEN $
    CRISPEX_VERBOSE_GET, event, [N_ELEMENTS(crossloc),loopsize], $
      labels=['np','loopsize']
END

PRO CRISPEX_LOOP_GET_REFSLAB, event
; Handles the extraction of the reference loopslab for display
	WIDGET_CONTROL, event.TOP, GET_UVALUE = info
	IF (TOTAL(((*(*info).feedbparams).verbosity)[2:3]) GE 1) THEN $
    CRISPEX_VERBOSE_GET_ROUTINE, event
  ; Get selected displayed xr/yr indices
	*(*(*info).loopparams).w_lpts_ref = $
    WHERE((*(*(*info).loopparams).xr_ref GE 0) AND $
      (*(*(*info).loopparams).xr_ref LT ((*(*info).dataparams).refnx)) AND $
      (*(*(*info).loopparams).yr_ref GE 0) AND $
      (*(*(*info).loopparams).yr_ref LT ((*(*info).dataparams).refny)), $
      nw_lpts_ref)
  (*(*info).loopparams).nw_lpts_ref = nw_lpts_ref
  ; Check for gaps
  IF (nw_lpts_ref NE 0) THEN $
    result = CRISPEX_ARRAY_GET_GAP(*(*(*info).loopparams).w_lpts_ref, $
      N_ELEMENTS(*(*(*info).loopparams).xr_ref)) $
  ELSE $
    result = {ngaps:0, databounds:0, wdatabounds:0}
  (*(*info).loopparams).ngaps_ref = result.ngaps
  *(*(*info).loopparams).databounds_ref = result.databounds
  *(*(*info).loopparams).wdatabounds_ref = result.wdatabounds
  IF ((*(*(*info).loopparams).w_lpts_ref)[0] NE -1) THEN BEGIN
  	IF (*(*info).dispswitch).refexts THEN BEGIN
  		WIDGET_CONTROL, /HOURGLASS
  		lp_orig = (*(*info).dataparams).lp_ref
  		FOR i=(*(*info).dispparams).lp_ref_low,$
        (*(*info).dispparams).lp_ref_upp DO BEGIN
  			(*(*info).dataparams).lp_ref = i
  			CRISPEX_LOOP_GET_EXACT_SLICE, event, *(*(*info).data).refdata, $
          *(*(*info).loopparams).xr_ref, *(*(*info).loopparams).yr_ref, $
          *(*(*info).loopparams).xp_ref, *(*(*info).loopparams).yp_ref, $
  				*(*(*info).loopparams).w_lpts_ref, refloopslice, refcrossloc, refloopsize
  			IF (i EQ (*(*info).dispparams).lp_ref_low) THEN $
          refloopslab = refloopslice $
        ELSE $
          refloopslab = [[[refloopslab]], [[refloopslice]]]
  		ENDFOR
  		(*(*info).dataparams).lp_ref = lp_orig
  	ENDIF ELSE BEGIN
  		CRISPEX_LOOP_GET_APPROX_SLAB, event, *(*(*info).loopparams).xr_ref, $
        *(*(*info).loopparams).yr_ref, *(*(*info).loopparams).xp_ref, $
        *(*(*info).loopparams).yp_ref, *(*(*info).loopparams).w_lpts_ref, $
        refloopslab, refcrossloc, refloopsize, /REFERENCE
  	ENDELSE
  	*(*(*info).loopsdata).refloopslab = refloopslab
    *(*(*info).loopsdata).refcrossloc = refcrossloc
  ENDIF
	(*(*info).loopsdata).refloopsize = N_ELEMENTS(*(*(*info).loopparams).xr_ref)
	IF (((*(*info).feedbparams).verbosity)[3] EQ 1) THEN $
    CRISPEX_VERBOSE_GET, event, [N_ELEMENTS(refcrossloc),refloopsize], $
      labels=['np','loopsize']
END

PRO CRISPEX_LOOP_GET_SJISLAB, event, IDX_SJI=idx_sji
; Handles the extraction of the slit-jaw loopslab for display
	WIDGET_CONTROL, event.TOP, GET_UVALUE = info
	IF (TOTAL(((*(*info).feedbparams).verbosity)[2:3]) GE 1) THEN $
    CRISPEX_VERBOSE_GET_ROUTINE, event
  IF (N_ELEMENTS(IDX_SJI) LT 1) THEN idx_sji = 0
  ; Get selected displayed xr/yr indices
	*(*(*info).loopparams).w_lpts_sji[idx_sji] = $
    WHERE((*(*(*info).loopparams).xr_sji[idx_sji] GE 0) AND $
      (*(*(*info).loopparams).xr_sji[idx_sji] LT $
      ((*(*info).dataparams).sjinx[idx_sji])) AND $
      (*(*(*info).loopparams).yr_sji[idx_sji] GE 0) AND $
      (*(*(*info).loopparams).yr_sji[idx_sji] LT $
      ((*(*info).dataparams).sjiny[idx_sji])), $
      nw_lpts_sji)
  (*(*info).loopparams).nw_lpts_sji[idx_sji] = nw_lpts_sji
  ; Check for gaps
  IF (nw_lpts_sji NE 0) THEN $
    result = CRISPEX_ARRAY_GET_GAP(*(*(*info).loopparams).w_lpts_sji[idx_sji], $
      N_ELEMENTS(*(*(*info).loopparams).xr_sji[idx_sji])) $
  ELSE $
    result = {ngaps:0, databounds:0, wdatabounds:0}
  (*(*info).loopparams).ngaps_sji[idx_sji] = result.ngaps
  *(*(*info).loopparams).databounds_sji[idx_sji] = result.databounds
  *(*(*info).loopparams).wdatabounds_sji[idx_sji] = result.wdatabounds
  IF ((*(*(*info).loopparams).w_lpts_sji[idx_sji])[0] NE -1) THEN BEGIN
    WIDGET_CONTROL, /HOURGLASS
    	CRISPEX_LOOP_GET_EXACT_SLICE, event, *(*(*info).data).sjidata[idx_sji], $
        *(*(*info).loopparams).xr_sji[idx_sji], $
        *(*(*info).loopparams).yr_sji[idx_sji], $
        *(*(*info).loopparams).xp_sji[idx_sji], $
        *(*(*info).loopparams).yp_sji[idx_sji], $
    		*(*(*info).loopparams).w_lpts_sji[idx_sji], sjiloopslice, sjicrossloc, $
        sjiloopsize, /SJI, IDX_SJI=idx_sji
    *(*(*info).loopsdata).sjiloopslice[idx_sji] = sjiloopslice
    *(*(*info).loopsdata).sjicrossloc[idx_sji] = sjicrossloc
  ENDIF
	(*(*info).loopsdata).sjiloopsize[idx_sji] = $
    N_ELEMENTS(*(*(*info).loopparams).xr_sji[idx_sji])
	IF (((*(*info).feedbparams).verbosity)[3] EQ 1) THEN $
    CRISPEX_VERBOSE_GET, event, [N_ELEMENTS(sjicrossloc),sjiloopsize], $
      labels=['np','loopsize']
END

PRO CRISPEX_LOOP_GET_APPROX_SLAB, event, xrs, yrs, xps, yps, w_lpts, ap_loopslab, $
  ap_crossloc, ap_loopsize, REFERENCE=reference
; Gets the approximated loopslab for in-pragram display
	WIDGET_CONTROL, event.TOP, GET_UVALUE = info
	IF (TOTAL(((*(*info).feedbparams).verbosity)[2:3]) GE 1) THEN $
    CRISPEX_VERBOSE_GET_ROUTINE, event
	IF KEYWORD_SET(REFERENCE) THEN BEGIN
    scaled = (*(*info).dispswitch).refimscaled
    bscale = (*(*info).dispparams).refimbscale
    bzero  = (*(*info).dispparams).refimbzero
		FOR i=0,(SIZE(xrs[w_lpts]))[1]-1 DO BEGIN
			IF (i EQ 0) THEN $
        tmp = ((*(*(*info).data).refspdata)[LONG(yrs[w_lpts[i]]) * $
          (*(*info).dataparams).refnx * (*(*info).dataparams).refns + $
          LONG(xrs[w_lpts[i]]) * (*(*info).dataparams).refns + $
          (*(*info).dataparams).s_ref]) $
      ELSE $
				tmp = [ [[tmp]] , [[ ((*(*(*info).data).refspdata)[LONG(yrs[w_lpts[i]]) * $
          (*(*info).dataparams).refnx * (*(*info).dataparams).refns + $
          LONG(xrs[w_lpts[i]]) * (*(*info).dataparams).refns + $
          (*(*info).dataparams).s_ref]) ]] ] 
		ENDFOR
	ENDIF ELSE BEGIN
    scaled = (*(*info).dispswitch).imscaled
    bscale = (*(*info).dispparams).imbscale
    bzero  = (*(*info).dispparams).imbzero
		FOR i=0,(SIZE(xrs[w_lpts]))[1]-1 DO BEGIN
			IF (i EQ 0) THEN BEGIN
				tmp = ((*(*(*info).data).spdata)[LONG(yrs[w_lpts[i]]) * $
          (*(*info).dataparams).nx * (*(*info).dataparams).ns + $
          LONG(xrs[w_lpts[i]])* (*(*info).dataparams).ns + (*(*info).dataparams).s])
			ENDIF ELSE BEGIN
				tmp = [[[tmp]],[[((*(*(*info).data).spdata)[LONG(yrs[w_lpts[i]]) * $
          (*(*info).dataparams).nx * (*(*info).dataparams).ns + $
          LONG(xrs[w_lpts[i]])* (*(*info).dataparams).ns + (*(*info).dataparams).s])]]]
			ENDELSE
		ENDFOR
	ENDELSE
  IF scaled THEN tmp = CRISPEX_SCALING_DESCALE(tmp, bscale, bzero)
  IF (SIZE(tmp,/N_DIMENSIONS) EQ 3) THEN $
	  ap_loopslab = TRANSPOSE(tmp, [2,1,0]) $
  ELSE BEGIN
    ap_loopslab = MAKE_ARRAY(1, (SIZE(tmp))[2], (SIZE(tmp))[1], $
      TYPE=(SIZE(tmp, /TYPE))) 
    ap_loopslab[0,*,*] = TRANSPOSE(tmp, [1,0])
  ENDELSE
	n = 1 + (ABS(((SIZE(xps))[0] EQ 1)-1))
	FOR k=0,(SIZE(xps))[n]-1 DO BEGIN
		IF (k EQ 0) THEN $
      ap_crossloc = [0] $
    ELSE $
      ap_crossloc = [ap_crossloc,WHERE((xrs EQ (xps[k])) AND (yrs EQ (yps[k])))]
	ENDFOR
	ap_loopsize = (SIZE(ap_loopslab))[1]
END

PRO CRISPEX_LOOP_GET_EXACT_SLICE, event, extractdata, xrs, yrs, xps, yps, $
  w_lpts, ex_loopslice, ex_crossloc, ex_loopsize, NO_NLP=no_nlp, IM=im, $
  SJI=sji, IDX_SJI=idx_sji
; Gets the exact loopslice for in-program display
	WIDGET_CONTROL, event.TOP, GET_UVALUE = info			
	IF (TOTAL(((*(*info).feedbparams).verbosity)[2:3]) GE 1) THEN $
    CRISPEX_VERBOSE_GET_ROUTINE, event
  tlow = 0
  IF KEYWORD_SET(IM) THEN BEGIN
    tupp = (*(*info).dataparams).mainnt-1 
    scaled = (*(*info).dispswitch).imscaled
    bscale = (*(*info).dispparams).imbscale
    bzero  = (*(*info).dispparams).imbzero
  ENDIF ELSE IF KEYWORD_SET(SJI) THEN BEGIN
    scaled = (*(*info).dispswitch).sjiscaled[idx_sji]
    bscale = (*(*info).dispparams).sjibscale[idx_sji]
    bzero  = (*(*info).dispparams).sjibzero[idx_sji]
    tupp = (*(*info).dataparams).sjint[idx_sji]-1 
  ENDIF ELSE BEGIN
    scaled = (*(*info).dispswitch).refimscaled
    bscale = (*(*info).dispparams).refimbscale
    bzero  = (*(*info).dispparams).refimbzero
    tupp = (*(*info).dataparams).refnt-1
  ENDELSE
	IF KEYWORD_SET(NO_NLP) THEN BEGIN
		FOR tt=tlow,tupp DO BEGIN
			IF (tt EQ tlow) THEN $
        tmp = INTERPOLATE( extractdata[tt], (xrs)[w_lpts],(yrs)[w_lpts]) $
      ELSE $
        tmp = [[tmp], [INTERPOLATE( extractdata[tt], (xrs)[w_lpts], $
          (yrs)[w_lpts])]]
		ENDFOR
	ENDIF ELSE BEGIN
		IF KEYWORD_SET(IM) THEN BEGIN		; Get space-time diagram from main cube
			FOR tt=tlow,tupp DO BEGIN
				IF (tt EQ tlow) THEN $
          tmp = INTERPOLATE( extractdata[$
            tt * (*(*info).dataparams).nlp * (*(*info).dataparams).ns+$
            (*(*info).dataparams).s * (*(*info).dataparams).nlp + $
            (*(*info).dataparams).lp], (xrs)[w_lpts],(yrs)[w_lpts])  $
        ELSE $
					tmp = [[tmp], [INTERPOLATE( extractdata[$
            tt * (*(*info).dataparams).nlp * (*(*info).dataparams).ns + $
            (*(*info).dataparams).s * (*(*info).dataparams).nlp + $
            (*(*info).dataparams).lp], (xrs)[w_lpts],(yrs)[w_lpts])]] 
			ENDFOR
    ENDIF ELSE IF KEYWORD_SET(SJI) THEN BEGIN ; Get space-time diagram from SJI
			FOR tt=tlow,tupp DO BEGIN
        extractdata_tmp = extractdata[tt]
        IF (*(*info).dispswitch).sjiscaled[idx_sji] THEN $
          extractdata_tmp = CRISPEX_SCALING_DESCALE(extractdata_tmp, $
          (*(*info).dispparams).sjibscale[idx_sji], $
          (*(*info).dispparams).sjibzero[idx_sji])
				IF (tt EQ tlow) THEN $
          tmp = INTERPOLATE( extractdata_tmp, (xrs)[w_lpts],(yrs)[w_lpts]) $
        ELSE $
					tmp = [[tmp], $
            [INTERPOLATE( extractdata_tmp, (xrs)[w_lpts],(yrs)[w_lpts])]]
			ENDFOR
		ENDIF ELSE BEGIN			; Get space-time diagram from reference cube
			FOR tt=tlow,tupp DO BEGIN
				IF (tt EQ tlow) THEN $
          tmp = INTERPOLATE( extractdata[$
            tt * (*(*info).dataparams).refnlp * (*(*info).dataparams).refns + $
            (*(*info).dataparams).s_ref * (*(*info).dataparams).refnlp + $
            (*(*info).dataparams).lp_ref], $
            (xrs)[w_lpts],(yrs)[w_lpts]) $
        ELSE $
					tmp = [[tmp], [INTERPOLATE( extractdata[$
            tt * (*(*info).dataparams).refnlp * (*(*info).dataparams).refns + $
            (*(*info).dataparams).s_ref * (*(*info).dataparams).refnlp + $
            (*(*info).dataparams).lp_ref], $
            (xrs)[w_lpts],(yrs)[w_lpts])]]
			ENDFOR
		ENDELSE
	ENDELSE
  IF scaled THEN tmp = CRISPEX_SCALING_DESCALE(tmp, bscale, bzero)
	ex_loopslice = tmp
	n = 1 + (ABS(((SIZE(xps))[0] EQ 1)-1))
	FOR k=0,(SIZE(xps))[n]-1 DO BEGIN
		IF (k EQ 0) THEN $
      ex_crossloc = [0] $
    ELSE $
      ex_crossloc = [ex_crossloc,WHERE( (xrs EQ (xps)[k]) AND (yrs EQ (yps)[k]))]
	ENDFOR
	ex_loopsize = (SIZE(ex_loopslice))[1]
END

PRO CRISPEX_LOOP_REMOVE_POINT, event, CURSOR_ACTION=cursor_action
; Handles the removal of a loop point
	WIDGET_CONTROL, event.TOP, GET_UVALUE = info
	IF (TOTAL(((*(*info).feedbparams).verbosity)[2:3]) GE 1) THEN $
    CRISPEX_VERBOSE_GET_ROUTINE, event
  IF ~KEYWORD_SET(CURSOR_ACTION) THEN BEGIN
  	(*(*info).loopparams).np -= 1
  	IF (*(*info).winswitch).showref THEN (*(*info).loopparams).np_ref -= 1
  	IF (TOTAL((*(*info).winswitch).showsji) GE 1) THEN $
      (*(*info).loopparams).np_sji -= 1
  ENDIF
	IF (((*(*info).feedbparams).verbosity)[3] EQ 1) THEN $
    CRISPEX_VERBOSE_GET, event, [(*(*info).loopparams).np], labels=['np']
  ; Reset main data and device coordinate points
	*(*(*info).loopparams).xp = $
    (*(*(*info).loopparams).xp)[0:(*(*info).loopparams).np-1]
	*(*(*info).loopparams).yp = $
    (*(*(*info).loopparams).yp)[0:(*(*info).loopparams).np-1]
	*(*(*info).loopparams).xpdisp = *(*(*info).loopparams).xp
	*(*(*info).loopparams).ypdisp = *(*(*info).loopparams).yp
  ; Reset xy-coordinates
  (*(*info).dataparams).x = $
    (*(*(*info).loopparams).xpdisp)[(*(*info).loopparams).np-1]
  (*(*info).dataparams).y = $
    (*(*(*info).loopparams).ypdisp)[(*(*info).loopparams).np-1]
  ; Check whether main coordinates are out of range
  (*(*info).dispswitch).xy_out_of_range = $
    (((*(*info).dataparams).x LT 0) OR ((*(*info).dataparams).y LT 0) OR $
     ((*(*info).dataparams).x GE (*(*info).dataparams).nx) OR $
     ((*(*info).dataparams).y GE (*(*info).dataparams).ny))
  ; Reset reference data and device coordinate points
  IF (*(*info).winswitch).showref THEN BEGIN
   	*(*(*info).loopparams).xp_ref = $
       (*(*(*info).loopparams).xp_ref)[0:(*(*info).loopparams).np_ref-1]
   	*(*(*info).loopparams).yp_ref = $
       (*(*(*info).loopparams).yp_ref)[0:(*(*info).loopparams).np_ref-1]
   	*(*(*info).loopparams).xpdisp_ref = *(*(*info).loopparams).xp_ref
   	*(*(*info).loopparams).ypdisp_ref = *(*(*info).loopparams).yp_ref
     ; Reset xy-coordinates
     (*(*info).dataparams).xref = $
       (*(*(*info).loopparams).xpdisp_ref)[(*(*info).loopparams).np_ref-1]
     (*(*info).dataparams).yref = $
       (*(*(*info).loopparams).ypdisp_ref)[(*(*info).loopparams).np_ref-1]
  ENDIF
  ; Check whether reference coordinates are out of range
  IF (*(*info).dataswitch).reffile THEN $
    (*(*info).dispswitch).xyref_out_of_range = $
      (((*(*info).dataparams).xref LT 0) OR ((*(*info).dataparams).yref LT 0) OR $
       ((*(*info).dataparams).xref GE (*(*info).dataparams).refnx) OR $
       ((*(*info).dataparams).yref GE (*(*info).dataparams).refny))
  ; Reset SJI data and device coordinate points
  IF (TOTAL((*(*info).winswitch).showsji) GE 1) THEN BEGIN
    FOR i=0,(*(*info).winswitch).nwhereshowsji-1 DO BEGIN
      idx_sji = (*(*(*info).winswitch).whereshowsji)[i]
     	*(*(*info).loopparams).xp_sji[idx_sji] = $
         (*(*(*info).loopparams).xp_sji[idx_sji])[0:(*(*info).loopparams).np_sji-1]
     	*(*(*info).loopparams).yp_sji[idx_sji] = $
         (*(*(*info).loopparams).yp_sji[idx_sji])[0:(*(*info).loopparams).np_sji-1]
     	*(*(*info).loopparams).xpdisp_sji[idx_sji] = $
        *(*(*info).loopparams).xp_sji[idx_sji]
     	*(*(*info).loopparams).ypdisp_sji[idx_sji] = $
        *(*(*info).loopparams).yp_sji[idx_sji]
       ; Reset xy-coordinates
       (*(*info).dataparams).xsji[idx_sji] = $
         (*(*(*info).loopparams).xpdisp_sji[idx_sji])[(*(*info).loopparams).np_sji-1]
       (*(*info).dataparams).ysji[idx_sji] = $
         (*(*(*info).loopparams).ypdisp_sji[idx_sji])[(*(*info).loopparams).np_sji-1]
     ; Check whether SJI coordinates are out of range
     (*(*info).dispswitch).xysji_out_of_range[idx_sji] = $
       (((*(*info).dataparams).xsji[idx_sji] LT 0) OR $
        ((*(*info).dataparams).ysji[idx_sji] LT 0) OR $
        ((*(*info).dataparams).xsji[idx_sji] GE $
        (*(*info).dataparams).sjinx[idx_sji]) OR $
        ((*(*info).dataparams).ysji[idx_sji] GE $
        (*(*info).dataparams).sjiny[idx_sji]))
    ENDFOR
  ENDIF
  ; Action if routine called by CURSOR
  IF KEYWORD_SET(CURSOR_ACTION) THEN BEGIN
    IF ((*(*info).loopparams).np GE 2) THEN $
      CRISPEX_LOOP_GET_PATH, event, /MAIN, /REFERENCE, /SJI $
    ELSE BEGIN
    	*(*(*info).loopparams).xr = (*(*(*info).loopparams).xp)[0]
    	*(*(*info).loopparams).yr = (*(*(*info).loopparams).yp)[0]
    	*(*(*info).loopparams).xrdisp = *(*(*info).loopparams).xr
    	*(*(*info).loopparams).yrdisp = *(*(*info).loopparams).yr
      IF (*(*info).winswitch).showref THEN BEGIN
    		*(*(*info).loopparams).xr_ref = (*(*(*info).loopparams).xp_ref)[0]
    		*(*(*info).loopparams).yr_ref = (*(*(*info).loopparams).yp_ref)[0]
      	*(*(*info).loopparams).xrdisp_ref = *(*(*info).loopparams).xr_ref
      	*(*(*info).loopparams).yrdisp_ref = *(*(*info).loopparams).yr_ref
      ENDIF
      IF (TOTAL((*(*info).winswitch).showsji) GE 1) THEN BEGIN
        FOR i=0,(*(*info).winswitch).nwhereshowsji-1 DO BEGIN
          idx_sji = (*(*(*info).winswitch).whereshowsji)[i]
      		*(*(*info).loopparams).xr_sji[idx_sji] = $
            (*(*(*info).loopparams).xp_sji[idx_sji])[0]
      		*(*(*info).loopparams).yr_sji[idx_sji] = $
            (*(*(*info).loopparams).yp_sji[idx_sji])[0]
        	*(*(*info).loopparams).xrdisp_sji[idx_sji] = $
            *(*(*info).loopparams).xr_sji[idx_sji]
        	*(*(*info).loopparams).yrdisp_sji[idx_sji] = $
            *(*(*info).loopparams).yr_sji[idx_sji]
        ENDFOR
      ENDIF
    ENDELSE
  ENDIF ELSE BEGIN
    ; Make buttons insensitive if necessary
  	IF ((*(*info).loopparams).np EQ 2) THEN $
      WIDGET_CONTROL, (*(*info).ctrlscp).rem_loop_pt_but, SENSITIVE = 0
  	IF ((*(*info).loopparams).np LT 2) THEN $
      WIDGET_CONTROL, (*(*info).ctrlscp).loop_slice_but, SENSITIVE = 0
    CRISPEX_LOOP_GET, event, /ADD_REMOVE
    CRISPEX_UPDATE_LP, event
  	IF ((*(*info).zooming).factor NE 1) THEN CRISPEX_ZOOM_LOOP, event
  ENDELSE
  ; Reset coordinate sliders
	CRISPEX_COORDSLIDERS_SET, 1, 1, event
  CRISPEX_UPDATE_SX, event
  CRISPEX_UPDATE_SY, event
  ; Update display data and Redraw windows as necessary 
  IF (*(*info).winswitch).showls THEN CRISPEX_UPDATE_SSP, event
  IF (*(*info).winswitch).showsp THEN CRISPEX_UPDATE_SPSLICE, event
  IF (*(*info).winswitch).showrefls THEN CRISPEX_UPDATE_REFSSP, event
  IF (*(*info).winswitch).showrefsp THEN CRISPEX_UPDATE_REFSPSLICE, event
	IF (*(*info).winswitch).showphis THEN BEGIN
		CRISPEX_PHISLIT_DIRECTION, event
    CRISPEX_UPDATE_PHISLIT_COORDS, event
		CRISPEX_UPDATE_PHISLICE, event
	ENDIF ELSE CRISPEX_DRAW, event
END

;========================= MASK PROCEDURES
PRO CRISPEX_MASK_OVERLAY_COLOR_SLIDER, event
; Handles the change mask overlay window
	WIDGET_CONTROL, event.TOP, GET_UVALUE = info
	IF (TOTAL(((*(*info).feedbparams).verbosity)[2:3]) GE 1) THEN $
    CRISPEX_VERBOSE_GET_ROUTINE, event
	(*(*info).overlayparams).maskcolor = event.VALUE
	CRISPEX_DRAW, event
END

PRO CRISPEX_MASK_OVERLAY_SELECT_COLOR_TABLE, event
; Handles the change mask overlay window
	WIDGET_CONTROL, event.TOP, GET_UVALUE = info
	IF (TOTAL(((*(*info).feedbparams).verbosity)[2:3]) GE 1) THEN $
    CRISPEX_VERBOSE_GET_ROUTINE, event
	(*(*info).overlayparams).maskct = event.index
	CRISPEX_DRAW, event
END

PRO CRISPEX_MASK_BUTTONS_SET, event
; Handles the setting of mask buttons
	WIDGET_CONTROL, event.TOP, GET_UVALUE = info
	IF (TOTAL(((*(*info).feedbparams).verbosity)[2:3]) GE 1) THEN $
    CRISPEX_VERBOSE_GET_ROUTINE, event
	WIDGET_CONTROL,((*(*info).ctrlscp).mask_button_ids)[0], $
    SET_BUTTON=((*(*info).overlayswitch).maskim)[0], $
    SENSITIVE=(*(*info).overlayswitch).mask
	WIDGET_CONTROL,((*(*info).ctrlscp).mask_button_ids)[1],$
    SET_BUTTON=((*(*info).overlayswitch).maskim)[1], $
    SENSITIVE=((*(*info).overlayswitch).mask AND (*(*info).dataswitch).reffile)
	WIDGET_CONTROL,((*(*info).ctrlscp).mask_button_ids)[2],$
    SET_BUTTON=((*(*info).overlayswitch).maskim)[2], $
    SENSITIVE=((*(*info).overlayswitch).mask AND (*(*info).winswitch).showdop)
END

;========================= MASTER TIME PROCEDURE
PRO CRISPEX_MASTER_TIME_SJI_SELECT, event
; Handles the change SJI to be master time
	WIDGET_CONTROL, event.TOP, GET_UVALUE = info
	IF (TOTAL(((*(*info).feedbparams).verbosity)[2:3]) GE 1) THEN $
    CRISPEX_VERBOSE_GET_ROUTINE, event, /IGNORE_LAST
  ; First get old arrays
  t_old = (*(*(*info).dispparams).tarr_sji[(*(*info).dispswitch).sji_select])[$
            (*(*info).dispparams).t]
  nt_old = (*(*info).dataparams).sjint[(*(*info).dispswitch).sji_select]
  ; Now get new SJI select index
  (*(*info).dispswitch).sji_select = event.INDEX
  CRISPEX_COORDS_TRANSFORM_T, event, T_OLD=t_old, NT_OLD=nt_old
  CRISPEX_MASTER_TIME_UPDATE_CONTROLS, event, NO_DRAW=no_draw
END

PRO CRISPEX_MASTER_TIME_UPDATE_CONTROLS, event, NO_DRAW=no_draw
; Handles the change SJI to be master time
	WIDGET_CONTROL, event.TOP, GET_UVALUE = info
	IF (TOTAL(((*(*info).feedbparams).verbosity)[2:3]) GE 1) THEN $
    CRISPEX_VERBOSE_GET_ROUTINE, event, /IGNORE_LAST
  CRISPEX_UPDATE_T, event
  IF ~KEYWORD_SET(NO_DRAW) THEN BEGIN
    IF (*(*info).winswitch).showsp THEN CRISPEX_DISPLAYS_SP_REPLOT_AXES, event
    IF (*(*info).winswitch).showrefsp THEN $
      CRISPEX_DISPLAYS_REFSP_REPLOT_AXES, event
  	CRISPEX_DRAW, event
  ENDIF
  WIDGET_CONTROL, (*(*info).ctrlscp).master_time_sjicbox, $
    SENSITIVE=(((*(*info).dispparams).master_time EQ 2) AND $
    ((*(*info).dataparams).nsjifiles GT 1))
  WIDGET_CONTROL, (*(*info).ctrlscp).t_slider, $
    SET_SLIDER_MIN=(*(*info).dispparams).t_low, $
    SET_SLIDER_MAX=((*(*info).dispparams).t_upp<(*(*info).dataparams).nt)
END


;========================= MEASUREMENT PROCEDURES
PRO CRISPEX_MEASURE_DX, event
; Handles the change of arcseconds per pixel resolution
	WIDGET_CONTROL, event.TOP, GET_UVALUE = info
	IF (TOTAL(((*(*info).feedbparams).verbosity)[2:3]) GE 1) THEN $
    CRISPEX_VERBOSE_GET_ROUTINE, event, /IGNORE_LAST
	WIDGET_CONTROL, (*(*info).ctrlscp).dx_text, GET_VALUE = textvalue
	(*(*info).dataparams).dx = FLOAT(textvalue[0])
	IF ((*(*info).meas).np GT 0) THEN CRISPEX_MEASURE_CALC, event
	IF (((*(*info).feedbparams).verbosity)[3] EQ 1) THEN $
    CRISPEX_VERBOSE_GET, event, [(*(*info).dataparams).dx], labels=['dx']
END

PRO CRISPEX_MEASURE_DY, event
; Handles the change of arcseconds per pixel resolution
	WIDGET_CONTROL, event.TOP, GET_UVALUE = info
	IF (TOTAL(((*(*info).feedbparams).verbosity)[2:3]) GE 1) THEN $
    CRISPEX_VERBOSE_GET_ROUTINE, event, /IGNORE_LAST
	WIDGET_CONTROL, (*(*info).ctrlscp).dy_text, GET_VALUE = textvalue
	(*(*info).dataparams).dy = FLOAT(textvalue[0])
	IF ((*(*info).meas).np GT 0) THEN CRISPEX_MEASURE_CALC, event
	IF (((*(*info).feedbparams).verbosity)[3] EQ 1) THEN $
    CRISPEX_VERBOSE_GET, event, [(*(*info).dataparams).dy], labels=['dy']
END

PRO CRISPEX_MEASURE_ENABLE, event, DISABLE=disable
; Enables the spatial measurement tool
	WIDGET_CONTROL, event.TOP, GET_UVALUE = info
	IF (TOTAL(((*(*info).feedbparams).verbosity)[2:3]) GE 1) THEN $
    CRISPEX_VERBOSE_GET_ROUTINE, event, /IGNORE_LAST
	IF KEYWORD_SET(DISABLE) THEN $
    (*(*info).meas).spatial_measurement = 0 $
  ELSE $
    (*(*info).meas).spatial_measurement = event.SELECT
  WIDGET_CONTROL, (*(*info).ctrlscp).measure_but, $
    SET_BUTTON=(*(*info).meas).spatial_measurement
	WIDGET_CONTROL, (*(*info).ctrlscp).apix_label, $
    SENSITIVE=(*(*info).meas).spatial_measurement
	WIDGET_CONTROL, (*(*info).ctrlscp).dx_text, $
    SENSITIVE=(*(*info).meas).spatial_measurement
	WIDGET_CONTROL, (*(*info).ctrlscp).x_label, $
    SENSITIVE=(*(*info).meas).spatial_measurement
	WIDGET_CONTROL, (*(*info).ctrlscp).dy_text, $
    SENSITIVE=(*(*info).meas).spatial_measurement
	WIDGET_CONTROL, (*(*info).ctrlscp).apix_unit, $
    SENSITIVE=(*(*info).meas).spatial_measurement
	WIDGET_CONTROL, (*(*info).ctrlscp).measure_asec_lab, $
    SENSITIVE=(*(*info).meas).spatial_measurement
	WIDGET_CONTROL, (*(*info).ctrlscp).measure_asec_text, $
    SENSITIVE=(*(*info).meas).spatial_measurement
	WIDGET_CONTROL, (*(*info).ctrlscp).measure_km_lab, $
    SENSITIVE=(*(*info).meas).spatial_measurement
	WIDGET_CONTROL, (*(*info).ctrlscp).measure_km_text, $
    SENSITIVE=(*(*info).meas).spatial_measurement
	IF (((*(*info).feedbparams).verbosity)[3] EQ 1) THEN $
    CRISPEX_VERBOSE_GET, event, [(*(*info).meas).spatial_measurement], $
      labels=['Enabled measurement']
	IF ((*(*info).meas).spatial_measurement EQ 0) THEN BEGIN
		(*(*info).meas).np = 0
		*(*(*info).meas).xp = 0
		*(*(*info).meas).yp = 0
		*(*(*info).meas).sxp = 0
		*(*(*info).meas).syp = 0
    IF (*(*info).winswitch).showref THEN BEGIN
  		*(*(*info).meas).xp_ref = 0
  		*(*(*info).meas).yp_ref = 0
  		*(*(*info).meas).sxp_ref = 0
  		*(*(*info).meas).syp_ref = 0
    ENDIF
    IF (TOTAL((*(*info).winswitch).showsji) GE 1) THEN BEGIN
      FOR i=0,(*(*info).winswitch).nwhereshowsji-1 DO BEGIN
        idx_sji = (*(*(*info).winswitch).whereshowsji)[i]
    		*(*(*info).meas).xp_sji[idx_sji] = 0
    		*(*(*info).meas).yp_sji[idx_sji] = 0
    		*(*(*info).meas).sxp_sji[idx_sji] = 0
    		*(*(*info).meas).syp_sji[idx_sji] = 0
      ENDFOR
    ENDIF
		WIDGET_CONTROL, (*(*info).ctrlscp).measure_asec_text, SET_VALUE = '0'
		WIDGET_CONTROL, (*(*info).ctrlscp).measure_km_text, SET_VALUE = '0'
    IF (*(*info).curs).lockset THEN BEGIN
      (*(*info).dataparams).x = (*(*info).curs).xlock
      (*(*info).dataparams).y = (*(*info).curs).ylock
      CRISPEX_COORDS_TRANSFORM_XY, event, $
        MAIN2SJI=(TOTAL((*(*info).winids).sjitlb) NE 0), $
        MAIN2REF=(((*(*info).winids).reftlb NE 0) AND $
          ((*(*info).winids).current_wid EQ (*(*info).winids).xydrawid)),$
        REF2MAIN=(((*(*info).winids).reftlb NE 0) AND $
          ((*(*info).winids).current_wid EQ (*(*info).winids).refdrawid)),$
        REF2SJI=(((*(*info).winids).reftlb NE 0) AND $
          (TOTAL((*(*info).winids).sjitlb) NE 0) AND $
          ((*(*info).winids).current_wid EQ (*(*info).winids).refdrawid))
      CRISPEX_UPDATE_SX, event
      CRISPEX_UPDATE_SY, event
    ENDIF
		(*(*info).curs).lockset = (*(*info).meas).spatial_measurement
    CRISPEX_CURSOR_LOCKBUTTON_SET, event
		CRISPEX_COORDSLIDERS_SET, 1, 1, event
		IF ~KEYWORD_SET(DISABLE) THEN CRISPEX_DRAW, event
	ENDIF
	WIDGET_CONTROL, (*(*info).ctrlscp).loop_slit_but, $
    SENSITIVE=ABS((*(*info).meas).spatial_measurement-1)
	WIDGET_CONTROL, (*(*info).ctrlscp).loop_feedb_but, $
    SENSITIVE=ABS((*(*info).meas).spatial_measurement-1)
END

PRO CRISPEX_MEASURE_CALC, event
; Computes the actual distance from the measurement line length and resolution
	WIDGET_CONTROL, event.TOP, GET_UVALUE = info
	IF (TOTAL(((*(*info).feedbparams).verbosity)[2:3]) GE 1) THEN $
    CRISPEX_VERBOSE_GET_ROUTINE, event
  au = 149697870. 
	delta_x = FLOAT((*(*(*info).meas).xp)[1]-(*(*(*info).meas).xp)[0]) * (*(*info).dataparams).dx
	delta_y = FLOAT((*(*(*info).meas).yp)[1]-(*(*(*info).meas).yp)[0]) * (*(*info).dataparams).dy
  ; Check whether dx/dy units are arcsec or (c/k/M)m
  IF (STRCMP((*(*info).dataparams).xunit,'arcsec') OR $
      STRCMP((*(*info).dataparams).xunit,'asec')) THEN BEGIN
  	delta_asec = SQRT(delta_x^2 + delta_y^2)
  	delta_km = au * TAN(delta_asec / 3600. * !DTOR)
  ENDIF ELSE BEGIN
    IF STRCMP((*(*info).dataparams).xunit,'m') THEN fact = 1E3 ELSE $
      IF STRCMP((*(*info).dataparams).xunit,'cm') THEN fact = 1E5 ELSE $
      IF STRCMP((*(*info).dataparams).xunit,'km') THEN fact = 1 ELSE $
      IF STRCMP((*(*info).dataparams).xunit,'Mm') THEN fact = 1E-3 
    delta_km = SQRT(delta_x^2 + delta_y^2) / fact
    delta_asec = ATAN(delta_km / au) / !DTOR * 3600.
  ENDELSE
	WIDGET_CONTROL, (*(*info).ctrlscp).measure_asec_text, SET_VALUE = STRTRIM(delta_asec,2)
	WIDGET_CONTROL, (*(*info).ctrlscp).measure_km_text, SET_VALUE = STRTRIM(delta_km,2)
	IF (((*(*info).feedbparams).verbosity)[3] EQ 1) THEN $
    CRISPEX_VERBOSE_GET, event, [delta_asec,delta_km], labels=['Arcseconds','Kilometers']
END

;========================= PLAYBACK PROCEDURES
PRO CRISPEX_PB_BG, event
; Handles the actual playback, given the mode of playback
	WIDGET_CONTROL, event.TOP, GET_UVALUE = info
	IF (TOTAL(((*(*info).feedbparams).verbosity)[2:3]) GE 1) THEN $
    CRISPEX_VERBOSE_GET_ROUTINE, event
	CASE (*(*info).pbparams).mode OF
		'PAUSE'	: BEGIN
				IF (*(*info).pbparams).spmode THEN BEGIN
          IF ((*(*info).dataparams).lp NE (*(*info).pbparams).lp_blink) THEN $
            (*(*info).dataparams).lp = (*(*info).pbparams).lp_blink $
          ELSE $
            (*(*info).dataparams).lp = (*(*info).pbparams).lp_blink_init
          (*(*info).intparams).lp_diag_all = $
            TOTAL((*(*info).dataparams).lp GE (*(*info).intparams).diag_start)-1
			  ENDIF ELSE IF (*(*info).pbparams).imrefmode THEN BEGIN
					(*(*info).winids).imrefdisp = ABS((*(*info).winids).imrefdisp-1)
				ENDIF ELSE RETURN
				WIDGET_CONTROL,(*(*info).ctrlscp).lp_slider, SET_VALUE = (*(*info).dataparams).lp
			  END
		'PLAY'	: BEGIN
				IF ((*(*info).feedbparams).count_pbstats EQ 0) THEN (*(*info).feedbparams).pbstats = SYSTIME(/SECONDS)
				(*(*info).dispparams).t += (*(*info).pbparams).direction * (*(*info).pbparams).t_step
				IF (*(*info).pbparams).spmode THEN BEGIN
          IF ((*(*info).dataparams).lp NE (*(*info).pbparams).lp_blink) THEN $
            (*(*info).dataparams).lp = (*(*info).pbparams).lp_blink $
          ELSE $
            (*(*info).dataparams).lp = (*(*info).pbparams).lp_blink_init
          (*(*info).intparams).lp_diag_all = $
            TOTAL((*(*info).dataparams).lp GE (*(*info).intparams).diag_start)-1
					WIDGET_CONTROL,(*(*info).ctrlscp).lp_slider, SET_VALUE = (*(*info).dataparams).lp
			  ENDIF ELSE IF (*(*info).pbparams).imrefmode THEN BEGIN
					(*(*info).winids).imrefdisp = ABS((*(*info).winids).imrefdisp-1)
				ENDIF
				CASE (*(*info).pbparams).lmode OF
					'LOOP'	: BEGIN
							IF (*(*info).dispparams).t GT (*(*info).dispparams).t_upp THEN (*(*info).dispparams).t -= (*(*info).dispparams).t_range
							IF (*(*info).dispparams).t LT (*(*info).dispparams).t_low THEN (*(*info).dispparams).t += (*(*info).dispparams).t_range
						  END
					'CYCLE'	: BEGIN
							IF (*(*info).dispparams).t GT (*(*info).dispparams).t_upp THEN BEGIN
								(*(*info).pbparams).direction = -1
								(*(*info).dispparams).t = (*(*info).dispparams).t_upp - ((*(*info).dispparams).t MOD (*(*info).dispparams).t_upp)
							ENDIF ELSE IF (*(*info).dispparams).t LT (*(*info).dispparams).t_low THEN BEGIN
								(*(*info).pbparams).direction = 1
								IF ((*(*info).dispparams).t_low EQ (*(*info).dispparams).t_first) THEN (*(*info).dispparams).t *= -1 ELSE $
									(*(*info).dispparams).t = -1 * ((*(*info).dispparams).t - (*(*info).dispparams).t_low) + (*(*info).dispparams).t_low
							ENDIF
							IF ((*(*info).pbparams).direction GT 0) THEN $
                CRISPEX_PB_BUTTONS_SET, event, /FWD_SET, /NO_PB_TYPE $
              ELSE $
                CRISPEX_PB_BUTTONS_SET, event, /BWD_SET, /NO_PB_TYPE
						  END
					'BLINK'	: BEGIN
							(*(*info).pbparams).direction *= -1
							IF (*(*info).dispparams).t GT (*(*info).dispparams).t_upp THEN (*(*info).dispparams).t -=(*(*info).dispparams).t_range ELSE $
								IF (*(*info).dispparams).t LT (*(*info).dispparams).t_low THEN (*(*info).dispparams).t += (*(*info).dispparams).t_range
							IF ((*(*info).pbparams).direction GT 0) THEN $
                CRISPEX_PB_BUTTONS_SET, event, /FWD_SET, /NO_PB_TYPE $
              ELSE $
                CRISPEX_PB_BUTTONS_SET, event, /BWD_SET, /NO_PB_TYPE
						  END
				ENDCASE
			  END
	ENDCASE
	WIDGET_CONTROL, (*(*info).ctrlscp).t_slider, SET_VALUE = (*(*info).dispparams).t
	WIDGET_CONTROL, (*(*info).pbparams).bg, TIMER = 1. / (*(*info).pbparams).t_speed
	IF (((*(*info).feedbparams).verbosity)[3] EQ 1) THEN $
    CRISPEX_VERBOSE_GET, event, [(*(*info).pbparams).mode,(*(*info).pbparams).lmode,STRTRIM((*(*info).dispparams).t,2),STRTRIM((*(*info).pbparams).direction,2),$
		STRTRIM((*(*info).pbparams).spmode,2),STRTRIM((*(*info).dataparams).lp,2),STRTRIM((*(*info).pbparams).spdirection,2)], $
		labels=['Play mode','Loop mode','t','Play direction','Spectral blink mode','lp','Blink direction']
	CRISPEX_UPDATE_T, event
	IF (*(*info).pbparams).spmode THEN CRISPEX_UPDATE_LP, event
	IF (*(*info).dispparams).phislice_update THEN $
    CRISPEX_UPDATE_SLICES, event, /NO_DRAW, $
      NO_PHIS=((*(*info).winswitch).showphis EQ 0), $
      SSP_UPDATE=(((*(*info).dataswitch).spfile EQ 0) AND $
                  (*(*info).winswitch).showls AND $
                  ((*(*info).pbparams).spmode EQ 0)), $
      REFSSP_UPDATE=((((*(*info).dataswitch).reffile EQ 1) AND $ 
                      ((*(*info).dataswitch).refspfile EQ 0)) AND $
                      (*(*info).winswitch).showrefls AND $
                      ((*(*info).pbparams).spmode EQ 0))
	CRISPEX_DRAW, event, $
    LS_NO_MAIN=(((*(*info).dataswitch).spfile EQ 0) AND $
                ((*(*info).pbparams).spmode EQ 0)), $
    LS_NO_REF=((*(*info).dataswitch).refspfile EQ 0), $
    NO_REF=(*(*info).pbparams).spmode, NO_SJI=(*(*info).pbparams).spmode
	IF (((*(*info).feedbparams).verbosity)[4] EQ 1) THEN BEGIN
		(*(*info).feedbparams).count_pbstats += 1
		newtime = SYSTIME(/SECONDS)
		timediff = newtime-(*(*info).feedbparams).pbstats
		(*(*(*info).feedbparams).sum_pbstats)[(*(*info).feedbparams).count_pbstats MOD 10] = timediff
		(*(*info).feedbparams).av_pbstats = (((*(*info).feedbparams).av_pbstats)*((*(*info).feedbparams).count_pbstats-1) + timediff)/FLOAT((*(*info).feedbparams).count_pbstats)
		(*(*info).feedbparams).pbstats = newtime
		IF ((*(*info).feedbparams).count_pbstats GE 10) THEN $
      average = STRING(MEAN(*(*(*info).feedbparams).sum_pbstats, /NAN),FORMAT='(F6.4)')+' s' $
    ELSE $
      average = 'N/A'
		CRISPEX_UPDATE_USER_FEEDBACK, event, title='CRISPEX DEBUGGING: Playback statistics', var=((*(*info).feedbparams).count_pbstats+(*(*info).winids).feedbacktlb), minvar=1, /close_button, $
			feedback_text='Time elapsed since last update: '+STRING(timediff,FORMAT='(F6.4)')+' s, average (over last 10): '+average+', (over last '+$
			STRING((*(*info).feedbparams).count_pbstats,FORMAT='(I'+STRTRIM(FLOOR(ALOG10((*(*info).feedbparams).count_pbstats))+1,2)+')')+'): '+STRING((*(*info).feedbparams).av_pbstats,FORMAT='(F6.4)')+' s'
	ENDIF
END

PRO CRISPEX_PB_BUTTONS_SET, event, FBWD_SET=fbwd_set, BWD_SET=bwd_set, PAUSE_SET=pause_set, $
  FWD_SET=fwd_set, FFWD_SET=ffwd_set, LOOP_SET=loop_set, CYCLE_SET=cycle_set, BLINK_SET=blink_set, $
  NO_PB_TYPE=no_pb_type, NO_PB_DIR=no_pb_dir, SENSITIVE_SET=sensitive_set
; Sets playback buttons according to actions
	WIDGET_CONTROL, event.TOP, GET_UVALUE = info
	IF (TOTAL(((*(*info).feedbparams).verbosity)[2:3]) GE 1) THEN $
    CRISPEX_VERBOSE_GET_ROUTINE, event
  IF ~KEYWORD_SET(NO_PB_TYPE) THEN BEGIN
		IF KEYWORD_SET(LOOP_SET) THEN $
      WIDGET_CONTROL, (*(*info).ctrlscp).loop_button, $
        SET_VALUE=(*(*info).ctrlspbbut).loop_pressed, /SET_BUTTON, SENSITIVE=sensitive_set $
    ELSE $
			WIDGET_CONTROL, (*(*info).ctrlscp).loop_button, SET_VALUE=(*(*info).ctrlspbbut).loop_idle, $
        SENSITIVE=sensitive_set
		IF KEYWORD_SET(CYCLE_SET) THEN $
      WIDGET_CONTROL, (*(*info).ctrlscp).cycle_button, $
        SET_VALUE=(*(*info).ctrlspbbut).cycle_pressed, /SET_BUTTON, SENSITIVE=sensitive_set $
    ELSE $
			WIDGET_CONTROL, (*(*info).ctrlscp).cycle_button, SET_VALUE=(*(*info).ctrlspbbut).cycle_idle, $
        SENSITIVE=sensitive_set
		IF KEYWORD_SET(BLINK_SET) THEN $
      WIDGET_CONTROL, (*(*info).ctrlscp).blink_button, $
        SET_VALUE=(*(*info).ctrlspbbut).blink_pressed, /SET_BUTTON, SENSITIVE=sensitive_set $
    ELSE $
			WIDGET_CONTROL, (*(*info).ctrlscp).blink_button, SET_VALUE=(*(*info).ctrlspbbut).blink_idle, $
        SENSITIVE=sensitive_set
	ENDIF 
  IF ~KEYWORD_SET(NO_PB_DIR) THEN BEGIN
		IF KEYWORD_SET(FBWD_SET) THEN $
      WIDGET_CONTROL, (*(*info).ctrlscp).fbwd_button, SET_VALUE=(*(*info).ctrlspbbut).fbwd_pressed,$
        SENSITIVE=sensitive_set $
    ELSE $
			WIDGET_CONTROL, (*(*info).ctrlscp).fbwd_button, SET_VALUE=(*(*info).ctrlspbbut).fbwd_idle, $
        SENSITIVE=sensitive_set
		IF KEYWORD_SET(BWD_SET) THEN $
      WIDGET_CONTROL, (*(*info).ctrlscp).bwd_button, SET_VALUE=(*(*info).ctrlspbbut).bwd_pressed, $
        SENSITIVE=sensitive_set $
    ELSE $
			WIDGET_CONTROL, (*(*info).ctrlscp).bwd_button, SET_VALUE=(*(*info).ctrlspbbut).bwd_idle, $
        SENSITIVE=sensitive_set
		IF KEYWORD_SET(PAUSE_SET) THEN $
      WIDGET_CONTROL, (*(*info).ctrlscp).pause_button, $
        SET_VALUE=(*(*info).ctrlspbbut).pause_pressed, SENSITIVE=sensitive_set $
    ELSE $
			WIDGET_CONTROL, (*(*info).ctrlscp).pause_button, SET_VALUE=(*(*info).ctrlspbbut).pause_idle, $
        SENSITIVE=sensitive_set
		IF KEYWORD_SET(FWD_SET) THEN $
      WIDGET_CONTROL, (*(*info).ctrlscp).fwd_button, SET_VALUE=(*(*info).ctrlspbbut).fwd_pressed, $
        SENSITIVE=sensitive_set $
    ELSE $
			WIDGET_CONTROL, (*(*info).ctrlscp).fwd_button, SET_VALUE=(*(*info).ctrlspbbut).fwd_idle, $
        SENSITIVE=sensitive_set
		IF KEYWORD_SET(FFWD_SET) $
      THEN WIDGET_CONTROL, (*(*info).ctrlscp).ffwd_button, $
        SET_VALUE=(*(*info).ctrlspbbut).ffwd_pressed, SENSITIVE=sensitive_set $
    ELSE $
			WIDGET_CONTROL, (*(*info).ctrlscp).ffwd_button, SET_VALUE=(*(*info).ctrlspbbut).ffwd_idle, $
        SENSITIVE=sensitive_set
  ENDIF
END

PRO CRISPEX_PB_BACKWARD, event
; Sets the playback mode to backward play
	WIDGET_CONTROL, event.TOP, GET_UVALUE = info
	IF (TOTAL(((*(*info).feedbparams).verbosity)[2:3]) GE 1) THEN $
    CRISPEX_VERBOSE_GET_ROUTINE, event
	IF (*(*info).pbparams).mode EQ 'PLAY' AND (*(*info).pbparams).direction EQ -1 THEN RETURN
	(*(*info).pbparams).direction = -1			&	(*(*info).pbparams).mode = 'PLAY'
	WIDGET_CONTROL, (*(*info).pbparams).bg, TIMER = 0.0
	CRISPEX_PB_BUTTONS_SET, event, /BWD_SET, /NO_PB_TYPE
	IF (((*(*info).feedbparams).verbosity)[3] EQ 1) THEN $
    CRISPEX_VERBOSE_GET, event, [(*(*info).pbparams).mode,STRTRIM((*(*info).pbparams).direction,2)], labels=['Play mode','Play direction']
END

PRO CRISPEX_PB_FORWARD, event
; Sets the playback mode to forward play
	WIDGET_CONTROL, event.TOP, GET_UVALUE = info
	IF (TOTAL(((*(*info).feedbparams).verbosity)[2:3]) GE 1) THEN $
    CRISPEX_VERBOSE_GET_ROUTINE, event
	IF (*(*info).pbparams).mode EQ 'PLAY' AND (*(*info).pbparams).direction EQ 1 THEN RETURN
	(*(*info).pbparams).direction = 1			&	(*(*info).pbparams).mode = 'PLAY'
	WIDGET_CONTROL, (*(*info).pbparams).bg, TIMER = 0.0
	CRISPEX_PB_BUTTONS_SET, event, /FWD_SET, /NO_PB_TYPE
	IF (((*(*info).feedbparams).verbosity)[3] EQ 1) THEN $
    CRISPEX_VERBOSE_GET, event, [(*(*info).pbparams).mode,STRTRIM((*(*info).pbparams).direction,2)], labels=['Play mode','Play direction']
END

PRO CRISPEX_PB_FASTBACKWARD, event
; Sets the playback mode to single step backward
	WIDGET_CONTROL, event.TOP, GET_UVALUE = info
	IF (TOTAL(((*(*info).feedbparams).verbosity)[2:3]) GE 1) THEN $
    CRISPEX_VERBOSE_GET_ROUTINE, event
	IF (*(*info).pbparams).mode EQ 'PAUSE' OR (*(*info).pbparams).lmode EQ 'BLINK' THEN BEGIN
		CRISPEX_PB_BUTTONS_SET, event, /FBWD_SET, /NO_PB_TYPE
		(*(*info).dispparams).t -= (*(*info).pbparams).t_step
		IF ((*(*info).dispparams).t LT (*(*info).dispparams).t_low) THEN (*(*info).dispparams).t = (*(*info).dispparams).t_upp
		CRISPEX_UPDATE_T, event
		WIDGET_CONTROL, (*(*info).ctrlscp).t_slider, SET_VALUE = (*(*info).dispparams).t
		CRISPEX_UPDATE_SLICES, event, $
		  SSP_UPDATE=(((*(*info).dataswitch).spfile EQ 0) AND $
                    (*(*info).winswitch).showls), $
      REFSSP_UPDATE=(((*(*info).dataswitch).reffile EQ 1) AND $
                     ((*(*info).dataswitch).refspfile EQ 0) AND $
                      (*(*info).winswitch).showrefls), $
      /NO_DRAW, NO_PHIS=((*(*info).winswitch).showphis EQ 0)
		CRISPEX_DRAW, event
		CRISPEX_PB_BUTTONS_SET, event, /PAUSE_SET, /NO_PB_TYPE
	ENDIF
	IF (((*(*info).feedbparams).verbosity)[3] EQ 1) THEN $
    CRISPEX_VERBOSE_GET, event, [(*(*info).pbparams).mode,(*(*info).pbparams).lmode,STRTRIM((*(*info).dispparams).t,2)], labels=['Play mode','Loop mode','t']
END

PRO CRISPEX_PB_FASTFORWARD, event
; Sets the playback mode to single step forward
	WIDGET_CONTROL, event.TOP, GET_UVALUE = info
	IF (TOTAL(((*(*info).feedbparams).verbosity)[2:3]) GE 1) THEN $
    CRISPEX_VERBOSE_GET_ROUTINE, event
	IF (*(*info).pbparams).mode EQ 'PAUSE' OR (*(*info).pbparams).lmode EQ 'BLINK' THEN BEGIN
		CRISPEX_PB_BUTTONS_SET, event, /FFWD_SET, /NO_PB_TYPE
		(*(*info).dispparams).t = (((*(*info).dispparams).t - (*(*info).dispparams).t_low + (*(*info).pbparams).t_step) MOD ((*(*info).dispparams).t_upp - (*(*info).dispparams).t_low + 1)) + (*(*info).dispparams).t_low
		CRISPEX_UPDATE_T, event
		WIDGET_CONTROL, (*(*info).ctrlscp).t_slider, SET_VALUE = (*(*info).dispparams).t
		CRISPEX_UPDATE_SLICES, event, $
		  SSP_UPDATE=(((*(*info).dataswitch).spfile EQ 0) AND $
                    (*(*info).winswitch).showls), $
      REFSSP_UPDATE=(((*(*info).dataswitch).reffile EQ 1) AND $
                     ((*(*info).dataswitch).refspfile EQ 0) AND $
                      (*(*info).winswitch).showrefls), $
      /NO_DRAW , NO_PHIS=((*(*info).winswitch).showphis EQ 0)
		CRISPEX_DRAW, event
		CRISPEX_PB_BUTTONS_SET, event, /PAUSE_SET, /NO_PB_TYPE
	ENDIF
	IF (((*(*info).feedbparams).verbosity)[3] EQ 1) THEN $
    CRISPEX_VERBOSE_GET, event, [(*(*info).pbparams).mode,(*(*info).pbparams).lmode,STRTRIM((*(*info).dispparams).t,2)], labels=['Play mode','Loop mode','t']
END

PRO CRISPEX_PB_PAUSE, event
; Sets the playback mode pause
	WIDGET_CONTROL, event.TOP, GET_UVALUE = info
	IF (TOTAL(((*(*info).feedbparams).verbosity)[2:3]) GE 1) THEN $
    CRISPEX_VERBOSE_GET_ROUTINE, event
	IF (*(*info).pbparams).mode EQ 'PAUSE' THEN RETURN
	(*(*info).pbparams).mode = 'PAUSE'
	IF ((*(*info).winids).feedbacktlb NE 0) THEN BEGIN
		(*(*info).feedbparams).count_pbstats = 0
		WIDGET_CONTROL, (*(*info).ctrlsfeedb).close_button, /SENSITIVE
	ENDIF
	IF (((*(*info).feedbparams).verbosity)[3] EQ 1) THEN $
    CRISPEX_VERBOSE_GET, event, [(*(*info).pbparams).mode,(*(*info).pbparams).lmode,STRTRIM((*(*info).dispparams).t,2)], labels=['Play mode','Loop mode','t']
	CRISPEX_PB_BUTTONS_SET, event, /PAUSE_SET, /NO_PB_TYPE
  CRISPEX_UPDATE_SLICES, event, $
	  SSP_UPDATE=(((*(*info).dataswitch).spfile EQ 0) AND $
                  (*(*info).winswitch).showls), $
    REFSSP_UPDATE=(((*(*info).dataswitch).reffile EQ 1) AND $
                   ((*(*info).dataswitch).refspfile EQ 0) AND $
                    (*(*info).winswitch).showrefls), $
    /LS_DRAW, /REFLS_DRAW, NO_PHIS=((*(*info).winswitch).showphis EQ 0)
END

PRO CRISPEX_PB_BLINK, event
; Sets the playback mode to temporal blink
	WIDGET_CONTROL, event.TOP, GET_UVALUE = info
	IF (TOTAL(((*(*info).feedbparams).verbosity)[2:3]) GE 1) THEN $
    CRISPEX_VERBOSE_GET_ROUTINE, event
	(*(*info).pbparams).lmode = 'BLINK'
	IF (((*(*info).feedbparams).verbosity)[3] EQ 1) THEN $
    CRISPEX_VERBOSE_GET, event, [(*(*info).pbparams).mode,(*(*info).pbparams).lmode,STRTRIM((*(*info).dispparams).t,2)], labels=['Play mode','Loop mode','t']
	CRISPEX_PB_BUTTONS_SET, event, /BLINK_SET, /NO_PB_DIR
END

PRO CRISPEX_PB_CYCLE, event
; Sets the playback mode to cycle
	WIDGET_CONTROL, event.TOP, GET_UVALUE = info
	IF (TOTAL(((*(*info).feedbparams).verbosity)[2:3]) GE 1) THEN $
    CRISPEX_VERBOSE_GET_ROUTINE, event
	(*(*info).pbparams).lmode = 'CYCLE'
	IF (((*(*info).feedbparams).verbosity)[3] EQ 1) THEN $
    CRISPEX_VERBOSE_GET, event, [(*(*info).pbparams).mode,(*(*info).pbparams).lmode,STRTRIM((*(*info).dispparams).t,2)], labels=['Play mode','Loop mode','t']
	CRISPEX_PB_BUTTONS_SET, event, /CYCLE_SET, /NO_PB_DIR
END

PRO CRISPEX_PB_LOOP, event
; Sets the playback mode to loop
	WIDGET_CONTROL, event.TOP, GET_UVALUE = info
	IF (TOTAL(((*(*info).feedbparams).verbosity)[2:3]) GE 1) THEN $
    CRISPEX_VERBOSE_GET_ROUTINE, event
	(*(*info).pbparams).lmode = 'LOOP'
	IF (((*(*info).feedbparams).verbosity)[3] EQ 1) THEN $
    CRISPEX_VERBOSE_GET, event, [(*(*info).pbparams).mode,(*(*info).pbparams).lmode,STRTRIM((*(*info).dispparams).t,2)], labels=['Play mode','Loop mode','t']
	CRISPEX_PB_BUTTONS_SET, event, /LOOP_SET, /NO_PB_DIR
END

PRO CRISPEX_PB_SPECTBLINK, event
; Sets the playback mode to spectral blink
	WIDGET_CONTROL, event.TOP, GET_UVALUE = info
	IF (TOTAL(((*(*info).feedbparams).verbosity)[2:3]) GE 1) THEN $
    CRISPEX_VERBOSE_GET_ROUTINE, event
	(*(*info).pbparams).spmode = event.SELECT
	WIDGET_CONTROL, (*(*info).ctrlscp).imref_blink_but, SENSITIVE=ABS((*(*info).pbparams).spmode-1)
	IF (*(*info).pbparams).spmode THEN BEGIN
		(*(*info).pbparams).spdirection = 1
    (*(*info).pbparams).lp_blink_init = (*(*info).dataparams).lp
		IF ((*(*info).feedbparams).count_pbstats EQ 0) THEN (*(*info).feedbparams).pbstats = SYSTIME(/SECONDS)
		WIDGET_CONTROL, (*(*info).pbparams).bg, TIMER = 0.0
	ENDIF ELSE BEGIN
    WIDGET_CONTROL, (*(*info).ctrlscp).lp_blink_but, $
      SENSITIVE=((*(*info).pbparams).lp_blink NE (*(*info).dataparams).lp)
		IF ((*(*info).winids).feedbacktlb NE 0) THEN BEGIN
			(*(*info).feedbparams).count_pbstats = 0
			WIDGET_CONTROL, (*(*info).ctrlsfeedb).close_button, /SENSITIVE
		ENDIF
	ENDELSE
	IF (((*(*info).feedbparams).verbosity)[3] EQ 1) THEN $
    CRISPEX_VERBOSE_GET, event, [(*(*info).pbparams).spmode,(*(*info).pbparams).spdirection], labels=['Spectral blink mode','Blink direction']
END

;========================= SPECTRAL PHI SLIT PROCEDURES
PRO CRISPEX_PHISLIT_DIRECTION, event
; Determines the direction of the spectral phi slit
	WIDGET_CONTROL, event.TOP, GET_UVALUE = info
	IF (TOTAL(((*(*info).feedbparams).verbosity)[2:3]) GE 1) THEN $
    CRISPEX_VERBOSE_GET_ROUTINE, event
	x_maxpts = COS(!DTOR * (*(*info).phiparams).angle) * $
    (FINDGEN( 2 * (*(*info).phiparams).nphi/2) - $
    (*(*info).phiparams).nphi/2) + FIX((*(*info).dataparams).x)
	y_maxpts = SIN(!DTOR * (*(*info).phiparams).angle) * $
    (FINDGEN( 2 * (*(*info).phiparams).nphi/2) - $
    (*(*info).phiparams).nphi/2) + FIX((*(*info).dataparams).y)
	wmax = WHERE( (x_maxpts GE 0 ) AND $
                (x_maxpts LE (*(*info).dispparams).x_last) AND $
                (y_maxpts GE 0) AND $
                (y_maxpts LE (*(*info).dispparams).y_last), nwmax)
  IF (nwmax GT 0) THEN BEGIN
  	thex = REBIN(x_maxpts[wmax], nwmax, 2)
  	they = REBIN(y_maxpts[wmax], nwmax, 2)
  	thep = REBIN(FINDGEN(1,2), nwmax, 2)
  	*(*(*info).data).indices = INTERPOLATE( *(*(*info).data).indexmap, $
      thex, they, thep)
  	search = WHERE($
      ((*(*(*info).data).indices)[*,0] EQ FIX((*(*info).dataparams).x)) AND $
      ((*(*(*info).data).indices)[*,1] EQ FIX((*(*info).dataparams).y)))
  	(*(*info).phiparams).curindex = search[0]
  	(*(*info).phiparams).maxindex = (SIZE(wmax))[1]
  ENDIF
	IF (((*(*info).feedbparams).verbosity)[3] EQ 1) THEN $
    CRISPEX_VERBOSE_GET, event, [(*(*info).dataparams).x,$
      (*(*info).dataparams).y,(*(*info).phiparams).curindex,$
      (*(*info).phiparams).maxindex], $
		labels=['x','y','current index', 'maximum index']
END

;========================= PREFERENCES ROUTINES
PRO CRISPEX_PREFERENCES_WINDOW, event
; Opens up the preferences window
	WIDGET_CONTROL, event.TOP, GET_UVALUE = info
	IF (TOTAL(((*(*info).feedbparams).verbosity)[2:3]) GE 1) THEN $
    CRISPEX_VERBOSE_GET_ROUTINE, event
	base 		= WIDGET_BASE(TITLE = 'CRISPEX'+(*(*info).sesparams).instance_label+$
    ': Preferences', GROUP_LEADER = (*(*info).winids).root, TLB_FRAME_ATTR = 1, $
    /TLB_KILL_REQUEST_EVENTS)
	main		= WIDGET_BASE(base, /COLUMN)
  tab_width = 432
  pad = 3
  tab_tlb = WIDGET_TAB(main, LOCATION=0, MULTILINE=3, XSIZE=tab_width+2*pad)
 
  ; Start-up preferences
  startup_base   = WIDGET_BASE(tab_tlb, TITLE='Start-up & Playback', /COLUMN, XSIZE=tab_width);, /FRAME)
	startup_buts 	= WIDGET_BASE(startup_base, /COLUMN, /NONEXCLUSIVE)
	(*(*info).ctrlspref).startup_win = $
                  WIDGET_BUTTON(startup_buts, VALUE = 'Show start-up window', $
                    EVENT_PRO='CRISPEX_PREFERENCES_SET_STARTUPWIN')
	(*(*info).ctrlspref).startup_autopl	= $
                  WIDGET_BUTTON(startup_buts, $
                  VALUE='Start playing automatically upon start-up', $
                  EVENT_PRO='CRISPEX_PREFERENCES_SET_AUTOPLAY')
  startup_divider= CRISPEX_WIDGET_DIVIDER(startup_base)
	playback_buts 	= WIDGET_BASE(startup_base, /COLUMN, /NONEXCLUSIVE)
	(*(*info).ctrlspref).displays_phislice = $
                    WIDGET_BUTTON(playback_buts, $
                      VALUE='Automatically update spectrum along slit '+$
                      '(may impact performance)', $
                      EVENT_PRO='CRISPEX_PREFERENCES_SET_PHISLICE_UPDATE')
  ; Set buttons according to preferences	
  WIDGET_CONTROL, (*(*info).ctrlspref).startup_win, SET_BUTTON=(*(*info).prefs).startupwin
	WIDGET_CONTROL, (*(*info).ctrlspref).startup_autopl, SET_BUTTON=(*(*info).prefs).autoplay
	WIDGET_CONTROL, (*(*info).ctrlspref).displays_phislice, $
    SET_BUTTON=(*(*info).dispparams).phislice_update

  ; Displays preferences
	layout_base   	= WIDGET_BASE(tab_tlb, TITLE='Layout', /COLUMN, XSIZE=tab_width);, /FRAME)
	displays_buts 	= WIDGET_BASE(layout_base, /GRID_LAYOUT, COLUMN=3)
	(*(*info).prefs).bgplotcol_old = (*(*info).plotparams).bgplotcol
	(*(*info).ctrlspref).displays_bgcols = $
                    WIDGET_SLIDER(displays_buts, TITLE='Background color', $
                      MIN=0, MAX=255, VALUE=(*(*info).plotparams).bgplotcol, /DRAG, $
		                  EVENT_PRO='CRISPEX_PREFERENCES_SET_BGPLOTCOL', $
                      XSIZE=FLOOR((tab_width-3*pad)/3.))
	(*(*info).ctrlspref).displays_plcols = $
                    WIDGET_SLIDER(displays_buts, TITLE='Line color', $
                      MIN=0, MAX=255, VALUE=(*(*info).plotparams).plotcol, /DRAG, $
                      EVENT_PRO='CRISPEX_PREFERENCES_SET_PLOTCOL')
  (*(*info).ctrlspref).displays_plthick = WIDGET_SLIDER(displays_buts, $
                      TITLE='Line thickness', MIN=1, MAX=4, $
                      VALUE=(*(*info).plotparams).plotthick, /DRAG, $
                      EVENT_PRO='CRISPEX_PREFERENCES_SET_PLOTTHICK')
  cursor_buts     = WIDGET_BASE(layout_base, /GRID_LAYOUT, COLUMN=3)
  (*(*info).ctrlspref).displays_overlays_symsize = $
                      WIDGET_SLIDER(cursor_buts, TITLE='Overlay symbol size', $
                      MIN=1, MAX=8, VALUE=(*(*info).overlayparams).symsize, $
                      /DRAG, EVENT_PRO='CRISPEX_PREFERENCES_SET_OVERLAYS_SYMSIZE', $
                      XSIZE=FLOOR((tab_width-3*pad)/3.))
  (*(*info).ctrlspref).displays_overlays_thick = $
                      WIDGET_SLIDER(cursor_buts, TITLE='Overlay thickness', $
                      MIN=1, MAX=8, VALUE=(*(*info).overlayparams).thick, $
                      /DRAG, EVENT_PRO='CRISPEX_PREFERENCES_SET_OVERLAYS_THICK')
	displays_int_base = WIDGET_BASE(layout_base, /ROW, /NONEXCLUSIVE)
	(*(*info).ctrlspref).displays_interp = $
                    WIDGET_BUTTON(displays_int_base, VALUE='Interpolate spectral slices',$
                      EVENT_PRO='CRISPEX_PREFERENCES_SET_INTERPOLATE')
	displays_preview= WIDGET_BUTTON(displays_int_base, VALUE='Preview changes', $
                      EVENT_PRO='CRISPEX_PREFERENCES_SET_PREVIEW')
  displays_divider= CRISPEX_WIDGET_DIVIDER(layout_base)
  displays_off_base= WIDGET_BASE(layout_base, /ROW, /NONEXCLUSIVE)
  (*(*info).ctrlspref).displays_offsets = $
                     WIDGET_BUTTON(displays_off_base, VALUE='Use current '+$
                      'window offsets as default', $
                      EVENT_PRO='CRISPEX_PREFERENCES_SET_OFFSETS')
  WIDGET_CONTROL, (*(*info).ctrlspref).displays_offsets, $
    SET_BUTTON=(*(*info).prefs).current_offsets

  scaling_base    = WIDGET_BASE(tab_tlb, TITLE='Scaling', /COLUMN, XSIZE=tab_width);, /FRAME)
  histo_base      = WIDGET_BASE(scaling_base, /ROW)
  histo_opt_lab   = WIDGET_LABEL(histo_base, VALUE='Default histogram optimisation value:', /ALIGN_LEFT)
  (*(*info).ctrlspref).histo_opt_txt = $
                    WIDGET_TEXT(histo_base, VALUE=STRTRIM((*(*info).prefs).histo_opt_val,2), $
                      /EDITABLE, XSIZE=11, EVENT_PRO='CRISPEX_PREFERENCES_SET_SCALING_HISTO_OPT')
  (*(*info).ctrlspref).gamma_label = $
                    WIDGET_LABEL(scaling_base, VALUE=STRING((*(*info).prefs).gamma_val, $
                      FORMAT='(F6.3)'), /ALIGN_CENTER)
  (*(*info).ctrlspref).gamma_slid = $
                    WIDGET_SLIDER(scaling_base, TITLE='Default gamma', MIN=0, MAX=1000, $
                      VALUE=500*(ALOG10((*(*info).prefs).gamma_val)+1), $
                      EVENT_PRO='CRISPEX_PREFERENCES_SET_SCALING_GAMMA', /SUPPRESS, /DRAG)
  use_current     = WIDGET_BUTTON(scaling_base, VALUE='Use current values', $
                      EVENT_PRO='CRISPEX_PREFERENCES_SET_SCALING_CURRENT')
	displays_opts	  = WIDGET_BASE(scaling_base, /COLUMN, /NONEXCLUSIVE)
	(*(*info).ctrlspref).displays_slices = $
                    WIDGET_BUTTON(displays_opts, $
                      VALUE='Scale slices according main/reference image', $
                      EVENT_PRO='CRISPEX_PREFERENCES_SET_SLICES_IMSCALE')
  ; Set buttons according to settings
	(*(*info).prefs).plotcol_old = (*(*info).plotparams).plotcol
	(*(*info).prefs).plotthick_old = (*(*info).plotparams).plotthick
	(*(*info).prefs).interpspslice_old = (*(*info).dispparams).interpspslice
  (*(*info).prefs).overlays_symsize_old = (*(*info).overlayparams).symsize
  (*(*info).prefs).overlays_thick_old = (*(*info).overlayparams).thick
	WIDGET_CONTROL, (*(*info).ctrlspref).displays_interp, $
    SET_BUTTON=(*(*info).dispparams).interpspslice
	WIDGET_CONTROL, displays_preview, SET_BUTTON=(*(*info).prefs).preview
	WIDGET_CONTROL, (*(*info).ctrlspref).displays_slices, $
    SET_BUTTON=(*(*info).dispparams).slices_imscale

  ; IO preferences: inputs
  paths_base      = WIDGET_BASE(tab_tlb, TITLE='Input/Output', /COLUMN, XSIZE=tab_width);, /FRAME)
	paths_io_base	  = WIDGET_BASE(paths_base, /COLUMN)
	paths_i_labbuts = WIDGET_BASE(paths_io_base, /ROW)
	paths_i_lab	    = WIDGET_LABEL(paths_i_labbuts, VALUE = 'Default input path:')
	paths_i_buts	  = WIDGET_BASE(paths_i_labbuts, /ROW, /EXCLUSIVE)
	(*(*info).ctrlspref).paths_i_def_but = $
                    WIDGET_BUTTON(paths_i_buts, VALUE='Local working directory', $
                      EVENT_PRO='CRISPEX_PREFERENCES_SET_IPATH_SEL_DEFAULT', /NO_RELEASE)
	(*(*info).ctrlspref).paths_i_sav_but = $
                    WIDGET_BUTTON(paths_i_buts, VALUE='Other directory', $
                      EVENT_PRO='CRISPEX_PREFERENCES_SET_IPATH_SEL_OTHER', /NO_RELEASE)
	(*(*info).ctrlspref).paths_ipath_text = $
                    WIDGET_TEXT(paths_io_base, VALUE=(*(*info).prefs).prefipath, /EDITABLE,$
                      EVENT_PRO='CRISPEX_PREFERENCES_SET_IPATH_OTHER', $
                      SENSITIVE=(*(*info).prefs).defipath)
  ; Set buttons according to settings
	WIDGET_CONTROL, (*(*info).ctrlspref).paths_i_def_but, $
    SET_BUTTON=ABS((*(*info).prefs).defipath-1)
	WIDGET_CONTROL, (*(*info).ctrlspref).paths_i_sav_but, $
    SET_BUTTON=(*(*info).prefs).defipath
  ; IO preferences: outputs
	paths_o_labbuts = WIDGET_BASE(paths_io_base, /ROW)
	paths_o_lab	    = WIDGET_LABEL(paths_o_labbuts, VALUE = 'Default output path:')
	paths_o_buts	  = WIDGET_BASE(paths_o_labbuts, /ROW, /EXCLUSIVE)
	(*(*info).ctrlspref).paths_o_def_but = $
                    WIDGET_BUTTON(paths_o_buts, VALUE='Local working directory', $
                      EVENT_PRO='CRISPEX_PREFERENCES_SET_OPATH_SEL_DEFAULT', /NO_RELEASE)
	(*(*info).ctrlspref).paths_o_sav_but = $
                    WIDGET_BUTTON(paths_o_buts, VALUE='Other directory', $
                      EVENT_PRO='CRISPEX_PREFERENCES_SET_OPATH_SEL_OTHER', /NO_RELEASE)
	(*(*info).ctrlspref).paths_opath_text = $
                    WIDGET_TEXT(paths_io_base, VALUE=(*(*info).prefs).prefopath, /EDITABLE,$
                      EVENT_PRO='CRISPEX_PREFERENCES_SET_OPATH_OTHER', $
                      SENSITIVE=(*(*info).prefs).defopath)
  path_button_base  = WIDGET_BASE(paths_base, COLUMN=2, /GRID_LAYOUT, $
                        /ALIGN_CENTER)
	(*(*info).ctrlspref).paths_o2ipath = $
                    WIDGET_BUTTON(path_button_base, VALUE='Set output path to input path', $
                      EVENT_PRO='CRISPEX_PREFERENCES_SET_O2IPATH', $
                      SENSITIVE=((*(*info).prefs).prefipath NE (*(*info).prefs).prefopath))
	(*(*info).ctrlspref).paths_i2opath = $
                    WIDGET_BUTTON(path_button_base, VALUE='Set input path to output path', $
                      EVENT_PRO='CRISPEX_PREFERENCES_SET_I2OPATH', $
                      SENSITIVE=((*(*info).prefs).prefipath NE (*(*info).prefs).prefopath))
  ; Set buttons according to settings
	WIDGET_CONTROL, (*(*info).ctrlspref).paths_o_def_but, $
    SET_BUTTON=ABS((*(*info).prefs).defopath-1)
	WIDGET_CONTROL, (*(*info).ctrlspref).paths_o_sav_but, $
    SET_BUTTON=(*(*info).prefs).defopath
  ; File-ID
	save_base	      = WIDGET_BASE(tab_tlb, TITLE='Filenaming', /COLUMN, XSIZE=tab_width);, /FRAME)
	saveid_buts 	  = WIDGET_BASE(save_base, /ROW)
	saveid_lab	    = WIDGET_LABEL(saveid_buts, VALUE='Default unique file ID:', /ALIGN_LEFT)
	saveids	= ['YYYYMMMDD_hhmmss (default)','DDMMMYYYY_hhmmss', $
              'YYYYMMDD_hhmmss','DDMMYYYY_hhmmss']
	(*(*info).ctrlspref).save_defsaveid = $
                    WIDGET_COMBOBOX(saveid_buts, VALUE=saveids, /DYNAMIC_RESIZE, $
                      EVENT_PRO='CRISPEX_PREFERENCES_SET_SAVEID')
	CRISPEX_SAVE_DETERMINE_SAVEID, event, defsaveid_sample, /PREF
	saveid_sample	  = WIDGET_BASE(save_base, /ROW)
	saveid_sample_lab = WIDGET_LABEL(saveid_sample, VALUE = 'Example:')
	(*(*info).ctrlspref).save_defsaveid_sample = $
                    WIDGET_LABEL(saveid_sample, VALUE=defsaveid_sample, /DYNAMIC_RESIZE)
	WIDGET_CONTROL, (*(*info).ctrlspref).save_defsaveid, $
    SET_COMBOBOX_SELECT=(*(*info).prefs).defsaveid

  ; Messages
  messages_base = WIDGET_BASE(tab_tlb, TITLE='Messages', /COLUMN, XSIZE=tab_width)
  warn_cbox_base = WIDGET_BASE(messages_base, /ROW)
  warnings_lab  = WIDGET_LABEL(warn_cbox_base, VALUE='Display set-up warnings:', $
                    /ALIGN_LEFT)
  warnings_desc =['Do not show messages',$
                  'Write messages to terminal only',$
                  'Always pop-up messages']
  (*(*info).ctrlspref).warnings_cbox = WIDGET_COMBOBOX(warn_cbox_base, VALUE=warnings_desc, $
                    EVENT_PRO='CRISPEX_PREFERENCES_SET_WARNINGS_SETUP')
  WIDGET_CONTROL, (*(*info).ctrlspref).warnings_cbox, SET_COMBOBOX_SELECT=(*(*info).prefs).warnings

  ; Defaults / Cancel / Accept settings buttons
	dec_buts 	      = WIDGET_BASE(main, /ALIGN_CENTER, /GRID_LAYOUT, COLUMN=3)
	(*(*info).ctrlspref).set_defaults	= $
                    WIDGET_BUTTON(dec_buts, VALUE='Default settings', $
                      EVENT_PRO='CRISPEX_PREFERENCES_SET_DEFAULTS', SENSITIVE=nondefault)
	CRISPEX_PREFERENCES_CHECK_DEFAULT_BUTTON, event
	cancel 		      = WIDGET_BUTTON(dec_buts, VALUE='Cancel', $
                      EVENT_PRO='CRISPEX_PREFERENCES_CANCEL')
	save_settings 	= WIDGET_BUTTON(dec_buts, VALUE='Save settings', $
                      EVENT_PRO='CRISPEX_PREFERENCES_SAVE_SETTINGS')

  ; Realize widget window
	WIDGET_CONTROL, base, /REALIZE, TLB_SET_XOFFSET=(*(*info).winsizes).aboutxoffset, $
    TLB_SET_YOFFSET=(*(*info).winsizes).aboutyoffset
	WIDGET_CONTROL, base, SET_UVALUE=info
	XMANAGER, 'CRISPEX', base, /NO_BLOCK
	(*(*info).winids).preftlb = base
	IF (((*(*info).feedbparams).verbosity)[3] EQ 1) THEN $
    CRISPEX_VERBOSE_GET, event, [(*(*info).winids).preftlb], labels=['preftlb']
END

PRO CRISPEX_PREFERENCES_CHECK_DEFAULT_BUTTON, event
; Handles the checking whether preference buttons and values are in their default position
	WIDGET_CONTROL, event.TOP, GET_UVALUE = info
	IF (TOTAL(((*(*info).feedbparams).verbosity)[2:3]) GE 1) THEN $
    CRISPEX_VERBOSE_GET_ROUTINE, event
	IF (((*(*info).prefs).tmp_autoplay NE (*(*info).prefs).default_autoplay) OR $
		((*(*info).prefs).tmp_startupwin NE (*(*info).prefs).default_startupwin) OR $
		((*(*info).prefs).tmp_bgplotcol NE (*(*info).prefs).default_bgplotcol) OR $
		((*(*info).prefs).tmp_plotcol NE (*(*info).prefs).default_plotcol) OR $
		((*(*info).prefs).tmp_plotthick NE (*(*info).prefs).default_plotthick) OR $
		((*(*info).prefs).tmp_overlays_thick NE $
     (*(*info).prefs).default_overlays_thick) OR $
		((*(*info).prefs).tmp_overlays_symsize NE $
     (*(*info).prefs).default_overlays_symsize) OR $
		((*(*info).prefs).current_offsets NE 0) OR $
		((*(*info).prefs).tmp_interpspslice NE (*(*info).prefs).default_interpspslice) OR $
		((*(*info).prefs).tmp_slices_imscale NE (*(*info).prefs).default_slices_imscale) OR $			
		((*(*info).prefs).tmp_histo_opt_val NE (*(*info).prefs).default_histo_opt_val) OR $			
		((*(*info).prefs).tmp_gamma_val NE (*(*info).prefs).default_gamma_val) OR $			
		((*(*info).prefs).tmp_phislice_update NE (*(*info).prefs).default_phislice_update) OR $			
		((*(*info).prefs).tmp_defipath NE (*(*info).prefs).default_defipath) OR $
		((*(*info).prefs).tmp_prefipath NE (*(*info).prefs).default_prefipath) OR $
		((*(*info).prefs).tmp_defopath NE (*(*info).prefs).default_defopath) OR $
		((*(*info).prefs).tmp_prefopath NE (*(*info).prefs).default_prefopath) OR $
		((*(*info).prefs).tmp_defsaveid NE (*(*info).prefs).default_defsaveid) OR $
		((*(*info).prefs).tmp_warnings NE (*(*info).prefs).default_warnings)) THEN $
      nondefault = 1 $
    ELSE $
      nondefault = 0
	WIDGET_CONTROL, (*(*info).ctrlspref).set_defaults, SENSITIVE=nondefault
	IF (((*(*info).feedbparams).verbosity)[3] EQ 1) THEN $
    CRISPEX_VERBOSE_GET, event, [ABS(nondefault-1)], labels=['Buttons on default']
END

PRO CRISPEX_PREFERENCES_SET_STARTUPWIN, event
; Handles the toggle on/off setting of start-up window
	WIDGET_CONTROL, event.TOP, GET_UVALUE = info
	IF (TOTAL(((*(*info).feedbparams).verbosity)[2:3]) GE 1) THEN $
    CRISPEX_VERBOSE_GET_ROUTINE, event
	(*(*info).prefs).tmp_startupwin = event.SELECT
	IF (((*(*info).feedbparams).verbosity)[3] EQ 1) THEN $
    CRISPEX_VERBOSE_GET, event, [(*(*info).prefs).tmp_startupwin], labels=['Startup window']
	CRISPEX_PREFERENCES_CHECK_DEFAULT_BUTTON, event
END

PRO CRISPEX_PREFERENCES_SET_AUTOPLAY, event
; Handles the toggle on/off setting of autoplay at start-up
	WIDGET_CONTROL, event.TOP, GET_UVALUE = info
	IF (TOTAL(((*(*info).feedbparams).verbosity)[2:3]) GE 1) THEN $
    CRISPEX_VERBOSE_GET_ROUTINE, event
	(*(*info).prefs).tmp_autoplay = event.SELECT
	IF (((*(*info).feedbparams).verbosity)[3] EQ 1) THEN $
    CRISPEX_VERBOSE_GET, event, [(*(*info).prefs).tmp_autoplay], labels=['Autoplay']
	CRISPEX_PREFERENCES_CHECK_DEFAULT_BUTTON, event
END

PRO CRISPEX_PREFERENCES_SET_BGPLOTCOL, event
; Handles the setting of the background plot color
	WIDGET_CONTROL, event.TOP, GET_UVALUE = info
	IF (TOTAL(((*(*info).feedbparams).verbosity)[2:3]) GE 1) THEN $
    CRISPEX_VERBOSE_GET_ROUTINE, event
	(*(*info).prefs).tmp_bgplotcol = event.VALUE
	IF (((*(*info).feedbparams).verbosity)[3] EQ 1) THEN $
    CRISPEX_VERBOSE_GET, event, [(*(*info).prefs).tmp_bgplotcol], labels=['Background color']
	CRISPEX_PREFERENCES_CHECK_DEFAULT_BUTTON, event
	IF (*(*info).prefs).preview THEN BEGIN
		(*(*info).plotparams).bgplotcol = (*(*info).prefs).tmp_bgplotcol
		CRISPEX_PREFERENCES_REDRAW, event, /SPDISPS
	ENDIF
END

PRO CRISPEX_PREFERENCES_SET_PHISLICE_UPDATE, event									
; Handles the toggle on/off live update of spectral phi-slice
	WIDGET_CONTROL, event.TOP, GET_UVALUE = info
	IF (TOTAL(((*(*info).feedbparams).verbosity)[2:3]) GE 1) THEN $
    CRISPEX_VERBOSE_GET_ROUTINE, event
	(*(*info).prefs).tmp_phislice_update = event.SELECT
	IF (((*(*info).feedbparams).verbosity)[3] EQ 1) THEN $
    CRISPEX_VERBOSE_GET, event, [(*(*info).prefs).tmp_phislice_update], labels=['Live update spectral Phi-slice']
	CRISPEX_PREFERENCES_CHECK_DEFAULT_BUTTON, event
END

PRO CRISPEX_PREFERENCES_SET_PLOTCOL, event
; Handles the setting of the line plot color
	WIDGET_CONTROL, event.TOP, GET_UVALUE = info
	IF (TOTAL(((*(*info).feedbparams).verbosity)[2:3]) GE 1) THEN $
    CRISPEX_VERBOSE_GET_ROUTINE, event
	(*(*info).prefs).tmp_plotcol = event.VALUE
	IF (((*(*info).feedbparams).verbosity)[3] EQ 1) THEN $
    CRISPEX_VERBOSE_GET, event, [(*(*info).prefs).tmp_plotcol], labels=['Plot color']
	CRISPEX_PREFERENCES_CHECK_DEFAULT_BUTTON, event
	IF (*(*info).prefs).preview THEN BEGIN
		(*(*info).plotparams).plotcol = (*(*info).prefs).tmp_plotcol
		CRISPEX_PREFERENCES_REDRAW, event, /SPDISPS
	ENDIF
END

PRO CRISPEX_PREFERENCES_SET_PLOTTHICK, event
; Handles the setting of the line plot thickness
	WIDGET_CONTROL, event.TOP, GET_UVALUE = info
	IF (TOTAL(((*(*info).feedbparams).verbosity)[2:3]) GE 1) THEN $
    CRISPEX_VERBOSE_GET_ROUTINE, event
	(*(*info).prefs).tmp_plotthick = event.VALUE
	IF (((*(*info).feedbparams).verbosity)[3] EQ 1) THEN $
    CRISPEX_VERBOSE_GET, event, [(*(*info).prefs).tmp_plotthick], $
      labels=['Plot thickness']
	CRISPEX_PREFERENCES_CHECK_DEFAULT_BUTTON, event
	IF (*(*info).prefs).preview THEN BEGIN
		(*(*info).plotparams).plotthick = (*(*info).prefs).tmp_plotthick
		CRISPEX_PREFERENCES_REDRAW, event, /SPDISPS
	ENDIF
END

PRO CRISPEX_PREFERENCES_SET_OVERLAYS_SYMSIZE, event
; Handles the setting of the overlays symbol size
	WIDGET_CONTROL, event.TOP, GET_UVALUE = info
	IF (TOTAL(((*(*info).feedbparams).verbosity)[2:3]) GE 1) THEN $
    CRISPEX_VERBOSE_GET_ROUTINE, event
  (*(*info).prefs).tmp_overlays_symsize = event.VALUE
	IF (((*(*info).feedbparams).verbosity)[3] EQ 1) THEN $
    CRISPEX_VERBOSE_GET, event, [(*(*info).prefs).tmp_overlays_symsize], $
      labels=['Overlays symbol size']
	CRISPEX_PREFERENCES_CHECK_DEFAULT_BUTTON, event
	IF (*(*info).prefs).preview THEN BEGIN
		(*(*info).overlayparams).symsize = (*(*info).prefs).tmp_overlays_symsize
		CRISPEX_PREFERENCES_REDRAW, event, /IMDISPS
	ENDIF
END

PRO CRISPEX_PREFERENCES_SET_OVERLAYS_THICK, event
; Handles the setting of the overlays symbol size
	WIDGET_CONTROL, event.TOP, GET_UVALUE = info
	IF (TOTAL(((*(*info).feedbparams).verbosity)[2:3]) GE 1) THEN $
    CRISPEX_VERBOSE_GET_ROUTINE, event
  (*(*info).prefs).tmp_overlays_thick = event.VALUE
	IF (((*(*info).feedbparams).verbosity)[3] EQ 1) THEN $
    CRISPEX_VERBOSE_GET, event, [(*(*info).prefs).tmp_overlays_thick], $
      labels=['Overlays thickness']
	CRISPEX_PREFERENCES_CHECK_DEFAULT_BUTTON, event
	IF (*(*info).prefs).preview THEN BEGIN
		(*(*info).overlayparams).thick = (*(*info).prefs).tmp_overlays_thick
		CRISPEX_PREFERENCES_REDRAW, event, /IMDISPS
  ENDIF
END

PRO CRISPEX_PREFERENCES_SET_SLICES_IMSCALE, event									
; Handles the toggle on/off scaling of slices according to main/reference image scaling
	WIDGET_CONTROL, event.TOP, GET_UVALUE = info
	IF (TOTAL(((*(*info).feedbparams).verbosity)[2:3]) GE 1) THEN $
    CRISPEX_VERBOSE_GET_ROUTINE, event
	(*(*info).prefs).tmp_slices_imscale = event.SELECT
	IF (((*(*info).feedbparams).verbosity)[3] EQ 1) THEN $
    CRISPEX_VERBOSE_GET, event, [(*(*info).prefs).tmp_slices_imscale], $
      labels=['Scale slices with main/reference image']
	CRISPEX_PREFERENCES_CHECK_DEFAULT_BUTTON, event
END

PRO CRISPEX_PREFERENCES_SET_SCALING_HISTO_OPT, event, $
  SET_HISTO_OPT_VAL=set_histo_opt_val
; Handles setting the default histrogram optimisation value
	WIDGET_CONTROL, event.TOP, GET_UVALUE = info
	IF (TOTAL(((*(*info).feedbparams).verbosity)[2:3]) GE 1) THEN $
    CRISPEX_VERBOSE_GET_ROUTINE, event
  IF (N_ELEMENTS(SET_HISTO_OPT_VAL) NE 1) THEN BEGIN
  	WIDGET_CONTROL, (*(*info).ctrlspref).histo_opt_txt, GET_VALUE=textvalue 
	  (*(*info).prefs).tmp_histo_opt_val = textvalue[0]
  ENDIF ELSE BEGIN
	  (*(*info).prefs).tmp_histo_opt_val = set_histo_opt_val
  	WIDGET_CONTROL, (*(*info).ctrlspref).histo_opt_txt, $
      SET_VALUE=STRTRIM(STRING(set_histo_opt_val, FORMAT='(F15.10)'),2)
  ENDELSE
	IF (((*(*info).feedbparams).verbosity)[3] EQ 1) THEN $
    CRISPEX_VERBOSE_GET, event, [(*(*info).prefs).tmp_histo_opt_val], $
      labels=['Histogram optimisation value']
	CRISPEX_PREFERENCES_CHECK_DEFAULT_BUTTON, event
END

PRO CRISPEX_PREFERENCES_SET_SCALING_GAMMA, event, SET_GAMMA_VAL=set_gamma_val
; Handles setting the default gamma value 
	WIDGET_CONTROL, event.TOP, GET_UVALUE = info
	IF (TOTAL(((*(*info).feedbparams).verbosity)[2:3]) GE 1) THEN $
    CRISPEX_VERBOSE_GET_ROUTINE, event
  IF (N_ELEMENTS(SET_GAMMA_VAL) NE 1) THEN $
    (*(*info).prefs).tmp_gamma_val = 10.^((FLOAT(event.VALUE)/500.) - 1.) $
  ELSE BEGIN
    (*(*info).prefs).tmp_gamma_val = set_gamma_val
    gamma_slider_val = 500 * (ALOG10(set_gamma_val) + 1)
    WIDGET_CONTROL, (*(*info).ctrlspref).gamma_slid, $
      SET_VALUE=gamma_slider_val
  ENDELSE
  WIDGET_CONTROL, (*(*info).ctrlspref).gamma_label, $
    SET_VALUE=STRING((*(*info).prefs).tmp_gamma_val,FORMAT='(F6.3)')
	IF (((*(*info).feedbparams).verbosity)[3] EQ 1) THEN $
    CRISPEX_VERBOSE_GET, event, [(*(*info).prefs).tmp_gamma_val], $
      labels=['Gamma']
	CRISPEX_PREFERENCES_CHECK_DEFAULT_BUTTON, event
END

PRO CRISPEX_PREFERENCES_SET_SCALING_CURRENT, event
; Handles setting the scaling parameters to current values
	WIDGET_CONTROL, event.TOP, GET_UVALUE = info
	IF (TOTAL(((*(*info).feedbparams).verbosity)[2:3]) GE 1) THEN $
    CRISPEX_VERBOSE_GET_ROUTINE, event
  CRISPEX_PREFERENCES_SET_SCALING_GAMMA, event, $
    SET_GAMMA_VAL=(*(*info).scaling).gamma[(*(*info).scaling).idx] 
  CRISPEX_PREFERENCES_SET_SCALING_HISTO_OPT, event, $
    SET_HISTO_OPT_VAL=(*(*info).scaling).histo_opt_val[(*(*info).scaling).idx] 
END

PRO CRISPEX_PREFERENCES_SET_INTERPOLATE, event
; Handles the toggle on/off setting of interpolating the spectral slices
	WIDGET_CONTROL, event.TOP, GET_UVALUE = info
	IF (TOTAL(((*(*info).feedbparams).verbosity)[2:3]) GE 1) THEN $
    CRISPEX_VERBOSE_GET_ROUTINE, event
	(*(*info).prefs).tmp_interpspslice = event.SELECT
	IF (((*(*info).feedbparams).verbosity)[3] EQ 1) THEN $
    CRISPEX_VERBOSE_GET, event, [(*(*info).prefs).tmp_interpspslice], labels=['Interpolate']
	CRISPEX_PREFERENCES_CHECK_DEFAULT_BUTTON, event
	IF (*(*info).prefs).preview THEN BEGIN
		(*(*info).dispparams).interpspslice = (*(*info).prefs).tmp_interpspslice
		CRISPEX_PREFERENCES_REDRAW, event, /SPDISPS
	ENDIF
END

PRO CRISPEX_PREFERENCES_SET_IPATH_SEL_DEFAULT, event
; Handles the toggle on/off selection of the default input path
	WIDGET_CONTROL, event.TOP, GET_UVALUE = info
	IF (TOTAL(((*(*info).feedbparams).verbosity)[2:3]) GE 1) THEN $
    CRISPEX_VERBOSE_GET_ROUTINE, event
	(*(*info).prefs).tmp_defipath = ABS(event.SELECT-1)
	(*(*info).prefs).tmp_prefipath = (*(*info).prefs).default_prefipath
	WIDGET_CONTROL, (*(*info).ctrlspref).paths_ipath_text, $
    SET_VALUE=(*(*info).prefs).default_prefipath, $
    SENSITIVE=(*(*info).prefs).tmp_defipath
	WIDGET_CONTROL, (*(*info).ctrlspref).paths_o2ipath, $
    SENSITIVE=((*(*info).prefs).tmp_prefopath NE (*(*info).prefs).tmp_prefipath)
	IF (((*(*info).feedbparams).verbosity)[3] EQ 1) THEN $
    CRISPEX_VERBOSE_GET, event, [STRTRIM(event.SELECT,2),$
    (*(*info).prefs).tmp_prefipath], labels=['Default input path set','Input path']
	CRISPEX_PREFERENCES_CHECK_DEFAULT_BUTTON, event
END

PRO CRISPEX_PREFERENCES_SET_IPATH_SEL_OTHER, event
; Handles the toggle on/off selection of different input path
	WIDGET_CONTROL, event.TOP, GET_UVALUE = info
	IF (TOTAL(((*(*info).feedbparams).verbosity)[2:3]) GE 1) THEN $
    CRISPEX_VERBOSE_GET_ROUTINE, event
	(*(*info).prefs).tmp_defipath = event.SELECT
	IF (*(*info).prefs).tmp_defipath THEN BEGIN
		IF ((*(*info).prefs).tmp_prefipath NE (*(*info).paths).ipath) THEN $
      (*(*info).prefs).tmp_prefipath = (*(*info).paths).ipath
		WIDGET_CONTROL, (*(*info).ctrlspref).paths_ipath_text, $
      SET_VALUE=(*(*info).prefs).tmp_prefipath, $
      SENSITIVE=(*(*info).prefs).tmp_defipath
		CRISPEX_SAVE_SET_IPATH, event
		WIDGET_CONTROL, (*(*info).ctrlspref).paths_ipath_text, $
      SET_VALUE=(*(*info).prefs).tmp_prefipath
	ENDIF
	WIDGET_CONTROL, (*(*info).ctrlspref).paths_o2ipath, $
    SENSITIVE=((*(*info).prefs).tmp_prefopath NE (*(*info).prefs).tmp_prefipath)
	IF (((*(*info).feedbparams).verbosity)[3] EQ 1) THEN $
    CRISPEX_VERBOSE_GET, event, [STRTRIM(ABS(event.SELECT-1),2),$
    (*(*info).prefs).tmp_prefipath], labels=['Default input path set','Input path']
	CRISPEX_PREFERENCES_CHECK_DEFAULT_BUTTON, event
END

PRO CRISPEX_PREFERENCES_SET_IPATH_OTHER, event
; Handles the setting of the input path
	WIDGET_CONTROL, event.TOP, GET_UVALUE = info
	IF (TOTAL(((*(*info).feedbparams).verbosity)[2:3]) GE 1) THEN $
    CRISPEX_VERBOSE_GET_ROUTINE, event
	WIDGET_CONTROL, (*(*info).ctrlspref).paths_ipath_text, GET_VALUE=textvalue
	(*(*info).prefs).tmp_prefipath = textvalue[0]
	WIDGET_CONTROL, (*(*info).ctrlspref).paths_o2ipath, $
    SENSITIVE=((*(*info).prefs).tmp_prefopath NE (*(*info).prefs).tmp_prefipath)
	WIDGET_CONTROL, (*(*info).ctrlspref).paths_i2opath, $
    SENSITIVE=((*(*info).prefs).tmp_prefopath NE (*(*info).prefs).tmp_prefipath)
	IF (((*(*info).feedbparams).verbosity)[3] EQ 1) THEN $
    CRISPEX_VERBOSE_GET, event, [(*(*info).prefs).tmp_prefipath], labels=['Input path']
	CRISPEX_PREFERENCES_CHECK_DEFAULT_BUTTON, event
END

PRO CRISPEX_PREFERENCES_SET_OPATH_SEL_DEFAULT, event
; Handles the toggle on/off selection of the default output path
	WIDGET_CONTROL, event.TOP, GET_UVALUE = info
	IF (TOTAL(((*(*info).feedbparams).verbosity)[2:3]) GE 1) THEN $
    CRISPEX_VERBOSE_GET_ROUTINE, event
	(*(*info).prefs).tmp_defopath = ABS(event.SELECT-1)
	(*(*info).prefs).tmp_prefopath = (*(*info).prefs).default_prefopath
	WIDGET_CONTROL, (*(*info).ctrlspref).paths_opath_text, $
    SET_VALUE=(*(*info).prefs).default_prefopath, $
    SENSITIVE=(*(*info).prefs).tmp_defopath
	WIDGET_CONTROL, (*(*info).ctrlspref).paths_i2opath, $
    SENSITIVE=((*(*info).prefs).tmp_prefopath NE (*(*info).prefs).tmp_prefipath)
	IF (((*(*info).feedbparams).verbosity)[3] EQ 1) THEN $
    CRISPEX_VERBOSE_GET, event, [STRTRIM(event.SELECT,2),$
    (*(*info).prefs).tmp_prefopath], labels=['Default output path set','Output path']
	CRISPEX_PREFERENCES_CHECK_DEFAULT_BUTTON, event
END

PRO CRISPEX_PREFERENCES_SET_OPATH_SEL_OTHER, event
; Handles the toggle on/off selection of different output path
	WIDGET_CONTROL, event.TOP, GET_UVALUE = info
	IF (TOTAL(((*(*info).feedbparams).verbosity)[2:3]) GE 1) THEN $
    CRISPEX_VERBOSE_GET_ROUTINE, event
	(*(*info).prefs).tmp_defopath = event.SELECT
	IF (*(*info).prefs).tmp_defopath THEN BEGIN
		IF ((*(*info).prefs).tmp_prefopath NE (*(*info).paths).opath) THEN $
      (*(*info).prefs).tmp_prefopath = (*(*info).paths).opath
		WIDGET_CONTROL, (*(*info).ctrlspref).paths_opath_text, $
      SET_VALUE=(*(*info).prefs).tmp_prefopath, SENSITIVE = (*(*info).prefs).tmp_defopath
		CRISPEX_SAVE_SET_OPATH, event
		WIDGET_CONTROL, (*(*info).ctrlspref).paths_opath_text, $
      SET_VALUE=(*(*info).prefs).tmp_prefopath
	ENDIF
	WIDGET_CONTROL, (*(*info).ctrlspref).paths_i2opath, $
    SENSITIVE=((*(*info).prefs).tmp_prefopath NE (*(*info).prefs).tmp_prefipath)
	IF (((*(*info).feedbparams).verbosity)[3] EQ 1) THEN $
    CRISPEX_VERBOSE_GET, event, [STRTRIM(ABS(event.SELECT-1),2),$
    (*(*info).prefs).tmp_prefopath], labels=['Default output path set','Output path']
	CRISPEX_PREFERENCES_CHECK_DEFAULT_BUTTON, event
END

PRO CRISPEX_PREFERENCES_SET_OPATH_OTHER, event
; Handles the setting of the output path
	WIDGET_CONTROL, event.TOP, GET_UVALUE = info
	IF (TOTAL(((*(*info).feedbparams).verbosity)[2:3]) GE 1) THEN $
    CRISPEX_VERBOSE_GET_ROUTINE, event
	WIDGET_CONTROL, (*(*info).ctrlspref).paths_opath_text, GET_VALUE=textvalue
	(*(*info).prefs).tmp_prefopath = textvalue[0]
	WIDGET_CONTROL, (*(*info).ctrlspref).paths_i2opath, $
    SENSITIVE=((*(*info).prefs).tmp_prefopath NE (*(*info).prefs).tmp_prefipath)
	IF (((*(*info).feedbparams).verbosity)[3] EQ 1) THEN $
    CRISPEX_VERBOSE_GET, event, [(*(*info).prefs).tmp_prefopath], labels=['Output path']
	CRISPEX_PREFERENCES_CHECK_DEFAULT_BUTTON, event
END

PRO CRISPEX_PREFERENCES_SET_O2IPATH, event
; Handles the setting of the output path to the input path
	WIDGET_CONTROL, event.TOP, GET_UVALUE = info
	IF (TOTAL(((*(*info).feedbparams).verbosity)[2:3]) GE 1) THEN $
    CRISPEX_VERBOSE_GET_ROUTINE, event
	(*(*info).prefs).tmp_prefopath = (*(*info).prefs).tmp_prefipath
	(*(*info).prefs).tmp_defopath = (*(*info).prefs).tmp_defipath
  CRISPEX_PREFERENCES_SET_PATH_BUTTONS, event
END

PRO CRISPEX_PREFERENCES_SET_I2OPATH, event
; Handles the setting of the input path to the output path
	WIDGET_CONTROL, event.TOP, GET_UVALUE = info
	IF (TOTAL(((*(*info).feedbparams).verbosity)[2:3]) GE 1) THEN $
    CRISPEX_VERBOSE_GET_ROUTINE, event
	(*(*info).prefs).tmp_prefipath = (*(*info).prefs).tmp_prefopath
	(*(*info).prefs).tmp_defipath = (*(*info).prefs).tmp_defopath
  CRISPEX_PREFERENCES_SET_PATH_BUTTONS, event
END

PRO CRISPEX_PREFERENCES_SET_PATH_BUTTONS, event
; Handles setting preference path buttons after setting input/output path to
; output/input path
	WIDGET_CONTROL, event.TOP, GET_UVALUE = info
	WIDGET_CONTROL, (*(*info).ctrlspref).paths_o_def_but, $
    SET_BUTTON=ABS((*(*info).prefs).tmp_defopath-1)
	WIDGET_CONTROL, (*(*info).ctrlspref).paths_o_sav_but, $
    SET_BUTTON=(*(*info).prefs).tmp_defopath
	WIDGET_CONTROL, (*(*info).ctrlspref).paths_opath_text, $
    SET_VALUE=(*(*info).prefs).tmp_prefopath, $
    SENSITIVE=(*(*info).prefs).tmp_defopath
	WIDGET_CONTROL, (*(*info).ctrlspref).paths_i_def_but, $
    SET_BUTTON=ABS((*(*info).prefs).tmp_defipath-1)
	WIDGET_CONTROL, (*(*info).ctrlspref).paths_i_sav_but, $
    SET_BUTTON=(*(*info).prefs).tmp_defipath
	WIDGET_CONTROL, (*(*info).ctrlspref).paths_ipath_text, $
    SET_VALUE=(*(*info).prefs).tmp_prefipath, $
    SENSITIVE=(*(*info).prefs).tmp_defipath
	WIDGET_CONTROL, (*(*info).ctrlspref).paths_i2opath, SENSITIVE=0
	WIDGET_CONTROL, (*(*info).ctrlspref).paths_o2ipath, SENSITIVE=0
	IF (((*(*info).feedbparams).verbosity)[3] EQ 1) THEN $
    CRISPEX_VERBOSE_GET, event, $
      [STRTRIM(ABS((*(*info).prefs).tmp_defipath-1),2),$
      (*(*info).prefs).tmp_prefipath,$
      STRTRIM(ABS((*(*info).prefs).tmp_defopath-1),2),$
      (*(*info).prefs).tmp_prefopath], labels=['Default input path set',$
      'Input path','Default output path set','Output path']
	CRISPEX_PREFERENCES_CHECK_DEFAULT_BUTTON, event
END

PRO CRISPEX_PREFERENCES_SET_PREVIEW, event
; Handles the enabling of preview mode
	WIDGET_CONTROL, event.TOP, GET_UVALUE = info
	IF (TOTAL(((*(*info).feedbparams).verbosity)[2:3]) GE 1) THEN $
    CRISPEX_VERBOSE_GET_ROUTINE, event
	(*(*info).prefs).preview = event.SELECT
	IF (*(*info).prefs).preview THEN BEGIN
		(*(*info).plotparams).plotcol = (*(*info).prefs).tmp_plotcol		
    (*(*info).plotparams).bgplotcol = (*(*info).prefs).tmp_bgplotcol
		(*(*info).plotparams).plotthick = (*(*info).prefs).tmp_plotthick
		(*(*info).dispparams).interpspslice = (*(*info).prefs).tmp_interpspslice
    (*(*info).overlayparams).symsize = (*(*info).prefs).tmp_overlays_symsize
    (*(*info).overlayparams).thick = (*(*info).prefs).tmp_overlays_thick
	ENDIF ELSE BEGIN
		(*(*info).plotparams).plotcol = (*(*info).prefs).plotcol_old		
    (*(*info).plotparams).bgplotcol = (*(*info).prefs).bgplotcol_old
		(*(*info).plotparams).plotthick = (*(*info).prefs).plotthick_old
		(*(*info).dispparams).interpspslice = (*(*info).prefs).interpspslice_old
    (*(*info).overlayparams).symsize = (*(*info).prefs).overlays_symsize_old
    (*(*info).overlayparams).thick = (*(*info).prefs).overlays_thick_old
	ENDELSE
	IF (((*(*info).feedbparams).verbosity)[3] EQ 1) THEN $
    CRISPEX_VERBOSE_GET, event, [(*(*info).prefs).preview], labels=['Preview']
	CRISPEX_PREFERENCES_REDRAW, event, /IMDISPS, /SPDISPS
END

PRO CRISPEX_PREFERENCES_SET_OFFSETS, event
; Handles the use of current window offsets
	WIDGET_CONTROL, event.TOP, GET_UVALUE = info
	IF (TOTAL(((*(*info).feedbparams).verbosity)[2:3]) GE 1) THEN $
    CRISPEX_VERBOSE_GET_ROUTINE, event
	(*(*info).prefs).current_offsets = event.SELECT
END

PRO CRISPEX_PREFERENCES_SET_SAVEID, event
; Handles the setting of unique save ID
	WIDGET_CONTROL, event.TOP, GET_UVALUE = info
	IF (TOTAL(((*(*info).feedbparams).verbosity)[2:3]) GE 1) THEN $
    CRISPEX_VERBOSE_GET_ROUTINE, event
	(*(*info).prefs).tmp_defsaveid = event.INDEX
	IF (((*(*info).feedbparams).verbosity)[3] EQ 1) THEN $
    CRISPEX_VERBOSE_GET, event, [(*(*info).prefs).tmp_defsaveid], labels=['Default save ID']
	CRISPEX_SAVE_DETERMINE_SAVEID, event, defsaveid_sample, /PREF
	WIDGET_CONTROL, (*(*info).ctrlspref).save_defsaveid_sample, SET_VALUE = defsaveid_sample
	CRISPEX_PREFERENCES_CHECK_DEFAULT_BUTTON, event
END

PRO CRISPEX_PREFERENCES_SET_WARNINGS_SETUP, event
; Handles setting of warnings
	WIDGET_CONTROL, event.TOP, GET_UVALUE = info
	IF (TOTAL(((*(*info).feedbparams).verbosity)[2:3]) GE 1) THEN $
    CRISPEX_VERBOSE_GET_ROUTINE, event
  (*(*info).prefs).tmp_warnings = event.INDEX 
	IF (event.TOP EQ (*(*info).winids).preftlb) THEN $
	  CRISPEX_PREFERENCES_CHECK_DEFAULT_BUTTON, event $
  ELSE $
    CRISPEX_PREFERENCES_SAVE_SETTINGS, event, /RESAVE
END

PRO CRISPEX_PREFERENCES_SET_DEFAULTS, event
; Handles the setting of all defaults
	WIDGET_CONTROL, event.TOP, GET_UVALUE = info
	IF (TOTAL(((*(*info).feedbparams).verbosity)[2:3]) GE 1) THEN $
    CRISPEX_VERBOSE_GET_ROUTINE, event
	(*(*info).prefs).tmp_startupwin = (*(*info).prefs).default_startupwin
  (*(*info).prefs).tmp_interpspslice = (*(*info).prefs).default_interpspslice
	(*(*info).prefs).tmp_autoplay = (*(*info).prefs).default_autoplay
  (*(*info).prefs).tmp_defsaveid = (*(*info).prefs).default_defsaveid
	(*(*info).prefs).tmp_defipath = (*(*info).prefs).default_defipath
  (*(*info).prefs).tmp_prefipath = (*(*info).prefs).default_prefipath
	(*(*info).prefs).tmp_defopath = (*(*info).prefs).default_defopath
  (*(*info).prefs).tmp_prefopath = (*(*info).prefs).default_prefopath
	(*(*info).prefs).tmp_bgplotcol = (*(*info).prefs).default_bgplotcol
  (*(*info).prefs).tmp_plotcol = (*(*info).prefs).default_plotcol
  (*(*info).prefs).current_offsets = 0
	(*(*info).prefs).tmp_phislice_update = (*(*info).prefs).default_phislice_update
  (*(*info).prefs).tmp_slices_imscale = (*(*info).prefs).default_slices_imscale		
  (*(*info).prefs).tmp_histo_opt_val = (*(*info).prefs).default_histo_opt_val
  (*(*info).prefs).tmp_gamma_val = (*(*info).prefs).default_gamma_val
  (*(*info).prefs).tmp_warnings = (*(*info).prefs).default_warnings
	WIDGET_CONTROL, (*(*info).ctrlspref).startup_win, SET_BUTTON = (*(*info).prefs).tmp_startupwin
	WIDGET_CONTROL, (*(*info).ctrlspref).startup_autopl, SET_BUTTON = (*(*info).prefs).tmp_autoplay
	WIDGET_CONTROL, (*(*info).ctrlspref).displays_bgcols, SET_VALUE = (*(*info).prefs).tmp_bgplotcol
	WIDGET_CONTROL, (*(*info).ctrlspref).displays_plcols, SET_VALUE = (*(*info).prefs).tmp_plotcol
	WIDGET_CONTROL, (*(*info).ctrlspref).displays_interp, SET_BUTTON = (*(*info).prefs).tmp_interpspslice
	WIDGET_CONTROL, (*(*info).ctrlspref).displays_phislice, $
    SET_BUTTON = (*(*info).prefs).tmp_phislice_update		
	WIDGET_CONTROL, (*(*info).ctrlspref).displays_slices, SET_BUTTON = (*(*info).prefs).tmp_slices_imscale
  WIDGET_CONTROL, (*(*info).ctrlspref).displays_offsets, SET_BUTTON=0
	WIDGET_CONTROL, (*(*info).ctrlspref).histo_opt_txt, $
    SET_VALUE=STRTRIM((*(*info).prefs).tmp_histo_opt_val,2)
	WIDGET_CONTROL, (*(*info).ctrlspref).gamma_label, $
    SET_VALUE=STRING((*(*info).prefs).tmp_gamma_val, FORMAT='(F6.3)') 
	WIDGET_CONTROL, (*(*info).ctrlspref).gamma_slid, $
    SET_VALUE=(500*(ALOG10((*(*info).prefs).tmp_gamma_val)+1))
	WIDGET_CONTROL, (*(*info).ctrlspref).paths_i_def_but, SET_BUTTON = ABS((*(*info).prefs).tmp_defipath-1)
	WIDGET_CONTROL, (*(*info).ctrlspref).paths_i_sav_but, SET_BUTTON = (*(*info).prefs).tmp_defipath
	WIDGET_CONTROL, (*(*info).ctrlspref).paths_ipath_text, $
    SET_VALUE = (*(*info).prefs).tmp_prefipath, SENSITIVE = (*(*info).prefs).tmp_defipath
	WIDGET_CONTROL, (*(*info).ctrlspref).paths_o_def_but, SET_BUTTON = ABS((*(*info).prefs).tmp_defopath-1)
	WIDGET_CONTROL, (*(*info).ctrlspref).paths_o_sav_but, SET_BUTTON = (*(*info).prefs).tmp_defopath
	WIDGET_CONTROL, (*(*info).ctrlspref).paths_opath_text, $
    SET_VALUE = (*(*info).prefs).tmp_prefopath, SENSITIVE = (*(*info).prefs).tmp_defopath
	WIDGET_CONTROL, (*(*info).ctrlspref).paths_i2opath, SENSITIVE = 0
	WIDGET_CONTROL, (*(*info).ctrlspref).paths_o2ipath, SENSITIVE = 0
	WIDGET_CONTROL, (*(*info).ctrlspref).save_defsaveid, $
    SET_COMBOBOX_SELECT = (*(*info).prefs).tmp_defsaveid
	CRISPEX_SAVE_DETERMINE_SAVEID, event, defsaveid_sample
	WIDGET_CONTROL, (*(*info).ctrlspref).save_defsaveid_sample, SET_VALUE = defsaveid_sample
  WIDGET_CONTROL, (*(*info).ctrlspref).warnings_cbox, SET_COMBOBOX_SELECT=(*(*info).prefs).warnings
	IF (*(*info).prefs).preview THEN BEGIN
		(*(*info).plotparams).plotcol = (*(*info).prefs).tmp_plotcol
		(*(*info).plotparams).bgplotcol = (*(*info).prefs).tmp_bgplotcol
		(*(*info).dispparams).interpspslice = (*(*info).prefs).tmp_interpspslice
		CRISPEX_PREFERENCES_REDRAW, event, /SPDISPS, /IMDISPS
	ENDIF
	IF (((*(*info).feedbparams).verbosity)[3] EQ 1) THEN $
    CRISPEX_VERBOSE_GET, event, [STRTRIM((*(*info).prefs).tmp_startupwin,2),STRTRIM((*(*info).prefs).tmp_autoplay,2),STRTRIM((*(*info).prefs).tmp_bgplotcol,2),$
		STRTRIM((*(*info).prefs).tmp_plotcol,2),STRTRIM((*(*info).prefs).tmp_interpspslice,2),STRTRIM((*(*info).prefs).preview,2),STRTRIM((*(*info).prefs).tmp_phislice_update,2),$
		STRTRIM((*(*info).prefs).tmp_slices_imscale,2),STRTRIM(ABS((*(*info).prefs).tmp_defipath-1),2),(*(*info).prefs).tmp_prefipath,STRTRIM(ABS((*(*info).prefs).tmp_defopath-1),2),$
		STRTRIM((*(*info).prefs).tmp_prefopath,2),STRTRIM((*(*info).prefs).tmp_defsaveid,2)], labels=['Startup window','Autoplay','Background color','Plot color',$
		'Interpolate','Preview','Update phi-slice','Scale slices','Default input path set','Input path','Default output path set','Output path','Default save ID']
	CRISPEX_PREFERENCES_CHECK_DEFAULT_BUTTON, event
END

PRO CRISPEX_PREFERENCES_SAVE_SETTINGS, event, RESAVE=resave
; Handles the saving of settings
	WIDGET_CONTROL, event.TOP, GET_UVALUE = info
	IF (TOTAL(((*(*info).feedbparams).verbosity)[2:3]) GE 1) THEN $
    CRISPEX_VERBOSE_GET_ROUTINE, event
	CD, CURRENT=curpath
	IF (*(*info).prefs).tmp_defipath THEN BEGIN
		IF ((*(*info).prefs).tmp_prefipath EQ curpath) THEN (*(*info).prefs).tmp_defipath = 0
	ENDIF
	IF (*(*info).prefs).tmp_defopath THEN BEGIN
		IF ((*(*info).prefs).tmp_prefopath EQ curpath) THEN (*(*info).prefs).tmp_defopath = 0
	ENDIF
	curpath = curpath+PATH_SEP()
	startupwin = (*(*info).prefs).tmp_startupwin		&	interpspslice = (*(*info).prefs).tmp_interpspslice
	autoplay = (*(*info).prefs).tmp_autoplay		&	defsaveid = (*(*info).prefs).tmp_defsaveid
	defipath = (*(*info).prefs).tmp_defipath		&	prefipath = (*(*info).prefs).tmp_prefipath
	defopath = (*(*info).prefs).tmp_defopath		&	prefopath = (*(*info).prefs).tmp_prefopath
	bgplotcol = (*(*info).prefs).tmp_bgplotcol		&	plotcol = (*(*info).prefs).tmp_plotcol
  plotthick = (*(*info).prefs).tmp_plotthick
  overlays_thick = (*(*info).prefs).tmp_overlays_thick
  overlays_symsize = (*(*info).prefs).tmp_overlays_symsize
	phislice_update = (*(*info).prefs).tmp_phislice_update	&	slices_imscale = (*(*info).prefs).tmp_slices_imscale	
  histo_opt_val = (*(*info).prefs).tmp_histo_opt_val
  gamma_val = (*(*info).prefs).tmp_gamma_val
  warnings = (*(*info).prefs).tmp_warnings
	crispex_version = [(*(*info).versioninfo).version_number, (*(*info).versioninfo).revision_number]
  ; Window offsets
  IF (*(*info).prefs).current_offsets THEN BEGIN
    CRISPEX_WINDOWS_GET_OFFSETS, event
    spxoffset = (*(*info).winsizes).spxoffset
    spyoffset = (*(*info).winsizes).spyoffset
    lsxoffset = (*(*info).winsizes).lsxoffset
    lsyoffset = (*(*info).winsizes).lsyoffset
    dopxoffset = (*(*info).winsizes).dopxoffset
    dopyoffset = (*(*info).winsizes).dopyoffset
    imrefxoffset = (*(*info).winsizes).imrefxoffset
    imrefyoffset = (*(*info).winsizes).imrefyoffset
    refxoffset = (*(*info).winsizes).refxoffset
    refyoffset = (*(*info).winsizes).refyoffset
    refspxoffset = (*(*info).winsizes).refspxoffset
    refspyoffset = (*(*info).winsizes).refspyoffset
    reflsxoffset = (*(*info).winsizes).reflsxoffset
    reflsyoffset = (*(*info).winsizes).reflsyoffset
    sjixoffset = (*(*info).winsizes).sjixoffset
    sjiyoffset = (*(*info).winsizes).sjiyoffset
    phisxoffset = (*(*info).winsizes).phisxoffset
    phisyoffset = (*(*info).winsizes).phisyoffset
    intxoffset = (*(*info).winsizes).intxoffset
    intyoffset = (*(*info).winsizes).intyoffset
    loopxoffset = (*(*info).winsizes).loopxoffset
    loopyoffset = (*(*info).winsizes).loopyoffset
    window_offsets = {set:1, spxoffset:spxoffset, spyoffset:spyoffset,$
      lsxoffset:lsxoffset, lsyoffset:lsyoffset, $
      dopxoffset:dopxoffset, dopyoffset:dopyoffset, $
      imrefxoffset:imrefxoffset, imrefyoffset:imrefyoffset, $
      refxoffset:refxoffset, refyoffset:refyoffset, $
      refspxoffset:refspxoffset, refspyoffset:refspyoffset, $
      reflsxoffset:reflsxoffset, reflsyoffset:reflsyoffset, $
      sjixoffset:sjixoffset, sjiyoffset:sjiyoffset, $
      phisxoffset:phisxoffset, phisyoffset:phisyoffset, $
      intxoffset:intxoffset, intyoffset:intyoffset, $
      loopxoffset:loopxoffset, loopyoffset:loopyoffset}
  ENDIF ELSE $
    window_offsets = {set:0}
	SAVE, crispex_version, startupwin, interpspslice, phislice_update, $
    slices_imscale, histo_opt_val,gamma_val, autoplay, defsaveid, defipath, $
    defopath, bgplotcol, plotcol, plotthick, prefipath, prefopath, warnings, $
    overlays_thick, overlays_symsize, window_offsets, $
    FILENAME=(*(*info).paths).dir_settings+'crispex.cpref'
	IF (((*(*info).feedbparams).verbosity)[3] EQ 1) THEN $
    CRISPEX_VERBOSE_GET, event, [(*(*info).paths).dir_settings+'crispex.cpref'],labels=['Written']
	(*(*info).prefs).startupwin = startupwin		&	(*(*info).dispparams).interpspslice = interpspslice
	(*(*info).prefs).autoplay = autoplay			&	(*(*info).prefs).defsaveid = defsaveid
	(*(*info).prefs).defipath = defipath			&	(*(*info).prefs).defopath = defopath
	(*(*info).plotparams).bgplotcol = bgplotcol		
  (*(*info).plotparams).plotcol = plotcol
  (*(*info).plotparams).plotthick = plotthick
  (*(*info).overlayparams).symsize = overlays_symsize
  (*(*info).overlayparams).thick = overlays_thick
	(*(*info).prefs).prefipath = prefipath			&	(*(*info).paths).ipath = prefipath
	(*(*info).prefs).prefopath = prefopath			&	(*(*info).paths).opath = prefopath
	(*(*info).dispparams).phislice_update = phislice_update	&	(*(*info).dispparams).slices_imscale = slices_imscale	
  (*(*info).prefs).histo_opt_val = histo_opt_val
  (*(*info).prefs).gamma_val = gamma_val
  (*(*info).prefs).warnings = warnings
	IF ~KEYWORD_SET(RESAVE) THEN BEGIN
		CRISPEX_PREFERENCES_REDRAW, event, /IMDISPS, /SPDISPS
		WIDGET_CONTROL, (*(*info).winids).preftlb, /DESTROY
		(*(*info).winids).preftlb = 0
	ENDIF
END

PRO CRISPEX_PREFERENCES_CANCEL, event
; Handles the exiting from the preferences window
	WIDGET_CONTROL, event.TOP, GET_UVALUE = info
	IF (TOTAL(((*(*info).feedbparams).verbosity)[2:3]) GE 1) THEN $
    CRISPEX_VERBOSE_GET_ROUTINE, event
	IF (*(*info).prefs).preview THEN BEGIN
		(*(*info).plotparams).plotcol = (*(*info).prefs).plotcol_old		
    (*(*info).plotparams).bgplotcol = (*(*info).prefs).bgplotcol_old
		(*(*info).plotparams).plotthick = (*(*info).prefs).plotthick_old		
		(*(*info).dispparams).interpspslice = (*(*info).prefs).interpspslice_old
    (*(*info).overlayparams).symsize = (*(*info).prefs).overlays_symsize_old
    (*(*info).overlayparams).thick = (*(*info).prefs).overlays_thick_old
		CRISPEX_PREFERENCES_REDRAW, event, /IMDISPS, /SPDISPS
	ENDIF
	WIDGET_CONTROL, (*(*info).winids).preftlb, /DESTROY
	(*(*info).winids).preftlb = 0
END

PRO CRISPEX_PREFERENCES_REDRAW, event, IMDISPS=imdisps, SPDISPS=spdisps
; Handles the redrawing of plot windows in case the preview mode is set
	WIDGET_CONTROL, event.TOP, GET_UVALUE = info
	IF (TOTAL(((*(*info).feedbparams).verbosity)[2:3]) GE 1) THEN $
    CRISPEX_VERBOSE_GET_ROUTINE, event
  IF KEYWORD_SET(IMDISPS) THEN CRISPEX_DRAW_IMREF, event
  IF KEYWORD_SET(SPDISPS) THEN BEGIN
  	IF ((*(*info).winids).sptlb NE 0) THEN CRISPEX_DISPLAYS_SP_REPLOT_AXES, event
  	IF (TOTAL(*(*(*info).winids).restlooptlb) NE 0) THEN $
      CRISPEX_DISPLAYS_RESTORE_LOOPSLAB_REPLOT_AXES, event
  	IF ((*(*info).winids).retrdettlb NE 0) THEN $
      CRISPEX_DISPLAYS_RETRIEVE_DET_LOOPSLAB_REPLOT_AXES, event
  	IF ((*(*info).winids).looptlb NE 0) THEN $
      CRISPEX_DISPLAYS_LOOPSLAB_REPLOT_AXES, event
  	IF ((*(*info).winids).refsptlb NE 0) THEN $
      CRISPEX_DISPLAYS_REFSP_REPLOT_AXES, event
  	CRISPEX_DRAW_SPECTRAL, event
  	CRISPEX_DRAW_TIMESLICES, event
  	IF (*(*info).winswitch).showint THEN CRISPEX_DRAW_INT, event
  ENDIF
END

;========================= READ HEADER PROCEDURE
PRO CRISPEX_IO_PARSE_HEADER, filename, HDR_IN=hdr_in, HDR_OUT=hdr_out, $
                         IMCUBE=imcube, SPCUBE=spcube, REFIMCUBE=refimcube, $
                         REFSPCUBE=refspcube, SJICUBE=sjicube, IDX_SJI=idx_sji, $
                         MASKCUBE=maskcube, CUBE_COMPATIBILITY=cube_compatibility,$
                         EXTEN_NO=exten_no, SINGLE_CUBE=single_cube
  ; Handles read-in of file header, running different parsing depending on
  ; CUBE_COMPATIBILITY setting   
  ; Start filling data header structure with header info from inputfile
  IF ~KEYWORD_SET(CUBE_COMPATIBILITY) THEN BEGIN
    ; Get header offset to data
    offset = CRISPEX_FITSPOINTER(filename, EXTEN_NO=exten_no, header, /SILENT)   
    ; Parse FITS header into key struct
    CRISPEX_READ_FITSHEADER, header, key, filename, $                    
      IMCUBE=imcube, SPCUBE=spcube, REFIMCUBE=refimcube, REFSPCUBE=refspcube, $
      SJICUBE=sjicube, VERBOSE=hdr_out.verbosity[1]
  ENDIF ELSE BEGIN
    offset = 512    ; Set header offset to data
    ; Parse old header into variables
    CRISPEX_READ_HEADER, filename, datatype=datatype, $         
                         dims=dims, nx=nx, ny=ny, nt=nt, endian=endian, $
                         stokes=stokes, ns=ns, diagnostics=diagnostics
  ENDELSE
  hdr_out = hdr_in                                              
  IF KEYWORD_SET(IMCUBE) THEN BEGIN                             
    ; Fill hdr_out parameters for IMCUBE
    hdr_out.imoffset = offset
    IF ~KEYWORD_SET(CUBE_COMPATIBILITY) THEN BEGIN              
      ; In case of FITS cube
      hdr_out.imtype = key.datatype     &  hdr_out.imnt = key.nlp * key.nt * key.ns
      hdr_out.nx = key.nx               &  hdr_out.dx = key.dx
      hdr_out.ny = key.ny               &  hdr_out.dy = key.dy
      hdr_out.imns = key.ns             &  hdr_out.ns = key.ns
      hdr_out.nlp = key.nlp             &  hdr_out.mainnt = key.nt
      hdr_out.xpix = key.xpix           &  hdr_out.ypix = key.ypix
      hdr_out.xval = key.xval           &  hdr_out.yval = key.yval
      hdr_out.blabel = key.btype        &  hdr_out.bunit = key.bunit
      hdr_out.xlabel = key.xlab         &  hdr_out.xunit = key.xunit     
      hdr_out.ylabel = key.ylab         &  hdr_out.yunit = key.yunit
      hdr_out.tlabel = key.tlab         &  hdr_out.tunit = key.tunit
      hdr_out.lplabel = key.lplab       &  hdr_out.lpunit = key.lpunit
      hdr_out.dt = key.dt               &  hdr_out.single_cube[0] = key.nlp
      hdr_out.wcs_set = key.wcs_set     &  hdr_out.imstokes = key.stokes         
      wcs_main = key.wcs_str
      ; Check for scaled integer
      hdr_out.imbscale = key.bscale     &  hdr_out.imbzero = key.bzero
      hdr_out.imscaled = ((key.bscale NE 1.) AND (key.bscale NE 0.) AND (key.datatype EQ 2)) 
      lc = key.lc
      hdr_out.obsid = STRTRIM(key.obsid,2)
      hdr_out.date_obs_main = key.date_obs
      hdr_out.startobs_main = key.startobs
      utc_main = key.utc_sel
      utc_full_main = key.utc_full
      date_main = key.date_sel
      date_full_main = key.date_full
      hdr_out = CREATE_STRUCT(hdr_out, 'lps', key.lam, 'lc', lc)
      ; Handle spectral windows, if present
      hdr_out.ndiagnostics = key.ndiagnostics
      diagnostics = key.diagnostics
      wstart = key.wstart
      wwidth = key.wwidth
      twave = key.twave
      tarr_main = key.tarr_sel
      tarr_full_main = key.tarr_full
      update_tfull_main = key.update_tfull_dims
      tfull_dims_main = update_tfull_main * $
        [hdr_out.nx-1, hdr_out.nlp-1, hdr_out.ns-1, hdr_out.mainnt-1]
      toffset_main = key.tini_col
      headers = key.headers
      hdr_out.instr_main = key.instrument
    ENDIF ELSE BEGIN       ; In case of compatibility mode
      hdr_out.imtype = datatype         &  hdr_out.imendian = endian
      hdr_out.nx = nx                   &  hdr_out.dx = 0.0592
      hdr_out.ny = ny                   &  hdr_out.dy = 0.0592
      hdr_out.imns = ns                 &  hdr_out.ns = ns
      hdr_out.imstokes = stokes         &  hdr_out.imnt = nt
      ndiagnostics = N_ELEMENTS(diagnostics)
      CRISPEX_IO_PARSE_SINGLE_CUBE, single_cube, HDR_IN=hdr_out, $
        HDR_OUT=hdr_out,/MAIN
      IF (hdr_out.dt EQ 0) THEN $
        tarr_main = FINDGEN(hdr_out.mainnt) $
      ELSE $
        tarr_main = FINDGEN(hdr_out.mainnt) * hdr_out.dt
      tarr_full_main = FLTARR(1,1,1,hdr_out.mainnt)
      tarr_full_main[0,0,0,*] = tarr_main
      utc_main = tarr_main
      utc_full_main = tarr_full_main
      date_main = REPLICATE('N/A',hdr_out.mainnt)
      date_full_main = REPLICATE('N/A',1,1,1,hdr_out.mainnt)
      update_tfull_main = [0,0,0,1]
      tfull_dims_main = update_tfull_main * [0, 0, 0, hdr_out.mainnt-1]
      toffset_main = 0
      IF (ndiagnostics GT 0) THEN BEGIN
        diagnostics = STRTRIM(STRSPLIT(STRMID(diagnostics,1,$
          STRLEN(diagnostics)-2),',',/EXTRACT),2)
        hdr_out.ndiagnostics = ndiagnostics
        wstart = INDGEN(ndiagnostics)
        wwidth = REPLICATE(1,ndiagnostics)
      ENDIF ELSE BEGIN
        wstart = 0
        wwidth = hdr_out.nlp
        hdr_out.ndiagnostics = 1
        diagnostics = 'CRISP'
      ENDELSE
      twave = 0
      headers = PTR_NEW('')
      wcs_main = 0
    ENDELSE
    hdr_out = CREATE_STRUCT(hdr_out, 'diagnostics', diagnostics, $
      'diag_start', wstart, 'diag_width', wwidth, 'toffset_main', toffset_main,$
      'twave', twave, 'hdrs_main', headers, 'wcs_main', wcs_main, $
      'tarr_main', tarr_main, 'tarr_full_main', tarr_full_main, $
      'utc_main', utc_main, 'utc_full_main', utc_full_main, $
      'date_main', date_main, 'date_full_main', date_full_main, $
      'tfull_dims_main', tfull_dims_main, $
      'update_tfull_main', update_tfull_main)
  ENDIF ELSE IF KEYWORD_SET(SPCUBE) THEN BEGIN                  
    ; Fill hdr parameters for SPCUBE
    hdr_out.spoffset = offset
    IF ~KEYWORD_SET(CUBE_COMPATIBILITY) THEN BEGIN              
      ; In case of FITS cube
      hdr_out.sptype = key.datatype     &  hdr_out.spnt = key.nx * key.ny * key.ns
      hdr_out.spns = key.ns             &  hdr_out.spstokes = key.stokes
      ; Check for scaled integer
      hdr_out.spbscale= key.bscale      &  hdr_out.spbzero = key.bzero
      hdr_out.spscaled = ((key.bscale NE 1.) AND (key.bscale NE 0.) AND (key.datatype EQ 2)) 
    ENDIF ELSE BEGIN                                            
      ; In case of compatibility mode
      hdr_out.sptype = datatype         &  hdr_out.spendian = endian
      hdr_out.nlp = nx                  &  hdr_out.mainnt = ny
      hdr_out.spns = ns                 &  hdr_out.spstokes = stokes
      hdr_out.spnt = nt
    ENDELSE
  ENDIF ELSE IF KEYWORD_SET(REFIMCUBE) THEN BEGIN               
    ; Fill hdr parameters for REFIMCUBE
    hdr_out.refimoffset = offset
    wheretag = WHERE(TAG_NAMES(hdr_out) EQ 'TARR_REF', count)
    IF (count NE 0) THEN $
      ; Delete potentially conflicting tags from structure...
      hdr_out = CRISPEX_TAG_DELETE(hdr_out,$
        ['REFLPS','REFLC','REFSPEC','REFSPECTRUM','REFMS','V_DOP_REF',$
        'REFDIAGNOSTICS','REFDIAG_START','REFDIAG_WIDTH', $
        'TARR_REF','TARR_FULL_REF','TOFFSET_REF','TWAVE_REF','WCS_REF',$
        'UTC_REF','UTC_FULL_REF','DATE_REF','DATE_FULL_REF','TSEL_REF',$
        'UPDATE_TFULL_REF', 'TFULL_DIMS_REF', $
        'HDRS_REF','XO_REF','XI_REF','YO_REF','YI_REF', $
        'STOKES_LABELS_REF','STOKES_SELECT_REFSP', 'TSEL_SCALING_REF'])
    IF ~KEYWORD_SET(CUBE_COMPATIBILITY) THEN BEGIN              
      ; In case of FITS cube
      hdr_out.refimtype = key.datatype  
      hdr_out.refimnt = key.nlp * key.nt * key.ns
      hdr_out.refnx = key.nx            &  hdr_out.refdx = key.dx
      hdr_out.refny = key.ny            &  hdr_out.refdy = key.dy
      hdr_out.xpix_ref = key.xpix       &  hdr_out.ypix_ref = key.ypix
      hdr_out.xval_ref = key.xval       &  hdr_out.yval_ref = key.yval
      hdr_out.refnlp = key.nlp          &  hdr_out.refnt = key.nt
      hdr_out.refns = key.ns            &  hdr_out.refdt = key.dt
      hdr_out.refbunit = key.bunit      &  hdr_out.refblabel = key.btype
      hdr_out.refxlabel = key.xlab      &  hdr_out.refxunit = key.xunit
      hdr_out.refylabel = key.ylab      &  hdr_out.refyunit = key.yunit
      hdr_out.reflplabel = key.lplab    &  hdr_out.reflpunit = key.lpunit
      hdr_out.ref_wcs_set = key.wcs_set &  hdr_out.refimstokes = key.stokes
      hdr_out.refimns = key.ns
      wcs_ref = key.wcs_str
      ; Check for scaled integer
      hdr_out.refimbscale= key.bscale      &  hdr_out.refimbzero = key.bzero
      hdr_out.refimscaled = ((key.bscale NE 1.) AND (key.bscale NE 0.) AND (key.datatype EQ 2)) 
      reflc = key.lc
      hdr_out.date_obs_ref = STRTRIM(key.date_obs,2)
      hdr_out.startobs_ref = key.startobs
      utc_ref = key.utc_sel
      utc_full_ref = key.utc_full
      date_ref = key.date_sel
      date_full_ref = key.date_full
      ; Handle spectral windows, if present
      hdr_out.nrefdiagnostics = key.ndiagnostics
      diagnostics = key.diagnostics
      wstart = key.wstart
      wwidth = key.wwidth
      twave = key.twave
      tarr_ref = key.tarr_sel
      tarr_full_ref = key.tarr_full
      update_tfull_ref = key.update_tfull_dims
      tfull_dims_ref = update_tfull_ref * $
        [hdr_out.refnx-1, hdr_out.refnlp-1, hdr_out.refns-1, hdr_out.refnt-1]
      toffset_ref = key.tini_col
      headers = key.headers
      reflps = key.lam
      hdr_out = CREATE_STRUCT(hdr_out, 'reflps', reflps, 'reflc', reflc)
    ENDIF ELSE BEGIN                                            
      ; In case of compatibility mode
      hdr_out.refimtype = datatype      &  hdr_out.refimendian = endian
      hdr_out.refnx = nx                &  hdr_out.refdx = 0.0592
      hdr_out.refny = ny                &  hdr_out.refdy = 0.0592
      hdr_out.refimns = ns              &  hdr_out.refns = ns
      hdr_out.refimstokes = stokes      &  hdr_out.refimnt = nt              
      IF (FLOOR(hdr_out.refimnt/FLOAT(hdr_out.mainnt)) EQ $
          hdr_out.refimnt/FLOAT(hdr_out.mainnt)) THEN $
        hdr_out.refnt = hdr_out.mainnt ELSE hdr_out.refnt = 1L
      hdr_out.refnlp = $
        LONG(hdr_out.refimnt/(FLOAT(hdr_out.refnt)*FLOAT(hdr_out.refns)))
      CRISPEX_IO_PARSE_SINGLE_CUBE, single_cube, HDR_IN=hdr_out, $
        HDR_OUT=hdr_out,/REFERENCE
      IF (hdr_out.refdt EQ 0) THEN $
        tarr_ref = FINDGEN(hdr_out.refnt) $
      ELSE $
        tarr_ref = FINDGEN(hdr_out.refnt) * hdr_out.dt
      tarr_full_ref = FLTARR(1,1,1,hdr_out.refnt)
      tarr_full_ref[0,0,0,*] = tarr_ref
      utc_ref = tarr_ref
      utc_full_ref = tarr_full_ref
      date_ref = REPLICATE('N/A',hdr_out.refnt)
      date_full_ref = REPLICATE('N/A',1,1,1,hdr_out.refnt)
      update_tfull_ref = [0,0,0,1]
      tfull_dims_ref = update_tfull_ref * [0, 0, 0, hdr_out.refnt-1]
      toffset_ref = 0
      ndiagnostics = N_ELEMENTS(diagnostics)
      IF (ndiagnostics GT 0) THEN BEGIN
        diagnostics = STRTRIM(STRSPLIT(STRMID(diagnostics,1,$
          STRLEN(diagnostics)-2),',',/EXTRACT),2)
        hdr_out.nrefdiagnostics = ndiagnostics
        wstart = INDGEN(ndiagnostics)
        wwidth = REPLICATE(1,ndiagnostics)
      ENDIF ELSE BEGIN
        wstart = 0
        wwidth = hdr_out.refnlp
        hdr_out.nrefdiagnostics = 1
        diagnostics = 'CRISP'
      ENDELSE
      twave = 0
      headers = PTR_NEW('')
      wcs_ref = 0
    ENDELSE
    hdr_out = CREATE_STRUCT(hdr_out, $;'reflps', reflps, 'reflc', reflc, $
      'refdiagnostics', diagnostics, $
      'refdiag_start', wstart, 'refdiag_width', wwidth, 'tarr_ref', tarr_ref, $
      'tarr_full_ref', tarr_full_ref, 'toffset_ref', toffset_ref, $
      'twave_ref', twave, 'hdrs_ref', headers, 'wcs_ref', wcs_ref, $
      'utc_ref', utc_ref, 'utc_full_ref', utc_full_ref, $
      'date_ref', date_ref, 'date_full_ref', date_full_ref,$
      'tfull_dims_ref', tfull_dims_ref, $
      'update_tfull_ref', update_tfull_ref)
  ENDIF ELSE IF KEYWORD_SET(REFSPCUBE) THEN BEGIN               
    ; Fill hdr parameters for REFSPCUBE
    hdr_out.refspoffset = offset
    IF ~KEYWORD_SET(CUBE_COMPATIBILITY) THEN BEGIN              
      ; In case of FITS cube
      hdr_out.refsptype = key.datatype  &  hdr_out.refspnt = key.nx * key.ny * key.ns
      hdr_out.refspns = key.ns          &  hdr_out.refspstokes = key.stokes
      ; Check for scaled integer
      hdr_out.refspbscale= key.bscale      &  hdr_out.refspbzero = key.bzero
      hdr_out.refspscaled = ((key.bscale NE 1.) AND (key.bscale NE 0.) AND (key.datatype EQ 2)) 
    ENDIF ELSE BEGIN                                            
      ; In case of compatibility mode
      hdr_out.refsptype = datatype      &  hdr_out.refspendian = endian
      hdr_out.refnlp = nx               &  hdr_out.refnt = ny
      hdr_out.refspnx = nx              &  hdr_out.refspny = ny
      hdr_out.refspns = ns              &  hdr_out.refspstokes = stokes
      hdr_out.refspnt = nt
    ENDELSE
  ENDIF ELSE IF KEYWORD_SET(SJICUBE) THEN BEGIN                
    ; Fill hdr parameters for SJICUBE
      hdr_out.sjioffset[idx_sji] = offset
      hdr_out.sjitype[idx_sji] = key.datatype    &  hdr_out.sjint[idx_sji] = key.nt
      hdr_out.sjinx[idx_sji] = key.nx            &  hdr_out.sjiny[idx_sji] = key.ny
      hdr_out.sjidx[idx_sji] = key.dx            &  hdr_out.sjidy[idx_sji] = key.dy
      hdr_out.xpix_sji[idx_sji] = key.xpix       &  hdr_out.ypix_sji[idx_sji] = key.ypix
      hdr_out.xval_sji[idx_sji] = key.xval       &  hdr_out.yval_sji[idx_sji] = key.yval
      hdr_out.sjibunit[idx_sji] = key.bunit      
      hdr_out.sjibscale[idx_sji] = key.bscale    &  hdr_out.sjibzero[idx_sji] = key.bzero
      hdr_out.sji_wcs_set[idx_sji] = key.wcs_set
      ; Check for scaled integer
      hdr_out.sjiscaled[idx_sji] = ((key.bscale NE 1.) AND (key.datatype EQ 2)) 
      hdr_out.date_obs_sji[idx_sji] = STRTRIM(key.date_obs,2)
      *hdr_out.tarr_sji[idx_sji] = key.tarr_sel
      *hdr_out.hdrs_sji[idx_sji] = key.headers
      *hdr_out.wcs_sji[idx_sji] = key.wcs_str
      *hdr_out.utc_sji[idx_sji] = key.utc_sel
      *hdr_out.date_sji[idx_sji] = key.date_sel
  ENDIF ELSE IF KEYWORD_SET(MASKCUBE) THEN BEGIN                
    ; Fill hdr parameters for MASKCUBE
    hdr_out.maskoffset = offset
    IF ~KEYWORD_SET(CUBE_COMPATIBILITY) THEN BEGIN              
      ; In case of FITS cube
      hdr_out.masktype = key.datatype   &  hdr_out.masknt = key.nt
      hdr_out.masknx = key.nx           &  hdr_out.maskny = key.ny
    ENDIF ELSE BEGIN                                            
      ; In case of compatibility mode
      hdr_out.masktype = datatype       &  hdr_out.maskendian = endian
      hdr_out.masknx = nx               &  hdr_out.maskny = ny
      hdr_out.masknt = nt
    ENDELSE
  ENDIF
END

PRO CRISPEX_READ_FITSHEADER, header, key, filename, $
  IMCUBE=imcube, SPCUBE=spcube, REFIMCUBE=refcube, REFSPCUBE=refspcube, $
  SJICUBE=sjicube, VERBOSE=verbose
; Handle parsing of FITS file header
; Based on earlier PARSEHEADER.PRO, modification history:
;   v1.1 21-Sep-2012 Viggo Hansteen - first version
;   v1.2 26-Jan-2013 Mats Carlsson - works for both Bifrost and Iris cubes
;   v1.3 13-Feb-2013 Mats Carlsson 
; Incorporated functionality into CRISPEX on 29-May-2013 and extended subsequently
  hdr1 = ''   ; initialise header placeholders
  hdr2 = ''
  ; Get number of data axes
  nnaxis = SXPAR(header,'NAXIS')
  naxis = SXPAR(header,'NAXIS*')
  wcsaxes = SXPAR(header,'WCSAXES*')
  IF (wcsaxes EQ '') THEN wcsaxes = naxis
  ; Get number of extensions
  FITS_OPEN, filename, fcb
  next = fcb.nextend
  FITS_CLOSE, filename
  FREE_LUN, fcb.unit
  ; Determine cube type
  ctype = STRUPCASE(STRCOMPRESS(SXPAR(header,'CTYPE*'), /REMOVE_ALL))
  wherenx = (WHERE((ctype EQ 'X') OR (ctype EQ 'HPLN-TAN') OR $
                  (ctype EQ 'HPLN-TAB') OR (ctype EQ 'SOLARX') OR $
                  (ctype EQ 'SOLAR-X'), nwherenx))[0]
  whereny = (WHERE((ctype EQ 'Y') OR (ctype EQ 'HPLT-TAN') OR $
                  (ctype EQ 'HPLT-TAB') OR (ctype EQ 'SOLARY') OR $
                  (ctype EQ 'SOLAR-Y'), nwhereny))[0]
  wherenlp = (WHERE((ctype EQ 'WAVE') OR (ctype EQ 'WAVE-TAB') OR $
                  (ctype EQ 'Z'), nwherenlp))[0]
  wherens = (WHERE((ctype EQ 'STOKES'), nwherens))[0]
  wherent = (WHERE((ctype EQ 'TIME') OR (ctype EQ 'UTC--TAB'), nwherent))[0]
  ; Check for faulty input: should be 3D cube, should have spatial dimensions
  ; and basic order should be default (checked through first two dimensions)
  IF ((nwherenlp EQ 0) AND (nwherens EQ 0) AND (nwherent EQ 0)) $
    OR (nwherenx EQ 0) OR (nwhereny EQ 0) $
    OR (((wherenx NE 0) OR (whereny NE 1)) AND $
      (KEYWORD_SET(IMCUBE) OR KEYWORD_SET(REFIMCUBE) OR KEYWORD_SET(SJICUBE))) $
    OR (((wherenlp NE 0) OR (wherent NE 1)) AND $
      (KEYWORD_SET(SPCUBE) OR KEYWORD_SET(REFSPCUBE))) THEN BEGIN
    whichfile = (['main image', 'main spectral', 'reference image', $
      'reference spectral', 'slit-jaw image'])[KEYWORD_SET(SPCUBE) + $
      KEYWORD_SET(REFIMCUBE)*2 + KEYWORD_SET(REFSPCUBE)*3 + $
      KEYWORD_SET(SJICUBE)*4]
    MESSAGE, 'ERROR: Invalid data ordering encountered in file provided as '+$
      whichfile+' cube. Please check your input.', /INFO
    RETURN
  ENDIF
  
  ; Are we dealing with tabulated FITS files?
  tabfits = STRMID(ctype[wherenx], STRLEN(ctype[wherenx])-3, 3) EQ 'TAB'
  
  ; Get axes dimensions
  nx = naxis[wherenx]
  ny = naxis[whereny]
  ; Default nlp, ns and nt
  nlp = 1L
  nt = 1L
  ns = 1L
  IF (nwherenlp EQ 1) THEN nlp = naxis[wherenlp]
  IF (nwherent EQ 1) THEN nt = naxis[wherent] 
  IF (nwherens EQ 1) THEN ns = naxis[wherens]
  cslab = [' ']
  ; Convert FITS datatype to IDL datatype
  CASE SXPAR(header,'BITPIX') OF
          8:      datatype = 1
         16:      datatype = 2  
         32:      datatype = 3  
        -32:      datatype = 4 
        -64:      datatype = 5 
          8:      datatype = 7
         16:      datatype = 12
         32:      datatype = 13
         64:      datatype = 14
          ELSE:   BEGIN
            MESSAGE,'ERROR: Illegal Image Datatype',/CONT
            datatype = -1
          ENDELSE
       endcase
  ; Read in header keywords      
  cdelt = SXPAR(header,'CDELT*')
  crpix = SXPAR(header,'CRPIX*')
  crval = SXPAR(header,'CRVAL*')
  cunit = SXPAR(header,'CUNIT*')
  btype = STRTRIM(SXPAR(header,'BTYPE'),2)
  bunit = STRTRIM(SXPAR(header,'BUNIT'))
  ; Get necessary info to process scaled data
  bscale= SXPAR(header,'BSCALE')
  bzero = SXPAR(header,'BZERO')
  ; Assign values to variables
  dx = cdelt[wherenx]
  dy = cdelt[whereny]
  xpix = crpix[wherenx]-1  ; Switch FITS->IDL pixel convention
  ypix = crpix[whereny]-1  ; Switch FITS->IDL pixel convention
  xval = crval[wherenx]
  yval = crval[whereny]
  pc1 = SXPAR(header,'PC1_*')
  wcs_set = (pc1[0] NE 0.)
  IF wcs_set THEN BEGIN
    ; Functions using the wcs_str already take care of the FITS->IDL pixel
    ; convention switch
    wcs = FITSHEAD2WCS(header, FILENAME=filename) 
    ; Grab the subset that only covers the first two dimensions
    wcs_str = {coord_type:wcs.coord_type, wcsname:wcs.wcsname, $
      naxis:wcs.naxis[0:1], variation:wcs.variation, compliant:wcs.compliant, $
      projection:wcs.projection, ix:wcs.ix, iy:wcs.iy, $
      crpix:wcs.crpix[0:1], crval:wcs.crval[0:1], ctype:wcs.ctype[0:1], $
      cname:wcs.cname[0:1], cunit:wcs.cunit[0:1], $
      cdelt:wcs.cdelt[0:1], pc:wcs.pc[0:1, 0:1], simple:wcs.simple, $
      time:wcs.time, position:wcs.position};, spectrum:wcs.spectrum}
  ENDIF ELSE $ 
    wcs_str = 0

  ; Get timing arrays
  ; Default dummy variables
  nx_dum = 1
  nlp_dum = 1
  IF tabfits THEN BEGIN
    ; Assume spatial coordinates are orthogonal to the rest
    ; - If tuning instrument: time independent of spatial coordinates, but
    ;   dependent on wavelength and polarisation
    ; - If (scanning) slit spectrograph: time independent of wavelength, but
    ;   dependent on spatial coordinate and polarisation
    ; Distinguish between those by checking the time for the first and last
    ; x-coordinate
    wcs.naxis[wherenx] = nx_dum
    wcs.naxis[whereny] = 1
    tabcoord4time = WCS_GET_COORD(wcs)
    wcs.naxis[wherenx] = 1
    wcs.naxis[whereny] = 1
    wcs.naxis[wherent] = 1
    ns_temp = wcs.naxis[wherens]
    wcs.naxis[wherens] = 1
    tabcoord4wave = WCS_GET_COORD(wcs)
    nlp_dum = nlp
    wcs.naxis[wherens] = ns_temp
    wcs.naxis[wherenlp] = 1
    tabcoord4stokes = WCS_GET_COORD(wcs)
  ENDIF ELSE IF ~KEYWORD_SET(SJICUBE) THEN $
    nx_dum = nx
  ; Get OBSID, DATE_OBS and STARTOBS
  obsid = SXPAR(header,'OBSID')
  date_obs = STRTRIM(SXPAR(header,'DATE_OBS'),2)
  startobs = STRTRIM(SXPAR(header,'STARTOBS'),2)
  instrument = STRUPCASE(STRCOMPRESS(SXPAR(header, 'INSTRUME'), /REMOVE_ALL))
  ; Process timing
  IF (nwherent EQ 1) THEN BEGIN
    dt = cdelt[wherent]
    tlab = ctype[wherent]
    tunit = STRTRIM(cunit[wherent],2)
  ENDIF ELSE BEGIN
    dt = 0
    tlab = 't'
    tunit = 's' ; Assume default timing in seconds
  ENDELSE
  tini_col = 0    ; Default raster timing column
  ; REFORM() as a failsafe against trailing 1-element dimensions
  tarr_full = REFORM(DBLARR(nx_dum,nlp_dum,ns,nt),nx_dum,nlp_dum,ns,nt)
  update_tfull = SIZE(tarr_full, /DIM) NE 1
  IF tabfits THEN BEGIN
    lpini_col = FLOOR(nlp/2.)
    IF KEYWORD_SET(SPCUBE) OR KEYWORD_SET(REFSPCUBE) THEN $
      tarr_full[0,*,*,*] = REFORM(tabcoord4time[wherent,*,*,*,0,0]) $
    ELSE $
      tarr_full[0,*,*,*] = REFORM(tabcoord4time[wherent,0,0,*,*,*])
    tarr_sel = REFORM(tarr_full[tini_col,lpini_col,0,*])
  ENDIF ELSE BEGIN
    IF ~KEYWORD_SET(SJICUBE) THEN BEGIN
      ; Get time array (assuming each raster is co-temporal)
      IF ((nt GE 1) AND (next GE 2)) THEN BEGIN
        tarr = READFITS(filename, hdr2, EXTEN_NO=2, SILENT=~KEYWORD_SET(VERBOSE))
        ntarrdims = SIZE(tarr,/N_DIMENSIONS)
        ; Handle IRIS (typically 2D array but may be single-repeat raster)
        IF ((ntarrdims EQ 2) OR (STRCMP(instrument,'IRIS') AND (nx GT 1))) THEN $
          tarr_full[*,0,0,*] = tarr  $
        ELSE BEGIN
          ; Restrict first dimension tarr_full and adjust update_tfull
          tarr_full = tarr_full[0,*,*,*]
          update_tfull = SIZE(tarr_full, /DIM) NE 1
          tarr_full[0,0,0,*] = tarr
        ENDELSE
        ; Determine initial tarr_sel
        tval = SXPAR(header, 'CRVAL4')    ; tini_col = toffset_main/ref defaults to CRVAL4
        dum = MIN(ABS(tarr-tval),wheretval, /NAN)
        IF (wheretval EQ -1) THEN BEGIN
          nrasterpos = (SIZE(tarr))[ntarrdims-1]
          tini_col = FLOOR(nrasterpos/2.)
        ENDIF ELSE $
          tini_col = (ARRAY_INDICES(tarr,wheretval))[0]
        IF ((ntarrdims EQ 2) OR (STRCMP(instrument,'IRIS') AND (nx GT 1))) THEN $
          tarr_sel = REFORM(tarr[tini_col,*]) $
        ELSE $
          tarr_sel = tarr
      ENDIF ELSE BEGIN
        tarr_sel = [0] 
        tarr_full = 0
      ENDELSE
    ENDIF ELSE BEGIN
      ; Get timing array for the SJI cube
      offsetarray = READFITS(filename, hdr1, EXTEN_NO=1, SILENT=~KEYWORD_SET(VERBOSE))
      tarr_sel = REFORM(offsetarray[0,*]) ; TIME
      tarr_full[0,0,0,*] = tarr_sel
    ENDELSE
  ENDELSE
  ; Determine tfactor and set time units to seconds
  common_tunit = [(tunit EQ 's'),(tunit EQ 'ms'),(tunit EQ 'hs')]
  where_common_tunit = (WHERE(common_tunit EQ 1, count))[0]
  IF (count GT 0) THEN $
    tfactor = ([1,0.001,100.])[where_common_tunit] $
  ELSE $
    tfactor = 1.
  tunit = 's'
  tarr_sel *= tfactor     ; Get tarr_sel in seconds
  tarr_full *= tfactor    ; Same for tarr_full
  ; Failsafe against tarr_raster with nt unique values (instead of nt*nx)
  ;IF ((N_ELEMENTS(UNIQ(tarr_full)) EQ nt) OR $
  ;    (SIZE(tarr_full,/N_DIMENSIONS) EQ 0)) THEN $
  ;  tarr_full = tarr_sel $
  ;ELSE IF (SIZE(tarr_full,/N_DIMENSIONS) NE 0) THEN $
  ;  tarr_full *= tfactor

  ; Set defaults for UTC and Date arrays
  utc_sel = tarr_sel
  utc_full = tarr_full
  date_sel = 'N/A'
  date_full = 'N/A'
  ; IF DATE_OBS or STARTOBS is defined, derive the UTC (raster) time array
  IF (date_obs NE '0') OR (startobs NE '0') THEN BEGIN
    utc_full = STRARR(nx_dum, nlp_dum, ns, nt)
    date_full = STRARR(nx_dum, nlp_dum, ns, nt)
    utc_sel = STRARR(nt)
    date_sel = STRARR(nt)
    ; Failsafe against non-existing STARTOBS
    IF (startobs NE '0') THEN $
      orig_str = STR2UTC(startobs) $
    ELSE $
      orig_str = STR2UTC(date_obs)
    IF (tabfits EQ 0) THEN BEGIN
      ; Ensure that tarr_sel and tarr_full represent actual times
      tarr_sel += orig_str.time/1000.     ; orig_str.time is in milliseconds
      tarr_full += orig_str.time/1000.
    ENDIF 
    ; Get timing in UTC; convert to milliseconds for UTC2STR function
    dayinms = 86400000    ; Full day in milliseconds
    tarr_sel_inms = LONG(tarr_sel*1000*tfactor)
    IF (nt EQ 1) THEN tarr_sel_inms = tarr_sel_inms[0]  ; Failsafe
    tarr_full_inms = LONG(tarr_full*1000*tfactor)
    ; Create new time structure and save time to utc_sel, date to date_sel
    new_str_sel = REPLICATE({mjd:0L, time:0L}, nt)
    new_str_sel.mjd = orig_str.mjd+(tarr_sel_inms GT dayinms)
    new_str_sel.time = tarr_sel_inms MOD dayinms
    utc_sel = UTC2STR(new_str_sel, /TIME_ONLY)
    date_sel = UTC2STR(new_str_sel, /DATE_ONLY)
    ; Do the same for the full multi-dimensional time and arrays
    new_str_full = REPLICATE({mjd:0L, time:0L}, nx_dum, nlp_dum, ns, nt)
    new_str_full.mjd = orig_str.mjd+(tarr_full_inms GT dayinms)
    new_str_full.time = tarr_full_inms MOD dayinms
    utc_full = UTC2STR(new_str_full, /TIME_ONLY)
    date_full = UTC2STR(new_str_full, /DATE_ONLY)
  ENDIF 

  ; Determine plot labels
  xlab = STRTRIM(ctype[wherenx],2)
  ylab = STRTRIM(ctype[whereny],2)
  xunit = STRTRIM(cunit[wherenx],2)
  yunit = STRTRIM(cunit[whereny],2)
  ; set failse defaults
  lplab = ''  
  lpunit = ''
  stokes = '' 
  lam = 0.
  lc = 0
  twave = ''
  wstart = 0
  wwidth = nlp
  whereselect = 0
  ndiagnostics = 1
  diagnostics = btype
  IF (nwherenlp EQ 1) THEN BEGIN
    lplab = STRTRIM(ctype[wherenlp],2)
    lpunit = STRTRIM(cunit[wherenlp],2)

    ; Determine spectral parameters
    IF tabfits THEN BEGIN
      stokes_labels = ['I','Q','U','V']
      IF KEYWORD_SET(SPCUBE) OR KEYWORD_SET(REFSPCUBE) THEN BEGIN
        lam = REFORM(tabcoord4wave[wherenlp,*,0,0,0,0]) 
        stokes_set = REFORM(tabcoord4stokes[wherens,0,0,*,0,0])-1
      ENDIF ELSE BEGIN
        lam = REFORM(tabcoord4wave[wherenlp,0,0,*,0,0]) 
        stokes_set = REFORM(tabcoord4stokes[wherens,0,0,0,*,0])-1
      ENDELSE
      stokes = '['+STRJOIN(stokes_labels[stokes_set],',')+']'
    ENDIF ELSE BEGIN
      IF (N_PARAMS() EQ 3) THEN BEGIN
        lam = READFITS(filename,hdr1,EXTEN_NO=1,SILENT=~KEYWORD_SET(VERBOSE))
      ENDIF ELSE BEGIN
        lam = (FINDGEN(nlp)+1-crpix[wherenlp])*cdelt[wherenlp]+crval[wherenlp]
      ENDELSE
    ENDELSE
    lcval = crval[wherenlp]
    lc = (WHERE(lam EQ lcval, count))[0]
    IF (count NE 1) THEN lc = 0
    ; Determine number of diagnostics
    ndiagnostics = SXPAR(header,'NWIN')
    IF (ndiagnostics GT 0) THEN BEGIN
      wstart = SXPAR(header,'WSTART*')
      wwidth = SXPAR(header,'WWIDTH*')
      wdesc = SXPAR(header,'WDESC*')
      whereselect = WHERE(wdesc NE '', count)
      IF (count GT 0) THEN BEGIN
        wstart = wstart[whereselect]
        wwidth = wwidth[whereselect]
        diagnostics = wdesc[whereselect]
      ENDIF ELSE diagnostics = wdesc
    ENDIF ELSE ndiagnostics = 1
    twave = SXPAR(header,'TWAVE*')
    IF (count GT 0) THEN $
      twave  = twave[whereselect]
  ENDIF 
  ; Get third header too, even if not used in CRISPEX
  IF KEYWORD_SET(SJICUBE) THEN $
    dummy = READFITS(filename, hdr2, EXTEN_NO=2, SILENT=~KEYWORD_SET(VERBOSE))
  ; Initialise headers variable
  headers = [PTR_NEW(header),PTR_NEW(hdr1),PTR_NEW(hdr2)]
  ;
  key = {nx:nx,ny:ny,nlp:nlp,nt:nt,ns:ns,cslab:cslab, $
       datatype:datatype,dx:dx,dy:dy,dt:dt,lam:lam,lc:lc, $
       xpix:xpix, ypix:ypix, xval:xval, yval:yval, $
       wcs_set:wcs_set, wcs_str:wcs_str, $
       tarr_sel:tarr_sel, tini_col:tini_col, $
       tarr_full:tarr_full, utc_full:utc_full, date_full:date_full, $
       xlab:xlab,ylab:ylab,lplab:lplab,tlab:tlab, $
       btype:btype,bunit:bunit, bscale:bscale, bzero:bzero, $ 
       xunit:xunit,yunit:yunit,lpunit:lpunit,tunit:tunit,stokes:stokes,$
       wstart:wstart, wwidth:wwidth, diagnostics:diagnostics, $
       ndiagnostics:ndiagnostics, twave:twave, headers:headers, obsid:obsid, $
       date_obs:date_obs, startobs:startobs, instrument:instrument, $
       utc_sel:utc_sel, date_sel:date_sel, update_tfull_dims:update_tfull $
       }
END

PRO CRISPEX_READ_HEADER, filename, header=header, datatype=datatype, dims=dims,$
      nx=nx, ny=ny, nt=nt, endian=endian, stokes=stokes, ns=ns, $
      diagnostics=diagnostics
; Handles the read in of the header of the input files
	OPENR, lun, filename, /GET_LUN
	rec	= ASSOC(lun, BYTARR(512,/NOZERO))	&	header	= STRING(rec[0])
	FREE_LUN, lun
	len	= STRLEN(header)

	search	= 'datatype='	&	pos	= STRPOS(header, search)
	IF pos EQ -1 THEN BEGIN
		MESSAGE, /INFO, 'Unknown datatype!'
		PRINT, 'Header: '+header
		RETALL
	ENDIF
	datatype= LONG( STRMID(header, pos + STRLEN(search), 1) )
	search	= 'dims='	&	pos	= STRPOS(header, search)
	IF pos EQ -1 THEN BEGIN
		MESSAGE, /INFO, 'Unknown number of dimensions!'
		PRINT, 'Header: '+header
		RETALL
	ENDIF
	dims	= LONG( STRMID(header, pos + STRLEN(search), 1) )
	IF (dims LT 2) OR (dims GT 3) THEN BEGIN
		MESSAGE, /INFO, 'Number of dimensions not supported!'
		PRINT, 'Dimensions: '+dims
		RETALL
	ENDIF
	search	= 'nx='		&	pos	= STRPOS(header, search)
	IF pos EQ -1 THEN BEGIN
		MESSAGE, /INFO, 'Unknown number of pixels in x-direction!'
		PRINT, 'Header: '+header
		RETALL
	ENDIF
	pos1	= STRPOS(header, ',', pos)
	nx	= LONG( STRMID(header, pos + STRLEN(search), pos1-pos) )
	search	= 'ny='		&	pos	= STRPOS(header, search)
	IF pos EQ -1 THEN BEGIN
		MESSAGE, /INFO, 'Unknown number of pixels in y-direction!'
		PRINT, 'Header: '+header
		RETALL
	ENDIF
	pos1	= STRPOS(header, ',', pos)
	ny	= LONG( STRMID(header, pos + STRLEN(search), pos1-pos) )
	search	= 'nt='		&	pos	= STRPOS(header, search)
	IF pos EQ -1 THEN BEGIN
		MESSAGE, /INFO, 'Unknown number of pixels in t-direction!'
		PRINT, 'Header: '+header
		RETALL
	ENDIF
	pos1	= STRPOS(header, ',', pos)
	nt	= LONG( STRMID(header, pos + STRLEN(search), pos1-pos) )
	search	= 'endian='	&	pos	= STRPOS(header, search)
	IF pos EQ -1 THEN BEGIN
		MESSAGE, /INFO, 'Unknown endianness!'
		PRINT, 'Header: '+header
		RETALL
	ENDIF
	endian	= STRMID(header, pos + STRLEN(search), 1)
	search	= 'ns='	&	pos	= STRPOS(header, search)
	IF pos EQ -1 THEN ns = 1 ELSE ns = STRMID(header, pos + STRLEN(search), 1)
	search	= 'stokes='	&	pos	= STRPOS(header, search)
	IF pos EQ -1 THEN stokes = ['I'] ELSE stokes = STRMID(header, pos + STRLEN(search), 2*ns+1)
	search	= 'diagnostics='	&	pos	= STRPOS(header, search)
	pos1	= STRPOS(header,']',pos)
	IF pos NE -1 THEN diagnostics = STRMID(header, pos + STRLEN(search), pos1-pos-STRLEN(search)+1)
END
 
;========================= RESTORE LOOPS PROCEDURES
PRO CRISPEX_RESTORE_LOOPS_MAIN, event
; Start the restore loops procedures, opens the menu if CLSAV files are present
; or otherwise returns an error message 
  WIDGET_CONTROL, event.TOP, GET_UVALUE = info
	IF (TOTAL(((*(*info).feedbparams).verbosity)[2:3]) GE 1) THEN $
    CRISPEX_VERBOSE_GET_ROUTINE, event
	(*(*info).loopswitch).restore_loops = event.SELECT
  IF event.SELECT THEN BEGIN
  	CRISPEX_FIND_CSAV, event, /ALLOW_SELECT_DIR
  	IF ((*(*info).restoreparams).cfilecount GT 0) THEN BEGIN
  		IF (*(*info).loopswitch).restore_loops THEN BEGIN
  			CRISPEX_RESTORE_LOOPS_MENU, event
  			WIDGET_CONTROL, (*(*info).ctrlscp).loop_overlay_button_ids[0], /SENSITIVE
  			WIDGET_CONTROL, (*(*info).ctrlscp).loop_overlay_button_ids[1], /SENSITIVE
  		ENDIF ELSE CRISPEX_RESTORE_LOOPS_MENU_CLOSE, event
  	ENDIF ELSE BEGIN
  		CRISPEX_WINDOW_OK, event,'ERROR!',$
        'No saved time slice (*csav) files found corresponding '+$
        'to the current data file. Unable to produce loop overlays.',$
  			OK_EVENT='CRISPEX_CLOSE_EVENT_WINDOW', BASE=tlb
  		(*(*info).winids).errtlb = tlb
  		WIDGET_CONTROL, (*(*info).ctrlscp).overlay_but, SET_BUTTON = 0
  	ENDELSE
  	IF (((*(*info).feedbparams).verbosity)[3] EQ 1) THEN $
      CRISPEX_VERBOSE_GET, event, [(*(*info).loopswitch).restore_loops],$
        labels=['Restoring loops']
  ENDIF
END

PRO CRISPEX_RESTORE_LOOPS_MENU, event, set_but_array
; Sets up the restored loops menu and reads in the loop points
	WIDGET_CONTROL, event.TOP, GET_UVALUE = info
	IF (TOTAL(((*(*info).feedbparams).verbosity)[2:3]) GE 1) THEN $
    CRISPEX_VERBOSE_GET_ROUTINE, event
	WIDGET_CONTROL,/HOURGLASS
	filenames = *(*(*info).restoreparams).cfiles
	filecount = (*(*info).restoreparams).cfilecount
	IF (N_ELEMENTS(set_but_array) NE filecount) THEN $
    *(*(*info).restoreparams).sel_loops = $
      INTARR((*(*info).restoreparams).cfilecount)
	eventval = INDGEN(filecount)
	base = WIDGET_BASE(TITLE = 'CRISPEX'+(*(*info).sesparams).instance_label+$
    ': Choose loop overlays', GROUP_LEADER = (*(*info).winids).root, $
    TLB_FRAME_ATTR = 1, /TLB_KILL_REQUEST_EVENTS)
	disp = WIDGET_BASE(base, /COLUMN)
	disp2 = WIDGET_BASE(disp, /COLUMN, /FRAME)
	sel_allnone = WIDGET_BASE(disp2, /ROW)
	sel_allnone_lab = WIDGET_LABEL(sel_allnone, VALUE = 'Select:', /ALIGN_LEFT)
	sel_allnone_buts = WIDGET_BASE(sel_allnone, /ROW, /EXCLUSIVE)
	(*(*info).ctrlsrestore).sel_all = $
    WIDGET_BUTTON(sel_allnone_buts, VALUE = 'All', $
    EVENT_PRO = 'CRISPEX_RESTORE_LOOPS_SEL_ALL')
	(*(*info).ctrlsrestore).sel_none = $
    WIDGET_BUTTON(sel_allnone_buts, VALUE = 'None', $
    EVENT_PRO = 'CRISPEX_RESTORE_LOOPS_SEL_NONE')
	disp_txt = REPLICATE('Display time slice ', filecount)
	list_values = ['Do not display any slice', disp_txt+STRTRIM(eventval,2)]
	(*(*info).ctrlsrestore).disp_list = WIDGET_COMBOBOX(sel_allnone, $
    VALUE = list_values, /DYNAMIC_RESIZE, $
    EVENT_PRO = 'CRISPEX_DISPLAYS_RESTORE_LOOPSLAB_SELECT')
	WIDGET_CONTROL, (*(*info).ctrlsrestore).sel_none, /SET_BUTTON
	IF (filecount GT 15) THEN $
    sel_buts = WIDGET_BASE(disp2, /COLUMN, /NONEXCLUSIVE,Y_SCROLL_SIZE = 425) $
  ELSE $
    sel_buts = WIDGET_BASE(disp2, /COLUMN, /NONEXCLUSIVE)
  ; Initialise variables
  *(*(*info).restoreparams).xp = PTRARR(filecount, /ALLOCATE_HEAP)
  *(*(*info).restoreparams).yp = PTRARR(filecount, /ALLOCATE_HEAP)
  *(*(*info).restoreparams).xr = PTRARR(filecount, /ALLOCATE_HEAP)
  *(*(*info).restoreparams).yr = PTRARR(filecount, /ALLOCATE_HEAP)
	*(*(*info).restoreparams).lp = LONARR(filecount)
	*(*(*info).restoreparams).ngaps = LONARR(filecount)
	*(*(*info).restoreparams).databounds = PTRARR(filecount, /ALLOCATE_HEAP)
	*(*(*info).restoreparams).wdatabounds = PTRARR(filecount, /ALLOCATE_HEAP)
  *(*(*info).loopsdata).rest_empty_slice = PTRARR(filecount, /ALLOCATE_HEAP)
	*(*(*info).restoreparams).imref = BYTARR(filecount)
  imfilename_noext = $
    STRMID(FILE_BASENAME((*(*info).dataparams).imfilename),0,$
    STRPOS(FILE_BASENAME((*(*info).dataparams).imfilename), '.', /REVERSE_SEARCH))
  refimfilename_noext = $
    STRMID(FILE_BASENAME((*(*info).dataparams).refimfilename),0,$
    STRPOS(FILE_BASENAME((*(*info).dataparams).refimfilename), '.', $
    /REVERSE_SEARCH))
  IF ((*(*info).dataparams).nsjifiles GE 1) THEN BEGIN
    sjifilename_noext = STRARR((*(*info).dataparams).nsjifiles) 
    FOR idx_sji=0,(*(*info).dataparams).nsjifiles-1 DO $
      sjifilename_noext[idx_sji] = $
        STRMID(FILE_BASENAME((*(*info).dataparams).sjifilename[idx_sji]),0,$
        STRPOS(FILE_BASENAME((*(*info).dataparams).sjifilename[idx_sji]), '.', $
        /REVERSE_SEARCH))
  ENDIF ELSE sjifilename_noext = ''
	FOR i=0,filecount-1 DO BEGIN
		IF (N_ELEMENTS(set_but_array) NE filecount) THEN $
      (*(*(*info).restoreparams).sel_loops)[i] = 0
		singlefilename = FILE_BASENAME((*(*(*info).restoreparams).cfiles)[i])
		name = 'sel_restore_but_'+STRTRIM(i,2)
		but_val = STRTRIM(i,2)+': '+singlefilename
		sel_but = WIDGET_BUTTON(sel_buts, VALUE = but_val, UVALUE = eventval[i], $
      EVENT_PRO = 'CRISPEX_RESTORE_LOOPS_MENU_EVENT', UNAME = name) 
		IF (N_ELEMENTS(set_but_array) GT 0) THEN $
      WIDGET_CONTROL, sel_but, SET_BUTTON = set_but_array[i]
		RESTORE,(*(*(*info).restoreparams).cfiles)[i]
    ; Failsafe against older saved files
    IF (N_ELEMENTS(ngaps) EQ 0) THEN BEGIN
      ngaps = 0
      databounds = -1
      wdatabounds = -1
    ENDIF
    ; Support for different saving methods of xp and yp points
		nel = N_ELEMENTS(SIZE(x_coords))						
		IF (nel EQ 5) THEN BEGIN
			xpcoords = REFORM(x_coords[0,*])
			ypcoords = REFORM(y_coords[0,*])
		ENDIF ELSE BEGIN
			xpcoords = x_coords
			ypcoords = y_coords
		ENDELSE
    ; Start filling variables
		*(*(*(*info).restoreparams).xp)[i] = xpcoords
		*(*(*(*info).restoreparams).yp)[i] = ypcoords
		*(*(*(*info).restoreparams).xr)[i] = x_loop_pts
		*(*(*(*info).restoreparams).yr)[i] = y_loop_pts
		(*(*(*info).restoreparams).lp)[i] = spect_pos
		(*(*(*info).restoreparams).ngaps)[i] = ngaps
		*(*(*(*info).restoreparams).databounds)[i] = databounds
		*(*(*(*info).restoreparams).wdatabounds)[i] = wdatabounds
    (*(*(*info).restoreparams).imref)[i] = $
      STRMATCH(singlefilename, imfilename_noext+'*', /FOLD_CASE) + $
      STRMATCH(singlefilename, refimfilename_noext+'*', /FOLD_CASE) * 2 * $
      (*(*info).dataswitch).reffile + $
      ; Switched around as sjifilename_noext may be an array
      TOTAL(STRMATCH(sjifilename_noext+'*', singlefilename, /FOLD_CASE)) * 3 * $
      (*(*info).dataswitch).sjifile
    ; Update user feedback
		initial_feedback = 'Processed save file '+STRTRIM(i,2)+': '+singlefilename
		CRISPEX_UPDATE_USER_FEEDBACK, event, title='Restoring loops...', var=i, $
      maxvar=filecount-1, feedback_text=initial_feedback
		IF (i EQ filecount-1) THEN CRISPEX_WINDOW_USER_FEEDBACK_CLOSE, event
	ENDFOR
  ; Add decision buttons
	decision_base = WIDGET_BASE(disp2,COLUMN=3,/GRID_LAYOUT,/ALIGN_CENTER)
	update_filelist = WIDGET_BUTTON(decision_base, VALUE = 'Update filelist', $
    EVENT_PRO = 'CRISPEX_RESTORE_LOOPS_UPDATE_FILELIST')
	(*(*info).ctrlsrestore).open_tanat = WIDGET_BUTTON(decision_base, $
    VALUE = 'Open in TANAT...', EVENT_PRO = 'CRISPEX_RESTORE_LOOPS_OPEN_TANAT')
	closebut = WIDGET_BUTTON(decision_base, VALUE = 'Close', $
    EVENT_PRO = 'CRISPEX_RESTORE_LOOPS_MENU_CLOSE')
  ; Realize widget window
	WIDGET_CONTROL, base, /REALIZE, $
    TLB_SET_XOFFSET=(*(*info).winsizes).lsxoffset, $
    TLB_SET_YOFFSET=(*(*info).winsizes).lswiny+1.5*(*(*info).winsizes).ydelta
	WIDGET_CONTROL, base, SET_UVALUE = info
	XMANAGER, 'CRISPEX', base, /NO_BLOCK
	(*(*info).winids).restoretlb = base
	IF (((*(*info).feedbparams).verbosity)[3] EQ 1) THEN $
    CRISPEX_VERBOSE_GET, event, [(*(*info).winids).restoretlb,filecount],$
      labels=['restoretlb','Restored loops']
END

PRO CRISPEX_RESTORE_LOOPS_MENU_EVENT, event
; Handles the selection of loops to be restored
	WIDGET_CONTROL, event.TOP, GET_UVALUE = info
	IF (TOTAL(((*(*info).feedbparams).verbosity)[2:3]) GE 1) THEN $
    CRISPEX_VERBOSE_GET_ROUTINE, event
	WIDGET_CONTROL, event.ID, GET_UVALUE = eventval
	(*(*(*info).restoreparams).sel_loops)[eventval] = ( (*(*(*info).restoreparams).sel_loops)[eventval] EQ 0) 
	IF (((*(*info).feedbparams).verbosity)[3] EQ 1) THEN $
    CRISPEX_VERBOSE_GET, event, [eventval,(*(*(*info).restoreparams).sel_loops)[eventval]], labels=['Loop ID','Loop selected']
	CRISPEX_RESTORE_LOOPS_BUTTON_CONDITION, event
	CRISPEX_DRAW, event
END

PRO CRISPEX_RESTORE_LOOPS_BUTTON_CONDITION, event
; Handles the update of buttons after selection
	WIDGET_CONTROL, event.TOP, GET_UVALUE = info
	IF (TOTAL(((*(*info).feedbparams).verbosity)[2:3]) GE 1) THEN $
    CRISPEX_VERBOSE_GET_ROUTINE, event
	condition = WHERE(*(*(*info).restoreparams).sel_loops EQ 1, count)
	WIDGET_CONTROL, (*(*info).ctrlsrestore).sel_none, SET_BUTTON = ABS((count GT 0)-1)
	WIDGET_CONTROL, (*(*info).ctrlsrestore).sel_all, SET_BUTTON = (count EQ (*(*info).restoreparams).cfilecount)
	IF (((*(*info).feedbparams).verbosity)[3] EQ 1) THEN $
    CRISPEX_VERBOSE_GET, event, [(((N_ELEMENTS(condition) GT 0) AND (TOTAL(condition) NE -1)) AND (N_ELEMENTS(condition) EQ (*(*info).restoreparams).cfilecount)),$
		ABS(((N_ELEMENTS(condition) GT 0) AND (TOTAL(condition) NE -1))-1),N_ELEMENTS(condition)-(TOTAL(condition) EQ -1)], labels=['All selected','None selected','Total selected']
END

PRO CRISPEX_RESTORE_LOOPS_MENU_CLOSE, event
; Handles the closing of the restored loops menu and clean-up of display afterwards
	WIDGET_CONTROL, event.TOP, GET_UVALUE = info
	IF (TOTAL(((*(*info).feedbparams).verbosity)[2:3]) GE 1) THEN $
    CRISPEX_VERBOSE_GET_ROUTINE, event
	IF ((*(*info).dispparams).t_range NE (*(*info).dataparams).nt) THEN $
    CRISPEX_DISPRANGE_T_RESET, event, /NO_DRAW
	IF ((*(*info).dispparams).lp_range NE (*(*info).dataparams).nlp) THEN $
    CRISPEX_DISPRANGE_LP_RESET, event, /NO_DRAW
	IF ((*(*info).dispparams).lp_ref_range NE (*(*info).dataparams).refnlp) THEN $
    CRISPEX_DISPRANGE_LP_RESET, event, /REFERENCE, /NO_DRAW
	WIDGET_CONTROL, (*(*info).ctrlscp).loop_overlay_button_ids[0], /SENSITIVE
	WIDGET_CONTROL, (*(*info).ctrlscp).loop_overlay_button_ids[1], /SENSITIVE
	(*(*info).loopswitch).restore_loops = 0
	(*(*info).restoreparams).disp_loopfile = '0'
	*(*(*info).restoreparams).disp_loopnr = -1
	IF (*(*info).winswitch).showrestloop THEN BEGIN
		FOR i=0,N_ELEMENTS(*(*(*info).winids).restlooptlb)-1 DO BEGIN
			WIDGET_CONTROL, (*(*(*info).winids).restlooptlb)[i], /DESTROY
			*(*(*(*info).loopsdata).rest_loopslice[i]) = 0
			*(*(*(*info).loopsdata).rest_loopslab[i]) = 0
			*(*(*(*info).loopsdata).rest_crossloc[i]) = 0
		ENDFOR
		(*(*info).winswitch).showrestloop = 0
		*(*(*info).winids).restlooptlb = 0
	ENDIF
	WIDGET_CONTROL, (*(*info).ctrlscp).overlay_but, SET_BUTTON = 0
	WIDGET_CONTROL, (*(*info).ctrlscp).lp_slider, /SENSITIVE
	IF (((*(*info).feedbparams).verbosity)[3] EQ 1) THEN $
    CRISPEX_VERBOSE_GET, event, [(*(*info).loopswitch).restore_loops,(*(*info).winids).restoretlb], labels=['Restoring loops','restoretlb was']
	CRISPEX_DRAW, event
	WIDGET_CONTROL, (*(*info).winids).restoretlb, /DESTROY
	(*(*info).winids).restoretlb = 0
END

PRO CRISPEX_RESTORE_LOOPS_SEL_ALL, event
; Handles selection of all restored loops
	WIDGET_CONTROL, event.TOP, GET_UVALUE = info
	IF (TOTAL(((*(*info).feedbparams).verbosity)[2:3]) GE 1) THEN $
    CRISPEX_VERBOSE_GET_ROUTINE, event
	*(*(*info).restoreparams).sel_loops = REPLICATE(1,(*(*info).restoreparams).cfilecount)
	FOR i=0,(*(*info).restoreparams).cfilecount-1 DO BEGIN
		name = 'sel_restore_but_'+STRTRIM(i,2)
		WIDGET_CONTROL, WIDGET_INFO(event.TOP, FIND_BY_UNAME = name), SET_BUTTON = 1
	ENDFOR		
	CRISPEX_DRAW, event
END

PRO CRISPEX_RESTORE_LOOPS_SEL_NONE, event
; Handles selection of none restored loops
	WIDGET_CONTROL, event.TOP, GET_UVALUE = info
	IF (TOTAL(((*(*info).feedbparams).verbosity)[2:3]) GE 1) THEN $
    CRISPEX_VERBOSE_GET_ROUTINE, event
	*(*(*info).restoreparams).sel_loops = REPLICATE(0,(*(*info).restoreparams).cfilecount)
	FOR i=0,(*(*info).restoreparams).cfilecount-1 DO BEGIN
		name = 'sel_restore_but_'+STRTRIM(i,2)
		WIDGET_CONTROL, WIDGET_INFO(event.TOP, FIND_BY_UNAME = name), SET_BUTTON = 0
	ENDFOR		
	CRISPEX_DRAW, event
END

PRO CRISPEX_RESTORE_LOOPS_UPDATE_FILELIST, event
; Handles the update of the restored file list
	WIDGET_CONTROL, event.TOP, GET_UVALUE = info
	IF (TOTAL(((*(*info).feedbparams).verbosity)[2:3]) GE 1) THEN $
    CRISPEX_VERBOSE_GET_ROUTINE, event
	IF ((*(*info).dispparams).t_range NE (*(*info).dataparams).nt) THEN $
    CRISPEX_DISPRANGE_T_RESET, event, /NO_DRAW
	IF ((*(*info).dispparams).lp_range NE (*(*info).dataparams).nlp) THEN $
    CRISPEX_DISPRANGE_LP_RESET, event, /NO_DRAW
	IF ((*(*info).dispparams).lp_ref_range NE (*(*info).dataparams).refnlp) THEN $
    CRISPEX_DISPRANGE_LP_RESET, event, /REFERENCE, /NO_DRAW
	(*(*info).restoreparams).disp_loopfile = '0'
	*(*(*info).restoreparams).disp_loopnr = -1
	IF (*(*info).winswitch).showrestloop THEN BEGIN
		FOR i=0,N_ELEMENTS(*(*(*info).winids).restlooptlb)-1 DO BEGIN
			WIDGET_CONTROL, (*(*(*info).winids).restlooptlb)[i], /DESTROY
			*(*(*(*info).loopsdata).rest_loopslice[i]) = 0
			*(*(*(*info).loopsdata).rest_loopslab[i]) = 0
			*(*(*(*info).loopsdata).rest_crossloc[i]) = 0
		ENDFOR
		(*(*info).winswitch).showrestloop = 0
		*(*(*info).winids).restlooptlb = 0
	ENDIF
	WIDGET_CONTROL, (*(*info).ctrlscp).lp_slider, /SENSITIVE
	WIDGET_CONTROL, (*(*info).winids).root, SET_UVALUE = info
	WIDGET_CONTROL, event.TOP, /DESTROY
	event.TOP = (*(*info).winids).root
	CRISPEX_RESTORE_LOOPS_MAIN, event
	CRISPEX_DRAW_IMREF, event
END

PRO CRISPEX_RESTORE_LOOPS_OPEN_TANAT, event			
; Handles all prior to loading TANAT to analyse the selected loop slice/slab
	WIDGET_CONTROL, event.TOP, GET_UVALUE = info
	IF (TOTAL(((*(*info).feedbparams).verbosity)[2:3]) GE 1) THEN $
    CRISPEX_VERBOSE_GET_ROUTINE, event
	path_tanat = (ROUTINE_INFO('TANAT',/SOURCE)).PATH								; CHeck whether TANAT has already been compiled
	tanat_file = FILE_SEARCH((*(*info).paths).dir_aux,'tanat.pro', /FULLY_QUALIFY_PATH, COUNT=tanat_count)	; Try to find TANAT where it should be
	IF (tanat_count EQ 1) THEN (*(*info).paths).dir_tanat = (*(*info).paths).dir_aux
	IF (path_tanat NE '') THEN BEGIN										; TANAT has been compiled, so check whether it is the one at the expected location
		IF (path_tanat NE (*(*info).paths).dir_tanat+'tanat.pro') THEN BEGIN					; Compiled TANAT is not the correct TANAT
			IF (tanat_count EQ 1) THEN BEGIN								; Correct TANAT exists, so compile that one and run
				dir_tanat = STRMID((*(*info).paths).dir_tanat,0,STRPOS((*(*info).paths).dir_tanat,'/',/REVERSE_SEARCH))
				IF (STRPOS(!PATH,dir_tanat) NE 0) THEN !PATH = dir_tanat+':'+!PATH
				RESOLVE_ROUTINE, 'TANAT'
				CRISPEX_RESTORE_LOOPS_OPEN_TANAT_OPEN, event
			ENDIF ELSE IF ((*(*info).paths).tanat_repointed NE 1) THEN BEGIN				; Correct TANAT can not be found, run anyway but warn
				CRISPEX_WINDOW_OK, event,'WARNING!',$
          'CRISPEX could not find TANAT at the expected location '+$
          '('+(*(*info).paths).dir_aux+'), but a local copy has been compiled before from '+$
					'('+STRMID(path_tanat,0,STRPOS(path_tanat,'/',/REVERSE_SEARCH))+'). '+$
          'Press OK to continue with that local copy of TANAT, or select a different one.',$
					OK_EVENT='CRISPEX_RESTORE_LOOPS_OPEN_TANAT_OPEN', $
          CANCEL_EVENT='CRISPEX_RESTORE_LOOPS_OPEN_TANAT_REPOINT', $
          CANCEL_LABEL='Select different', BASE=tlb
				(*(*info).winids).errtlb = tlb
				(*(*info).paths).tanat_repointed = 1
			ENDIF ELSE CRISPEX_RESTORE_LOOPS_OPEN_TANAT_OPEN, event
		ENDIF ELSE CRISPEX_RESTORE_LOOPS_OPEN_TANAT_OPEN, event
	ENDIF ELSE BEGIN												; TANAT has not been compiled, but perhaps resides where it should
		IF (tanat_count EQ 1) THEN BEGIN									; Correct TANAT can be found
			dir_tanat = STRMID((*(*info).paths).dir_tanat,0,STRPOS((*(*info).paths).dir_tanat,'/',/REVERSE_SEARCH))
			IF (STRPOS(!PATH,dir_tanat) NE 0) THEN !PATH = dir_tanat+':'+!PATH				; Make sure that that version will be compiled
			RESOLVE_ROUTINE, 'TANAT'
			CRISPEX_RESTORE_LOOPS_OPEN_TANAT_OPEN, event
		ENDIF ELSE BEGIN											; TANAT has not been compiled, nor can be found where it should: have user point to local copy or abort	
			CRISPEX_WINDOW_OK, event,'ERROR!',$
        'CRISPEX could not find TANAT at the expected location ('+(*(*info).paths).dir_aux+'). '+$
				'Press OK to point CRISPEX to a local copy of TANAT, or cancel to abort.',$
        OK_EVENT='CRISPEX_RESTORE_LOOPS_OPEN_TANAT_REPOINT', $
        CANCEL_EVENT='CRISPEX_CLOSE_EVENT_WINDOW', BASE=tlb
			(*(*info).winids).errtlb = tlb
		ENDELSE
	ENDELSE 
END

PRO CRISPEX_RESTORE_LOOPS_OPEN_TANAT_REPOINT, event				
; Handles (re)pointing CRISPEX to the correct copy of TANAT
	WIDGET_CONTROL, event.TOP, GET_UVALUE = info
	IF (TOTAL(((*(*info).feedbparams).verbosity)[2:3]) GE 1) THEN $
    CRISPEX_VERBOSE_GET_ROUTINE, event
	file_tanat = DIALOG_PICKFILE(PATH='~/', FILTER='*.pro', /FIX_FILTER, /MUST_EXIST, TITLE='CRISPEX'+(*(*info).sesparams).instance_label+': Choose copy of TANAT to compile')
	(*(*info).paths).dir_tanat = STRMID(file_tanat,0,STRPOS(file_tanat,'/',/REVERSE_SEARCH))
	!PATH = (*(*info).paths).dir_tanat+':'+!PATH
	RESOLVE_ROUTINE,'TANAT'
	(*(*info).paths).tanat_repointed = 1
	WIDGET_CONTROL, (*(*info).winids).root, SET_UVALUE = info
	WIDGET_CONTROL, (*(*info).winids).errtlb,/DESTROY
	(*(*info).winids).errtlb = 0
	event.TOP = (*(*info).winids).root
	CRISPEX_RESTORE_LOOPS_OPEN_TANAT_OPEN, event
END

PRO CRISPEX_RESTORE_LOOPS_OPEN_TANAT_OPEN, event
; Handles the actual loading TANAT to analyse the selected loop slice/slab
	WIDGET_CONTROL, event.TOP, GET_UVALUE = info
	IF (TOTAL(((*(*info).feedbparams).verbosity)[2:3]) GE 1) THEN $
    CRISPEX_VERBOSE_GET_ROUTINE, event
	IF ((*(*info).winids).errtlb GT 0) THEN BEGIN
		WIDGET_CONTROL, (*(*info).winids).root, SET_UVALUE = info
		WIDGET_CONTROL, (*(*info).winids).errtlb,/DESTROY
		(*(*info).winids).errtlb = 0
		event.TOP = (*(*info).winids).root
	ENDIF
	file_csav = DIALOG_PICKFILE(PATH=(*(*info).paths).ipath, FILTER='*.csav', /FIX_FILTER, /MUST_EXIST, TITLE='CRISPEX'+(*(*info).sesparams).instance_label+': Choose CSAV file to load in TANAT')
	IF (STRLEN(file_csav) GT 0) THEN $
    TANAT, file_csav, ASECPIX=[(*(*info).dataparams).dx,$
      (*(*info).dataparams).dy], DT=(*(*info).plotaxes).dt
END


;========================= RETRIEVE FROM DETECTIONS PROCEDURES
PRO CRISPEX_RETRIEVE_DET_FILE_MENU, event, set_but_array, $
  DETFILENAME=detfilename, NO_DRAW=no_draw
; Opens the retrieved detections menu and reads in the data from the detection file
	WIDGET_CONTROL, event.TOP, GET_UVALUE = info
	IF (TOTAL(((*(*info).feedbparams).verbosity)[2:3]) GE 1) THEN $
    CRISPEX_VERBOSE_GET_ROUTINE, event
	IF (N_ELEMENTS(detfilename) NE 1) THEN $
    (*(*info).detparams).detfilename = DIALOG_PICKFILE(/READ, /MUST_EXIST, $
      TITLE = 'CRISPEX'+(*(*info).sesparams).instance_label+$
      ': Select detection file', PATH=(*(*info).paths).ipath)
	IF ((*(*info).detparams).detfilename EQ '') THEN BEGIN
		(*(*info).loopswitch).retrieve_detfile = 0
		RETURN
	ENDIF ELSE BEGIN
		WIDGET_CONTROL, (*(*info).ctrlscp).det_file_but, SENSITIVE = 0
		WIDGET_CONTROL, /HOURGLASS
		(*(*info).loopswitch).retrieve_detfile = 1
		RESTORE,(*(*info).detparams).detfilename
		(*(*info).detparams).nr_dets = ntot
		IF (N_ELEMENTS(set_but_array) NE (*(*info).detparams).nr_dets) THEN $
      *(*(*info).detparams).sel_dets = INTARR((*(*info).detparams).nr_dets)
    *(*(*info).detparams).overlay_dets = *(*(*info).detparams).sel_dets
		eventval = INDGEN((*(*info).detparams).nr_dets)
		base = WIDGET_BASE(TITLE = 'CRISPEX'+(*(*info).sesparams).instance_label+$
      ': Save from detection file', GROUP_LEADER = (*(*info).winids).root, $
      TLB_FRAME_ATTR = 1, /TLB_KILL_REQUEST_EVENTS)
		disp = WIDGET_BASE(base, /COLUMN)
		disp2 = WIDGET_BASE(disp, /COLUMN, /FRAME)
		sel_allnone = WIDGET_BASE(disp2, /ROW)
		sel_allnone_lab = WIDGET_LABEL(sel_allnone, VALUE = 'Select:', /ALIGN_LEFT)
		sel_allnone_buts = WIDGET_BASE(sel_allnone, /ROW, /EXCLUSIVE)
		(*(*info).ctrlsdet).sel_all = WIDGET_BUTTON(sel_allnone_buts, VALUE='All', $
      EVENT_PRO = 'CRISPEX_RETRIEVE_DET_SEL_ALL')
		(*(*info).ctrlsdet).sel_none = WIDGET_BUTTON(sel_allnone_buts, VALUE='None',$
      EVENT_PRO = 'CRISPEX_RETRIEVE_DET_SEL_NONE')
		WIDGET_CONTROL, (*(*info).ctrlsdet).sel_none, /SET_BUTTON
		disp_txt = REPLICATE('Display time slice D', (*(*info).detparams).nr_dets)
		list_values = ['Do not display any slice', disp_txt+STRTRIM(eventval,2)]
		(*(*info).ctrlsdet).disp_list = WIDGET_COMBOBOX(sel_allnone, $
      VALUE = list_values, /DYNAMIC_RESIZE, $
      EVENT_PRO = 'CRISPEX_DISPLAYS_RETRIEVE_DET_LOOPSLAB')
		overlays = WIDGET_BASE(disp2,/ROW)
		overlay_lab = WIDGET_LABEL(overlays, VALUE = 'Overlay:', /ALIGN_LEFT)
		overlay_buts = WIDGET_BASE(overlays, /ROW, /EXCLUSIVE)
		(*(*info).ctrlsdet).overlay_all = WIDGET_BUTTON(overlay_buts, $
      VALUE = 'All detections', EVENT_PRO = 'CRISPEX_RETRIEVE_DET_OVERLAY_ALL')
		(*(*info).ctrlsdet).overlay_sel = WIDGET_BUTTON(overlay_buts, $
      VALUE = 'Selected detections')
		WIDGET_CONTROL, (*(*info).ctrlsdet).overlay_sel, /SET_BUTTON
		IF ((*(*info).detparams).nr_dets GT 15) THEN $
      sel_buts = WIDGET_BASE(disp2, /ROW, Y_SCROLL_SIZE = 425) $
    ELSE $
      sel_buts = WIDGET_BASE(disp2, /ROW)
		ncols = 5
		nlines = CEIL((*(*info).detparams).nr_dets / FLOAT(ncols))
		sel_buts_col_0 = WIDGET_BASE(sel_buts, /NONEXCLUSIVE, /COLUMN)
		sel_buts_col_1 = WIDGET_BASE(sel_buts, /NONEXCLUSIVE, /COLUMN)
		sel_buts_col_2 = WIDGET_BASE(sel_buts, /NONEXCLUSIVE, /COLUMN)
		sel_buts_col_3 = WIDGET_BASE(sel_buts, /NONEXCLUSIVE, /COLUMN)
		sel_buts_col_4 = WIDGET_BASE(sel_buts, /NONEXCLUSIVE, /COLUMN)
    ; Initialise variables
    *(*(*info).detparams).xlp = PTRARR((*(*info).detparams).nr_dets, /ALLOCATE_HEAP)
    *(*(*info).detparams).ylp = PTRARR((*(*info).detparams).nr_dets, /ALLOCATE_HEAP)
    *(*(*info).detparams).xlr = PTRARR((*(*info).detparams).nr_dets, /ALLOCATE_HEAP)
    *(*(*info).detparams).ylr = PTRARR((*(*info).detparams).nr_dets, /ALLOCATE_HEAP)
  	*(*(*info).detparams).t   = LONARR((*(*info).detparams).nr_dets)
		FOR i=0,(*(*info).detparams).nr_dets-1 DO BEGIN
			IF (N_ELEMENTS(set_but_array) NE (*(*info).detparams).nr_dets) THEN $
        (*(*(*info).detparams).sel_dets)[i] = 0
			col = FLOOR(i/nlines)
			name = 'det_sel_but_'+STRTRIM(i,2)
			but_val = 'D'+STRTRIM(i,2)
			IF (col EQ 0) THEN act_sel_buts_col = sel_buts_col_0
			IF (col EQ 1) THEN act_sel_buts_col = sel_buts_col_1
			IF (col EQ 2) THEN act_sel_buts_col = sel_buts_col_2
			IF (col EQ 3) THEN act_sel_buts_col = sel_buts_col_3
			IF (col EQ 4) THEN act_sel_buts_col = sel_buts_col_4
			sel_but = WIDGET_BUTTON(act_sel_buts_col, VALUE = but_val, $
        UVALUE = eventval[i], EVENT_PRO = 'CRISPEX_RETRIEVE_DET_MENU_EVENT', $
        UNAME = name) 
			IF (N_ELEMENTS(set_but_array) EQ (*(*info).detparams).nr_dets) THEN $
        WIDGET_CONTROL, sel_but, SET_BUTTON = set_but_array[i]
			npoints = (SIZE((*detections[i]).x))[1]
			maxwidth = (SIZE((*detections[i]).x))[2]
			stdwidth = CEIL(maxwidth/2.)
			IF ~KEYWORD_SET(NO_DRAW) THEN (*(*info).detparams).width = stdwidth
			(*(*info).detparams).mid = CEIL(maxwidth/2.)-1
			(*(*(*info).detparams).t)[i] = (*detections[i]).t
			*(*(*(*info).detparams).xlp)[i] = $
        [(*detections[i]).x[0,2],(*detections[i]).x[npoints-1,2]]
			*(*(*(*info).detparams).ylp)[i] = $
        [(*detections[i]).y[0,2],(*detections[i]).y[npoints-1,2]]
			*(*(*(*info).detparams).xlr)[i] = (*detections[i]).x
			*(*(*(*info).detparams).ylr)[i] = (*detections[i]).y
		ENDFOR			
		time_base = WIDGET_BASE(disp, /ROW, /FRAME)
		dtmin_label = WIDGET_LABEL(time_base, VALUE = 'Delta t down:', /ALIGN_LEFT)
		(*(*info).ctrlsdet).dtmin_text = WIDGET_TEXT(time_base, $
      VALUE = STRTRIM((*(*info).detparams).delta_t_dn,2), /EDITABLE, XSIZE = 5,$
      EVENT_PRO = 'CRISPEX_RETRIEVE_DET_DELTA_T_DN')
		dtmax_label = WIDGET_LABEL(time_base, VALUE = 'Delta t up:', /ALIGN_LEFT)
		(*(*info).ctrlsdet).dtmax_text = WIDGET_TEXT(time_base, $
      VALUE = STRTRIM((*(*info).detparams).delta_t_up,2), /EDITABLE, XSIZE = 5,$
      EVENT_PRO = 'CRISPEX_RETRIEVE_DET_DELTA_T_UP')
		(*(*info).ctrlsdet).width_slider = WIDGET_SLIDER(disp, $
      TITLE = 'Detection loop width', MIN = 1, MAX = maxwidth, $
      VALUE = (*(*info).detparams).width, EVENT_PRO = 'CRISPEX_RETRIEVE_DET_WIDTH')
		spectral_pos = WIDGET_BASE(disp, /COLUMN, /FRAME)
		spectral_pos_base = WIDGET_BASE(spectral_pos, /ROW)
		spectral_pos_label = WIDGET_LABEL(spectral_pos_base, $
      VALUE = 'Spectral positions:', /ALIGN_LEFT)
		spectral_pos_buts_base = WIDGET_BASE(spectral_pos_base, /ROW, /EXCLUSIVE)
		(*(*info).ctrlsdet).all_pos = WIDGET_BUTTON(spectral_pos_buts_base, $
      VALUE = 'All', EVENT_PRO = 'CRISPEX_RETRIEVE_DET_ALL_POS', /NO_RELEASE)
		WIDGET_CONTROL, (*(*info).ctrlsdet).all_pos, $
      SET_BUTTON = ((*(*info).savswitch).pos_dets EQ 1)
		(*(*info).ctrlsdet).saved_pos = WIDGET_BUTTON(spectral_pos_buts_base, $
      VALUE = 'Current', EVENT_PRO = 'CRISPEX_RETRIEVE_DET_CUR_POS', /NO_RELEASE)
		WIDGET_CONTROL, (*(*info).ctrlsdet).saved_pos, $
      SET_BUTTON = ((*(*info).savswitch).pos_dets EQ 2)
		(*(*info).ctrlsdet).sel_range_pos = WIDGET_BUTTON(spectral_pos_buts_base, $
      VALUE = 'Selected range', EVENT_PRO = 'CRISPEX_RETRIEVE_DET_SEL_RANGE_POS', /NO_RELEASE)
		WIDGET_CONTROL, (*(*info).ctrlsdet).sel_range_pos, $
      SET_BUTTON = ((*(*info).savswitch).pos_dets EQ 3)
		range_pos_base = WIDGET_BASE(spectral_pos, /ROW)
		main_label = WIDGET_LABEL(range_pos_base, VALUE = 'Main:', /ALIGN_LEFT)
		dlpmin_label = WIDGET_LABEL(range_pos_base, VALUE = 'Lower lp-index:', $
      /ALIGN_LEFT)
		(*(*info).ctrlsdet).dlpmin_text = WIDGET_TEXT(range_pos_base, $
      VALUE = STRTRIM((*(*info).detparams).lp_dn,2), /EDITABLE, XSIZE = 5, $
      EVENT_PRO = 'CRISPEX_RETRIEVE_DET_LP_DN', SENSITIVE = 0)
		dlpmax_label = WIDGET_LABEL(range_pos_base, VALUE = 'Upper lp-index:', $
      /ALIGN_LEFT)
		(*(*info).ctrlsdet).dlpmax_text = WIDGET_TEXT(range_pos_base, $
      VALUE = STRTRIM((*(*info).detparams).lp_up,2), /EDITABLE, XSIZE = 5, $
      EVENT_PRO = 'CRISPEX_RETRIEVE_DET_LP_UP', SENSITIVE = 0)
		refrange_pos_base = WIDGET_BASE(spectral_pos, /ROW)
		ref_label = WIDGET_LABEL(refrange_pos_base, VALUE = 'Reference:', $
      /ALIGN_LEFT)
		refdlpmin_label = WIDGET_LABEL(refrange_pos_base, VALUE = 'Lower lp-index:',$
      /ALIGN_LEFT)
		(*(*info).ctrlsdet).refdlpmin_text = WIDGET_TEXT(refrange_pos_base, $
      VALUE = STRTRIM((*(*info).detparams).lp_ref_dn,2), /EDITABLE, XSIZE = 5, $
      EVENT_PRO = 'CRISPEX_RETRIEVE_DET_LP_REF_DN', SENSITIVE = 0)
		refdlpmax_label = WIDGET_LABEL(refrange_pos_base, VALUE = 'Upper lp-index:',$
      /ALIGN_LEFT)
		(*(*info).ctrlsdet).refdlpmax_text = WIDGET_TEXT(refrange_pos_base, $
      VALUE = STRTRIM((*(*info).detparams).lp_ref_up,2), /EDITABLE, XSIZE = 5, $
      EVENT_PRO = 'CRISPEX_RETRIEVE_DET_LP_REF_UP', SENSITIVE = 0)
		save_cube = WIDGET_BASE(disp, /ROW, /FRAME)
		save_cube_lab = WIDGET_LABEL(save_cube, VALUE = 'Save from: ')
		save_cube_but = WIDGET_BASE(save_cube, /ROW, /EXCLUSIVE)
		(*(*info).ctrlsdet).save_imonly = WIDGET_BUTTON(save_cube_but, $
      VALUE = 'IMCUBE only', EVENT_PRO = 'CRISPEX_RETRIEVE_DET_IMCUBE_ONLY', $
      /NO_RELEASE)
		WIDGET_CONTROL, (*(*info).ctrlsdet).save_imonly, /SET_BUTTON
		refsens = (*(*info).winswitch).showref AND ((*(*info).dataparams).refnt GT 1) 
		(*(*info).ctrlsdet).save_refonly = WIDGET_BUTTON(save_cube_but, $
      VALUE = 'REFCUBE only', EVENT_PRO = 'CRISPEX_RETRIEVE_DET_REFCUBE_ONLY', $
      SENSITIVE = refsens, /NO_RELEASE)
		(*(*info).ctrlsdet).save_imref = WIDGET_BUTTON(save_cube_but, $
      VALUE = 'both cubes', EVENT_PRO = 'CRISPEX_RETRIEVE_DET_IMREF', $
      SENSITIVE = refsens, /NO_RELEASE)
		dec_buts = WIDGET_BASE(disp, /ROW, /ALIGN_CENTER)
		change_path_but = WIDGET_BUTTON(dec_buts, VALUE = 'Change path', $
      EVENT_PRO = 'CRISPEX_SAVE_SET_OPATH')
		(*(*info).ctrlsdet).get_dets = WIDGET_BUTTON(dec_buts, $
      VALUE = 'Save selected detection(s)', $
      EVENT_PRO = 'CRISPEX_RETRIEVE_DET_SEL_LOOPS', SENSITIVE = 0)
		cancel = WIDGET_BUTTON(dec_buts, VALUE = 'Cancel', $
      EVENT_PRO = 'CRISPEX_RETRIEVE_DET_CANCEL')
		WIDGET_CONTROL, base, /REALIZE, TLB_SET_XOFFSET = (*(*info).winsizes).lsxoffset
		WIDGET_CONTROL, base, SET_UVALUE = info
		XMANAGER, 'CRISPEX', base, /NO_BLOCK
		(*(*info).winids).detsavetlb = base
	ENDELSE
	IF ~KEYWORD_SET(NO_DRAW) THEN CRISPEX_DRAW, event
	IF (((*(*info).feedbparams).verbosity)[3] EQ 1) THEN $
    CRISPEX_VERBOSE_GET, event, $
      [(*(*info).loopswitch).retrieve_detfile,(*(*info).winids).detsavetlb,$
      (*(*info).detparams).nr_dets],$
      labels=['Retrieving detections','detsavetlb','Retrieved detections']
END

PRO CRISPEX_RETRIEVE_DET_SEL_ALL, event
; Handles the selection of all detections
	WIDGET_CONTROL, event.TOP, GET_UVALUE = info
	IF (TOTAL(((*(*info).feedbparams).verbosity)[2:3]) GE 1) THEN $
    CRISPEX_VERBOSE_GET_ROUTINE, event
	*(*(*info).detparams).sel_dets = REPLICATE(1,(*(*info).detparams).nr_dets)
	WIDGET_CONTROL, (*(*info).ctrlsdet).get_dets, SENSITIVE = 1
	FOR i=0,(*(*info).detparams).nr_dets-1 DO BEGIN
		name = 'det_sel_but_'+STRTRIM(i,2)
		WIDGET_CONTROL, WIDGET_INFO(event.TOP, FIND_BY_UNAME = name), SET_BUTTON = 1
	ENDFOR		
	IF ((*(*info).overlayswitch).det_overlay_all EQ 0) THEN CRISPEX_DRAW, event
END

PRO CRISPEX_RETRIEVE_DET_SEL_NONE, event
; Handles the selection of no detections
	WIDGET_CONTROL, event.TOP, GET_UVALUE = info
	IF (TOTAL(((*(*info).feedbparams).verbosity)[2:3]) GE 1) THEN $
    CRISPEX_VERBOSE_GET_ROUTINE, event
	*(*(*info).detparams).sel_dets = REPLICATE(0,(*(*info).detparams).nr_dets)
	WIDGET_CONTROL, (*(*info).ctrlsdet).get_dets, SENSITIVE = 0
	FOR i=0,(*(*info).detparams).nr_dets-1 DO BEGIN
		name = 'det_sel_but_'+STRTRIM(i,2)
		WIDGET_CONTROL, WIDGET_INFO(event.TOP, FIND_BY_UNAME = name), SET_BUTTON = 0
	ENDFOR		
	IF ((*(*info).overlayswitch).det_overlay_all EQ 0) THEN CRISPEX_DRAW, event
END

PRO CRISPEX_RETRIEVE_DET_MENU_EVENT, event
; Handles the selection of a certain detection
	WIDGET_CONTROL, event.TOP, GET_UVALUE = info
	IF (TOTAL(((*(*info).feedbparams).verbosity)[2:3]) GE 1) THEN $
    CRISPEX_VERBOSE_GET_ROUTINE, event, /IGNORE_LAST
	WIDGET_CONTROL, event.ID, GET_UVALUE = eventval
	(*(*(*info).detparams).sel_dets)[eventval] = ( (*(*(*info).detparams).sel_dets)[eventval] EQ 0) 
	condition = WHERE(*(*(*info).detparams).sel_dets EQ 1, count)
	WIDGET_CONTROL, (*(*info).ctrlsdet).get_dets, SENSITIVE = (count GT 0)
	WIDGET_CONTROL, (*(*info).ctrlsdet).sel_all, SET_BUTTON = (count EQ (*(*info).detparams).nr_dets)
	WIDGET_CONTROL, (*(*info).ctrlsdet).sel_none, SET_BUTTON = ABS((count GT 0)-1)
	IF ((*(*info).overlayswitch).det_overlay_all EQ 0) THEN BEGIN
    (*(*(*info).detparams).overlay_dets)[eventval] = $
      (*(*(*info).detparams).sel_dets)[eventval]
    CRISPEX_DRAW, event
  ENDIF
	IF (((*(*info).feedbparams).verbosity)[3] EQ 1) THEN $
    CRISPEX_VERBOSE_GET, event, [eventval,(*(*(*info).detparams).sel_dets)[eventval],$
		(((N_ELEMENTS(condition) GT 0) AND (TOTAL(condition) NE -1)) AND (N_ELEMENTS(condition) EQ (*(*info).restoreparams).cfilecount)),ABS(((N_ELEMENTS(condition) GT 0) AND (TOTAL(condition) NE -1))-1),$
		N_ELEMENTS(condition)-(TOTAL(condition) EQ -1)], labels=['Detection ID','Detection selected','All selected','None selected','Total selected']

END

PRO CRISPEX_RETRIEVE_DET_OVERLAY_ALL, event
; Enables the overlay of all or no detections
	WIDGET_CONTROL, event.TOP, GET_UVALUE = info
	IF (TOTAL(((*(*info).feedbparams).verbosity)[2:3]) GE 1) THEN $
    CRISPEX_VERBOSE_GET_ROUTINE, event
	(*(*info).overlayswitch).det_overlay_all = event.SELECT
  IF (*(*info).overlayswitch).det_overlay_all THEN $
    *(*(*info).detparams).overlay_dets = REPLICATE(1, $
      (*(*info).detparams).nr_dets) $
  ELSE $
    *(*(*info).detparams).overlay_dets = *(*(*info).detparams).sel_dets
	CRISPEX_DRAW, event
END

PRO CRISPEX_RETRIEVE_DET_WIDTH, event
; Handles the width of the retrieved detection
	WIDGET_CONTROL, event.TOP, GET_UVALUE = info
	IF (TOTAL(((*(*info).feedbparams).verbosity)[2:3]) GE 1) THEN $
    CRISPEX_VERBOSE_GET_ROUTINE, event
	prev_width = (*(*info).detparams).width
	set_width = event.VALUE
	IF (set_width NE prev_width) THEN BEGIN
		WIDGET_CONTROL, /HOURGLASS
		IF (FLOOR(set_width/2.) EQ set_width/2.) THEN BEGIN
			IF (prev_width GT set_width) THEN $
        set_width = set_width-1 $
      ELSE $
        set_width = set_width+1
		ENDIF
		(*(*info).detparams).width = set_width
		WIDGET_CONTROL, (*(*info).ctrlsdet).width_slider, $
      SET_VALUE = (*(*info).detparams).width
		IF (*(*info).winswitch).showretrdet THEN BEGIN
      ; Gather input parameters
      maxpass = ((*(*info).detparams).lp_up-(*(*info).detparams).lp_dn+1) * $
        (*(*info).detparams).width
      t_0 = SYSTIME(/SECONDS)
      inparams = {xlp:*(*(*(*info).detparams).xlp)[(*(*info).detparams).idx], $
        ylp:*(*(*(*info).detparams).ylp)[(*(*info).detparams).idx], $
        xlr:*(*(*(*info).detparams).xlr)[(*(*info).detparams).idx], $
        ylr:*(*(*(*info).detparams).ylr)[(*(*info).detparams).idx], $
        nx:(*(*info).dataparams).nx, ny:(*(*info).dataparams).ny, $
        lp_dn:(*(*info).detparams).lp_dn, lp_up:(*(*info).detparams).lp_up, $
        no_nlp:((*(*info).dataparams).nlp LE 1), idx:(*(*info).detparams).idx, $
        detimref:1, data:(*(*info).data).imagedata, t_0:t_0, maxpass:maxpass}
      ; Get actual detection slab
      CRISPEX_RETRIEVE_DET_GET_SLAB, event, inparams, w_lpts_out, gapresult_out, $
        loopslab_out, crossloc_out, loopsize_out, t_det_out, t_low_out, $
        t_upp_out
      (*(*info).detparams).ngaps = gapresult_out.ngaps
      *(*(*info).detparams).databounds = gapresult_out.databounds
      *(*(*info).detparams).wdatabounds = gapresult_out.wdatabounds
  	  *(*(*info).loopsdata).det_loopslab = loopslab_out
  	  *(*(*info).loopsdata).det_crossloc = crossloc_out
  	  (*(*info).loopsdata).det_loopsize = loopsize_out
      *(*(*info).detparams).w_lpts = w_lpts_out
      (*(*info).dispparams).t_low = t_low_out
      (*(*info).dispparams).t_upp = t_upp_out
      (*(*info).dispparams).t = t_det_out
			CRISPEX_UPDATE_LP, event
			CRISPEX_DISPRANGE_T_RANGE, event
			WIDGET_CONTROL, (*(*info).ctrlscp).lower_t_text,$
        SET_VALUE = STRTRIM((*(*info).dispparams).t_low,2),SENSITIVE = 0
			WIDGET_CONTROL, (*(*info).ctrlscp).upper_t_text,$
        SET_VALUE = STRTRIM((*(*info).dispparams).t_upp,2),SENSITIVE = 0 
		IF (((*(*info).feedbparams).verbosity)[3] EQ 1) THEN $
      CRISPEX_VERBOSE_GET, event, [prev_width,set_width],$
        labels=['Previous width','New width']
		ENDIF ELSE CRISPEX_DRAW, event
	ENDIF ELSE RETURN
END

PRO CRISPEX_RETRIEVE_DET_ALL_POS, event
; Enables the retreival of detections at all spectral positions
	WIDGET_CONTROL, event.TOP, GET_UVALUE = info
	IF (TOTAL(((*(*info).feedbparams).verbosity)[2:3]) GE 1) THEN $
    CRISPEX_VERBOSE_GET_ROUTINE, event
	(*(*info).savswitch).pos_dets = 1
	WIDGET_CONTROL, (*(*info).ctrlsdet).dlpmin_text, SENSITIVE = 0
	WIDGET_CONTROL, (*(*info).ctrlsdet).dlpmax_text, SENSITIVE = 0
	IF ((*(*info).savswitch).det_imref_only GE 2) THEN BEGIN
		WIDGET_CONTROL, (*(*info).ctrlsdet).refdlpmin_text, SENSITIVE = 0
		WIDGET_CONTROL, (*(*info).ctrlsdet).refdlpmax_text, SENSITIVE = 0
	ENDIF
	IF (((*(*info).feedbparams).verbosity)[3] EQ 1) THEN $
    CRISPEX_VERBOSE_GET, event, [(*(*info).savswitch).pos_dets],labels=['Saving spectral position setting']
END

PRO CRISPEX_RETRIEVE_DET_CUR_POS, event
; Enables the retreival of detections at the current spectral position only
	WIDGET_CONTROL, event.TOP, GET_UVALUE = info
	IF (TOTAL(((*(*info).feedbparams).verbosity)[2:3]) GE 1) THEN $
    CRISPEX_VERBOSE_GET_ROUTINE, event
	(*(*info).savswitch).pos_dets = 2
	WIDGET_CONTROL, (*(*info).ctrlsdet).dlpmin_text, SENSITIVE = 0
	WIDGET_CONTROL, (*(*info).ctrlsdet).dlpmax_text, SENSITIVE = 0
	IF ((*(*info).savswitch).det_imref_only GE 2) THEN BEGIN
		WIDGET_CONTROL, (*(*info).ctrlsdet).refdlpmin_text, SENSITIVE = 0
		WIDGET_CONTROL, (*(*info).ctrlsdet).refdlpmax_text, SENSITIVE = 0
	ENDIF
	IF (((*(*info).feedbparams).verbosity)[3] EQ 1) THEN $
    CRISPEX_VERBOSE_GET, event, [(*(*info).savswitch).pos_dets],labels=['Saving spectral position setting']
END
	
PRO CRISPEX_RETRIEVE_DET_SEL_RANGE_POS, event
; Enables the retreival of detections at a selected range of spectral positions
	WIDGET_CONTROL, event.TOP, GET_UVALUE = info
	IF (TOTAL(((*(*info).feedbparams).verbosity)[2:3]) GE 1) THEN $
    CRISPEX_VERBOSE_GET_ROUTINE, event
	(*(*info).savswitch).pos_dets = 3
	WIDGET_CONTROL, (*(*info).ctrlsdet).dlpmin_text, SENSITIVE = ((*(*info).savswitch).det_imref_only NE 2)
	WIDGET_CONTROL, (*(*info).ctrlsdet).dlpmax_text, SENSITIVE = ((*(*info).savswitch).det_imref_only NE 2)
	WIDGET_CONTROL, (*(*info).ctrlsdet).refdlpmin_text, SENSITIVE = ((*(*info).savswitch).det_imref_only GE 2)
	WIDGET_CONTROL, (*(*info).ctrlsdet).refdlpmax_text, SENSITIVE = ((*(*info).savswitch).det_imref_only GE 2)
	CRISPEX_RETRIEVE_DET_LP_DN, event
	CRISPEX_RETRIEVE_DET_LP_UP, event
	CRISPEX_RETRIEVE_DET_LP_REF_DN, event
	CRISPEX_RETRIEVE_DET_LP_REF_UP, event
	IF (((*(*info).feedbparams).verbosity)[3] EQ 1) THEN $
    CRISPEX_VERBOSE_GET, event, [(*(*info).savswitch).pos_dets],labels=['Saving spectral position setting']
END

PRO CRISPEX_RETRIEVE_DET_IMCUBE_ONLY, event
; Enables the retreival of detections from the image cube only
	WIDGET_CONTROL, event.TOP, GET_UVALUE = info
	IF (TOTAL(((*(*info).feedbparams).verbosity)[2:3]) GE 1) THEN $
    CRISPEX_VERBOSE_GET_ROUTINE, event
	(*(*info).savswitch).det_imref_only = 1
	WIDGET_CONTROL, (*(*info).ctrlsdet).dlpmin_text, SENSITIVE = ((*(*info).savswitch).pos_dets EQ 3) 
	WIDGET_CONTROL, (*(*info).ctrlsdet).dlpmax_text, SENSITIVE = ((*(*info).savswitch).pos_dets EQ 3) 
	WIDGET_CONTROL, (*(*info).ctrlsdet).refdlpmin_text, SENSITIVE = 0
	WIDGET_CONTROL, (*(*info).ctrlsdet).refdlpmax_text, SENSITIVE = 0
	IF (((*(*info).feedbparams).verbosity)[3] EQ 1) THEN $
    CRISPEX_VERBOSE_GET, event, [(*(*info).savswitch).det_imref_only],labels=['Saving from cube setting']
END

PRO CRISPEX_RETRIEVE_DET_REFCUBE_ONLY, event
; Enables the retreival of detections from the reference cube only
	WIDGET_CONTROL, event.TOP, GET_UVALUE = info
	IF (TOTAL(((*(*info).feedbparams).verbosity)[2:3]) GE 1) THEN $
    CRISPEX_VERBOSE_GET_ROUTINE, event
	(*(*info).savswitch).det_imref_only = 2
	WIDGET_CONTROL, (*(*info).ctrlsdet).dlpmin_text, SENSITIVE = 0
	WIDGET_CONTROL, (*(*info).ctrlsdet).dlpmax_text, SENSITIVE = 0
	WIDGET_CONTROL, (*(*info).ctrlsdet).refdlpmin_text, SENSITIVE = ((*(*info).savswitch).pos_dets EQ 3) 
	WIDGET_CONTROL, (*(*info).ctrlsdet).refdlpmax_text, SENSITIVE = ((*(*info).savswitch).pos_dets EQ 3) 
	IF (((*(*info).feedbparams).verbosity)[3] EQ 1) THEN $
    CRISPEX_VERBOSE_GET, event, [(*(*info).savswitch).det_imref_only],labels=['Saving from cube setting']
END

PRO CRISPEX_RETRIEVE_DET_IMREF, event
; Enables the retreival of detections from both the image and the reference cube
	WIDGET_CONTROL, event.TOP, GET_UVALUE = info
	IF (TOTAL(((*(*info).feedbparams).verbosity)[2:3]) GE 1) THEN $
    CRISPEX_VERBOSE_GET_ROUTINE, event
	(*(*info).savswitch).det_imref_only = 3
	WIDGET_CONTROL, (*(*info).ctrlsdet).dlpmin_text, SENSITIVE = ((*(*info).savswitch).pos_dets EQ 3) 
	WIDGET_CONTROL, (*(*info).ctrlsdet).dlpmax_text, SENSITIVE = ((*(*info).savswitch).pos_dets EQ 3) 
	WIDGET_CONTROL, (*(*info).ctrlsdet).refdlpmin_text, SENSITIVE = ((*(*info).savswitch).pos_dets EQ 3) 
	WIDGET_CONTROL, (*(*info).ctrlsdet).refdlpmax_text, SENSITIVE = ((*(*info).savswitch).pos_dets EQ 3) 
	IF (((*(*info).feedbparams).verbosity)[3] EQ 1) THEN $
    CRISPEX_VERBOSE_GET, event, [(*(*info).savswitch).det_imref_only],labels=['Saving from cube setting']
END

PRO CRISPEX_RETRIEVE_DET_SEL_LOOPS, event
; Opens the warning windows giving the saving time estimates of the chosen saving procedure, intermediate step towards saving detection loopslabs
	WIDGET_CONTROL, event.TOP, GET_UVALUE = info
	IF (TOTAL(((*(*info).feedbparams).verbosity)[2:3]) GE 1) THEN $
    CRISPEX_VERBOSE_GET_ROUTINE, event
	CRISPEX_SAVE_CHECK_PATH_WRITE, event
	IF ((*(*info).paths).opath_write EQ 1) THEN BEGIN
		*(*(*info).detparams).sel_loops = $
      WHERE(*(*(*info).detparams).sel_dets EQ 1, count)
		(*(*info).detparams).nr_sel_loops = count
    IF (count GT 0) THEN BEGIN
  		IF ((*(*info).savswitch).pos_dets EQ 2) THEN BEGIN
        ; Saving from single wavelength position
  			IF ((*(*info).feedbparams).estimate_run EQ 0) THEN BEGIN
  				CRISPEX_ESTIMATE_TIME_WINDOW, event
  				CRISPEX_ESTIMATE_TIME_CALCULATION, event
  			ENDIF
  			time = 0
  			FOR i=0,(*(*info).detparams).nr_sel_loops-1 DO BEGIN
          xlr_tmp = $
            (*(*(*(*info).detparams).xlr)[(*(*(*info).detparams).sel_loops)[i]])[$
              *,(*(*info).detparams).mid]
          ylr_tmp = $
            (*(*(*(*info).detparams).ylr)[(*(*(*info).detparams).sel_loops)[i]])[$
              *,(*(*info).detparams).mid]
          w_loop_pts =  $
            WHERE((xlr_tmp GE 0) AND (xlr_tmp LT ((*(*info).dataparams).nx)) AND $
                  (ylr_tmp GE 0) AND (ylr_tmp LT ((*(*info).dataparams).ny)), $
                  nw_lpts)
  				sub_time = (*(*info).feedbparams).estimate_time * $
            nw_lpts/FLOAT((*(*info).feedbparams).estimate_lx) * $
            (*(*info).detparams).width * ((*(*info).detparams).delta_t_up + $
  					(*(*info).detparams).delta_t_dn + 1) * $
            CEIL((*(*info).savswitch).det_imref_only/2.)
  				time = time + sub_time
  			ENDFOR
  			CRISPEX_ESTIMATE_FULL_TIME, time, denom, units
  			(*(*info).savswitch).cont = 4
  			CRISPEX_SAVE_WARNING_YESNO, event,$
          STRTRIM((*(*info).detparams).nr_sel_loops,2)+$
          ' detection(s) selected. Saving the exact loop slice(s) may take' ,$
  				'up to about '+STRTRIM(CEIL(time/denom),2)+units+$
          '. Do you wish to continue saving?', $
          OK_EVENT='CRISPEX_SAVE_LOOPSL_CONTINUE', $
          CANCEL_EVENT='CRISPEX_SAVE_LOOPSL_ABORT'
  			IF ((*(*info).winswitch).estimate_win EQ 1) THEN BEGIN
  				WIDGET_CONTROL, (*(*info).winids).estimatetlb, /DESTROY
  				(*(*info).winids).estimatetlb = 0
  				(*(*info).winswitch).estimate_win = 0
  			ENDIF
  		ENDIF ELSE IF ((*(*info).savswitch).pos_dets EQ 1) THEN BEGIN
        ; Saving from all wavelength positions
  			IF ((*(*info).feedbparams).estimate_run EQ 0) THEN BEGIN
  				CRISPEX_ESTIMATE_TIME_WINDOW, event
  				CRISPEX_ESTIMATE_TIME_CALCULATION, event
  			ENDIF
  			time = 0
  			FOR i=0,(*(*info).detparams).nr_sel_loops-1 DO BEGIN
          xlr_tmp = $
            (*(*(*(*info).detparams).xlr)[(*(*(*info).detparams).sel_loops)[i]])[$
              *,(*(*info).detparams).mid]
          ylr_tmp = $
            (*(*(*(*info).detparams).ylr)[(*(*(*info).detparams).sel_loops)[i]])[$
              *,(*(*info).detparams).mid]
          w_loop_pts =  $
            WHERE((xlr_tmp GE 0) AND (xlr_tmp LT ((*(*info).dataparams).nx)) AND $
                  (ylr_tmp GE 0) AND (ylr_tmp LT ((*(*info).dataparams).ny)),$
                  nw_lpts)
  				sub_im_time = (*(*info).feedbparams).estimate_time * $
            nw_lpts/FLOAT((*(*info).feedbparams).estimate_lx) * $
            (*(*info).dataparams).nlp * (*(*info).detparams).width * $
  					((*(*info).detparams).delta_t_up + (*(*info).detparams).delta_t_dn + 1)
  				IF ((*(*info).dataparams).refnt EQ (*(*info).dataparams).nt) THEN $
            sub_ref_time = sub_im_time/(*(*info).dataparams).nlp $
          ELSE $
            sub_ref_time = sub_im_time
  				IF ((*(*info).savswitch).det_imref_only EQ 1) THEN $
            sub_time = sub_im_time $
          ELSE IF ((*(*info).savswitch).det_imref_only EQ 2) THEN $
            sub_time = sub_ref_time $
          ELSE $
            sub_time = sub_im_time + sub_ref_time
  				time += sub_time
  			ENDFOR
  			CRISPEX_ESTIMATE_FULL_TIME, time, denom, units
  			(*(*info).savswitch).cont = 5
  			CRISPEX_SAVE_WARNING_YESNO, event, $
          STRTRIM((*(*info).detparams).nr_sel_loops,2)+$
          ' detection(s) selected. Saving the exact loop slab(s) may take',$
  				'up to about '+STRTRIM(CEIL(time/denom),2)+units+$
          '. Do you wish to continue saving?', $
          OK_EVENT='CRISPEX_SAVE_LOOPSL_CONTINUE', $
          CANCEL_EVENT='CRISPEX_SAVE_LOOPSL_ABORT'
  			IF ((*(*info).winswitch).estimate_win EQ 1) THEN BEGIN
  				WIDGET_CONTROL, (*(*info).winids).estimatetlb, /DESTROY
  				(*(*info).winids).estimatetlb = 0
  				(*(*info).winswitch).estimate_win = 0
  			ENDIF
  		ENDIF ELSE IF ((*(*info).savswitch).pos_dets EQ 3) THEN BEGIN
        ; Saving from selected wavelength range
  			IF ((*(*info).feedbparams).estimate_run EQ 0) THEN BEGIN
  				CRISPEX_ESTIMATE_TIME_WINDOW, event
  				CRISPEX_ESTIMATE_TIME_CALCULATION, event
  			ENDIF
  			time = 0
  			FOR i=0,(*(*info).detparams).nr_sel_loops-1 DO BEGIN
          xlr_tmp = $
            (*(*(*(*info).detparams).xlr)[(*(*(*info).detparams).sel_loops)[i]])[$
              *,(*(*info).detparams).mid]
          ylr_tmp = $
            (*(*(*(*info).detparams).ylr)[(*(*(*info).detparams).sel_loops)[i]])[$
              *,(*(*info).detparams).mid]
          w_loop_pts =  $
            WHERE((xlr_tmp GE 0) AND (xlr_tmp LT ((*(*info).dataparams).nx)) AND $
                  (ylr_tmp GE 0) AND (ylr_tmp LT ((*(*info).dataparams).ny)),$
                  nw_lpts)
  				sub_im_time = (*(*info).feedbparams).estimate_time * $
            nw_lpts/FLOAT((*(*info).feedbparams).estimate_lx) * $
            ((*(*info).detparams).lp_up-(*(*info).detparams).lp_dn+1) * $
  					(*(*info).detparams).width * ((*(*info).detparams).delta_t_up + $
            (*(*info).detparams).delta_t_dn + 1)
  				IF ((*(*info).dataparams).refnt EQ (*(*info).dataparams).nt) THEN $
            sub_ref_time = sub_im_time/((*(*info).detparams).lp_up-$
              (*(*info).detparams).lp_dn+1) $
          ELSE $
            sub_ref_time = sub_im_time
  				IF ((*(*info).savswitch).det_imref_only EQ 1) THEN $
            sub_time = sub_im_time $
          ELSE IF ((*(*info).savswitch).det_imref_only EQ 2) THEN $
            sub_time = sub_ref_time $
          ELSE $
            sub_time = sub_im_time + sub_ref_time
  				time += sub_time
  			ENDFOR
  			CRISPEX_ESTIMATE_FULL_TIME, time, denom, units
  			(*(*info).savswitch).cont = 5
  			CRISPEX_SAVE_WARNING_YESNO, event, $
          STRTRIM((*(*info).detparams).nr_sel_loops,2)+$
          ' detection(s) selected. Saving the exact loop slab(s) may take',$
  				'up to about '+STRTRIM(CEIL(time/denom),2)+units+$
          '. Do you wish to continue saving?', $
          OK_EVENT='CRISPEX_SAVE_LOOPSL_CONTINUE', $
          CANCEL_EVENT='CRISPEX_SAVE_LOOPSL_ABORT'
  			IF ((*(*info).winswitch).estimate_win EQ 1) THEN BEGIN
  				WIDGET_CONTROL, (*(*info).winids).estimatetlb, /DESTROY
  				(*(*info).winids).estimatetlb = 0
  				(*(*info).winswitch).estimate_win = 0
  			ENDIF
  		ENDIF ELSE RETURN
    ENDIF
		IF (((*(*info).feedbparams).verbosity)[3] EQ 1) THEN $
      CRISPEX_VERBOSE_GET, event, $
        [(*(*info).detparams).nr_sel_loops,(*(*info).savswitch).cont],$
        labels=['Number of detections','Saving procedure']
	ENDIF
END

PRO CRISPEX_RETRIEVE_DET_DELTA_T_DN, event
; Handles the change in delta_t down from the detection framenumber
	WIDGET_CONTROL, event.TOP, GET_UVALUE = info
	IF (TOTAL(((*(*info).feedbparams).verbosity)[2:3]) GE 1) THEN $
    CRISPEX_VERBOSE_GET_ROUTINE, event
	WIDGET_CONTROL, (*(*info).ctrlsdet).dtmin_text, GET_VALUE = textvalue
	(*(*info).detparams).delta_t_dn = FLOAT(LONG(FLOAT(textvalue[0])))
	IF (((*(*info).detparams).delta_t_dn GE 0) AND ((*(*info).detparams).delta_t_dn LT 1)) THEN (*(*info).detparams).delta_t_dn = 1 
	IF ((*(*info).detparams).delta_t_dn LT 0) THEN (*(*info).detparams).delta_t_dn = FLOAT(LONG(ABS((*(*info).detparams).delta_t_dn)))
	IF ((*(*info).detparams).delta_t_dn GT (*(*info).dispparams).t_last) THEN (*(*info).detparams).delta_t_dn = (*(*info).dispparams).t_last
	WIDGET_CONTROL, (*(*info).ctrlsdet).dtmin_text, SET_VALUE = STRTRIM((*(*info).detparams).delta_t_dn, 2)
	CRISPEX_DISPRANGE_T_RANGE, event
END

PRO CRISPEX_RETRIEVE_DET_DELTA_T_UP, event
; Handles the change in delta_t up from the detection framenumber
	WIDGET_CONTROL, event.TOP, GET_UVALUE = info
	IF (TOTAL(((*(*info).feedbparams).verbosity)[2:3]) GE 1) THEN $
    CRISPEX_VERBOSE_GET_ROUTINE, event
	WIDGET_CONTROL, (*(*info).ctrlsdet).dtmax_text, GET_VALUE = textvalue
	(*(*info).detparams).delta_t_up = FLOAT(LONG(FLOAT(textvalue[0])))
	IF (((*(*info).detparams).delta_t_up GE 0) AND ((*(*info).detparams).delta_t_up LT 1)) THEN (*(*info).detparams).delta_t_up = 1 
	IF ((*(*info).detparams).delta_t_up LT 0) THEN (*(*info).detparams).delta_t_up = FLOAT(LONG(ABS((*(*info).detparams).delta_t_up)))
	IF ((*(*info).detparams).delta_t_up GT (*(*info).dispparams).t_last) THEN (*(*info).detparams).delta_t_up = (*(*info).dispparams).t_last
	WIDGET_CONTROL, (*(*info).ctrlsdet).dtmax_text, SET_VALUE = STRTRIM((*(*info).detparams).delta_t_up, 2)
	CRISPEX_DISPRANGE_T_RANGE, event
END

PRO CRISPEX_RETRIEVE_DET_LP_DN, event
; Handles the change in lower spectral boundary for the detection extraction
	WIDGET_CONTROL, event.TOP, GET_UVALUE = info
	IF (TOTAL(((*(*info).feedbparams).verbosity)[2:3]) GE 1) THEN $
    CRISPEX_VERBOSE_GET_ROUTINE, event
	WIDGET_CONTROL, (*(*info).ctrlsdet).dlpmin_text, GET_VALUE = textvalue
	(*(*info).detparams).lp_dn = FLOAT(textvalue[0])
	IF ((*(*info).detparams).lp_dn LT (*(*info).dispparams).lp_first) THEN (*(*info).detparams).lp_dn = (*(*info).dispparams).lp_first ELSE IF ((*(*info).detparams).lp_dn GE (*(*info).detparams).lp_up) THEN $
		(*(*info).detparams).lp_dn = (*(*info).detparams).lp_up-1
	WIDGET_CONTROL, (*(*info).ctrlsdet).dlpmin_text, SET_VALUE = STRTRIM((*(*info).detparams).lp_dn,2)
	(*(*info).dispparams).lp_low = (*(*info).detparams).lp_dn
	WIDGET_CONTROL, (*(*info).ctrlscp).lower_lp_text, SET_VALUE = STRTRIM((*(*info).dispparams).lp_low,2)
	CRISPEX_DISPRANGE_LP_RANGE, event
END

PRO CRISPEX_RETRIEVE_DET_LP_UP, event
; Handles the change in upper spectral boundary for the detection extraction
	WIDGET_CONTROL, event.TOP, GET_UVALUE = info
	IF (TOTAL(((*(*info).feedbparams).verbosity)[2:3]) GE 1) THEN $
    CRISPEX_VERBOSE_GET_ROUTINE, event
	WIDGET_CONTROL, (*(*info).ctrlsdet).dlpmax_text, GET_VALUE = textvalue
	(*(*info).detparams).lp_up = FLOAT(textvalue[0])
	IF ((*(*info).detparams).lp_up GT (*(*info).dispparams).lp_last) THEN (*(*info).detparams).lp_up = (*(*info).dispparams).lp_last ELSE IF ((*(*info).detparams).lp_up LE (*(*info).detparams).lp_dn) THEN $
		(*(*info).detparams).lp_up = (*(*info).detparams).lp_dn+1
	WIDGET_CONTROL, (*(*info).ctrlsdet).dlpmax_text, SET_VALUE = STRTRIM((*(*info).detparams).lp_up,2)
	(*(*info).dispparams).lp_upp = (*(*info).detparams).lp_up
	WIDGET_CONTROL, (*(*info).ctrlscp).upper_lp_text, SET_VALUE = STRTRIM((*(*info).dispparams).lp_upp,2)
	CRISPEX_DISPRANGE_LP_RANGE, event
END

PRO CRISPEX_RETRIEVE_DET_LP_REF_DN, event
; Handles the change in lower spectral boundary for the detection extraction
	WIDGET_CONTROL, event.TOP, GET_UVALUE = info
	IF (TOTAL(((*(*info).feedbparams).verbosity)[2:3]) GE 1) THEN $
    CRISPEX_VERBOSE_GET_ROUTINE, event
	WIDGET_CONTROL, (*(*info).ctrlsdet).refdlpmin_text, GET_VALUE = textvalue
	(*(*info).detparams).lp_ref_dn = FLOAT(textvalue[0])
	IF ((*(*info).detparams).lp_ref_dn LT (*(*info).dispparams).lp_ref_first) THEN (*(*info).detparams).lp_ref_dn = (*(*info).dispparams).lp_ref_first ELSE $
		IF ((*(*info).detparams).lp_ref_dn GE (*(*info).detparams).lp_ref_up) THEN (*(*info).detparams).lp_ref_dn = (*(*info).detparams).lp_ref_up-1
	WIDGET_CONTROL, (*(*info).ctrlsdet).refdlpmin_text, SET_VALUE = STRTRIM((*(*info).detparams).lp_ref_dn,2)
	(*(*info).dispparams).lp_ref_low = (*(*info).detparams).lp_ref_dn
END

PRO CRISPEX_RETRIEVE_DET_LP_REF_UP, event
; Handles the change in upper spectral boundary for the detection extraction
	WIDGET_CONTROL, event.TOP, GET_UVALUE = info
	IF (TOTAL(((*(*info).feedbparams).verbosity)[2:3]) GE 1) THEN $
    CRISPEX_VERBOSE_GET_ROUTINE, event
	WIDGET_CONTROL, (*(*info).ctrlsdet).refdlpmax_text, GET_VALUE = textvalue
	(*(*info).detparams).lp_ref_up = FLOAT(textvalue[0])
	IF ((*(*info).detparams).lp_ref_up GT (*(*info).dispparams).lp_ref_last) THEN (*(*info).detparams).lp_ref_up = (*(*info).dispparams).lp_ref_last ELSE $
		IF ((*(*info).detparams).lp_ref_up LE (*(*info).detparams).lp_ref_dn) THEN (*(*info).detparams).lp_ref_up = (*(*info).detparams).lp_ref_dn+1
	WIDGET_CONTROL, (*(*info).ctrlsdet).refdlpmax_text, SET_VALUE = STRTRIM((*(*info).detparams).lp_ref_up,2)
	(*(*info).dispparams).lp_ref_upp = (*(*info).detparams).lp_ref_up
END

PRO CRISPEX_RETRIEVE_DET_GET_SLAB, event, inparams, w_lpts_out, gapresult_out, $
  loopslab_out, crossloc_out, loopsize_out, t_det_out, t_low_out, t_upp_out, $
  SAVE_DET=save_det
; Handles the in-program display of the detection loopslab
	WIDGET_CONTROL, event.TOP, GET_UVALUE = info
	IF (TOTAL(((*(*info).feedbparams).verbosity)[2:3]) GE 1) THEN $
    CRISPEX_VERBOSE_GET_ROUTINE, event
	tmp_loopslab = 0
	delta = FLOOR((*(*info).detparams).width/2.)
  ; Set feedback messages and feedback window titles
  IF KEYWORD_SET(SAVE_DET) THEN BEGIN
    IF (inparams.lp_dn EQ inparams.lp_up) THEN $
      save_message = 'slice' $
    ELSE $
      save_message = 'slab'
    feedb_title = 'Saving retrieved detection loop '+save_message+'(s)'
  ENDIF ELSE BEGIN
    feedb_title='Retrieved detection loop slice'
  ENDELSE
  ; Determine w_lpts
  nw_lpts = 0
	FOR k=((*(*info).detparams).mid-delta),((*(*info).detparams).mid+delta) DO BEGIN
    xlr_det = (inparams.xlr)[*,k]
    ylr_det = (inparams.ylr)[*,k]
   w_lpts_tmp =  $
      WHERE((xlr_det GE 0) AND (xlr_det LT (inparams.nx)) AND $
            (ylr_det GE 0) AND (ylr_det LT (inparams.ny)), $
            nw_lpts_tmp)
    IF (nw_lpts GT 0) THEN BEGIN
      IF (nw_lpts_tmp LT nw_lpts) THEN w_lpts_out = w_lpts_tmp
    ENDIF ELSE $
      w_lpts_out = w_lpts_tmp
  ENDFOR
  ; Save time variables
	t_det_out = (*(*(*info).detparams).t)[inparams.idx]
	t_low_out = t_det_out - (*(*info).detparams).delta_t_dn > $
                (*(*info).dispparams).t_first
	t_upp_out = t_det_out + (*(*info).detparams).delta_t_up < $
                (*(*info).dispparams).t_last
  IF KEYWORD_SET(SAVE_DET) THEN BEGIN
    (*(*info).dispparams).t_low = t_low_out
    (*(*info).dispparams).t_upp = t_upp_out
  ENDIF
  pass = 0L
  ; Loop over detection width
	FOR k=((*(*info).detparams).mid-delta),((*(*info).detparams).mid+delta) DO BEGIN
    xlr_det = (inparams.xlr)[*,k]
    ylr_det = (inparams.ylr)[*,k]
    ; If saving or showing exact time slices in-program, call appropriate
    ; routine
		IF (KEYWORD_SET(SAVE_DET) OR (*(*info).dispswitch).exts) THEN BEGIN
			WIDGET_CONTROL,/HOURGLASS
			lp_orig = (*(*info).dataparams).lp
			FOR i=inparams.lp_dn,inparams.lp_up DO BEGIN
        pass += 1L
        ; Set the wavelength index
        IF (inparams.detimref EQ 1) THEN $
				  (*(*info).dataparams).lp = i $
        ELSE $
				  (*(*info).dataparams).lp_ref = i
				CRISPEX_LOOP_GET_EXACT_SLICE, event, *inparams.data, xlr_det, ylr_det, $
          inparams.xlp, inparams.ylp, w_lpts_out, det_loopslice, $
          det_crossloc, det_loopsize, IM=(inparams.detimref EQ 1), $
          NO_NLP=inparams.no_nlp
				IF (i EQ inparams.lp_dn) THEN $
          loopslab = det_loopslice $
        ELSE $
          loopslab = [[[loopslab]], [[det_loopslice]]]
        ; Re-estimate running time and update feedback
				t_1 = SYSTIME(/SECONDS)
				CRISPEX_ESTIMATE_FULL_TIME_RUNNING, pass, inparams.maxpass, $
          inparams.t_0, t_1, denom, units, accumsectime, totalsectime
				feedback_text = 'Detection '+STRTRIM(inparams.idx,2)+', position '+$
          STRTRIM(k,2)+'/'+STRTRIM((*(*info).detparams).width,2)+$
          ': '+STRTRIM(i-inparams.lp_dn+1,2)+'/'+$
          STRTRIM(inparams.lp_up-inparams.lp_dn+1,2)+$
          '('+STRTRIM(pass,2)+'/'+STRTRIM(inparams.maxpass,2)+')'+$
          ' slices extracted in '+$
          STRTRIM(STRING(accumsectime/denom,FORMAT='(3(F9.2,x))'),2)+'/'+$
          STRTRIM(STRING(totalsectime/denom,FORMAT='(3(F9.2,x))'),2)+units
				CRISPEX_UPDATE_USER_FEEDBACK, event, $
          title=feedb_title, var=pass-1, maxvar=inparams.maxpass, $
          feedback_text=feedback_text, DESTROY_TOP=KEYWORD_SET(SAVE_DET)
			ENDFOR
			(*(*info).dataparams).lp = lp_orig
			IF (~KEYWORD_SET(SAVE_DET) AND $
        (k EQ (*(*info).detparams).mid+delta)) THEN $
        CRISPEX_WINDOW_USER_FEEDBACK_CLOSE, event
		ENDIF ELSE BEGIN
      ; If not saving or showing exact time slice, get approximate slice
			CRISPEX_LOOP_GET_APPROX_SLAB, event, xlr_det, ylr_det, inparams.xlp, $
        inparams.ylp, w_lpts_out, loopslab, det_crossloc, det_loopsize
		ENDELSE
		IF (k EQ (*(*info).detparams).mid) THEN BEGIN
			crossloc_out = det_crossloc
			loopsize_out = det_loopsize
		ENDIF
		tmp_loopslab += loopslab
	ENDFOR
  ; If not saving check whether an empty slice needs to be created
  IF (~KEYWORD_SET(SAVE_DET) AND (nw_lpts NE N_ELEMENTS(xlr_det))) THEN $
    *(*(*info).loopsdata).det_empty_slice = $
      MAKE_ARRAY(N_ELEMENTS(xlr_det), (SIZE(loopslab))[2], $
        TYPE=SIZE(*(*(*info).data).imagedata, /TYPE))
  ; Determine the gaps in the path
  gapresult_out = CRISPEX_ARRAY_GET_GAP(w_lpts_out, N_ELEMENTS(xlr_det))
  ; Divide the space-time diagram values by the width of the path
	loopslab_out = tmp_loopslab/(*(*info).detparams).width
END

PRO CRISPEX_RETRIEVE_DET_CANCEL, event
; Handles the closing of the detection file menu
	WIDGET_CONTROL, event.TOP, GET_UVALUE = info
	IF (TOTAL(((*(*info).feedbparams).verbosity)[2:3]) GE 1) THEN $
    CRISPEX_VERBOSE_GET_ROUTINE, event
	(*(*info).loopswitch).retrieve_detfile = 0
	(*(*info).winswitch).showretrdet = 0
	IF (((*(*info).feedbparams).verbosity)[3] EQ 1) THEN $
    CRISPEX_VERBOSE_GET, event, [(*(*info).loopswitch).retrieve_detfile,(*(*info).winids).detsavetlb], labels=['Retrieving detections','retrdettlb was']
	CRISPEX_DISPRANGE_T_RESET, event
	WIDGET_CONTROL, (*(*info).winids).detsavetlb, /DESTROY
	(*(*info).winids).detsavetlb = 0
	IF ((*(*info).winids).retrdettlb GT 0) THEN WIDGET_CONTROL, (*(*info).winids).retrdettlb, /DESTROY
	(*(*info).winids).retrdettlb = 0
	*(*(*info).detparams).sel_dets = REPLICATE(0,(*(*info).detparams).nr_dets)
	(*(*info).overlayswitch).det_overlay_all = 1
	(*(*info).savswitch).pos_dets = 1
	(*(*info).savswitch).det_imref_only = 1
	(*(*info).detparams).lp_dn = (*(*info).dispparams).lp_first		&	(*(*info).detparams).lp_up = (*(*info).dispparams).lp_last
	(*(*info).detparams).lp_ref_dn = (*(*info).dispparams).lp_ref_first	&	(*(*info).detparams).lp_ref_up = (*(*info).dispparams).lp_ref_last
	WIDGET_CONTROL, (*(*info).ctrlscp).det_file_but, /SENSITIVE
	WIDGET_CONTROL, (*(*info).ctrlscp).lower_t_text, SENSITIVE = 1
	WIDGET_CONTROL, (*(*info).ctrlscp).upper_t_text, SENSITIVE = 1
END

;========================= RETRIEVE FROM SAVED LOOP POINT PROCEDURES
PRO CRISPEX_RETRIEVE_LOOP_MENU, event, set_but_array, $
  XOFFSET=xoffset, YOFFSET=yoffset
; Sets up the retrieved loop points menu and reads in the data from the respective files
	WIDGET_CONTROL, event.TOP, GET_UVALUE = info
	IF (TOTAL(((*(*info).feedbparams).verbosity)[2:3]) GE 1) THEN $
    CRISPEX_VERBOSE_GET_ROUTINE, event
	CRISPEX_FIND_CLSAV, event, /ALLOW_SELECT_DIR, /ALL_FILES
	IF ((*(*info).retrparams).clfilecount GT 0) THEN BEGIN
    IF (N_ELEMENTS(XOFFSET) NE 1) THEN xoffset = (*(*info).winsizes).spxoffset
    IF (N_ELEMENTS(YOFFSET) NE 1) THEN yoffset = 0
		WIDGET_CONTROL,/HOURGLASS
		WIDGET_CONTROL, (*(*info).ctrlscp).sel_saved_loop, SENSITIVE = 0
		(*(*info).loopswitch).retrieve_loops = 1
		filenames = *(*(*info).retrparams).clfiles
		filecount = (*(*info).retrparams).clfilecount
		IF (N_ELEMENTS(set_but_array) NE filecount) THEN $
      *(*(*info).retrparams).sel_loops = INTARR((*(*info).retrparams).clfilecount)
		eventval = INDGEN(filecount)
		base = WIDGET_BASE(TITLE = 'CRISPEX'+(*(*info).sesparams).instance_label+$
      ': Save from retrieved loop(s)', GROUP_LEADER = (*(*info).winids).root, $
      TLB_FRAME_ATTR = 1, /TLB_KILL_REQUEST_EVENTS)
		disp = WIDGET_BASE(base, /COLUMN)
		disp2 = WIDGET_BASE(disp, /COLUMN, /FRAME)
		sel_allnone = WIDGET_BASE(disp2, /ROW)
		sel_allnone_lab = WIDGET_LABEL(sel_allnone, VALUE = 'Select:', /ALIGN_LEFT)
		sel_allnone_buts = WIDGET_BASE(sel_allnone, /ROW, /EXCLUSIVE)
		(*(*info).ctrlsloop).sel_all = WIDGET_BUTTON(sel_allnone_buts, $
      VALUE = 'All', EVENT_PRO = 'CRISPEX_RETRIEVE_LOOP_SEL_ALL')
		(*(*info).ctrlsloop).sel_none = WIDGET_BUTTON(sel_allnone_buts, $
      VALUE = 'None', EVENT_PRO = 'CRISPEX_RETRIEVE_LOOP_SEL_NONE')
		WIDGET_CONTROL, (*(*info).ctrlsloop).sel_none, /SET_BUTTON
		update_filelist = WIDGET_BUTTON(sel_allnone, VALUE = 'Update filelist', $
      EVENT_PRO = 'CRISPEX_RETRIEVE_LOOP_UPDATE_FILELIST')
    sel_buts = WIDGET_BASE(disp2, /COLUMN, /NONEXCLUSIVE, $
      X_SCROLL_SIZE=(filecount GT 16)*400, Y_SCROLL_SIZE=(filecount GT 16)*425) 
    ; Initialise variables
    *(*(*info).retrparams).xlp = PTRARR(filecount, /ALLOCATE_HEAP)
    *(*(*info).retrparams).ylp = PTRARR(filecount, /ALLOCATE_HEAP)
    *(*(*info).retrparams).xlr = PTRARR(filecount, /ALLOCATE_HEAP)
    *(*(*info).retrparams).ylr = PTRARR(filecount, /ALLOCATE_HEAP)
		FOR i=0,filecount-1 DO BEGIN
			IF (N_ELEMENTS(set_but_array) NE filecount) THEN $
        (*(*(*info).retrparams).sel_loops)[i] = 0
			singlefilename = $
        (STRSPLIT((*(*(*info).retrparams).clfiles)[i], PATH_SEP(), /EXTRACT))[$
        N_ELEMENTS(STRSPLIT((*(*(*info).retrparams).clfiles)[i], PATH_SEP(), $
        /EXTRACT))-1]
			name = 'sel_but_'+STRTRIM(i,2)
			but_val = 'L'+STRTRIM(i,2)+': '+singlefilename
			sel_but = WIDGET_BUTTON(sel_buts, VALUE = but_val, UVALUE = eventval[i], $
        EVENT_PRO = 'CRISPEX_RETRIEVE_LOOP_MENU_EVENT', UNAME = name) 
			IF (N_ELEMENTS(set_but_array) GT 0) THEN $
        WIDGET_CONTROL, sel_but, SET_BUTTON = set_but_array[i]
			RESTORE,(*(*(*info).retrparams).clfiles)[i]
      ; Support for different saving methods of xp and yp points
      IF (SIZE(x_coords,/N_DIMENSIONS) EQ 2) THEN x_coords = REFORM(x_coords[0,*])
      IF (SIZE(y_coords,/N_DIMENSIONS) EQ 2) THEN y_coords = REFORM(y_coords[0,*])
			*(*(*(*info).retrparams).xlp)[i] = x_coords
			*(*(*(*info).retrparams).ylp)[i] = y_coords
			*(*(*(*info).retrparams).xlr)[i] = x_loop_pts
			*(*(*(*info).retrparams).ylr)[i] = y_loop_pts
		ENDFOR
		spectral_pos = WIDGET_BASE(disp, /ROW, /FRAME, /EXCLUSIVE)
		(*(*info).ctrlsloop).all_pos = WIDGET_BUTTON(spectral_pos, $
      VALUE = 'At all spectral positions', EVENT_PRO = 'CRISPEX_RETRIEVE_LOOP_ALL_POS')
		WIDGET_CONTROL, (*(*info).ctrlsloop).all_pos, /SET_BUTTON
		(*(*info).ctrlsloop).saved_pos = WIDGET_BUTTON(spectral_pos, $
      VALUE = 'At saved spectral position')
		del_clsav = WIDGET_BASE(disp, /ROW, /FRAME, /EXCLUSIVE)
		(*(*info).ctrlsloop).del_files = WIDGET_BUTTON(del_clsav, $
      VALUE = 'Delete *clsav file(s) after saving',  $
      EVENT_PRO = 'CRISPEX_RETRIEVE_LOOP_DELETE_CLSAV')
		WIDGET_CONTROL, (*(*info).ctrlsloop).del_files, /SET_BUTTON
		(*(*info).ctrlsloop).keep_files = WIDGET_BUTTON(del_clsav, $
      VALUE = 'Keep *clsav file(s) after saving')
		save_cube = WIDGET_BASE(disp, /ROW, /FRAME)
		save_cube_lab = WIDGET_LABEL(save_cube, VALUE = 'Save from: ')
		save_cube_but = WIDGET_BASE(save_cube, /ROW)
    save_imrefsji_labels = ['main','reference','slit-jaw image']
    save_imrefsji = CW_BGROUP(save_cube_but, save_imrefsji_labels, $
                          BUTTON_UVALUE=INDGEN(N_ELEMENTS(save_imrefsji_labels)),$
                          IDS=save_imrefsji_ids, /NONEXCLUSIVE, /ROW, $
                          EVENT_FUNC='CRISPEX_BGROUP_SAVE_IMREFSJI_LOOP')
    sensbutton = [0, $
      (*(*info).winswitch).showref AND ((*(*info).dataparams).refnt GT 1), $
      (*(*info).winswitch).showsji AND ((*(*info).dataparams).sjint GT 1)]
    FOR i=0,N_ELEMENTS(save_imrefsji_labels)-1 DO $
      WIDGET_CONTROL, save_imrefsji_ids[i], $
        SET_BUTTON=(*(*info).savswitch).imrefsji[i], SENSITIVE=sensbutton[i]
    (*(*info).ctrlsloop).save_imrefsji_ids = save_imrefsji_ids
    ; Decision buttons
		dec_buts = WIDGET_BASE(disp, COLUMN=3, /GRID_LAYOUT, /ALIGN_CENTER)
		change_path_but = WIDGET_BUTTON(dec_buts, VALUE = 'Change path', $
      EVENT_PRO = 'CRISPEX_SAVE_SET_OPATH')
		cancel = WIDGET_BUTTON(dec_buts, VALUE = 'Cancel', $
      EVENT_PRO = 'CRISPEX_RETRIEVE_LOOP_MENU_CANCEL')
		get_loops = WIDGET_BUTTON(dec_buts, VALUE = 'Retrieve and save', $
      EVENT_PRO = 'CRISPEX_RETRIEVE_LOOP_MENU_CONTINUE', SENSITIVE = 0)
		(*(*info).ctrlsloop).get_loops = get_loops
		WIDGET_CONTROL, base, /REALIZE, TLB_SET_XOFFSET=xoffset, TLB_SET_YOFFSET=yoffset
		WIDGET_CONTROL, base, SET_UVALUE = info
		XMANAGER, 'CRISPEX', base, /NO_BLOCK
		(*(*info).winids).savetlb = base
		IF (((*(*info).feedbparams).verbosity)[3] EQ 1) THEN $
      CRISPEX_VERBOSE_GET, event, [(*(*info).winids).savetlb,filecount,$
      (*(*info).loopswitch).restore_loops],$
      labels=['savetlb','Retrieved loops','Was restoring loops']
	ENDIF ELSE BEGIN
		CRISPEX_WINDOW_OK, event,'ERROR!',$
      'No saved loop points (*.clsav) files found.',$
      OK_EVENT='CRISPEX_CLOSE_EVENT_WINDOW', BASE=tlb
		(*(*info).winids).errtlb = tlb
	ENDELSE
	IF (*(*info).loopswitch).restore_loops THEN BEGIN
		(*(*info).loopswitch).was_restore_loops = (*(*info).loopswitch).restore_loops
		(*(*info).loopswitch).restore_loops = 0
	ENDIF
END

PRO CRISPEX_RETRIEVE_LOOP_MENU_EVENT, event
; Handles the selection of a certain retrieved loop point file
	WIDGET_CONTROL, event.TOP, GET_UVALUE = info
	IF (TOTAL(((*(*info).feedbparams).verbosity)[2:3]) GE 1) THEN $
    CRISPEX_VERBOSE_GET_ROUTINE, event
	WIDGET_CONTROL, event.ID, GET_UVALUE = eventval
	(*(*(*info).retrparams).sel_loops)[eventval] = ( (*(*(*info).retrparams).sel_loops)[eventval] EQ 0)
	condition = WHERE(*(*(*info).retrparams).sel_loops EQ 1, count)
	WIDGET_CONTROL, (*(*info).ctrlsloop).get_loops, SENSITIVE = (count GT 0)
	WIDGET_CONTROL, (*(*info).ctrlsloop).sel_all, SET_BUTTON = (count EQ (*(*info).retrparams).clfilecount) 
	WIDGET_CONTROL, (*(*info).ctrlsloop).sel_none, SET_BUTTON = ABS((count GT 0)-1)
	IF (((*(*info).feedbparams).verbosity)[3] EQ 1) THEN $
    CRISPEX_VERBOSE_GET, event, [eventval,(*(*(*info).retrparams).sel_loops)[eventval],$
		(((N_ELEMENTS(condition) GT 0) AND (TOTAL(condition) NE -1)) AND (N_ELEMENTS(condition) EQ (*(*info).retrparams).clfilecount)),ABS(((N_ELEMENTS(condition) GT 0) AND (TOTAL(condition) NE -1))-1),$
		N_ELEMENTS(condition)-(TOTAL(condition) EQ -1)], labels=['Retrieved loop ID','Retreived loop selected','All selected','None selected','Total selected']
	CRISPEX_DRAW_IMREF, event
END

PRO CRISPEX_RETRIEVE_LOOP_MENU_CANCEL, event
; Handles the closing of the retrieved loop menu
	WIDGET_CONTROL, event.TOP, GET_UVALUE = info
	IF (TOTAL(((*(*info).feedbparams).verbosity)[2:3]) GE 1) THEN $
    CRISPEX_VERBOSE_GET_ROUTINE, event
	WIDGET_CONTROL, (*(*info).ctrlscp).sel_saved_loop, SENSITIVE = 1
	(*(*info).loopswitch).retrieve_loops = 0
	(*(*info).loopswitch).restore_loops = (*(*info).loopswitch).was_restore_loops
	IF (((*(*info).feedbparams).verbosity)[3] EQ 1) THEN $
    CRISPEX_VERBOSE_GET, event, [(*(*info).loopswitch).retrieve_loops,(*(*info).winids).savetlb,(*(*info).loopswitch).restore_loops], $
		labels=['Retrieving loops','savetlb was','Restoring loops']
	CRISPEX_UPDATE_T, event
	CRISPEX_DRAW_IMREF, event
	WIDGET_CONTROL, (*(*info).winids).savetlb, /DESTROY
	(*(*info).winids).savetlb = 0
END

PRO CRISPEX_RETRIEVE_LOOP_MENU_CONTINUE, event
; Opens the warning windows giving the saving time estimates of the chosen saving procedure, intermediate step towards saving selected retrieved loopslabs
	WIDGET_CONTROL, event.TOP, GET_UVALUE = info
	IF (TOTAL(((*(*info).feedbparams).verbosity)[2:3]) GE 1) THEN $
    CRISPEX_VERBOSE_GET_ROUTINE, event
	CRISPEX_SAVE_CHECK_PATH_WRITE, event
	IF ((*(*info).paths).opath_write EQ 1) THEN BEGIN
    whereretr = WHERE(*(*(*info).retrparams).sel_loops EQ 1, count)
    IF (count GT 0) THEN BEGIN
  		*(*(*info).retrparams).retrieve_files = (*(*(*info).retrparams).clfiles)[whereretr]
  		(*(*info).retrparams).retrieve_filecount = N_ELEMENTS(*(*(*info).retrparams).retrieve_files)
  		IF ((*(*info).savswitch).all_pos_loops EQ 0) THEN BEGIN
  			IF ((*(*info).feedbparams).estimate_run EQ 0) THEN BEGIN
  				CRISPEX_ESTIMATE_TIME_WINDOW, event
  				CRISPEX_ESTIMATE_TIME_CALCULATION, event
  			ENDIF
  			time = 0
  			FOR i=0,(*(*info).retrparams).retrieve_filecount-1 DO BEGIN
  				RESTORE,(*(*(*info).retrparams).retrieve_files)[i]
  				sub_time = (*(*info).feedbparams).estimate_time * $
            N_ELEMENTS(w_loop_pts)/FLOAT((*(*info).feedbparams).estimate_lx) * $
            (*(*info).dispparams).t_range * TOTAL((*(*info).savswitch).imrefsji)
  				time += sub_time
  			ENDFOR
  			CRISPEX_ESTIMATE_FULL_TIME, time, denom, units
  			(*(*info).savswitch).cont = 1
  			CRISPEX_SAVE_WARNING_YESNO, event, STRTRIM((*(*info).retrparams).retrieve_filecount,2)+' *clsav file(s) selected. Saving the exact loop slice(s) may take',$
  				'up to about '+STRTRIM(CEIL(time/denom),2)+units+' and equally named (approximated) loop','slice(s) may be overwritten. Do you wish to continue saving?', $
  				OK_EVENT='CRISPEX_SAVE_LOOPSL_CONTINUE', CANCEL_EVENT='CRISPEX_SAVE_LOOPSL_ABORT'
  			IF ((*(*info).winswitch).estimate_win EQ 1) THEN BEGIN
  				WIDGET_CONTROL, (*(*info).winids).estimatetlb, /DESTROY
  				(*(*info).winids).estimatetlb = 0
  				(*(*info).winswitch).estimate_win = 0
  			ENDIF
  		ENDIF ELSE IF (*(*info).savswitch).all_pos_loops THEN BEGIN
  			IF ((*(*info).feedbparams).estimate_run EQ 0) THEN BEGIN
  				CRISPEX_ESTIMATE_TIME_WINDOW, event
  				CRISPEX_ESTIMATE_TIME_CALCULATION, event
  			ENDIF
  			time = 0
        sub_base_time = (*(*info).feedbparams).estimate_time / $
          FLOAT((*(*info).feedbparams).estimate_lx) * $
          (*(*info).dispparams).t_range
  			FOR i=0,(*(*info).retrparams).retrieve_filecount-1 DO BEGIN
          sub_time = 0.
  				RESTORE,(*(*(*info).retrparams).retrieve_files)[i]
          IF ((*(*info).savswitch).imrefsji[0] EQ 1) THEN $
    				sub_time += (*(*info).dataparams).nlp * sub_base_time * $
              N_ELEMENTS(w_loop_pts)
          IF ((*(*info).savswitch).imrefsji[1] EQ 1) THEN $
    				sub_time += (*(*info).dataparams).refnlp * sub_base_time * $
              N_ELEMENTS(w_loop_pts)
          IF ((*(*info).savswitch).imrefsji[2] EQ 1) THEN $
    				sub_time += sub_base_time * N_ELEMENTS(w_loop_pts)
  				time += sub_time
  			ENDFOR
  			CRISPEX_ESTIMATE_FULL_TIME, time, denom, units
  			(*(*info).savswitch).cont = 2
  			CRISPEX_SAVE_WARNING_YESNO, event, STRTRIM((*(*info).retrparams).retrieve_filecount,2)+' *clsav file(s) selected. Saving the exact loop slab(s) may take',$
  				'up to about '+STRTRIM(CEIL(time/denom),2)+units+' and equally named (approximated) loop','slab(s) may be overwritten. Do you wish to continue saving?',$
  				OK_EVENT='CRISPEX_SAVE_LOOPSL_CONTINUE', CANCEL_EVENT='CRISPEX_SAVE_LOOPSL_ABORT'
  			IF ((*(*info).winswitch).estimate_win EQ 1) THEN BEGIN
  				WIDGET_CONTROL, (*(*info).winids).estimatetlb, /DESTROY
  				(*(*info).winids).estimatetlb = 0
  				(*(*info).winswitch).estimate_win = 0
  			ENDIF
  		ENDIF ELSE RETURN
    ENDIF
		IF (((*(*info).feedbparams).verbosity)[3] EQ 1) THEN $
      CRISPEX_VERBOSE_GET, event, [(*(*info).retrparams).retrieve_filecount,(*(*info).savswitch).cont],labels=['Number of retrieved loops','Saving procedure']
	ENDIF
END

PRO CRISPEX_RETRIEVE_LOOP_SEL_ALL, event
; Handles the selection of all retrieved loop files
	WIDGET_CONTROL, event.TOP, GET_UVALUE = info
	IF (TOTAL(((*(*info).feedbparams).verbosity)[2:3]) GE 1) THEN $
    CRISPEX_VERBOSE_GET_ROUTINE, event
	*(*(*info).retrparams).sel_loops = REPLICATE(1,(*(*info).retrparams).clfilecount)
	WIDGET_CONTROL, (*(*info).ctrlsloop).get_loops, SENSITIVE = 1
	FOR i=0,(*(*info).retrparams).clfilecount-1 DO BEGIN
		name = 'sel_but_'+STRTRIM(i,2)
		WIDGET_CONTROL, WIDGET_INFO(event.TOP, FIND_BY_UNAME = name), SET_BUTTON = 1
	ENDFOR		
	CRISPEX_DRAW_IMREF, event
END

PRO CRISPEX_RETRIEVE_LOOP_SEL_NONE, event
; Handles the selection of no retrieved loop files
	WIDGET_CONTROL, event.TOP, GET_UVALUE = info
	IF (TOTAL(((*(*info).feedbparams).verbosity)[2:3]) GE 1) THEN $
    CRISPEX_VERBOSE_GET_ROUTINE, event
	*(*(*info).retrparams).sel_loops = REPLICATE(0,(*(*info).retrparams).clfilecount)
	WIDGET_CONTROL, (*(*info).ctrlsloop).get_loops, SENSITIVE = 0
	FOR i=0,(*(*info).retrparams).clfilecount-1 DO BEGIN
		name = 'sel_but_'+STRTRIM(i,2)
		WIDGET_CONTROL, WIDGET_INFO(event.TOP, FIND_BY_UNAME = name), SET_BUTTON = 0
	ENDFOR		
	CRISPEX_DRAW_IMREF, event
END

PRO CRISPEX_RETRIEVE_LOOP_UPDATE_FILELIST, event
; Handles the update of the retrieved file list
	WIDGET_CONTROL, event.TOP, GET_UVALUE = info
	IF (TOTAL(((*(*info).feedbparams).verbosity)[2:3]) GE 1) THEN $
    CRISPEX_VERBOSE_GET_ROUTINE, event
	WIDGET_CONTROL, (*(*info).winids).root, SET_UVALUE=info
  geometry = WIDGET_INFO(event.TOP, /GEOMETRY)
	WIDGET_CONTROL, event.TOP, /DESTROY
	event.TOP = (*(*info).winids).root
	CRISPEX_RETRIEVE_LOOP_MENU, event, XOFFSET=geometry.xoffset, $
    YOFFSET=geometry.yoffset-22 ; subtract 22 for window top bar
	CRISPEX_DRAW_IMREF, event
END

PRO CRISPEX_RETRIEVE_LOOP_DELETE_CLSAV, event
; Enables or disables the deletion of CLSAV files after saving the respective loopslabs
	WIDGET_CONTROL, event.TOP, GET_UVALUE = info
	IF (TOTAL(((*(*info).feedbparams).verbosity)[2:3]) GE 1) THEN $
    CRISPEX_VERBOSE_GET_ROUTINE, event
	(*(*info).savswitch).delete_clsav = event.SELECT
	IF (((*(*info).feedbparams).verbosity)[3] EQ 1) THEN $
    CRISPEX_VERBOSE_GET, event, [(*(*info).savswitch).delete_clsav],labels=['Delete loop path file']
END

PRO CRISPEX_RETRIEVE_LOOP_ALL_POS, event
; Enables the extraction of the retrieved loop at all or only the saved spectral positions
	WIDGET_CONTROL, event.TOP, GET_UVALUE = info
	IF (TOTAL(((*(*info).feedbparams).verbosity)[2:3]) GE 1) THEN $
    CRISPEX_VERBOSE_GET_ROUTINE, event
	(*(*info).savswitch).all_pos_loops = event.SELECT
	IF (((*(*info).feedbparams).verbosity)[3] EQ 1) THEN $
    CRISPEX_VERBOSE_GET, event, [(*(*info).savswitch).all_pos_loops],labels=['Saving spectral position setting']
END

PRO CRISPEX_RETRIEVE_LOOP_ALL_LOOPSLAB, event
; Opens the warning windows giving the saving time estimate of the procedure, intermediate step towards saving all retrieved loopslabs (i.e. at all spectral positions)
	WIDGET_CONTROL, event.TOP, GET_UVALUE = info
	IF (TOTAL(((*(*info).feedbparams).verbosity)[2:3]) GE 1) THEN $
    CRISPEX_VERBOSE_GET_ROUTINE, event
	IF ((*(*info).retrparams).clfilecount GT 0) THEN BEGIN
		CRISPEX_SAVE_CHECK_PATH_WRITE, event
		IF ((*(*info).paths).opath_write EQ 1) THEN BEGIN
			(*(*info).savparams).lp_orig = (*(*info).dataparams).lp
			(*(*info).retrparams).retrieve_filecount = (*(*info).retrparams).clfilecount
			*(*(*info).retrparams).retrieve_files = *(*(*info).retrparams).clfiles
			IF ((*(*info).feedbparams).estimate_run EQ 0) THEN BEGIN
				CRISPEX_ESTIMATE_TIME_WINDOW, event
				CRISPEX_ESTIMATE_TIME_CALCULATION, event
			ENDIF
			time = 0
			FOR i=0,(*(*info).retrparams).retrieve_filecount-1 DO BEGIN
				RESTORE,(*(*(*info).retrparams).retrieve_files)[i]
				sub_time = (*(*info).feedbparams).estimate_time * N_ELEMENTS(w_loop_pts)/FLOAT((*(*info).feedbparams).estimate_lx) * (*(*info).dataparams).nlp * (*(*info).dispparams).t_range
				time += sub_time
			ENDFOR
			(*(*info).savswitch).cont = 2
			CRISPEX_ESTIMATE_FULL_TIME, time, denom, units
			CRISPEX_SAVE_WARNING_YESNO, event, STRTRIM((*(*info).retrparams).retrieve_filecount,2)+' *clsav file(s) found. Saving the exact loop slab(s) may take',$
				'up to about '+STRTRIM(CEIL(time/denom),2)+units+' and equally named (approximated) loop','slab(s) may be overwritten. Do you wish to continue saving?',$
				OK_EVENT='CRISPEX_SAVE_LOOPSL_CONTINUE', CANCEL_EVENT='CRISPEX_SAVE_LOOPSL_ABORT'
			IF ((*(*info).winswitch).estimate_win EQ 1) THEN BEGIN
				WIDGET_CONTROL, (*(*info).winids).estimatetlb, /DESTROY
				(*(*info).winids).estimatetlb = 0
				(*(*info).winswitch).estimate_win = 0
			ENDIF
			(*(*info).dataparams).lp = (*(*info).savparams).lp_orig
		ENDIF
		IF (((*(*info).feedbparams).verbosity)[3] EQ 1) THEN $
      CRISPEX_VERBOSE_GET, event, [(*(*info).retrparams).retrieve_filecount,(*(*info).savswitch).cont],labels=['Number of retrieved loops','Saving procedure']
	ENDIF
END

PRO CRISPEX_RETRIEVE_LOOP_ALL_LOOPSLICE, event
; Opens the warning windows giving the saving time estimate of the procedure, intermediate step towards saving all retrieved loopslices (i.e. at saved spectral positions)
	WIDGET_CONTROL, event.TOP, GET_UVALUE = info
	IF (TOTAL(((*(*info).feedbparams).verbosity)[2:3]) GE 1) THEN $
    CRISPEX_VERBOSE_GET_ROUTINE, event
	CRISPEX_FIND_CLSAV, event
	IF ((*(*info).retrparams).clfilecount GT 0) THEN BEGIN
		CRISPEX_SAVE_CHECK_PATH_WRITE, event
		IF ((*(*info).paths).opath_write EQ 1) THEN BEGIN
			(*(*info).retrparams).retrieve_filecount = (*(*info).retrparams).clfilecount
			*(*(*info).retrparams).retrieve_files = *(*(*info).retrparams).clfiles
			IF ((*(*info).feedbparams).estimate_run EQ 0) THEN BEGIN
				CRISPEX_ESTIMATE_TIME_WINDOW, event
				CRISPEX_ESTIMATE_TIME_CALCULATION, event
			ENDIF
			time = 0
			FOR i=0,(*(*info).retrparams).retrieve_filecount-1 DO BEGIN
				RESTORE,(*(*(*info).retrparams).retrieve_files)[i]
				sub_time = (*(*info).feedbparams).estimate_time * N_ELEMENTS(w_loop_pts)/FLOAT((*(*info).feedbparams).estimate_lx) * (*(*info).dispparams).t_range
				time += sub_time
			ENDFOR
			(*(*info).savswitch).cont = 1
			CRISPEX_ESTIMATE_FULL_TIME, time, denom, units
			CRISPEX_SAVE_WARNING_YESNO, event, STRTRIM((*(*info).retrparams).retrieve_filecount,2)+' *clsav file(s) found. Saving the exact loop slice(s) may take',$
				'up to about '+STRTRIM(CEIL(time/denom),2)+units+' and equally named (approximated) loop','slice(s) may be overwritten. Do you wish to continue saving?',$
				OK_EVENT='CRISPEX_SAVE_LOOPSL_CONTINUE', CANCEL_EVENT='CRISPEX_SAVE_LOOPSL_ABORT'
			IF ((*(*info).winswitch).estimate_win EQ 1) THEN BEGIN
				WIDGET_CONTROL, (*(*info).winids).estimatetlb, /DESTROY
				(*(*info).winids).estimatetlb = 0
				(*(*info).winswitch).estimate_win = 0
			ENDIF
		ENDIF
		IF (((*(*info).feedbparams).verbosity)[3] EQ 1) THEN $
      CRISPEX_VERBOSE_GET, event, [(*(*info).retrparams).retrieve_filecount,(*(*info).savswitch).cont],labels=['Number of retrieved loops','Saving procedure']
	ENDIF
END

;========================= IMAGE SCALING PROCEDURES
PRO CRISPEX_SCALING_SELECT_DATA, event
; Handles the selection of scaling 
	WIDGET_CONTROL, event.TOP, GET_UVALUE = info
	IF (TOTAL(((*(*info).feedbparams).verbosity)[2:3]) GE 1) THEN $
    CRISPEX_VERBOSE_GET_ROUTINE, event
  ;index = {0,1,2,3+} -> Main, reference, Doppler, slit-jaw
  (*(*info).scaling).imrefscaling = event.INDEX
  (*(*info).scaling).idx = $
    (((*(*info).scaling).imrefscaling EQ 0) OR ((*(*info).scaling).imrefscaling EQ 2)) * $
    (*(*info).intparams).lp_diag_all + $
    (((*(*info).scaling).imrefscaling GT 0) + ((*(*info).scaling).imrefscaling GT 2)) * $
    (*(*info).intparams).ndiagnostics + $
    ((*(*info).scaling).imrefscaling EQ 1) * (*(*info).intparams).lp_ref_diag_all + $
    ((*(*info).scaling).imrefscaling GT 1) * (*(*info).intparams).nrefdiagnostics + $
    ((*(*info).scaling).imrefscaling GE 3) * ((*(*info).scaling).imrefscaling-3)
	CRISPEX_SCALING_SET_BOXBUTTONS, event
	CRISPEX_SCALING_SET_SLIDERS, event
END

PRO CRISPEX_SCALING_SELECT_TYPE, event
; Handles the selection of scaling 
	WIDGET_CONTROL, event.TOP, GET_UVALUE = info
	IF (TOTAL(((*(*info).feedbparams).verbosity)[2:3]) GE 1) THEN $
    CRISPEX_VERBOSE_GET_ROUTINE, event
  ;index = {0,1,2} -> Based on first, based on current, per time step
  (*(*(*info).scaling).imagescale)[(*(*info).scaling).imrefscaling] = event.INDEX
  CRISPEX_SCALING_APPLY_SELECTED, event, $
    UPDATE_MAIN=(((*(*info).scaling).imrefscaling EQ 0) AND (event.INDEX NE 2)), $
    UPDATE_REF=(((*(*info).scaling).imrefscaling EQ 1) AND (event.INDEX NE 2)), $
    UPDATE_DOP=(((*(*info).scaling).imrefscaling EQ 2) AND (event.INDEX NE 2)), $
    UPDATE_SJI=(((*(*info).scaling).imrefscaling GE 3) AND (event.INDEX NE 2))
	IF (((*(*info).feedbparams).verbosity)[3] EQ 1) THEN $
    CRISPEX_VERBOSE_GET, event, [(*(*info).scaling).imrefscaling,$
    (*(*(*info).scaling).imagescale)[(*(*info).scaling).imrefscaling]],$
		labels=['Scaling image','Scaling setting']
	CRISPEX_SCALING_REDRAW, event
END

PRO CRISPEX_SCALING_APPLY_SELECTED, event, UPDATE_MAIN=update_main, $
  UPDATE_REF=update_ref, UPDATE_DOP=update_dop, UPDATE_SJI=update_sji
	WIDGET_CONTROL, event.TOP, GET_UVALUE = info
	IF (TOTAL(((*(*info).feedbparams).verbosity)[2:3]) GE 1) THEN $
    CRISPEX_VERBOSE_GET_ROUTINE, event
  ; Handle keywords
  IF (N_ELEMENTS(UPDATE_MAIN) EQ 0) THEN $
    update_main = ((*(*(*info).scaling).imagescale)[0] NE 2)
  IF (N_ELEMENTS(UPDATE_REF) EQ 0) THEN $
    update_ref = ((*(*info).winswitch).showref AND $
                  ((*(*(*info).scaling).imagescale)[1] NE 2))
  IF (N_ELEMENTS(UPDATE_DOP) EQ 0) THEN update_dop = $
    (((*(*info).winswitch).showdop AND (*(*info).dispswitch).drawdop) AND $
    ((*(*(*info).scaling).imagescale)[3] NE 2))
  IF (N_ELEMENTS(UPDATE_SJI) EQ 0) THEN update_sji = $
    TOTAL((*(*info).winswitch).showsji GT 0)
  IF update_main THEN BEGIN
    ; Main image
    idx = (*(*info).intparams).lp_diag_all
    CASE (*(*(*info).scaling).imagescale)[0] OF
      0:  minmax_data = (*(*(*info).data).imagedata)[$
            (*(*info).scaling).tsel_scaling_main * (*(*info).dataparams).ns * $
            (*(*info).dataparams).nlp + $
            (*(*info).dataparams).s * (*(*info).dataparams).nlp + (*(*info).dataparams).lp]
      1:  minmax_data = *(*(*info).data).xyslice
    ENDCASE
    IF (*(*info).dispswitch).imscaled THEN $
      minmax_data = CRISPEX_SCALING_DESCALE(minmax_data, $
        (*(*info).dispparams).imbscale, (*(*info).dispparams).imbzero)
    ; Process Stokes scaling
    IF ((*(*info).dispswitch).scalestokes[0] AND $
        ((*(*info).dataparams).s NE 0)) THEN BEGIN
      cont_slice = FLOAT((*(*(*info).data).imagedata)[$
          (*(*info).dispparams).t_main * (*(*info).dataparams).nlp * $
          (*(*info).dataparams).ns + (*(*info).stokesparams).contpos[0]]) 
      IF (*(*info).dispswitch).imscaled THEN $
        cont_slice = CRISPEX_SCALING_DESCALE(cont_slice, $
          (*(*info).dispparams).imbscale, (*(*info).dispparams).imbzero)
      minmax_data /= cont_slice
    ENDIF
    minmax = CRISPEX_SCALING_SLICES(minmax_data, (*(*info).scaling).gamma[idx], $
      (*(*info).scaling).histo_opt_val[idx], /FORCE_HISTO)
    IF ((*(*(*info).scaling).imagescale)[0] EQ 0) THEN BEGIN
      (*(*info).scaling).imagemin = minmax[0]
      (*(*info).scaling).imagemax = minmax[1]
    ENDIF ELSE BEGIN
      (*(*info).scaling).imagemin_curr = minmax[0]
      (*(*info).scaling).imagemax_curr = minmax[1]
    ENDELSE
  ENDIF

  ; Reference image
  IF update_ref THEN BEGIN
    idx = (*(*info).intparams).ndiagnostics + (*(*info).intparams).lp_ref_diag_all
    CASE (*(*(*info).scaling).imagescale)[1] OF
      0:  minmax_data = (*(*(*info).data).refdata)[$
            (*(*info).scaling).tsel_scaling_ref * (*(*info).dataparams).refns * $
            (*(*info).dataparams).refnlp + $
            (*(*info).dataparams).s_ref * (*(*info).dataparams).refnlp + $
            (*(*info).dataparams).lp_ref]
      1:  minmax_data = *(*(*info).data).refslice
    ENDCASE
    IF (*(*info).dispswitch).refimscaled THEN $
      minmax_data = CRISPEX_SCALING_DESCALE(minmax_data, $
        (*(*info).dispparams).refimbscale, (*(*info).dispparams).refimbzero)
    IF ((*(*info).dispswitch).scalestokes[1] AND $
        ((*(*info).dataparams).s_ref NE 0)) THEN BEGIN
      cont_slice = FLOAT((*(*(*info).data).refdata)[$
        (*(*info).dispparams).t_ref * (*(*info).dataparams).refnlp * $
        (*(*info).dataparams).refns + (*(*info).stokesparams).contpos[1]])
      IF (*(*info).dispswitch).refimscaled THEN $
        cont_slice = CRISPEX_SCALING_DESCALE(cont_slice, $
          (*(*info).dispparams).refimbscale, (*(*info).dispparams).refimbzero)
      minmax_data /= cont_slice
    ENDIF
    minmax = CRISPEX_SCALING_SLICES(minmax_data, (*(*info).scaling).gamma[idx], $
      (*(*info).scaling).histo_opt_val[idx], /FORCE_HISTO)
    IF ((*(*(*info).scaling).imagescale)[1] EQ 0) THEN BEGIN
      (*(*info).scaling).refmin = minmax[0]
      (*(*info).scaling).refmax = minmax[1]
    ENDIF ELSE BEGIN
      (*(*info).scaling).refmin_curr = minmax[0]
      (*(*info).scaling).refmax_curr = minmax[1]
    ENDELSE
  ENDIF

  ; Doppler image
  IF update_dop THEN BEGIN
    idx = (*(*info).intparams).ndiagnostics + $
      (*(*info).intparams).nrefdiagnostics + (*(*info).intparams).lp_diag_all
    CASE (*(*(*info).scaling).imagescale)[2] OF
      0:  BEGIN
  		      xyslice =  (*(*(*info).data).imagedata)[$
              (*(*info).scaling).tsel_scaling_main * (*(*info).dataparams).ns * $
              (*(*info).dataparams).nlp + $
              (*(*info).dataparams).s * (*(*info).dataparams).nlp + $
              (*(*info).dataparams).lp]
  		      temp_xyslice = (*(*(*info).data).imagedata)[$
              (*(*info).scaling).tsel_scaling_main * (*(*info).dataparams).ns * $
              (*(*info).dataparams).nlp + $
              (*(*info).dataparams).s * (*(*info).dataparams).nlp + $
              (*(*info).dataparams).lp_dop]
  		      IF ((*(*info).dataparams).lp_dop GT (*(*info).dataparams).lc) THEN $
              minmax_data = temp_xyslice - xyslice $
            ELSE $
              minmax_data = xyslice - temp_xyslice 
          END
      1:  minmax_data = *(*(*info).data).dopslice
    ENDCASE
    IF ((*(*info).dispswitch).scalestokes[0] AND $
        ((*(*info).dataparams).s NE 0)) THEN $
      minmax_data /= FLOAT((*(*(*info).data).imagedata)[$
        (*(*info).dispparams).t_main * (*(*info).dataparams).nlp * $
        (*(*info).dataparams).ns + (*(*info).stokesparams).contpos[0]])
    minmax = CRISPEX_SCALING_SLICES(minmax_data, (*(*info).scaling).gamma[idx], $
        (*(*info).scaling).histo_opt_val[idx], /FORCE_HISTO)
    IF ((*(*(*info).scaling).imagescale)[2] EQ 0) THEN BEGIN
      (*(*info).scaling).dopmin = minmax[0]
      (*(*info).scaling).dopmax = minmax[1]
    ENDIF ELSE BEGIN
      (*(*info).scaling).dopmin_curr = minmax[0]
      (*(*info).scaling).dopmax_curr = minmax[1]
    ENDELSE
  ENDIF

  ; SJI image
  IF update_sji THEN BEGIN
    base_idx = 2*(*(*info).intparams).ndiagnostics + (*(*info).intparams).nrefdiagnostics
    FOR i=0,(*(*info).winswitch).nwhereshowsji-1 DO BEGIN
      idx_sji = (*(*(*info).winswitch).whereshowsji)[i]
      idx = base_idx + idx_sji
      IF ((*(*(*info).scaling).imagescale)[3+idx_sji] EQ 0) THEN BEGIN
        minmax_data = (*(*(*info).data).sjidata[idx_sji])[$
          (*(*info).scaling).tsel_scaling_sji[idx_sji]]
      ; If SJI data is scaled integer, descale and convert to float
      IF (*(*info).dispswitch).sjiscaled[idx_sji] THEN $
        minmax_data = CRISPEX_SCALING_DESCALE(minmax_data, $
          (*(*info).dispparams).sjibscale[idx_sji], $
          (*(*info).dispparams).sjibzero[idx_sji])
        minmax = CRISPEX_SCALING_SLICES(minmax_data, (*(*info).scaling).gamma[idx], $
          (*(*info).scaling).histo_opt_val[idx], /FORCE_HISTO)
        (*(*info).scaling).sjimin[idx_sji] = minmax[0]
        (*(*info).scaling).sjimax[idx_sji] = minmax[1]
      ENDIF ELSE IF ((*(*(*info).scaling).imagescale)[3+idx_sji] EQ 1) THEN BEGIN
        minmax_data = *(*(*info).data).sjislice[idx_sji]
        minmax = CRISPEX_SCALING_SLICES(minmax_data, (*(*info).scaling).gamma[idx], $
          (*(*info).scaling).histo_opt_val[idx], /FORCE_HISTO)
        (*(*info).scaling).sjimin_curr[idx_sji] = minmax[0]
        (*(*info).scaling).sjimax_curr[idx_sji] = minmax[1]
      ENDIF
    ENDFOR
  ENDIF
END

PRO CRISPEX_SCALING_HISTO_OPT_VALUE, event
; Handles the setting of the HISTO_OPT parameter
	WIDGET_CONTROL, event.TOP, GET_UVALUE = info
	IF (TOTAL(((*(*info).feedbparams).verbosity)[2:3]) GE 1) THEN $
    CRISPEX_VERBOSE_GET_ROUTINE, event
	WIDGET_CONTROL, (*(*info).ctrlscp).histo_opt_txt, GET_VALUE = textvalue
  textvalue = FLOAT(textvalue[0])
	(*(*info).scaling).histo_opt_val[(*(*info).scaling).idx] = FLOAT(textvalue[0])
  CRISPEX_SCALING_APPLY_SELECTED, event
  CRISPEX_SCALING_REDRAW, event
END

PRO CRISPEX_SCALING_SLIDER_MIN, event
; Handles events from the minimum scaling value slider
	WIDGET_CONTROL, event.TOP, GET_UVALUE = info
	IF (TOTAL(((*(*info).feedbparams).verbosity)[2:3]) GE 1) THEN $
    CRISPEX_VERBOSE_GET_ROUTINE, event
  idx = (*(*info).scaling).idx
  (*(*info).scaling).minimum[idx] = event.VALUE
  IF ((*(*info).scaling).minimum[idx] GE (*(*info).scaling).maximum[idx]) THEN BEGIN
    (*(*info).scaling).maximum[idx] = (*(*info).scaling).minimum[idx] + 1
    CRISPEX_SCALING_SET_SLIDERS, event
  ENDIF
  CRISPEX_SCALING_APPLY_SELECTED, event
  CRISPEX_SCALING_REDRAW, event
  ; CRISPEX_DRAW, event
END

PRO CRISPEX_SCALING_SLIDER_MAX, event
; Handles events from the minimum scaling value slider
	WIDGET_CONTROL, event.TOP, GET_UVALUE = info
	IF (TOTAL(((*(*info).feedbparams).verbosity)[2:3]) GE 1) THEN $
    CRISPEX_VERBOSE_GET_ROUTINE, event
  idx = (*(*info).scaling).idx
  (*(*info).scaling).maximum[idx] = event.VALUE
  IF ((*(*info).scaling).maximum[idx] LE (*(*info).scaling).minimum[idx]) THEN BEGIN
    (*(*info).scaling).minimum[idx] = (*(*info).scaling).maximum[idx] - 1
    CRISPEX_SCALING_SET_SLIDERS, event
  ENDIF
  CRISPEX_SCALING_APPLY_SELECTED, event
  CRISPEX_SCALING_REDRAW, event
  ; CRISPEX_DRAW, event
END

PRO CRISPEX_SCALING_GAMMA_SLIDER, event
; Handles events from the minimum scaling value slider
	WIDGET_CONTROL, event.TOP, GET_UVALUE = info
	IF (TOTAL(((*(*info).feedbparams).verbosity)[2:3]) GE 1) THEN $
    CRISPEX_VERBOSE_GET_ROUTINE, event
  (*(*info).scaling).gamma[(*(*info).scaling).idx] = 10.^((FLOAT(event.VALUE)/500.) - 1.)
  WIDGET_CONTROL, (*(*info).ctrlscp).gamma_label, $
    SET_VALUE=STRING((*(*info).scaling).gamma[(*(*info).scaling).idx],FORMAT='(F6.3)')
  CRISPEX_SCALING_APPLY_SELECTED, event
  CRISPEX_SCALING_REDRAW, event
END

PRO CRISPEX_SCALING_RESET_DEFAULTS, event, IDX=idx, NO_DRAW=no_draw
; Handles events from the minimum scaling value slider
	WIDGET_CONTROL, event.TOP, GET_UVALUE = info
	IF (TOTAL(((*(*info).feedbparams).verbosity)[2:3]) GE 1) THEN $
    CRISPEX_VERBOSE_GET_ROUTINE, event
  IF (N_ELEMENTS(IDX) NE 1) THEN idx = (*(*info).scaling).idx
  ; Reset contrast value
  (*(*info).scaling).minimum[idx] = 0
  (*(*info).scaling).maximum[idx] = 100
  (*(*info).scaling).gamma[idx] = (*(*info).prefs).default_gamma_val
  (*(*info).scaling).histo_opt_val[idx] = (*(*info).prefs).default_histo_opt_val
  IF ~KEYWORD_SET(NO_DRAW) THEN BEGIN
    CRISPEX_SCALING_APPLY_SELECTED, event
    CRISPEX_SCALING_SET_BOXBUTTONS, event
    CRISPEX_SCALING_SET_SLIDERS, event
    CRISPEX_SCALING_REDRAW, event
  ENDIF
END 

PRO CRISPEX_SCALING_RESET_ALL_DEFAULTS, event
; Handles events from the minimum scaling value slider
	WIDGET_CONTROL, event.TOP, GET_UVALUE = info
	IF (TOTAL(((*(*info).feedbparams).verbosity)[2:3]) GE 1) THEN $
    CRISPEX_VERBOSE_GET_ROUTINE, event
  FOR i=0,N_ELEMENTS((*(*info).scaling).gamma)-1 DO $
    CRISPEX_SCALING_RESET_DEFAULTS, event, IDX=i, $
    NO_DRAW=(i NE (N_ELEMENTS((*(*info).scaling).gamma)-1))
END 

PRO CRISPEX_SCALING_REDRAW, event
; Handles the redrawing of window contents after adjustment of scaling
	WIDGET_CONTROL, event.TOP, GET_UVALUE = info
	IF (TOTAL(((*(*info).feedbparams).verbosity)[2:3]) GE 1) THEN $
    CRISPEX_VERBOSE_GET_ROUTINE, event
  CASE (*(*info).scaling).imrefscaling OF
    0:  BEGIN
          CRISPEX_DRAW_CTBAR, event, /MAIN
      		CRISPEX_DRAW_XY, event 
      		IF (*(*info).winswitch).showsp THEN BEGIN
            CRISPEX_UPDATE_SPSLICE, event
            CRISPEX_DRAW_SPECTRAL_MAIN, event, /SP_ONLY
          ENDIF
      		IF (*(*info).winswitch).showphis THEN BEGIN
            CRISPEX_UPDATE_PHISLICE, event, /NO_DRAW
            CRISPEX_DRAW_PHIS, event 
          ENDIF
	        IF (*(*info).winswitch).showloop THEN CRISPEX_DRAW_LOOPSLAB, event 
        END
    1:  BEGIN
      		IF (*(*info).winswitch).showref THEN BEGIN
            CRISPEX_DRAW_CTBAR, event, /REFERENCE
            CRISPEX_DRAW_REF, event
          ENDIF
      		IF (*(*info).winswitch).showrefsp THEN BEGIN
            CRISPEX_UPDATE_REFSPSLICE, event
            CRISPEX_DRAW_SPECTRAL_REF, event, /SP_ONLY
          ENDIF
	        IF (*(*info).winswitch).showrefloop THEN CRISPEX_DRAW_REFLOOPSLAB, event 
        END
    2:  BEGIN
      		IF ((*(*info).winswitch).showdop AND $
              (*(*info).dispswitch).drawdop) THEN BEGIN
            CRISPEX_DRAW_CTBAR, event, /DOPPLER
            CRISPEX_DRAW_DOPPLER, event
          ENDIF
        END
    ELSE: BEGIN
            idx_sji = (*(*info).scaling).imrefscaling-3
          IF (*(*info).winswitch).showsji[idx_sji] THEN BEGIN
            CRISPEX_DRAW_CTBAR, event, /SJI, IDX_SJI=idx_sji
            CRISPEX_DRAW_SJI, event, IDX_SJI=idx_sji
          ENDIF
	        IF (*(*info).winswitch).showsjiloop THEN CRISPEX_DRAW_SJILOOPSLAB, event 
        END
  ENDCASE
	IF (*(*info).winswitch).showrestloop THEN $
    CRISPEX_DRAW_REST_LOOP, event
END

PRO CRISPEX_SCALING_SET_BOXBUTTONS, event, SENSITIVITY_OVERRIDE=sensitivity_override
; Handles the setting of scaling buttons
	WIDGET_CONTROL, event.TOP, GET_UVALUE = info
	IF (TOTAL(((*(*info).feedbparams).verbosity)[2:3]) GE 1) THEN $
    CRISPEX_VERBOSE_GET_ROUTINE, event
  showarr = [1,(*(*info).winswitch).showref,(*(*info).winswitch).showdop,$
    (*(*info).winswitch).showsji]
  CASE (*(*info).scaling).imrefscaling OF
    0:  ndiagnostics = (*(*info).intparams).ndiagnostics
    1:  ndiagnostics = (*(*info).intparams).nrefdiagnostics
    ELSE:  ndiagnostics = 1
  ENDCASE
  WIDGET_CONTROL, (*(*info).ctrlscp).imagescale_cbox, $
    SET_COMBOBOX_SELECT=(*(*(*info).scaling).imagescale)[(*(*info).scaling).imrefscaling], $
    SENSITIVE=showarr[(*(*info).scaling).imrefscaling]
  WIDGET_CONTROL, (*(*info).ctrlscp).scaling_reset_button, $
      SENSITIVE=showarr[(*(*info).scaling).imrefscaling]
  WIDGET_CONTROL, (*(*info).ctrlscp).diagscale_label, $
    SET_VALUE=(*(*info).scaling).diagscale_label_vals[(*(*info).scaling).idx]
  ; HISTO_OPT controls
  WIDGET_CONTROL, (*(*info).ctrlscp).histo_opt_txt, $
    SET_VALUE=STRTRIM((*(*info).scaling).histo_opt_val[(*(*info).scaling).idx],2), $
    SENSITIVE=showarr[(*(*info).scaling).imrefscaling]
  ; Multiply controls
  update_constraint = (((*(*info).scaling).idx GE 0) AND $
    ((*(*info).scaling).idx LT N_ELEMENTS((*(*info).scaling).mult_val)))
	WIDGET_CONTROL, (*(*info).ctrlscp).ls_mult_cbox, $
    SET_COMBOBOX_SELECT=(*(*info).scaling).idx, $
    SENSITIVE=(showarr[(*(*info).scaling).imrefscaling] AND $
      update_constraint AND (ndiagnostics GT 1))
  IF update_constraint THEN $
  	WIDGET_CONTROL, (*(*info).ctrlscp).ls_mult_txt, $
      SET_VALUE=STRTRIM((*(*info).scaling).mult_val[(*(*info).scaling).idx],2), $
      SENSITIVE=(showarr[(*(*info).scaling).imrefscaling] AND (ndiagnostics GT 1)) $
  ELSE $
  	WIDGET_CONTROL, (*(*info).ctrlscp).ls_mult_txt, $
      SENSITIVE=(showarr[(*(*info).scaling).imrefscaling] AND $
        update_constraint AND (ndiagnostics GT 1))
END

PRO CRISPEX_SCALING_SET_SLIDERS, event, GAMMA_ONLY=gamma_only, SET_GAMMA=set_gamma, $
  SENSITIVITY_OVERRIDE=sensitivity_override
; Handles the setting of scaling sliders
	WIDGET_CONTROL, event.TOP, GET_UVALUE = info
	IF (TOTAL(((*(*info).feedbparams).verbosity)[2:3]) GE 1) THEN $
    CRISPEX_VERBOSE_GET_ROUTINE, event
  showarr = [1,(*(*info).winswitch).showref,(*(*info).winswitch).showdop,$
    (*(*info).winswitch).showsji]
  IF ~KEYWORD_SET(GAMMA_ONLY) THEN BEGIN
    WIDGET_CONTROL, (*(*info).ctrlscp).scalemin_slider,$
      SET_VALUE=(*(*info).scaling).minimum[(*(*info).scaling).idx], $
      SENSITIVE=showarr[(*(*info).scaling).imrefscaling]
    WIDGET_CONTROL, (*(*info).ctrlscp).scalemax_slider,$
      SET_VALUE=(*(*info).scaling).maximum[(*(*info).scaling).idx], $
      SENSITIVE=showarr[(*(*info).scaling).imrefscaling]
  ENDIF
  IF (N_ELEMENTS(SET_GAMMA) EQ 1) THEN BEGIN
    gamma_slider_val = set_gamma
    gamma_val = 10.^((FLOAT(gamma_slider_val)/500.) - 1.)
    (*(*info).scaling).gamma[(*(*info).scaling).idx] = gamma_val
  ENDIF ELSE BEGIN
    gamma_val = (*(*info).scaling).gamma[(*(*info).scaling).idx]
    gamma_slider_val = 500 * (ALOG10(gamma_val) + 1)
  ENDELSE
  WIDGET_CONTROL, (*(*info).ctrlscp).gamma_slider, SET_VALUE=gamma_slider_val, $
    SENSITIVE=showarr[(*(*info).scaling).imrefscaling]
  WIDGET_CONTROL, (*(*info).ctrlscp).gamma_label, SET_VALUE=STRING(gamma_val,FORMAT='(F6.3)')
END

PRO CRISPEX_SCALING_MULTIPLY_LS_SELECT, event
; Handles the selection of diagnostic for multiplying detailed spectrum
	WIDGET_CONTROL, event.TOP, GET_UVALUE = info
	IF (TOTAL(((*(*info).feedbparams).verbosity)[2:3]) GE 1) THEN $
    CRISPEX_VERBOSE_GET_ROUTINE, event
  (*(*info).scaling).idx = event.INDEX
  WIDGET_CONTROL, (*(*info).ctrlscp).ls_mult_txt, $
    SET_VALUE=STRTRIM((*(*info).scaling).mult_val[(*(*info).scaling).idx],2)
END  

PRO CRISPEX_SCALING_MULTIPLY_LS_VALUE, event
; Handles the selection of diagnostic for multiplying detailed spectrum
	WIDGET_CONTROL, event.TOP, GET_UVALUE = info
	IF (TOTAL(((*(*info).feedbparams).verbosity)[2:3]) GE 1) THEN $
    CRISPEX_VERBOSE_GET_ROUTINE, event
	WIDGET_CONTROL, (*(*info).ctrlscp).ls_mult_txt, GET_VALUE = textvalue
  textvalue = FLOAT(textvalue[0])
  IF (textvalue EQ 0) THEN BEGIN
    textvalue = 1.
	  WIDGET_CONTROL, (*(*info).ctrlscp).ls_mult_txt, SET_VALUE=STRTRIM(textvalue,2)
  ENDIF
	(*(*info).scaling).mult_val[(*(*info).scaling).idx] = FLOAT(textvalue[0])
  CRISPEX_DRAW_SPECTRAL, event
  CRISPEX_DRAW_TIMESLICES, event
END

PRO CRISPEX_SCALING_STOKES_CONTPOS, event, NO_DRAW=no_draw, SET_VALUE=set_value
  WIDGET_CONTROL, event.TOP, GET_UVALUE=info
	IF (TOTAL(((*(*info).feedbparams).verbosity)[2:3]) GE 1) THEN $
    CRISPEX_VERBOSE_GET_ROUTINE, event
  IF ~KEYWORD_SET(SET_VALUE) THEN BEGIN
  	WIDGET_CONTROL, (*(*info).ctrlscp).stokes_contpos_text, GET_VALUE=textvalue
    CASE (*(*info).stokesparams).mainref_select OF
      0:  nlp = (*(*info).dataparams).nlp
      1:  nlp = (*(*info).dataparams).refnlp
    ENDCASE
    (*(*info).stokesparams).contpos[(*(*info).stokesparams).mainref_select] = $
      textvalue[0] > 0 < (nlp-1)    ; Failsafe against out of bounds position
  ENDIF
	WIDGET_CONTROL, (*(*info).ctrlscp).stokes_contpos_text, $
    SET_VALUE=STRTRIM((*(*info).stokesparams).contpos[$
                        (*(*info).stokesparams).mainref_select],2)
  IF ~KEYWORD_SET(NO_DRAW) THEN CRISPEX_SCALING_STOKES_REDRAW, event, $
    MAINREF_SELECT=(*(*info).stokesparams).mainref_select
END

PRO CRISPEX_SCALING_STOKES_CONTPOS_CURRENT, event, NO_DRAW=no_draw
  WIDGET_CONTROL, event.TOP, GET_UVALUE=info
	IF (TOTAL(((*(*info).feedbparams).verbosity)[2:3]) GE 1) THEN $
    CRISPEX_VERBOSE_GET_ROUTINE, event
  CASE (*(*info).stokesparams).mainref_select OF
    0:  (*(*info).stokesparams).contpos[0] = (*(*info).dataparams).lp
    1:  (*(*info).stokesparams).contpos[1] = (*(*info).dataparams).lp_ref
  ENDCASE
	WIDGET_CONTROL, (*(*info).ctrlscp).stokes_contpos_text, $
    SET_VALUE=STRTRIM((*(*info).stokesparams).contpos[$
                        (*(*info).stokesparams).mainref_select],2)
  IF ~KEYWORD_SET(NO_DRAW) THEN CRISPEX_SCALING_STOKES_REDRAW, event, $
    MAINREF_SELECT=(*(*info).stokesparams).mainref_select
END

PRO CRISPEX_SCALING_STOKES_REDRAW, event, MAINREF_SELECT=mainref_select
  WIDGET_CONTROL, event.TOP, GET_UVALUE=info
	IF (TOTAL(((*(*info).feedbparams).verbosity)[2:3]) GE 1) THEN $
    CRISPEX_VERBOSE_GET_ROUTINE, event
  ; Update image slices
  CRISPEX_UPDATE_T, event
  CRISPEX_SCALING_APPLY_SELECTED, event, $
    UPDATE_MAIN=(mainref_select EQ 0), $
    UPDATE_REF=(mainref_select EQ 1)
  ; Update spectral slices
  CASE mainref_select OF
    0:  BEGIN
          IF (*(*info).winswitch).showsp THEN BEGIN
            CRISPEX_DISPLAYS_SP_REPLOT_AXES, event
            CRISPEX_UPDATE_SPSLICE, event
          ENDIF
          IF (*(*info).winswitch).showls THEN CRISPEX_UPDATE_SSP, event
        END
    1:  BEGIN
          IF (*(*info).winswitch).showrefsp THEN BEGIN
            CRISPEX_DISPLAYS_REFSP_REPLOT_AXES, event
            CRISPEX_UPDATE_REFSPSLICE, event
          ENDIF
          IF (*(*info).winswitch).showrefls THEN CRISPEX_UPDATE_REFSSP, event
        END
  ENDCASE
  ; Redraw displays
  CRISPEX_DRAW, event, NO_MAIN=(mainref_select EQ 1), $
    NO_PHIS=(mainref_select EQ 1), LS_NO_MAIN=(mainref_select EQ 1), $
    NO_REF=(mainref_select EQ 0), LS_NO_REF=(mainref_select EQ 0), /NO_SJI, $
    UPDATE_MAINDATAVALS=(mainref_select EQ 0), $
    UPDATE_REFDATAVALS=(mainref_select EQ 1)
END

;========================= SESSION SAVE/RESTORE PROCEDURES
PRO CRISPEX_SESSION_SAVE_WINDOW, event
; Gets the filename for the session save routine
	WIDGET_CONTROL, event.TOP, GET_UVALUE = info
	IF (TOTAL(((*(*info).feedbparams).verbosity)[2:3]) GE 1) THEN $
    CRISPEX_VERBOSE_GET_ROUTINE, event
	CRISPEX_SAVE_CHECK_PATH_WRITE, event
	CRISPEX_SAVE_GET_FILENAME, event, 'Save session', 'crispex_session',$
    'CRISPEX_SESSION_SAVE_CONTINUE', /SESSION_SAVE
END

PRO CRISPEX_SESSION_SAVE_CONTINUE, event
; Checks the session save filename for validity and overwrite problems
	WIDGET_CONTROL, event.TOP, GET_UVALUE = info
	IF (TOTAL(((*(*info).feedbparams).verbosity)[2:3]) GE 1) THEN $
    CRISPEX_VERBOSE_GET_ROUTINE, event
	(*(*info).savparams).savpro = 'SESSION'
	CRISPEX_SAVE_CHECK_FILENAME, event, 'cses', 'CRISPEX_SESSION_SAVE_OVER_CONTINUE'
END

PRO CRISPEX_SESSION_SAVE_OVER_CONTINUE, event
; Handles the overwriting and activates the subsequent saving of the session
	WIDGET_CONTROL, event.TOP, GET_UVALUE = info
	IF (TOTAL(((*(*info).feedbparams).verbosity)[2:3]) GE 1) THEN $
    CRISPEX_VERBOSE_GET_ROUTINE, event
	WIDGET_CONTROL, (*(*info).savparams).filename_text, GET_VALUE = session_filename
	CRISPEX_SESSION_SAVE, event, session_filename
	WIDGET_CONTROL, event.TOP, /DESTROY
END

PRO CRISPEX_SESSION_SAVE, event, sesfilename, LAST_SESSION=last_session
; Handles the actual saving of the session
	WIDGET_CONTROL, event.TOP, GET_UVALUE = info
	WIDGET_CONTROL, /HOURGLASS
	IF (TOTAL(((*(*info).feedbparams).verbosity)[2:3]) GE 1) THEN $
    CRISPEX_VERBOSE_GET_ROUTINE, event
  ; Get current window positions
  CRISPEX_WINDOWS_GET_OFFSETS, event
  ; Save all pointers
	ctrlsswitch = *(*info).ctrlsswitch	    &	curs = *(*info).curs
	dataparams = *(*info).dataparams	      &	dataswitch = *(*info).dataswitch		
  detparams = *(*info).detparams          & dispparams = *(*info).dispparams	
  dispswitch = *(*info).dispswitch		    &	intparams = *(*info).intparams
  ioparams = *(*info).ioparams            &	loopparams = *(*info).loopparams	
  loopswitch = *(*info).loopswitch		    &	meas = *(*info).meas
	overlayparams = *(*info).overlayparams	&	overlayswitch = *(*info).overlayswitch		
  paramswitch = *(*info).paramswitch      & pbparams = *(*info).pbparams
  phiparams = *(*info).phiparams          & plotaxes = *(*info).plotaxes
  plotparams = *(*info).plotparams        & plotpos = *(*info).plotpos		
  plotswitch = *(*info).plotswitch		    & plottitles = *(*info).plottitles
	restoreparams = *(*info).restoreparams	&	retrparams = *(*info).retrparams		
  savswitch = *(*info).savswitch          & scaling = *(*info).scaling		
  stokesparams = *(*info).stokesparams		& versioninfo = *(*info).versioninfo
	winsizes = *(*info).winsizes		        &	winswitch = *(*info).winswitch			
  zooming = *(*info).zooming
  IF KEYWORD_SET(LAST_SESSION) THEN $
    outdir = (*(*info).paths).dir_settings $
  ELSE $
    outdir = (*(*info).paths).opath
  SAVE, ctrlsswitch, curs, dataparams, dataswitch, detparams, dispparams, $
        dispswitch, intparams, ioparams, loopparams, loopswitch, meas, $
        overlayparams, overlayswitch, paramswitch, pbparams, phiparams,$
        plotaxes, plotparams, plotpos, plotswitch, plottitles, restoreparams, $
        retrparams, savswitch, scaling, stokesparams, versioninfo, winsizes, $
        winswitch, zooming, FILENAME=outdir+sesfilename+'.cses'
  IF ~KEYWORD_SET(LAST_SESSION) THEN BEGIN
  	PRINT,'Written: '+outdir+sesfilename+'.cses'
  	WIDGET_CONTROL, (*(*info).winids).savewintlb, /DESTROY
  	(*(*info).winids).savewintlb = 0
  ENDIF
END

PRO CRISPEX_SESSION_RESTORE_READ_POINTER, event, currpointer, restpointer, $
  NO_RESTORE=no_restore, HALT=halt
; Handles the actual restoration of the session
	WIDGET_CONTROL, event.TOP, GET_UVALUE = info
	IF (TOTAL(((*(*info).feedbparams).verbosity)[2:3]) GE 1) THEN $
    CRISPEX_VERBOSE_GET_ROUTINE, event
	currtags = TAG_NAMES(currpointer)	&	resttags = TAG_NAMES(restpointer)
	ncurr = N_ELEMENTS(currtags)		  &	nrest = N_ELEMENTS(resttags)
	no_rest = N_ELEMENTS(NO_RESTORE)
  IF KEYWORD_SET(HALT) THEN STOP
	IF (((*(*info).feedbparams).verbosity)[3] EQ 1) THEN $
    CRISPEX_VERBOSE_GET, event, [ncurr,nrest,no_rest-1],$
      labels=['Current tags','Restored tags','Prevent replace tag']
  ; Both the restored and current pointer have the same number of tags
	IF (ncurr EQ nrest) THEN BEGIN											
		IF (no_rest EQ 0) THEN BEGIN	; Pointer to be restored without skipping tags
      ; If all tagnames are equal, then just replace the pointer
			IF (WHERE((resttags EQ currtags) EQ 0) EQ -1) THEN $
        currpointer = restpointer $
      ELSE BEGIN		
        ; Else go through all tags and replace only where tagnames are the same
				FOR i=0,nrest-1 DO $
          (currpointer).(WHERE(currtags EQ resttags[i])) = restpointer.(i)	
			ENDELSE
		ENDIF ELSE BEGIN		; Pointer to be restored while skipping tags
			no_replace = WHERE((STRLOWCASE(resttags) EQ STRLOWCASE(no_restore)) EQ 1)
			FOR i=0,nrest-1 DO BEGIN
        ; If pointer tag is not the one to be skipped, replace its value
				IF (no_replace NE i) THEN (currpointer).(i) = restpointer.(i)				
			ENDFOR
		ENDELSE
	ENDIF ELSE BEGIN			; Unequal number of tags between current and restored pointer
		FOR i=0,nrest-1 DO BEGIN
      ; Go through all tags and replace only where tagnames are the same
			IF (WHERE(currtags EQ resttags[i]) NE -1) THEN $
        (currpointer).(WHERE(currtags EQ resttags[i])) = restpointer.(i)			
		ENDFOR
	ENDELSE
END

PRO CRISPEX_SESSION_RESTORE, event, CSESFILE=csesfile
; Handles the actual restoration of the session
	WIDGET_CONTROL, event.TOP, GET_UVALUE = info
	IF (TOTAL(((*(*info).feedbparams).verbosity)[2:3]) GE 1) THEN $
    CRISPEX_VERBOSE_GET_ROUTINE, event
  IF (N_ELEMENTS(csesfile) NE 1) THEN $
    csesfile = $
      DIALOG_PICKFILE(/READ,/MUST_EXIST,PATH=(*(*info).paths).ipath,$
      TITLE='CRISPEX'+(*(*info).sesparams).instance_label+': Restore session', $
      FILTER='*cses')
  IF (STRCOMPRESS(csesfile) NE '') THEN BEGIN
  	WIDGET_CONTROL, /HOURGLASS
  	CRISPEX_UPDATE_USER_FEEDBACK, event, title='Restoring session...', var=0, $
      feedback_text='Restoring session file and checking version...', /SESSION
  	RESTORE, csesfile
  	; Check revision number
  	IF (N_ELEMENTS(versioninfo) GT 0) THEN $
      cont = (versioninfo.revision_number GE '820') $
    ELSE $
      cont = 0
  	IF cont THEN BEGIN
      allsjifiles_loaded = 1
      nallsjifiles = MAX([dataparams.nsjifiles,(*(*info).dataparams).nsjifiles])
      IF (nallsjifiles GT 0) THEN BEGIN
        i = 0
        WHILE ((allsjifiles_loaded EQ 1) AND (i LE nallsjifiles-1)) DO BEGIN
          allsjifiles_loaded = ((*(*info).dataparams).sjifilename[i] EQ $
                                dataparams.sjifilename[i])
          i += 1
        ENDWHILE
      ENDIF 
  		IF (((*(*info).dataparams).imfilename EQ dataparams.imfilename) AND $
          ((*(*info).dataparams).spfilename EQ dataparams.spfilename) AND $
  			((*(*info).dataparams).refimfilename EQ dataparams.refimfilename) AND $
        ((*(*info).dataparams).refspfilename EQ dataparams.refspfilename) AND $
        allsjifiles_loaded) THEN BEGIN
        ; Restore the winswitch to decide what windows to close
  			CRISPEX_SESSION_RESTORE_READ_POINTER, event, *(*info).winswitch, winswitch
  			CRISPEX_UPDATE_USER_FEEDBACK, event, title='Restoring session...', $
          var=1, feedback_text='Closing deselected windows...'
  			IF (((*(*info).winids).sptlb NE 0) AND $
            ((*(*info).winswitch).showsp EQ 0)) THEN BEGIN 
  				WIDGET_CONTROL, (*(*info).winids).sptlb, /DESTROY 
  				(*(*info).winids).sptlb = 0 
  			ENDIF
  			IF (((*(*info).winids).lstlb NE 0) AND $
            ((*(*info).winswitch).showls EQ 0)) THEN BEGIN 
  				WIDGET_CONTROL, (*(*info).winids).lstlb, /DESTROY
  				(*(*info).winids).lstlb = 0 
  			ENDIF
  			IF (((*(*info).winids).phistlb NE 0) AND $
            ((*(*info).winswitch).showphis EQ 0)) THEN BEGIN 
  				WIDGET_CONTROL, (*(*info).winids).phistlb, /DESTROY 
  				(*(*info).winids).phistlb = 0 
  			ENDIF
  			IF (((*(*info).winids).reftlb NE 0) AND $
            ((*(*info).winswitch).showref EQ 0)) THEN BEGIN 
  				WIDGET_CONTROL, (*(*info).winids).reftlb, /DESTROY 
  				(*(*info).winids).reftlb = 0 
  			ENDIF
  			IF (((*(*info).winids).doptlb NE 0) AND $
            ((*(*info).winswitch).showdop EQ 0)) THEN BEGIN 
  				WIDGET_CONTROL, (*(*info).winids).doptlb, /DESTROY 
  				(*(*info).winids).doptlb = 0 
  			ENDIF
  			IF (((*(*info).winids).imreftlb NE 0) AND $
            ((*(*info).winswitch).showimref EQ 0)) THEN BEGIN 
  				WIDGET_CONTROL, (*(*info).winids).imreftlb, /DESTROY 
  				(*(*info).winids).imreftlb = 0 
  			ENDIF
	      IF (TOTAL((*(*info).winids).sjitlb) NE 0) THEN BEGIN
          FOR i=0,(*(*info).dataparams).nsjifiles-1 DO BEGIN
            IF ((*(*info).winswitch).showsji[i] EQ 0) THEN BEGIN
              WIDGET_CONTROL, (*(*info).winids).sjitlb[i], /DESTROY
              (*(*info).winids).sjitlb[i] = 0
            ENDIF
          ENDFOR
        ENDIF
  			IF (TOTAL(*(*(*info).winids).restlooptlb) NE 0) THEN BEGIN 
  				FOR i=0,N_ELEMENTS(*(*(*info).winids).restlooptlb)-1 DO $
            WIDGET_CONTROL, (*(*(*info).winids).restlooptlb)[i], /DESTROY
  				(*(*info).winids).restlooptlb = PTR_NEW(0) 
  			ENDIF
  			IF (((*(*info).winids).retrdettlb NE 0) AND $
            ((*(*info).winswitch).showretrdet EQ 0)) THEN BEGIN 
  				WIDGET_CONTROL, (*(*info).winids).retrdettlb, /DESTROY 
  				(*(*info).winids).retrdettlb = 0 
  			ENDIF
  			IF (((*(*info).winids).looptlb NE 0) AND $
            ((*(*info).winswitch).showloop EQ 0)) THEN BEGIN 
  				WIDGET_CONTROL, (*(*info).winids).looptlb, /DESTROY 
  				(*(*info).winids).looptlb = 0 
  			ENDIF
  			IF (((*(*info).winids).reflooptlb NE 0) AND $
            ((*(*info).winswitch).showrefloop EQ 0)) THEN BEGIN 
  				WIDGET_CONTROL, (*(*info).winids).reflooptlb, /DESTROY 
  				(*(*info).winids).reflooptlb = 0 
  			ENDIF
  			IF (((*(*info).winids).refsptlb NE 0) AND $
            ((*(*info).winswitch).showrefsp EQ 0)) THEN BEGIN 
  				WIDGET_CONTROL, (*(*info).winids).refsptlb, /DESTROY 
  				(*(*info).winids).refsptlb = 0 
  			ENDIF
  			IF (((*(*info).winids).reflstlb NE 0) AND $
            ((*(*info).winswitch).showrefls EQ 0)) THEN BEGIN 
  				WIDGET_CONTROL, (*(*info).winids).reflstlb, /DESTROY 
  				(*(*info).winids).reflstlb = 0 
  			ENDIF
  			IF (((*(*info).winids).inttlb NE 0) AND $
            ((*(*info).winswitch).showint EQ 0)) THEN BEGIN 
  				WIDGET_CONTROL, (*(*info).winids).inttlb, /DESTROY 
  				(*(*info).winids).inttlb = 0 
  			ENDIF
  			IF (((*(*info).winids).paramtlb NE 0) AND $
            ((*(*info).winswitch).showparam EQ 0)) THEN BEGIN 
  				WIDGET_CONTROL, (*(*info).winids).paramtlb, /DESTROY 
  				(*(*info).winids).paramtlb = 0 
  			ENDIF
        ; Restore all parameters, for each parameter checking whether the number
        ; of subparameters has changed (if revision_number on session file differs
        ; from current CRISPEX)
        CRISPEX_UPDATE_USER_FEEDBACK, event, title='Restoring session...', $
          var=1, feedback_text='Restoring session variables...'
  			CRISPEX_SESSION_RESTORE_READ_POINTER, event, *(*info).ctrlsswitch, ctrlsswitch
  			CRISPEX_SESSION_RESTORE_READ_POINTER, event, *(*info).curs, curs
  			CRISPEX_SESSION_RESTORE_READ_POINTER, event, *(*info).dataparams, dataparams
  			CRISPEX_SESSION_RESTORE_READ_POINTER, event, *(*info).dataswitch, dataswitch
  			CRISPEX_SESSION_RESTORE_READ_POINTER, event, *(*info).detparams, detparams
  			CRISPEX_SESSION_RESTORE_READ_POINTER, event, *(*info).dispparams, dispparams
  			CRISPEX_SESSION_RESTORE_READ_POINTER, event, *(*info).dispswitch, dispswitch
  			CRISPEX_SESSION_RESTORE_READ_POINTER, event, *(*info).intparams, intparams
  			CRISPEX_SESSION_RESTORE_READ_POINTER, event, *(*info).ioparams, ioparams
  			CRISPEX_SESSION_RESTORE_READ_POINTER, event, *(*info).loopparams, loopparams
  			CRISPEX_SESSION_RESTORE_READ_POINTER, event, *(*info).loopswitch, loopswitch
  			CRISPEX_SESSION_RESTORE_READ_POINTER, event, *(*info).meas, meas
  			CRISPEX_SESSION_RESTORE_READ_POINTER, event, *(*info).overlayparams, overlayparams
  			CRISPEX_SESSION_RESTORE_READ_POINTER, event, *(*info).overlayswitch, overlayswitch
  			CRISPEX_SESSION_RESTORE_READ_POINTER, event, *(*info).paramswitch, paramswitch
  			CRISPEX_SESSION_RESTORE_READ_POINTER, event, *(*info).pbparams, pbparams, NO_RESTORE='BG'
  			CRISPEX_SESSION_RESTORE_READ_POINTER, event, *(*info).phiparams, phiparams
  			CRISPEX_SESSION_RESTORE_READ_POINTER, event, *(*info).plotaxes, plotaxes
  			CRISPEX_SESSION_RESTORE_READ_POINTER, event, *(*info).plotparams, plotparams
  			CRISPEX_SESSION_RESTORE_READ_POINTER, event, *(*info).plotpos, plotpos
  			CRISPEX_SESSION_RESTORE_READ_POINTER, event, *(*info).plotswitch, plotswitch
  			CRISPEX_SESSION_RESTORE_READ_POINTER, event, *(*info).plottitles, plottitles
  			CRISPEX_SESSION_RESTORE_READ_POINTER, event, *(*info).restoreparams, $
          restoreparams
  			CRISPEX_SESSION_RESTORE_READ_POINTER, event, *(*info).retrparams, retrparams
  			CRISPEX_SESSION_RESTORE_READ_POINTER, event, *(*info).scaling, scaling
  			CRISPEX_SESSION_RESTORE_READ_POINTER, event, *(*info).savswitch, savswitch
  			CRISPEX_SESSION_RESTORE_READ_POINTER, event, *(*info).stokesparams, stokesparams
  			CRISPEX_SESSION_RESTORE_READ_POINTER, event, *(*info).zooming, zooming
  			; Reset controls on control panel given the control switches and other parameters
  			CRISPEX_UPDATE_USER_FEEDBACK, event, title='Restoring session...', var=1, $
          feedback_text='Resetting control panel controls...'
        ; ==================== Always visible controls ====================
        ; Zooming controls
        CRISPEX_ZOOM_BUTTONS_SET, event, /FIT_SCALE, /ZOOM_INOUT, /PAN_SELECT, $
          /ZGOTO
        ; Playback controls
  			WIDGET_CONTROL, (*(*info).ctrlscp).t_slider, SET_VALUE = (*(*info).dispparams).t, $
          SET_SLIDER_MIN=(*(*info).dispparams).t_low, $
          SET_SLIDER_MAX=(*(*info).dispparams).t_upp, $
  				SENSITIVE = ((*(*info).dataparams).nt GT 1)
  			CRISPEX_PB_BUTTONS_SET, event, $
          bwd_set=(((*(*info).pbparams).direction EQ -1) AND $
                   ((*(*info).pbparams).mode EQ 'PLAY')), $
          pause_set=((*(*info).pbparams).mode EQ 'PAUSE'), $
          fwd_set=(((*(*info).pbparams).direction EQ 1) AND $
                   ((*(*info).pbparams).mode EQ 'PLAY')), $
  				loop_set=((*(*info).pbparams).lmode EQ 'LOOP'),	$
          cycle_set=((*(*info).pbparams).lmode EQ 'CYCLE'), $
          blink_set=((*(*info).pbparams).lmode EQ 'BLINK')
        ; Spectral control
  			WIDGET_CONTROL, (*(*info).ctrlscp).lp_slider, SET_VALUE = (*(*info).dataparams).lp, $
          SET_SLIDER_MIN=(*(*info).dispparams).lp_low, $
          SET_SLIDER_MAX=(*(*info).dispparams).lp_upp, $
  				SENSITIVE=((*(*info).dataparams).nlp GT 1)
        ; Cursor lock controls
        CRISPEX_CURSOR_LOCKBUTTON_SET, event, /NO_DRAW
        ; ==================== Playback Tab ====================
  			WIDGET_CONTROL, (*(*info).ctrlscp).lower_t_text, $
          SET_VALUE=STRTRIM((*(*info).dispparams).t_low,2), $
          SENSITIVE=((*(*info).dataparams).nt GT 1)
  			WIDGET_CONTROL, (*(*info).ctrlscp).upper_t_text, $
          SET_VALUE=STRTRIM((*(*info).dispparams).t_upp,2), $
          SENSITIVE=((*(*info).dataparams).nt GT 1)
  			WIDGET_CONTROL, (*(*info).ctrlscp).reset_trange_but, $
          SENSITIVE=((*(*info).dispparams).t_range NE (*(*info).dataparams).nt)
  			WIDGET_CONTROL, (*(*info).ctrlscp).t_speed_slider, $
          SET_VALUE=(*(*info).pbparams).t_speed, SENSITIVE = ((*(*info).dataparams).nt GT 1)
  			WIDGET_CONTROL, (*(*info).ctrlscp).t_step_slider, $
          SET_SLIDER_MAX=(*(*info).dispparams).t_range - 1, $
          SET_VALUE=(*(*info).pbparams).t_step, $
  				SENSITIVE=(((*(*info).dispparams).t_range - 1 NE 1) AND $
                        (*(*info).dataparams).nt GT 1)
  			WIDGET_CONTROL, (*(*info).ctrlscp).imref_blink_but, $
          SET_BUTTON=(*(*info).winswitch).showimref, $
          SENSITIVE=(*(*info).dataswitch).reffile
        ; Master timing
        showdata = [((*(*info).dataswitch).reffile OR (*(*info).dataswitch).sjifile), $
          (*(*info).dataswitch).reffile, (*(*info).dataswitch).sjifile]
        is_raster = [(*(*info).dataparams).tfull_dims_main[0], $
          (*(*info).dataparams).tfull_dims_ref[0], 1] GE 1
        FOR i=0,N_ELEMENTS((*(*info).ctrlscp).master_time_ids)-1 DO $
          WIDGET_CONTROL, (*(*info).ctrlscp).master_time_ids[i], $
          SET_BUTTON=(i EQ (*(*info).dispparams).master_time), $
          SENSITIVE=(showdata[i] AND is_raster[i])
        WIDGET_CONTROL, (*(*info).ctrlscp).master_time_sjicbox, $
          SENSITIVE=((*(*info).dispparams).master_time EQ 2)
        WIDGET_CONTROL, (*(*info).ctrlscp).time_offset_slider, $
          SENSITIVE=(((is_raster[(*(*info).dispparams).master_time] EQ 0) AND $
            ((*(*info).dataparams).nt EQ 1) AND ((*(*info).dataparams).nx GT 1)) OR $
            is_raster[(*(*info).dispparams).master_time]), $
          SET_VALUE=([(*(*info).dispparams).toffset_main, $
            (*(*info).dispparams).toffset_ref, 0])[(*(*info).dispparams).master_time]
        ; ==================== Spectral Tab ====================
        ; Spectral range
        reset_lp_restrict = CRISPEX_BGROUP_LP_RESTRICT(event, /SESSION_RESTORE)
        ; By default show only globloc for Main
        WIDGET_CONTROL, (*(*info).ctrlscp).lp_globloc_button_ids[$
          (*(*info).dispswitch).lp_restrict_globloc[0]], /SET_BUTTON
        ; Spectral blink
      	WIDGET_CONTROL, (*(*info).ctrlscp).lp_blink_slider, $
          SET_SLIDER_MIN=(*(*info).dispparams).lp_low, $
          SET_SLIDER_MAX=(*(*info).dispparams).lp_upp, $
          SET_VALUE=(*(*info).pbparams).lp_blink, $
          SENSITIVE=(((*(*info).dispparams).lp_range-1) NE 1)
  			WIDGET_CONTROL, (*(*info).ctrlscp).lp_blink_but, $
          SET_BUTTON=(*(*info).pbparams).spmode, $
          SENSITIVE=(((*(*info).dataparams).nlp GT 1) AND $
                     ((*(*info).winswitch).showimref EQ 0))
        ; Reference spectrum
  			WIDGET_CONTROL, (*(*info).ctrlscp).lp_ref_but, $
          SET_BUTTON=((*(*info).ctrlsswitch).lp_ref_lock AND $
                     ((*(*info).dataparams).refnlp GT 1)), $
  				SENSITIVE=(((*(*info).dataparams).nlp EQ (*(*info).dataparams).refnlp) AND $
                     ((*(*info).dataparams).refnlp GT 1))
  			WIDGET_CONTROL, (*(*info).ctrlscp).lp_ref_slider, $
          SET_VALUE=(*(*info).dataparams).lp_ref, $
          SENSITIVE=((*(*info).dataswitch).refspfile AND $
                      ABS((*(*info).ctrlsswitch).lp_ref_lock-1))
        ; Spectrum along slit
  			WIDGET_CONTROL, (*(*info).ctrlscp).phi_slider, $
          SET_VALUE=(*(*info).phiparams).angle, $
          SENSITIVE=((*(*info).winswitch).showphis AND $
          (*(*info).dataparams).nx GT 1)
  			WIDGET_CONTROL, (*(*info).ctrlscp).nphi_slider, $
          SET_VALUE=(*(*info).phiparams).nphi_set, $
          SENSITIVE=(*(*info).winswitch).showphis
  			; ==================== Spatial Tab ====================
        ; Set cursor sliders and lock/unlock buttons
  			CRISPEX_COORDSLIDERS_SET, 1, 1, event
        ; Set zooming buttons
  			IF ((*(*info).zooming).factorswitch[0] NE 1) THEN $
          CRISPEX_ZOOM, event, /NO_DRAW, /NO_UPDATE_SLIDERS, $
            SET_FACTOR_IDX=WHERE((*(*info).zooming).factorswitch EQ 1)
        ; Set scrolling sliders
  			WIDGET_CONTROL, (*(*info).ctrlscp).xpos_slider, SET_VALUE=(*(*info).zooming).xpos, $
          SENSITIVE=((*(*info).zooming).factorswitch[0] NE 1)
  			WIDGET_CONTROL, (*(*info).ctrlscp).ypos_slider, SET_VALUE=(*(*info).zooming).ypos, $
          SENSITIVE=((*(*info).zooming).factorswitch[0] NE 1)
  			; ==================== Diagnostics Tab ====================
        imbuttons = CRISPEX_BGROUP_STOKES_SELECT_XY(event, /NO_DRAW, /SET_BUTTONS)
        spbuttons = CRISPEX_BGROUP_STOKES_SELECT_SP(event, /NO_DRAW, /SET_BUTTONS)
  			IF ((*(*info).dataparams).nlp EQ 1) THEN $
          WIDGET_CONTROL, (*(*info).ctrlscp).stokes_spbutton_ids[0], SET_BUTTON = 0
        ; Spectral window settings
        IF ((*(*info).intparams).ndiagnostics GT 1) THEN BEGIN
          set = [((*(*info).intparams).ndisp_diagnostics EQ $
                  (*(*info).intparams).ndiagnostics),$
                  ((*(*info).intparams).disp_diagnostics EQ $
                    REPLICATE(1,(*(*info).intparams).ndiagnostics))]
          sens = [((*(*info).intparams).ndisp_diagnostics NE $
                  (*(*info).intparams).ndiagnostics),$
                  (((*(*info).intparams).disp_diagnostics NE $
                    REPLICATE(1,(*(*info).intparams).ndiagnostics)) OR $
                  (((*(*info).intparams).disp_diagnostics EQ $
                    REPLICATE(1,(*(*info).intparams).ndiagnostics)) AND $
                   ((*(*info).intparams).ndisp_diagnostics NE 1)))]
          FOR i=0,(*(*info).intparams).ndiagnostics DO $
            WIDGET_CONTROL, (*(*info).ctrlscp).specwin_button_ids[i], $
              SENSITIVE=sens[i], SET_BUTTON=set[i]
        ENDIF
        IF ((*(*info).intparams).nrefdiagnostics GT 1) THEN BEGIN
          hide_display_array = STRARR((*(*info).intparams).nrefdiagnostics)
          FOR i=0,(*(*info).intparams).nrefdiagnostics-1 DO $
            hide_display_array[i] = (['Display ','Hide '])[$
              ((*(*info).intparams).disp_refdiagnostics[i] EQ 1)]
          all_displayed = (TOTAL((*(*info).intparams).disp_refdiagnostics) EQ $
            (*(*info).intparams).nrefdiagnostics)
          WIDGET_CONTROL, (*(*info).ctrlscp).ref_specwin_cbox, $
            SET_VALUE=['Display all', hide_display_array+$
            (*(*info).intparams).refdiagnostics], $
            SET_COMBOBOX_SELECT=([0,1])[all_displayed]
        ENDIF
  			; ==================== Displays Tab ====================
        reset_detspect_imref = $
          CRISPEX_BGROUP_DETSPECT_IMREF(event, /SESSION_RESTORE)
  			CRISPEX_DISPLAYS_DETSPECT_SET_BUTTONS, event
        reset_displays_select = $
          CRISPEX_BGROUP_DISPLAYS_SELECT(event, /SESSION_RESTORE)
        reset_refdisplays_select = $
          CRISPEX_BGROUP_REFDISPLAYS_SELECT(event, /SESSION_RESTORE)
        FOR i=0,(*(*info).dataparams).nsjifiles-1 DO $
          WIDGET_CONTROL, (*(*info).ctrlscp).sjidisplays_button_ids[i], $
            SET_BUTTON=(*(*info).winswitch).showsji[i], $
            SENSITIVE=(*(*info).dataswitch).sjifile
  			WIDGET_CONTROL, (*(*info).ctrlscp).int_toggle_but, $
          SET_BUTTON=(*(*info).winswitch).showint, $
          SENSITIVE=(*(*info).dataswitch).spfile
        WIDGET_CONTROL, (*(*info).ctrlscp).displays_ct_disp, $
          SET_COMBOBOX_SELECT=(*(*info).plotparams).imct_select
        WIDGET_CONTROL, (*(*info).ctrlscp).displays_ct_cbox, $
          SET_COMBOBOX_SELECT=(*(*info).plotparams).imct[$
          ((*(*info).plotparams).imct_select-1)>0]+1
  			; ==================== Scaling Tab ====================
        WIDGET_CONTROL, (*(*info).ctrlscp).scaling_cbox, $
          SET_COMBOBOX_SELECT=(*(*info).scaling).imrefscaling
  			CRISPEX_SCALING_SET_BOXBUTTONS, event
  			CRISPEX_SCALING_SET_SLIDERS, event
  			; ==================== Analysis Tab ====================
  			; Space-time diagram
  			WIDGET_CONTROL, (*(*info).ctrlscp).loop_slit_but, $
          SET_BUTTON = ((*(*info).loopparams).np GE 2), $
          SENSITIVE = ABS((*(*info).meas).spatial_measurement-1)
  			WIDGET_CONTROL, (*(*info).ctrlscp).loop_feedb_but, $
          SET_BUTTON = (*(*info).overlayswitch).looppath_feedback
  			WIDGET_CONTROL, (*(*info).ctrlscp).rem_loop_pt_but, $
          SENSITIVE = ((*(*info).loopparams).np GE 3)
  			WIDGET_CONTROL, (*(*info).ctrlscp).loop_slice_but, $
          SENSITIVE = (ABS((*(*info).winswitch).showloop-1) AND $
          ABS((*(*info).meas).spatial_measurement-1) AND ((*(*info).loopparams).np GE 2))
        ; Measurement
  			WIDGET_CONTROL, (*(*info).ctrlscp).measure_but, $
          SET_BUTTON = (*(*info).meas).spatial_measurement
  			WIDGET_CONTROL, (*(*info).ctrlscp).apix_label, $
          SENSITIVE = (*(*info).meas).spatial_measurement
  	    WIDGET_CONTROL, (*(*info).ctrlscp).apix_unit, $
          SENSITIVE = (*(*info).meas).spatial_measurement
  			WIDGET_CONTROL, (*(*info).ctrlscp).dx_text, $
          SET_VALUE = STRTRIM((*(*info).dataparams).dx,2), $
          SENSITIVE = (*(*info).meas).spatial_measurement
  			WIDGET_CONTROL, (*(*info).ctrlscp).x_label, $
          SENSITIVE = (*(*info).meas).spatial_measurement
  			WIDGET_CONTROL, (*(*info).ctrlscp).dy_text, $
          SET_VALUE = STRTRIM((*(*info).dataparams).dy,2), $
          SENSITIVE = (*(*info).meas).spatial_measurement
  			WIDGET_CONTROL, (*(*info).ctrlscp).measure_asec_lab, $
          SENSITIVE = (*(*info).meas).spatial_measurement
  			WIDGET_CONTROL, (*(*info).ctrlscp).measure_asec_text, $
          SENSITIVE = (*(*info).meas).spatial_measurement
  			WIDGET_CONTROL, (*(*info).ctrlscp).measure_km_lab, $
          SENSITIVE = (*(*info).meas).spatial_measurement
  			WIDGET_CONTROL, (*(*info).ctrlscp).measure_km_text, $
          SENSITIVE = (*(*info).meas).spatial_measurement
  			; ==================== Overlays Tab ====================
  			; Mask
  			WIDGET_CONTROL, (*(*info).ctrlscp).masks_overlay_ct_cbox, $
          SET_COMBOBOX_SELECT = (*(*info).overlayparams).maskct, $
          /SENSITIVE 
  			WIDGET_CONTROL, (*(*info).ctrlscp).masks_overlay_col_slid, $
          SET_VALUE = (*(*info).overlayparams).maskcolor, $
          /SENSITIVE 
  			CRISPEX_MASK_BUTTONS_SET, event
        ; Loop overlays
  			WIDGET_CONTROL, (*(*info).ctrlscp).overlay_but, $
          SET_BUTTON = (*(*info).loopswitch).restore_loops
        reset_loop_overlay = CRISPEX_BGROUP_LOOP_OVERLAY(event, /SESSION_RESTORE)
        reset_loop_linestyle = CRISPEX_BGROUP_LOOP_LINESTYLE(event, $
          /SESSION_RESTORE) 
        ; Raster overlays
        WIDGET_CONTROL, (*(*info).ctrlscp).raster_button_ids[0], $
          SENSITIVE=((*(*info).dataswitch).reffile AND $
          (is_raster[0] OR ((*(*info).dataparams).nx EQ 1))), $
          SET_BUTTON=((*(*info).overlayswitch).refraster AND $
          (is_raster[0] OR ((*(*info).dataparams).nx EQ 1)))
        WIDGET_CONTROL, (*(*info).ctrlscp).raster_button_ids[1], $
          SENSITIVE=((*(*info).dataswitch).sjifile AND $
          (is_raster[0] OR ((*(*info).dataparams).nx EQ 1))), $
          SET_BUTTON=((*(*info).overlayswitch).sjiraster AND $
          (is_raster[0] OR ((*(*info).dataparams).nx EQ 1)))
  			IF (*(*info).meas).spatial_measurement THEN CRISPEX_MEASURE_CALC, event
  			; Open windows for replotting and replot
  			CRISPEX_UPDATE_USER_FEEDBACK, event, TITLE='Restoring session...', $
          VAR=1, FEEDBACK_TEXT='Refreshing displays...'
  			old_cfilecount = (*(*info).restoreparams).cfilecount
  			CRISPEX_FIND_CSAV, event, $
          FORCE_PATH=FILE_DIRNAME((*(*(*info).restoreparams).cfiles)[0])+PATH_SEP()
  			IF ((*(*info).loopswitch).restore_loops AND $
           ((*(*info).restoreparams).cfilecount EQ old_cfilecount)) THEN BEGIN
  				CRISPEX_RESTORE_LOOPS_MENU, event, *(*(*info).restoreparams).sel_loops
  				WIDGET_CONTROL, (*(*info).winids).restsesfeedbtlb, /SHOW
  				WIDGET_CONTROL, (*(*info).ctrlsrestore).sel_all, $
            SET_BUTTON=(TOTAL(*(*(*info).restoreparams).sel_loops) EQ $
                        N_ELEMENTS(*(*(*info).restoreparams).sel_loops))
  				WIDGET_CONTROL, (*(*info).ctrlsrestore).sel_none, $
            SET_BUTTON=(TOTAL(*(*(*info).restoreparams).sel_loops) EQ 0)
  				WIDGET_CONTROL, (*(*info).ctrlsrestore).disp_list, GET_VALUE=list_values
  				IF (*(*info).winswitch).showrestloop THEN BEGIN
  					FOR i=0,N_ELEMENTS(*(*(*info).restoreparams).disp_loopnr)-1 DO BEGIN
  						list_values[(*(*(*info).restoreparams).disp_loopnr)[i]+1] = $
                'Hide time slice '+STRTRIM((*(*(*info).restoreparams).disp_loopnr)[i],2)
  						(*(*info).restoreparams).disp_loopfile = $
                (*(*(*info).restoreparams).cfiles)[(*(*(*info).restoreparams).disp_loopnr)[i]]
  						CRISPEX_DISPLAYS_RESTORE_LOOPSLAB, event, /NO_DRAW, INDEX=i
  					ENDFOR
  				ENDIF ELSE FOR i=1,N_ELEMENTS(list_values)-1 DO list_values[i] = 'Display time slice '+STRTRIM(i-1,2)
  				WIDGET_CONTROL, (*(*info).ctrlsrestore).disp_list, $
            SET_VALUE=list_values, $
            SET_COMBOBOX_SELECT=(*(*(*info).restoreparams).disp_loopnr)[0]+1
  			ENDIF ELSE BEGIN			; Add error message
  				(*(*info).loopswitch).restore_loops = 0	
  				(*(*info).winswitch).showrestloop = 0
  			ENDELSE
  			old_clfilecount = (*(*info).retrparams).clfilecount
  			CRISPEX_FIND_CLSAV, event, $
          FORCE_PATH=FILE_DIRNAME((*(*(*info).retrparams).clfiles)[0])+PATH_SEP()
  			IF ((*(*info).loopswitch).retrieve_loops AND ((*(*info).retrparams).clfilecount EQ old_clfilecount)) THEN BEGIN
  				CRISPEX_RETRIEVE_LOOP_MENU, event, *(*(*info).retrparams).sel_loops
  				WIDGET_CONTROL, (*(*info).winids).restsesfeedbtlb, /SHOW
  				WIDGET_CONTROL, (*(*info).ctrlsloop).sel_all, $
            SET_BUTTON=(TOTAL(*(*(*info).retrparams).sel_loops) EQ $
                        N_ELEMENTS(*(*(*info).retrparams).sel_loops))
  				WIDGET_CONTROL, (*(*info).ctrlsloop).sel_none, $
            SET_BUTTON=(TOTAL(*(*(*info).retrparams).sel_loops) EQ 0)
  				WIDGET_CONTROL, (*(*info).ctrlsloop).all_pos, $
            SET_BUTTON=(*(*info).savswitch).all_pos_loops
  				WIDGET_CONTROL, (*(*info).ctrlsloop).saved_pos, $
            SET_BUTTON=ABS((*(*info).savswitch).all_pos_loops-1)
  				WIDGET_CONTROL, (*(*info).ctrlsloop).del_files, $
            SET_BUTTON=(*(*info).savswitch).delete_clsav
  				WIDGET_CONTROL, (*(*info).ctrlsloop).keep_files, $
            SET_BUTTON=ABS((*(*info).savswitch).delete_clsav-1)
          sensbutton = [1, $
            (*(*info).winswitch).showref AND ((*(*info).dataparams).refnt GT 1), $
            (*(*info).winswitch).showsji AND ((*(*info).dataparams).sjint GT 1)]
          FOR i=0,N_ELEMENTS(save_imrefsji_labels)-1 DO $
            WIDGET_CONTROL, save_imrefsji_ids[i], $
              SET_BUTTON=(*(*info).savswitch).imrefsji[i], SENSITIVE=sensbutton[i]
  			ENDIF ELSE (*(*info).loopswitch).retrieve_loops = 0	; Add error message
  			detfile = FILE_SEARCH((*(*info).detparams).detfilename, COUNT=detcount)
  			IF ((*(*info).loopswitch).retrieve_detfile AND (detcount EQ 1)) THEN BEGIN
  				CRISPEX_RETRIEVE_DET_FILE_MENU, event, *(*(*info).detparams).sel_dets, DETFILENAME=(*(*info).detparams).detfilename, /NO_DRAW
  				WIDGET_CONTROL, (*(*info).winids).restsesfeedbtlb, /SHOW
  				WIDGET_CONTROL, (*(*info).ctrlsdet).sel_all, $
            SET_BUTTON=(TOTAL(*(*(*info).detparams).sel_dets) EQ $
                        N_ELEMENTS(*(*(*info).detparams).sel_dets))
  				WIDGET_CONTROL, (*(*info).ctrlsdet).sel_none, $
            SET_BUTTON=(TOTAL(*(*(*info).detparams).sel_dets) EQ 0)
  				WIDGET_CONTROL, (*(*info).ctrlsdet).disp_list, $
            SET_COMBOBOX_SELECT=(*(*info).detparams).idx+1
  				WIDGET_CONTROL, (*(*info).ctrlsdet).overlay_all, $
            SET_BUTTON=(*(*info).overlayswitch).det_overlay_all
  				WIDGET_CONTROL, (*(*info).ctrlsdet).overlay_sel, $
            SET_BUTTON=ABS((*(*info).overlayswitch).det_overlay_all-1)
  				WIDGET_CONTROL, (*(*info).ctrlsdet).width_slider, $
            SET_VALUE=(*(*info).detparams).width
  				WIDGET_CONTROL, (*(*info).ctrlsdet).all_pos, $
            SET_BUTTON=((*(*info).savswitch).pos_dets EQ 1)
  				WIDGET_CONTROL, (*(*info).ctrlsdet).saved_pos, $
            SET_BUTTON=((*(*info).savswitch).pos_dets EQ 2)
  				WIDGET_CONTROL, (*(*info).ctrlsdet).sel_range_pos, $
            SET_BUTTON=((*(*info).savswitch).pos_dets EQ 3)
  				WIDGET_CONTROL, (*(*info).ctrlsdet).dlpmin_text, $
            SENSITIVE=((*(*info).savswitch).pos_dets EQ 3)
  				WIDGET_CONTROL, (*(*info).ctrlsdet).dlpmax_text, $
            SENSITIVE=((*(*info).savswitch).pos_dets EQ 3)
  				WIDGET_CONTROL, (*(*info).ctrlsdet).refdlpmin_text, $
            SENSITIVE=((*(*info).savswitch).pos_dets EQ 3)
  				WIDGET_CONTROL, (*(*info).ctrlsdet).refdlpmax_text, $
            SENSITIVE=((*(*info).savswitch).pos_dets EQ 3)
  				WIDGET_CONTROL, (*(*info).ctrlsdet).save_imonly, $
            SET_BUTTON=((*(*info).savswitch).det_imref_only EQ 1)
  				WIDGET_CONTROL, (*(*info).ctrlsdet).save_refonly, $
            SET_BUTTON=((*(*info).savswitch).det_imref_only EQ 2)
  				WIDGET_CONTROL, (*(*info).ctrlsdet).save_imref, $
            SET_BUTTON=((*(*info).savswitch).det_imref_only EQ 3)
  				WIDGET_CONTROL, (*(*info).ctrlsdet).get_dets, $
            SENSITIVE=(TOTAL(*(*(*info).detparams).sel_dets) GE 1)
  				IF (*(*info).winswitch).showretrdet THEN $
            CRISPEX_DISPLAYS_RETRIEVE_DET_LOOPSLAB, event, /NO_DRAW
  				CRISPEX_DISPRANGE_LP_RANGE, event
  				CRISPEX_UPDATE_LP, event
  				WIDGET_CONTROL, (*(*info).winids).restsesfeedbtlb, /SHOW
  			ENDIF ELSE (*(*info).loopswitch).retrieve_detfile = 0	; Add error message
  			IF (*(*info).winswitch).showloop THEN BEGIN
  				CRISPEX_DISPLAYS_LOOPSLAB, event, /NO_DRAW
  				IF (*(*info).winswitch).showrefloop THEN $
            CRISPEX_DISPLAYS_REFLOOPSLAB, event, /NO_DRAW
  				IF (*(*info).winswitch).showsjiloop THEN $
            CRISPEX_DISPLAYS_SJILOOPSLAB, event, /NO_DRAW
  				CRISPEX_UPDATE_LP, event
  				WIDGET_CONTROL, (*(*info).winids).restsesfeedbtlb, /SHOW
  			ENDIF
        ; Update T and redraw displays
				CRISPEX_UPDATE_T, event
        IF (*(*info).winswitch).showls THEN CRISPEX_UPDATE_SSP, event
        IF (*(*info).winswitch).showsp THEN CRISPEX_UPDATE_SPSLICE, event
        IF (*(*info).winswitch).showrefls THEN CRISPEX_UPDATE_REFSSP, event
        IF (*(*info).winswitch).showrefsp THEN CRISPEX_UPDATE_REFSPSLICE, event
				CRISPEX_DRAW, event, /UPDATE_MAINDATAVALS, $
          UPDATE_REFDATAVALS=(*(*info).dataswitch).reffile
				WIDGET_CONTROL, (*(*info).winids).restsesfeedbtlb, /SHOW
        ; Redraw color bars
        CRISPEX_DRAW_CTBAR, event, /MAIN, $
          REFERENCE=(*(*info).winswitch).showref, $
          DOPPLER=(*(*info).dispswitch).drawdop, $
          SJI=(*(*info).winswitch).showsji
  			; Menu
  			IF (*(*info).winswitch).dispwids THEN BEGIN
  				(*(*info).winswitch).dispwids = 0
  				CRISPEX_DISPWIDS, event
  			ENDIF
  			CRISPEX_WINDOW_USER_FEEDBACK_CLOSE, event, /SESSION
  			(*(*(*info).sesparams).sessions)[WHERE(*(*(*info).sesparams).sessions EQ 1)] = 0
  		ENDIF ELSE BEGIN
  			CRISPEX_WINDOW_USER_FEEDBACK_CLOSE, event, /SESSION
  			CRISPEX_WINDOW_OK, event,'ERROR!',$
          'Unable to restore earlier session due to incompatibility '+$
          'between currently and earlier loaded data.',$
  				OK_EVENT='CRISPEX_CLOSE_EVENT_WINDOW', BASE=tlb
  			(*(*info).winids).errtlb = tlb
  		ENDELSE
  	ENDIF ELSE BEGIN
  		CRISPEX_WINDOW_USER_FEEDBACK_CLOSE, event, /SESSION
  		IF (N_ELEMENTS(versioninfo) GT 0) THEN $
        message4 = 'Session was saved with CRISPEX v'+$
          versioninfo.version_number+' (rev '+versioninfo.revision_number+').' $
      ELSE $
        message4 = ''
  		CRISPEX_WINDOW_OK, event,'ERROR!',$
        'Unable to restore earlier session due to incompatibility between '+$
        'saved and expected session save file format. Running version of '+$
  			'CRISPEX requires a session saved with CRISPEX v1.7.4 (rev 820) or later. '+$
        message4, OK_EVENT='CRISPEX_CLOSE_EVENT_WINDOW', BASE=tlb
  		(*(*info).winids).errtlb = tlb
  	ENDELSE
  ENDIF ELSE BEGIN
  	CRISPEX_WINDOW_OK, event,'ERROR!','No session selected for restore.', $
  		OK_EVENT='CRISPEX_CLOSE_EVENT_WINDOW', BASE=tlb
  	(*(*info).winids).errtlb = tlb
  ENDELSE
END

;========================= SAVE LOOPSLICE/SLAB PROCEDURES
PRO CRISPEX_SAVE_DETERMINE_FILENAME, event, infilename=infilename, $
  outfilename=outfilename, tlab=tlab, ext=ext, exch_ext=exch_ext, $
  export_id=export_id, import_id=import_id
; Handles the creation of an output filename
	WIDGET_CONTROL, event.TOP, GET_UVALUE = info
	IF (TOTAL(((*(*info).feedbparams).verbosity)[2:3]) GE 1) THEN $
    CRISPEX_VERBOSE_GET_ROUTINE, event
	IF (N_ELEMENTS(INFILENAME) NE 1) THEN infilename = (*(*info).dataparams).imfilename
	infilename = (STRSPLIT(infilename,PATH_SEP(),/EXTRACT))[N_ELEMENTS(STRSPLIT(infilename,PATH_SEP(),/EXTRACT))-1]
	basefstr = STRMID(infilename,0,STRPOS(infilename,'.',/REVERSE_SEARCH))
	IF KEYWORD_SET(EXCH_EXT) THEN outfilename = basefstr ELSE BEGIN
		IF KEYWORD_SET(TLAB) THEN BEGIN
			CRISPEX_SAVE_DETERMINE_SAVEID, event, saveid
			outfilename = basefstr+'_'+saveid
			IF (N_ELEMENTS(EXPORT_ID) EQ 1) THEN export_id = saveid ELSE export_id=''
		ENDIF ELSE IF (N_ELEMENTS(IMPORT_ID) EQ 1) THEN outfilename = basefstr+'_'+import_id ELSE $
			outfilename = basefstr
	ENDELSE
	IF (N_ELEMENTS(EXT) EQ 1) THEN outfilename = outfilename+'.'+ext
	IF (((*(*info).feedbparams).verbosity)[3] EQ 1) THEN $
    CRISPEX_VERBOSE_GET, event, [infilename,outfilename],labels=['base filename', 'output filename']
END

PRO CRISPEX_SAVE_DETERMINE_SAVEID, event, saveid, PREF=pref
	WIDGET_CONTROL, event.TOP, GET_UVALUE = info
	IF (TOTAL(((*(*info).feedbparams).verbosity)[2:3]) GE 1) THEN $
    CRISPEX_VERBOSE_GET_ROUTINE, event
	monthstrarr = ['Jan','Feb','Mar','Apr','May','Jun','Jul','Aug','Sep','Oct','Nov','Dec']
	curt = SYSTIME()
	tstr = STRSPLIT(curt,/EXTRACT)
	sstr = STRSPLIT(tstr[3],':',/EXTRACT)
	tstr[2] = STRING(tstr[2],FORMAT='(I02)')								; date
	IF KEYWORD_SET(PREF) THEN $
    defsaveid = (*(*info).prefs).tmp_defsaveid $
  ELSE $
    defsaveid = (*(*info).prefs).defsaveid
	IF (defsaveid GE 2) THEN tstr[1] = STRING(WHERE(monthstrarr EQ tstr[1])+1,FORMAT='(I02)')		; month (numeric)
  CASE defsaveid OF
    0:  date_order = [4,1,2] ; defsaveid = 0 > YYYYMMMDD_hhmmss, ex: 2011Apr12_114545
    1:  date_order = [2,1,4] ; defsaveid = 1 > DDMMMYYYY_hhmmss, ex: 12Apr2011_114545
		2:  date_order = [4,1,2] ; defsaveid = 2 > YYYYMMDD_hhmmss, ex: 20110412_114545
		3:  date_order = [2,1,4]; defsaveid = 3 > DDMMYYYY_hhmmss, ex: 12042011_114545
  ENDCASE
	saveid = STRJOIN(tstr[date_order])+'_'+STRJOIN(sstr)
	IF (((*(*info).feedbparams).verbosity)[3] EQ 1) THEN $
    CRISPEX_VERBOSE_GET, event, [saveid],labels=['save ID']
END

PRO CRISPEX_SAVE_LOOP_PTS, event
; Handles the saving of loop points of a defined path
	WIDGET_CONTROL, event.TOP, GET_UVALUE = info
	IF (TOTAL(((*(*info).feedbparams).verbosity)[2:3]) GE 1) THEN $
    CRISPEX_VERBOSE_GET_ROUTINE, event
	CRISPEX_SAVE_CHECK_PATH_WRITE, event
	IF ((*(*info).paths).opath_write EQ 1) THEN BEGIN
		WIDGET_CONTROl,/HOURGLASS
		PRINT,'Saving current loop points..'
		x_coords        = *(*(*info).loopparams).xp		
    y_coords        = *(*(*info).loopparams).yp
		x_loop_pts      = *(*(*info).loopparams).xr		
    y_loop_pts      = *(*(*info).loopparams).yr
		w_loop_pts      = *(*(*info).loopparams).w_lpts	
    spect_pos       = (*(*info).dataparams).lp
		t_saved         = (*(*info).dispparams).t
    ngaps           = (*(*info).loopparams).ngaps
    databounds      = *(*(*info).loopparams).databounds
    wdatabounds     = *(*(*info).loopparams).wdatabounds
		crispex_version = [(*(*info).versioninfo).version_number, $
      (*(*info).versioninfo).revision_number]
		CRISPEX_SAVE_DETERMINE_FILENAME, event, outfilename=filename, /tlab, ext='clsav'
		SAVE, crispex_version, x_coords, y_coords, x_loop_pts, y_loop_pts, $
      w_loop_pts, spect_pos, t_saved, ngaps, databounds, wdatabounds, $
      FILENAME = (*(*info).paths).opath+filename
		PRINT,'Saving current loop points done. Saved data to: '+STRTRIM(filename,2)
		WIDGET_CONTROL, (*(*info).ctrlscp).sel_saved_loop, SENSITIVE = 1
		WIDGET_CONTROL, (*(*info).ctrlscp).all_saved_loop, SENSITIVE = 1
	ENDIF
END

PRO CRISPEX_SAVE_APPROX_LOOPSLICE, event
; Handles the saving of an approximate (i.e. nearest neighbour interpolated) timeslice along a loop
	WIDGET_CONTROL, event.TOP, GET_UVALUE = info
	CRISPEX_SAVE_APPROX_LOOPSLAB, event, /SAVE_SLICE
END

PRO CRISPEX_SAVE_APPROX_LOOPSLAB, event, SAVE_SLICE=save_slice
; Handles the saving of an approximate (i.e. nearest neighbour interpolated)
;  timeslab along a loop 
  WIDGET_CONTROL, event.TOP, GET_UVALUE = info
	IF (TOTAL(((*(*info).feedbparams).verbosity)[2:3]) GE 1) THEN $
    CRISPEX_VERBOSE_GET_ROUTINE, event
  ; Determine filenames
  CRISPEX_SAVE_DETERMINE_FILENAME, event, outfilename=filename, /tlab, $
    ext='csav', export_id=expid 
  CRISPEX_SAVE_DETERMINE_FILENAME, event, infilename=filename, $
    outfilename=filename2, ext='clsav', /exch_ext
  ; Set save messages
	save_message1 = REPLICATE('Saving current approximate loop ',2)+$
    ['slab...','slice...']
	save_message2 = REPLICATE('Saving current approximate loop ',2)+$
    ['slab','slice']+REPLICATE(' done. Saved data to: '+STRTRIM(filename,2),2)
  ; Set loop_slab to slice or slab, depending on set keyword
	IF KEYWORD_SET(SAVE_SLICE) THEN $
    loop_slab = *(*(*info).loopsdata).loopslice $
  ELSE $
    loop_slab = *(*(*info).loopsdata).loopslab
  ; Check for writeability of output path
	CRISPEX_SAVE_CHECK_PATH_WRITE, event
  ; If output path is writeable, start writing
	IF ((*(*info).paths).opath_write) THEN BEGIN
		WIDGET_CONTROL,/HOURGLASS
		PRINT,save_message1[KEYWORD_SET(SAVE_SLICE)]
    ; Set all variables that are to be saved
		type            = 1
		average_spectrum= ((*(*info).dataparams).spec)[*,(*(*info).dataparams).s] 
		scaling_factor  = (*(*info).dataparams).ms
		vertices        = *(*(*info).loopsdata).crossloc
		x_coords        = *(*(*info).loopparams).xp	
    y_coords        = *(*(*info).loopparams).yp
		x_loop_pts      = *(*(*info).loopparams).xr			
    y_loop_pts      = *(*(*info).loopparams).yr
		w_loop_pts      = *(*(*info).loopparams).w_lpts		
    spect_pos       = (*(*info).dataparams).lp
		t_saved         = (*(*info).dispparams).t			
    loop_size       = (*(*info).loopsdata).loopsize
    ngaps           = (*(*info).loopparams).ngaps
    databounds      = *(*(*info).loopparams).databounds
    wdatabounds     = *(*(*info).loopparams).wdatabounds
		crispex_version = [(*(*info).versioninfo).version_number, $
                       (*(*info).versioninfo).revision_number]
    ; Save loop slab variables to IDL save file and print out message
		SAVE, crispex_version, type, average_spectrum, scaling_factor, vertices, $
      x_coords, y_coords, x_loop_pts, y_loop_pts, w_loop_pts, loop_size, $
      loop_slab, spect_pos, t_saved, ngaps, databounds, wdatabounds, $
      FILENAME=(*(*info).paths).opath+filename
		PRINT,save_message2[KEYWORD_SET(SAVE_SLICE)]
    ; Save loop path variables to separate IDL save file and print out message
		SAVE, crispex_version, x_coords, y_coords, x_loop_pts, y_loop_pts, $
      w_loop_pts, spect_pos, t_saved, FILENAME=(*(*info).paths).opath+filename2
		PRINT,'Saved current loop points for later retrieval to: '+STRTRIM(filename2,2)
    ; Reset buttons
		WIDGET_CONTROL, (*(*info).ctrlscp).sel_saved_loop, SENSITIVE = 1
		WIDGET_CONTROL, (*(*info).ctrlscp).all_saved_loop, SENSITIVE = 1
	ENDIF
END

PRO CRISPEX_SAVE_EXACT_LOOPSLICE, event
; Handles the saving of an exact (i.e. linearly interpolated) timeslice along a loop
	WIDGET_CONTROL, event.TOP, GET_UVALUE = info
	IF (TOTAL(((*(*info).feedbparams).verbosity)[2:3]) GE 1) THEN $
    CRISPEX_VERBOSE_GET_ROUTINE, event
	CRISPEX_SAVE_EXACT_LOOPSLAB, event, /SAVE_SLICE
END

PRO CRISPEX_SAVE_EXACT_LOOPSLAB_CHECK, event, SAVE_SLICE=save_slice
; Opens a time estimate warning window
	WIDGET_CONTROL, event.TOP, GET_UVALUE = info
	IF (TOTAL(((*(*info).feedbparams).verbosity)[2:3]) GE 1) THEN $
    CRISPEX_VERBOSE_GET_ROUTINE, event
	CRISPEX_SAVE_CHECK_PATH_WRITE, event
	IF ((*(*info).paths).opath_write EQ 1) THEN BEGIN
		IF ((*(*info).feedbparams).estimate_run EQ 0) THEN BEGIN
			CRISPEX_ESTIMATE_TIME_WINDOW, event
			CRISPEX_ESTIMATE_TIME_CALCULATION, event
			WIDGET_CONTROL, (*(*info).winids).estimatetlb, /DESTROY
			(*(*info).winids).estimatetlb = 0
			(*(*info).winswitch).estimate_win = 0
		ENDIF
		time = (*(*info).feedbparams).estimate_time * N_ELEMENTS(*(*(*info).loopparams).w_lpts)/FLOAT((*(*info).feedbparams).estimate_lx) * (*(*info).dataparams).nlp * (*(*info).dispparams).t_range
		(*(*info).savswitch).cont = 3
		CRISPEX_ESTIMATE_FULL_TIME, time, denom, units
		CRISPEX_SAVE_WARNING_YESNO, event, 'Saving the exact loop slab may take up to about',STRTRIM(CEIL(time/denom),2)+units+'. Do you wish to continue saving?',$
			OK_EVENT='CRISPEX_SAVE_LOOPSL_CONTINUE', CANCEL_EVENT='CRISPEX_SAVE_LOOPSL_ABORT'
		IF (((*(*info).feedbparams).verbosity)[3] EQ 1) THEN $
      CRISPEX_VERBOSE_GET, event, [(*(*info).savswitch).cont],labels=['Saving procedure']
	ENDIF
END

PRO CRISPEX_SAVE_EXACT_LOOPSLAB, event, SAVE_SLICE=save_slice
; Handles the saving of an exact (i.e. linearly interpolated) timeslab along a loop
	WIDGET_CONTROL, event.TOP, GET_UVALUE = info
	IF (TOTAL(((*(*info).feedbparams).verbosity)[2:3]) GE 1) THEN $
    CRISPEX_VERBOSE_GET_ROUTINE, event
	WIDGET_CONTROL,/HOURGLASS
  ; Set save sub-messages
	save_message1 = ['slab','slice']
	IF KEYWORD_SET(SAVE_SLICE) THEN BEGIN
		PRINT,'Saving current exact loop slice...'
    ; Get exact loop slice based on loop parameters
		CRISPEX_LOOP_GET_EXACT_SLICE, event, *(*(*info).data).imagedata, $
      *(*(*info).loopparams).xr, *(*(*info).loopparams).yr, $
      *(*(*info).loopparams).xp, *(*(*info).loopparams).yp, $
			*(*(*info).loopparams).w_lpts, *(*(*info).loopsdata).exact_loopslice, $
      *(*(*info).loopsdata).exact_crossloc, loopsize, /im
		(*(*info).loopsdata).exact_loopsize = loopsize
		loop_slab = *(*(*info).loopsdata).exact_loopslice
		lp_low = (*(*info).dataparams).lp	&	lp_upp = lp_low
	ENDIF ELSE BEGIN
		t_0 = SYSTIME(/SECONDS)
		feedback_text = 'Saving current exact loop slab...'
		PRINT,feedback_text
		(*(*info).savparams).lp_orig = (*(*info).dataparams).lp
		lp_low = 0	&	lp_upp = (*(*info).dataparams).nlp-1
		FOR k=lp_low,lp_upp DO BEGIN
      ; Call user feedback with appropriate parameters
			CRISPEX_UPDATE_USER_FEEDBACK, event, title='Saving exact loop slab', $
        var=k, maxvar=(*(*info).dataparams).nlp-1, $
        feedback_text=feedback_text+'            ',/destroy_top
			(*(*info).dataparams).lp = k
      ; Get exact loop slice based on loop parameters
			CRISPEX_LOOP_GET_EXACT_SLICE, event, *(*(*info).data).imagedata, $
        *(*(*info).loopparams).xr, *(*(*info).loopparams).yr, $
        *(*(*info).loopparams).xp, *(*(*info).loopparams).yp, $
				*(*(*info).loopparams).w_lpts, *(*(*info).loopsdata).exact_loopslice, $
        *(*(*info).loopsdata).exact_crossloc, loopsize, /im
			IF (k EQ 0) THEN $
				*(*(*info).loopsdata).exact_loopslab = $
          *(*(*info).loopsdata).exact_loopslice $
			ELSE $
        *(*(*info).loopsdata).exact_loopslab = $
          [[[*(*(*info).loopsdata).exact_loopslab]], $
          [[*(*(*info).loopsdata).exact_loopslice]]]
			t_1 = SYSTIME(/SECONDS)
      ; Estimate saving time based on what has been extracted until now
			CRISPEX_ESTIMATE_FULL_TIME_RUNNING, k+1, (*(*info).dataparams).nlp, t_0, $
        t_1, denom, units, accumsectime, totalsectime
      ; Set feedback message
			feedback_text = STRTRIM(k+1,2)+'/'+STRTRIM((*(*info).dataparams).nlp,2)+$
        ' slices extracted in '+STRTRIM(STRING(accumsectime/denom,$
        FORMAT='(3(F9.2,x))'),2)+'/'+STRTRIM(STRING(totalsectime/denom,$
        FORMAT='(3(F9.2,x))'),2)+units
		ENDFOR
		(*(*info).dataparams).lp = (*(*info).savparams).lp_orig
		loop_slab = *(*(*info).loopsdata).exact_loopslab
	ENDELSE
	(*(*info).loopsdata).exact_loopsize = loopsize
  ; Check for writeability of output path
	CRISPEX_SAVE_CHECK_PATH_WRITE, event
  ; If output path is writeable, start writing
	IF ((*(*info).paths).opath_write EQ 1) THEN BEGIN
		WIDGET_CONTROL,/HOURGLASS
    ; Set all variables that are to be saved
  	type            = 0
  	average_spectrum= ((*(*info).dataparams).spec)[*,(*(*info).dataparams).s] 
  	scaling_factor  = (*(*info).dataparams).ms
  	vertices        = *(*(*info).loopsdata).exact_crossloc
  	x_coords        = *(*(*info).loopparams).xp  
    y_coords        = *(*(*info).loopparams).yp
  	x_loop_pts      = *(*(*info).loopparams).xr				
    y_loop_pts      = *(*(*info).loopparams).yr
		w_loop_pts      = *(*(*info).loopparams).w_lpts		
  	spect_pos       = (*(*info).dataparams).lp				
    loop_size       = (*(*info).loopsdata).exact_loopsize
  	spect_pos_low   = lp_low						
    spect_pos_upp   = lp_upp
  	t_low           = (*(*info).dispparams).t_low				
    t_upp           = (*(*info).dispparams).t_upp
  	t_saved         = (*(*info).dispparams).t
    ngaps           = (*(*info).loopparams).ngaps
    databounds      = *(*(*info).loopparams).databounds
    wdatabounds     = *(*(*info).loopparams).wdatabounds
  	crispex_version = [(*(*info).versioninfo).version_number, $
                       (*(*info).versioninfo).revision_number]
  	CRISPEX_SAVE_DETERMINE_FILENAME, event, outfilename=filename, /tlab, $
      ext='csav'
  	IF ~KEYWORD_SET(SAVE_SLICE) THEN CRISPEX_WINDOW_USER_FEEDBACK_CLOSE, event
    ; Save loop slab variables to IDL save file and print out message
  	SAVE, crispex_version, type, average_spectrum, scaling_factor, vertices, $
      x_coords, y_coords, x_loop_pts, y_loop_pts, w_loop_pts, loop_size, loop_slab, $
      spect_pos, lp_low, lp_upp, t_saved, t_low, t_upp, ngaps, databounds, $
      wdatabounds, FILENAME = (*(*info).paths).opath+filename
  	PRINT,'Saving current exact loop '+save_message1[KEYWORD_SET(SAVE_SLICE)]+$
      ' done. Saved data to: '+STRTRIM(filename,2)
  ENDIF
END

PRO CRISPEX_SAVE_LOOPSL_CONTINUE, event
; Handles continue events from the loopslice/slab warning window
	WIDGET_CONTROL, event.TOP, GET_UVALUE = info
	IF (TOTAL(((*(*info).feedbparams).verbosity)[2:3]) GE 1) THEN $
    CRISPEX_VERBOSE_GET_ROUTINE, event
  CASE (*(*info).savswitch).cont OF
  ; Save diagram from saved path at single spectral position
    1: CRISPEX_SAVE_RETRIEVE_LOOPSLAB, event, /SAVE_SLICE		
  ; Save diagram from saved path for all spectral positions
    2: CRISPEX_SAVE_RETRIEVE_LOOPSLAB, event 		
  ; Save diagram for all spectral positions
    3: CRISPEX_SAVE_EXACT_LOOPSLAB, event 				
  ; Save diagram from saved detection at single spectral position
    4: CRISPEX_SAVE_RETRIEVE_DET_LOOPSLAB, event, /SAVE_SLICE		
  ; Save diagram from saved detection at all spectral positions
    5: CRISPEX_SAVE_RETRIEVE_DET_LOOPSLAB, event 			
    ELSE: RETURN
  ENDCASE
END

PRO CRISPEX_SAVE_LOOPSL_ABORT, event
; Handles abort event from the loopslice/slab warning window
	WIDGET_CONTROL, event.TOP, GET_UVALUE = info
	IF (TOTAL(((*(*info).feedbparams).verbosity)[2:3]) GE 1) THEN $
    CRISPEX_VERBOSE_GET_ROUTINE, event
	(*(*info).savswitch).cont = 0
	IF (((*(*info).feedbparams).verbosity)[3] EQ 1) THEN $
    CRISPEX_VERBOSE_GET, event, [(*(*info).savswitch).cont],$
      labels=['Saving procedure']
	WIDGET_CONTROL, event.TOP, /DESTROY
END

PRO CRISPEX_SAVE_RETRIEVE_LOOPSLAB, event, SAVE_SLICE=save_slice
; Handles the saving of an exact (i.e. linearly interpolated) timeslab along a
;  retrieved loop 
  WIDGET_CONTROL, event.TOP, GET_UVALUE = info
	IF (TOTAL(((*(*info).feedbparams).verbosity)[2:3]) GE 1) THEN $
    CRISPEX_VERBOSE_GET_ROUTINE, event
  ; Store current wavelength values, to be restored once done
	(*(*info).savparams).lp_orig = (*(*info).dataparams).lp
	(*(*info).savparams).lp_ref_orig = (*(*info).dataparams).lp_ref
  ndatafiles = TOTAL((*(*info).savswitch).imrefsji * [1,1,(*(*info).dataparams).nsjifiles])
	nfiles = (*(*info).retrparams).retrieve_filecount * ndatafiles
  where_imrefsji = WHERE((*(*info).savswitch).imrefsji EQ 1)
	pass = 0L
	loopdet = ([2,1])[KEYWORD_SET(SAVE_SLICE)]
  ; Set variables depending on whether saving a slice or a slab
	IF KEYWORD_SET(SAVE_SLICE) THEN BEGIN
		nlp_pos = 1				&	refnlp_pos = 1
		save_message = 'slice'
	ENDIF ELSE BEGIN
		nlp_pos = (*(*info).dataparams).nlp	
    refnlp_pos = (*(*info).dataparams).refnlp
		save_message = 'slab'
	ENDELSE
  ; Determine number of passes, depending on saving from main, ref or both
  maxpass = 0
  IF ((*(*info).savswitch).imrefsji[0] EQ 1) THEN $
    maxpass += nlp_pos * (*(*info).retrparams).retrieve_filecount 
  IF ((*(*info).savswitch).imrefsji[1] EQ 1) THEN $
    maxpass += refnlp_pos * (*(*info).retrparams).retrieve_filecount 
  IF ((*(*info).savswitch).imrefsji[2] EQ 1) THEN BEGIN
    maxpass += (*(*info).dataparams).nsjifiles * (*(*info).retrparams).retrieve_filecount 
    IF ((*(*info).dataparams).nsjifiles GT 1) THEN BEGIN
      where_imrefsji = $
        [where_imrefsji, REPLICATE(2, (*(*info).dataparams).nsjifiles-1)]
    ENDIF
  ENDIF
  idx_sji = BYTARR(N_ELEMENTS(where_imrefsji))
  where_sji = WHERE(where_imrefsji EQ 2, sjicount)
  IF (sjicount GT 0) THEN $
    idx_sji[WHERE(where_imrefsji EQ 2)] = $
      INDGEN((*(*info).dataparams).nsjifiles)
	t_0 = SYSTIME(/SECONDS)
	WIDGET_CONTROL,/HOURGLASS
  ; Check output path for writeability
	CRISPEX_SAVE_CHECK_PATH_WRITE, event
	FOR i=0,nfiles-1 DO BEGIN
		t_1 = SYSTIME(/SECONDS)
    ; Get current filename
    inp_idx = (i MOD (*(*info).retrparams).retrieve_filecount)
    out_idx = FLOOR(i / FLOAT((*(*info).retrparams).retrieve_filecount))
    idx_sji_sel = idx_sji[out_idx]
		fstr = (*(*(*info).retrparams).retrieve_files)[inp_idx]
    imrefsji_sel = where_imrefsji[out_idx]
    ; Restore loop path file
		RESTORE,(*(*(*info).retrparams).retrieve_files)[inp_idx]
    ; Determine save filename, based on input file names
    CRISPEX_SAVE_RETRIEVE_DETERMINE_FILENAME, event, $
      imrefsji_sel, (*(*info).dataparams).imfilename, $
		  refimfilename=(*(*info).dataparams).refimfilename, $
		  sjifilename=(*(*info).dataparams).sjifilename[idx_sji_sel], $
      *(*(*info).data).imagedata, refdata=*(*(*info).data).refdata, $
      sjidata=*(*(*info).data).sjidata[idx_sji_sel], $
      filename, data, nonlp, fstr=fstr, loopdet=loopdet ;$
    ; Check whether saved-from file is different from current data file
    saved_from = FILE_BASENAME(fstr,'.clsav')
    saved_to = FILE_BASENAME(filename,'.csav')
    IF (saved_to NE saved_from) THEN BEGIN
      IF (imrefsji_sel EQ 0) THEN BEGIN
        ; Current data file is main, but path was saved from ref
        ; Convert path coordinates from ref to main
        IF ((*(*info).dataswitch).wcs_set AND $
          (*(*info).dataswitch).ref_wcs_set) THEN BEGIN
          IF ((TOTAL(x_coords LT 0) EQ 0) AND $
            (TOTAL(x_coords GE (*(*info).dataparams).refnx) EQ 0) AND $
            (TOTAL(y_coords LT 0) EQ 0) AND $
            (TOTAL(y_coords GE (*(*info).dataparams).refny)) EQ 0) THEN BEGIN
            xp_main = $
              REFORM(((*(*(*info).dataparams).pix_ref2main)[*,x_coords,0])[0,*])
            yp_main = $
              REFORM(((*(*(*info).dataparams).pix_ref2main)[*,0,y_coords])[1,0,*])
            xyp = {x:xp_main, y:yp_main}
          ENDIF ELSE $
            xyp = CRISPEX_TRANSFORM_GET_WCS(x_coords, y_coords, $
              *(*(*info).dataparams).wcs_ref, (*(*info).dataparams).wcs_main, $
              /PIXEL, /COORD)
        ENDIF ELSE BEGIN
          xyp = CRISPEX_TRANSFORM_COORDS(x_coords, y_coords, $
            (*(*info).dataparams).refdx, (*(*info).dataparams).dx, $
            (*(*info).dataparams).refdy, (*(*info).dataparams).dy, $
            (*(*info).dataparams).xval_ref, (*(*info).dataparams).xval, $
            (*(*info).dataparams).yval_ref, (*(*info).dataparams).yval, $
            (*(*info).dataparams).xpix_ref, (*(*info).dataparams).xpix, $
            (*(*info).dataparams).ypix_ref, (*(*info).dataparams).ypix)
        ENDELSE
        xypath = CRISPEX_GET_PATH(xyp.x, xyp.y, N_ELEMENTS(xyp.x), $
          (*(*info).dataparams).nx, (*(*info).dataparams).ny)
        x_coords = xyp.x
        y_coords = xyp.y
        x_loop_pts = xypath.xr
        y_loop_pts = xypath.yr
        nx = (*(*info).dataparams).nx
        ny = (*(*info).dataparams).ny
      ENDIF ELSE IF (imrefsji_sel EQ 1) THEN BEGIN
        ; Current data file is ref, but path was saved from main
        ; Convert path coordinates from main to ref
        IF ((*(*info).dataswitch).wcs_set AND $
          (*(*info).dataswitch).ref_wcs_set) THEN BEGIN
          IF ((TOTAL(x_coords LT 0) EQ 0) AND $
            (TOTAL(x_coords GE (*(*info).dataparams).nx) EQ 0) AND $
            (TOTAL(y_coords LT 0) EQ 0) AND $
            (TOTAL(y_coords GE (*(*info).dataparams).ny)) EQ 0) THEN BEGIN
            xp_ref = $
              REFORM(((*(*(*info).dataparams).pix_main2ref)[*,x_coords,0])[0,*])
            yp_ref = $
              REFORM(((*(*(*info).dataparams).pix_main2ref)[*,0,y_coords])[1,0,*])
            xyp = {x:xp_ref, y:yp_ref}
          ENDIF ELSE $
            xyp = CRISPEX_TRANSFORM_GET_WCS(x_coords, y_coords, $
              (*(*info).dataparams).wcs_main, *(*(*info).dataparams).wcs_ref, $
              /PIXEL, /COORD)
        ENDIF ELSE BEGIN
          xyp = CRISPEX_TRANSFORM_COORDS(x_coords, y_coords, $
            (*(*info).dataparams).dx, (*(*info).dataparams).refdx, $
            (*(*info).dataparams).dy, (*(*info).dataparams).refdy, $
            (*(*info).dataparams).xval, (*(*info).dataparams).xval_ref, $
            (*(*info).dataparams).yval, (*(*info).dataparams).yval_ref, $
            (*(*info).dataparams).xpix, (*(*info).dataparams).xpix_ref, $
            (*(*info).dataparams).ypix, (*(*info).dataparams).ypix_ref)
        ENDELSE
        xypath = CRISPEX_GET_PATH(xyp.x, xyp.y, N_ELEMENTS(xyp.x), $
          (*(*info).dataparams).refnx, (*(*info).dataparams).refny)
        x_coords = xyp.x
        y_coords = xyp.y
        x_loop_pts = xypath.xr
        y_loop_pts = xypath.yr
        nx = (*(*info).dataparams).refnx
        ny = (*(*info).dataparams).refny
      ENDIF ELSE BEGIN
        ; Current data file is sji, but path was saved from main
        ; Convert path coordinates from main to sji
        IF ((*(*info).dataswitch).wcs_set AND $
          (*(*info).dataswitch).sji_wcs_set[idx_sji_sel]) THEN BEGIN
          IF ((TOTAL(x_coords LT 0) EQ 0) AND $
            (TOTAL(x_coords GE (*(*info).dataparams).nx) EQ 0) AND $
            (TOTAL(y_coords LT 0) EQ 0) AND $
            (TOTAL(y_coords GE (*(*info).dataparams).ny)) EQ 0) THEN BEGIN
            xp_sji = $
              REFORM(((*(*(*info).dataparams).pix_main2sji[idx_sji_sel])[*,x_coords,0])[0,*])
            yp_sji = $
              REFORM(((*(*(*info).dataparams).pix_main2sji[idx_sji_sel])[*,0,y_coords])[1,0,*])
            xyp = {x:xp_sji, y:yp_sji}
          ENDIF ELSE $
            xyp = CRISPEX_TRANSFORM_GET_WCS(x_coords, y_coords, $
              (*(*info).dataparams).wcs_main, $
              *(*(*info).dataparams).wcs_sji[idx_sji_sel], $
              /PIXEL, /COORD)
        ENDIF ELSE BEGIN
          xyp = CRISPEX_TRANSFORM_COORDS(x_coords, y_coords, $
            (*(*info).dataparams).dx, (*(*info).dataparams).sjidx[idx_sji_sel], $
            (*(*info).dataparams).dy, (*(*info).dataparams).sjidy[idx_sji_sel], $
            (*(*info).dataparams).xval, $
            (*(*info).dataparams).xval_sji[idx_sji_sel], $
            (*(*info).dataparams).yval, $
            (*(*info).dataparams).yval_sji[idx_sji_sel], $
            (*(*info).dataparams).xpix, $
            (*(*info).dataparams).xpix_sji[idx_sji_sel], $
            (*(*info).dataparams).ypix, $
          (*(*info).dataparams).ypix_sji[idx_sji_sel])
        ENDELSE
        xypath = CRISPEX_GET_PATH(xyp.x, xyp.y, N_ELEMENTS(xyp.x), $
          (*(*info).dataparams).sjinx[idx_sji_sel], $
          (*(*info).dataparams).sjiny[idx_sji_sel])
        x_coords = xyp.x
        y_coords = xyp.y
        x_loop_pts = xypath.xr
        y_loop_pts = xypath.yr
        nx = (*(*info).dataparams).sjinx[idx_sji_sel]
        ny = (*(*info).dataparams).sjiny[idx_sji_sel]
      ENDELSE
	    w_loop_pts = $
        WHERE((x_loop_pts GE 0) AND (x_loop_pts LT (nx)) AND $
              (y_loop_pts GE 0) AND (y_loop_pts LT (ny)), nw_lpts)
    ENDIF
		IF (N_ELEMENTS(T_SAVED) NE 1) THEN t_saved = (*(*info).dispparams).t
		IF (KEYWORD_SET(SAVE_SLICE) OR (imrefsji_sel EQ 2)) THEN BEGIN
      IF (imrefsji_sel EQ 0) THEN BEGIN
        IF (saved_from EQ saved_to) THEN $
			    lp_low = spect_pos<((*(*info).dataparams).nlp-1)	$
        ELSE $
          lp_low = (*(*info).savparams).lp_orig
      ENDIF ELSE IF (imrefsji_sel EQ 1) THEN BEGIN
        IF (saved_from EQ saved_to) THEN $
			    lp_low = spect_pos<((*(*info).dataparams).refnlp-1) $
        ELSE $
          lp_low = (*(*info).savparams).lp_ref_orig
      ENDIF ELSE $
        lp_low = 0
      lp_upp = lp_low
      spect_pos = lp_low
		ENDIF ELSE BEGIN
			lp_low = 0
			IF (imrefsji_sel EQ 0) THEN BEGIN
				lp_upp = (*(*info).dataparams).nlp-1 
        IF (saved_from NE saved_to) THEN $
          spect_pos = (*(*info).savparams).lp_orig
      ENDIF ELSE IF (imrefsji_sel EQ 1) THEN BEGIN
				lp_upp = (*(*info).dataparams).refnlp-1	
        IF (saved_from NE saved_to) THEN $
          spect_pos = (*(*info).savparams).lp_ref_orig
      ENDIF ELSE BEGIN
        lp_upp = 0
        spect_pos = 0
			ENDELSE
		ENDELSE
		FOR k=lp_low,lp_upp DO BEGIN
			pass += 1L
			part = STRTRIM(pass,2)+'/'+STRTRIM(maxpass,2)
			IF (pass EQ 1) THEN $
        feedback_text = ': saving retrieved exact loop '+$
          save_message+'...               '
			CRISPEX_UPDATE_USER_FEEDBACK, event, title='Saving retrieved loop '+$
        save_message+'(s)', var=pass-1, maxvar=maxpass, feedback_text=part+$
        feedback_text, /destroy_top
			IF (imrefsji_sel EQ 0) THEN $ 
        (*(*info).dataparams).lp = k $
      ELSE IF (imrefsji_sel EQ 1) THEN $
        (*(*info).dataparams).lp_ref = k
			CRISPEX_LOOP_GET_EXACT_SLICE, event, data, x_loop_pts, $
        y_loop_pts, x_coords, y_coords, w_loop_pts, loop_slice_out, $
        crossloc_out, loopsize_out, IM=(imrefsji_sel EQ 0), $
        SJI=(imrefsji_sel EQ 2), IDX_SJI=idx_sji_sel
			IF ~KEYWORD_SET(SAVE_SLICE) THEN BEGIN
				IF (k EQ lp_low) THEN $
          loop_slab = loop_slice_out $
        ELSE $
          loop_slab = [ [[loop_slab]], [[loop_slice_out]] ]
			ENDIF ELSE $
        loop_slab = loop_slice_out
			t_1 = SYSTIME(/SECONDS)
			CRISPEX_ESTIMATE_FULL_TIME_RUNNING, pass, maxpass, t_0, t_1, denom, $
        units, accumsectime, totalsectime
			feedback_text = ' slices extracted in '+$
        STRTRIM(STRING(accumsectime/denom,FORMAT='(3(F9.2,x))'),2)+'/'+$
        STRTRIM(STRING(totalsectime/denom,FORMAT='(3(F9.2,x))'),2)+units
		ENDFOR
    ; Check for gaps if info not availabe from restored file (although it will
    ; likely have no gaps then)
    IF ((N_ELEMENTS(ngaps) NE 0) AND (saved_to EQ saved_from)) THEN $
      result = {ngaps:ngaps, databounds:databounds, wdatabounds:wdatabounds} $
    ELSE $ 
      result = CRISPEX_ARRAY_GET_GAP(w_loop_pts, N_ELEMENTS(x_loop_pts))
		type = 0
		IF (imrefsji_sel EQ 0) THEN BEGIN
			average_spectrum= ((*(*info).dataparams).spec)[*,(*(*info).dataparams).s] 
			scaling_factor  = (*(*info).dataparams).ms
    ENDIF ELSE IF (imrefsji_sel EQ 1) THEN BEGIN
			average_spectrum= $
        ((*(*info).dataparams).refspec)[*,(*(*info).dataparams).s_ref]
			scaling_factor  = (*(*info).dataparams).refms
    ENDIF ELSE BEGIN
      average_spectrum = 0
      scaling_factor = 1
		ENDELSE
    vertices        = crossloc_out
		spect_pos_low   = lp_low						
    spect_pos_upp   = lp_upp
    loop_size       = loopsize_out
		t_low           = (*(*info).dispparams).t_low				
    t_upp           = (*(*info).dispparams).t_upp
    ngaps           = result.ngaps
    databounds      = result.databounds
    wdatabounds     = result.wdatabounds
		crispex_version = [(*(*info).versioninfo).version_number, $
      (*(*info).versioninfo).revision_number]
    singlefilename = FILE_BASENAME(filename)
		SAVE, crispex_version, type, average_spectrum, scaling_factor, vertices, $
      x_coords, y_coords, x_loop_pts, y_loop_pts, loop_size, loop_slab, $
      spect_pos, spect_pos_low, spect_pos_upp, t_saved, t_low, t_upp, $
      ngaps, databounds, wdatabounds, $
			FILENAME = (*(*info).paths).opath+singlefilename 
		PRINT,'Saving retrieved exact loop '+save_message+' done. Saved data to: '+$
      STRTRIM(singlefilename,2)
		IF (*(*info).savswitch).delete_clsav THEN BEGIN
			IF (TOTAL((*(*info).savswitch).imrefsji) LE 2) THEN $
        FILE_DELETE, STRTRIM((*(*(*info).retrparams).retrieve_files)[i],2), /QUIET $
      ELSE BEGIN
				IF (i GE (*(*info).retrparams).retrieve_filecount) THEN $
          FILE_DELETE, STRTRIM((*(*(*info).retrparams).retrieve_files)[$
                        (i MOD (*(*info).retrparams).retrieve_filecount)],2), /QUIET
			ENDELSE
		ENDIF
	ENDFOR
	CRISPEX_WINDOW_USER_FEEDBACK_CLOSE, event
	(*(*info).dataparams).lp = (*(*info).savparams).lp_orig
	(*(*info).dataparams).lp_ref = (*(*info).savparams).lp_ref_orig
END

PRO CRISPEX_SAVE_RETRIEVE_DETERMINE_FILENAME, event, imrefsji, imfilename, $
  refimfilename=refimfilename, sjifilename=sjifilename, imdata, refdata=refdata,$
  sjidata=sjidata, outputfilename, outputdata, $
  outputnonlp, index=index, fstr=fstr, $
  loopdet=loopdet
; Determines the filename of the retrieved loop path or detection timeslice to be saved
	; loopdet = 1 > loop, slice
	; loopdet = 2 > loop, slab
	; loopdet = 3 > det, slice
	; loopdet = 4 > det, slab
	; outputimref = 1 > main
	; outputimref = 2 > reference
  ; outputimref = 3 > sji
  outputnonlp = (loopdet EQ 1) OR (loopdet EQ 3) OR (imrefsji EQ 2)
  IF (imrefsji EQ 0) THEN BEGIN
    infilename = imfilename
		outputdata = imdata
  ENDIF
  IF (imrefsji EQ 1) THEN BEGIN
    infilename = refimfilename
		outputdata = refdata
  ENDIF
  IF (imrefsji EQ 2) THEN BEGIN
    infilename = sjifilename
		outputdata = sjidata
  ENDIF
	IF (loopdet LE 2) THEN BEGIN
	  clstr = STRSPLIT(fstr,'_',/EXTRACT)
	  datestamp = clstr[N_ELEMENTS(clstr)-2]
	  timestamp = (STRSPLIT(clstr[N_ELEMENTS(clstr)-1],'.',/EXTRACT))[0]
		CRISPEX_SAVE_DETERMINE_FILENAME, event, infilename=infilename, $
      outfilename=outputfilename, ext='csav', $
      import_id=datestamp+'_'+timestamp 
  ENDIF ELSE $
    CRISPEX_SAVE_DETERMINE_FILENAME, event, infilename=infilename, $
      outfilename=outputfilename, ext='csav', import_id = 'D'+STRTRIM(index,2)
END

PRO CRISPEX_SAVE_RETRIEVE_DET_LOOPSLAB, event, SAVE_SLICE=save_slice
; Handles the saving of an exact (i.e. linearly interpolated) timeslab along a
; retrieved detection 
  WIDGET_CONTROL, event.TOP, GET_UVALUE = info
	IF (TOTAL(((*(*info).feedbparams).verbosity)[2:3]) GE 1) THEN $
    CRISPEX_VERBOSE_GET_ROUTINE, event
	nfiles = (*(*info).detparams).nr_sel_loops * $
    CEIL((*(*info).savswitch).det_imref_only/2.)
	pass = 0
	loopdet = ([4,3])[KEYWORD_SET(SAVE_SLICE)]
  ; Store original temporal boundaries and wavelength position
	lower_t = (*(*info).dispparams).t_low
	upper_t = (*(*info).dispparams).t_upp
	(*(*info).savparams).lp_orig = (*(*info).dataparams).lp
  ; Determine wavelength boundaries, based on save settings
	IF KEYWORD_SET(SAVE_SLICE) THEN BEGIN
    ; Saving slice, from main 
		lp_dn = (*(*info).dataparams).lp	
    lp_up = lp_dn
		IF ((*(*info).savswitch).det_imref_only GE 2) THEN BEGIN
      ; Saving slice, either from ref only or from main and ref
			lp_ref_dn = (*(*info).dataparams).lp_ref	
      lp_ref_up = lp_ref_dn
		ENDIF
	ENDIF ELSE BEGIN
    ; Saving slab
		IF ((*(*info).savswitch).pos_dets EQ 1) THEN BEGIN
      ; All wavelengths, for main
			lp_dn = (*(*info).dispparams).lp_first	
      lp_up = (*(*info).dispparams).lp_last
			IF ((*(*info).savswitch).det_imref_only GE 2) THEN BEGIN
        ; All wavelengths, either from ref only or from main and ref
				lp_ref_dn = (*(*info).dispparams).lp_ref_first	
        lp_ref_up = (*(*info).dispparams).lp_ref_last
			ENDIF
		ENDIF 
	ENDELSE
  IF ((*(*info).savswitch).pos_dets NE 3) THEN BEGIN
    ; Selected wavelengths, from main
  	(*(*info).detparams).lp_dn = lp_dn	
    (*(*info).detparams).lp_up = lp_up
    IF ((*(*info).savswitch).det_imref_only GE 2) THEN BEGIN
      ; Selected wavelengths, from reference
			(*(*info).detparams).lp_ref_dn = lp_ref_dn	
      (*(*info).detparams).lp_ref_up = lp_ref_up
    ENDIF
  ENDIF
  lp_range = (*(*info).detparams).lp_up-(*(*info).detparams).lp_dn+1
  lp_ref_range = (*(*info).detparams).lp_ref_up-(*(*info).detparams).lp_ref_dn+1
  ; Determine number of maximum passes, based on what to save
	IF ((*(*info).savswitch).det_imref_only EQ 1) THEN $
    maxpass = lp_range * (*(*info).detparams).width * nfiles $
  ELSE IF ((*(*info).savswitch).det_imref_only EQ 2) THEN $
    maxpass = lp_ref_range * (*(*info).detparams).width * nfiles $
  ELSE $
		maxpass = (lp_range  + lp_ref_range) * (*(*info).detparams).width * $
                (*(*info).detparams).nr_sel_loops
  ; Determine saved wavelength
	IF ((*(*info).savparams).lp_orig LT (*(*info).detparams).lp_dn) THEN $
    lp_im_saved = (*(*info).detparams).lp_dn $
  ELSE IF ((*(*info).savparams).lp_orig GT (*(*info).detparams).lp_up) THEN $
    lp_im_saved = (*(*info).detparams).lp_up $
  ELSE $
    lp_im_saved = (*(*info).savparams).lp_orig
	IF ((*(*info).savswitch).det_imref_only GE 2) THEN BEGIN
    ; Store original wavelength and determine saved wavlength for ref
		(*(*info).savparams).lp_ref_orig = (*(*info).dataparams).lp_ref
		IF ((*(*info).savparams).lp_ref_orig LT $
      (*(*info).detparams).lp_ref_dn) THEN $
      lp_ref_saved = (*(*info).detparams).lp_ref_dn $
    ELSE IF ((*(*info).savparams).lp_ref_orig GT $
      (*(*info).detparams).lp_ref_up) THEN $
      lp_ref_saved = (*(*info).detparams).lp_ref_up $
    ELSE $
      lp_ref_saved = (*(*info).savparams).lp_ref_orig
	ENDIF
	t_0 = SYSTIME(/SECONDS)
  ; Loop over all detections to be retrieved
	FOR i=0,nfiles-1 DO BEGIN
		WIDGET_CONTROL,/HOURGLASS
		part = STRTRIM(i+1,2)+'/'+STRTRIM(nfiles,2)
    ; Get the current detection index
		idx = (*(*(*info).detparams).sel_loops)[$
      (i MOD (*(*info).detparams).nr_sel_loops)]
    ; Determine the output filename
		IF ((*(*info).dataparams).refimfilename NE '') THEN BEGIN
      CRISPEX_SAVE_RETRIEVE_DETERMINE_FILENAME, event, $
        (*(*info).savswitch).det_imref_only, (*(*info).dataparams).imfilename, $
			  refimfilename=(*(*info).dataparams).refimfilename, $
        *(*(*info).data).imagedata, refdata=*(*(*info).data).refdata, $
        (*(*info).paths).opath, i, (*(*info).detparams).nr_sel_loops, $
        filename, data, nonlp, detimref, detwhichdata, fstr=fstr, $
        loopdet=loopdet, index=idx 
    ENDIF ELSE BEGIN
			CRISPEX_SAVE_RETRIEVE_DETERMINE_FILENAME, event, $
        (*(*info).savswitch).det_imref_only, (*(*info).dataparams).imfilename, $
        *(*(*info).data).imagedata, (*(*info).paths).opath, i, $
				(*(*info).detparams).nr_sel_loops, filename, data, nonlp, detimref, $
        detwhichdata, fstr=fstr, loopdet=loopdet, index=idx
    ENDELSE
		delta = FLOOR((*(*info).detparams).width/2.)
    ; Get path variables
    xlp_det = *(*(*(*info).detparams).xlp)[idx]
    ylp_det = *(*(*(*info).detparams).ylp)[idx]
    xlr_det = *(*(*(*info).detparams).xlr)[idx]
    ylr_det = *(*(*(*info).detparams).ylr)[idx]
    ; Loop over detection width to get the smallest subset of w_lpts in order to
    ; determine path selection, gaps, etc. (and if necessary, conversions to
    ; reference) 
		IF (detimref EQ 1) THEN BEGIN
      ; If saving from main, set parameters accordingly
      data = (*(*info).data).imagedata
      lp_saved = lp_im_saved 
      nx = (*(*info).dataparams).nx
      ny = (*(*info).dataparams).ny
			lp_dn = (*(*info).detparams).lp_dn 	
      lp_up = (*(*info).detparams).lp_up < ((*(*info).dataparams).nlp-1)
    ENDIF ELSE BEGIN
      ; If saving from reference, set parameters accordingly
      data = (*(*info).data).refdata
			lp_saved = lp_ref_saved
			lp_dn = (*(*info).detparams).lp_ref_dn 	
      lp_up = (*(*info).detparams).lp_ref_up < $
        ((*(*info).dataparams).refnlp-1)
      nx = (*(*info).dataparams).refnx
      ny = (*(*info).dataparams).refny
      ; Transform coordinates if necessary
      IF ((*(*info).dispswitch).main2ref_no_map EQ 0) THEN BEGIN
        IF ((*(*info).dataswitch).wcs_set AND $
          (*(*info).dataswitch).ref_wcs_set) THEN BEGIN
          IF ((TOTAL(xlp_det LT 0) EQ 0) AND $
            (TOTAL(xlp_det GE (*(*info).dataparams).nx) EQ 0) AND $
            (TOTAL(ylp_det LT 0) EQ 0) AND $
            (TOTAL(ylp_det GE (*(*info).dataparams).ny)) EQ 0) THEN BEGIN
            xlp_ref = $
              REFORM(((*(*(*info).dataparams).pix_main2ref)[*,xlp_det,0])[0,*])
            ylp_ref = $
              REFORM(((*(*(*info).dataparams).pix_main2ref)[*,0,ylp_det])[1,0,*])
            xylp_ref = {x:xlp_ref, y:ylp_ref}
          ENDIF ELSE $
            xylp_ref = CRISPEX_TRANSFORM_GET_WCS(xlp_det, ylp_det, $
              (*(*info).dataparams).wcs_main, *(*(*info).dataparams).wcs_ref, $
              /PIXEL, /COORD)
        ENDIF ELSE BEGIN
          xylp_ref = CRISPEX_TRANSFORM_COORDS(xlp_det, ylp_det, $
            (*(*info).dataparams).dx, (*(*info).dataparams).refdx, $
            (*(*info).dataparams).dy, (*(*info).dataparams).refdy, $
            (*(*info).dataparams).xval, (*(*info).dataparams).xval_ref, $
            (*(*info).dataparams).yval, (*(*info).dataparams).yval_ref, $
            (*(*info).dataparams).xpix, (*(*info).dataparams).xpix_ref, $
            (*(*info).dataparams).ypix, (*(*info).dataparams).ypix_ref)
        ENDELSE
        xlp_det = xylp_ref.x
        ylp_det = xylp_ref.y
  		  FOR k=((*(*info).detparams).mid-delta),$
              ((*(*info).detparams).mid+delta) DO BEGIN
          xlr_tmp = (xlr_det)[*,k]
          ylr_tmp = (ylr_det)[*,k]
          IF ((*(*info).dataswitch).wcs_set AND $
            (*(*info).dataswitch).ref_wcs_set) THEN $
            xylr_ref = CRISPEX_TRANSFORM_GET_WCS(xlr_tmp, ylr_tmp, $
              (*(*info).dataparams).wcs_main, *(*(*info).dataparams).wcs_ref, $
              /PIXEL, /COORD, /NO_ROUND) $
          ELSE BEGIN
            xylr_ref = CRISPEX_TRANSFORM_COORDS(xlr_tmp, ylr_tmp, $
              (*(*info).dataparams).dx, (*(*info).dataparams).refdx, $
              (*(*info).dataparams).dy, (*(*info).dataparams).refdy, $
              (*(*info).dataparams).xval, (*(*info).dataparams).xval_ref, $
              (*(*info).dataparams).yval, (*(*info).dataparams).yval_ref, $
              (*(*info).dataparams).xpix, (*(*info).dataparams).xpix_ref, $
              (*(*info).dataparams).ypix, (*(*info).dataparams).ypix_ref)
          ENDELSE
          xlr_det[*,k] = xylr_ref.x
          ylr_det[*,k] = xylr_ref.y
        ENDFOR
      ENDIF
    ENDELSE
    ; Get detection slab
    inparams = {xlp:xlp_det, ylp:ylp_det, xlr:xlr_det, ylr:ylr_det, $
      nx:nx, ny:ny, lp_dn:lp_dn, lp_up:lp_up, no_nlp:nonlp, idx:idx, $
      detimref:detimref, data:data, t_0:t_0, maxpass:maxpass}
    CRISPEX_RETRIEVE_DET_GET_SLAB, event, inparams, w_lpts_out, gapresult_out, $
      loopslab_out, crossloc_out, loopsize_out, t_det_out, t_low_out, $
      t_upp_out, /SAVE_DET
    ; Save variables
	  loop_slab = loopslab_out 
		type = 0
		IF (detimref EQ 1) THEN BEGIN
			average_spectrum = ((*(*info).dataparams).spec)[*,(*(*info).dataparams).s] 
			scaling_factor = (*(*info).dataparams).ms
		ENDIF ELSE BEGIN
			average_spectrum = $
        ((*(*info).dataparams).refspec)[*,(*(*info).dataparams).s_ref]
			scaling_factor = (*(*info).dataparams).refms
		ENDELSE
		vertices        = crossloc_out
		spect_pos       = lp_saved	
    spect_pos_low   = lp_dn	
    spect_pos_upp   = lp_up
    loop_size       = loopsize_out
		x_coords        = xlp_det				
    y_coords        = ylp_det
    x_loop_pts      = REFORM(xlr_det[*,(*(*info).detparams).mid])
    y_loop_pts      = REFORM(ylr_det[*,(*(*info).detparams).mid])
		t_saved         = t_det_out					
    t_low           = t_low_out
    t_upp           = t_upp_out
    ngaps           = gapresult_out.ngaps
    databounds      = gapresult_out.databounds
    wdatabounds     = gapresult_out.wdatabounds
		crispex_version = [(*(*info).versioninfo).version_number, $
                       (*(*info).versioninfo).revision_number]
    singlefilename = FILE_BASENAME(filename)
    ; Save variables to file
		SAVE, crispex_version, type, average_spectrum, scaling_factor, vertices, $
      x_coords, y_coords, x_loop_pts, y_loop_pts, loop_size, loop_slab, $
      spect_pos, spect_pos_low, spect_pos_upp, t_saved, t_low, t_upp, $
      ngaps, databounds, wdatabounds, $
			FILENAME = (*(*info).paths).opath+singlefilename 
		PRINT,'Saving retrieved exact space-time diagram done. Saved data to: '+$
      STRTRIM(singlefilename,2)
	ENDFOR
  ; Reset display variable to original values
	(*(*info).dispparams).t_low = lower_t
	(*(*info).dispparams).t_upp = upper_t
	(*(*info).dataparams).lp = (*(*info).savparams).lp_orig
	IF ((*(*info).savswitch).det_imref_only GE 2) THEN $
    (*(*info).dataparams).lp_ref = (*(*info).savparams).lp_ref_orig
	CRISPEX_WINDOW_USER_FEEDBACK_CLOSE, event
END

;========================= OUTPUT SAVE SETTINGS AND FILENAME CHECK
PRO CRISPEX_SAVE_CHECK_PATH_WRITE, event
; Checks whether the user has write permissions in the current opath
	WIDGET_CONTROL, event.TOP, GET_UVALUE = info
	IF (TOTAL(((*(*info).feedbparams).verbosity)[2:3]) GE 1) THEN $
    CRISPEX_VERBOSE_GET_ROUTINE, event
	(*(*info).paths).opath_write = FILE_TEST((*(*info).paths).opath, /WRITE)
	IF ((*(*info).paths).opath_write EQ 0) THEN BEGIN
		CRISPEX_WINDOW_OK, event, 'ERROR!',$
      'You appear not to have write permissions to the current '+$
      'output directory ('+(*(*info).paths).opath+'). '+$
			'Please change the path before continuing saving.', $
      OK_EVENT='CRISPEX_CLOSE_EVENT_WINDOW', BASE=tlb, /BLOCK
		(*(*info).winids).errtlb = tlb
	END
	IF (((*(*info).feedbparams).verbosity)[3] EQ 1) THEN $
    CRISPEX_VERBOSE_GET, event, [(*(*info).paths).opath_write],labels=['Output path writeable']
END

PRO CRISPEX_SAVE_SET_IPATH, event 
; Sets the output path for all saving procedures
	WIDGET_CONTROL, event.TOP, GET_UVALUE = info
	IF (TOTAL(((*(*info).feedbparams).verbosity)[2:3]) GE 1) THEN $
    CRISPEX_VERBOSE_GET_ROUTINE, event
	thispath = DIALOG_PICKFILE(TITLE = 'CRISPEX'+(*(*info).sesparams).instance_label+': Set input path', /DIRECTORY, PATH = (*(*info).paths).ipath)
	IF (thispath EQ '') THEN RETURN ELSE (*(*info).paths).ipath = thispath
	IF ((*(*info).winids).savewintlb GT 0) THEN WIDGET_CONTROL, (*(*info).ctrlssav).path_textlab, SET_VALUE = STRTRIM((*(*info).paths).ipath,2)
	IF (event.TOP EQ (*(*info).winids).preftlb) THEN (*(*info).prefs).tmp_prefipath = (*(*info).paths).ipath
	IF (((*(*info).feedbparams).verbosity)[3] EQ 1) THEN $
    CRISPEX_VERBOSE_GET, event, [(*(*info).paths).ipath],labels=['Input path']
END

PRO CRISPEX_SAVE_SET_OPATH, event 
; Sets the output path for all saving procedures
	WIDGET_CONTROL, event.TOP, GET_UVALUE = info
	IF (TOTAL(((*(*info).feedbparams).verbosity)[2:3]) GE 1) THEN $
    CRISPEX_VERBOSE_GET_ROUTINE, event
	thispath = DIALOG_PICKFILE(TITLE = 'CRISPEX'+(*(*info).sesparams).instance_label+': Set output path', /DIRECTORY, PATH = (*(*info).paths).opath)
	IF (thispath EQ '') THEN RETURN ELSE (*(*info).paths).opath = thispath
	IF ((*(*info).winids).savewintlb GT 0) THEN WIDGET_CONTROL, (*(*info).ctrlssav).path_textlab, SET_VALUE = STRTRIM((*(*info).paths).opath,2)
	IF ((*(*info).winids).saveoptwintlb GT 0) THEN WIDGET_CONTROL, (*(*info).ctrlssav).savopt_path_textlab, SET_VALUE = STRTRIM((*(*info).paths).opath,2)
	IF (event.TOP EQ (*(*info).winids).preftlb) THEN (*(*info).prefs).tmp_prefopath = (*(*info).paths).opath
	IF (((*(*info).feedbparams).verbosity)[3] EQ 1) THEN $
    CRISPEX_VERBOSE_GET, event, [(*(*info).paths).opath],labels=['Output path']
END

PRO CRISPEX_SAVE_GET_FILENAME, event, title, standard_filename, ok_event, session_save=session_save, SNAPSHOT=snapshot
; Gets the filename for save routines
	WIDGET_CONTROL, event.TOP, GET_UVALUE = info
	IF (TOTAL(((*(*info).feedbparams).verbosity)[2:3]) GE 1) THEN $
    CRISPEX_VERBOSE_GET_ROUTINE, event
	IF ((*(*info).winids).savewintlb NE 0) THEN BEGIN
		CRISPEX_WINDOW_OK, event, 'WARNING!',$
      'You are currently already saving output. Please finish '+$
      'saving or discard the current saving procedure first, '+$
			'before starting a new saving procedure.', OK_EVENT='CRISPEX_CLOSE_EVENT_WINDOW', BASE=tlb
		(*(*info).winids).warntlb = tlb
		RETURN
	END
	fulltitle = 'CRISPEX'+(*(*info).sesparams).instance_label+': '+STRTRIM(title,2)
	base = WIDGET_BASE(TITLE = title, GROUP_LEADER = (*(*info).winids).root, TLB_FRAME_ATTR = 1, /TLB_KILL_REQUEST_EVENTS)
	disp = WIDGET_BASE(base, /COLUMN)
	message_base = WIDGET_BASE(disp, /COLUMN)
	path_base = WIDGET_BASE(message_base, /ROW)
	path_label = WIDGET_LABEL(path_base, VALUE = 'Current path:')
	(*(*info).ctrlssav).path_textlab = WIDGET_LABEL(path_base, VALUE = STRTRIM((*(*info).paths).opath,2), /DYNAMIC_RESIZE)
	filename_base = WIDGET_BASE(message_base, /ROW)
	text_label1 = WIDGET_LABEL(filename_base, VALUE = 'Filename (w/o extension):')
	(*(*info).savparams).filename_text = WIDGET_TEXT(filename_base, VALUE = standard_filename,  /EDITABLE, XSIZE = 40)
	WIDGET_CONTROL, (*(*info).savparams).filename_text, SET_TEXT_SELECT = [0,STRLEN(standard_filename)]
	button_base = WIDGET_BASE(disp,COLUMN=3,/GRID_LAYOUT,/ALIGN_CENTER)
	IF KEYWORD_SET(SESSION_SAVE) THEN change_path_but = WIDGET_BUTTON(button_base, VALUE = 'Change path', EVENT_PRO = 'CRISPEX_SAVE_SET_OPATH') ELSE $
		options_but = WIDGET_BUTTON(button_base, VALUE = 'Options...', EVENT_PRO = 'CRISPEX_SAVE_OPTIONS')
	no_but = WIDGET_BUTTON(button_base, VALUE = 'Cancel', EVENT_PRO = 'CRISPEX_CLOSE_EVENT_WINDOW')
	yes_but = WIDGET_BUTTON(button_base, VALUE = 'OK' , EVENT_PRO = ok_event)
	WIDGET_CONTROL, base, /REALIZE, TLB_SET_XOFFSET = 500, TLB_SET_YOFFSET = 500
	WIDGET_CONTROL, base, SET_UVALUE = info
	XMANAGER, 'CRISPEX', base, /NO_BLOCK
	(*(*info).winids).savewintlb = base
	IF (((*(*info).feedbparams).verbosity)[3] EQ 1) THEN $
    CRISPEX_VERBOSE_GET, event, [(*(*info).winids).savewintlb],labels=['savewintlb']
END

PRO CRISPEX_SAVE_CHECK_FILENAME, event, extension, ok_event, midtension=midtension
; Checks the save filename for validity and overwrite problems
	WIDGET_CONTROL, event.TOP, GET_UVALUE = info
	IF (TOTAL(((*(*info).feedbparams).verbosity)[2:3]) GE 1) THEN $
    CRISPEX_VERBOSE_GET_ROUTINE, event
	csesfiles = FILE_SEARCH((*(*info).paths).opath+"*"+extension, COUNT = csesfilecount)
	WIDGET_CONTROL, (*(*info).savparams).filename_text, GET_VALUE = session_filename
	IF (N_ELEMENTS(midtension) GT 0) THEN midtension = midtension ELSE midtension = ''
	full_session_filename = session_filename+midtension+'.'+extension
	compressedfilename = STRCOMPRESS(full_session_filename, /REMOVE_ALL)
	existing = WHERE(STRPOS(csesfiles,(*(*info).paths).opath+full_session_filename) EQ 0, count)
	IF (count LE 0) AND (session_filename NE '') AND (compressedfilename EQ full_session_filename)  AND ((*(*info).paths).opath_write EQ 1) THEN CRISPEX_SAVE_CONTINUE, event, session_filename $
	ELSE IF (count LE 0) AND (session_filename EQ '') OR (compressedfilename NE full_session_filename) THEN BEGIN
		CRISPEX_WINDOW_OK, event,'ERROR!',$
      'Invalid filename. Please enter a filename of '+$
      'at least one character and without any white spaces.',$
			OK_EVENT='CRISPEX_CLOSE_EVENT_WINDOW', BASE=tlb
		(*(*info).winids).errtlb = tlb
	ENDIF ELSE IF ((*(*info).paths).opath_write EQ 0) THEN CRISPEX_SAVE_CHECK_PATH_WRITE, event $
	ELSE CRISPEX_SAVE_WARNING_YESNO, event,'The file already exists. Do you wish to','continue and overwrite this file?', OK_EVENT=ok_event, CANCEL_EVENT='CRISPEX_CLOSE_EVENT_WINDOW'
END

PRO CRISPEX_SAVE_CONTINUE, event, session_filename
; Selects the continuation of saving session, JPEG or MPEG
	WIDGET_CONTROL, event.TOP, GET_UVALUE = info
	IF (TOTAL(((*(*info).feedbparams).verbosity)[2:3]) GE 1) THEN $
    CRISPEX_VERBOSE_GET_ROUTINE, event
	IF ((*(*info).savparams).savpro EQ 'SESSION') THEN CRISPEX_SESSION_SAVE, event, session_filename
	IF ((STRPOS((*(*info).savparams).savpro,'FRAMES') NE -1) OR STRCMP((*(*info).savparams).savpro,'MPEG')) THEN CRISPEX_SAVE_FRAMES_SAVE, event, session_filename ELSE $
		IF (STRPOS((*(*info).savparams).savpro,'LINESCAN') NE -1) THEN CRISPEX_SAVE_LINESCAN_SAVE, event, session_filename
END

PRO CRISPEX_SAVE_WARNING_YESNO, event, warningmessage1, warningmessage2, warningmessage3, ok_event=ok_event, cancel_event=cancel_event
; Creates the loopslice/slab warning window
	WIDGET_CONTROL, event.TOP, GET_UVALUE = info
	IF (TOTAL(((*(*info).feedbparams).verbosity)[2:3]) GE 1) THEN $
    CRISPEX_VERBOSE_GET_ROUTINE, event
	base = WIDGET_BASE(TITLE = 'CRISPEX'+(*(*info).sesparams).instance_label+': WARNING!', GROUP_LEADER = (*(*info).winids).root, TLB_FRAME_ATTR = 1, /TLB_KILL_REQUEST_EVENTS)
	disp = WIDGET_BASE(base, /COLUMN)
	message_base = WIDGET_BASE(disp, /COLUMN)
	IF (N_ELEMENTS(warningmessage1) GT 0) THEN text_label1 = WIDGET_LABEL(message_base, VALUE = warningmessage1)
	IF (N_ELEMENTS(warningmessage2) GT 0) THEN text_label2 = WIDGET_LABEL(message_base, VALUE = warningmessage2)
	IF (N_ELEMENTS(warningmessage3) GT 0) THEN text_label3 = WIDGET_LABEL(message_base, VALUE = warningmessage3)
	button_base = WIDGET_BASE(disp,/ROW,/ALIGN_CENTER)
	no_but = WIDGET_BUTTON(button_base, VALUE = 'No, cancel', EVENT_PRO = cancel_event)
	yes_but = WIDGET_BUTTON(button_base, VALUE = 'Yes, continue' , EVENT_PRO = ok_event)
	WIDGET_CONTROL, base, /REALIZE, TLB_SET_XOFFSET = 500, TLB_SET_YOFFSET = 500
	WIDGET_CONTROL, base, SET_UVALUE = info
	XMANAGER, 'CRISPEX', base, /NO_BLOCK
END

;========================= OUTPUT SAVE PROCEDURES
PRO CRISPEX_SAVE_JPEG_SNAPSHOT, event
; Handles the saving of a single main image (as in display) as JPEG
	WIDGET_CONTROL, event.TOP, GET_UVALUE = info
	IF (TOTAL(((*(*info).feedbparams).verbosity)[2:3]) GE 1) THEN $
    CRISPEX_VERBOSE_GET_ROUTINE, event
	(*(*info).savparams).savpro = 'JPEG_FRAMES'
	(*(*info).savparams).snapshot = 1
	CRISPEX_SAVE_FRAMES, event
END	

PRO CRISPEX_SAVE_JPEG_ALL_FRAMES, event
; Handles the saving of a series of main images (as in display) as JPEG
	WIDGET_CONTROL, event.TOP, GET_UVALUE = info
	IF (TOTAL(((*(*info).feedbparams).verbosity)[2:3]) GE 1) THEN $
    CRISPEX_VERBOSE_GET_ROUTINE, event
	(*(*info).savparams).savpro = 'JPEG_FRAMES'
	(*(*info).savparams).snapshot = 0
	CRISPEX_SAVE_FRAMES, event
END

PRO CRISPEX_SAVE_JPEG_LINESCAN, event
; Handles the saving of a single main image (as in display) as JPEG
	WIDGET_CONTROL, event.TOP, GET_UVALUE = info
	IF (TOTAL(((*(*info).feedbparams).verbosity)[2:3]) GE 1) THEN $
    CRISPEX_VERBOSE_GET_ROUTINE, event
	(*(*info).savparams).savpro = 'JPEG_LINESCAN'
	CRISPEX_SAVE_LINESCAN, event
END	

PRO CRISPEX_SAVE_PNG_SNAPSHOT, event
; Handles the saving of a single main image (as in display) as JPEG
	WIDGET_CONTROL, event.TOP, GET_UVALUE = info
	IF (TOTAL(((*(*info).feedbparams).verbosity)[2:3]) GE 1) THEN $
    CRISPEX_VERBOSE_GET_ROUTINE, event
	(*(*info).savparams).savpro = 'PNG_FRAMES'
	(*(*info).savparams).snapshot = 1
	CRISPEX_SAVE_FRAMES, event
END	

PRO CRISPEX_SAVE_PNG_ALL_FRAMES, event
; Handles the saving of a series of main images (as in display) as JPEG
	WIDGET_CONTROL, event.TOP, GET_UVALUE = info
	IF (TOTAL(((*(*info).feedbparams).verbosity)[2:3]) GE 1) THEN $
    CRISPEX_VERBOSE_GET_ROUTINE, event
	(*(*info).savparams).savpro = 'PNG_FRAMES'
	(*(*info).savparams).snapshot = 0
	CRISPEX_SAVE_FRAMES, event
END

PRO CRISPEX_SAVE_PNG_LINESCAN, event
; Handles the saving of a single main image (as in display) as JPEG
	WIDGET_CONTROL, event.TOP, GET_UVALUE = info
	IF (TOTAL(((*(*info).feedbparams).verbosity)[2:3]) GE 1) THEN $
    CRISPEX_VERBOSE_GET_ROUTINE, event
	(*(*info).savparams).savpro = 'PNG_LINESCAN'
	CRISPEX_SAVE_LINESCAN, event
END	

PRO CRISPEX_SAVE_CHECK, event
; Checks the jpeg series save filename for validity and overwrite problems
	WIDGET_CONTROL, event.TOP, GET_UVALUE = info
	IF (TOTAL(((*(*info).feedbparams).verbosity)[2:3]) GE 1) THEN $
    CRISPEX_VERBOSE_GET_ROUTINE, event
	IF ((*(*info).savparams).savpro EQ 'MPEG') THEN BEGIN
		extension = 'mpg'	&	midtension = ''
	ENDIF ELSE IF (STRPOS((*(*info).savparams).savpro,'FRAMES') NE -1) THEN BEGIN		; Check whether saving procedure contains 'FRAMES' (test = 1) or 'LINESCAN' (test = 0)
		IF (*(*info).savparams).snapshot THEN midtension = '' ELSE BEGIN
			nlpos = CEIL(ALOG10((*(*info).dataparams).nlp))
			lp_id = 'lp'+STRING((*(*info).dataparams).lp,FORMAT='(I0'+STRTRIM(nlpos,2)+')')
			midtension = '_'+lp_id
		ENDELSE
		IF ((*(*info).savparams).savpro EQ 'JPEG_FRAMES') THEN extension = 'jpg'
		IF ((*(*info).savparams).savpro EQ 'PNG_FRAMES') THEN extension = 'png'
	ENDIF ELSE BEGIN
		ntpos = CEIL(ALOG10((*(*info).dataparams).nt))
		nlpos = CEIL(ALOG10((*(*info).dataparams).nlp))
		t_id = 't'+STRING((*(*info).dispparams).t,FORMAT='(I0'+STRTRIM(ntpos,2)+')')
		lp_id = 'lp'+STRING((*(*info).dataparams).lp,FORMAT='(I0'+STRTRIM(nlpos,2)+')')
		midtension = '_'+t_id+'_'+lp_id
		IF ((*(*info).savparams).savpro EQ 'JPEG_LINESCAN') THEN extension = 'jpg'
		IF ((*(*info).savparams).savpro EQ 'PNG_LINESCAN') THEN extension = 'png'
	ENDELSE
	CRISPEX_SAVE_CHECK_FILENAME, event, extension, 'CRISPEX_SAVE_OVER', midtension = midtension
END

PRO CRISPEX_SAVE_OVER, event
; Handles the overwriting and activates the subsequent saving of the jpeg frames
	WIDGET_CONTROL, event.TOP, GET_UVALUE = info
	IF (TOTAL(((*(*info).feedbparams).verbosity)[2:3]) GE 1) THEN $
    CRISPEX_VERBOSE_GET_ROUTINE, event
	WIDGET_CONTROL, (*(*info).savparams).filename_text, GET_VALUE = filename
	IF ((*(*info).savparams).savpro EQ 'MPEG') THEN CRISPEX_SAVE_MPEG_SAVE, event, filename ELSE $
		IF (STRPOS((*(*info).savparams).savpro,'FRAMES') NE -1) THEN CRISPEX_SAVE_FRAMES_SAVE, event, filename ELSE CRISPEX_SAVE_LINESCAN_SAVE, event, filename
	IF ((*(*info).winids).saveoptwintlb GT 0) THEN BEGIN
		WIDGET_CONTROL, (*(*info).winids).saveoptwintlb,/DESTROY
		(*(*info).winids).saveoptwintlb = 0
	ENDIF
	WIDGET_CONTROL, event.TOP, /DESTROY
END

PRO CRISPEX_SAVE_FRAMES, event
; Handles the saving of a series of main images (as in display) as JPEG
	WIDGET_CONTROL, event.TOP, GET_UVALUE = info
	IF (TOTAL(((*(*info).feedbparams).verbosity)[2:3]) GE 1) THEN $
    CRISPEX_VERBOSE_GET_ROUTINE, event
	CRISPEX_SAVE_CHECK_PATH_WRITE, event
	label = ['series','snapshot']
	IF (*(*info).savparams).snapshot THEN BEGIN
		ntpos = CEIL(ALOG10((*(*info).dataparams).nt))
		nlpos = CEIL(ALOG10((*(*info).dataparams).nlp))
		t_id = 't'+STRING((*(*info).dispparams).t,FORMAT='(I0'+STRTRIM(ntpos,2)+')')
		lp_id = 'lp'+STRING((*(*info).dataparams).lp,FORMAT='(I0'+STRTRIM(nlpos,2)+')')
		CRISPEX_SAVE_CHECK_PATH_WRITE, event
		CRISPEX_SAVE_DETERMINE_FILENAME, event, outfilename=standardfilename, import_id=lp_id+'_'+t_id
	ENDIF ELSE CRISPEX_SAVE_DETERMINE_FILENAME, event, outfilename=standardfilename
	IF ((*(*info).savparams).savpro EQ 'JPEG_FRAMES') THEN CRISPEX_SAVE_GET_FILENAME, event, 'Save JPEG '+label[KEYWORD_SET(SNAPSHOT)], standardfilename, 'CRISPEX_SAVE_CHECK'
	IF ((*(*info).savparams).savpro EQ 'PNG_FRAMES') THEN CRISPEX_SAVE_GET_FILENAME, event, 'Save PNG '+label[KEYWORD_SET(SNAPSHOT)], standardfilename, 'CRISPEX_SAVE_CHECK'
END

PRO CRISPEX_SAVE_FRAMES_SAVE, event, supplied_filename
; Handles the saving of a series (between temporal boundaries) of main images
; (as in display) as JPEG 
  WIDGET_CONTROL, event.TOP, GET_UVALUE = info
	IF (TOTAL(((*(*info).feedbparams).verbosity)[2:3]) GE 1) THEN $
    CRISPEX_VERBOSE_GET_ROUTINE, event
	ntpos = CEIL(ALOG10((*(*info).dataparams).nt))
	nlpos = CEIL(ALOG10((*(*info).dataparams).nlp))
	t_before = (*(*info).dispparams).t
	IF (*(*info).savparams).snapshot THEN BEGIN
		t_low = (*(*info).dispparams).t		&	t_upp = t_low
	ENDIF ELSE BEGIN
		t_low = (*(*info).dispparams).t_low	&	t_upp = (*(*info).dispparams).t_upp 
		lp_id = 'lp'+STRING((*(*info).dataparams).lp,FORMAT='(I0'+STRTRIM(nlpos,2)+')')
	ENDELSE
	WIDGET_CONTROL, /HOURGLASS
	IF STRCMP((*(*info).savparams).savpro,'MPEG') THEN $
    mpegid = MPEG_OPEN([(*(*info).winsizes).xywinx, $
      (*(*info).winsizes).xywiny], QUALITY = 100, BITRATE = 1E8)
  draw_mask = ((*(*info).overlayswitch).mask AND $
              ((*(*info).overlayswitch).maskim)[0])
	FOR i = t_low, t_upp DO BEGIN
		(*(*info).dispparams).t = i
		CRISPEX_UPDATE_T, event
		IF ((*(*info).savparams).overlays_incl OR draw_mask) THEN BEGIN
			CRISPEX_DRAW_XY, event, $
        NO_CURSOR=ABS((*(*info).savparams).overlays_curs-1), $
        NO_NUMBER=ABS((*(*info).savparams).overlays_num-1), $
        THICK=(*(*info).savparams).overlays_thick, $
				NO_ENDPOINTS=ABS((*(*info).savparams).overlays_pts-1), $
        SYMSIZE=(*(*info).savparams).overlays_symsize, $
        ASECBAR=(*(*info).savparams).overlays_asecbar
			image=TVRD(/TRUE)
		ENDIF ELSE BEGIN
      CRISPEX_DRAW_SCALING, event, tmp_image, /MAIN
      s = SIZE(tmp_image)
      image = BYTARR(3, s[1], s[2])
      image[0,*,*] = (REFORM((*(*info).plotparams).rgb_main[*,0]))[tmp_image]
      image[1,*,*] = (REFORM((*(*info).plotparams).rgb_main[*,1]))[tmp_image]
      image[2,*,*] = (REFORM((*(*info).plotparams).rgb_main[*,2]))[tmp_image]
    ENDELSE
		IF (*(*info).savparams).snapshot THEN midtension = '' ELSE BEGIN
			t_id = 't'+STRING((*(*info).dispparams).t,FORMAT='(I0'+STRTRIM(ntpos,2)+')')
			midtension = '_'+lp_id+'_'+t_id
		ENDELSE
		IF STRCMP((*(*info).savparams).savpro,'MPEG') THEN BEGIN
			imdisp = REVERSE(image,3)
			MPEG_PUT,mpegid, IMAGE=imdisp, FRAME=i-(*(*info).dispparams).t_low, /COLOR
		ENDIF ELSE IF STRCMP((*(*info).savparams).savpro,'JPEG_FRAMES') THEN BEGIN
			filename = (*(*info).paths).opath+supplied_filename+midtension+'.jpg'
			WRITE_JPEG, filename, image, TRUE=1, QUALITY=75				
			PRINT, 'Written: '+filename
    ENDIF ELSE IF STRCMP((*(*info).savparams).savpro,'PNG_FRAMES') THEN BEGIN
			filename = (*(*info).paths).opath+supplied_filename+midtension+'.png'
			WRITE_PNG,filename,image
			PRINT, 'Written: '+filename
		ENDIF
	ENDFOR
	IF STRCMP((*(*info).savparams).savpro,'MPEG') THEN BEGIN
		MPEG_SAVE, mpegid, FILENAME = (*(*info).paths).opath+supplied_filename+'.mpg'
		MPEG_CLOSE, mpegid
		PRINT, 'Written: '+(*(*info).paths).opath+supplied_filename+'.mpg'
	ENDIF
	(*(*info).dispparams).t = t_before
	CRISPEX_UPDATE_T, event
	IF (*(*info).savparams).overlays_incl THEN CRISPEX_DRAW_XY, event
	WIDGET_CONTROL, (*(*info).winids).savewintlb, /DESTROY
	(*(*info).winids).savewintlb = 0
END

PRO CRISPEX_SAVE_LINESCAN, event
; Handles the saving of a series of main images (as in display) as JPEG
	WIDGET_CONTROL, event.TOP, GET_UVALUE = info
	IF (TOTAL(((*(*info).feedbparams).verbosity)[2:3]) GE 1) THEN $
    CRISPEX_VERBOSE_GET_ROUTINE, event
	CRISPEX_SAVE_CHECK_PATH_WRITE, event
	CRISPEX_SAVE_DETERMINE_FILENAME, event, outfilename=standardfilename
	IF ((*(*info).savparams).savpro EQ 'JPEG_LINESCAN') THEN CRISPEX_SAVE_GET_FILENAME, event, 'Save JPEG line scan', standardfilename, 'CRISPEX_SAVE_CHECK'
	IF ((*(*info).savparams).savpro EQ 'PNG_LINESCAN') THEN CRISPEX_SAVE_GET_FILENAME, event, 'Save PNG line scan', standardfilename, 'CRISPEX_SAVE_CHECK'
END

PRO CRISPEX_SAVE_LINESCAN_SAVE, event, supplied_filename
; Handles the saving of a series (between temporal boundaries) of main images (as in display) as JPEG
	WIDGET_CONTROL, event.TOP, GET_UVALUE = info
	IF (TOTAL(((*(*info).feedbparams).verbosity)[2:3]) GE 1) THEN $
    CRISPEX_VERBOSE_GET_ROUTINE, event
	nlpos = CEIL(ALOG10((*(*info).dataparams).nlp))
	ntpos = CEIL(ALOG10((*(*info).dataparams).nt))
	lp_before = (*(*info).dataparams).lp
	WIDGET_CONTROL, /HOURGLASS
	t_id = 't'+STRING((*(*info).dispparams).t,FORMAT='(I0'+STRTRIM(ntpos,2)+')')
  draw_mask = ((*(*info).overlayswitch).mask AND $
              ((*(*info).overlayswitch).maskim)[0])
  FOR d=0,(*(*info).intparams).ndisp_diagnostics-1 DO BEGIN
    ; Only loop over selected diagnostics
    dd_sel = (*(*(*info).intparams).wheredispdiag)[d] 
    lp_low = (*(*info).intparams).diag_start[dd_sel] + $
              (*(*info).dispparams).lp_low_tmp[dd_sel]
    lp_upp = (*(*info).intparams).diag_start[dd_sel] + $
              (*(*info).dispparams).lp_upp_tmp[dd_sel]
  	FOR i=lp_low,lp_upp DO BEGIN
  		(*(*info).dataparams).lp = i
  		CRISPEX_UPDATE_T, event
  		IF ((*(*info).savparams).overlays_incl OR draw_mask) THEN BEGIN
  			CRISPEX_DRAW_XY, event, $
          NO_CURSOR=ABS((*(*info).savparams).overlays_curs-1), $
          NO_NUMBER=ABS((*(*info).savparams).overlays_num-1), $
          THICK=(*(*info).savparams).overlays_thick, $
  				NO_ENDPOINTS=ABS((*(*info).savparams).overlays_pts-1), $
          SYMSIZE=(*(*info).savparams).overlays_symsize, $
          ASECBAR=(*(*info).savparams).overlays_asecbar
  			image=TVRD(/TRUE)
  		ENDIF ELSE BEGIN
        CRISPEX_DRAW_SCALING, event, tmp_image, /MAIN
        s = SIZE(tmp_image)
        image = BYTARR(3, s[1], s[2])
        image[0,*,*] = (REFORM((*(*info).plotparams).rgb_main[*,0]))[tmp_image]
        image[1,*,*] = (REFORM((*(*info).plotparams).rgb_main[*,1]))[tmp_image]
        image[2,*,*] = (REFORM((*(*info).plotparams).rgb_main[*,2]))[tmp_image]
      ENDELSE
  		IF (*(*info).savparams).linescan_ls THEN BEGIN
  			CRISPEX_UPDATE_LP, event
        CRISPEX_DRAW_SPECTRAL_MAIN, event, /LS_ONLY
  			lsimage = TVRD(/TRUE)
  		ENDIF
  		lp_id = 'lp'+STRING((*(*info).dataparams).lp,FORMAT='(I0'+STRTRIM(nlpos,2)+')')
  		IF ((*(*info).savparams).savpro EQ 'JPEG_LINESCAN') THEN BEGIN
  			filename = (*(*info).paths).opath+supplied_filename+'_'+t_id+'_'+lp_id+'.jpg'
  			WRITE_JPEG, filename, image, TRUE=1, QUALITY=75
  			PRINT, 'Written: '+filename
  			IF (*(*info).savparams).linescan_ls THEN BEGIN
  				lsfilename = (*(*info).paths).opath+supplied_filename+'_detspect_'+$
            t_id+'_'+lp_id+'.jpg'
  				WRITE_JPEG, lsfilename, lsimage, QUALITY=75
  				PRINT, 'Written: '+lsfilename
  			ENDIF
  		ENDIF
  		IF ((*(*info).savparams).savpro EQ 'PNG_LINESCAN') THEN BEGIN
  			filename = (*(*info).paths).opath+supplied_filename+'_'+t_id+'_'+lp_id+'.png'
  			WRITE_PNG,filename,image
  			PRINT, 'Written: '+filename
  			IF (*(*info).savparams).linescan_ls THEN BEGIN
  				lsfilename = (*(*info).paths).opath+supplied_filename+'_detspect_'+$
            t_id+'_'+lp_id+'.png'
  				WRITE_PNG,lsfilename,lsimage
  				PRINT, 'Written: '+lsfilename
  			ENDIF
  		ENDIF
  	ENDFOR
  ENDFOR
	(*(*info).dataparams).lp = lp_before
	CRISPEX_UPDATE_T, event
	IF (*(*info).savparams).overlays_incl THEN CRISPEX_DRAW_XY, event
	IF (*(*info).savparams).linescan_ls THEN BEGIN
		CRISPEX_UPDATE_LP, event
    CRISPEX_DRAW_SPECTRAL_MAIN, event, /LS_ONLY
	ENDIF
	WIDGET_CONTROL, (*(*info).winids).savewintlb, /DESTROY
	(*(*info).winids).savewintlb = 0
END

PRO CRISPEX_SAVE_MPEG, event
; Handles the saving of a series of main images (as in display) as JPEG
	WIDGET_CONTROL, event.TOP, GET_UVALUE = info
	IF (TOTAL(((*(*info).feedbparams).verbosity)[2:3]) GE 1) THEN $
    CRISPEX_VERBOSE_GET_ROUTINE, event
	(*(*info).savparams).savpro = 'MPEG'
	CRISPEX_SAVE_CHECK_PATH_WRITE, event
	CRISPEX_SAVE_DETERMINE_FILENAME, event, outfilename=standardfilename, import_id='lp'+STRTRIM(LONG((*(*info).dataparams).lp),2)
	CRISPEX_SAVE_GET_FILENAME, event, 'Save MPEG movie', standardfilename, 'CRISPEX_SAVE_CHECK'
END

PRO CRISPEX_SAVE_OPTIONS, event
; Handles the extra saving options for save as PNG/JPEG/MPEG
	WIDGET_CONTROL, event.TOP, GET_UVALUE = info
	IF (TOTAL(((*(*info).feedbparams).verbosity)[2:3]) GE 1) THEN $
    CRISPEX_VERBOSE_GET_ROUTINE, event
	base = WIDGET_BASE(TITLE='CRISPEX'+(*(*info).sesparams).instance_label+$
    ': Saving options', GROUP_LEADER=(*(*info).winids).root, TLB_FRAME_ATTR=1, $
    /TLB_KILL_REQUEST_EVENTS)
	disp = WIDGET_BASE(base, /COLUMN)
	path_base = WIDGET_BASE(disp, /COLUMN)
	path_label = WIDGET_LABEL(path_base, VALUE='Path options', /ALIGN_LEFT)
	curpath_base = WIDGET_BASE(path_base, /ROW)
	curpath_label = WIDGET_LABEL(curpath_base, VALUE='Current path:')
	(*(*info).ctrlssav).savopt_path_textlab = WIDGET_LABEL(curpath_base, $
    VALUE=STRTRIM((*(*info).paths).opath,2), /DYNAMIC_RESIZE)
	pathbut_base = WIDGET_BASE(path_base, COLUMN=1,/GRID_LAYOUT,/ALIGN_LEFT)
	change_path_but = WIDGET_BUTTON(pathbut_base, VALUE='Change path', $
    EVENT_PRO='CRISPEX_SAVE_SET_OPATH')
  divider1 = CRISPEX_WIDGET_DIVIDER(disp)
	overlays_base = WIDGET_BASE(disp, /COLUMN)
	overlays_label = WIDGET_LABEL(overlays_base, VALUE='Overlays options', $
    /ALIGN_LEFT)
	overlays_but_base = WIDGET_BASE(overlays_base, /ROW)
	overlays_buts_base = WIDGET_BASE(overlays_but_base, /COLUMN, /NONEXCLUSIVE)
	overlays_incl_but = WIDGET_BUTTON(overlays_buts_base, $
    VALUE='Include overlays', EVENT_PRO='CRISPEX_SAVE_OPTIONS_OVERLAYS_INCLUDE')
	overlays_subbuts_base = WIDGET_BASE(overlays_but_base, /COLUMN, /NONEXCLUSIVE)
	WIDGET_CONTROL, overlays_incl_but, SET_BUTTON=(*(*info).savparams).overlays_incl
	(*(*info).ctrlssav).overlays_num_but = WIDGET_BUTTON(overlays_subbuts_base, $
    VALUE='Number overlays', EVENT_PRO='CRISPEX_SAVE_OPTIONS_OVERLAYS_NUMBER', $
    SENSITIVE=(*(*info).savparams).overlays_incl)
	WIDGET_CONTROL, (*(*info).ctrlssav).overlays_num_but, $
    SET_BUTTON=(*(*info).savparams).overlays_num
	(*(*info).ctrlssav).overlays_curs_but = WIDGET_BUTTON(overlays_subbuts_base, $
    VALUE='Include cursor', EVENT_PRO='CRISPEX_SAVE_OPTIONS_OVERLAYS_CURSOR', $
    SENSITIVE=(*(*info).savparams).overlays_incl)
	WIDGET_CONTROL, (*(*info).ctrlssav).overlays_curs_but, $
    SET_BUTTON=(*(*info).savparams).overlays_curs
	(*(*info).ctrlssav).overlays_pts_but = WIDGET_BUTTON(overlays_subbuts_base, $
    VALUE='Include endpoints', SENSITIVE=(*(*info).savparams).overlays_incl, $
    EVENT_PRO='CRISPEX_SAVE_OPTIONS_OVERLAYS_ENDPOINTS')
	WIDGET_CONTROL, (*(*info).ctrlssav).overlays_pts_but, $
    SET_BUTTON=(*(*info).savparams).overlays_pts
	(*(*info).ctrlssav).overlays_asecbar_but = $
    WIDGET_BUTTON(overlays_subbuts_base, VALUE='Add arcseconds bar', $
    EVENT_PRO='CRISPEX_SAVE_OPTIONS_OVERLAYS_ASECBAR', $
    SENSITIVE=(*(*info).savparams).overlays_incl)
	WIDGET_CONTROL, (*(*info).ctrlssav).overlays_asecbar_but, $
    SET_BUTTON=(*(*info).savparams).overlays_asecbar
	overlays_combo_base = WIDGET_BASE(overlays_base, /COLUMN)
	overlays_thick_base = WIDGET_BASE(overlays_combo_base, /ROW)
	(*(*info).ctrlssav).overlays_thick_slider = $
    WIDGET_SLIDER(overlays_thick_base, TITLE='Overlay thickness', MIN=1, $
    MAX=8, VALUE=(*(*info).savparams).overlays_thick, $
		EVENT_PRO='CRISPEX_SAVE_OPTIONS_OVERLAYS_THICK', $
    SENSITIVE=(*(*info).savparams).overlays_incl, /DRAG)
	(*(*info).ctrlssav).overlays_symsize_slider = $
    WIDGET_SLIDER(overlays_thick_base, TITLE='Overlay symbol size', MIN=1,$
    MAX=8, VALUE=(*(*info).savparams).overlays_symsize, $
		EVENT_PRO='CRISPEX_SAVE_OPTIONS_OVERLAYS_SYMSIZE', $
    SENSITIVE=(*(*info).savparams).overlays_incl, /DRAG)
	(*(*info).ctrlssav).overlays_asecbar_slider = $
    WIDGET_SLIDER(overlays_base, TITLE='Arcseconds bar length', MIN=1, $
    MAX=8, VALUE=(*(*info).savparams).overlays_asecbar_length, $
		EVENT_PRO='CRISPEX_SAVE_OPTIONS_OVERLAYS_ASECBAR_LENGTH', $
    SENSITIVE=((*(*info).savparams).overlays_incl AND $
               (*(*info).savparams).overlays_asecbar), /DRAG)
  divider2 = CRISPEX_WIDGET_DIVIDER(disp)
	linescan_base = WIDGET_BASE(disp,/COLUMN)
	linescan_label = WIDGET_LABEL(linescan_base, VALUE='Linescan options', $
    /ALIGN_LEFT)
	linescan_but_base = WIDGET_BASE(linescan_base, /NONEXCLUSIVE)
	linescan_incl_ls_but = WIDGET_BUTTON(linescan_but_base, $
    VALUE='Save detailed spectrum', $
    EVENT_PRO='CRISPEX_SAVE_OPTIONS_INCLUDE_DETSPECT', $
		SENSITIVE=(((*(*info).dataparams).nlp GT 1) AND $
    (((*(*info).savparams).savpro EQ 'JPEG_LINESCAN') OR $
    ((*(*info).savparams).savpro EQ 'PNG_LINESCAN'))))
	WIDGET_CONTROL, linescan_incl_ls_but, SET_BUTTON=(*(*info).savparams).linescan_ls
  divider2 = CRISPEX_WIDGET_DIVIDER(disp)
	button_base = WIDGET_BASE(disp,COLUMN=1,/GRID_LAYOUT,/ALIGN_CENTER)
	ok_but = WIDGET_BUTTON(button_base, VALUE = '   OK   ', $
    EVENT_PRO='CRISPEX_CLOSE_EVENT_WINDOW')
	WIDGET_CONTROL, base, /REALIZE, $
    TLB_SET_XOFFSET=(*(*info).winsizes).spxoffset, TLB_SET_YOFFSET=0, $
    /TLB_KILL_REQUEST_EVENTS
	WIDGET_CONTROL, base, SET_UVALUE = info
	XMANAGER, 'CRISPEX', base, /NO_BLOCK
	(*(*info).winids).saveoptwintlb = base
	IF (((*(*info).feedbparams).verbosity)[3] EQ 1) THEN $
    CRISPEX_VERBOSE_GET, event, [(*(*info).winids).saveoptwintlb],$
    labels=['saveoptwintlb']
END

PRO CRISPEX_SAVE_OPTIONS_OVERLAYS_INCLUDE, event
; Handles the extra saving options for save as PNG/JPEG/MPEG
	WIDGET_CONTROL, event.TOP, GET_UVALUE = info
	IF (TOTAL(((*(*info).feedbparams).verbosity)[2:3]) GE 1) THEN $
    CRISPEX_VERBOSE_GET_ROUTINE, event
	(*(*info).savparams).overlays_incl = event.SELECT
	WIDGET_CONTROL, (*(*info).ctrlssav).overlays_num_but, SENSITIVE = (*(*info).savparams).overlays_incl
	WIDGET_CONTROL, (*(*info).ctrlssav).overlays_curs_but, SENSITIVE = (*(*info).savparams).overlays_incl
	WIDGET_CONTROL, (*(*info).ctrlssav).overlays_pts_but, SENSITIVE = (*(*info).savparams).overlays_incl
	WIDGET_CONTROL, (*(*info).ctrlssav).overlays_asecbar_but, SENSITIVE = (*(*info).savparams).overlays_incl
	WIDGET_CONTROL, (*(*info).ctrlssav).overlays_thick_slider, SENSITIVE = (*(*info).savparams).overlays_incl
	WIDGET_CONTROL, (*(*info).ctrlssav).overlays_symsize_slider, SENSITIVE = (*(*info).savparams).overlays_incl
	CRISPEX_SAVE_OPTIONS_OVERLAYS_INCLUDE_UPDATE_DISPLAY, event
	IF (((*(*info).feedbparams).verbosity)[3] EQ 1) THEN $
    CRISPEX_VERBOSE_GET, event, [(*(*info).savparams).overlays_incl],labels=['Include overlays']
END

PRO CRISPEX_SAVE_OPTIONS_OVERLAYS_INCLUDE_UPDATE_DISPLAY, event
; Handles the extra saving options for save as PNG/JPEG/MPEG
	WIDGET_CONTROL, event.TOP, GET_UVALUE = info
	IF (TOTAL(((*(*info).feedbparams).verbosity)[2:3]) GE 1) THEN $
    CRISPEX_VERBOSE_GET_ROUTINE, event
	IF (*(*info).savparams).overlays_incl THEN BEGIN
		CRISPEX_DRAW_XY, event, NO_CURSOR=ABS((*(*info).savparams).overlays_curs-1), NO_NUMBER=ABS((*(*info).savparams).overlays_num-1), THICK=(*(*info).savparams).overlays_thick, $
			NO_ENDPOINTS=ABS((*(*info).savparams).overlays_pts-1), SYMSIZE=(*(*info).savparams).overlays_symsize, ASECBAR=(*(*info).savparams).overlays_asecbar
	ENDIF ELSE CRISPEX_DRAW_XY, event
END

PRO CRISPEX_SAVE_OPTIONS_OVERLAYS_NUMBER, event
; Handles the extra saving options for save as PNG/JPEG/MPEG
	WIDGET_CONTROL, event.TOP, GET_UVALUE = info
	IF (TOTAL(((*(*info).feedbparams).verbosity)[2:3]) GE 1) THEN $
    CRISPEX_VERBOSE_GET_ROUTINE, event
	(*(*info).savparams).overlays_num = event.SELECT
	CRISPEX_SAVE_OPTIONS_OVERLAYS_INCLUDE_UPDATE_DISPLAY, event
	IF (((*(*info).feedbparams).verbosity)[3] EQ 1) THEN $
    CRISPEX_VERBOSE_GET, event, [(*(*info).savparams).overlays_num],labels=['Number overlays']
END

PRO CRISPEX_SAVE_OPTIONS_OVERLAYS_CURSOR, event
; Handles the extra saving options for save as PNG/JPEG/MPEG
	WIDGET_CONTROL, event.TOP, GET_UVALUE = info
	IF (TOTAL(((*(*info).feedbparams).verbosity)[2:3]) GE 1) THEN $
    CRISPEX_VERBOSE_GET_ROUTINE, event
	(*(*info).savparams).overlays_curs = event.SELECT
	CRISPEX_SAVE_OPTIONS_OVERLAYS_INCLUDE_UPDATE_DISPLAY, event
	IF (((*(*info).feedbparams).verbosity)[3] EQ 1) THEN $
    CRISPEX_VERBOSE_GET, event, [(*(*info).savparams).overlays_curs],labels=['Include cursor']
END

PRO CRISPEX_SAVE_OPTIONS_OVERLAYS_THICK, event
; Handles the extra saving options for save as PNG/JPEG/MPEG
	WIDGET_CONTROL, event.TOP, GET_UVALUE = info
	IF (TOTAL(((*(*info).feedbparams).verbosity)[2:3]) GE 1) THEN $
    CRISPEX_VERBOSE_GET_ROUTINE, event
	(*(*info).savparams).overlays_thick = event.VALUE
	CRISPEX_SAVE_OPTIONS_OVERLAYS_INCLUDE_UPDATE_DISPLAY, event
	IF (((*(*info).feedbparams).verbosity)[3] EQ 1) THEN $
    CRISPEX_VERBOSE_GET, event, [(*(*info).savparams).overlays_thick],labels=['Overlay thickness']
END

PRO CRISPEX_SAVE_OPTIONS_OVERLAYS_SYMSIZE, event
; Handles the extra saving options for save as PNG/JPEG/MPEG
	WIDGET_CONTROL, event.TOP, GET_UVALUE = info
	IF (TOTAL(((*(*info).feedbparams).verbosity)[2:3]) GE 1) THEN $
    CRISPEX_VERBOSE_GET_ROUTINE, event
	(*(*info).savparams).overlays_symsize = event.VALUE
	CRISPEX_SAVE_OPTIONS_OVERLAYS_INCLUDE_UPDATE_DISPLAY, event
	IF (((*(*info).feedbparams).verbosity)[3] EQ 1) THEN $
    CRISPEX_VERBOSE_GET, event, [(*(*info).savparams).overlays_symsize],labels=['Overlay symbol size']
END

PRO CRISPEX_SAVE_OPTIONS_OVERLAYS_ENDPOINTS, event
; Handles the extra saving options for save as PNG/JPEG/MPEG
	WIDGET_CONTROL, event.TOP, GET_UVALUE = info
	IF (TOTAL(((*(*info).feedbparams).verbosity)[2:3]) GE 1) THEN $
    CRISPEX_VERBOSE_GET_ROUTINE, event
	(*(*info).savparams).overlays_pts = event.SELECT
	CRISPEX_SAVE_OPTIONS_OVERLAYS_INCLUDE_UPDATE_DISPLAY, event
	IF (((*(*info).feedbparams).verbosity)[3] EQ 1) THEN $
    CRISPEX_VERBOSE_GET, event, [(*(*info).savparams).overlays_pts],labels=['Include endpoints']
END

PRO CRISPEX_SAVE_OPTIONS_OVERLAYS_ASECBAR, event
; Handles the extra saving options for save as PNG/JPEG/MPEG
	WIDGET_CONTROL, event.TOP, GET_UVALUE = info
	IF (TOTAL(((*(*info).feedbparams).verbosity)[2:3]) GE 1) THEN $
    CRISPEX_VERBOSE_GET_ROUTINE, event
	(*(*info).savparams).overlays_asecbar = event.SELECT
	WIDGET_CONTROL, (*(*info).ctrlssav).overlays_asecbar_slider, SENSITIVE = (*(*info).savparams).overlays_asecbar
	CRISPEX_SAVE_OPTIONS_OVERLAYS_INCLUDE_UPDATE_DISPLAY, event
	IF (((*(*info).feedbparams).verbosity)[3] EQ 1) THEN $
    CRISPEX_VERBOSE_GET, event, [(*(*info).savparams).overlays_asecbar],labels=['Add arcseconds bar']
END

PRO CRISPEX_SAVE_OPTIONS_OVERLAYS_ASECBAR_LENGTH, event
; Handles the extra saving options for save as PNG/JPEG/MPEG
	WIDGET_CONTROL, event.TOP, GET_UVALUE = info
	IF (TOTAL(((*(*info).feedbparams).verbosity)[2:3]) GE 1) THEN $
    CRISPEX_VERBOSE_GET_ROUTINE, event
	(*(*info).savparams).overlays_asecbar_length = event.VALUE
	(*(*info).savparams).overlays_asecbar_pix = $
    (*(*info).savparams).overlays_asecbar_length / $
    FLOAT((*(*info).dataparams).dx) * (*(*info).zooming).factor
	CRISPEX_SAVE_OPTIONS_OVERLAYS_INCLUDE_UPDATE_DISPLAY, event
	IF (((*(*info).feedbparams).verbosity)[3] EQ 1) THEN $
    CRISPEX_VERBOSE_GET, event, [(*(*info).savparams).overlays_asecbar_length, (*(*info).savparams).overlays_asecbar_pix],$
		labels=['Arcseconds bar length','Arcseconds bar length in pixels']
END

PRO CRISPEX_SAVE_OPTIONS_INCLUDE_DETSPECT, event
; Handles the extra saving options for save as PNG/JPEG/MPEG
	WIDGET_CONTROL, event.TOP, GET_UVALUE = info
	IF (TOTAL(((*(*info).feedbparams).verbosity)[2:3]) GE 1) THEN $
    CRISPEX_VERBOSE_GET_ROUTINE, event
	(*(*info).savparams).linescan_ls = event.SELECT
	IF (((*(*info).feedbparams).verbosity)[3] EQ 1) THEN $
    CRISPEX_VERBOSE_GET, event, [(*(*info).savparams).linescan_ls],labels=['Save detailed spectrum']
END

;========================= SLIDER CONTROL PROCEDURES
PRO CRISPEX_SLIDER_NPHI, event
; Handles the change in spectral slit length slider
	WIDGET_CONTROL, event.TOP, GET_UVALUE = info
	IF (TOTAL(((*(*info).feedbparams).verbosity)[2:3]) GE 1) THEN $
    CRISPEX_VERBOSE_GET_ROUTINE, event
	(*(*info).phiparams).nphi_set = event.VALUE
	IF (((*(*info).feedbparams).verbosity)[3] EQ 1) THEN $
    CRISPEX_VERBOSE_GET, event, [(*(*info).phiparams).nphi_set],labels=['Phi-slit length']
  CRISPEX_UPDATE_PHISLIT_COORDS, event
	CRISPEX_UPDATE_PHISLICE, event
END

PRO CRISPEX_SLIDER_PHI_ANGLE, event
; Handles the change in spectral slit angle slider
	WIDGET_CONTROL, event.TOP, GET_UVALUE = info
	IF (TOTAL(((*(*info).feedbparams).verbosity)[2:3]) GE 1) THEN $
    CRISPEX_VERBOSE_GET_ROUTINE, event
	(*(*info).phiparams).angle = event.VALUE
	IF (((*(*info).feedbparams).verbosity)[3] EQ 1) THEN $
    CRISPEX_VERBOSE_GET, event, [(*(*info).phiparams).angle],$
    labels=['Phi-slit angle']
  CRISPEX_UPDATE_PHISLIT_COORDS, event, $
    PHI_ANGLE=((*(*info).dataparams).pixelratio NE 1)
	CRISPEX_PHISLIT_DIRECTION, event
	CRISPEX_UPDATE_PHISLICE, event
END

PRO CRISPEX_SLIDER_LP, event
; Handles the change in spectral position slider
	WIDGET_CONTROL, event.TOP, GET_UVALUE = info
	IF (TOTAL(((*(*info).feedbparams).verbosity)[2:3]) GE 1) THEN $
    CRISPEX_VERBOSE_GET_ROUTINE, event
	(*(*info).dataparams).lp = event.VALUE
  WIDGET_CONTROL, (*(*info).ctrlscp).lp_blink_but, $
    SENSITIVE=((*(*info).pbparams).lp_blink NE (*(*info).dataparams).lp)
	CRISPEX_SLIDER_LP_UPDATE, event, OVERRIDE_DIAGNOSTIC=(event.DRAG EQ 0)
END

PRO CRISPEX_SLIDER_LP_DECR, event
; Handles increase of spectral position
	WIDGET_CONTROL, event.TOP, GET_UVALUE = info
	IF (TOTAL(((*(*info).feedbparams).verbosity)[2:3]) GE 1) THEN $
    CRISPEX_VERBOSE_GET_ROUTINE, event
	(*(*info).dataparams).lp -= 1L 
	IF ((*(*info).dataparams).lp LT (*(*info).dispparams).lp_low) THEN $
    (*(*info).dataparams).lp = (*(*info).dispparams).lp_upp
	CRISPEX_SLIDER_LP_UPDATE, event, /OVERRIDE_DIAGNOSTIC
END

PRO CRISPEX_SLIDER_LP_INCR, event
; Handles increase of spectral position
	WIDGET_CONTROL, event.TOP, GET_UVALUE = info
	IF (TOTAL(((*(*info).feedbparams).verbosity)[2:3]) GE 1) THEN $
    CRISPEX_VERBOSE_GET_ROUTINE, event
	(*(*info).dataparams).lp += 1L
	IF ((*(*info).dataparams).lp GT (*(*info).dispparams).lp_upp) THEN $
    (*(*info).dataparams).lp = (*(*info).dispparams).lp_low
	CRISPEX_SLIDER_LP_UPDATE, event, /OVERRIDE_DIAGNOSTIC
END

PRO CRISPEX_SLIDER_LP_REF, event
; Handles change in reference spectral position slider
	WIDGET_CONTROL, event.TOP, GET_UVALUE = info
	IF (TOTAL(((*(*info).feedbparams).verbosity)[2:3]) GE 1) THEN $
    CRISPEX_VERBOSE_GET_ROUTINE, event
	(*(*info).dataparams).lp_ref = event.VALUE
	CRISPEX_SLIDER_LP_UPDATE, event, OVERRIDE_DIAGNOSTIC=(event.DRAG EQ 0), $
    /REFERENCE
END

PRO CRISPEX_SLIDER_LP_REF_DECR, event
; Handles increase of spectral position
	WIDGET_CONTROL, event.TOP, GET_UVALUE = info
	IF (TOTAL(((*(*info).feedbparams).verbosity)[2:3]) GE 1) THEN $
    CRISPEX_VERBOSE_GET_ROUTINE, event
	(*(*info).dataparams).lp_ref -= 1L 
	IF ((*(*info).dataparams).lp_ref LT (*(*info).dispparams).lp_ref_low) THEN $
    (*(*info).dataparams).lp_ref = (*(*info).dispparams).lp_ref_upp
	CRISPEX_SLIDER_LP_UPDATE, event, /OVERRIDE_DIAGNOSTIC, /REFERENCE
END

PRO CRISPEX_SLIDER_LP_REF_INCR, event
; Handles increase of spectral position
	WIDGET_CONTROL, event.TOP, GET_UVALUE = info
	IF (TOTAL(((*(*info).feedbparams).verbosity)[2:3]) GE 1) THEN $
    CRISPEX_VERBOSE_GET_ROUTINE, event
	(*(*info).dataparams).lp_ref += 1L
	IF ((*(*info).dataparams).lp_ref GT (*(*info).dispparams).lp_ref_upp) THEN $
    (*(*info).dataparams).lp_ref = (*(*info).dispparams).lp_ref_low
	CRISPEX_SLIDER_LP_UPDATE, event, /OVERRIDE_DIAGNOSTIC, /REFERENCE
END

PRO CRISPEX_SLIDER_LP_REF_LOCK, event, UNLOCK=unlock, NO_DRAW=no_draw
; Handles (un)locking the reference reference to (from) the main spectral
; position slider
  WIDGET_CONTROL, event.TOP, GET_UVALUE = info
	IF (TOTAL(((*(*info).feedbparams).verbosity)[2:3]) GE 1) THEN $
    CRISPEX_VERBOSE_GET_ROUTINE, event
  IF KEYWORD_SET(UNLOCK) THEN BEGIN
	  (*(*info).ctrlsswitch).lp_ref_lock = 0
    WIDGET_CONTROL, (*(*info).ctrlscp).lp_ref_but, SET_BUTTON=0
  ENDIF ELSE $
	  (*(*info).ctrlsswitch).lp_ref_lock = event.SELECT
  IF (*(*info).ctrlsswitch).lp_ref_lock THEN BEGIN
	  (*(*info).dataparams).lp_ref = (*(*info).dataparams).lp
    (*(*info).intparams).lp_ref_diag_all = $
      TOTAL((*(*info).dataparams).lp_ref GE (*(*info).intparams).refdiag_start)-1
  ENDIF
	WIDGET_CONTROL, (*(*info).ctrlscp).lp_ref_slider, $
    SENSITIVE=ABS((*(*info).ctrlsswitch).lp_ref_lock-1), $
    SET_VALUE=(*(*info).dataparams).lp_ref
	IF (((*(*info).feedbparams).verbosity)[3] EQ 1) THEN $
    CRISPEX_VERBOSE_GET, event, [(*(*info).dataparams).lp, $
      (*(*info).dataparams).lp_ref], labels=['lp','lp_ref']
  IF ~KEYWORD_SET(NO_DRAW) THEN BEGIN
  	CRISPEX_UPDATE_T, event
  	CRISPEX_UPDATE_LP, event
  	CRISPEX_DRAW, event
  ENDIF
END

PRO CRISPEX_SLIDER_LP_RESTRICT_LOW, event
; Handles restricting the lower boundary of the wavelength/height range
	WIDGET_CONTROL, event.TOP, GET_UVALUE = info
	IF (TOTAL(((*(*info).feedbparams).verbosity)[2:3]) GE 1) THEN $
    CRISPEX_VERBOSE_GET_ROUTINE, event
  idx = ((*(*info).dispswitch).lp_restrict[1] EQ 1)
  CASE idx OF
    0:  BEGIN
          validx = ([0,(*(*info).intparams).lp_diag_all+1])[$
            (*(*info).dispswitch).lp_restrict_globloc[idx]]
          (*(*info).dispparams).v_dop_low[validx] = event.VALUE 
          ; Check whether slider overshot the other one
          IF ((*(*info).dispparams).v_dop_low[validx] GE $
              (*(*info).dispparams).v_dop_upp[validx]) THEN $
            (*(*info).dispparams).v_dop_upp[validx] = $
              (*(*info).dispparams).v_dop_low[validx] + $
              (*(*info).dispparams).v_dop_incr[validx]
          (*(*info).dispparams).v_dop_upp[validx] = $
            (*(*info).dispparams).v_dop_upp[validx] < $
            (*(*info).dataparams).v_dop_upp_max[validx]
          ; Set slider accordingly
          WIDGET_CONTROL, (*(*info).ctrlscp).lp_restr_slider_upp, $
            SET_VALUE=(*(*info).dispparams).v_dop_upp[validx]
        END
    1:  BEGIN 
          validx = ([0,(*(*info).intparams).lp_ref_diag_all+1])[$
            (*(*info).dispswitch).lp_restrict_globloc[idx]]
          (*(*info).dispparams).v_dop_ref_low[validx] = event.VALUE 
          ; Check whether slider overshot the other one
          IF ((*(*info).dispparams).v_dop_ref_low[validx] GE $
              (*(*info).dispparams).v_dop_ref_upp[validx]) THEN $
            (*(*info).dispparams).v_dop_ref_upp[validx] = $
              (*(*info).dispparams).v_dop_ref_low[validx] + $
              (*(*info).dispparams).v_dop_ref_incr[validx]
          (*(*info).dispparams).v_dop_ref_upp[validx] = $
            (*(*info).dispparams).v_dop_ref_upp[validx] < $
            (*(*info).dataparams).v_dop_ref_upp_max[validx]
          ; Set slider accordingly
          WIDGET_CONTROL, (*(*info).ctrlscp).lp_restr_slider_upp, $
            SET_VALUE=(*(*info).dispparams).v_dop_ref_upp[validx]
        END
  ENDCASE
  CRISPEX_SLIDER_LP_RESTRICT, event, REFERENCE=idx
END

PRO CRISPEX_SLIDER_LP_RESTRICT_UPP, event
; Handles restricting the upper boundary of the wavelength/height range
	WIDGET_CONTROL, event.TOP, GET_UVALUE = info
	IF (TOTAL(((*(*info).feedbparams).verbosity)[2:3]) GE 1) THEN $
    CRISPEX_VERBOSE_GET_ROUTINE, event
  idx = ((*(*info).dispswitch).lp_restrict[1] EQ 1)
  CASE idx OF
    0:  BEGIN
          validx = ([0,(*(*info).intparams).lp_diag_all+1])[$
            (*(*info).dispswitch).lp_restrict_globloc[idx]]
          (*(*info).dispparams).v_dop_upp[validx] = event.VALUE 
          ; Check whether slider overshot the other one
          IF ((*(*info).dispparams).v_dop_upp[validx] LE $
              (*(*info).dispparams).v_dop_low[validx]) THEN $
            (*(*info).dispparams).v_dop_low[validx] = $
              (*(*info).dispparams).v_dop_upp[validx] - $
              (*(*info).dispparams).v_dop_incr[validx]
          (*(*info).dispparams).v_dop_low[validx] = $
            (*(*info).dispparams).v_dop_low[validx] > $
            (*(*info).dataparams).v_dop_low_min[validx]
          ; Set slider accordingly
          WIDGET_CONTROL, (*(*info).ctrlscp).lp_restr_slider_low, $
            SET_VALUE=(*(*info).dispparams).v_dop_low[validx]
        END
    1:  BEGIN 
          validx = ([0,(*(*info).intparams).lp_ref_diag_all+1])[$
            (*(*info).dispswitch).lp_restrict_globloc[idx]]
          (*(*info).dispparams).v_dop_ref_upp[validx] = event.VALUE 
          ; Check whether slider overshot the other one
          IF ((*(*info).dispparams).v_dop_ref_upp[validx] LE $
              (*(*info).dispparams).v_dop_ref_low[validx]) THEN $
            (*(*info).dispparams).v_dop_ref_low[validx] = $
              (*(*info).dispparams).v_dop_ref_upp[validx] - $
              (*(*info).dispparams).v_dop_ref_incr[validx]
          (*(*info).dispparams).v_dop_ref_low[validx] = $
            (*(*info).dispparams).v_dop_ref_low[validx] > $
            (*(*info).dataparams).v_dop_ref_low_min[validx]
          ; Set slider accordingly
          WIDGET_CONTROL, (*(*info).ctrlscp).lp_restr_slider_low, $
            SET_VALUE=(*(*info).dispparams).v_dop_ref_low[validx]
        END
  ENDCASE
  CRISPEX_SLIDER_LP_RESTRICT, event
END

PRO CRISPEX_SLIDER_LP_RESTRICT, event, REFERENCE=reference, NO_DRAW=no_draw
; Handles restricting the wavelength/height range
	WIDGET_CONTROL, event.TOP, GET_UVALUE = info
	IF (TOTAL(((*(*info).feedbparams).verbosity)[2:3]) GE 1) THEN $
    CRISPEX_VERBOSE_GET_ROUTINE, event
  IF ((*(*info).dispswitch).lp_restrict[0] AND ~KEYWORD_SET(REFERENCE)) THEN BEGIN
    IF (*(*info).dispswitch).lp_restrict_globloc[0] THEN BEGIN
      ; +1 to skip the first index, which contains the "overall" value
      validx = INDGEN((*(*info).intparams).ndiagnostics)+1 
      sensidx = (*(*info).intparams).lp_diag_all+1
    ENDIF ELSE BEGIN
      validx = BYTARR((*(*info).intparams).ndiagnostics)
      sensidx = 0
      ; Silently update the v_dop_low/upp values according to the global
      ; settings
      FOR d=0,(*(*info).intparams).ndiagnostics-1 DO BEGIN
        (*(*info).dispparams).v_dop_low[d+1] = $
          (*(*info).dispparams).v_dop_low[0] > $
          (*(*info).dataparams).v_dop_low_min[d+1] < $
          (*(*info).dataparams).v_dop_low_max[d+1]
        (*(*info).dispparams).v_dop_upp[d+1] = $
          (*(*info).dispparams).v_dop_upp[0] > $
          (*(*info).dataparams).v_dop_upp_min[d+1] < $
          (*(*info).dataparams).v_dop_upp_max[d+1]
      ENDFOR 
    ENDELSE
    ; Get the reset sensitivity
    reset_sens = ((*(*info).dispparams).v_dop_low[sensidx] NE $
                 (*(*info).dataparams).v_dop_low_min[sensidx]) OR $
                 ((*(*info).dispparams).v_dop_upp[sensidx] NE $
                 (*(*info).dataparams).v_dop_upp_max[sensidx])
    FOR dd=0,(*(*info).intparams).ndisp_diagnostics-1 DO BEGIN
      d = (*(*(*info).intparams).wheredispdiag)[dd]
      IF ((*(*info).plotswitch).heightset EQ 0) THEN $
        vdop_tmp = (*(*(*info).plotaxes).v_dop[d])[$
          0:((*(*info).intparams).diag_width)[d]-1] $
      ELSE $
        vdop_tmp = (*(*info).dataparams).lps[$
          ((*(*info).intparams).diag_start)[d]:$
          ((*(*info).intparams).diag_start)[d]+$
          ((*(*info).intparams).diag_width)[d]-1]
      wheresel = WHERE((vdop_tmp GE (*(*info).dispparams).v_dop_low[validx[d]]) AND $
                       (vdop_tmp LE (*(*info).dispparams).v_dop_upp[validx[d]]), $
                       nwheresel)
      (*(*info).dispparams).lp_low_tmp[d] = wheresel[0]
      (*(*info).dispparams).lp_upp_tmp[d] = wheresel[nwheresel-1]
      ; Handle identical lp_low/upp as a result of overshooting sliders
      IF (nwheresel LE 1) THEN BEGIN  
        IF (event.ID EQ (*(*info).ctrlscp).lp_restr_slider_upp) THEN BEGIN
          ; Value adjusted by upper slider, so adjust the lower slider
          IF ((*(*info).dispparams).lp_upp_tmp[d] EQ -1) THEN BEGIN
            closest_position = MIN(ABS(vdop_tmp - $
              (*(*info).dispparams).v_dop_upp[validx[d]]), where_closest)
            (*(*info).dispparams).lp_upp_tmp[d] = where_closest
          ENDIF
          (*(*info).dispparams).lp_low_tmp[d] = $
            (*(*info).dispparams).lp_upp_tmp[d] - 1
          (*(*info).dispparams).v_dop_low[validx[d]] = $
            FLOOR(vdop_tmp[(*(*info).dispparams).lp_low_tmp[d]])
          WIDGET_CONTROL, (*(*info).ctrlscp).lp_restr_slider_low, $
            SET_VALUE=(*(*info).dispparams).v_dop_low[validx[d]]
        ENDIF ELSE BEGIN
          ; Value adjusted by lower slider, so adjust the upper slider
          IF ((*(*info).dispparams).lp_low_tmp[d] EQ -1) THEN BEGIN
            closest_position = MIN(ABS(vdop_tmp - $
              (*(*info).dispparams).v_dop_low[validx[d]]), where_closest)
            (*(*info).dispparams).lp_low_tmp[d] = where_closest
          ENDIF
          (*(*info).dispparams).lp_upp_tmp[d] = $
            (*(*info).dispparams).lp_low_tmp[d] + 1
          (*(*info).dispparams).v_dop_upp[validx[d]] = $
            CEIL(vdop_tmp[(*(*info).dispparams).lp_upp_tmp[d]])
          WIDGET_CONTROL, (*(*info).ctrlscp).lp_restr_slider_upp, $
            SET_VALUE=(*(*info).dispparams).v_dop_upp[validx[d]]
        ENDELSE
      ENDIF 
    ENDFOR
    (*(*info).dispparams).lp_low_bounds = $
      (*(*info).intparams).diag_start + (*(*info).dispparams).lp_low_tmp
    (*(*info).dispparams).lp_upp_bounds = $
      (*(*info).intparams).diag_start + (*(*info).dispparams).lp_upp_tmp
    CRISPEX_DISPRANGE_LP_RANGE, event, NO_DRAW=no_draw
  ENDIF 
  IF ((*(*info).dispswitch).lp_restrict[1] OR KEYWORD_SET(REFERENCE)) THEN BEGIN
    IF (*(*info).dispswitch).lp_restrict_globloc[1] THEN BEGIN
      ; +1 to skip the first index, which contains the "overall" value
      validx = INDGEN((*(*info).intparams).nrefdiagnostics)+1 
      sensidx = (*(*info).intparams).lp_ref_diag_all+1
    ENDIF ELSE BEGIN
      validx = BYTARR((*(*info).intparams).nrefdiagnostics)
      sensidx = 0
      ; Silently update the v_dop_low/upp values according to the global
      ; settings
      FOR d=0,(*(*info).intparams).nrefdiagnostics-1 DO BEGIN
        (*(*info).dispparams).v_dop_ref_low[d+1] = $
          (*(*info).dispparams).v_dop_ref_low[0] > $
          (*(*info).dataparams).v_dop_ref_low_min[d+1] < $
          (*(*info).dataparams).v_dop_ref_low_max[d+1]
        (*(*info).dispparams).v_dop_ref_upp[d+1] = $
          (*(*info).dispparams).v_dop_ref_upp[0] > $
          (*(*info).dataparams).v_dop_ref_upp_min[d+1] < $
          (*(*info).dataparams).v_dop_ref_upp_max[d+1]
      ENDFOR 
    ENDELSE
    ; Get the reset sensitivity
    reset_sens = ((*(*info).dispparams).v_dop_ref_low[sensidx] NE $
                 (*(*info).dataparams).v_dop_ref_low_min[sensidx]) OR $
                 ((*(*info).dispparams).v_dop_ref_upp[sensidx] NE $
                 (*(*info).dataparams).v_dop_ref_upp_max[sensidx])
    FOR dd=0,(*(*info).intparams).ndisp_refdiagnostics-1 DO BEGIN
      d = (*(*(*info).intparams).wheredisprefdiag)[dd]
      IF ((*(*info).plotswitch).refheightset EQ 0) THEN $
        vdop_tmp = (*(*(*info).plotaxes).v_dop_ref[d])[$
          0:(*(*info).intparams).refdiag_width[d]-1] $
      ELSE $
        vdop_tmp = (*(*info).dataparams).reflps[$
          (*(*info).intparams).refdiag_start[d]:$
          (*(*info).intparams).refdiag_start[d]+$
          (*(*info).intparams).refdiag_width[d]-1]
      wheresel = WHERE((vdop_tmp GE (*(*info).dispparams).v_dop_ref_low[validx[d]]) AND $
                       (vdop_tmp LE (*(*info).dispparams).v_dop_ref_upp[validx[d]]), $
                       nwheresel)
      (*(*info).dispparams).lp_ref_low_tmp[d] = wheresel[0]
      (*(*info).dispparams).lp_ref_upp_tmp[d] = wheresel[nwheresel-1]
      ; Handle identical lp_low/upp as a result of overshooting sliders
      IF (nwheresel LE 1) THEN BEGIN  
        IF (event.ID EQ (*(*info).ctrlscp).lp_restr_slider_upp) THEN BEGIN
          ; Value adjusted by upper slider, so adjust the lower slider
          IF ((*(*info).dispparams).lp_ref_upp_tmp[d] EQ -1) THEN BEGIN
            closest_position = MIN(ABS(vdop_tmp - $
              (*(*info).dispparams).v_dop_ref_upp[validx[d]]), where_closest)
            (*(*info).dispparams).lp_ref_upp_tmp[d] = where_closest
          ENDIF
          (*(*info).dispparams).lp_ref_low_tmp[d] = $
            (*(*info).dispparams).lp_ref_upp_tmp[d] - 1
          (*(*info).dispparams).v_dop_ref_low[validx[d]] = $
            FLOOR(vdop_tmp[(*(*info).dispparams).lp_ref_low_tmp[d]])
          WIDGET_CONTROL, (*(*info).ctrlscp).lp_restr_slider_low, $
            SET_VALUE=(*(*info).dispparams).v_dop_ref_low[validx[d]]
        ENDIF ELSE BEGIN
          ; Value adjusted by lower slider, so adjust the upper slider
          IF ((*(*info).dispparams).lp_ref_low_tmp[d] EQ -1) THEN BEGIN
            closest_position = MIN(ABS(vdop_tmp - $
              (*(*info).dispparams).v_dop_ref_low[validx[d]]), where_closest)
            (*(*info).dispparams).lp_ref_low_tmp[d] = where_closest
          ENDIF
          (*(*info).dispparams).lp_ref_upp_tmp[d] = $
            (*(*info).dispparams).lp_ref_low_tmp[d] + 1
          (*(*info).dispparams).v_dop_ref_upp[validx[d]] = $
            CEIL(vdop_tmp[(*(*info).dispparams).lp_ref_upp_tmp[d]])
          WIDGET_CONTROL, (*(*info).ctrlscp).lp_restr_slider_upp, $
            SET_VALUE=(*(*info).dispparams).v_dop_ref_upp[validx[d]]
        ENDELSE
      ENDIF 
    ENDFOR
    (*(*info).dispparams).lp_ref_low_bounds = $
      (*(*info).intparams).refdiag_start + (*(*info).dispparams).lp_ref_low_tmp
    (*(*info).dispparams).lp_ref_upp_bounds = $
      (*(*info).intparams).refdiag_start + (*(*info).dispparams).lp_ref_upp_tmp
    CRISPEX_DISPRANGE_LP_REF_RANGE, event, NO_DRAW=no_draw
  ENDIF
	WIDGET_CONTROL, (*(*info).ctrlscp).reset_lprange_but, SENSITIVE=reset_sens
END

PRO CRISPEX_SLIDER_LP_RESTRICT_SETRANGE, event, idx
; Handles setting the range of LP_RESTRICT sliders
	WIDGET_CONTROL, event.TOP, GET_UVALUE=info
  CASE idx OF
    0:  BEGIN   ; Main
          validx = ([0,(*(*info).intparams).lp_diag_all+1])[$
            (*(*info).dispswitch).lp_restrict_globloc[idx]]
          slider_low_min = (*(*info).dataparams).v_dop_low_min[validx]
          slider_low_max = (*(*info).dataparams).v_dop_low_max[validx]
          slider_upp_min = (*(*info).dataparams).v_dop_upp_min[validx]
          slider_upp_max = (*(*info).dataparams).v_dop_upp_max[validx]
          v_dop_low = (*(*info).dispparams).v_dop_low[validx]
          v_dop_upp = (*(*info).dispparams).v_dop_upp[validx]
        END
    1:  BEGIN   ; Reference
          validx = ([0,(*(*info).intparams).lp_ref_diag_all+1])[$
            (*(*info).dispswitch).lp_restrict_globloc[idx]]
          slider_low_min = (*(*info).dataparams).v_dop_ref_low_min[validx]
          slider_low_max = (*(*info).dataparams).v_dop_ref_low_max[validx]
          slider_upp_min = (*(*info).dataparams).v_dop_ref_upp_min[validx]
          slider_upp_max = (*(*info).dataparams).v_dop_ref_upp_max[validx]
          v_dop_low = (*(*info).dispparams).v_dop_ref_low[validx]
          v_dop_upp = (*(*info).dispparams).v_dop_ref_upp[validx]
        END
  ENDCASE
  WIDGET_CONTROL, (*(*info).ctrlscp).lp_restr_slider_low, $
    SET_SLIDER_MIN=slider_low_min, SET_SLIDER_MAX=slider_low_max, $
    SET_VALUE=v_dop_low
  WIDGET_CONTROL, (*(*info).ctrlscp).lp_restr_slider_upp, $
    SET_SLIDER_MIN=slider_upp_min, SET_SLIDER_MAX=slider_upp_max, $
    SET_VALUE=v_dop_upp
	WIDGET_CONTROL, (*(*info).ctrlscp).reset_lprange_but, SENSITIVE=($
    (v_dop_low NE slider_low_min) OR (v_dop_upp NE slider_upp_max))
END

PRO CRISPEX_SLIDER_LP_UPDATE, event, OVERRIDE_DIAGNOSTIC=override_diagnostic, $
  NO_DRAW=no_draw, REFERENCE=reference
; Handles the the update after change in the spectral position slider
	WIDGET_CONTROL, event.TOP, GET_UVALUE = info
	IF (TOTAL(((*(*info).feedbparams).verbosity)[2:3]) GE 1) THEN $
    CRISPEX_VERBOSE_GET_ROUTINE, event
  IF ~KEYWORD_SET(REFERENCE) THEN BEGIN
    ; Determine whether lp falls in not displayed (portion of) diagnostic
    ; window(s), act accordingly
    lp_diag_all = $
      TOTAL((*(*info).dataparams).lp GE (*(*info).intparams).diag_start)-1
    above_low_bounds = $
      ((*(*info).dataparams).lp GE (*(*info).dispparams).lp_low_bounds)
    below_upp_bounds = $
      ((*(*info).dataparams).lp LE (*(*info).dispparams).lp_upp_bounds)
    IF ((TOTAL(above_low_bounds AND below_upp_bounds) EQ 0) OR $
        ((*(*info).intparams).disp_diagnostics[lp_diag_all] EQ 0)) THEN BEGIN
      ; Determine distance to upper and lower boundaries of closest displayed
      ; diagnostics window
      result = CRISPEX_SLIDER_LP_DIAG(event, $
        TOTAL((*(*info).dataparams).lp GE *(*(*info).intparams).diag_starts)-1, $
        OVERRIDE_DIAGNOSTIC=override_diagnostic)
      (*(*info).dataparams).lp = result.lp_new
      lp_diag_all = result.lp_diag_new
    ENDIF 
    (*(*info).intparams).lp_diag_all = lp_diag_all
	  WIDGET_CONTROL, (*(*info).ctrlscp).lp_slider, SET_VALUE=(*(*info).dataparams).lp
  ENDIF 
  IF (*(*info).ctrlsswitch).lp_ref_lock THEN BEGIN
    (*(*info).dataparams).lp_ref = (*(*info).dataparams).lp
    reference = 1B
  ENDIF
  IF KEYWORD_SET(REFERENCE) THEN BEGIN
    ; Determine whether lp_ref falls in not displayed diagnostic window, 
    ; act accordingly
    lp_ref_diag_all = $
      TOTAL((*(*info).dataparams).lp_ref GE (*(*info).intparams).refdiag_start)-1
    above_low_bounds = $
      ((*(*info).dataparams).lp_ref GE (*(*info).dispparams).lp_ref_low_bounds)
    below_upp_bounds = $
      ((*(*info).dataparams).lp_ref LE (*(*info).dispparams).lp_ref_upp_bounds)
    IF ((TOTAL(above_low_bounds AND below_upp_bounds) EQ 0) OR $
        ((*(*info).intparams).disp_refdiagnostics[lp_ref_diag_all] EQ 0)) THEN BEGIN
      ; Determine distance to upper and lower boundaries of closest displayed 
      ; diagnostics window
      ; 0=dist_low, 1=dist_upp, 2=disp_low_next, 3=disp_upp_next
      result = CRISPEX_SLIDER_LP_DIAG(event, $
        TOTAL((*(*info).dataparams).lp_ref GE $
              *(*(*info).intparams).refdiag_starts)-1, $
        OVERRIDE_DIAGNOSTIC=override_diagnostic, /REFERENCE)
      (*(*info).dataparams).lp_ref = result.lp_new
      lp_ref_diag_all = result.lp_diag_new
    ENDIF
    (*(*info).intparams).lp_ref_diag_all = lp_ref_diag_all
    WIDGET_CONTROL, (*(*info).ctrlscp).lp_ref_slider, $
      SET_VALUE=(*(*info).dataparams).lp_ref
  ENDIF
  IF (*(*info).dispswitch).lp_restrict_globloc[KEYWORD_SET(REFERENCE)] THEN $
    CRISPEX_SLIDER_LP_RESTRICT_SETRANGE, event, KEYWORD_SET(REFERENCE)
  (*(*info).scaling).idx = $
    (((*(*info).scaling).imrefscaling EQ 0) OR $
     ((*(*info).scaling).imrefscaling EQ 2)) * $
    (*(*info).intparams).lp_diag_all + $
    (((*(*info).scaling).imrefscaling GT 0) + $
    ((*(*info).scaling).imrefscaling GT 2)) * $
    (*(*info).intparams).ndiagnostics + $
    ((*(*info).scaling).imrefscaling EQ 1) * (*(*info).intparams).lp_ref_diag_all + $
    ((*(*info).scaling).imrefscaling GT 1) * (*(*info).intparams).nrefdiagnostics 
  IF (((*(*info).intparams).ndiagnostics GT 1) OR $
    ((*(*info).intparams).nrefdiagnostics GT 1)) THEN BEGIN
    CRISPEX_SCALING_SET_BOXBUTTONS, event
    CRISPEX_SCALING_SET_SLIDERS, event
  ENDIF
	IF (((*(*info).feedbparams).verbosity)[3] EQ 1) THEN $
    CRISPEX_VERBOSE_GET, event, $
      [(*(*info).dataparams).lp, (*(*info).dataparams).lp_ref], $
      labels=['lp','lp_ref']
  IF ~KEYWORD_SET(NO_DRAW) THEN BEGIN
  	CRISPEX_UPDATE_T, event
	  IF ((*(*info).overlayswitch).loopslit AND ((*(*info).loopparams).np GT 0) $
      OR (*(*info).winswitch).showrestloop OR $
         (*(*info).winswitch).showretrdet) THEN $
      CRISPEX_UPDATE_LP, event $
    ELSE $
      CRISPEX_SCALING_APPLY_SELECTED, event
    CRISPEX_DRAW_CTBAR, event, MAIN=~KEYWORD_SET(REFERENCE), $
      REFERENCE=KEYWORD_SET(REFERENCE), $
      DOPPLER=((*(*info).dispswitch).drawdop AND ~KEYWORD_SET(REFERENCE))
  	CRISPEX_DRAW, event
  ENDIF
END

PRO CRISPEX_SLIDER_SPECTBLINK, event
; Handles the change in spectral step (for spectral blink) slider
	WIDGET_CONTROL, event.TOP, GET_UVALUE = info
	IF (TOTAL(((*(*info).feedbparams).verbosity)[2:3]) GE 1) THEN $
    CRISPEX_VERBOSE_GET_ROUTINE, event
	(*(*info).pbparams).lp_blink = event.VALUE
  lp_blink_diag_all = $
    TOTAL((*(*info).pbparams).lp_blink GE (*(*info).intparams).diag_start)-1
  above_low_bounds = $
    ((*(*info).pbparams).lp_blink GE (*(*info).dispparams).lp_low_bounds)
  below_upp_bounds = $
    ((*(*info).pbparams).lp_blink LE (*(*info).dispparams).lp_upp_bounds)
  IF ((TOTAL(above_low_bounds AND below_upp_bounds) EQ 0) OR $
      ((*(*info).intparams).disp_diagnostics[lp_blink_diag_all] EQ 0)) THEN BEGIN
    ; Determine distance to upper and lower boundaries of closest displayed
    ; diagnostics window
    result = CRISPEX_SLIDER_LP_DIAG(event, $
      TOTAL((*(*info).pbparams).lp_blink GE *(*(*info).intparams).diag_starts)-1, $
      OVERRIDE_DIAGNOSTIC=(event.DRAG EQ 0), /BLINK)
    (*(*info).pbparams).lp_blink = result.lp_new
    (*(*info).intparams).lp_diag_all = result.lp_diag_new
  ENDIF
  WIDGET_CONTROL, (*(*info).ctrlscp).lp_blink_but, $
    SENSITIVE=((*(*info).pbparams).lp_blink NE (*(*info).dataparams).lp)
  WIDGET_CONTROL, (*(*info).ctrlscp).lp_blink_slider, $
    SET_VALUE=(*(*info).pbparams).lp_blink
  (*(*info).dataparams).lp = (*(*info).pbparams).lp_blink
  CRISPEX_SLIDER_LP_UPDATE, event
	IF (((*(*info).feedbparams).verbosity)[3] EQ 1) THEN $
    CRISPEX_VERBOSE_GET, event, [(*(*info).pbparams).lp_blink], labels=['lp_blink']
END

PRO CRISPEX_SLIDER_SPEED, event
; Handles the change in playback speed slider
	WIDGET_CONTROL, event.TOP, GET_UVALUE = info
	IF (TOTAL(((*(*info).feedbparams).verbosity)[2:3]) GE 1) THEN $
    CRISPEX_VERBOSE_GET_ROUTINE, event, /IGNORE_LAST
	(*(*info).pbparams).t_speed = event.VALUE
  WIDGET_CONTROL, (*(*info).ctrlscp).t_speed_slider, SET_VALUE = (*(*info).pbparams).t_speed 
	IF (((*(*info).feedbparams).verbosity)[3] EQ 1) THEN $
    CRISPEX_VERBOSE_GET, event, [(*(*info).pbparams).t_speed], labels=['Playback (blink) speed']
END

PRO CRISPEX_SLIDER_STEP, event
; Handles the change in temporal step slider
	WIDGET_CONTROL, event.TOP, GET_UVALUE = info
	IF (TOTAL(((*(*info).feedbparams).verbosity)[2:3]) GE 1) THEN $
    CRISPEX_VERBOSE_GET_ROUTINE, event
	(*(*info).pbparams).t_step = event.VALUE
	IF (((*(*info).feedbparams).verbosity)[3] EQ 1) THEN $
    CRISPEX_VERBOSE_GET, event, [(*(*info).pbparams).t_step], labels=['t_step']
END

PRO CRISPEX_SLIDER_T, event
; Handles the change in temporal slider
	WIDGET_CONTROL, event.TOP, GET_UVALUE = info
	IF (TOTAL(((*(*info).feedbparams).verbosity)[2:3]) GE 1) THEN $
    CRISPEX_VERBOSE_GET_ROUTINE, event
	(*(*info).dispparams).t = event.VALUE
	IF (((*(*info).feedbparams).verbosity)[3] EQ 1) THEN $
    CRISPEX_VERBOSE_GET, event, [(*(*info).dispparams).t], labels=['t']
	CRISPEX_UPDATE_T, event
	IF ((*(*info).dispparams).phislice_update OR (event.DRAG EQ 0)) THEN $
    CRISPEX_UPDATE_SLICES, event, /NO_DRAW, $
      NO_PHIS=((*(*info).winswitch).showphis EQ 0), $
		  SSP_UPDATE=(((*(*info).dataswitch).spfile EQ 0) AND $
                    (*(*info).winswitch).showls), $
      REFSSP_UPDATE=(((*(*info).dataswitch).reffile EQ 1) AND $
                     ((*(*info).dataswitch).refspfile EQ 0) AND $
                      (*(*info).winswitch).showrefls) $
  ELSE BEGIN		
		IF ((*(*info).dataswitch).onecube AND $
        (((*(*info).dataparams).nlp GT 1) OR $
         ((*(*info).dataparams).refnlp GT 1))) THEN $
      WIDGET_CONTROL, (*(*info).ctrlscp).slice_button, SENSITIVE = 1, $
        SET_VALUE = 'Update spectral windows' 
	ENDELSE
  IF ((*(*info).winswitch).showls AND $
      ((*(*info).dataswitch).spfile EQ 0)) THEN CRISPEX_UPDATE_SSP, event
  IF ((*(*info).winswitch).showrefls AND $
    ((*(*info).dataswitch).refspfile EQ 0)) THEN CRISPEX_UPDATE_REFSSP, event
  CRISPEX_DRAW, event, NO_PHIS=event.DRAG
END

PRO CRISPEX_SLIDER_TIME_OFFSET, event
; Handles the change in temporal slider
	WIDGET_CONTROL, event.TOP, GET_UVALUE = info
	IF (TOTAL(((*(*info).feedbparams).verbosity)[2:3]) GE 1) THEN $
    CRISPEX_VERBOSE_GET_ROUTINE, event
  CASE (*(*info).dispparams).master_time OF
    0:  BEGIN
          (*(*info).dispparams).toffset_main = event.VALUE
;          t_old = (*(*(*info).dispparams).tarr_main)[(*(*info).dispparams).t_main]
          t_old = (*(*(*info).dispparams).tarr_main)[(*(*info).dispparams).t]
        END
    1:  BEGIN
          (*(*info).dispparams).toffset_ref = event.VALUE
          t_old = (*(*(*info).dispparams).tarr_ref)[(*(*info).dispparams).t_ref]
        END
  ENDCASE
  CRISPEX_COORDS_TRANSFORM_T, event, NT_OLD=(*(*info).dataparams).nt, $
    T_OLD=t_old
	IF (((*(*info).feedbparams).verbosity)[3] EQ 1) THEN $
    CRISPEX_VERBOSE_GET, event, [event.VALUE], labels=['Raster timing offset']
	CRISPEX_UPDATE_T, event
  IF (*(*info).winswitch).showsp THEN CRISPEX_DISPLAYS_SP_REPLOT_AXES, event
  IF (*(*info).winswitch).showrefsp THEN CRISPEX_DISPLAYS_REFSP_REPLOT_AXES, event
	CRISPEX_DRAW, event
END

PRO CRISPEX_SLIDER_X, event
; Handles the change in main x-position slider
	WIDGET_CONTROL, event.TOP, GET_UVALUE = info
	IF (TOTAL(((*(*info).feedbparams).verbosity)[2:3]) GE 1) THEN $
    CRISPEX_VERBOSE_GET_ROUTINE, event
	(*(*info).dataparams).x = event.VALUE
	IF (((*(*info).feedbparams).verbosity)[3] EQ 1) THEN $
    CRISPEX_VERBOSE_GET, event, [(*(*info).dataparams).x], labels=['x']
  CRISPEX_SLIDER_X_XREF_UPDATE, event, /MAIN
END

PRO CRISPEX_SLIDER_XREF, event
; Handles the change in reference x-position slider
	WIDGET_CONTROL, event.TOP, GET_UVALUE = info
	IF (TOTAL(((*(*info).feedbparams).verbosity)[2:3]) GE 1) THEN $
    CRISPEX_VERBOSE_GET_ROUTINE, event
	(*(*info).dataparams).xref = event.VALUE
	IF (((*(*info).feedbparams).verbosity)[3] EQ 1) THEN $
    CRISPEX_VERBOSE_GET, event, [(*(*info).dataparams).xref], labels=['xref']
  CRISPEX_SLIDER_X_XREF_UPDATE, event, /REFERENCE
END

PRO CRISPEX_SLIDER_X_XREF_UPDATE, event, MAIN=main, REFERENCE=reference
; Handles the updates after a change in main/reference x-position slider
	WIDGET_CONTROL, event.TOP, GET_UVALUE = info
	IF (TOTAL(((*(*info).feedbparams).verbosity)[2:3]) GE 1) THEN $
    CRISPEX_VERBOSE_GET_ROUTINE, event
  ; If necessary, transform coordinates prior to updating sy
  CRISPEX_COORDS_TRANSFORM_XY, event, $
    MAIN2SJI=(*(*info).dataswitch).sjifile,$ 
    MAIN2REF=(KEYWORD_SET(MAIN) AND (*(*info).dataswitch).reffile),$
    REF2MAIN=KEYWORD_SET(REFERENCE), $
    REF2SJI=(KEYWORD_SET(REFERENCE) AND (*(*info).dataswitch).sjifile)
  ; Adjust path if drawing one
  IF ((*(*info).overlayswitch).loopslit AND $
      ((*(*info).loopparams).np GE 1) OR $
      ((*(*info).loopparams).np_ref GE 1)) THEN BEGIN
    IF ((*(*info).loopparams).np GE 1) THEN $
	  	*(*(*info).loopparams).xp = $
        [(*(*(*info).loopparams).xp)[0:(*(*info).loopparams).np-2],$
                                    (*(*info).dataparams).x]
    IF ((*(*info).winswitch).showref AND $
      (*(*info).loopparams).np_ref GE 1) THEN $
	  	*(*(*info).loopparams).xp_ref = $
        [(*(*(*info).loopparams).xp_ref)[0:(*(*info).loopparams).np_ref-2],$
                                    (*(*info).dataparams).xref]
    IF ((*(*info).winswitch).showsji AND $
      (*(*info).loopparams).np_sji GE 1) THEN $
	  	*(*(*info).loopparams).xp_sji = $
        [(*(*(*info).loopparams).xp_sji)[0:(*(*info).loopparams).np_sji-2],$
                                    (*(*info).dataparams).xsji]
    CRISPEX_LOOP_GET_PATH, event, /ADD_REMOVE, /MAIN, /REFERENCE, /SJI
  ENDIF
  ; Set main/reference slider accordingly
  CRISPEX_COORDSLIDERS_SET, 1, 1, event
  ; Update cursor coordinates
	CRISPEX_UPDATE_SX, event
  ; Update slices and redraw 
  IF (*(*info).winswitch).showls THEN CRISPEX_UPDATE_SSP, event
  IF (*(*info).winswitch).showsp THEN CRISPEX_UPDATE_SPSLICE, event
  IF (*(*info).winswitch).showrefls THEN CRISPEX_UPDATE_REFSSP, event
  IF (*(*info).winswitch).showrefsp THEN CRISPEX_UPDATE_REFSPSLICE, event
	IF (*(*info).winswitch).showphis THEN BEGIN
		CRISPEX_PHISLIT_DIRECTION, event
    CRISPEX_UPDATE_PHISLIT_COORDS, event
		CRISPEX_UPDATE_PHISLICE, event
	ENDIF ELSE CRISPEX_DRAW, event
END

PRO CRISPEX_SLIDER_XPOS, event, REFERENCE=reference, SJI=sji, $
  SET_VALUE=set_value, IDX_SJI=idx_sji, NO_DRAW=no_draw
; Handles change in xpos-slider
	WIDGET_CONTROL, event.TOP, GET_UVALUE = info
	IF (TOTAL(((*(*info).feedbparams).verbosity)[2:3]) GE 1) THEN $
    CRISPEX_VERBOSE_GET_ROUTINE, event
  IF (N_ELEMENTS(SET_VALUE) EQ 1) THEN $
    value = set_value $
  ELSE $
    value = event.VALUE
  IF KEYWORD_SET(REFERENCE) THEN BEGIN
    (*(*info).zooming).xrefpos = value
    IF (N_ELEMENTS(SET_VALUE) EQ 1) THEN BEGIN
      WIDGET_CONTROL, (*(*info).ctrlsref).xrefpos_slider, $
        SET_VALUE=(*(*info).zooming).xrefpos
    IF (*(*info).dispswitch).main2ref_no_map THEN $
      (*(*info).zooming).xpos = (*(*info).zooming).xrefpos
      WIDGET_CONTROL, (*(*info).ctrlscp).xpos_slider, $
        SET_VALUE=(*(*info).zooming).xpos
    ENDIF
  ENDIF ELSE IF KEYWORD_SET(SJI) THEN BEGIN
    (*(*info).zooming).xsjipos[idx_sji] = value 
    IF (N_ELEMENTS(SET_VALUE) EQ 1) THEN $
      WIDGET_CONTROL, (*(*info).ctrlssji).xsjipos_slider[idx_sji], $
        SET_VALUE=(*(*info).zooming).xsjipos[idx_sji]
  ENDIF ELSE BEGIN
    (*(*info).zooming).xpos = value
    IF (N_ELEMENTS(SET_VALUE) EQ 1) THEN $
      WIDGET_CONTROL, (*(*info).ctrlscp).xpos_slider, $
        SET_VALUE=(*(*info).zooming).xpos
    IF ((*(*info).winswitch).showref AND $
      (*(*info).dispswitch).main2ref_no_map) THEN BEGIN
      (*(*info).zooming).xrefpos = (*(*info).zooming).xpos
      WIDGET_CONTROL, (*(*info).ctrlsref).xrefpos_slider, $
        SET_VALUE=(*(*info).zooming).xrefpos
    ENDIF
  ENDELSE
	IF (((*(*info).feedbparams).verbosity)[3] EQ 1) THEN $
    CRISPEX_VERBOSE_GET, event, [(*(*info).zooming).xpos], labels=['xpos']
	CRISPEX_UPDATE_SX, event
	IF ~KEYWORD_SET(NO_DRAW) THEN CRISPEX_DRAW, event
END

PRO CRISPEX_SLIDER_XPOS_REF, event
; Handles change in reference xpos-slider
	WIDGET_CONTROL, event.TOP, GET_UVALUE = info
	IF (TOTAL(((*(*info).feedbparams).verbosity)[2:3]) GE 1) THEN $
    CRISPEX_VERBOSE_GET_ROUTINE, event
  CRISPEX_SLIDER_XPOS, event, /REFERENCE
END

PRO CRISPEX_SLIDER_XPOS_SJI, event
; Handles change in slit-jaw image xpos-slider
	WIDGET_CONTROL, event.TOP, GET_UVALUE = info
	IF (TOTAL(((*(*info).feedbparams).verbosity)[2:3]) GE 1) THEN $
    CRISPEX_VERBOSE_GET_ROUTINE, event
  CRISPEX_SLIDER_XPOS, event, /SJI
END

PRO CRISPEX_SLIDER_Y, event
; Handles the change in main y-position slider
	WIDGET_CONTROL, event.TOP, GET_UVALUE = info
	IF (TOTAL(((*(*info).feedbparams).verbosity)[2:3]) GE 1) THEN $
    CRISPEX_VERBOSE_GET_ROUTINE, event
	(*(*info).dataparams).y = event.VALUE
	IF (((*(*info).feedbparams).verbosity)[3] EQ 1) THEN $
    CRISPEX_VERBOSE_GET, event, [(*(*info).dataparams).y], labels=['y']
  CRISPEX_SLIDER_Y_YREF_UPDATE, event, /MAIN
END

PRO CRISPEX_SLIDER_YREF, event
; Handles the change in reference y-position slider
	WIDGET_CONTROL, event.TOP, GET_UVALUE = info
	IF (TOTAL(((*(*info).feedbparams).verbosity)[2:3]) GE 1) THEN $
    CRISPEX_VERBOSE_GET_ROUTINE, event
	(*(*info).dataparams).yref = event.VALUE
	IF (((*(*info).feedbparams).verbosity)[3] EQ 1) THEN $
    CRISPEX_VERBOSE_GET, event, [(*(*info).dataparams).yref], labels=['yref']
  CRISPEX_SLIDER_Y_YREF_UPDATE, event, /REFERENCE
END

PRO CRISPEX_SLIDER_Y_YREF_UPDATE, event, MAIN=main, REFERENCE=reference
; Handles the updates after a change in main/reference y-position slider
	WIDGET_CONTROL, event.TOP, GET_UVALUE = info
	IF (TOTAL(((*(*info).feedbparams).verbosity)[2:3]) GE 1) THEN $
    CRISPEX_VERBOSE_GET_ROUTINE, event
  ; If necessary, transform coordinates prior to updating sy
  CRISPEX_COORDS_TRANSFORM_XY, event, $
    MAIN2SJI=(*(*info).dataswitch).sjifile,$ 
    MAIN2REF=(KEYWORD_SET(MAIN) AND (*(*info).dataswitch).reffile),$
    REF2MAIN=KEYWORD_SET(REFERENCE), $
    REF2SJI=(KEYWORD_SET(REFERENCE) AND (*(*info).dataswitch).sjifile)
  ; Adjust path if drawing one
  IF ((*(*info).overlayswitch).loopslit AND $
      ((*(*info).loopparams).np GE 1) OR $
      ((*(*info).loopparams).np_ref GE 1)) THEN BEGIN
    IF ((*(*info).loopparams).np GE 1) THEN $
  		*(*(*info).loopparams).yp = $
        [(*(*(*info).loopparams).yp)[0:(*(*info).loopparams).np-2],$
                                    (*(*info).dataparams).y]
    IF ((*(*info).winswitch).showref AND $
      (*(*info).loopparams).np_ref GE 1) THEN $
  		*(*(*info).loopparams).yp_ref = $
        [(*(*(*info).loopparams).yp_ref)[0:(*(*info).loopparams).np_ref-2],$
                                    (*(*info).dataparams).yref]
    IF ((*(*info).winswitch).showsji AND $
      (*(*info).loopparams).np_sji GE 1) THEN $
  		*(*(*info).loopparams).yp_sji = $
        [(*(*(*info).loopparams).yp_sji)[0:(*(*info).loopparams).np_sji-2],$
                                    (*(*info).dataparams).ysji]
    CRISPEX_LOOP_GET_PATH, event, /ADD_REMOVE, /MAIN, /REFERENCE, /SJI
  ENDIF
  ; Set main/reference slider accordingly
  CRISPEX_COORDSLIDERS_SET, 1, 1, event
  ; Update cursor coordinates
	CRISPEX_UPDATE_SY, event
  ; Update slices and redraw 
  IF (*(*info).winswitch).showls THEN CRISPEX_UPDATE_SSP, event
  IF (*(*info).winswitch).showsp THEN CRISPEX_UPDATE_SPSLICE, event
  IF (*(*info).winswitch).showrefls THEN CRISPEX_UPDATE_REFSSP, event
  IF (*(*info).winswitch).showrefsp THEN CRISPEX_UPDATE_REFSPSLICE, event
	IF (*(*info).winswitch).showphis THEN BEGIN
		CRISPEX_PHISLIT_DIRECTION, event
    CRISPEX_UPDATE_PHISLIT_COORDS, event
		CRISPEX_UPDATE_PHISLICE, event
	ENDIF ELSE CRISPEX_DRAW, event
END

PRO CRISPEX_SLIDER_YPOS, event, REFERENCE=reference, SJI=sji, $
  SET_VALUE=set_value, IDX_SJI=idx_sji, NO_DRAW=no_draw
; Handles change in y-slider
	WIDGET_CONTROL, event.TOP, GET_UVALUE = info
	IF (TOTAL(((*(*info).feedbparams).verbosity)[2:3]) GE 1) THEN $
    CRISPEX_VERBOSE_GET_ROUTINE, event
  IF (N_ELEMENTS(SET_VALUE) EQ 1) THEN $
    value = set_value $
  ELSE $
    value = event.VALUE
  IF KEYWORD_SET(REFERENCE) THEN BEGIN
    (*(*info).zooming).yrefpos = value
    IF (N_ELEMENTS(SET_VALUE) EQ 1) THEN $
      WIDGET_CONTROL, (*(*info).ctrlsref).yrefpos_slider, $
        SET_VALUE=(*(*info).zooming).yrefpos
    IF (*(*info).dispswitch).main2ref_no_map THEN BEGIN
      (*(*info).zooming).ypos = (*(*info).zooming).yrefpos
      WIDGET_CONTROL, (*(*info).ctrlscp).ypos_slider, $
        SET_VALUE=(*(*info).zooming).ypos
    ENDIF
  ENDIF ELSE IF KEYWORD_SET(SJI) THEN BEGIN
    (*(*info).zooming).ysjipos[idx_sji] = value 
    IF (N_ELEMENTS(SET_VALUE) EQ 1) THEN $
      WIDGET_CONTROL, (*(*info).ctrlssji).xsjipos_slider[idx_sji], $
        SET_VALUE=(*(*info).zooming).xsjipos[idx_sji]
  ENDIF ELSE BEGIN
    (*(*info).zooming).ypos = value
    IF (N_ELEMENTS(SET_VALUE) EQ 1) THEN $
      WIDGET_CONTROL, (*(*info).ctrlscp).ypos_slider, $
        SET_VALUE=(*(*info).zooming).ypos
    IF ((*(*info).winswitch).showref AND $
      (*(*info).dispswitch).main2ref_no_map) THEN BEGIN
      (*(*info).zooming).yrefpos = (*(*info).zooming).ypos
      WIDGET_CONTROL, (*(*info).ctrlsref).yrefpos_slider, $
        SET_VALUE=(*(*info).zooming).yrefpos
    ENDIF
  ENDELSE
	IF (((*(*info).feedbparams).verbosity)[3] EQ 1) THEN $
    CRISPEX_VERBOSE_GET, event, [(*(*info).zooming).ypos], labels=['ypos']
	CRISPEX_UPDATE_SY, event	
	IF ~KEYWORD_SET(NO_DRAW) THEN CRISPEX_DRAW, event
END

PRO CRISPEX_SLIDER_YPOS_REF, event
; Handles change in slit-jaw image ypos-slider
	WIDGET_CONTROL, event.TOP, GET_UVALUE = info
	IF (TOTAL(((*(*info).feedbparams).verbosity)[2:3]) GE 1) THEN $
    CRISPEX_VERBOSE_GET_ROUTINE, event
  CRISPEX_SLIDER_YPOS, event, /REFERENCE
END

PRO CRISPEX_SLIDER_YPOS_SJI, event
; Handles change in slit-jaw image ypos-slider
	WIDGET_CONTROL, event.TOP, GET_UVALUE = info
	IF (TOTAL(((*(*info).feedbparams).verbosity)[2:3]) GE 1) THEN $
    CRISPEX_VERBOSE_GET_ROUTINE, event
  CRISPEX_SLIDER_YPOS, event, /SJI
END

;========================= UPDATE SLICES AND PARAMETERS PROCEDURES
PRO CRISPEX_UPDATE_SLICES, event, NO_DRAW=no_draw, NO_PHIS=no_phis, $
  SSP_UPDATE=ssp_update, REFSSP_UPDATE=refssp_update, $
  GET_PHISLIT_COORDS=get_phislit_coords, $
  LS_DRAW=ls_draw, REFLS_DRAW=refls_draw, NO_FEEDBACK=no_feedback
  ; Handles getting new new spectral scans after change in frame number, also
  ; updating detailed spectra if need be
	WIDGET_CONTROL, event.TOP, GET_UVALUE = info
	IF (TOTAL(((*(*info).feedbparams).verbosity)[2:3]) GE 1) THEN $
    CRISPEX_VERBOSE_GET_ROUTINE, event
  ; Override NO_FEEDBACK setting if need be
  IF (N_ELEMENTS(NO_FEEDBACK) NE 1) THEN $
    no_feedback = $
      (KEYWORD_SET(SSP_UPDATE) AND ((*(*info).winswitch).showls EQ 0)) AND $
      (KEYWORD_SET(REFSSP_UPDATE) AND ((*(*info).winswitch).showrefls EQ 0)) AND $
      (~KEYWORD_SET(NO_PHIS) AND ((*(*info).winswitch).showphis EQ 0))
  IF (~KEYWORD_SET(NO_PHIS) OR KEYWORD_SET(SSP_UPDATE) OR $
    KEYWORD_SET(REFSSP_UPDATE)) THEN BEGIN
    IF ~KEYWORD_SET(NO_FEEDBACK) THEN BEGIN
      WIDGET_CONTROL,/HOURGLASS
      totslices = $
        ((*(*info).winswitch).showrefls AND $
        ((*(*info).dataswitch).refspfile EQ 0))+$
  	    ((*(*info).winswitch).showphis OR $
        ((*(*info).dataswitch).onecube AND (*(*info).winswitch).showls))+$
        (~KEYWORD_SET(NO_PHIS) AND (*(*info).winswitch).showphis) 
      base_txt = 'Updating '+STRLOWCASE((*(*info).paramparams).sp_h[$
        (*(*info).plotswitch).heightset])+' slices... '
      CRISPEX_WINDOW_USER_FEEDBACK, event, 'Updating slices', $
        base_txt+'(may take some time)'
    ENDIF
    IF KEYWORD_SET(REFSSP_UPDATE) THEN BEGIN
    	IF ((*(*info).dataparams).refnt GT 1) THEN $
        *(*(*info).data).refsspscan = $
          (*(*(*info).data).refscan)[(*(*info).dispparams).t_ref] 
      CRISPEX_UPDATE_REFSSP, event
      IF KEYWORD_SET(REFLS_DRAW) THEN CRISPEX_DRAW_SPECTRAL_REF, event, /LS_ONLY
      IF ~KEYWORD_SET(NO_FEEDBACK) THEN $
        WIDGET_CONTROL, (*(*info).ctrlsfeedb).feedback_text, $
          SET_VALUE=base_txt+'1/'+STRTRIM(totslices,2)+' done            '
    ENDIF
    IF (~KEYWORD_SET(NO_PHIS) OR KEYWORD_SET(SSP_UPDATE)) THEN BEGIN
  		IF ((*(*info).dataparams).mainnt GT 1) THEN $
        *(*(*info).data).sspscan = $
          (*(*(*info).data).scan)[(*(*info).dispparams).t_main] 
      IF KEYWORD_SET(SSP_UPDATE) THEN BEGIN
        CRISPEX_UPDATE_SSP, event
        IF KEYWORD_SET(LS_DRAW) THEN CRISPEX_DRAW_SPECTRAL_MAIN, event, /LS_ONLY
      ENDIF
      IF ~KEYWORD_SET(NO_FEEDBACK) THEN $
        WIDGET_CONTROL, (*(*info).ctrlsfeedb).feedback_text, SET_VALUE=base_txt+$
          STRTRIM(KEYWORD_SET(REFSSP_UPDATE)+1,2)+'/'+STRTRIM(totslices,2)+$
          ' done            '
      IF ~KEYWORD_SET(NO_PHIS) THEN BEGIN
        phiscan_tmp = (*(*(*info).data).sspscan)[*,*,$
           ((*(*info).dataparams).s * (*(*info).dataparams).nlp):$
          (((*(*info).dataparams).s+1)*(*(*info).dataparams).nlp-1)] 
        IF (*(*info).dispswitch).imscaled THEN $
          phiscan_tmp = CRISPEX_SCALING_DESCALE(phiscan_tmp, $
            (*(*info).dispparams).imbscale, (*(*info).dispparams).imbzero)
    		*(*(*info).data).phiscan = phiscan_tmp
        IF KEYWORD_SET(GET_PHISLIT_COORDS) THEN $
          CRISPEX_UPDATE_PHISLIT_COORDS, event, NO_DRAW=no_draw
        CRISPEX_UPDATE_PHISLICE, event, NO_DRAW=no_draw
        IF ~KEYWORD_SET(NO_FEEDBACK) THEN $
          WIDGET_CONTROL, (*(*info).ctrlsfeedb).feedback_text, SET_VALUE=base_txt+$
            STRTRIM(KEYWORD_SET(REFSSP_UPDATE)+KEYWORD_SET(SSP_UPDATE)+1,2)+$
            '/'+STRTRIM(totslices,2)+' done            '
      ENDIF
  	ENDIF
    WIDGET_CONTROL, (*(*info).ctrlscp).slice_button, SENSITIVE=0
    IF ~KEYWORD_SET(NO_FEEDBACK) THEN $
      CRISPEX_WINDOW_USER_FEEDBACK_CLOSE, event
  ENDIF
END

PRO CRISPEX_UPDATE_SPSLICE, event
; Handles updating spectrum-time diagram
	WIDGET_CONTROL, event.TOP, GET_UVALUE = info
	IF (TOTAL(((*(*info).feedbparams).verbosity)[2:3]) GE 1) THEN $
    CRISPEX_VERBOSE_GET_ROUTINE, event
  IF ((*(*info).dispswitch).xy_out_of_range EQ 0) THEN BEGIN
    t_low = (*(*(*info).dispparams).tsel_main)[(*(*info).dispparams).t_low]
    t_upp = (*(*(*info).dispparams).tsel_main)[(*(*info).dispparams).t_upp]
    baseidx = LONG((*(*info).dataparams).y) * (*(*info).dataparams).nx * $
      (*(*info).dataparams).ns + LONG((*(*info).dataparams).x) * $
      (*(*info).dataparams).ns 
  	spslice = ((*(*(*info).data).spdata)[ baseidx + (*(*info).dataparams).s ])
    IF (*(*info).dispswitch).imscaled THEN $
      spslice = CRISPEX_SCALING_DESCALE(spslice, $
        (*(*info).dispparams).imbscale, (*(*info).dispparams).imbzero)
    IF ((*(*info).dispswitch).scalestokes[0] AND $
        ((*(*info).dataparams).s NE 0)) THEN BEGIN
  	  cont_slice = FLOAT(REBIN(((*(*(*info).data).spdata)[baseidx])[$
        (*(*info).stokesparams).contpos[0],*], $
        (*(*info).dataparams).nlp,(*(*info).dataparams).nt))
      IF (*(*info).dispswitch).imscaled THEN $
        cont_slice = CRISPEX_SCALING_DESCALE(cont_slice, $
          (*(*info).dispparams).imbscale, (*(*info).dispparams).imbzero)
      spslice /= cont_slice
    ENDIF
    dispslice = spslice[*,t_low:t_upp]
    ; Cut up dispslice for independent scaling per diagnostic
    FOR d=0,(*(*info).intparams).ndisp_diagnostics-1 DO BEGIN
      disp_idx = (*(*(*info).intparams).wheredispdiag)[d]
      tmp_disp = dispslice[((*(*info).dispparams).lp_low_tmp[disp_idx]+$
                           (*(*(*info).intparams).diag_starts)[d]):$
                           ((*(*info).dispparams).lp_upp_tmp[disp_idx]+$
                           (*(*(*info).intparams).diag_starts)[d]-1),*]
      ; Warp slice if non-equidistant lp
      IF (*(*info).dispswitch).warpspslice[disp_idx] THEN BEGIN
        sz_tmp_disp = SIZE(tmp_disp)
        tmp_disp = INTERPOLATE(tmp_disp, $
          (*(*(*info).dispparams).xytri[0,disp_idx])[0:sz_tmp_disp[1]-1, $
                                                    t_low:t_upp], $
          (*(*(*info).dispparams).xytri[1,disp_idx])[0:sz_tmp_disp[1]-1, $
                                                    t_low:t_upp])
      ENDIF
      
    	IF ((*(*info).dispparams).slices_imscale EQ 0) THEN BEGIN
        minmax = CRISPEX_SCALING_SLICES(tmp_disp, $
          (*(*info).scaling).gamma[disp_idx],$
          (*(*info).scaling).histo_opt_val[disp_idx], $
          (*(*info).scaling).minimum[disp_idx],$
          (*(*info).scaling).maximum[disp_idx])
      ENDIF ELSE BEGIN
        IF ((*(*(*info).scaling).imagescale)[0] EQ 0) THEN $
          minmax = [(*(*info).scaling).imagemin, (*(*info).scaling).imagemax] $
        ELSE $
          minmax = [(*(*info).scaling).imagemin_curr, $
                    (*(*info).scaling).imagemax_curr]
      ENDELSE
      tmp_disp = BYTSCL(tmp_disp, MIN=minmax[0], MAX=minmax[1], /NAN)
      IF (d EQ 0) THEN $
        final_disp = tmp_disp $
      ELSE $
        final_disp = [final_disp,tmp_disp]
    ENDFOR
    *(*(*info).data).spslice = final_disp
    *(*(*info).data).spslice_congrid = $
      CONGRID( *(*(*info).data).spslice, (*(*info).dispparams).nlpreb, $
      (*(*info).dispparams).ntreb, INTERP=(*(*info).dispparams).interpspslice,$
      /CENTER)
  ENDIF ELSE $
    *(*(*info).data).spslice_congrid =  $
      CONGRID( *(*(*info).data).emptydopslice, (*(*info).dispparams).nlpreb, $
      (*(*info).dispparams).ntreb, INTERP=(*(*info).dispparams).interpspslice,$
      /CENTER)
END

PRO CRISPEX_UPDATE_REFSPSLICE, event
; Handles updating reference spectrum-time diagram
	WIDGET_CONTROL, event.TOP, GET_UVALUE = info
	IF (TOTAL(((*(*info).feedbparams).verbosity)[2:3]) GE 1) THEN $
    CRISPEX_VERBOSE_GET_ROUTINE, event
  IF ((*(*info).dispswitch).xyref_out_of_range EQ 0) THEN BEGIN
    t_low = (*(*(*info).dispparams).tsel_ref)[(*(*info).dispparams).t_low]
    t_upp = (*(*(*info).dispparams).tsel_ref)[(*(*info).dispparams).t_upp]
    baseidx = LONG((*(*info).dataparams).yref) * (*(*info).dataparams).refnx * $
      (*(*info).dataparams).refns + LONG((*(*info).dataparams).xref) * $
      (*(*info).dataparams).refns 
  	refspslice = ((*(*(*info).data).refspdata)[ $
      baseidx + (*(*info).dataparams).s_ref ])
    IF (*(*info).dispswitch).refimscaled THEN $
      refspslice = CRISPEX_SCALING_DESCALE(refspslice, $
        (*(*info).dispparams).refimbscale, (*(*info).dispparams).refimbzero)
    IF ((*(*info).dispswitch).scalestokes[1] AND $
        ((*(*info).dataparams).s_ref NE 0)) THEN BEGIN
  	  cont_slice = FLOAT(REBIN(((*(*(*info).data).refspdata)[baseidx])[$
        (*(*info).stokesparams).contpos[1],*], $
        (*(*info).dataparams).refnlp,(*(*info).dataparams).refnt))
      IF (*(*info).dispswitch).refimscaled THEN $
        cont_slice = CRISPEX_SCALING_DESCALE(cont_slice, $
          (*(*info).dispparams).refimbscale, (*(*info).dispparams).refimbzero)
      refspslice /= cont_slice
    ENDIF
    dispslice = refspslice[*,t_low:t_upp]
    FOR d=0,(*(*info).intparams).ndisp_refdiagnostics-1 DO BEGIN
      sel_idx = (*(*(*info).intparams).wheredisprefdiag)[d]
      disp_idx = (*(*info).intparams).ndiagnostics+sel_idx
      tmp_disp = dispslice[((*(*info).dispparams).lp_ref_low_tmp[sel_idx]+$
                           (*(*(*info).intparams).refdiag_starts)[d]):$
                           ((*(*info).dispparams).lp_ref_upp_tmp[sel_idx]+$
                           (*(*(*info).intparams).refdiag_starts)[d]-1),*]
      ; Warp slice if non-equidistant lp
      IF (*(*info).dispswitch).warprefspslice[sel_idx] THEN BEGIN
        sz_tmp_disp = SIZE(tmp_disp)
        tmp_disp = INTERPOLATE(tmp_disp, $
          (*(*(*info).dispparams).xytri_ref[0,sel_idx])[0:sz_tmp_disp[1]-1, $
                                                    t_low:t_upp], $
          (*(*(*info).dispparams).xytri_ref[1,sel_idx])[0:sz_tmp_disp[1]-1, $
                                                    t_low:t_upp])
      ENDIF
      IF ((*(*info).dispparams).slices_imscale EQ 0) THEN BEGIN
        refminmax = CRISPEX_SCALING_SLICES(tmp_disp, $
          (*(*info).scaling).gamma[disp_idx], $
          (*(*info).scaling).histo_opt_val[disp_idx], $
          (*(*info).scaling).minimum[disp_idx],$
          (*(*info).scaling).maximum[disp_idx])
      ENDIF ELSE BEGIN
        IF ((*(*(*info).scaling).imagescale)[1] EQ 0) THEN $
          refminmax = [(*(*info).scaling).refmin, (*(*info).scaling).refmax] $
        ELSE $
          refminmax = $
            [(*(*info).scaling).refmin_curr, (*(*info).scaling).refmax_curr]
      ENDELSE
      tmp_disp = BYTSCL(tmp_disp, MIN=refminmax[0], MAX=refminmax[1], /NAN)
      IF (d EQ 0) THEN $
        final_disp = tmp_disp $
      ELSE $
        final_disp = [final_disp,tmp_disp]
    ENDFOR
    *(*(*info).data).refspslice = final_disp
    *(*(*info).data).refspslice_congrid = $
      CONGRID( *(*(*info).data).refspslice, $
      (*(*info).dispparams).refnlpreb, (*(*info).dispparams).refntreb, $
      INTERP=(*(*info).dispparams).interpspslice, /CENTER)
  ENDIF ELSE $
    *(*(*info).data).refspslice_congrid =  $
      CONGRID( *(*(*info).data).emptydopslice, (*(*info).dispparams).refnlpreb, $
      (*(*info).dispparams).refntreb, INTERP=(*(*info).dispparams).interpspslice,$
      /CENTER)
END

PRO CRISPEX_UPDATE_SSP, event
; Handles updating the detailed spectrum
	WIDGET_CONTROL, event.TOP, GET_UVALUE = info
	IF (TOTAL(((*(*info).feedbparams).verbosity)[2:3]) GE 1) THEN $
    CRISPEX_VERBOSE_GET_ROUTINE, event
  wheres = WHERE((*(*info).stokesparams).select_sp EQ 1, count) 
  IF ((count GT 0) AND ((*(*info).dispswitch).xy_out_of_range EQ 0)) THEN BEGIN
  	FOR i=0,TOTAL((*(*info).stokesparams).select_sp)-1 DO BEGIN
  		IF ((*(*info).dataswitch).spfile EQ 1) THEN BEGIN
        spidx = LONG((*(*info).dataparams).y) * (*(*info).dataparams).nx * $
                    (*(*info).dataparams).ns + $
  				      LONG((*(*info).dataparams).x) * (*(*info).dataparams).ns 
  			ssp = ( ( *(*(*info).data).spdata)[spidx+wheres[i]] )
      ; If no spectral cube supplied, determine from image cube
  		ENDIF ELSE $
  			ssp = (*(*(*info).data).sspscan)[$
          LONG((*(*info).dataparams).x),LONG((*(*info).dataparams).y),$
          (wheres[i] * (*(*info).dataparams).nlp):$
          ((wheres[i]+1) * (*(*info).dataparams).nlp - 1)]  
      IF (*(*info).dispswitch).imscaled THEN $
        ssp = CRISPEX_SCALING_DESCALE(ssp, $
          (*(*info).dispparams).imbscale, (*(*info).dispparams).imbzero)
      ; Check for Stokes scaling and apply accordingly
      IF ((*(*info).dispswitch).scalestokes[0] AND $
          (wheres[i] NE 0)) THEN BEGIN
        cont_slice = FLOAT(REBIN((*(*(*info).data).ssp_cur[0])[$
          (*(*info).stokesparams).contpos[0],*],$
          (*(*info).dataparams).nlp,(*(*info).dataparams).nt))
        IF (*(*info).dispswitch).imscaled THEN $
          cont_slice = CRISPEX_SCALING_DESCALE(cont_slice, $
            (*(*info).dispparams).imbscale, (*(*info).dispparams).imbzero)
        ssp /= cont_slice
      ENDIF
      (*(*info).data).ssp_cur[i] = PTR_NEW(ssp)
    ENDFOR
  ENDIF
END

PRO CRISPEX_UPDATE_REFSSP, event
; Handles updating the reference detailed spectrum
	WIDGET_CONTROL, event.TOP, GET_UVALUE = info
	IF (TOTAL(((*(*info).feedbparams).verbosity)[2:3]) GE 1) THEN $
    CRISPEX_VERBOSE_GET_ROUTINE, event
  wheres = WHERE((*(*info).stokesparams).select_refsp EQ 1, count) 
  IF ((count GT 0) AND ((*(*info).dispswitch).xyref_out_of_range EQ 0)) THEN BEGIN
  	FOR i=0,TOTAL((*(*info).stokesparams).select_refsp)-1 DO BEGIN
      IF ((*(*info).dataswitch).refspfile EQ 1) THEN BEGIN
        sspidx = LONG((*(*info).dataparams).yref) * $
                    (*(*info).dataparams).refnx * (*(*info).dataparams).refns + $
                    LONG((*(*info).dataparams).xref) * $
                    (*(*info).dataparams).refns + wheres[i]
        refssp = ( ( *(*(*info).data).refspdata)[sspidx] ) 
      ; If no spectral cube supplied, determine from image cube
      ENDIF ELSE $
        refssp = REFORM((*(*(*info).data).refsspscan)[$
                  LONG((*(*info).dataparams).xref),$
                  LONG((*(*info).dataparams).yref),$
                  (wheres[i] * (*(*info).dataparams).refnlp):$
                  ((wheres[i]+1) * (*(*info).dataparams).refnlp - 1)])
      IF (*(*info).dispswitch).refimscaled THEN $
        refssp = CRISPEX_SCALING_DESCALE(refssp, $
          (*(*info).dispparams).refimbscale, (*(*info).dispparams).refimbzero)
      IF ((*(*info).dispswitch).scalestokes[1] AND $
          (wheres[i] NE 0)) THEN BEGIN
        cont_slice = FLOAT(REBIN((*(*(*info).data).refssp_cur[0])[$
          (*(*info).stokesparams).contpos[1],*],$
          (*(*info).dataparams).refnlp,(*(*info).dataparams).refnt))
        IF (*(*info).dispswitch).refimscaled THEN $
          cont_slice = CRISPEX_SCALING_DESCALE(cont_slice, $
            (*(*info).dispparams).refimbscale, (*(*info).dispparams).refimbzero)
        refssp /= cont_slice
      ENDIF
      (*(*info).data).refssp_cur[i] = PTR_NEW(refssp)
    ENDFOR
  ENDIF
END

PRO CRISPEX_UPDATE_PHISLIT_COORDS, event, PHI_ANGLE=phi_angle, $
  NO_DRAW=no_draw
; Handles the update of the slit coordinates 
	WIDGET_CONTROL, event.TOP, GET_UVALUE = info
	IF (TOTAL(((*(*info).feedbparams).verbosity)[2:3]) GE 1) THEN $
    CRISPEX_VERBOSE_GET_ROUTINE, event
  nw_prev = (*(*info).phiparams).nw_cur
  ; Failsafe necessary because of numerical accuracy
  cosval = COS(!DTOR * (*(*info).phiparams).angle)
  sinval = SIN(!DTOR * (*(*info).phiparams).angle)
  IF (((*(*info).phiparams).angle EQ 0) OR $
      ((*(*info).phiparams).angle EQ 90)) THEN BEGIN
    cosval = ROUND(cosval)
    sinval = ROUND(sinval)
  ENDIF
  x_pts = cosval * (FINDGEN( 2*(*(*info).phiparams).nphi_set/2) - $
              (*(*info).phiparams).nphi_set/2) + LONG((*(*info).dataparams).x)
  y_pts = sinval * (FINDGEN( 2*(*(*info).phiparams).nphi_set/2) - $
              (*(*info).phiparams).nphi_set/2) + LONG((*(*info).dataparams).y)
	w = WHERE((x_pts GE 0) AND (x_pts LE (*(*info).dispparams).x_last) AND $
            (y_pts GE 0) AND (y_pts LE (*(*info).dispparams).y_last), nw)
  IF (nw GT 0) THEN BEGIN
    ; Only change parameters if within xy-bounds
  	(*(*info).phiparams).nw_cur = nw
  	*(*(*info).phiparams).x_pts = REBIN(x_pts[w], nw, (*(*info).dataparams).nlp)
  	*(*(*info).phiparams).y_pts = REBIN(y_pts[w], nw, (*(*info).dataparams).nlp)
    x_pts_loc = REFORM((*(*(*info).phiparams).x_pts)[*,0])
    y_pts_loc = REFORM((*(*(*info).phiparams).y_pts)[*,0])
    ; Convert to REFERENCE if displaying
    IF (*(*info).winswitch).showref THEN BEGIN
      xyref = (*(*(*info).dataparams).pix_main2ref)[*, x_pts_loc, y_pts_loc]
      *(*(*info).phiparams).x_pts_ref = REFORM(xyref[0,*,0])
      *(*(*info).phiparams).y_pts_ref = REFORM(xyref[1,0,*])
    ENDIF
    ; Convert to SJI if displaying
    IF (TOTAL((*(*info).winswitch).showsji) GT 0) THEN BEGIN
      FOR i=0,(*(*info).winswitch).nwhereshowsji-1 DO BEGIN
        idx_sji = (*(*(*info).winswitch).whereshowsji)[i]
        xysji = (*(*(*info).dataparams).pix_main2sji[idx_sji])[*, x_pts_loc, y_pts_loc]
        *(*(*info).phiparams).x_pts_sji[idx_sji] = REFORM(xysji[0,*,0])
        *(*(*info).phiparams).y_pts_sji[idx_sji] = REFORM(xysji[1,0,*])
      ENDFOR
    ENDIF
    midphi = WHERE($
      ((*(*(*info).phiparams).x_pts)[*,0] EQ LONG((*(*info).dataparams).x)) AND $
      ((*(*(*info).phiparams).y_pts)[*,0] EQ LONG((*(*info).dataparams).y)))
  	(*(*info).phiparams).sphi = midphi +  ((*(*info).phiparams).nphi - nw)/2
    CRISPEX_UPDATE_SX, event
    CRISPEX_UPDATE_SY, event
    ; Replot axes only under conditions specified below
      ; change in nw_cur 
    IF (((*(*info).phiparams).nw_cur NE nw_prev) OR $                      
      ; while nw_cur lt nphi_set
      ((*(*info).phiparams).nw_cur NE (*(*info).phiparams).nphi_set) OR $  
      ; nw_cur becomes nphi_set
      (nw_prev NE (*(*info).phiparams).nphi_set) OR $
      ; phi angle is changed and pixels are non-square
      KEYWORD_SET(PHI_ANGLE) AND ~KEYWORD_SET(NO_DRAW)) THEN $                   
        CRISPEX_DISPLAYS_PHIS_REPLOT_AXES, event
  ENDIF
	IF (((*(*info).feedbparams).verbosity)[3] EQ 1) THEN $
    CRISPEX_VERBOSE_GET, event, [nw,midphi], labels=['nw','midphi']
END

PRO CRISPEX_UPDATE_PHISLICE, event, NO_DRAW=no_draw
; Handles the actual update of the spectral phi slit slice after change in
;  framenumber
  WIDGET_CONTROL, event.TOP, GET_UVALUE = info
	IF (TOTAL(((*(*info).feedbparams).verbosity)[2:3]) GE 1) THEN $
    CRISPEX_VERBOSE_GET_ROUTINE, event
  IF ((*(*info).dispswitch).xy_out_of_range EQ 0) THEN BEGIN
  	lp_pts = REBIN(FINDGEN(1,(*(*info).dataparams).nlp), $
      (*(*info).phiparams).nw_cur, (*(*info).dataparams).nlp)
  	tmp = INTERPOLATE( *(*(*info).data).phiscan, *(*(*info).phiparams).x_pts, $
      *(*(*info).phiparams).y_pts, lp_pts) ;$
  	phislice = (TRANSPOSE(tmp, [1,0]))
    ; If 2D, then display
    IF ((SIZE(phislice))[0] EQ 2) THEN BEGIN
      FOR d=0,(*(*info).intparams).ndisp_diagnostics-1 DO BEGIN
        disp_idx = (*(*(*info).intparams).wheredispdiag)[d]
        tmp_disp = phislice[((*(*info).dispparams).lp_low_tmp[disp_idx]+$
                             (*(*(*info).intparams).diag_starts)[d]):$
                             ((*(*info).dispparams).lp_upp_tmp[disp_idx]+$
                             (*(*(*info).intparams).diag_starts)[d]-1),*]
        ; Warp slice if non-equidistant lp
        IF (*(*info).dispswitch).warpspslice[disp_idx] THEN BEGIN
          sz_tmp_disp = SIZE(tmp_disp)
          tmp_disp = INTERPOLATE(tmp_disp, $
            (*(*(*info).dispparams).phisxytri[0,disp_idx])[$
              0:sz_tmp_disp[1]-1,0:sz_tmp_disp[2]-1], $
            (*(*(*info).dispparams).phisxytri[1,disp_idx])[$
              0:sz_tmp_disp[1]-1,0:sz_tmp_disp[2]-1])
        ENDIF
      	IF ((*(*info).dispparams).slices_imscale EQ 0) THEN BEGIN
          minmax = CRISPEX_SCALING_SLICES(tmp_disp, $
            (*(*info).scaling).gamma[disp_idx],$
          (*(*info).scaling).histo_opt_val[disp_idx], $
            (*(*info).scaling).minimum[disp_idx],$
          (*(*info).scaling).maximum[disp_idx])
        ENDIF ELSE BEGIN
          IF ((*(*(*info).scaling).imagescale)[0] EQ 0) THEN $
            minmax = [(*(*info).scaling).imagemin, (*(*info).scaling).imagemax] $
          ELSE $
            minmax = [(*(*info).scaling).imagemin_curr, $
                      (*(*info).scaling).imagemax_curr]
        ENDELSE
        tmp_disp = BYTSCL(tmp_disp, MIN=minmax[0], MAX=minmax[1], /NAN)
        IF (d EQ 0) THEN $
          final_disp = tmp_disp $
        ELSE $
          final_disp = [final_disp,tmp_disp]
      ENDFOR
      *(*(*info).data).phislice = final_disp
    ENDIF ELSE *(*(*info).data).phislice = phislice
  ENDIF
  IF ~KEYWORD_SET(NO_DRAW) THEN CRISPEX_DRAW, event
END

PRO CRISPEX_UPDATE_LP, event, NO_LOOP_GET=no_loop_get
; Handles the update of displayed data after change in spectral position
	WIDGET_CONTROL, event.TOP, GET_UVALUE = info
	IF (TOTAL(((*(*info).feedbparams).verbosity)[2:3]) GE 1) THEN $
    CRISPEX_VERBOSE_GET_ROUTINE, event
	IF (*(*info).overlayswitch).loopslit AND ((*(*info).loopparams).np GT 0) THEN BEGIN
    IF ~KEYWORD_SET(NO_LOOP_GET) THEN CRISPEX_LOOP_GET, event
    IF ((*(*info).winswitch).showloop AND ((*(*info).loopparams).nw_lpts NE 0)) THEN BEGIN
  		IF (*(*info).dispswitch).exts THEN $
        *(*(*info).loopsdata).loopslice = (*(*(*info).loopsdata).loopslab)[*,*,$
          (*(*info).dataparams).lp-(*(*info).dispparams).lp_low] $
      ELSE $
  			*(*(*info).loopsdata).loopslice = (*(*(*info).loopsdata).loopslab)[*,*,$
          (*(*info).dataparams).lp]
      IF ((*(*info).loopparams).nw_lpts NE 1) THEN $
        *(*(*info).loopsdata).loopslice = REFORM(*(*(*info).loopsdata).loopslice)
    ENDIF
		IF ((*(*info).winswitch).showrefloop AND $
       ((*(*info).loopparams).nw_lpts_ref NE 0)) THEN BEGIN
			IF (*(*info).dispswitch).refexts THEN $
        *(*(*info).loopsdata).refloopslice = REFORM((*(*(*info).loopsdata).refloopslab)[*,*,$
          (*(*info).dataparams).lp_ref-(*(*info).dispparams).lp_ref_low]) $
      ELSE $
				*(*(*info).loopsdata).refloopslice = REFORM((*(*(*info).loopsdata).refloopslab)[*,*,$
          (*(*info).dataparams).lp_ref])
      IF ((*(*info).loopparams).nw_lpts_ref NE 1) THEN $
        *(*(*info).loopsdata).refloopslice = REFORM(*(*(*info).loopsdata).refloopslice)
		ENDIF
	ENDIF
	IF (*(*info).winswitch).showrestloop THEN $
    FOR k=0,N_ELEMENTS(*(*(*info).restoreparams).disp_loopnr)-1 DO BEGIN
		IF (SIZE(*(*(*(*info).loopsdata).rest_loopslab[k]),/N_DIMENSIONS) EQ 3) THEN BEGIN
			IF (*(*(*info).restoreparams).disp_imref)[k] THEN $
        *(*(*(*info).loopsdata).rest_loopslice[k]) = $
          (*(*(*(*info).loopsdata).rest_loopslab[k]))[*,*,(*(*info).dataparams).lp_ref-$
				    (*(*info).dispparams).lp_ref_low] $
      ELSE $
        *(*(*(*info).loopsdata).rest_loopslice[k]) = $
          (*(*(*(*info).loopsdata).rest_loopslab[k]))[*,*,(*(*info).dataparams).lp-$
            (*(*info).dispparams).lp_low]
      IF ((SIZE(*(*(*(*info).loopsdata).rest_loopslice[k])))[1] NE 1) THEN $
        *(*(*(*info).loopsdata).rest_loopslice[k]) = $
          REFORM(*(*(*(*info).loopsdata).rest_loopslice[k]))
		ENDIF ELSE BEGIN
			IF (*(*(*info).restoreparams).disp_imref)[k] THEN $
        *(*(*(*info).loopsdata).rest_loopslice[k]) = *(*(*(*info).loopsdata).rest_loopslab[k]) $
      ELSE $
				*(*(*(*info).loopsdata).rest_loopslice[k]) = *(*(*(*info).loopsdata).rest_loopslab[k])
		ENDELSE
	ENDFOR
	IF (*(*info).winswitch).showretrdet THEN BEGIN
    *(*(*info).loopsdata).det_loopslice = REFORM((*(*(*info).loopsdata).det_loopslab)[*,*,$
      (*(*info).dataparams).lp-(*(*info).dispparams).lp_low])
  ENDIF
  CRISPEX_SCALING_APPLY_SELECTED, event
END

PRO CRISPEX_UPDATE_T, event
; Handles the updated of displayed data after change in framenumber
	WIDGET_CONTROL, event.TOP, GET_UVALUE = info
	IF (TOTAL(((*(*info).feedbparams).verbosity)[2:3]) GE 1) THEN $
    CRISPEX_VERBOSE_GET_ROUTINE, event
  ; Update time indices
  IF ((*(*info).dataparams).mainnt GT 1) THEN $
    (*(*info).dispparams).t_main = $
      (*(*(*info).dispparams).tsel_main)[(*(*info).dispparams).t]
  IF ((*(*info).dataparams).refnt GT 1) THEN $
    (*(*info).dispparams).t_ref = $
      (*(*(*info).dispparams).tsel_ref)[(*(*info).dispparams).t]
	IF (*(*info).winswitch).showdop THEN BEGIN
		(*(*info).dataparams).lp_dop = $
      2*(*(*info).dataparams).lc - (*(*info).dataparams).lp
		(*(*info).dispswitch).drawdop = $
      (((*(*info).dataparams).lp_dop GE (*(*info).dispparams).lp_low) AND $
       ((*(*info).dataparams).lp_dop LE (*(*info).dispparams).lp_upp) AND $
       ((*(*info).dataparams).lp_dop NE (*(*info).dataparams).lc)) 
	ENDIF
  scalestokes_main = ((*(*info).dispswitch).scalestokes[0] AND $
                      ((*(*info).dataparams).s NE 0))
  scalestokes_ref = ((*(*info).dispswitch).scalestokes[1] AND $
                      ((*(*info).dataparams).s_ref NE 0))
  ; Determine main image, in case the cube has a spectral dimension
  basecubeidx = (*(*info).dispparams).t_main * (*(*info).dataparams).nlp * $
    (*(*info).dataparams).ns+ (*(*info).dataparams).s * (*(*info).dataparams).nlp
	*(*(*info).data).xyslice = (*(*(*info).data).imagedata)[$
    basecubeidx + (*(*info).dataparams).lp]
  IF (*(*info).dispswitch).imscaled THEN *(*(*info).data).xyslice = $
    CRISPEX_SCALING_DESCALE(*(*(*info).data).xyslice, $
      (*(*info).dispparams).imbscale, (*(*info).dispparams).imbzero)
  ; Process Stokes scaling
  IF (*(*info).dispswitch).scalestokes[0] THEN BEGIN
    cont_slice = FLOAT((*(*(*info).data).imagedata)[$
        (*(*info).dispparams).t_main * (*(*info).dataparams).nlp * $
        (*(*info).dataparams).ns + (*(*info).stokesparams).contpos[0]]) 
    IF (*(*info).dispswitch).imscaled THEN $
      cont_slice = CRISPEX_SCALING_DESCALE(cont_slice, $
        (*(*info).dispparams).imbscale, (*(*info).dispparams).imbzero)
  ENDIF ELSE $
    cont_slice = REBIN(REPLICATE(1,(*(*info).dataparams).nx),$
      (*(*info).dataparams).nx, (*(*info).dataparams).ny)
  ; Scale the image if need be
  IF scalestokes_main THEN $
    *(*(*info).data).xyslice /= cont_slice 
  ; Get noise level
  FOR s=0,(*(*info).dataparams).ns-1 DO BEGIN
    tmp_im = (*(*(*info).data).imagedata)[$
      (*(*info).dispparams).t_main * (*(*info).dataparams).nlp * $
      (*(*info).dataparams).ns + s * (*(*info).dataparams).nlp + $
      (*(*info).stokesparams).contpos[0]]
    IF (*(*info).dispswitch).imscaled THEN $
      tmp_im = CRISPEX_SCALING_DESCALE(tmp_im, $
        (*(*info).dispparams).imbscale, (*(*info).dispparams).imbzero)
    (*(*info).stokesparams).noise[s] = STDDEV(tmp_im/cont_slice, /NAN)
  ENDFOR
	IF ((*(*info).winswitch).showdop AND $
      (*(*info).dispswitch).drawdop) THEN BEGIN
		temp_xyslice =  (*(*(*info).data).imagedata)[$
      basecubeidx + (*(*info).dataparams).lp_dop]
    IF (*(*info).dispswitch).imscaled THEN $
      tmp_xyslice = CRISPEX_SCALING_DESCALE(tmp_xyslice, $
        (*(*info).dispparams).imbscale, (*(*info).dispparams).imbzero)
    IF scalestokes_main THEN temp_xyslice /= cont_slice
  ENDIF
  
  ; Determine Doppler image
	IF ((*(*info).winswitch).showdop AND (*(*info).dispswitch).drawdop) THEN BEGIN
		IF ((*(*info).dataparams).lp_dop GT (*(*info).dataparams).lc) THEN $
      *(*(*info).data).dopslice = temp_xyslice - *(*(*info).data).xyslice $
    ELSE $
      *(*(*info).data).dopslice = *(*(*info).data).xyslice - temp_xyslice 
	ENDIF
 
  ; Determine reference image
	IF ((*(*info).winswitch).showref OR (*(*info).winswitch).showimref) THEN BEGIN
		IF (((*(*info).dataparams).refnlp GE 1) AND $
        ((*(*info).dataparams).refnt GE 1)) THEN BEGIN
        ; If both refnlp > 1 and refnt > 1
      refidx = (*(*info).dispparams).t_ref * (*(*info).dataparams).refnlp * $
        (*(*info).dataparams).refns + (*(*info).dataparams).s_ref * $
        (*(*info).dataparams).refnlp + (*(*info).dataparams).lp_ref
      *(*(*info).data).refslice = (*(*(*info).data).refdata)[refidx]
      IF (*(*info).dispswitch).refimscaled THEN $
        *(*(*info).data).refslice = CRISPEX_SCALING_DESCALE($
          *(*(*info).data).refslice, (*(*info).dispparams).refimbscale, $
          (*(*info).dispparams).refimbzero)
      ; Process Stokes scaling
      IF (*(*info).dispswitch).scalestokes[1] THEN BEGIN
        cont_slice = FLOAT((*(*(*info).data).refdata)[$
            (*(*info).dispparams).t_ref * (*(*info).dataparams).refnlp * $
            (*(*info).dataparams).refns + (*(*info).stokesparams).contpos[1]]) 
        IF (*(*info).dispswitch).refimscaled THEN $
          cont_slice = CRISPEX_SCALING_DESCALE(cont_slice, $
            (*(*info).dispparams).refimbscale, (*(*info).dispparams).refimbzero)
      ENDIF ELSE $
        cont_slice = REBIN(REPLICATE(1,(*(*info).dataparams).refnx),$
          (*(*info).dataparams).refnx, (*(*info).dataparams).refny)
      ; Scale the image if need be
      IF scalestokes_ref THEN $
        *(*(*info).data).refslice /= cont_slice
      ; Get noise level
      FOR s=0,(*(*info).dataparams).refns-1 DO BEGIN
        tmp_refim = (*(*(*info).data).refdata)[$
            (*(*info).dispparams).t_ref * (*(*info).dataparams).refnlp * $
            (*(*info).dataparams).refns + s * (*(*info).dataparams).refnlp + $
            (*(*info).stokesparams).contpos[1]]
        IF (*(*info).dispswitch).refimscaled THEN $
          tmp_refim = CRISPEX_SCALING_DESCALE(tmp_refim, $
            (*(*info).dispparams).refimbscale, (*(*info).dispparams).refimbzero)
        (*(*info).stokesparams).noise_ref[s] = STDDEV(tmp_refim/cont_slice, /NAN)
      ENDFOR
		ENDIF ELSE $
        *(*(*info).data).refslice = (*(*(*info).data).refdata) 
	ENDIF

  ; Determine mask image
	IF (*(*info).dataswitch).maskfile THEN BEGIN
		IF ((*(*info).dataparams).masknt GT 1) THEN BEGIN
      *(*(*info).data).maskslice = (*(*(*info).data).maskdata)[$
        (*(*info).dispparams).t_main]
		ENDIF ELSE BEGIN
      *(*(*info).data).maskslice = (*(*(*info).data).maskdata)[0]
		ENDELSE
	ENDIF
  
  ; Determine sji image
	IF ((*(*info).dataswitch).sjifile AND $
    (TOTAL((*(*info).winswitch).showsji) GT 0)) THEN BEGIN
    FOR idx_sji=0,(*(*info).dataparams).nsjifiles-1 DO BEGIN
  		IF ((*(*info).dataparams).sjint[idx_sji] GT 1) THEN BEGIN
        (*(*info).dispparams).t_sji[idx_sji] = $
          (*(*(*info).dispparams).tsel_sji[idx_sji])[(*(*info).dispparams).t]
        sjislice_tmp =  $
          ((*(*(*info).data).sjidata[idx_sji])[(*(*info).dispparams).t_sji[idx_sji]]) 
      ENDIF ELSE $
          sjislice_tmp = ((*(*(*info).data).sjidata[idx_sji])[0])
      ; If SJI data is scaled integer, descale and convert to float
      IF (*(*info).dispswitch).sjiscaled[idx_sji] THEN $
        sjislice_tmp = CRISPEX_SCALING_DESCALE(sjislice_tmp, $
          (*(*info).dispparams).sjibscale[idx_sji], $
          (*(*info).dispparams).sjibzero[idx_sji])
      *(*(*info).data).sjislice[idx_sji] = sjislice_tmp
    ENDFOR
	ENDIF
END

PRO CRISPEX_UPDATE_SX, event
; Handles the change in xy- and reference image x-position slider
	WIDGET_CONTROL, event.TOP, GET_UVALUE = info
	IF (TOTAL(((*(*info).feedbparams).verbosity)[2:3]) GE 1) THEN $
    CRISPEX_VERBOSE_GET_ROUTINE, event
  sx = CRISPEX_TRANSFORM_DATA2DEVICE(info, X_IN=(*(*info).dataparams).x, /MAIN)
  sxp = CRISPEX_TRANSFORM_DATA2DEVICE(info, X_IN=*(*(*info).loopparams).xp, $
    /MAIN)
  sxr = CRISPEX_TRANSFORM_DATA2DEVICE(info, X_IN=*(*(*info).loopparams).xr, $
    /MAIN)
	(*(*info).curs).sxlock = sx.x
	(*(*info).curs).sx = sx.x
	*(*(*info).overlayparams).sxp = sxp.x
	*(*(*info).overlayparams).sxr = sxr.x
  IF (*(*info).winswitch).showphis THEN BEGIN
    sx_pts = CRISPEX_TRANSFORM_DATA2DEVICE(info, $
      X_IN=REFORM((*(*(*info).phiparams).x_pts)[*,0]), /MAIN)
    *(*(*info).overlayparams).sx_pts = sx_pts.x
  ENDIF
  IF (TOTAL((*(*info).winswitch).showsji) GT 0) THEN BEGIN
    FOR i=0,(*(*info).winswitch).nwhereshowsji-1 DO BEGIN
      idx_sji = (*(*(*info).winswitch).whereshowsji)[i]
      sxsji = CRISPEX_TRANSFORM_DATA2DEVICE(info, $
        X_IN=(*(*info).dataparams).xsji[idx_sji], /SJI, IDX_SJI=idx_sji)
    	(*(*info).curs).sxsji[idx_sji] = sxsji.x
    	(*(*info).curs).sxsjilock[idx_sji] = sxsji.x
      IF (*(*info).winswitch).showphis THEN BEGIN
        sx_pts_sji = CRISPEX_TRANSFORM_DATA2DEVICE(info, $
          X_IN=(*(*(*info).phiparams).x_pts_sji[idx_sji]), /SJI, $
          IDX_SJI=idx_sji)
        *(*(*info).overlayparams).sx_pts_sji[idx_sji] = sx_pts_sji.x
      ENDIF
    ENDFOR
  ENDIF
  IF (*(*info).winswitch).showref THEN BEGIN
    sxref = CRISPEX_TRANSFORM_DATA2DEVICE(info, $
      X_IN=(*(*info).dataparams).xref, /REFERENCE)
    sxpref = CRISPEX_TRANSFORM_DATA2DEVICE(info, $
      X_IN=*(*(*info).loopparams).xp_ref, /REFERENCE)
    sxrref = CRISPEX_TRANSFORM_DATA2DEVICE(info, $
      X_IN=*(*(*info).loopparams).xr_ref, /REFERENCE)
  	(*(*info).curs).sxref = sxref.x
    (*(*info).curs).sxreflock = sxref.x
  	*(*(*info).overlayparams).sxp_ref = sxpref.x
  	*(*(*info).overlayparams).sxr_ref = sxrref.x
    IF (*(*info).winswitch).showphis THEN BEGIN
      sx_pts_ref = CRISPEX_TRANSFORM_DATA2DEVICE(info, $
        X_IN=(*(*(*info).phiparams).x_pts_ref), /REFERENCE)
      *(*(*info).overlayparams).sx_pts_ref = sx_pts_ref.x
    ENDIF
  ENDIF
	IF (((*(*info).feedbparams).verbosity)[3] EQ 1) THEN $
    CRISPEX_VERBOSE_GET,event,$
      [(*(*info).dataparams).x,(*(*info).curs).sxlock,(*(*info).curs).sx],$
      labels=['x','sxlock','sx']
END

PRO CRISPEX_UPDATE_SY, event
; Handles the change in xy- and reference image y-position slider
	WIDGET_CONTROL, event.TOP, GET_UVALUE = info
	IF (TOTAL(((*(*info).feedbparams).verbosity)[2:3]) GE 1) THEN $
    CRISPEX_VERBOSE_GET_ROUTINE, event
  sy = CRISPEX_TRANSFORM_DATA2DEVICE(info, Y_IN=(*(*info).dataparams).y, /MAIN)
  syp = CRISPEX_TRANSFORM_DATA2DEVICE(info, Y_IN=*(*(*info).loopparams).yp, $
    /MAIN)
  syr = CRISPEX_TRANSFORM_DATA2DEVICE(info, Y_IN=*(*(*info).loopparams).yr, $
    /MAIN)
	(*(*info).curs).sylock = sy.y
	(*(*info).curs).sy = sy.y
	*(*(*info).overlayparams).syp = syp.y
	*(*(*info).overlayparams).syr = syr.y
  IF (*(*info).winswitch).showphis THEN BEGIN
    sy_pts = CRISPEX_TRANSFORM_DATA2DEVICE(info, $
      Y_IN=REFORM((*(*(*info).phiparams).y_pts)[*,0]), /MAIN)
    *(*(*info).overlayparams).sy_pts = sy_pts.y
  ENDIF
  IF (TOTAL((*(*info).winswitch).showsji) GT 0) THEN BEGIN
    FOR i=0,(*(*info).winswitch).nwhereshowsji-1 DO BEGIN
      idx_sji = (*(*(*info).winswitch).whereshowsji)[i]
      sysji = CRISPEX_TRANSFORM_DATA2DEVICE(info, $
        Y_IN=(*(*info).dataparams).ysji[idx_sji], /SJI, IDX_SJI=idx_sji)
    	(*(*info).curs).sysji[idx_sji] = sysji.y
    	(*(*info).curs).sysjilock[idx_sji] = sysji.y
      IF (*(*info).winswitch).showphis THEN BEGIN
        sy_pts_sji = CRISPEX_TRANSFORM_DATA2DEVICE(info, $
          Y_IN=(*(*(*info).phiparams).y_pts_sji[idx_sji]), /SJI, $
          IDX_SJI=idx_sji)
        *(*(*info).overlayparams).sy_pts_sji[idx_sji] = sy_pts_sji.y
      ENDIF
    ENDFOR
  ENDIF
  IF (*(*info).winswitch).showref THEN BEGIN
    syref = CRISPEX_TRANSFORM_DATA2DEVICE(info, $
      Y_IN=(*(*info).dataparams).yref, /REFERENCE)
    sypref = CRISPEX_TRANSFORM_DATA2DEVICE(info, $
      Y_IN=*(*(*info).loopparams).yp_ref, /REFERENCE)
    syrref = CRISPEX_TRANSFORM_DATA2DEVICE(info, $
      Y_IN=*(*(*info).loopparams).yr_ref, /REFERENCE)
  	(*(*info).curs).syref = syref.y
  	(*(*info).curs).syreflock = syref.y
  	*(*(*info).overlayparams).syp_ref = sypref.y
  	*(*(*info).overlayparams).syr_ref = syrref.y
    IF (*(*info).winswitch).showphis THEN BEGIN
      sy_pts_ref = CRISPEX_TRANSFORM_DATA2DEVICE(info, $
        Y_IN=(*(*(*info).phiparams).y_pts_ref), /REFERENCE)
      *(*(*info).overlayparams).sy_pts_ref = sy_pts_ref.y
    ENDIF
  ENDIF
	IF (((*(*info).feedbparams).verbosity)[3] EQ 1) THEN $
    CRISPEX_VERBOSE_GET,event,$
      [(*(*info).dataparams).y,(*(*info).curs).sylock,(*(*info).curs).sy],$
      labels=['y','sylock','sy']
END

PRO CRISPEX_UPDATE_USER_FEEDBACK, event, title=title, var=var, minvar=minvar, $
  maxvar=maxvar, feedback_text=feedback_text, destroy_top=destroy_top, $
  close_button=close_button, session=session
; Handles the update of user feedback while saving timeslices
	WIDGET_CONTROL, event.TOP, GET_UVALUE = info
	IF (TOTAL(((*(*info).feedbparams).verbosity)[2:3]) GE 1) THEN $
    CRISPEX_VERBOSE_GET_ROUTINE, event
	IF (N_ELEMENTS(MINVAR) LT 1) THEN minvar = 0
	IF (var EQ minvar) THEN BEGIN
		CRISPEX_WINDOW_USER_FEEDBACK, event, title, feedback_text+'     ', $
      close_button=close_button, session=session
		IF KEYWORD_SET(DESTROY_TOP) THEN BEGIN
			WIDGET_CONTROL, (*(*info).winids).feedbacktlb, SET_UVALUE = info
			WIDGET_CONTROL, event.TOP, /DESTROY
			event.TOP = (*(*info).winids).feedbacktlb
		ENDIF
	ENDIF ELSE BEGIN
		WIDGET_CONTROL,(*(*info).ctrlsfeedb).feedback_text, SET_VALUE = feedback_text
		IF KEYWORD_SET(CLOSE_BUTTON) THEN $
      WIDGET_CONTROL, (*(*info).ctrlsfeedb).close_button, SENSITIVE = 0
	ENDELSE
	IF (((*(*info).feedbparams).verbosity)[3] EQ 1) THEN $
    CRISPEX_VERBOSE_GET, event, [feedback_text], labels=['Feedback text']
END

PRO CRISPEX_UPDATE_STARTUP_FEEDBACK, bgim, xout, yout, feedback_text
	LOADCT,1,/SILENT
	TVSCL,bgim^0.4
	LOADCT,0,/SILENT
	FOR i=0,N_ELEMENTS(feedback_text)-1 DO $
    XYOUTS, xout[i], yout[i], feedback_text[i], COLOR=255, $
    /DEVICE, CHARSIZE=1.125, CHARTHICK=thick
END

PRO CRISPEX_UPDATE_STARTUP_SETUP_FEEDBACK, msg, OVERWRITEABLE=overwriteable, DONE=done, OPT=opt, $
                                           WIDGET=widget, NEWLINE=newline, FAILED=failed, $
                                           REPEAT_STAGE=repeat_stage, NO_ROUTINE=no_routine, $
                                           WARNING=warning, ERROR=error
  routine = 'CRISPEX SETUP: '
  stages = [KEYWORD_SET(OPT),KEYWORD_SET(WIDGET),KEYWORD_SET(WARNING),KEYWORD_SET(ERROR)]
  stage_set = (WHERE(stages EQ 1))[0]+1
  stage_lab = ['','Setting start-up options ','Setting up widget ','WARNING: ','ERROR: ']
  IF KEYWORD_SET(NO_ROUTINE) THEN routine = STRJOIN(REPLICATE(' ',STRLEN(routine)))
  IF KEYWORD_SET(FAILED) THEN donetext = 'failed.' ELSE donetext = 'done!'
  IF KEYWORD_SET(REPEAT_STAGE) THEN outputtext = routine+stage_lab[stage_set]+msg+'... ' $
    ELSE outputtext = ''
  IF KEYWORD_SET(OVERWRITEABLE) THEN BEGIN
    IF KEYWORD_SET(DONE) THEN BEGIN
	    WRITEU,-1,outputtext+donetext
      PRINT,''
    ENDIF ELSE WRITEU,-1,routine+stage_lab[stage_set]+msg+'... '
  ENDIF ELSE BEGIN
    IF KEYWORD_SET(NEWLINE) THEN PRINT,''
    FOR i=0,N_ELEMENTS(msg)-1 DO BEGIN
      IF (i NE 0) THEN temp_routine = STRJOIN(REPLICATE(' ',STRLEN(routine))) $
        ELSE temp_routine = routine
      PRINT, temp_routine+stage_lab[stage_set]+msg[i]
    ENDFOR
  ENDELSE
END

;========================= VERBOSE PROCEDURES
PRO CRISPEX_VERBOSE_GET, event, variables, labels=labels
; Displays feedback of variables structuredly 
	WIDGET_CONTROL, event.TOP, GET_UVALUE = info
	nvars = N_ELEMENTS(variables)
	IF ((*(*info).feedbparams).last_routine_count NE 0) THEN PRINT,''
	IF (N_ELEMENTS(labels) EQ nvars) THEN BEGIN
		maxchar = MAX(STRLEN(labels))
		FOR i=0,nvars-1 DO BEGIN
			IF (STRLEN(labels[i]) NE maxchar) THEN whitespace = STRJOIN(REPLICATE(' ',(maxchar-STRLEN(labels[i])))) ELSE whitespace = ''
			PRINT,STRJOIN(REPLICATE('  ',SCOPE_LEVEL()-2))+'> '+labels[i]+whitespace+': '+STRTRIM(variables[i],2)
		ENDFOR
	ENDIF ELSE BEGIN
		FOR i=0,nvars-1 DO HELP, variables[i]
	ENDELSE
END

PRO CRISPEX_VERBOSE_GET_ROUTINE, event, rname, IGNORE_LAST=ignore_last
	WIDGET_CONTROL, event.TOP, GET_UVALUE = info
	prespace = STRJOIN(REPLICATE('  ',SCOPE_LEVEL()-2))
  rname = (SCOPE_TRACEBACK(/STRUCTURE))[N_ELEMENTS(SCOPE_TRACEBACK(/STRUCTURE))-2].ROUTINE
	IF KEYWORD_SET(IGNORE_LAST) THEN (*(*info).feedbparams).last_routine = ''
	IF ((rname NE (*(*info).feedbparams).last_routine) AND $
    ((*(*info).feedbparams).last_routine_count GT 0)) THEN PRINT,''
	IF (rname EQ (*(*info).feedbparams).last_routine) THEN $
    (*(*info).feedbparams).last_routine_count += 1 $
  ELSE $
    (*(*info).feedbparams).last_routine_count = 0
	IF ((*(*info).feedbparams).last_routine_count GT 0) THEN $
    rcount = ' x '+STRTRIM((*(*info).feedbparams).last_routine_count,2)+'.' $
  ELSE $
    rcount = '.'
	IF (rname NE (*(*info).feedbparams).last_routine) THEN $
    PRINT,prespace+'CRISPEX RUN: Called '+rname+'.' $
  ELSE $
		WRITEU,-1,STRING(FORMAT='(%"\r'+prespace+'CRISPEX RUN: Called ",a'+$
      STRTRIM(STRLEN(rname),2)+',a'+STRTRIM(STRLEN(rcount),2)+')',rname,rcount) 
	(*(*info).feedbparams).last_routine = rname
END

PRO CRISPEX_VERBOSE_SET, event
	WIDGET_CONTROL, event.TOP, GET_UVALUE = info
	IF (TOTAL(((*(*info).feedbparams).verbosity)[2:3]) GE 1) THEN $
    CRISPEX_VERBOSE_GET_ROUTINE, event
	WIDGET_CONTROL, event.ID, GET_UVALUE = add_verbosity
	tmp_verbosity = (*(*info).feedbparams).verbosity
	IF (add_verbosity EQ -1) THEN (*(*info).feedbparams).verbosity = INTARR(N_ELEMENTS((*(*info).feedbparams).verbosity)) ELSE BEGIN
		tmp_verbosity[add_verbosity] = ABS((tmp_verbosity[add_verbosity] EQ 1) - 1)
		(*(*info).feedbparams).verbosity = tmp_verbosity
	ENDELSE
	CRISPEX_VERBOSE_SET_BUTTONS, event
	IF (((*(*info).feedbparams).verbosity)[3] EQ 1) THEN $
    CRISPEX_VERBOSE_GET, event, [add_verbosity], labels=['Verbosity level']
END

PRO CRISPEX_VERBOSE_SET_BUTTONS, event
	WIDGET_CONTROL, event.TOP, GET_UVALUE = info
	IF (TOTAL(((*(*info).feedbparams).verbosity)[2:3]) GE 1) THEN $
    CRISPEX_VERBOSE_GET_ROUTINE, event
	WIDGET_CONTROL,(*(*(*info).ctrlscp).verbose_set)[0], SET_BUTTON = (TOTAL((*(*info).feedbparams).verbosity) EQ 0)
	WIDGET_CONTROL,(*(*(*info).ctrlscp).verbose_set)[1], SET_BUTTON = ((*(*info).feedbparams).verbosity)[2]
	WIDGET_CONTROL,(*(*(*info).ctrlscp).verbose_set)[2], SET_BUTTON = ((*(*info).feedbparams).verbosity)[3]
	WIDGET_CONTROL,(*(*(*info).ctrlscp).verbose_set)[3], SET_BUTTON = ((*(*info).feedbparams).verbosity)[4]
END

;========================= GENERAL WINDOW PROCEDURES
PRO CRISPEX_WINDOW, xsize, ysize, leader, title, base, wid, xoffset, yoffset, $
                    DRAWID=drawid, DRAWBASE=disp, XSCROLL=xscroll, $
                    YSCROLL=yscroll, SCROLL=scroll, RESIZING=resizing, $
                    RES_HANDLER=res_handler, $
                    NO_TLB_KILL_REQUEST=no_tlb_kill_request, $
                    REFERENCE=reference, SJI=sji, CTBAR_SHOW=ctbar_show, $
                    CTBAR_DRAWID=ctbar_drawid
; Sets up the display windows
	IF (N_ELEMENTS(RESIZING) EQ 0) THEN resizing = 0
	IF (N_ELEMENTS(LEADER) EQ 0) THEN $
    base = WIDGET_BASE(TITLE=title, TLB_FRAME_ATTR=1, $
      TLB_KILL_REQUEST_EVENTS=~KEYWORD_SET(NO_TLB_KILL_REQUEST), $
      TLB_SIZE_EVENTS=resizing) $
  ELSE $
		base = WIDGET_BASE(TITLE=STRTRIM(title), GROUP_LEADER=leader, $
      /TLB_FRAME_ATTR, TLB_KILL_REQUEST_EVENTS=~KEYWORD_SET(NO_TLB_KILL_REQUEST),$
      TLB_SIZE_EVENTS=resizing)
	disp = WIDGET_BASE(base, /COLUMN)
  IF KEYWORD_SET(CTBAR_SHOW) THEN BEGIN
    ; CTBAR draw base on top by default, unless xsize is much smaller than ysize
    ratio = xsize / FLOAT(ysize)
    ctbar_init = (((ratio GT 5.) OR (ratio LT 0.2)) OR (xsize LT 0.5*ysize))
    IF ctbar_init THEN BEGIN
      ; CTBAR on right side of image
      ctbar_width = 75
      ctbar_height = ysize
    ENDIF ELSE BEGIN
      ; CTBAR on right side of image
      ctbar_width = xsize
      ctbar_height = 50
      draw_ctbar_base = WIDGET_BASE(disp,/ROW)
      ctbar_drawid = WIDGET_DRAW(draw_ctbar_base, XSIZE=ctbar_width, $
                      YSIZE=ctbar_height, RETAIN=2)
    ENDELSE
  ENDIF
  IF KEYWORD_SET(SCROLL) THEN BEGIN
    draw_verslid_base = WIDGET_BASE(disp,/ROW)
    draw_horslid_base = WIDGET_BASE(disp,/ROW)
  ENDIF ELSE draw_verslid_base = disp
	drawid = WIDGET_DRAW(draw_verslid_base, XSIZE=xsize, YSIZE=ysize, RETAIN=2)
  IF KEYWORD_SET(CTBAR_SHOW) THEN BEGIN
    IF ctbar_init THEN $
      ctbar_drawid = WIDGET_DRAW(draw_verslid_base, XSIZE=ctbar_width, $
                      YSIZE=ctbar_height, RETAIN=2)
  ENDIF
  IF KEYWORD_SET(SCROLL) THEN BEGIN
    IF KEYWORD_SET(REFERENCE) THEN BEGIN
      xscroll_pro = 'CRISPEX_SLIDER_XPOS_REF'
      yscroll_pro = 'CRISPEX_SLIDER_YPOS_REF'
    ENDIF ELSE IF KEYWORD_SET(SJI) THEN BEGIN
      xscroll_pro = 'CRISPEX_SLIDER_XPOS_SJI'
      yscroll_pro = 'CRISPEX_SLIDER_YPOS_SJI'
    ENDIF ELSE BEGIN
      xscroll_pro = 'CRISPEX_SLIDER_XPOS'
      yscroll_pro = 'CRISPEX_SLIDER_YPOS'
    ENDELSE
    yscroll = WIDGET_SLIDER(draw_verslid_base,VALUE=0,MIN=0,MAX=1,/SUPPRESS,/DRAG,$
                            EVENT_PRO=yscroll_pro,/VERTICAL, YSIZE=ysize)
    xscroll = WIDGET_SLIDER(draw_horslid_base,VALUE=0,MIN=0,MAX=1,/SUPPRESS,/DRAG,$
                            EVENT_PRO=xscroll_pro, $
                            XSIZE=xsize+ctbar_init*ctbar_width)
  ENDIF
	WIDGET_CONTROL, base, /REALIZE, TLB_SET_XOFFSET=xoffset, TLB_SET_YOFFSET=yoffset
	IF (N_ELEMENTS(RES_HANDLER) GT 0) THEN $
    XMANAGER, 'CRISPEX', base, EVENT_HANDLER = res_handler, /NO_BLOCK $
  ELSE $
    XMANAGER, 'CRISPEX', base, /NO_BLOCK
	WIDGET_CONTROL, drawid, GET_VALUE = wid
END

PRO CRISPEX_WINDOW_OK, event, title, message1, OK_EVENT=ok_event, $
  CANCEL_EVENT=cancel_event, CANCEL_LABEL=cancel_label, BASE=base, $
  BLOCK=block, NO_SHOW_EVENT=no_show_event, $
  NO_SHOW_CHOICES=no_show_choices, SET_CHOICE_IDX=set_choice_idx
; Sets up the message windows with only an OK-button
	WIDGET_CONTROL, event.TOP, GET_UVALUE = info
	IF (TOTAL(((*(*info).feedbparams).verbosity)[2:3]) GE 1) THEN $
    CRISPEX_VERBOSE_GET_ROUTINE, event
	fulltitle = 'CRISPEX'+(*(*info).sesparams).instance_label+': '+STRTRIM(title,2)
	base = WIDGET_BASE(TITLE = fulltitle, GROUP_LEADER = (*(*info).winids).root, $
    TLB_FRAME_ATTR = 1, /TLB_KILL_REQUEST_EVENTS)
	disp = WIDGET_BASE(base, /COLUMN)
	message_base = WIDGET_BASE(disp, /COLUMN)
  final_msg = CRISPEX_SPLIT_MSG(message1, 50) ; Set maximum width in characters to 50
  FOR j=0,N_ELEMENTS(final_msg)-1 DO $
	  text_label = WIDGET_LABEL(message_base, VALUE = final_msg[j])
  IF (N_ELEMENTS(NO_SHOW_EVENT) EQ 1) THEN BEGIN
    divider = CRISPEX_WIDGET_DIVIDER(disp)
    choice_base = WIDGET_BASE(disp, /ALIGN_CENTER)
    choices = WIDGET_COMBOBOX(choice_base, VALUE=NO_SHOW_CHOICES, $
      EVENT_PRO=NO_SHOW_EVENT)
    IF (N_ELEMENTS(SET_CHOICE_IDX) EQ 1) THEN $
      WIDGET_CONTROL, choices, SET_COMBOBOX_SELECT=set_choice_idx
  ENDIF
	IF (N_ELEMENTS(CANCEL_EVENT) GT 0) THEN BEGIN
		IF (N_ELEMENTS(CANCEL_LABEL) NE 1) THEN cancel_label = 'Cancel'
		button_base = WIDGET_BASE(disp, COLUMN=2, /GRID_LAYOUT, /ALIGN_CENTER) 
		cancel_but = WIDGET_BUTTON(button_base, VALUE=cancel_label, $
      EVENT_PRO=cancel_event)
	ENDIF ELSE button_base = WIDGET_BASE(disp,/ROW,/ALIGN_CENTER)
	ok_but = WIDGET_BUTTON(button_base, VALUE = '   OK   ' , EVENT_PRO = ok_event)
	WIDGET_CONTROL, base, /REALIZE, TLB_SET_XOFFSET = 500, TLB_SET_YOFFSET = 500
	WIDGET_CONTROL, base, SET_UVALUE = info
	IF (N_ELEMENTS(BLOCK) NE 1) THEN block = 0
	XMANAGER, 'CRISPEX', base, NO_BLOCK=ABS(block-1)
END

PRO CRISPEX_WINDOW_USER_FEEDBACK, event, title, initial_feedback, $
  CLOSE_BUTTON=close_button, SESSION=session
; Sets up the message windows for user feedback 
	WIDGET_CONTROL, event.TOP, GET_UVALUE=info
	IF (TOTAL(((*(*info).feedbparams).verbosity)[2:3]) GE 1) THEN $
    CRISPEX_VERBOSE_GET_ROUTINE, event
	fulltitle = 'CRISPEX'+(*(*info).sesparams).instance_label+': '+STRTRIM(title,2)
	base = WIDGET_BASE(TITLE=fulltitle, GROUP_LEADER=(*(*info).winids).root, $
    XSIZE=(*(*info).winsizes).aboutwinx, TLB_FRAME_ATTR=1, /TLB_KILL_REQUEST_EVENTS)
	disp = WIDGET_BASE(base, /COLUMN)
	message_base = WIDGET_BASE(disp, /COLUMN)
	(*(*info).ctrlsfeedb).feedback_text = $
    WIDGET_LABEL(message_base, VALUE=initial_feedback, /ALIGN_LEFT, /DYNAMIC_RESIZE)
	IF KEYWORD_SET(close_button) THEN BEGIN
		button_base = WIDGET_BASE(disp,/ROW,/ALIGN_CENTER)
		(*(*info).ctrlsfeedb).close_button = $
      WIDGET_BUTTON(button_base, VALUE='Close', $
      EVENT_PRO='CRISPEX_WINDOW_USER_FEEDBACK_CLOSE', SENSITIVE=0)
	ENDIF ELSE empty_text = WIDGET_LABEL(message_base, VALUE=' ')
	WIDGET_CONTROL, base, /REALIZE, TLB_SET_XOFFSET=500, TLB_SET_YOFFSET=500
	WIDGET_CONTROL, base, SET_UVALUE=info
	XMANAGER, 'CRISPEX', base, /NO_BLOCK
	IF KEYWORD_SET(SESSION) THEN $
    (*(*info).winids).restsesfeedbtlb = base $
  ELSE $
    (*(*info).winids).feedbacktlb = base
	IF (((*(*info).feedbparams).verbosity)[3] EQ 1) THEN $
    CRISPEX_VERBOSE_GET, event, [base], labels=['feedbacktlb']
END

PRO CRISPEX_WINDOW_USER_FEEDBACK_CLOSE, event, session=session
; Handles the closure of the user feedback window
	WIDGET_CONTROL, event.TOP, GET_UVALUE = info
	IF (TOTAL(((*(*info).feedbparams).verbosity)[2:3]) GE 1) THEN $
    CRISPEX_VERBOSE_GET_ROUTINE, event
	IF KEYWORD_SET(SESSION) THEN BEGIN
		tlb = (*(*info).winids).restsesfeedbtlb 
		WIDGET_CONTROL, (*(*info).winids).restsesfeedbtlb, /DESTROY
		(*(*info).winids).restsesfeedbtlb = 0
	ENDIF ELSE BEGIN
		tlb = (*(*info).winids).feedbacktlb
		WIDGET_CONTROL, (*(*info).winids).feedbacktlb, /DESTROY
		(*(*info).winids).feedbacktlb = 0
	ENDELSE
	(*(*info).ctrlsfeedb).feedback_text = 0
	IF (((*(*info).feedbparams).verbosity)[3] EQ 1) THEN $
    CRISPEX_VERBOSE_GET, event, [tlb], labels=['feedbacktlb was']
END

PRO CRISPEX_WINDOWS_GET_OFFSETS, event
; Handles the determination current window offsets
	WIDGET_CONTROL, event.TOP, GET_UVALUE = info
	IF (TOTAL(((*(*info).feedbparams).verbosity)[2:3]) GE 1) THEN $
    CRISPEX_VERBOSE_GET_ROUTINE, event
	IF ((*(*info).winids).sptlb NE 0) THEN BEGIN
    geometry = WIDGET_INFO((*(*info).winids).sptlb, /GEOMETRY)
    (*(*info).winsizes).spxoffset = geometry.xoffset
    (*(*info).winsizes).spyoffset = geometry.yoffset
  ENDIF
	IF ((*(*info).winids).lstlb NE 0) THEN BEGIN
    geometry = WIDGET_INFO((*(*info).winids).lstlb, /GEOMETRY)
    (*(*info).winsizes).lsxoffset = geometry.xoffset
    (*(*info).winsizes).lsyoffset = geometry.yoffset
  ENDIF
	IF ((*(*info).winids).doptlb NE 0) THEN BEGIN
    geometry = WIDGET_INFO((*(*info).winids).doptlb, /GEOMETRY)
    (*(*info).winsizes).dopxoffset = geometry.xoffset
    (*(*info).winsizes).dopyoffset = geometry.yoffset
  ENDIF
	IF ((*(*info).winids).imreftlb NE 0) THEN BEGIN
    geometry = WIDGET_INFO((*(*info).winids).imreftlb, /GEOMETRY)
    (*(*info).winsizes).imrefxoffset = geometry.xoffset
    (*(*info).winsizes).imrefyoffset = geometry.yoffset
  ENDIF
	IF ((*(*info).winids).reftlb NE 0) THEN BEGIN
    geometry = WIDGET_INFO((*(*info).winids).reftlb, /GEOMETRY)
    (*(*info).winsizes).refxoffset = geometry.xoffset
    (*(*info).winsizes).refyoffset = geometry.yoffset
  ENDIF
	IF ((*(*info).winids).refsptlb NE 0) THEN BEGIN
    geometry = WIDGET_INFO((*(*info).winids).refsptlb, /GEOMETRY)
    (*(*info).winsizes).refspxoffset = geometry.xoffset
    (*(*info).winsizes).refspyoffset = geometry.yoffset
  ENDIF
	IF ((*(*info).winids).reflstlb NE 0) THEN BEGIN
    geometry = WIDGET_INFO((*(*info).winids).reflstlb, /GEOMETRY)
    (*(*info).winsizes).reflsxoffset = geometry.xoffset
    (*(*info).winsizes).reflsyoffset = geometry.yoffset
  ENDIF
	IF (TOTAL((*(*info).winids).sjitlb) NE 0) THEN BEGIN
    FOR i=0,(*(*info).winswitch).nwhereshowsji-1 DO BEGIN
      idx_sji = (*(*(*info).winswitch).whereshowsji)[i]
      geometry = WIDGET_INFO((*(*info).winids).sjitlb[idx_sji], /GEOMETRY)
      (*(*info).winsizes).sjixoffset[idx_sji] = geometry.xoffset
      (*(*info).winsizes).sjiyoffset[idx_sji] = geometry.yoffset
    ENDFOR
  ENDIF
	IF ((*(*info).winids).phistlb NE 0) THEN BEGIN
    geometry = WIDGET_INFO((*(*info).winids).phistlb, /GEOMETRY)
    (*(*info).winsizes).phisxoffset = geometry.xoffset
    (*(*info).winsizes).phisyoffset = geometry.yoffset
  ENDIF
	IF ((*(*info).winids).inttlb NE 0) THEN BEGIN
    geometry = WIDGET_INFO((*(*info).winids).inttlb, /GEOMETRY)
    (*(*info).winsizes).intxoffset = geometry.xoffset
    (*(*info).winsizes).intyoffset = geometry.yoffset
  ENDIF
	IF ((*(*info).winids).looptlb NE 0) THEN BEGIN
    geometry = WIDGET_INFO((*(*info).winids).looptlb, /GEOMETRY)
    (*(*info).winsizes).loopxoffset = geometry.xoffset
    (*(*info).winsizes).loopyoffset = geometry.yoffset
  ENDIF
END

;========================= ZOOM PROCEDURES
PRO CRISPEX_ZOOM, event, NO_DRAW=no_draw, $
      NO_UPDATE_SLIDERS=no_update_sliders, SET_FACTOR_IDX=set_factor_idx, $
      UNSET_FACTOR_IDX=unset_factor_idx
; Handles the zoom event
	WIDGET_CONTROL, event.TOP, GET_UVALUE = info
	IF (TOTAL(((*(*info).feedbparams).verbosity)[2:3]) GE 1) THEN $
    CRISPEX_VERBOSE_GET_ROUTINE, event
  ; Save old zoomfactor and get the new one
  (*(*info).zooming).factor_old = (*(*info).zooming).factor
  IF (N_ELEMENTS(SET_FACTOR_IDX) EQ 1) THEN BEGIN
    idx = set_factor_idx   & select = 1B
    IF (N_ELEMENTS(UNSET_FACTOR_IDX) EQ 1) THEN $
      (*(*info).zooming).factorswitch[unset_factor_idx]= 0B
  ENDIF 
  (*(*info).zooming).factorswitch[idx] = select
  (*(*info).zooming).factor = (*(*info).zooming).init_factor * $
    ((*(*info).zooming).factors)[idx]
  ; Compute the new display range
	(*(*info).dataparams).d_nx = $
    ((*(*info).dataparams).nx / ((*(*info).zooming).factor/$
    ((*(*info).winsizes).xywinx / (*(*info).dataparams).pixelratio / $
    FLOAT((*(*info).dataparams).nx)))) < ((*(*info).dataparams).nx-1)
	(*(*info).dataparams).d_ny = $
    ((*(*info).dataparams).ny / ((*(*info).zooming).factor/$
    ((*(*info).winsizes).xywiny / FLOAT((*(*info).dataparams).ny)))) < $
    ((*(*info).dataparams).ny-1)
	(*(*info).phiparams).d_nphi_set = $
    (*(*info).phiparams).nphi_set / (*(*info).zooming).factor
  IF ((*(*info).winids).reftlb NE 0) THEN BEGIN
  	(*(*info).dataparams).d_refnx = $
      ((*(*info).dataparams).refnx / ((*(*info).zooming).factor/$
      ((*(*info).winsizes).refwinx / (*(*info).dataparams).refpixelratio / $
      FLOAT((*(*info).dataparams).refnx)))) < ((*(*info).dataparams).refnx-1)
  	(*(*info).dataparams).d_refny = $
      ((*(*info).dataparams).refny / ((*(*info).zooming).factor/$
      ((*(*info).winsizes).refwiny / FLOAT((*(*info).dataparams).refny)))) < $
      ((*(*info).dataparams).refny-1)
  ENDIF
  IF (TOTAL((*(*info).winids).sjitlb) NE 0) THEN BEGIN
    FOR i=0,(*(*info).winswitch).nwhereshowsji-1 DO BEGIN
      idx_sji = (*(*(*info).winswitch).whereshowsji)[i]
    	(*(*info).dataparams).d_sjinx[idx_sji] = $
        ((*(*info).dataparams).sjinx[idx_sji] / ((*(*info).zooming).factor/ $
        ((*(*info).winsizes).sjiwinx[idx_sji] / $
        (*(*info).dataparams).sjipixelratio[idx_sji] / $
        FLOAT((*(*info).dataparams).sjinx[idx_sji])))) < $
          ((*(*info).dataparams).sjinx[idx_sji]-1)
    	(*(*info).dataparams).d_sjiny[idx_sji] = $
        ((*(*info).dataparams).sjiny[idx_sji] / ((*(*info).zooming).factor/ $
        ((*(*info).winsizes).sjiwiny[idx_sji] / $
        FLOAT((*(*info).dataparams).sjiny[idx_sji])))) < $
          ((*(*info).dataparams).sjiny[idx_sji]-1)
    ENDFOR
  ENDIF
  ; Focus will always be on the main image window when zooming (either through
  ; buttons or shortcuts), so only need to grab main coordinates
	IF (*(*info).curs).lockset THEN BEGIN
		cursor_x = (*(*info).curs).xlock
		cursor_y = (*(*info).curs).ylock
	ENDIF ELSE BEGIN
		cursor_x = (*(*info).dataparams).x
		cursor_y = (*(*info).dataparams).y
	END
  IF ~KEYWORD_SET(NO_UPDATE_SLIDERS) THEN $
  	CRISPEX_ZOOM_UPDATE_SLIDERS, event, cursor_x=cursor_x, cursor_y=cursor_y
	CRISPEX_UPDATE_SX, event
	CRISPEX_UPDATE_SY, event
	IF (((*(*info).feedbparams).verbosity)[3] EQ 1) THEN $
    CRISPEX_VERBOSE_GET, event, [(*(*info).zooming).factor,xposconstr,yposconstr], $
    labels=['Zoomfactor','Maximum xpos','Maximum ypos']
  CRISPEX_UPDATE_T, event
	IF ~KEYWORD_SET(NO_DRAW) THEN $
    CRISPEX_DRAW, event, /NO_PHIS, /LS_NO_MAIN, /LS_NO_REF
END

PRO CRISPEX_ZOOM_TOFIT, event
	WIDGET_CONTROL, event.TOP, GET_UVALUE=info
	IF (TOTAL(((*(*info).feedbparams).verbosity)[2:3]) GE 1) THEN $
    CRISPEX_VERBOSE_GET_ROUTINE, event
  (*(*info).zooming).tofit = 1B
  (*(*info).zooming).init_factor = (*(*info).winsizes).xywinx / $
    (*(*info).dataparams).pixelratio / FLOAT((*(*info).dataparams).nx)
  CRISPEX_ZOOM, event, SET_FACTOR_IDX=0, $
    UNSET_FACTOR_IDX=(WHERE((*(*info).zooming).factorswitch EQ 1))[0]
  WIDGET_CONTROL, (*(*info).ctrlscp).zoom_to_fit, $
    SET_VALUE=(*(*info).ctrlspbbut).zoom_tofit_pressed
  WIDGET_CONTROL, (*(*info).ctrlscp).zoom_to_scale, $
    SET_VALUE=(*(*info).ctrlspbbut).zoom_toscale_idle
END

PRO CRISPEX_ZOOM_TOSCALE, event
	WIDGET_CONTROL, event.TOP, GET_UVALUE=info
	IF (TOTAL(((*(*info).feedbparams).verbosity)[2:3]) GE 1) THEN $
    CRISPEX_VERBOSE_GET_ROUTINE, event
  (*(*info).zooming).tofit = 0B
  IF ((*(*info).zooming).init_factor LT 1.) THEN $
    (*(*info).zooming).init_factor = 1.  
  CRISPEX_ZOOM, event, SET_FACTOR_IDX=0, $
    UNSET_FACTOR_IDX=(WHERE((*(*info).zooming).factorswitch EQ 1))[0]
  WIDGET_CONTROL, (*(*info).ctrlscp).zoom_to_scale, $
    SET_VALUE=(*(*info).ctrlspbbut).zoom_toscale_pressed
  WIDGET_CONTROL, (*(*info).ctrlscp).zoom_to_fit, $
    SET_VALUE=(*(*info).ctrlspbbut).zoom_tofit_idle
  WIDGET_CONTROL, (*(*info).ctrlscp).zoom_select, $
    SET_VALUE=(*(*info).ctrlspbbut).zoom_select_pressed
END

PRO CRISPEX_ZOOM_PAN, event
; Handles selecting drag or select as function for the cursor
	WIDGET_CONTROL, event.TOP, GET_UVALUE=info
  (*(*info).curs).panselect = 0B
  (*(*info).curs).image = (*(*info).curs).image_hand
  (*(*info).curs).mask  = (*(*info).curs).mask_hand
 	DEVICE, CURSOR_IMAGE=(*(*info).curs).image, $
     CURSOR_MASK=(*(*info).curs).mask, CURSOR_XY=[7,7] 
  WIDGET_CONTROL, (*(*info).ctrlscp).zoom_pan, $
    SET_VALUE=(*(*info).ctrlspbbut).zoom_pan_pressed
  WIDGET_CONTROL, (*(*info).ctrlscp).zoom_select, $
    SET_VALUE=(*(*info).ctrlspbbut).zoom_select_idle
END

PRO CRISPEX_ZOOM_SELECT, event
; Handles selecting drag or select as function for the cursor
	WIDGET_CONTROL, event.TOP, GET_UVALUE=info
  (*(*info).curs).panselect = 1B 
  (*(*info).curs).image = (*(*info).curs).image_default
  IF (*(*info).curs).lockset THEN $
    (*(*info).curs).mask  = (*(*info).curs).mask_locked $
  ELSE $
    (*(*info).curs).mask  = (*(*info).curs).mask_default
 	DEVICE, CURSOR_IMAGE=(*(*info).curs).image, $
     CURSOR_MASK=(*(*info).curs).mask, CURSOR_XY=[7,7] 
  WIDGET_CONTROL, (*(*info).ctrlscp).zoom_pan, $
    SET_VALUE=(*(*info).ctrlspbbut).zoom_pan_idle
  WIDGET_CONTROL, (*(*info).ctrlscp).zoom_select, $
    SET_VALUE=(*(*info).ctrlspbbut).zoom_select_pressed
END

PRO CRISPEX_ZOOM_GOTO_CURSOR, event
	WIDGET_CONTROL, event.TOP, GET_UVALUE=info
  WIDGET_CONTROL, (*(*info).ctrlscp).zoom_goto_cursor, $
    SET_VALUE=(*(*info).ctrlspbbut).zoom_goto_cursor_pressed
  CRISPEX_ZOOM_UPDATE_SLIDERS, event, CURSOR_X=(*(*info).dataparams).x, $
    CURSOR_Y=(*(*info).dataparams).y
  CRISPEX_UPDATE_SX, event
  CRISPEX_UPDATE_SY, event
  CRISPEX_DRAW, event, /NO_PHIS, /LS_NO_MAIN, /LS_NO_REF
  WIDGET_CONTROL, (*(*info).ctrlscp).zoom_goto_cursor, $
    SET_VALUE=(*(*info).ctrlspbbut).zoom_goto_cursor_idle
END

PRO CRISPEX_ZOOM_UPDATE_SLIDERS, event, cursor_x=cursor_x, cursor_y=cursor_y
; Handles the update of xpos and ypos sliders when changing zoomfactor
	WIDGET_CONTROL, event.TOP, GET_UVALUE = info
	IF (TOTAL(((*(*info).feedbparams).verbosity)[2:3]) GE 1) THEN $
    CRISPEX_VERBOSE_GET_ROUTINE, event
  ; Get the new slider positions based on the cursor location
	(*(*info).zooming).xpos = (cursor_x - (*(*info).dataparams).d_nx / 2.) > 0
	(*(*info).zooming).ypos = (cursor_y - (*(*info).dataparams).d_ny / 2.) > 0
	IF (((*(*info).zooming).xpos+(*(*info).dataparams).d_nx) GE $
       (*(*info).dataparams).nx) THEN $
    (*(*info).zooming).xpos = $
      (((*(*info).dataparams).nx-1) - (*(*info).dataparams).d_nx) > 0
	IF (((*(*info).zooming).ypos+(*(*info).dataparams).d_ny) GE $
       (*(*info).dataparams).ny) THEN $
    (*(*info).zooming).ypos = $
      (((*(*info).dataparams).ny-1) - (*(*info).dataparams).d_ny) > 0
	(*(*info).zooming).xpos = LONG((*(*info).zooming).xpos)
	(*(*info).zooming).ypos = LONG((*(*info).zooming).ypos)
	(*(*info).zooming).xypos_max = [$
    ((*(*info).dataparams).nx-1) - (*(*info).dataparams).d_nx, $
	  ((*(*info).dataparams).ny-1) - (*(*info).dataparams).d_ny ]
  sensitive = [(*(*info).dataparams).d_nx,(*(*info).dataparams).d_ny] NE $
    [(*(*info).dataparams).nx-1,(*(*info).dataparams).ny-1]
  ; Set main/reference x/ypos sliders
	WIDGET_CONTROL, (*(*info).ctrlscp).xpos_slider, SENSITIVE=sensitive[0], $
    SET_SLIDER_MAX=(*(*info).zooming).xypos_max[0], SET_VALUE=(*(*info).zooming).xpos 
	WIDGET_CONTROL, (*(*info).ctrlscp).ypos_slider, SENSITIVE=sensitive[1], $
    SET_SLIDER_MAX=(*(*info).zooming).xypos_max[1], SET_VALUE=(*(*info).zooming).ypos 
  ; Set reference variables and x/ypos sliders
  IF ((*(*info).winids).reftlb NE 0) THEN BEGIN
  	(*(*info).zooming).xrefpos = ((*(*info).dataparams).xref - $
      (*(*info).dataparams).d_refnx / 2.) > 0
  	(*(*info).zooming).yrefpos = ((*(*info).dataparams).yref - $
      (*(*info).dataparams).d_refny / 2.) > 0
  	IF (((*(*info).zooming).xrefpos+(*(*info).dataparams).d_refnx) GE $
      (*(*info).dataparams).refnx) THEN $
      (*(*info).zooming).xrefpos = $
        (((*(*info).dataparams).refnx-1) - (*(*info).dataparams).d_refnx) > 0
  	IF (((*(*info).zooming).yrefpos+(*(*info).dataparams).d_refny) GE $
      (*(*info).dataparams).refny) THEN $
      (*(*info).zooming).yrefpos = (((*(*info).dataparams).refny-1) - $
        (*(*info).dataparams).d_refny) > 0
  	(*(*info).zooming).xrefpos = LONG((*(*info).zooming).xrefpos)
  	(*(*info).zooming).yrefpos = LONG((*(*info).zooming).yrefpos)
  	(*(*info).zooming).xyrefpos_max = [$
      ((*(*info).dataparams).refnx-1) - (*(*info).dataparams).d_refnx, $
      ((*(*info).dataparams).refny-1) - (*(*info).dataparams).d_refny]
    sensitive = [(*(*info).dataparams).d_refnx,(*(*info).dataparams).d_refny] NE $
      [(*(*info).dataparams).refnx-1,(*(*info).dataparams).refny-1]
  	WIDGET_CONTROL, (*(*info).ctrlsref).xrefpos_slider, SENSITIVE=sensitive[0],$
      SET_SLIDER_MAX=(*(*info).zooming).xyrefpos_max[0], $
      SET_VALUE=(*(*info).zooming).xrefpos
  	WIDGET_CONTROL, (*(*info).ctrlsref).yrefpos_slider, SENSITIVE=sensitive[1],$
      SET_SLIDER_MAX=(*(*info).zooming).xyrefpos_max[1], $
      SET_VALUE=(*(*info).zooming).yrefpos
    ; Get imrefblink boundaries
    result = CRISPEX_GET_IMREF_BLINK_BOUNDS(*(*(*info).dataparams).pix_main2ref,$
      *(*(*info).dataparams).pix_ref2main, (*(*info).zooming).xpos, $
      (*(*info).zooming).xpos+(*(*info).dataparams).d_nx, $
      (*(*info).zooming).ypos, $
      (*(*info).zooming).ypos+(*(*info).dataparams).d_ny, $
      (*(*info).zooming).xrefpos, $
      (*(*info).zooming).xrefpos+(*(*info).dataparams).d_refnx, $
      (*(*info).zooming).yrefpos, $
      (*(*info).zooming).yrefpos+(*(*info).dataparams).d_refny)
    (*(*info).dispparams).x_main = result.x_main-(*(*info).zooming).xpos
    (*(*info).dispparams).y_main = result.y_main-(*(*info).zooming).ypos
    (*(*info).dispparams).x_ref = result.x_ref-(*(*info).zooming).xrefpos
    (*(*info).dispparams).y_ref = result.y_ref-(*(*info).zooming).yrefpos
  ENDIF
  ; Set SJI variables and x/ypos sliders
  IF (TOTAL((*(*info).winids).sjitlb) NE 0) THEN BEGIN
    FOR i=0,(*(*info).winswitch).nwhereshowsji-1 DO BEGIN
      idx_sji = (*(*(*info).winswitch).whereshowsji)[i]
    	(*(*info).zooming).xsjipos[idx_sji] = ((*(*info).dataparams).xsji[idx_sji] - $
        (*(*info).dataparams).d_sjinx[idx_sji] / 2.) > 0
    	(*(*info).zooming).ysjipos[idx_sji] = ((*(*info).dataparams).ysji[idx_sji] - $
        (*(*info).dataparams).d_sjiny[idx_sji] / 2.) > 0
    	IF (((*(*info).zooming).xsjipos[idx_sji]+$
        (*(*info).dataparams).d_sjinx[idx_sji]) GE $
        (*(*info).dataparams).sjinx[idx_sji]) THEN $
        (*(*info).zooming).xsjipos[idx_sji] = $
          (((*(*info).dataparams).sjinx[idx_sji]-1) - $
          (*(*info).dataparams).d_sjinx[idx_sji]) > 0
    	IF (((*(*info).zooming).ysjipos[idx_sji]+$
        (*(*info).dataparams).d_sjiny[idx_sji]) GE $
        (*(*info).dataparams).sjiny[idx_sji]) THEN $
        (*(*info).zooming).ysjipos[idx_sji] = $
          (((*(*info).dataparams).sjiny[idx_sji]-1) - $
          (*(*info).dataparams).d_sjiny[idx_sji]) > 0
    	(*(*info).zooming).xsjipos[idx_sji] = $
        LONG((*(*info).zooming).xsjipos[idx_sji])
    	(*(*info).zooming).ysjipos[idx_sji] = $
        LONG((*(*info).zooming).ysjipos[idx_sji])
    	(*(*info).zooming).xysjipos_max[*,idx_sji] = [$
        ((*(*info).dataparams).sjinx[idx_sji]-1) - $
         (*(*info).dataparams).d_sjinx[idx_sji], $
        ((*(*info).dataparams).sjiny[idx_sji]-1) - $
         (*(*info).dataparams).d_sjiny[idx_sji]]
      sensitive = [(*(*info).dataparams).d_sjinx[idx_sji],$
        (*(*info).dataparams).d_sjiny[idx_sji]] NE $
        [(*(*info).dataparams).sjinx[idx_sji]-1,$
        (*(*info).dataparams).sjiny[idx_sji]-1]
    	WIDGET_CONTROL, (*(*info).ctrlssji).xsjipos_slider[idx_sji], SENSITIVE=sensitive[0],$
        SET_SLIDER_MAX=(*(*info).zooming).xysjipos_max[0,idx_sji],$
        SET_VALUE=(*(*info).zooming).xsjipos[idx_sji]
    	WIDGET_CONTROL, (*(*info).ctrlssji).ysjipos_slider[idx_sji], SENSITIVE=sensitive[1],$
        SET_SLIDER_MAX=(*(*info).zooming).xysjipos_max[1,idx_sji],$
        SET_VALUE=(*(*info).zooming).ysjipos[idx_sji]
    ENDFOR
  ENDIF
  ; Update buttons
  CRISPEX_ZOOM_BUTTONS_SET, event, /ZOOM_INOUT, /PAN_SELECT, /ZGOTO, $
    SENSITIVE=(TOTAL(sensitive) GT 0)
	IF (((*(*info).feedbparams).verbosity)[3] EQ 1) THEN $
    CRISPEX_VERBOSE_GET, event, $
      [(*(*info).zooming).xpos, (*(*info).zooming).ypos, $
      (*(*info).dataparams).d_nx, (*(*info).dataparams).d_ny], $
      labels=['xpos','ypos','d_nx','d_ny']
END

PRO CRISPEX_ZOOM_BUTTONS_SET, event, FIT_SCALE=fit_scale, ZOOM_INOUT=zoom_inout, $
  PAN_SELECT=pan_select, ZGOTO=zgoto, SENSITIVE=sensitive
; Handles setting of the zoom buttons
	WIDGET_CONTROL, event.TOP, GET_UVALUE=info
	IF (TOTAL(((*(*info).feedbparams).verbosity)[2:3]) GE 1) THEN $
    CRISPEX_VERBOSE_GET_ROUTINE, event
  IF (N_ELEMENTS(SENSITIVE) NE 1) THEN sensitive = 1
  IF KEYWORD_SET(FIT_SCALE) THEN BEGIN
    IF (*(*info).zooming).tofit THEN BEGIN
      tofit_bmp = (*(*info).ctrlspbbut).zoom_tofit_pressed
      toscl_bmp = (*(*info).ctrlspbbut).zoom_toscale_idle
    ENDIF ELSE BEGIN
      tofit_bmp = (*(*info).ctrlspbbut).zoom_tofit_idle
      toscl_bmp = (*(*info).ctrlspbbut).zoom_toscale_pressed
    ENDELSE
    WIDGET_CONTROL, (*(*info).ctrlscp).zoom_to_fit, SET_VALUE=tofit_bmp
    WIDGET_CONTROL, (*(*info).ctrlscp).zoom_to_scale, SET_VALUE=toscl_bmp
  ENDIF
  IF KEYWORD_SET(ZOOM_INOUT) THEN BEGIN
    factor_idx = WHERE((*(*info).zooming).factorswitch EQ 1)
    WIDGET_CONTROL, (*(*info).ctrlscp).zoom_out, SENSITIVE=(factor_idx NE 0)
    WIDGET_CONTROL, (*(*info).ctrlscp).zoom_in, SENSITIVE=(factor_idx NE $
      N_ELEMENTS((*(*info).zooming).factorswitch)-1)
  ENDIF
  IF KEYWORD_SET(PAN_SELECT) THEN BEGIN
    IF (*(*info).curs).panselect THEN BEGIN
      pan_bmp = (*(*info).ctrlspbbut).zoom_pan_idle 
      sel_bmp = (*(*info).ctrlspbbut).zoom_select_pressed
    ENDIF ELSE BEGIN
      pan_bmp = (*(*info).ctrlspbbut).zoom_pan_pressed
      sel_bmp = (*(*info).ctrlspbbut).zoom_select_idle
    ENDELSE
    WIDGET_CONTROL, (*(*info).ctrlscp).zoom_pan, SET_VALUE=pan_bmp, $
      SENSITIVE=sensitive
    WIDGET_CONTROL, (*(*info).ctrlscp).zoom_select, SET_VALUE=sel_bmp 
  ENDIF
  IF KEYWORD_SET(ZGOTO) THEN $
    WIDGET_CONTROL, (*(*info).ctrlscp).zoom_goto_cursor, SENSITIVE=sensitive
END

PRO CRISPEX_ZOOMFAC_DECR, event
; Decreases the zoomfactor and calls CRISPEX_BGROUP_ZOOMFAC_SET
	WIDGET_CONTROL, event.TOP, GET_UVALUE = info
	IF (TOTAL(((*(*info).feedbparams).verbosity)[2:3]) GE 1) THEN $
    CRISPEX_VERBOSE_GET_ROUTINE, event
  WIDGET_CONTROL, (*(*info).ctrlscp).zoom_out, $
    SET_VALUE=(*(*info).ctrlspbbut).zoom_out_pressed
  old_factor_idx = WHERE((*(*info).zooming).factorswitch EQ 1)
  set_factor_idx = ( old_factor_idx - 1 ) > 0
  IF (set_factor_idx NE old_factor_idx) THEN $
    CRISPEX_ZOOM, event, SET_FACTOR_IDX=set_factor_idx, $
      UNSET_FACTOR_IDX=old_factor_idx
  WIDGET_CONTROL, (*(*info).ctrlscp).zoom_out, $
    SET_VALUE=(*(*info).ctrlspbbut).zoom_out_idle
END

PRO CRISPEX_ZOOMFAC_INCR, event
; Increases the zoomfactor and calls CRISPEX_BGROUP_ZOOMFAC_SET
	WIDGET_CONTROL, event.TOP, GET_UVALUE = info
	IF (TOTAL(((*(*info).feedbparams).verbosity)[2:3]) GE 1) THEN $
    CRISPEX_VERBOSE_GET_ROUTINE, event
  WIDGET_CONTROL, (*(*info).ctrlscp).zoom_in, $
    SET_VALUE=(*(*info).ctrlspbbut).zoom_in_pressed
  old_factor_idx = WHERE((*(*info).zooming).factorswitch EQ 1)
  set_factor_idx = ( old_factor_idx + 1 ) < (N_ELEMENTS((*(*info).zooming).factorswitch)-1)
  IF (set_factor_idx NE old_factor_idx) THEN $
    CRISPEX_ZOOM, event, SET_FACTOR_IDX=set_factor_idx, $
      UNSET_FACTOR_IDX=old_factor_idx
  WIDGET_CONTROL, (*(*info).ctrlscp).zoom_in, $
    SET_VALUE=(*(*info).ctrlspbbut).zoom_in_idle
END

PRO CRISPEX_ZOOM_MEAS, event, REFERENCE=reference, SJI=sji, IDX_SJI=idx_sji
; Handles the change in measurement position after a zoom event
	WIDGET_CONTROL, event.TOP, GET_UVALUE = info
	IF (TOTAL(((*(*info).feedbparams).verbosity)[2:3]) GE 1) THEN $
    CRISPEX_VERBOSE_GET_ROUTINE, event
  result = CRISPEX_TRANSFORM_DATA2DEVICE(info, $
    X=*(*(*info).meas).xp, Y=*(*(*info).meas).yp, /MAIN)
  *(*(*info).meas).sxp = result.x
  *(*(*info).meas).syp = result.y
  IF KEYWORD_SET(REFERENCE) THEN BEGIN
    result = CRISPEX_TRANSFORM_DATA2DEVICE(info, $
      X=*(*(*info).meas).xp_ref, Y=*(*(*info).meas).yp_ref, /REF)
    *(*(*info).meas).sxp_ref = result.x
    *(*(*info).meas).syp_ref = result.y
  ENDIF 
  IF KEYWORD_SET(SJI) THEN BEGIN
    result = CRISPEX_TRANSFORM_DATA2DEVICE(info, $
      X=*(*(*info).meas).xp_sji[idx_sji], Y=*(*(*info).meas).yp_sji[idx_sji], $
      /SJI, IDX_SJI=idx_sji)
    *(*(*info).meas).sxp_sji[idx_sji] = result.x
    *(*(*info).meas).syp_sji[idx_sji] = result.y
  ENDIF
END	

PRO CRISPEX_ZOOM_LOOP, event, REFERENCE=reference, SJI=sji, IDX_SJI=idx_sji
; Handles the change in loop positions after a zoom event
	WIDGET_CONTROL, event.TOP, GET_UVALUE = info
	IF (TOTAL(((*(*info).feedbparams).verbosity)[2:3]) GE 1) THEN $
    CRISPEX_VERBOSE_GET_ROUTINE, event
  result = CRISPEX_TRANSFORM_DATA2DEVICE(info, $
    X=*(*(*info).loopparams).xrdisp, Y=*(*(*info).loopparams).yrdisp, /MAIN)
  *(*(*info).overlayparams).sxr = result.x
  *(*(*info).overlayparams).syr = result.y
  IF KEYWORD_SET(REFERENCE) THEN BEGIN
    result = CRISPEX_TRANSFORM_DATA2DEVICE(info, $
      X=*(*(*info).loopparams).xrdisp_ref, Y=*(*(*info).loopparams).yrdisp_ref, /REF)
    *(*(*info).overlayparams).sxr_ref = result.x
    *(*(*info).overlayparams).syr_ref = result.y
  ENDIF
  IF KEYWORD_SET(SJI) THEN BEGIN
    IF (N_ELEMENTS(IDX_SJI) EQ 1) THEN BEGIN
      showsji = BYTARR((*(*info).dataparams).nsjifiles)
      showsji[idx_sji] = 1B
    ENDIF ELSE showsji = (*(*info).winswitch).showsji
    whereshowsji_loc = WHERE(showsji EQ 1, nwhereshowsji)
    FOR i=0,nwhereshowsji-1 DO BEGIN
      idx_sji = whereshowsji_loc[i]
      result = CRISPEX_TRANSFORM_DATA2DEVICE(info, $
        X=*(*(*info).loopparams).xrdisp_sji[idx_sji], $
        Y=*(*(*info).loopparams).yrdisp_sji[idx_sji], $
        /SJI, IDX_SJI=idx_sji)
      *(*(*info).overlayparams).sxr_sji[idx_sji] = result.x
      *(*(*info).overlayparams).syr_sji[idx_sji] = result.y
    ENDFOR
  ENDIF
END

;===============================================================================
;================================== MAIN PROGRAM CODE ==========================
;===============================================================================
PRO CRISPEX, imcube, spcube, $        ; filename of main im & sp cube
      REFCUBE=refcube, $              ; filename(s) of ref im (& sp) cube(s)
      SJICUBE=sjicube, $              ; filename of slit-jaw image cube
      MASKCUBE=maskcube, $            ; filename of mask cube
      SPECTFILE=spectfile, $          ; filename(s) of spectral save file(s)
      LINE_CENTER=line_center, $		  ; line centre and/or wavelength info
	    DT=dt, $                        ; time step in seconds
      EXTS=exts, $                    ; exact timeslices keyword
      MNSPEC=mnspec, $                ; mean spectrum over selected scans
      SINGLE_CUBE=single_cube, $      ; single full cube call
      SCALE_STOKES=scale_stokes, $    ; scale Stokes spectra internally
      NO_WARP=no_warp, $              ; don't warp nonequidistant spectra 
      SCALE_CUBES=scale_cubes, $      ; scale cubes
      XTITLE=xtitle, YTITLE=ytitle,$  ; custom detailed spectrum x- and ytitle
      OFFSET_SJI=offset_sji, $        ; (x,y) offset in slit-jaw image coords
      WINDOW_LARGE=window_large, $    ; draw large windows for small cubes
      LAST_SESSION=last_session, $    ; load last session
      VERBOSE=verbose                 ; program verbosity


;========================= COMPILE OPTIONS
  COMPILE_OPT IDL2

;========================= PROGRAM VERBOSITY CHECK
	IF (N_ELEMENTS(VERBOSE) NE 1) THEN BEGIN			
		IF (N_ELEMENTS(VERBOSE) GT 1) THEN $
      MESSAGE,'ERROR: The VERBOSE keyword may only be set to a single '+$
        'integer number. Reverting to default verbosity level 0.'
		verbose = 0
		verbosity = [0,0,0,0,0]
	ENDIF ELSE BEGIN
		verbose >= 0	&	verbose <= 26
	ENDELSE
	verbosity = CRISPEX_TRANSFORM_DEC2BIN(verbose)   ; Convert verbosity value to binary array
  IF verbosity[1] THEN setup_starttime = SYSTIME(/SECONDS)

;========================= CRISPEX DIRECTORY TREE CHECK
	file_crispex    = (ROUTINE_INFO('CRISPEX',/SOURCE)).PATH      ; Path to compiled CRISPEX
	dir_crispex     = FILE_DIRNAME(file_crispex,/MARK_DIRECTORY)
	dir_aux         = dir_crispex+'aux'+PATH_SEP()         ; Path to auxiliary routines
	dir_resources   = dir_crispex+'resources'+PATH_SEP()   ; Path to resources container
	dir_buttons     = dir_resources+'buttons'+PATH_SEP()   ; Path to button images
  dir_settings    = CRISPEX_CONFIG_DIR()+PATH_SEP()      ; Path to settings container
	dir_settings_write  = FILE_TEST(dir_settings, /WRITE)  ; Check for cpft dir writeability
	IF (verbosity[1] EQ 1) THEN $
    CRISPEX_UPDATE_STARTUP_SETUP_FEEDBACK,'CRISPEX has been compiled from: '+file_crispex

;========================= TEMPORARILY PRELOAD MODIFIED WCS_PROJ_TAB PROCEDURE
  ; Check that dir_aux/ininterpol exists
  dir_ninterpol_exist = FILE_TEST(dir_aux+'ninterpol')
  ; Routine located under dir_aux/ninterpol
  IF dir_ninterpol_exist THEN $
    RESOLVE_ROUTINE, 'crispex_wcs_proj_tab', /COMPILE_FULL_FILE $
  ELSE BEGIN
    CRISPEX_UPDATE_STARTUP_SETUP_FEEDBACK, $
      'Your CRISPEX distribution appears to be incomplete: missing directory '+$
      dir_aux+'ninterpol. CRISPEX will not be able to properly read '+$
      'metadata from SOLARNET-standard tabulated FITS cubes.', $
      /WARNING, /NO_ROUTINE, /NEWLINE
  ENDELSE

;========================= VERSION AND REVISION NUMBER
  ; Version 1.7.4 (rev 820, cvs_rev 1.250) == version 1.7.4.0
	base_version_number = '1.7.4'
  
  ; Get revision number from CVS $Id
  id_string='; $Id: crispex.pro,v 1.277 2019/12/17 05:18:07 gregal Exp $'
  split_id_string = STRSPLIT(id_string[0],' ',/EXTRACT)
  cvs_idn = split_id_string[3]
  cvs_rev = (STRSPLIT(cvs_idn,'.',/EXTRACT))[1]
  cvs_msg = STRJOIN(split_id_string[3:6],' ')
  ; Assumption: CVS committed revision number will always be 1.x, with x increasing linearly
  revnr = 634+FIX(cvs_rev)-64             ; rev_nr=634, cvs_rev=64 when implemented
 
  ; Change rev_nr and cvs_rev below whenever changing base_versions_number!
  subvnr = 652 + (FIX(cvs_rev)-82) - 820  ; rev_nr=652, cvs_rev=82 when implemented
  
  ; Convert revision and version numbers to strings
  revision_number = STRTRIM(revnr,2)   
  version_number = base_version_number +'.'+ STRTRIM(subvnr,2)
  vnr_msg = version_number+' (r'+revision_number+'; '+cvs_msg+')'
	IF (verbosity[1] EQ 1) THEN $
    CRISPEX_UPDATE_STARTUP_SETUP_FEEDBACK,'Version and revision number: '+vnr_msg

;========================= PROGRAM-INFO ON CALL W/O PARAMS
	IF ((N_PARAMS() LT 1) AND (NOT KEYWORD_SET(LAST_SESSION))) THEN BEGIN
    MESSAGE,'Version '+vnr_msg, /INFO
		MESSAGE,'Syntax: CRISPEX, Imcube [, Spcube] [, REFCUBE=refcube] '+$
            '[, SJICUBE=sjicube] [, MASKCUBE=maskcube] [, SPECTFILE=spectfile] '+$
            '[, LINE_CENTER=line_center] [, DT=dt] [, /EXTS] [, MNSPEC=mnspec] '+$
            '[, SINGLE_CUBE=single_cube] [, SCALE_STOKES=scale_stokes] '+$
            '[, /NO_WARP] [, SCALE_CUBES=scale_cubes] [, XTITLE=xtitle] '+$
            '[, YTITLE=ytitle] [, WINDOW_LARGE=window_large] '+$
            '[, /LAST_SESSION] [, VERBOSE=verbose]', /INFO
		RETURN
	ENDIF

;========================= LOAD PREFERENCES
  ; Define default preferences
  ;   Show startup win, interpolate slices
	default_startupwin = 1      &  default_interpspslice = 1  
  ;                               0 = yyyymmdd, 1 = ddmmyyyy
	default_autoplay = 0        &  default_defsaveid = 0      
  ; 0 = local working directory, 1 = saved directory
	default_defipath = 0        &  default_defopath = 0			  
	default_bgplotcol = 255     &  default_plotcol = 0
  default_plotthick = 2.0
  default_overlays_thick = 1  &  default_overlays_symsize = 1
	default_phislice_update = 0 &  default_slices_imscale = 0
  default_histo_opt_val = 0.0001  & default_gamma_val = 1.0
  ; 0=no startup warnings, 1=warnings on cmd line, 2=warnings in pop-up
  default_warnings = 2  
	cpreffiles = FILE_SEARCH(dir_settings+'crispex.cpref', COUNT = cpreffilecount)
	IF (cpreffilecount GE 1) THEN BEGIN     
    ; If preference file is present, load preference file
		RESTORE, cpreffiles[0] 
		IF (verbosity[1] EQ 1) THEN $
      CRISPEX_UPDATE_STARTUP_SETUP_FEEDBACK, 'Preferences restored from: '+$
        dir_settings+'crispex.cpref'
		resave_preferences = $
      ((N_ELEMENTS(phislice_update) NE 1) OR (N_ELEMENTS(slices_imscale) NE 1))
    ; Failsafe inheritances from older CRISPEX versions
    ; Automatic phislice update
		IF (N_ELEMENTS(phislice_update) NE 1) THEN $
      phislice_update = default_phislice_update
    ; Scale slices with image scaling
		IF (N_ELEMENTS(slices_imscale) NE 1) THEN $
      slices_imscale = default_slices_imscale
    ; HISTO_OPT value
		IF (N_ELEMENTS(histo_opt_val) NE 1) THEN histo_opt_val = default_histo_opt_val
    ; Gamma value
		IF (N_ELEMENTS(gamma_val) NE 1) THEN gamma_val = default_gamma_val
    ; Warnings
		IF (N_ELEMENTS(warnings) NE 1) THEN warnings = default_warnings
    ; Window offsets
		IF (N_ELEMENTS(window_offsets) NE 1) THEN window_offsets = {set:0}
    ; Line plot thickness
		IF (N_ELEMENTS(plotthick) NE 1) THEN plotthick = default_plotthick
    ; Overlays thickness and symbol size
    IF (N_ELEMENTS(overlays_symsize) NE 1) THEN $
      overlays_symsize = default_overlays_symsize
    IF (N_ELEMENTS(overlays_thick) NE 1) THEN $
      overlays_thick = default_overlays_thick
	ENDIF ELSE BEGIN                        
    ; If no preference file is present, set defaults
		startupwin = default_startupwin           
    interpspslice = default_interpspslice
		autoplay = default_autoplay               &  defsaveid = default_defsaveid
		defipath = default_defipath               &  defopath = default_defopath
		bgplotcol = default_bgplotcol             &  plotcol = default_plotcol
    plotthick = default_plotthick
    overlays_thick = default_overlays_thick   
    overlays_symsize = default_overlays_symsize
		phislice_update = default_phislice_update 
    slices_imscale = default_slices_imscale
    histo_opt_val = default_histo_opt_val     &  gamma_val = default_gamma_val
    warnings = default_warnings
		resave_preferences = 0
		window_offsets = {set:0}
	ENDELSE

;------------------------- SETTINGS FOR PERFORMANCE SAVE FILE
	hostname = GETENV('HOSTNAME')
  IF (STRLEN(STRCOMPRESS(hostname)) NE 0) THEN hostname += '.'
	cpftfile = FILE_SEARCH(dir_settings+'crispex.'+hostname+'cpft', COUNT = cpftfilecount)
	IF cpftfilecount THEN BEGIN   ; If cpft file is present, restore
		RESTORE, cpftfile[0] 
		IF (verbosity[1] EQ 1) THEN CRISPEX_UPDATE_STARTUP_SETUP_FEEDBACK, 'Restored '+cpftfile[0]+'.'
	ENDIF ELSE BEGIN              ; If not, then initialise variables
		IF (verbosity[1] EQ 1) THEN BEGIN
			CRISPEX_UPDATE_STARTUP_SETUP_FEEDBACK, ['No CRISPEX performance test file (crispex.'+hostname+$
                                             'cpft) found to restore in ',dir_settings]
		ENDIF
		estimate_lx = 0             ; Size variable for time estimate
		estimate_run = 0            ; Run counter for time estimate
		estimate_time = 0.          ; Updated time estimate per unit run and unit slice size
	ENDELSE 

;------------------------- SETTINGS FOR INSTANCES SAVE FILE
	instfilename = 'crispex.'+hostname+'inst'
	IF dir_settings_write THEN BEGIN    ; If instances directory is writeable, start procedures
		instfile = FILE_SEARCH(dir_settings+instfilename, COUNT = instfilecount)
		IF instfilecount THEN BEGIN   ; If inst file is present for current hostname, add current
			IF (verbosity[1] EQ 1) THEN $
        CRISPEX_UPDATE_STARTUP_SETUP_FEEDBACK, 'Opening existing instance tracking file: '+$
                                               instfilename+'.'
			nlines = FILE_LINES(instfile)
			datarr = STRARR(1,nlines)
			OPENR,unit1,instfile,/GET_LUN
			READF,unit1,datarr
			FREE_LUN,unit1
			routine_name = STRARR(nlines)
			instance_id = LONARR(nlines)
			FOR i=1,nlines[0]-1 DO BEGIN
				splitline = STRSPLIT(datarr[i],'	',/EXTRACT)
				routine_name[i] = splitline[0]
				instance_id[i] = splitline[3]
			ENDFOR
			where_crispex = WHERE(routine_name EQ 'CRISPEX', count)
			OPENU, unit2, dir_settings+instfilename, WIDTH = 360, /GET_LUN, /APPEND
		ENDIF ELSE BEGIN              ; If no inst file present for current hostname, make one
			IF (verbosity[1] EQ 1) THEN BEGIN
				CRISPEX_UPDATE_STARTUP_SETUP_FEEDBACK, 'No CRISPEX instance tracking file ('+instfilename+$
                                               ') found in '+dir_settings+'. Creating file.'
			ENDIF
			count = 0
			OPENW, unit2, dir_settings+instfilename, WIDTH = 360, /GET_LUN
			PRINTF, unit2, '# routine_name	version		revision	ID'
		ENDELSE
		IF (count GT 0) THEN $
      set_instance_id = STRTRIM((instance_id[where_crispex])[WHERE(instance_id[where_crispex] EQ $
                        MAX(instance_id[where_crispex], /NAN))] + 1,2) $
    ELSE $
      set_instance_id = STRTRIM(0,2)
		PRINTF, unit2, 'CRISPEX	'+version_number+'	'+revision_number+'	'+set_instance_id
		FREE_LUN, unit2
		IF (set_instance_id GE 1) THEN instance_label = '-'+set_instance_id ELSE instance_label = ''
		IF (verbosity[1] EQ 1) THEN $
      CRISPEX_UPDATE_STARTUP_SETUP_FEEDBACK, 'Written instance ID ('+set_instance_id+') to '+$
                                             instfilename+'.'
	ENDIF ELSE BEGIN
		set_instance_id = ''
		instance_label = ''
		instfilecount = 0
		IF (verbosity[1] EQ 1) THEN BEGIN
 			CRISPEX_UPDATE_STARTUP_SETUP_FEEDBACK, 'ERROR: Could not write CRISPEX instance tracking '+$
                                             'file '+instfilename+'to '+dir_settings+'. Permission denied.'
		ENDIF
	ENDELSE
	
;------------------------- INPUT/OUTPUT PATH SETTINGS
	CD, CURRENT=curpath
	default_prefipath = STRTRIM(curpath+PATH_SEP(),2)
	default_prefopath = default_prefipath
	IF (defipath EQ 0) THEN BEGIN
		prefipath = default_prefipath
		ipath = default_prefipath
	ENDIF ELSE ipath = prefipath
	IF (defopath EQ 0) THEN BEGIN
		prefopath = default_prefopath
		opath = default_prefopath
	ENDIF ELSE opath = prefopath
	opath_write = FILE_TEST(opath, /WRITE)
  IF verbosity[1] THEN BEGIN
    CRISPEX_UPDATE_STARTUP_SETUP_FEEDBACK, 'Input path set to: '+STRTRIM(ipath,2), /NEWLINE, $
                                           /NO_ROUTINE
    CRISPEX_UPDATE_STARTUP_SETUP_FEEDBACK, 'Output path set to: '+STRTRIM(opath,2), /NO_ROUTINE
  ENDIF

;========================= START-UP WINDOW AND SCREEN PARAMETERS
	screeninfo  = OBJ_NEW('IDLsysMonitorInfo')
	nmonitors    = screeninfo -> GetNumberOfMonitors()
	screensizes = screeninfo -> GetRectangles()
	IF (nmonitors GT 1) THEN BEGIN   ; Define monitor order if multiple monitors attached
		monitor_order       = (INDGEN(nmonitors))[SORT(screensizes[0,0:1])]
		monitor_xsize_order = (INDGEN(nmonitors))[SORT(screensizes[2,0:1])]
		monitor_ysize_order = (INDGEN(nmonitors))[SORT(screensizes[3,0:1])]
	ENDIF ELSE BEGIN                ; Default monitor order if only one monitor attached
		monitor_order       = 0
		monitor_ysize_order = 0
	ENDELSE
	x_screen_mid  = screensizes[2,monitor_order[0]]/2.    ; x-coordinate of central screen pixel
	y_screen_mid  = screensizes[3,monitor_order[0]]/2.    ; y-coordinate of central screen pixel
	startup_im    = REBIN(REFORM(TOTAL((CRISPEX_READ_BMP_BUTTONS('crispex_startup.bmp',$
                  dir_resources))[*,*,1:2],3)),400,300)
	startup_nx    = (SIZE(startup_im))[1]                 ; x-size of statup window image
	startup_ny    = (SIZE(startup_im))[2]                 ; y-size of statup window image
	startup_xpos  = FIX(x_screen_mid-startup_nx/2.)       ; x-position of startup window
	startup_ypos  = FIX(y_screen_mid-startup_ny/2.)       ; y-position of startup window
	xout          = REPLICATE(24,9)
	yout          = REPLICATE(FIX(startup_ny/2.5)+10,9)-INDGEN(9)*15
	IF startupwin THEN BEGIN  ; If startup window is to be shown, launch window
		CRISPEX_WINDOW, startup_nx, startup_ny, 0, 'CRISPEX', startuptlb, startupwid, startup_xpos, $
                    startup_ypos, DRAWID = startupdrawid, DRAWBASE = drawbase, $
                    /NO_TLB_KILL_REQUEST
		CRISPEX_UPDATE_STARTUP_FEEDBACK, startup_im, xout, yout, 'Initializing... '
	ENDIF

;========================= READ-IN AND INITIALISATION OF FILES
  ; N.B.: After CRISPEX v1.6.3 FITS cubes have become the standard. Old read-in
  ; procedures are retained in compatibility for older cubes. Differentiation is
  ; performed based on filename extension, where FITS cubes are assumed to have a
  ; *.fits extension (case insensitive).
  IF startupwin THEN CRISPEX_UPDATE_STARTUP_FEEDBACK, startup_im, xout, yout, $
    'Reading input files... '
  IF ((BYTE(1L,0,1))[0] EQ 1) THEN endian = 'l' ELSE endian = 'b' ; Check endianness of machine
  dt_keyword_set = (N_ELEMENTS(DT) EQ 1) 
  IF (dt_keyword_set EQ 0) THEN dt = 0.
  ; Set maximum of SJI files
  nsjifiles_max = 6

  ; Check whether main input file (Imcube) is a session file
  IF KEYWORD_SET(LAST_SESSION) THEN BEGIN
    Imcube = dir_settings+'crispex_last_session.cses' 
    ; Failsafe against non-existing last save file
    IF NOT FILE_TEST(Imcube) THEN BEGIN
      CRISPEX_UPDATE_STARTUP_SETUP_FEEDBACK, 'Could not find last session '+$
      'file to restore from in '+dir_settings, /ERROR, /NO_ROUTINE
			IF (N_ELEMENTS(STARTUPTLB) EQ 1) THEN WIDGET_CONTROL, startuptlb, /DESTROY
      RETURN
    ENDIF
  ENDIF 
  imcube_ext = STRMID(Imcube,STRPOS(Imcube,'.',$
    /REVERSE_SEARCH)+1,STRLEN(Imcube))  ; Process extension
  restore_from_session = STRMATCH(imcube_ext,'cses',/FOLD_CASE) 
  IF restore_from_session THEN BEGIN
    restore_session_file = Imcube
    RESTORE, restore_session_file, VERBOSE=verbosity[1]
    ; Recover hdr variable
    hdr = *ioparams.hdr
    ; Extract local variables
    imcube = hdr.imfilename
    ; Failsafe
    IF (STRCOMPRESS(hdr.spfilename, /REMOVE_ALL) NE '') THEN $
      spcube = hdr.spfilename
    refcube = hdr.refimfilename
    ; Failsafe
    IF (STRCOMPRESS(hdr.refspfilename, /REMOVE_ALL) NE '') THEN $
      refcube = [refcube, hdr.refspfilename]
    sjicube = hdr.sjifilename
    maskcube = hdr.maskfilename
    spectfile = hdr.spectfile
    IF (spectfile[1] EQ '') THEN spectfile = spectfile[0]
    dt = hdr.dt
    exts = dispswitch.exts
    mnspec = hdr.mnspec
    line_center = *hdr.line_center
    single_cube = hdr.single_cube
    scale_stokes = stokesparams.contpos
    no_warp = hdr.no_warp
    xtitle = hdr.xtitle
    ytitle = hdr.ytitle
    window_large = hdr.window_large
    override_winswitch = winswitch
    call_verbosity = verbosity
    ; Call verbosity overrides saved verbosity if > 0
    IF (TOTAL(call_verbosity) GT 0) THEN $
      verbosity = call_verbosity $
    ELSE $
      verbosity = hdr.verbosity
    IF ((call_verbosity[0] NE verbosity[0]) OR $
      (call_verbosity[1] NE verbosity[1]) )THEN verbosity[0:1] = call_verbosity[0:1]
    ; Failsafes for non-set input keywords
    IF (refcube[0] EQ '') THEN refcube = !NULL
    wheresjivalid = WHERE(hdr.sjifilename NE '', count)
    IF (count GT 0) THEN $
      sjicube = sjicube[wheresjivalid] $
    ELSE $
      sjicube = !NULL
    IF (maskcube EQ '') THEN maskcube = !NULL
    IF (spectfile[0] EQ '') THEN spectfile = !NULL
    IF (TOTAL(mnspec) EQ 0) THEN mnspec = !NULL
    IF (TOTAL(line_center) EQ 0) THEN line_center = !NULL
    IF (TOTAL(single_cube) EQ 0) THEN single_cube = !NULL
  ENDIF ELSE BEGIN
    ; Handle input file headers by parsing them into the hdr structure; 
    ; first initialise hdr
    hdr = {$
              ; Data types
              imtype:0, sptype:0, refimtype:0, refsptype:0, $
              sjitype:REPLICATE(0,nsjifiles_max), $
              masktype:0, $
              ; Data offsets within file
              imoffset:0L, spoffset:0L, refimoffset:0L, refspoffset:0L, $
              sjioffset:REPLICATE(0L,nsjifiles_max), maskoffset:0L, $
              ; Endians, OBSID and DATE_OBS
              imendian:'b', spendian:'b', refimendian:'b', refspendian:'b', $
              sjiendian:REPLICATE('b',nsjifiles_max), maskendian:'b',endian:endian, obsid:'0', $
              date_obs_main:'0', date_obs_ref:'0', $
              startobs_main:'0', startobs_ref:'0', $
              instr_main:'N/A', instr_ref:'N/A', $
              startobs_sji:REPLICATE('0',nsjifiles_max), $
              date_obs_sji:REPLICATE('0',nsjifiles_max), $
              ; Compatibility switches
              imcube_compatibility:0B, spcube_compatibility:0B, $
              refimcube_compatibility:0B, refspcube_compatibility:0B, $
              maskcube_compatibility:0B, multichannel:0B, refmultichannel:0B, $
              ; Data dimensions
              nx:0L, ny:0L, nlp:1L, mainnt:1L, ns:1L, imnt:0L, spnt:0L, imns:0L, $
              spns:0L, $ 
              refnx:0L, refny:0L, refnlp:0L, refnt:0L, refns:1L, refimnt:0L, $
              refimns:0L, refspns:0L, $
              refspnt:0L, refspnx:0L, refspny:0L, $
              sjinx:REPLICATE(0L,nsjifiles_max), sjiny:REPLICATE(0L,nsjifiles_max), $
              sjint:REPLICATE(0L,nsjifiles_max), $
              masknx:0L, maskny:0L, masknt:0L, $
              ; Data ranges
              lp_restr_slid_low_sens:0, lp_restr_slid_upp_sens:0, $
              ; Spatial reference values
              xpix:0L, ypix:0L, xval:0., yval:0., xpix_ref:0L, ypix_ref:0L, $
              xval_ref:0., yval_ref:0., $
              xpix_sji:REPLICATE(0L,nsjifiles_max), $
              ypix_sji:REPLICATE(0L,nsjifiles_max), $
              xval_sji:REPLICATE(0.,nsjifiles_max), $
              yval_sji:REPLICATE(0.,nsjifiles_max), $
              main2ref_no_map:1, wcs_set:0, ref_wcs_set:0, $
              sji_wcs_set:REPLICATE(0,nsjifiles_max), $
              xyoffset_sji:FLTARR(2,nsjifiles_max), $
              ; Pixel sizes
              dx:1., dy:1., dt:dt, dx_fixed:0B, $
              refdx:1., refdy:1., refdt:dt, sjidt:dt, $
              sjidx:REPLICATE(1.,nsjifiles_max), sjidy:REPLICATE(1.,nsjifiles_max), $
              ; Data scaling variables
              imbscale:0., imbzero:0., imscaled:0B, $
              spbscale:0., spbzero:0., spscaled:0B, $
              refimbscale:0., refimbzero:0., refimscaled:0B, $
              refspbscale:0., refspbzero:0., refspscaled:0B, $
              sjibscale:REPLICATE(0.,nsjifiles_max),$
              sjibzero:REPLICATE(0.,nsjifiles_max),$
              sjiscaled:REPLICATE(0B,nsjifiles_max), $
              ; Timing variables
              tarr_sji:PTRARR(nsjifiles_max, /ALLOCATE_HEAP), $
              tsel_sji:PTRARR(nsjifiles_max, /ALLOCATE_HEAP), $
              date_sji:PTRARR(nsjifiles_max, /ALLOCATE_HEAP), $
              hdrs_sji:PTRARR(nsjifiles_max, /ALLOCATE_HEAP), $
              wcs_sji:PTRARR(nsjifiles_max, /ALLOCATE_HEAP), $
              utc_sji:PTRARR(nsjifiles_max, /ALLOCATE_HEAP), $
              ; Axes labels and units
              xunit:'arcsec', yunit:'arcsec', tunit:'', lpunit:'', sunit:'', $
              bunit:'counts', xlabel:'x', ylabel:'y', tlabel:'Frame number', $
              lplabel:'Spectral position', slabel:'', blabel:'Intensity', $
              refxunit:'arcsec', refyunit:'arcsec', reflpunit:'', $
              refbunit:'counts', refxlabel:'x', refylabel:'y', reftlabel:'', $
              reflplabel:'', refblabel:'Intensity', $
              sjibunit:REPLICATE('counts',nsjifiles_max), $
              xtitle:STRARR(2), ytitle:STRARR(2), refspxtitle:'', spxtitle:'', $
              spytitle:'', $
              ; Stokes and diagnostics parameters
              imstokes:'', spstokes:'', refimstokes:'', refspstokes:'', $
              imdiagnostics:'', $
              stokes_enabled:[0,0,0,0], refstokes_enabled:[0,0,0,0],  $
              ndiagnostics:1, nrefdiagnostics:1, $
              ; File units
              lunim:0, lunsp:0, lunrefim:0, lunrefsp:0, $
              lunsji:REPLICATE(0,nsjifiles_max), lunmask:0, $
              ; File names
              imfilename:'', spfilename:'', refimfilename:'', refspfilename:'', $
              sjifilename:REPLICATE('',nsjifiles_max), maskfilename:'', $
              ; File switches
              spfile:0, onecube:0, single_cube:[0,0], showref:0, refspfile:0, $
              nsjifiles:0, nsjifiles_max:nsjifiles_max, sjifile:0, maskfile:0, $ 
              ; Call parameters not otherwise initialised or stored in info
              ; pointer
              spectfile:['',''], line_center:PTR_NEW(0), mnspec:[0,0], $
              no_warp:0, window_large:0, $
              ; Data pointers
              imdata:PTR_NEW(0), scan:PTR_NEW(0), spdata:PTR_NEW(0), $
              spectra:PTR_NEW(0), refdata:PTR_NEW(0), refslice:PTR_NEW(0), $
              refspdata:PTR_NEW(0), refscan:PTR_NEW(0), refsspscan:PTR_NEW(0), $
              sjidata:PTRARR(nsjifiles_max,/ALLOCATE_HEAP), $
              sjislice:PTRARR(nsjifiles_max,/ALLOCATE_HEAP), maskdata:PTR_NEW(0), $
              ; Miscellaneous
              ipath:ipath, opath:opath, instance_label:instance_label, $
              verbosity:verbosity $
              }
  ENDELSE

  CRISPEX_IO_OPEN_MAINCUBE, IMCUBE=imcube, SPCUBE=spcube, HDR_IN=hdr, HDR_OUT=hdr, $
                            SINGLE_CUBE=single_cube, STARTUPTLB=startuptlb, $
                            IO_FAILSAFE_MAIN_ERROR=io_failsafe_main_error, $
                            RESTORE_FROM_SESSION=restore_from_session
  IF (io_failsafe_main_error EQ 1) THEN BEGIN
    CRISPEX_CLOSE_FREE_LUN, hdr.lunim, hdr.lunsp, hdr.lunrefim, hdr.lunrefsp, $
      hdr.lunmask, hdr.lunsji, IMDISP=(hdr.lunim NE 0), SPDISP=(hdr.lunsp NE 0), $
      REFIMDISP=(hdr.lunrefim NE 0), REFSPDISP=(hdr.lunrefsp NE 0), $
      MASKDISP=(hdr.lunmask NE 0), SJIDISP=(TOTAL(hdr.lunsji) NE 0)
    IF (hdr.lunsp NE 0) THEN FREE_LUN, hdr.lunsp
    WIDGET_CONTROL, startuptlb, /DESTROY
    RETURN
  ENDIF

  CRISPEX_IO_OPEN_REFCUBE, REFCUBE=refcube, HDR_IN=hdr, HDR_OUT=hdr, $
                            SINGLE_CUBE=single_cube, $
                            IO_FAILSAFE_REF_ERROR=io_failsafe_ref_error, $
                            IO_FAILSAFE_MAIN_REF_ERROR=io_failsafe_main_ref_error,$
                            RESTORE_FROM_SESSION=restore_from_session
  IF ((io_failsafe_ref_error EQ 1) OR (io_failsafe_main_ref_error EQ 1)) THEN BEGIN
    CRISPEX_CLOSE_FREE_LUN, hdr.lunim, hdr.lunsp, hdr.lunrefim, hdr.lunrefsp, $
      hdr.lunmask, hdr.lunsji, IMDISP=(hdr.lunim NE 0), SPDISP=(hdr.lunsp NE 0), $
      REFIMDISP=(hdr.lunrefim NE 0), REFSPDISP=(hdr.lunrefsp NE 0), $
      MASKDISP=(hdr.lunmask NE 0), SJIDISP=(TOTAL(hdr.lunsji) NE 0)
    WIDGET_CONTROL, startuptlb, /DESTROY
    RETURN
  ENDIF
  IF ((N_ELEMENTS(REFCUBE) LT 1) AND ~KEYWORD_SET(RESTORE_FROM_SESSION)) THEN $
    hdr = CREATE_STRUCT(hdr, 'refdiagnostics', 'N/A', 'refdiag_start', 0, $
            'refdiag_width', 1, 'tarr_ref', 0, 'tarr_full_ref', 0, $
            'toffset_ref', 0, 'hdrs_ref', PTR_NEW(''), 'wcs_ref', 0, $
            'utc_ref', '0', 'utc_full_ref', 0, 'date_ref', 'N/A', $
            'date_full_ref', 'N/A', 'tfull_dims_ref', 0, $
            'update_tfull_ref', BYTARR(4))
  IF (hdr.nsjifiles GT 6) THEN BEGIN
    ; Failsafe against too many SJI files
    MESSAGE, 'ERROR: CRISPEX is currently limited to displaying up to 6 '+$
      'SJICUBE files simultaneously (you have provided '+$
      STRTRIM(hdr.nsjifiles,2)+'). Please ammend your input.', /INFO
    CRISPEX_CLOSE_FREE_LUN, hdr.lunim, hdr.lunsp, hdr.lunrefim, hdr.lunrefsp, $
      hdr.lunmask, hdr.lunsji, IMDISP=(hdr.lunim NE 0), SPDISP=(hdr.lunsp NE 0), $
      REFIMDISP=(hdr.lunrefim NE 0), REFSPDISP=(hdr.lunrefsp NE 0), $
      MASKDISP=(hdr.lunmask NE 0), SJIDISP=(TOTAL(hdr.lunsji) NE 0)
    WIDGET_CONTROL, startuptlb, /DESTROY
    RETURN
  ENDIF

  CRISPEX_IO_OPEN_SJICUBE, SJICUBE=sjicube, HDR_IN=hdr, HDR_OUT=hdr, $  
                            OFFSET_SJI=offset_sji, $
                            STARTUPTLB=startuptlb, $
                            IO_FAILSAFE_SJI_ERROR=io_failsafe_sji_error, $
                            RESTORE_FROM_SESSION=restore_from_session
  IF (io_failsafe_sji_error EQ 1) THEN BEGIN
    CRISPEX_CLOSE_FREE_LUN, hdr.lunim, hdr.lunsp, hdr.lunrefim, hdr.lunrefsp, $
      hdr.lunmask, hdr.lunsji, IMDISP=(hdr.lunim NE 0), SPDISP=(hdr.lunsp NE 0), $
      REFIMDISP=(hdr.lunrefim NE 0), REFSPDISP=(hdr.lunrefsp NE 0), $
      MASKDISP=(hdr.lunmask NE 0), SJIDISP=(TOTAL(hdr.lunsji) NE 0)
    WIDGET_CONTROL, startuptlb, /DESTROY
    RETURN
  ENDIF

  IF ~KEYWORD_SET(RESTORE_FROM_SESSION) THEN BEGIN
    ; Populate containers for headers and number of extensions
    hdrs = PTRARR(2+hdr.nsjifiles_max)
    next = LONARR(2+hdr.nsjifiles_max)
    hdrs[0] = PTR_NEW(hdr.hdrs_main)
    hdrs[1] = PTR_NEW(hdr.hdrs_ref)
    next[0:1]= [N_ELEMENTS(hdr.hdrs_main), N_ELEMENTS(hdr.hdrs_ref)]
    FOR idx_sji=0,hdr.nsjifiles-1 DO BEGIN
      hdrs[2+idx_sji] = PTR_NEW(*hdr.hdrs_sji[idx_sji])
      next[2+idx_sji] = N_ELEMENTS(*hdr.hdrs_sji[idx_sji])
    ENDFOR

    ; If WCS information is present, use that to get conversion maps
    ; Set defaults first
    pix_main2ref = 0.
    pix_ref2main = 0.
    pix_main2sji = PTRARR(hdr.nsjifiles_max, /ALLOCATE_HEAP)
    pix_sji2main = PTRARR(hdr.nsjifiles_max, /ALLOCATE_HEAP)
    pix_ref2sji = PTRARR(hdr.nsjifiles_max, /ALLOCATE_HEAP)
    pix_sji2ref = PTRARR(hdr.nsjifiles_max, /ALLOCATE_HEAP) 
    pix_sji2sji = PTRARR(hdr.nsjifiles_max,hdr.nsjifiles_max, /ALLOCATE_HEAP)
    ; Compute values depending on availability of files
    IF hdr.showref THEN BEGIN
      IF (hdr.wcs_set AND hdr.ref_wcs_set) THEN BEGIN
        pix_main2ref = ROUND(WCS_GET_PIXEL(hdr.wcs_ref, WCS_GET_COORD(hdr.wcs_main)))
        pix_ref2main = ROUND(WCS_GET_PIXEL(hdr.wcs_main, WCS_GET_COORD(hdr.wcs_ref)))
      ENDIF ELSE BEGIN
        result = CRISPEX_TRANSFORM_GET_COORDMAPS(hdr, /MAINREF)
        pix_main2ref = ROUND(result.pix_a2b)
        pix_ref2main = ROUND(result.pix_b2a)
      ENDELSE
    ENDIF 
    IF hdr.sjifile THEN BEGIN
      FOR idx_sji=0,hdr.nsjifiles-1 DO BEGIN
        ; Get conversion between main and SJI
        IF (hdr.wcs_set AND hdr.sji_wcs_set[idx_sji]) THEN BEGIN
          *pix_main2sji[idx_sji] = $
            ROUND(WCS_GET_PIXEL(*hdr.wcs_sji[idx_sji], WCS_GET_COORD(hdr.wcs_main)))
          *pix_sji2main[idx_sji] = $
            ROUND(WCS_GET_PIXEL(hdr.wcs_main, WCS_GET_COORD(*hdr.wcs_sji[idx_sji])))
        ENDIF ELSE BEGIN
          result = CRISPEX_TRANSFORM_GET_COORDMAPS(hdr, /MAINSJI, IDX_SJI=idx_sji)
          *pix_main2sji[idx_sji] = ROUND(result.pix_a2b)
          *pix_sji2main[idx_sji] = ROUND(result.pix_b2a)
        ENDELSE
        ; Get conversion between reference and SJI
        IF hdr.showref THEN BEGIN
          IF (hdr.ref_wcs_set AND hdr.sji_wcs_set[idx_sji]) THEN BEGIN
            *pix_ref2sji[idx_sji] = $
              ROUND(WCS_GET_PIXEL(*hdr.wcs_sji[idx_sji], WCS_GET_COORD(hdr.wcs_ref)))
            *pix_sji2ref[idx_sji] = $
              ROUND(WCS_GET_PIXEL(hdr.wcs_ref, WCS_GET_COORD(*hdr.wcs_sji[idx_sji])))
          ENDIF ELSE BEGIN
            result = CRISPEX_TRANSFORM_GET_COORDMAPS(hdr, /REFSJI, IDX_SJI=idx_sji)
            *pix_ref2sji[idx_sji] = ROUND(result.pix_a2b)
            *pix_sji2ref[idx_sji] = ROUND(result.pix_b2a)
          ENDELSE
        ENDIF
        ; Get conversion between SJIs 
        FOR idx_tmp_sji=0,hdr.nsjifiles-1 DO BEGIN
          IF (hdr.sji_wcs_set[idx_sji] AND hdr.sji_wcs_set[idx_tmp_sji]) THEN $
            *pix_sji2sji[idx_sji,idx_tmp_sji] = $
              ROUND(WCS_GET_PIXEL(*hdr.wcs_sji[idx_tmp_sji], $
                    WCS_GET_COORD(*hdr.wcs_sji[idx_sji]))) 
        ENDFOR
      ENDFOR
    ENDIF 
    hdr = CREATE_STRUCT(hdr, 'hdrs', hdrs, 'next', next, $
      'pix_main2ref', pix_main2ref, 'pix_ref2main', pix_ref2main, $
      'pix_main2sji', pix_main2sji, 'pix_sji2main', pix_sji2main, $
      'pix_sji2ref', pix_sji2ref, 'pix_ref2sji', pix_ref2sji, $
      'pix_sji2sji', pix_sji2sji)
  ENDIF

  CRISPEX_IO_OPEN_MASKCUBE, MASKCUBE=maskcube, HDR_IN=hdr, HDR_OUT=hdr, $
                            STARTUPTLB=startuptlb, $
                            IO_FAILSAFE_MASK_ERROR=io_failsafe_mask_error
  IF (io_failsafe_mask_error EQ 1) THEN BEGIN
    CRISPEX_CLOSE_FREE_LUN, hdr.lunim, hdr.lunsp, hdr.lunrefim, hdr.lunrefsp, $
      hdr.lunmask, hdr.lunsji, IMDISP=(hdr.lunim NE 0), SPDISP=(hdr.lunsp NE 0), $
      REFIMDISP=(hdr.lunrefim NE 0), REFSPDISP=(hdr.lunrefsp NE 0), $
      MASKDISP=(hdr.lunmask NE 0), SJIDISP=(TOTAL(hdr.lunsji) NE 0)
    WIDGET_CONTROL, startuptlb, /DESTROY
    RETURN
  ENDIF

	IF (hdr.refnlp NE hdr.nlp) THEN BEGIN
		eqnlps = 0 
		refslid_sens = (hdr.showref AND (hdr.refnlp GT 1)) 
	ENDIF ELSE BEGIN
		eqnlps = 1
		refslid_sens = 0
	ENDELSE
	
  IF startupwin THEN CRISPEX_UPDATE_STARTUP_FEEDBACK, startup_im, xout, yout, $
                                                      'Reading input files... done!'

	DEVICE, DECOMPOSE = 0	

;========================= SETTING START-UP OPTIONS 
;------------------------- PARAMETERS FROM MEAN SPEC
	IF (TOTAL(verbosity[0:1]) GE 1) THEN CRISPEX_UPDATE_STARTUP_SETUP_FEEDBACK, $
                                        '(parameters from/for mean spectrum)', /OPT, /OVER
	feedback_text = ['Setting start-up options... ','> Parameters from/for mean spectrum... ']
	IF startupwin THEN CRISPEX_UPDATE_STARTUP_FEEDBACK, startup_im, xout, yout, feedback_text
	detspect_scale_enable = (hdr.nlp GT 1)
	detspect_scale = 1      ; Default regardless of spectral info or not
	ref_detspect_scale = 1  ; Default regardless of spectral info or not 
  scalestokes = [((hdr.ns GT 1) AND (hdr.nlp GT 1)), $
                 ((hdr.refns GT 1) AND (hdr.refnlp GT 1))] ; Default for main and reference

  IF ((N_ELEMENTS(SCALE_STOKES) LT 1) OR (N_ELEMENTS(SCALE_STOKES) GT 2)) THEN $
    scale_stokes = [0,0] $
  ELSE IF (N_ELEMENTS(SCALE_STOKES) EQ 1) THEN $
    scale_stokes = [scale_stokes,0]

  ; Set final XTITLE and YTITLE variables for LS and SP windows
	IF (N_ELEMENTS(XTITLE) EQ 1) THEN BEGIN         
    IF (N_ELEMENTS(REFXTITLE) EQ 1) THEN $        
      ; If both main and reference xtitle given, use them
      hdr.xtitle = [xtitle[0],refxtitle[0]] $     
    ELSE $                                        
      ; Else, fill xtitle variable only with main
      hdr.xtitle = [xtitle[0],''] 
  ENDIF ELSE IF (N_ELEMENTS(XTITLE) EQ 2) THEN $  
    ; If xtitle keyword provided with 2 elements, use them
    hdr.xtitle = xtitle $                         
  ELSE IF (N_ELEMENTS(REFXTITLE) EQ 1) THEN $     
    ; If REFXTITLE provided, use that one
    hdr.xtitle = ['',refxtitle[0]]                
  ; Repeat procedure for YTITLE/REFYTITLE
	IF (N_ELEMENTS(YTITLE) EQ 1) THEN BEGIN         
    IF (N_ELEMENTS(REFYTITLE) EQ 1) THEN $        
      hdr.ytitle = [ytitle[0],refytitle[0]] $     
    ELSE $                                        
      hdr.ytitle = [ytitle[0],''] 
  ENDIF ELSE IF (N_ELEMENTS(YTITLE) EQ 2) THEN $  
    hdr.ytitle = ytitle $                         
  ELSE IF (N_ELEMENTS(REFYTITLE) EQ 1) THEN $     
    hdr.ytitle = ['',refytitle[0]]                
 
  IF (restore_from_session EQ 0) THEN BEGIN
    CRISPEX_IO_SETTINGS_SPECTRAL, HDR_IN=hdr, HDR_OUT=hdr, $
      /MAIN, REFERENCE=(hdr.refnlp GE 1), MNSPEC=mnspec, $
      SPECTFILE=spectfile, LINE_CENTER=line_center, NO_WARP=no_warp, $
      STARTUPTLB=startuptlb, IO_FAILSAFE_MNSPEC_ERROR=io_failsafe_mnspec_error, $
      IO_FAILSAFE_IMSPECTFILE_ERROR=io_failsafe_imspectfile_error, $
      IO_FAILSAFE_REFSPECTFILE_ERROR=io_failsafe_refspectfile_error, $
      IO_FAILSAFE_LINE_CENTER_ERROR=io_failsafe_line_center_error

    IF ((io_failsafe_mnspec_error EQ 1) OR (io_failsafe_imspectfile_error EQ 1) OR $
        (io_failsafe_refspectfile_error EQ 1) OR $
        (io_failsafe_line_center_error EQ 1)) THEN BEGIN
      CRISPEX_CLOSE_FREE_LUN, hdr.lunim, hdr.lunsp, hdr.lunrefim, hdr.lunrefsp, $
        hdr.lunmask, hdr.lunsji, IMDISP=(hdr.lunim NE 0), SPDISP=(hdr.lunsp NE 0), $
        REFIMDISP=(hdr.lunrefim NE 0), REFSPDISP=(hdr.lunrefsp NE 0), $
        MASKDISP=(hdr.lunmask NE 0), SJIDISP=(TOTAL(hdr.lunsji) NE 0)
      WIDGET_CONTROL, startuptlb, /DESTROY
      RETURN
    ENDIF
  ENDIF
  
	IF (TOTAL(verbosity[0:1]) GE 1) THEN CRISPEX_UPDATE_STARTUP_SETUP_FEEDBACK, $
                                        '(parameters from/for mean spectrum)', /OPT, /OVER, /DONE, $
                                        REPEAT_STAGE=(verbosity[1] OR $
                                          (io_failsafe_imspectfile_error EQ 2) OR $
                                          (io_failsafe_refspectfile_error EQ 2))
	feedback_text = [feedback_text[0:N_ELEMENTS(feedback_text)-2],$
                   '> Parameters from/for mean spectrum... done!']
	IF startupwin THEN CRISPEX_UPDATE_STARTUP_FEEDBACK, startup_im, xout, yout, feedback_text

;------------------------- INITIAL SLIT PARAMETERS
	IF (TOTAL(verbosity[0:1]) GE 1) THEN CRISPEX_UPDATE_STARTUP_SETUP_FEEDBACK, $
                                        '(initial slit parameters)', /OPT, /OVER
	feedback_text = [feedback_text,'> Initial slit parameters... ']
	IF startupwin THEN CRISPEX_UPDATE_STARTUP_FEEDBACK, startup_im, xout, yout, feedback_text

  nphi	= LONG(CEIL(SQRT( FLOAT(hdr.nx)^2 + FLOAT(hdr.ny)^2 )))	; Determine maximum number of slitpositions
	angle = 90														; Set initial angle of the slit

  IF (TOTAL(verbosity[0:1]) GE 1) THEN CRISPEX_UPDATE_STARTUP_SETUP_FEEDBACK, $
                                        '(initial slit parameters)', /OPT, /OVER, /DONE
	feedback_text = [feedback_text[0:N_ELEMENTS(feedback_text)-2],'> Initial slit parameters... done!']
	IF startupwin THEN CRISPEX_UPDATE_STARTUP_FEEDBACK, startup_im, xout, yout, feedback_text

;------------------------- INITIAL PLAYBACK PARAMETERS
	IF (TOTAL(verbosity[0:1]) GE 1) THEN CRISPEX_UPDATE_STARTUP_SETUP_FEEDBACK, $
                                        '(initial playback parameters)', /OPT, /OVER
	feedback_text = [feedback_text,'> Initial playback parameters... ']
	IF startupwin THEN CRISPEX_UPDATE_STARTUP_FEEDBACK, startup_im, xout, yout, feedback_text
	t_first		= 0L													; Set number of first frame		
  t_last = hdr.mainnt-1													; Set number of last frame
  t_slid_sens = (hdr.mainnt NE 1)
	t_step		= 1L													; Set initial timestep
	t_speed 	= 10													; Set initial animation speed
	direction 	= 1													; Set initial animation direction
	t_start = t_first

  ; Check setting of DT keyword; is superseded by FITS header information, if present
  IF dt_keyword_set THEN BEGIN
    dt_set = dt_keyword_set
    IF hdr.imcube_compatibility THEN BEGIN
			IF (N_ELEMENTS(SPYTITLE) NE 1) THEN spytitle = 'Time [s]'
    ENDIF ELSE spytitle = hdr.spytitle
  ; If no DT set, check whether supplied from FITS header (in which case hdr.dt ne 0)
  ENDIF ELSE BEGIN
    dt_set = ((hdr.dt NE 0.) OR (hdr.refdt NE 0.) OR (hdr.sjidt NE 0.))
    IF dt_set THEN $
      spytitle = hdr.spytitle $   ; FITS header: no override of SPYTITLE allowed
    ; If no DT set and no info from header, then set defaults
    ELSE BEGIN
      IF (hdr.dt EQ 0.) THEN hdr.dt = 1.
      IF (hdr.refdt EQ 0.) THEN hdr.refdt = 1.
      IF (hdr.sjidt EQ 0.) THEN hdr.sjidt = 1.
			IF (N_ELEMENTS(SPYTITLE) NE 1) THEN spytitle = 'Frame number'
    ENDELSE
  ENDELSE

  ; Handle SJI (pointers to allow multiple files)
  t_sji = LONARR(hdr.nsjifiles_max)
  t_low_sji = LONARR(hdr.nsjifiles_max)
  t_upp_sji = LONARR(hdr.nsjifiles_max)
  t_sji_old = LONARR(hdr.nsjifiles_max)
  disp_tarr_sji = PTRARR(hdr.nsjifiles_max, /ALLOCATE_HEAP)
  disp_utc_sji = PTRARR(hdr.nsjifiles_max, /ALLOCATE_HEAP)
  IF hdr.sjifile THEN BEGIN
    FOR idx_sji=0,hdr.nsjifiles-1 DO BEGIN
      t_sji[idx_sji] = (*hdr.tsel_sji[idx_sji])[0]
      t_low_sji[idx_sji] = (*hdr.tsel_sji[idx_sji])[0]
      t_upp_sji[idx_sji] = (*hdr.tarr_sji[idx_sji])[(hdr.sjint[idx_sji]-1)>0]
      t_sji_old[idx_sji] = (*hdr.tsel_sji[idx_sji])[0]
      *disp_tarr_sji[idx_sji] = (*hdr.tarr_sji[idx_sji])[*hdr.tsel_sji[idx_sji]]
      *disp_utc_sji[idx_sji] = (*hdr.utc_sji[idx_sji])[*hdr.tsel_sji[idx_sji]]
    ENDFOR
  ENDIF 

	IF (TOTAL(verbosity[0:1]) GE 1) THEN CRISPEX_UPDATE_STARTUP_SETUP_FEEDBACK, $
                                        '(initial playback parameters)', /OPT, /OVER, /DONE
	feedback_text = [feedback_text[0:N_ELEMENTS(feedback_text)-2],'> Initial playback parameters... done!']
	IF startupwin THEN $
    CRISPEX_UPDATE_STARTUP_FEEDBACK, startup_im, xout, yout, feedback_text

;------------------------- INITIAL SPECTRAL PARAMETERS
	IF (TOTAL(verbosity[0:1]) GE 1) THEN CRISPEX_UPDATE_STARTUP_SETUP_FEEDBACK, $
                                        '(initial spectral parameters)', /OPT, /OVER
	feedback_text = [feedback_text,'> Initial spectral parameters... ']
	IF startupwin THEN $
    CRISPEX_UPDATE_STARTUP_FEEDBACK, startup_im, xout, yout, feedback_text
	lp_first 	= 0L													; Set number of first lineposition
	lp_last		= hdr.nlp-1L													; Set number of last lineposition
	sp		= hdr.mainnt * hdr.nlp												; Set spectral dimension
	lp_start 	= hdr.lc
	lp_ref_first = lp_first

  ; Switch for single wavelength spectral windows cube
  singlewav_windows = (FIX(TOTAL(hdr.diag_width)) EQ hdr.ndiagnostics)
  refsinglewav_windows = (FIX(TOTAL(hdr.refdiag_width)) EQ hdr.nrefdiagnostics)

  showls = ((hdr.spfile OR (hdr.nlp GT 1)) AND (singlewav_windows EQ 0))
  showrefls = $
    ((hdr.refspfile OR (hdr.refnlp GT 1)) AND (refsinglewav_windows EQ 0))
 
  IF (hdr.refnlp GT 1) THEN BEGIN
    lp_ref_last = hdr.refnlp - 1L
    lp_ref_start = hdr.reflc
	ENDIF ELSE BEGIN
		lp_ref_last = 1L
		lp_ref_start = 0L
	ENDELSE
  lp_ref_lock = eqnlps ;(eqnlps AND (lp_ref_start EQ lp_start))
  IF lp_ref_lock THEN lp_ref_start = lp_start

  ; Determine whether we're dealing with height instead of wavelength
	heightset 	= 0
	refheightset 	= 0
	IF ((N_ELEMENTS(hdr.xtitle) GE 1) AND (N_ELEMENTS(hdr.xtitle) LE 2)) THEN BEGIN
		IF (STRCOMPRESS(hdr.xtitle[0]) NE '') THEN BEGIN
			heightset = (STRCMP(hdr.xtitle[0],'Height',6,/FOLD_CASE) OR $
                   STRCMP(hdr.xtitle[0],'z',1,/FOLD_CASE))
      IF heightset THEN BEGIN
  			hdr.v_dop_set[0] = 0
  			hdr.spxtitle = hdr.xtitle[0]
      ENDIF
		ENDIF
		IF (N_ELEMENTS(hdr.xtitle) EQ 2) THEN BEGIN
			IF (STRCOMPRESS(hdr.xtitle[1]) NE '') THEN BEGIN
				refheightset = (STRCMP(hdr.xtitle[1],'Height',6,/FOLD_CASE) OR $
                        STRCMP(hdr.xtitle[1],'z',1,/FOLD_CASE))
        IF refheightset THEN BEGIN
				  hdr.v_dop_set[1] = 0
				  hdr.refspxtitle = hdr.xtitle[1]
        ENDIF
			ENDIF
		ENDIF
	ENDIF
	IF heightset THEN detspect_scale = 0
	IF refheightset THEN ref_detspect_scale = 0

	sp_h 	        = ['Spectral','Height']
	wav_h 	      = ['Wavelength','Height']
	lp_h_capital	= ['S','H']
	but_tooltip   = ['Spectrum','Height profile']
  IF hdr.v_dop_set[0] THEN BEGIN
    lp_min_lab = 'Doppler minimum [km/s]'
    lp_max_lab = 'Doppler maximum [km/s]'
  ENDIF ELSE BEGIN
    lp_min_lab = 'Lower spectral position'
    lp_max_lab = 'Upper spectral position'
  ENDELSE
  lp_min_lab = [lp_min_lab, 'Minimum '+STRLOWCASE(sp_h[1])+' ['+hdr.xunit+']']
  lp_max_lab = [lp_max_lab, 'Maximum '+STRLOWCASE(sp_h[1])+' ['+hdr.xunit+']']

  ; Load (ref)lsytitles from FITS cubes or SPECTFILE
	lsytitle	= hdr.ytitle[0]
	reflsytitle	= hdr.ytitle[1]
  ; Override by XTITLE and YTITLE keywords, if set
	IF ((N_ELEMENTS(YTITLE) GE 1) AND (N_ELEMENTS(YTITLE) LE 2)) THEN BEGIN
		IF (STRCOMPRESS(ytitle[0]) NE '') THEN lsytitle = ytitle[0]
		IF (N_ELEMENTS(YTITLE) EQ 2) THEN BEGIN
			IF (STRCOMPRESS(ytitle[1]) NE '') THEN reflsytitle = ytitle[1]
		ENDIF
	ENDIF
  ; Default axis (tick) labels
  lsytitles = REPLICATE(lsytitle,4)
  lsxtitles = REPLICATE(hdr.spxtitle,4)
  lsxticknames = PTRARR(4, /ALLOCATE_HEAP)
  lsyticknames = PTRARR(4, /ALLOCATE_HEAP)
  lsdopxticknames = PTRARR(2, /ALLOCATE_HEAP)
  lsdopxtitle = 'Doppler velocity [km/s]'
  lsdopxtitles = REPLICATE((['',lsdopxtitle])[hdr.v_dop_set[0]], 2)
  *lsdopxticknames[0] = '' 
  *lsdopxticknames[1] = REPLICATE(' ',60)
  FOR i=0,3 DO BEGIN
    *lsxticknames[i] = ''
    *lsyticknames[i] = ''
  ENDFOR
  lsplotaxes = CRISPEX_PLOTAXES_UPDATE(hdr.ns, lsxticknames, lsyticknames, $
    lsxtitles, lsytitles, hdr.spxtitle, lsytitle,lsdopxtitles,lsdopxtitle, $
    hdr.ndiagnostics)
  
  reflsytitles = REPLICATE(reflsytitle,4)
  reflsxtitles = REPLICATE(hdr.refspxtitle,4)
  reflsxticknames = PTRARR(4, /ALLOCATE_HEAP)
  reflsyticknames = PTRARR(4, /ALLOCATE_HEAP)
  reflsdopxticknames = PTRARR(2, /ALLOCATE_HEAP)
  reflsdopxtitles = REPLICATE((['',lsdopxtitle])[hdr.v_dop_set[1]], 2)
  *reflsdopxticknames[0] = '' 
  *reflsdopxticknames[1] = REPLICATE(' ',60)
  FOR i=0,3 DO BEGIN
    *reflsxticknames[i] = ''
    *reflsyticknames[i] = ''
  ENDFOR
  reflsplotaxes = CRISPEX_PLOTAXES_UPDATE(hdr.refns, reflsxticknames, reflsyticknames, $
    reflsxtitles, reflsytitles, hdr.refspxtitle, reflsytitle, reflsdopxtitles, $
    lsdopxtitle, hdr.nrefdiagnostics)
  
  ; Get minimum and maximum Doppler verlocities, but check if restoring
  IF NOT KEYWORD_SET(restore_from_session) THEN BEGIN
    CRISPEX_IO_PARSE_VDOP, hdr.ndiagnostics, INDGEN(hdr.ndiagnostics), $
      hdr.v_dop, hdr.nlp, hdr.lps, hdr.diag_start, hdr.diag_width, heightset,$
      result, SINGLEWAV_WINDOWS=singlewav_windows
    hdr = CREATE_STRUCT(hdr, 'v_dop_low_min', result.v_dop_low_min, $
      'v_dop_low_max', result.v_dop_low_max, $
      'v_dop_upp_min', result.v_dop_upp_min, $
      'v_dop_upp_max', result.v_dop_upp_max, 'v_dop_incr', result.v_dop_incr)
  ENDIF 
  hdr.lp_restr_slid_low_sens = ((hdr.nlp GT 1) AND $
    (hdr.v_dop_low_min[0] NE hdr.v_dop_low_max[0])) 
  hdr.lp_restr_slid_upp_sens = ((hdr.nlp GT 1) AND $
    (hdr.v_dop_upp_min[0] NE hdr.v_dop_upp_max[0]))

  IF NOT KEYWORD_SET(restore_from_session) THEN BEGIN
    CRISPEX_IO_PARSE_VDOP, hdr.nrefdiagnostics, INDGEN(hdr.nrefdiagnostics), $
      hdr.v_dop_ref, hdr.refnlp, hdr.reflps, hdr.refdiag_start, $
      hdr.refdiag_width, refheightset, result, $
      SINGLEWAV_WINDOWS=refsinglewav_windows
    hdr = CREATE_STRUCT(hdr, 'v_dop_ref_low_min', result.v_dop_low_min, $
      'v_dop_ref_low_max', result.v_dop_low_max, $
      'v_dop_ref_upp_min', result.v_dop_upp_min, $
      'v_dop_ref_upp_max', result.v_dop_upp_max, $
      'v_dop_ref_incr', result.v_dop_incr)
  ENDIF 

	IF (TOTAL(verbosity[0:1]) GE 1) THEN CRISPEX_UPDATE_STARTUP_SETUP_FEEDBACK, $
                                        '(initial spectral parameters)', /OPT, $
                                        /OVER, /DONE
	feedback_text = [feedback_text[0:N_ELEMENTS(feedback_text)-2],'> Initial spectral parameters... done!']
	IF startupwin THEN CRISPEX_UPDATE_STARTUP_FEEDBACK, startup_im, xout, yout, feedback_text

;------------------------- WINDOW SIZES (CHANGE ONLY
;------------------------- NUMERICAL VALUES!)
	IF (TOTAL(verbosity[0:1]) GE 1) THEN CRISPEX_UPDATE_STARTUP_SETUP_FEEDBACK, $
                                        '(window sizes)', /OPT, /OVER
	feedback_text = [feedback_text,'> Window sizes... ']
	IF startupwin THEN $
    CRISPEX_UPDATE_STARTUP_FEEDBACK, startup_im, xout, yout, feedback_text
	
	xdelta		    = 20					; Extra xoffset for positioning of windows
	ydelta		    = 40					; Extra yoffset for positioning of windows
  minsize       = 200.
  ; Factors of x/y_scr_size to use for automatic screen sizing
  xsize_factor  = 0.7         ; Of remainder of window area, not of total
  ysize_factor  = 0.8
  lspx_factor   = 0.2         ; For lswin, spwin, phiswin, etc.
  
 
  ; Determine image and pixel aspect ratio
  ratio      = FLOAT(ABS(hdr.nx)) / FLOAT(ABS(hdr.ny))                  
  pixelratio = FLOAT(ABS(hdr.dx)) / FLOAT(ABS(hdr.dy))                  

  ; Determine default window sizes (i.e., regardless of monitor size)
  imwinx_default = hdr.nx
  imwiny_default = hdr.ny

  ; Handle pixel aspect ratio for default sizes
  IF (pixelratio GT 1) THEN imwinx_default *= pixelratio ELSE $
    IF (pixelratio LT 1) THEN imwiny_default /= pixelratio
  
  ; Check for extreme aspect ratio and small dimensions
  extreme_aspect = (((ratio GT 5.) AND (imwiny_default LT minsize)) OR $
                    ((ratio LT 0.2) AND (imwinx_default LT minsize))) 
  
  ; Get main screen sizes
  x_scr_size = screensizes[2,monitor_order[0]]
  x_scr_size -= 400     ; Subtract the part taken up by the GUI controls, approx
	y_scr_size = screensizes[3,monitor_order[0]]

  IF (N_ELEMENTS(WINDOW_LARGE) EQ 1) THEN hdr.window_large = window_large
  IF (hdr.window_large LE 1) THEN BEGIN
    ; Check whether window would in principle fit (only if xsize > nx+space for
    ; spectral windows AND ysize > ny), but override by WINDOW_LARGE if set:
  	IF ((x_scr_size GT (imwinx_default+2*xdelta+lspx_factor*x_scr_size)) AND $
        (y_scr_size GT imwiny_default)) THEN BEGIN		
      ; If xsize is small, then still go to old settings procedures
  		IF ((imwinx_default LT xsize_factor * x_scr_size) AND $
          (imwiny_default LT (xsize_factor * x_scr_size / ratio)) AND $
          (extreme_aspect OR (hdr.window_large EQ 1))) THEN BEGIN				
        ; Set maximum x- and y-extent of image window
        IF (extreme_aspect AND (hdr.nx EQ 1)) THEN $
          imwinx = 25*hdr.nx $
        ELSE $
  			  imwinx 	= xsize_factor * x_scr_size											
  			imwiny 	= imwinx / ratio
        ; Failsafe to avoid a window larger than the screensize
  		  IF (imwiny GT y_scr_size) THEN BEGIN										
  			  imwiny = ysize_factor * y_scr_size											
          IF (extreme_aspect AND (hdr.nx EQ 1)) THEN $
            imwinx = 25*hdr.nx $
          ELSE $
  			    imwinx = imwiny * ratio
  		  ENDIF
  			IF (verbosity[1] EQ 1) THEN $
          msg = 'User screen resolution allows 1:1 image window sizing, '+$
            'but dimensions are small. '
      ; Else fit the window with actual data dimensions
  		ENDIF ELSE BEGIN
        ; Use actual nx/ny as imwinx/imwiny
  			imwinx	= hdr.nx                  
        IF (extreme_aspect AND (hdr.nx EQ 1)) THEN imwinx *= 25
  			imwiny	= hdr.ny                 
  			IF (verbosity[1] EQ 1) THEN $
          msg = 'User screen resolution allows 1:1 image window sizing. '
  		ENDELSE
    ; Else use the old procedures to determine imwinx and imwiny
  	ENDIF ELSE BEGIN													
      ; Set maximum x- and y-extent of image window
  		imwinx 	= xsize_factor * x_scr_size
  		imwiny 	= imwinx / ratio	 
      ; Failsafe to avoid a window larger than the screensize
  		IF (imwiny GT y_scr_size) THEN BEGIN										
  			imwiny = ysize_factor * y_scr_size
        IF (extreme_aspect AND (hdr.nx EQ 1)) THEN $
          imwinx = 25*hdr.nx $
        ELSE $
  			  imwinx = imwiny * ratio
  		ENDIF
  		IF (verbosity[1] EQ 1) THEN $
        msg = 'User screen resolution does not allow for 1:1 image window sizing. '
  	ENDELSE
  ENDIF ELSE BEGIN
    ; Else set imwiny to WINDOW_LARGE value and scale imwinx accordingly, but
    ; with a failsafe for "ridiculously" small values (arbitrarily set at a
    ; fifth of the default ysize)
    IF (hdr.window_large GE 0.2*imwiny_default) THEN BEGIN
      imwiny = hdr.window_large < y_scr_size
      imwinx = imwiny * ratio
  		IF (verbosity[1] EQ 1) THEN $
        msg = 'Window sizing adjusted according to WINDOW_LARGE setting. '
    ENDIF ELSE BEGIN
      imwinx = imwinx_default
      imwiny = imwiny_default
  		IF (verbosity[1] EQ 1) THEN $
        msg = 'Window sizing not adjusted due to overly small WINDOW_LARGE setting. '
    ENDELSE
  ENDELSE

  ; Initial color bar settings and fix window sizes for color bar positioning
  ctbar_init = ((extreme_aspect AND (imwinx LT imwiny)) OR (imwinx LT 0.5*imwiny)) 
  IF ctbar_init THEN BEGIN
    ctbar_width = 75
    ; Failsafe against overflow window in x-direction
    IF (imwinx + ctbar_width GT xsize_factor * x_scr_size) THEN BEGIN
      imwinx -= ctbar_width
      imwiny = imwinx / ratio
    ENDIF
    ctbar_height = imwiny
  ENDIF ELSE BEGIN
    ctbar_height = 50
    ; Failsafe against overflow window in y-direction
    IF (imwiny + ctbar_height GT ysize_factor * y_scr_size) THEN BEGIN
      imwiny -= ctbar_height
      imwinx = imwiny * ratio
    ENDIF
    ctbar_width = imwinx
  ENDELSE
  ; Fix window sizes for pixelratio
  IF (pixelratio GT 1) THEN $
    imwinx *= pixelratio $
  ELSE IF (pixelratio LT 1) THEN $
    imwiny /= pixelratio

  IF (verbosity[1] EQ 1) THEN $
    CRISPEX_UPDATE_STARTUP_SETUP_FEEDBACK, msg+'Main image window set to '+$
      STRTRIM(imwinx,2)+'x'+STRTRIM(imwiny,2)+'.', /NEWLINE, /NO_ROUTINE
                                
  ; Set zoomfactors
  zoomfactors = [1.,2.,3.,4.,6.,8.]
  factorswitch = [1B,BYTARR(N_ELEMENTS(zoomfactors)-1)]
  ; Default zooming is "to fit"; account for pixelratio
  zoomfactor = imwinx / pixelratio / FLOAT(hdr.nx)

  ; If reference cube supplied, determine sizes
  IF hdr.showref THEN BEGIN
    ; Determine image and pixel aspect ratio
    refratio      = FLOAT(ABS(hdr.refnx)) / FLOAT(ABS(hdr.refny))
    refpixelratio = FLOAT(ABS(hdr.refdx)) / FLOAT(ABS(hdr.refdy))
    IF hdr.main2ref_no_map THEN BEGIN
      refwinx = imwinx
      refwiny = imwiny
    ENDIF ELSE BEGIN
      refwinx_default = hdr.refnx
      refwiny_default = hdr.refny
      ; Handle pixel aspect ratio
      IF (refpixelratio GT 1) THEN refwinx_default *= refpixelratio ELSE $
        IF (refpixelratio LT 1) THEN refwiny_default /= refpixelratio
      ; Size refwiny according to the y-pixelsize
      refwiny = refwiny_default*hdr.refdy / FLOAT(imwiny_default*hdr.dy) * imwiny
      ; If refwiny becomes too big (i.e., because FOV is bigger than y-extent of
      ; main data) OR if refwiny and imwiny should be the same because of
      ; respective ny*dy, but aren't, then resize to the final main y-window
      IF ((refwiny GT y_scr_size) OR $
        ((hdr.ny*hdr.dy EQ hdr.refny*hdr.refdy) AND (refwiny NE imwiny))) THEN $
          refwiny = imwiny
      refwinx = refwinx_default/FLOAT(refwiny_default)*refwiny
    ENDELSE
    result = CRISPEX_GET_IMREF_BLINK_BOUNDS(hdr.pix_main2ref, hdr.pix_ref2main, $
      0, (hdr.nx-1), 0, (hdr.ny-1), 0, (hdr.refnx-1), 0, (hdr.refny-1))
    x_main = result.x_main
    y_main = result.y_main
    x_ref = result.x_ref
    y_ref = result.y_ref
    imrefwinx = imwinx * result.nx_sel / FLOAT(hdr.nx)
    imrefwiny = imwiny * result.ny_sel / FLOAT(hdr.ny)
    IF (verbosity[1] EQ 1) THEN $
      CRISPEX_UPDATE_STARTUP_SETUP_FEEDBACK, msg+'Reference image window set to '+$
        STRTRIM(refwinx,2)+'x'+STRTRIM(refwiny,2)+'.', /NEWLINE, /NO_ROUTINE
  ENDIF ELSE BEGIN
    refpixelratio = 0
    refwinx = 0
    refwiny = 0
    imrefwinx = 0
    imrefwiny = 0
    x_main = 0
    y_main = 0
    x_ref = 0
    y_ref = 0
  ENDELSE

  ; If SJI cube supplied, determine sizes
  showsji = BYTARR(hdr.nsjifiles_max)
  whereshowsji = PTR_NEW(0)
  sjiratio = FLTARR(hdr.nsjifiles_max)
  sjipixelratio = FLTARR(hdr.nsjifiles_max)
  sjiwinx_default = LONARR(hdr.nsjifiles_max)
  sjiwiny_default = LONARR(hdr.nsjifiles_max)
  sjiwinx = FLTARR(hdr.nsjifiles_max)
  sjiwiny = FLTARR(hdr.nsjifiles_max)
  IF hdr.sjifile THEN BEGIN
    FOR idx_sji=0,hdr.nsjifiles-1 DO BEGIN
      showsji[idx_sji] = hdr.sjifile
      ; Determine image and pixel aspect ratio
      sjiratio[idx_sji] = $
        FLOAT(ABS(hdr.sjinx[idx_sji])) / FLOAT(ABS(hdr.sjiny[idx_sji]))
      sjipixelratio[idx_sji] = $
        FLOAT(ABS(hdr.sjidx[idx_sji])) / FLOAT(ABS(hdr.sjidy[idx_sji]))
      sjiwinx_default[idx_sji] = hdr.sjinx[idx_sji]
      sjiwiny_default[idx_sji] = hdr.sjiny[idx_sji]
      ; Handle pixel aspect ratio
      IF (sjipixelratio[idx_sji] GT 1) THEN $
        sjiwinx_default[idx_sji] *= sjipixelratio[idx_sji] $
      ELSE IF (sjipixelratio[idx_sji] LT 1) THEN $
        sjiwiny_default[idx_sji] /= sjipixelratio[idx_sji]
      ; Size sjiwiny according to the y-pixelsize
      sjiwiny[idx_sji] = sjiwiny_default[idx_sji]*hdr.sjidy[idx_sji] / FLOAT(imwiny*hdr.dy) * imwiny
      ; If sjiwiny becomes too big (i.e., because FOV is bigger than y-extent of
      ; main data) OR if sjiwiny and imwiny should be the same because of
      ; respective ny*dy, but aren't, then resize to the final main y-window
      IF ((sjiwiny[idx_sji] GT y_scr_size) OR $
          ((hdr.ny*hdr.dy EQ hdr.sjiny[idx_sji]*hdr.sjidy[idx_sji]) AND $
          (sjiwiny[idx_sji] NE imwiny))) THEN $
          sjiwiny[idx_sji] = imwiny
      sjiwinx[idx_sji] = $
        sjiwinx_default[idx_sji]/FLOAT(sjiwiny_default[idx_sji])*sjiwiny[idx_sji]
    ENDFOR
    whereshowsji = PTR_NEW(INDGEN(hdr.nsjifiles))
  ENDIF 

  ; Set default tickmark length (fraction of window size)
  ticklen 	= 0.01

  ; ==================== Main detailed spectrum window ====================
  ; Set detailed spectrum window parameters
  ; Set maximum x-extent of loc spec win
	lswinx 		= lspx_factor * x_scr_size											
	lsmargin 	= 0.15  ;0.12
	lswall 		= 0.03
	lswintitle	= ['Detailed spectrum','Height profile']
	xsize 		= 1.*lswinx
  plotpos = CRISPEX_GET_PLOTPOS(hdr.ns, lswinx, lsmargin, lswall, $
              V_DOP_SET=(hdr.v_dop_set[0] EQ 1))
  lsx0 = plotpos.x0         & lsx1 = plotpos.x1
  lsy0 = plotpos.y0         & lsy1 = plotpos.y1
  lsx0_all = plotpos.x0_all & lsx1_all = plotpos.x1_all
  lsy0_all = plotpos.y0_all & lsy1_all = plotpos.y1_all
  lswidth = plotpos.width
  lsheight = plotpos.height
  lswiny = plotpos.winy
  ; Determine default margin, wall and tickmark length 
	lsxmargin_init	= lsmargin * lswinx
	lsxwall_init	= lswall * lswinx
	lsxticklen 	= ticklen / lsheight
	lsyticklen 	= ticklen / lswidth

  ; ==================== Reference detailed spectrum window ====================
  ; Set reference spectrum window parameters
	reflswintitle	= ['Reference detailed spectrum','Reference height profile']
	reflswinx	= lswinx
  plotpos = CRISPEX_GET_PLOTPOS(hdr.refns, lswinx, lsmargin, lswall, $
              V_DOP_SET=(hdr.v_dop_set[1] EQ 1))
  reflsx0 = plotpos.x0          & reflsx1 = plotpos.x1
  reflsy0 = plotpos.y0          & reflsy1 = plotpos.y1
  reflsx0_all = plotpos.x0_all  & reflsx1_all = plotpos.x1_all
  reflsy0_all = plotpos.y0_all  & reflsy1_all = plotpos.y1_all
  reflswidth = plotpos.width
  reflsheight = plotpos.height
  reflswiny = plotpos.winy
  ; Determine default margin, wall and tickmark length 
	reflsxmargin_init= lsmargin * reflswinx
	reflsxwall_init	= lswall * reflswinx
	reflsxticklen 	= ticklen / reflsheight
	reflsyticklen 	= ticklen / reflswidth

  ; ==================== Lightcurve window ====================
  ; Set lightcurve window parameters
	intwidth 	= (xsize/lswinx - (lsmargin + lswall))
	intheight 	= intwidth * 2D / (1 + SQRT(5))
	intwinx		= lswinx
	intwiny 	= (lsmargin + intheight + lswall) * intwinx
  ; Determine plot positions
	intx0 		= lsmargin 
	intx1 		= intx0 + intwidth 
	inty0 		= lsmargin * intwinx/intwiny
	inty1	 	= inty0 + intheight * intwinx/intwiny
  ; Determine default margin, wall and tickmark length 
	intxmargin_init	= lsmargin * intwinx
	intxwall_init	= lswall * intwinx
	intxticklen 	= ticklen / intheight
	intyticklen 	= ticklen / intwidth

  ; ==================== Spectrum-time and Phi-slit window ====================
	spwintitle	= ['Spectral T-slice','Height T-slice']
  phiswintitle	= ['Spectral Phi-slice','Height Phi-slice']
  ; Window sizes	
  spwinx		= lspx_factor * x_scr_size											; Set maximum x-extent of spectral win
  spwiny    = (imwiny - lswiny) > (y_scr_size/2.)
	phiswinx	= spwinx
  phiswiny  = spwiny
  ; Determine default margin adn wall 
	spxmargin_init	= lsmargin * lswinx * 1.3
	spxwall_init	= lswall * lswinx
	spmargin 	= spxmargin_init/spwinx
	spwall 		= spxwall_init/spwinx
  ; Plot sizes
	spwidth 	= (1. - (spmargin + spwall))
	IF ((hdr.v_dop_set[0] EQ 1) OR (hdr.ns GT 1)) THEN BEGIN
		spheight = (1. - (spmargin * 2.) * spwinx/spwiny)
		phisheight = (1. - (spmargin * 2.) * phiswinx/phiswiny)
	ENDIF ELSE BEGIN
		spheight = (1. - (spmargin + spwall) * spwinx/spwiny)
		phisheight = (1. - (spmargin + spwall) * phiswinx/phiswiny)
	ENDELSE
  ; Determine plot positions
	spx0 		= spmargin 
	spx1 		= spx0 + spwidth 
	spy0 		= spmargin * spwinx/spwiny
	spy1 		= spy0 + spheight; * spwinx/spwiny
	xplspw		= spx1 - spx0												; x-extent of the plot
	yplspw		= spy1 - spy0												; y-extent of the plot
  ; Determine default tickmark length 
	spxticklen 	= -1. * ticklen / spheight
	spyticklen 	= -1. * ticklen / spwidth
  ; Determine rebinning factors for display of slice
	IF ((hdr.spfile EQ 1) OR (hdr.single_cube[0] GE 1)) THEN $
    ntreb = yplspw * spwiny $
  ELSE $
    ntreb = 0						; actual nt rebinning factor
	nlpreb		= xplspw * spwinx							 				; actual nlp rebinning factor
	
  ; Determine plot positions: Phi-slit
	phisx0 		= spmargin * phiswinx/phiswinx 
	phisx1 		= phisx0 + spwidth * phiswinx/phiswinx
	phisy0 		= spmargin * phiswinx/phiswiny
	phisy1 		= phisy0 + phisheight; * spwinx/spwiny
	phisxplspw	= phisx1 - phisx0												; x-extent of the plot
	phisyplspw	= phisy1 - phisy0												; y-extent of the plot
  ; Determine default tickmark length 
	phisxticklen 	= -1. * ticklen / phisheight
	phisyticklen 	= -1. * ticklen / spwidth
  ; Determine rebinning factors for display of slice
	nphireb		= phisyplspw * phiswiny

  ; ==================== Reference spectrum-time window ====================
	refspwiny	= spwiny 
	refspwintitle	= ['Reference spectral T-slice','Reference height T-slice']
  ; Determine plot width and height
	IF ((hdr.v_dop_set[1] EQ 1) OR (hdr.refns GT 1)) THEN $
    refspheight = (1. - (spmargin * 2.) * spwinx/spwiny) $
  ELSE $
    refspheight = (1. - (spmargin + spwall) * spwinx/spwiny)
  ; Determine plot positions
	refspy0 	= spmargin * spwinx/refspwiny
	refspy1 	= refspy0 + refspheight; * spwinx/refspwiny
	refyplspw	= refspy1 - refspy0												; y-extent of the plot
  ; Determine rebinning factors for display of slice
	refntreb	= refyplspw * refspwiny
	
  ; ==================== Space-time diagram window ====================
	loopheight	= (1. - (spmargin + spwall) * spwinx/spwiny)
	loopy1		= spy0 + loopheight
	loopyplspw	= loopy1 - spy0
	loopntreb	= loopyplspw * spwiny

	IF (TOTAL(verbosity[0:1]) GE 1) THEN CRISPEX_UPDATE_STARTUP_SETUP_FEEDBACK, $
                                        '(window sizes)', /OPT, /OVER, /DONE, $
                                        REPEAT_STAGE=verbosity[1]
	feedback_text = [feedback_text[0:N_ELEMENTS(feedback_text)-2],'> Window sizes... done!']
	IF startupwin THEN CRISPEX_UPDATE_STARTUP_FEEDBACK, startup_im, xout, yout, feedback_text

;------------------------- INITIAL SPATIAL PARAMETERS
	IF (TOTAL(verbosity[0:1]) GE 1) THEN CRISPEX_UPDATE_STARTUP_SETUP_FEEDBACK, $
                                        '(initial spatial parameters)', /OPT, /OVER
	feedback_text = [feedback_text,'> Initial spatial parameters... ']
	IF startupwin THEN CRISPEX_UPDATE_STARTUP_FEEDBACK, startup_im, xout, yout, feedback_text
	x_first		= 0L													; Set number of first x-coordinate
	x_last		= hdr.nx-1L													; Set number of last x-coordinate
	y_first		= 0L												; Set number of first y-coordinate
	y_last		= hdr.ny-1L													; Set number of last y-coordinate
  ; Get default start coordinates
	x_start		= FLOAT(FLOOR(hdr.nx/2))												
	y_start		= FLOAT(FLOOR(hdr.ny/2))
	sx_start	= x_start * imwinx / FLOAT(hdr.nx)										
	sy_start	= y_start * imwiny / FLOAT(hdr.ny)

  ; Determine starting positions for reference image
  xyref_out_of_range = 0
  IF hdr.showref THEN BEGIN
    xref_first = 0L
    yref_first = 0L
    xref_last = hdr.refnx-1L
    yref_last = hdr.refny-1L
    IF hdr.main2ref_no_map THEN BEGIN
      xref_start = x_start
      yref_start = y_start
      sxref_start = sx_start
      syref_start = sy_start
    ENDIF ELSE BEGIN
      ; Get starting points directly from conversion maps
      xref_start = hdr.pix_main2ref[0,x_start,y_start];$
      yref_start = hdr.pix_main2ref[1,x_start,y_start];$
      xyref_out_of_range = ((xref_start LT 0) OR (yref_start LT 0) OR $
                            (xref_start GE hdr.refnx) OR $
                            (yref_start GE hdr.refny))
      ; If conversion of x/y_start to x/yref_start pushes the latter out of
      ; range adjust x/y(ref)_start to middle of overlapping area
      IF xyref_out_of_range THEN BEGIN
        ; x/y boundaries of reference in main coordinate system
        x_ref_on_main = [hdr.pix_ref2main[0,0,0],hdr.pix_ref2main[0,hdr.refnx-1,0]]
        y_ref_on_main = [hdr.pix_ref2main[1,0,0],hdr.pix_ref2main[1,0,hdr.refny-1]]
        ; Determine boundaries in main
        x_bound = [(x_ref_on_main[0] > 0), $
                   (x_ref_on_main[1] < (hdr.nx-1))]
        y_bound = [(y_ref_on_main[0] > 0), $
                   (y_ref_on_main[1] < (hdr.ny-1))]
        ; Set new x/y_start and convert to reference coordinate system
        x_start = FLOAT(FLOOR((x_bound[1]-x_bound[0]+1)/2.)+x_bound[0])
        y_start = FLOAT(FLOOR((y_bound[1]-y_bound[0]+1)/2.)+y_bound[0])
        xref_start = hdr.pix_main2ref[0,x_start,y_start]
        yref_start = hdr.pix_main2ref[1,x_start,y_start]
        xyref_out_of_range = 0
      ENDIF
      sxref_start = xref_start * refwinx / hdr.refnx
      syref_start = yref_start * refwiny / hdr.refny
    ENDELSE
  ENDIF ELSE BEGIN
    xref_first = 0L
    xref_last = 1L
    yref_first = 0L
    yref_last = 1L
    xref_start = 0L
    yref_start = 0L
    sxref_start = 0.
    syref_start = 0.
  ENDELSE

  ; Determine starting positions for slit-jaw image
  xsji_start = FLTARR(hdr.nsjifiles_max)
  ysji_start = FLTARR(hdr.nsjifiles_max)
  xysji_out_of_range = BYTARR(hdr.nsjifiles_max)
  sxsji_start = FLTARR(hdr.nsjifiles_max)
  sysji_start = FLTARR(hdr.nsjifiles_max)
  IF hdr.sjifile THEN BEGIN
    FOR idx=0,hdr.nsjifiles-1 DO BEGIN
      ; Get starting points directly from conversion maps
      xsji_start[idx] = (*hdr.pix_main2sji[idx])[0,x_start,y_start];$
      ysji_start[idx] = (*hdr.pix_main2sji[idx])[1,x_start,y_start];$
      xysji_out_of_range[idx] = ( (xsji_start[idx] LT 0) OR (ysji_start[idx] LT 0) OR $
                                  (xsji_start[idx] GE hdr.sjinx[idx]) OR $
                                  (ysji_start[idx] GE hdr.sjiny[idx]))
      sxsji_start[idx] = xsji_start[idx] * sjiwinx[idx] / hdr.sjinx[idx]
      sysji_start[idx] = ysji_start[idx] * sjiwiny[idx] / hdr.sjiny[idx]
    ENDFOR
  ENDIF 

	IF (TOTAL(verbosity[0:1]) GE 1) THEN CRISPEX_UPDATE_STARTUP_SETUP_FEEDBACK, $
                                        '(initial spatial parameters)', /OPT, /OVER, /DONE
	feedback_text = [feedback_text[0:N_ELEMENTS(feedback_text)-2],'> Initial spatial parameters... done!']
	IF startupwin THEN CRISPEX_UPDATE_STARTUP_FEEDBACK, startup_im, xout, yout, feedback_text

;------------------------- SCALING PARAMETERS
	IF (TOTAL(verbosity[0:1]) GE 1) THEN CRISPEX_UPDATE_STARTUP_SETUP_FEEDBACK, $
                                        '(initial scaling parameters)', /OPT, /OVER
	feedback_text = [feedback_text,'> Initial scaling parameters... ']
	IF startupwin THEN CRISPEX_UPDATE_STARTUP_FEEDBACK, startup_im, xout, yout, feedback_text
  IF (restore_from_session EQ 0) THEN BEGIN
	  imagescale = PTR_NEW(INTARR(3+hdr.nsjifiles_max))			; Image scaling based on first image

    CRISPEX_IO_PARSE_SCALING_INIT, hdr, histo_opt_val, mainresult, $
      SCALE_STOKES=scale_stokes, SHOWLS=showls
	  ls_low_y = PTR_NEW(mainresult.ls_low_y,/NO_COPY)
	  ls_upp_y = PTR_NEW(mainresult.ls_upp_y,/NO_COPY)
	  ls_yrange = PTR_NEW(mainresult.ls_yrange,/NO_COPY)
	  int_low_y = PTR_NEW(mainresult.int_low_y,/NO_COPY)
	  int_upp_y = PTR_NEW(mainresult.int_upp_y,/NO_COPY)

    IF hdr.showref THEN BEGIN
      CRISPEX_IO_PARSE_SCALING_INIT, hdr, histo_opt_val, result, /REFERENCE, $
        SCALE_STOKES=scale_stokes, SHOWLS=showrefls
      ls_low_y_ref = PTR_NEW(result.ls_low_y, /NO_COPY)
      ls_upp_y_ref = PTR_NEW(result.ls_upp_y, /NO_COPY)
      ls_yrange_ref = PTR_NEW(result.ls_yrange, /NO_COPY)
      ref_mult_val = result.mult_val
      refmin = result.immin
      refmax = result.immax
    ENDIF ELSE BEGIN
      ls_low_y_ref = PTR_NEW(0.)
      ls_upp_y_ref = PTR_NEW(0.)
      ls_yrange_ref = PTR_NEW(0.)
      ref_mult_val = 0.
      refmin = 0.
      refmax = 0.
    ENDELSE

    sjimin = FLTARR(hdr.nsjifiles_max)
    sjimax = FLTARR(hdr.nsjifiles_max)
    tsel_scaling_sji = LONARR(hdr.nsjifiles_max)
    IF hdr.sjifile THEN BEGIN
      FOR idx=0,hdr.nsjifiles-1 DO BEGIN
        finite_count = 0
        WHILE (finite_count EQ 0) DO BEGIN
          ; Failsafe against empty/NaN-only first image(s)
          sjidata_tmp = (*hdr.sjidata[idx])[tsel_scaling_sji[idx]]
          ; If SJI data is scaled integer, descale and convert to float
          IF hdr.sjiscaled[idx] THEN $
            sjidata_tmp = CRISPEX_SCALING_DESCALE(sjidata_tmp, $
              hdr.sjibscale[idx], hdr.sjibzero[idx])
          wherefinite = WHERE(FINITE(sjidata_tmp) EQ 1, finite_count)
          IF (finite_count EQ 0) THEN BEGIN
            tsel_scaling_sji[idx] += 1
            ; Failsafe against overshooting time domain
            tsel_scaling_sji[idx] = tsel_scaling_sji[idx] < (hdr.sjint - 1)
          ENDIF
        ENDWHILE
        sjimin[idx] = MIN(sjidata_tmp, MAX=sjimax_val, /NAN)
        sjimax[idx] = sjimax_val
      ENDFOR
    ENDIF 
    hdr = CREATE_STRUCT(hdr, 'imagescale', imagescale, $
      'ls_low_y_init', (*ls_low_y[0])[0], 'ls_upp_y_init', (*ls_upp_y[0])[0], $
      'ls_low_y', ls_low_y, 'ls_upp_y', ls_upp_y, 'ls_yrange', ls_yrange, $
      'int_low_y', int_low_y, 'int_upp_y', int_upp_y, $
      'main_mult_val', mainresult.mult_val, 'immin', mainresult.immin, $
      'immax', mainresult.immax, $
      'dopplermin', mainresult.dopplermin, 'dopplermax', mainresult.dopplermax, $
      'ls_low_y_ref', ls_low_y_ref, 'ls_upp_y_ref', ls_upp_y_ref, $
      'ls_yrange_ref', ls_yrange_ref, 'ref_mult_val', ref_mult_val, $
      'refmin', refmin, 'refmax', refmax, 'sjimin', sjimin, 'sjimax', sjimax, $
      'tsel_scaling_sji', tsel_scaling_sji)
  ENDIF
  ; Load default color tables
  LOADCT, GET_NAMES=ct_idl_names, /SILENT
  ct_names = ct_idl_names
  ; Get IRIS color tables (assumption on location within SSWIDL, check for
  ; existence)
  iris_lct = FILE_SEARCH('$SSW/iris/idl/lmsal/calibration/iris_lct.pro', $
    /EXPAND_ENVIRONMENT, COUNT=iris_lct_count)
  iris_lct_exist = (iris_lct_count EQ 1)
  IF iris_lct_exist THEN BEGIN
    ct_iris_names = ['SJI_5000W', 'SJI_2832', 'SJI_2796', 'SJI_1600W', $
      'SJI_1400', 'SJI_1330', 'FUV', 'NUV', 'SJI_NUV']
    ct_iris_names_cbox = REPLICATE('IRIS ',N_ELEMENTS(ct_iris_names))+$
      ct_iris_names
  ENDIF ELSE $
    ct_iris_names = ''
  ct_idl_names_cbox = REPLICATE('IDL ',N_ELEMENTS(ct_idl_names))+$
    STRTRIM(INDGEN(N_ELEMENTS(ct_idl_names)),2)+REPLICATE(': ',$
    N_ELEMENTS(ct_idl_names))+ct_idl_names
  ct_names_cbox = ct_idl_names_cbox
  IF (ct_iris_names[0] NE '') THEN BEGIN
    ct_names = [ct_names, ct_iris_names]
    ct_names_cbox = [ct_names_cbox, ct_iris_names_cbox] 
  ENDIF

  ; Get SDO/AIA and HMI color tables (assumption location within SSWIDL, but
  ; check for existence first
  aia_lct = FILE_SEARCH('$SSW/sdo/aia/idl/pubrel/aia_lct.pro', $
    /EXPAND_ENVIRONMENT, COUNT=aia_lct_count)
  aia_lct_exist = (aia_lct_count EQ 1)
  IF aia_lct_exist THEN BEGIN
    ct_sdo_names = ['1600','1700','4500','94','131','171','193','211','304','335',$
      'HMI continuum','HMI B_LOS']
    ct_sdo_names_cbox = $
      [REPLICATE('SDO/AIA ',N_ELEMENTS(ct_sdo_names)-2),REPLICATE('SDO/',2)]+$
      ct_sdo_names
  ENDIF ELSE $
    ct_sdo_names = ''
  IF (ct_sdo_names[0] NE '') THEN BEGIN
    ct_names = [ct_names, ct_sdo_names]
    ct_names_cbox = [ct_names_cbox, ct_sdo_names_cbox] 
  ENDIF
 
  ; Set color tables
  imct = INTARR(3+hdr.nsjifiles_max)
  LOADCT, 0, RGB_TABLE=rgb_table, /SILENT ; Load default B-W color table
  main_instr = ''
  IF (hdr.imcube_compatibility EQ 0) THEN $
    main_instr = (FITSHEAD2STRUCT(*hdr.hdrs_main[0])).instrume 
  ; Set default color tables
  rgb_ref = rgb_table
  rgb_dop = rgb_table
  rgb_main = rgb_table
  rgb_sji = PTRARR(hdr.nsjifiles_max,/ALLOCATE_HEAP)
  ; Adjust color tables if appropriate
  IF ((STRTRIM(main_instr,2) EQ 'IRIS') AND iris_lct_exist) THEN BEGIN
    rgb_main = CRISPEX_GET_RGB_TABLE(TABLE_NAME='FUV', /IRIS) 
    imct[0] = (WHERE(ct_names EQ 'FUV'))[0]
    imct[2] = (WHERE(ct_names EQ 'FUV'))[0]
  ENDIF
  IF hdr.showref THEN BEGIN
    ref_instr = ''
    IF (hdr.refimcube_compatibility EQ 0) THEN $
      ref_instr = (FITSHEAD2STRUCT(*hdr.hdrs_ref[0])).instrume
    IF ((STRTRIM(ref_instr,2) EQ 'IRIS') AND iris_lct_exist) THEN BEGIN
      rgb_ref = CRISPEX_GET_RGB_TABLE(TABLE_NAME='FUV', /IRIS) 
      imct[1] = (WHERE(ct_names EQ 'FUV'))[0]
    ENDIF
  ENDIF
  sji_labels = STRARR(3,hdr.nsjifiles_max)
  sji_labels[0,*] = REPLICATE('N/A', hdr.nsjifiles_max)
  IF hdr.sjifile THEN BEGIN
    FOR idx=0,hdr.nsjifiles-1 DO BEGIN
      *rgb_sji[idx] = rgb_table
      sji_labels[0,idx] = $
        STRTRIM((FITSHEAD2STRUCT(*(*hdr.hdrs_sji[idx])[0])).telescop,2)
      sji_channel = (FITSHEAD2STRUCT(*(*hdr.hdrs_sji[idx])[0])).tdesc1
      splitchannel = STRSPLIT(sji_channel,'_',/EXTRACT)
      IF (splitchannel[0] EQ 'SJI') THEN $
        ; If IRIS SJI then TDESC1 is of type SJI_1400
        sji_labels[1,idx] = STRTRIM(splitchannel[1],2) $
      ELSE $
        ; If SDO SJI then TDESC1 is of type 131_THIN
        sji_labels[1,idx] = STRTRIM(splitchannel[0],2) 
    ENDFOR
    ; Adust color tables if appropriate and possible
    IF (iris_lct_exist OR aia_lct_exist) THEN BEGIN
      FOR idx=0,hdr.nsjifiles-1 DO BEGIN
        ; Check whether loading IRIS or SDO data, otherwise load default color table
        is_iris_or_sdo = (TOTAL(sji_labels[0,idx] EQ ['IRIS','SDO']) EQ 1)
        IF is_iris_or_sdo THEN BEGIN
          sji_channel = sji_labels[1,idx]
          is_iris_sji = (sji_labels[0,idx] EQ 'IRIS') 
          IF is_iris_sji THEN sji_channel = 'SJI_'+sji_channel
          *rgb_sji[idx] = CRISPEX_GET_RGB_TABLE(TABLE_NAME=sji_channel, $
            IRIS=(is_iris_sji AND iris_lct_exist), $
            SDO=((is_iris_sji EQ 0) AND aia_lct_exist))
          imct[3+idx] = (WHERE(ct_names EQ sji_channel))[0]
        ENDIF 
      ENDFOR
    ENDIF 
    ; Failsafe against duplicate sji_labels
    sji_comb_labels = sji_labels[0,*]+sji_labels[1,*]
    uniq_labels = UNIQ(sji_comb_labels)
    FOR idx=0,N_ELEMENTS(uniq_labels)-1 DO BEGIN
      ; Exclude N/A labels
      IF (sji_comb_labels[uniq_labels[idx]] NE 'N/A') THEN BEGIN
        where_label = WHERE(sji_comb_labels EQ sji_comb_labels[uniq_labels[idx]], $
          count)
        IF (count GT 1) THEN BEGIN
          FOR cc=0,count-1 DO $
            sji_labels[2,where_label[cc]] = '('+STRTRIM(cc+1,2)+')'
        ENDIF
      ENDIF
    ENDFOR
  ENDIF

  IF (TOTAL(verbosity[0:1]) GE 1) THEN $
    CRISPEX_UPDATE_STARTUP_SETUP_FEEDBACK, '(initial scaling parameters)', $
      /OPT, /OVER, /DONE
	feedback_text = [feedback_text[0:N_ELEMENTS(feedback_text)-2],'> Initial scaling parameters... done!']
	IF startupwin THEN CRISPEX_UPDATE_STARTUP_FEEDBACK, startup_im, xout, yout, feedback_text

;------------------------- OTHER PARAMETERS
	IF (TOTAL(verbosity[0:1]) GE 1) THEN CRISPEX_UPDATE_STARTUP_SETUP_FEEDBACK, $
                                        '(other parameters)', /OPT, /OVER
	feedback_text = [feedback_text,'> Other parameters... ']
	IF startupwin THEN CRISPEX_UPDATE_STARTUP_FEEDBACK, startup_im, xout, yout, feedback_text
	IF KEYWORD_SET(EXTS) THEN exts_set = 1 ELSE exts_set = 0
	IF (hdr.single_cube[0] GE 1) THEN BEGIN
		IF (hdr.mainnt GT 1) THEN BEGIN
			exts_set = 1						; Automatically set EXTS when providing a (single lineposition) 3D cube
      CRISPEX_UPDATE_STARTUP_SETUP_FEEDBACK, 'The exact timeslice (EXTS) keyword has been '+$
        'automatically set to enable the drawing of loop paths and extraction of timeslices!', $
        /WARNING, /NO_ROUTINE, /NEWLINE
		ENDIF ELSE exts_set=0
	ENDIF
	refexts_set = (hdr.refspfile NE 1)
	lp_slid_sens = (hdr.nlp GE 2)
	lp_blink_vals_sens = (hdr.nlp GT 2)
	lp_last_slid = (hdr.nlp-1) > 1
	lp_last_blink = (hdr.nlp-1) > 2
	lp_last_vals = hdr.nlp-1

	scale_cubes_vals = [1.,1.]
	IF (N_ELEMENTS(SCALE_CUBES) EQ 1) THEN scale_cubes_vals[0] = scale_cubes ELSE $
    IF (N_ELEMENTS(SCALE_CUBES) EQ 2) THEN scale_cubes_vals = scale_cubes
	IF (TOTAL(verbosity[0:1]) GE 1) THEN CRISPEX_UPDATE_STARTUP_SETUP_FEEDBACK, $
                                        '(other parameters)', /OPT, /OVER, /DONE,$
                                        REPEAT_STAGE=verbosity[1]
	feedback_text = [feedback_text[0]+'done!',feedback_text[1:N_ELEMENTS(feedback_text)-2],$
    '> Other parameters... done!']
	IF startupwin THEN CRISPEX_UPDATE_STARTUP_FEEDBACK, startup_im, xout, yout, feedback_text
	WAIT,0.1

;========================= SETTING UP WIDGET
;------------------------- CREATE CURSOR IMAGES
cursim_default = UINTARR(16)
cursmk_default = UINTARR(16)
cursmk_locked = cursmk_default
cursmk_locked[6:8] = 7

cursim_hand = CREATE_CURSOR([$
  '      ##        ',$
  '   ####.###     ',$
  '   #.##.#.#     ',$
  '   #.##.#.####  ',$
  '   #. #.#.#.##  ',$
  ' ####.....#.##  ',$
  ' #..#.......#   ',$
  '  #.........#   ',$
  '  ##.......##   ',$
  '   #.......#    ',$
  '    #.....#     ',$
  '     #....#     ',$
  '     ######     ',$
  '                ',$
  '                ',$
  '                ' ], MASK=mask_hand)

cursim_grab = CREATE_CURSOR([$
  '                ',$
  '                ',$
  '                ',$
  '                ',$
  '    ### # #     ',$
  '   #.#.#.#.##   ',$
  '   ##......#.#  ',$
  '   #.........#  ',$
  '  ##.........#  ',$
  '  ##.......#    ',$
  '   ##.....##    ',$
  '    ##....#     ',$
  '     ######     ',$
  '                ',$
  '                ',$
  '                ' ], MASK=mask_grab)

;------------------------- INITIALISE CONTROL PANEL
	IF (TOTAL(verbosity[0:1]) GE 1) THEN CRISPEX_UPDATE_STARTUP_SETUP_FEEDBACK, $
                                        '(loading BMP buttons)', /WIDGET, /OVER
	feedback_text = ['Setting up widget... ','> Loading BMP buttons... ']
	IF startupwin THEN CRISPEX_UPDATE_STARTUP_FEEDBACK, startup_im, xout, yout, feedback_text
	bmpbut_fbwd_idle     = CRISPEX_READ_BMP_BUTTONS('fbwd_idle.bmp',$
                          dir_buttons, DEFAULT='<<')
	bmpbut_fbwd_pressed  = CRISPEX_READ_BMP_BUTTONS('fbwd_pressed.bmp',$
                          dir_buttons, DEFAULT='<<')
	bmpbut_bwd_idle      = CRISPEX_READ_BMP_BUTTONS('bwd_idle.bmp',dir_buttons,$
                          DEFAULT='<')
	bmpbut_bwd_pressed   = CRISPEX_READ_BMP_BUTTONS('bwd_pressed.bmp',$
                          dir_buttons, DEFAULT='<')
	bmpbut_pause_idle    = CRISPEX_READ_BMP_BUTTONS('pause_idle.bmp',$
                          dir_buttons, DEFAULT='||')
	bmpbut_pause_pressed = CRISPEX_READ_BMP_BUTTONS('pause_pressed.bmp',$
                          dir_buttons, DEFAULT='||')
	bmpbut_fwd_idle      = CRISPEX_READ_BMP_BUTTONS('fwd_idle.bmp',$
                          dir_buttons, DEFAULT='>')
	bmpbut_fwd_pressed   = CRISPEX_READ_BMP_BUTTONS('fwd_pressed.bmp',$
                          dir_buttons, DEFAULT='>')
	bmpbut_ffwd_idle     = CRISPEX_READ_BMP_BUTTONS('ffwd_idle.bmp',$
                          dir_buttons, DEFAULT='>>')
	bmpbut_ffwd_pressed  = CRISPEX_READ_BMP_BUTTONS('ffwd_pressed.bmp',$
                          dir_buttons, DEFAULT='>>')
	bmpbut_loop_idle     = CRISPEX_READ_BMP_BUTTONS('loop_idle.bmp',$
                          dir_buttons, DEFAULT='Loop')
	bmpbut_loop_pressed  = CRISPEX_READ_BMP_BUTTONS('loop_pressed.bmp',$
                          dir_buttons, DEFAULT='Loop')
	bmpbut_cycle_idle    = CRISPEX_READ_BMP_BUTTONS('cycle_idle.bmp',$
                          dir_buttons, DEFAULT='Cycle')
	bmpbut_cycle_pressed = CRISPEX_READ_BMP_BUTTONS('cycle_pressed.bmp',$
                          dir_buttons, DEFAULT='Cycle')
	bmpbut_blink_idle    = CRISPEX_READ_BMP_BUTTONS('blink_idle.bmp',$
                          dir_buttons, DEFAULT='Blink')
	bmpbut_blink_pressed = CRISPEX_READ_BMP_BUTTONS('blink_pressed.bmp',$
                          dir_buttons, DEFAULT='Blink')
  bmpbut_add_failed = ((SIZE(bmpbut_loop_idle,/TYPE) EQ 7) OR $
    (SIZE(bmpbut_cycle_idle,/TYPE) EQ 7) OR (SIZE(bmpbut_blink_idle,/TYPE) EQ 7))
  ; Cursor and zoom buttons
  bmpbut_cursor_unlock        = CRISPEX_READ_BMP_BUTTONS('cursor_unlock.bmp',$
                                  dir_buttons, DEFAULT='Unlock')
  bmpbut_cursor_lock          = CRISPEX_READ_BMP_BUTTONS('cursor_lock.bmp',$
                                  dir_buttons, DEFAULT='Lock')
  bmpbut_zoom_in_idle         = CRISPEX_READ_BMP_BUTTONS('zoom_in_idle.bmp', $
                                  dir_buttons, DEFAULT='+')
  bmpbut_zoom_out_idle        = CRISPEX_READ_BMP_BUTTONS('zoom_out_idle.bmp',$
                                  dir_buttons, DEFAULT='-')
  bmpbut_zoom_tofit_idle      = CRISPEX_READ_BMP_BUTTONS('zoom_tofit_idle.bmp',$
                                  dir_buttons, DEFAULT='[ ]')
  bmpbut_zoom_toscale_idle    = CRISPEX_READ_BMP_BUTTONS('zoom_toscale_idle.bmp',$ 
                                  dir_buttons, DEFAULT='1:1')
  bmpbut_zoom_goto_curs_idle  = CRISPEX_READ_BMP_BUTTONS('zoom_goto_cursor_idle.bmp',$
                                  dir_buttons, DEFAULT='>\<')
  bmpbut_zoom_pan_idle        = CRISPEX_READ_BMP_BUTTONS('zoom_pan_idle.bmp',$
                                  dir_buttons, DEFAULT='< >')
  bmpbut_zoom_select_idle     = CRISPEX_READ_BMP_BUTTONS('zoom_select_idle.bmp',$
                                  dir_buttons, DEFAULT='<--')
  bmpbut_zoom_in_pressed      = CRISPEX_READ_BMP_BUTTONS('zoom_in_pressed.bmp',$
                                  dir_buttons, DEFAULT='+')
  bmpbut_zoom_out_pressed     = CRISPEX_READ_BMP_BUTTONS('zoom_out_pressed.bmp',$
                                  dir_buttons, DEFAULT='-')
  bmpbut_zoom_tofit_pressed   = CRISPEX_READ_BMP_BUTTONS('zoom_tofit_pressed.bmp',$
                                  dir_buttons, DEFAULT='[ ]')
  bmpbut_zoom_toscale_pressed   = CRISPEX_READ_BMP_BUTTONS('zoom_toscale_pressed.bmp',$
                                    dir_buttons, DEFAULT='1:1')
  bmpbut_zoom_goto_curs_pressed = CRISPEX_READ_BMP_BUTTONS('zoom_goto_cursor_pressed.bmp',$
                                    dir_buttons, DEFAULT='>\<')
  bmpbut_zoom_pan_pressed       = CRISPEX_READ_BMP_BUTTONS('zoom_pan_pressed.bmp',$
                                    dir_buttons, DEFAULT='< >')
  bmpbut_zoom_select_pressed    = CRISPEX_READ_BMP_BUTTONS('zoom_select_pressed.bmp',$
                                    dir_buttons, DEFAULT='<--')
  IF bmpbut_add_failed THEN donetext = 'failed.' ELSE donetext = 'done!'
	IF (TOTAL(verbosity[0:1]) GE 1) THEN CRISPEX_UPDATE_STARTUP_SETUP_FEEDBACK, $
                                        '(loading BMP buttons)', /WIDGET, $
                                        /OVER, /DONE, FAIL=bmpbut_add_failed
	feedback_text = [feedback_text[0:N_ELEMENTS(feedback_text)-2],'> Loading BMP buttons... '+donetext]
	IF startupwin THEN CRISPEX_UPDATE_STARTUP_FEEDBACK, startup_im, xout, yout, feedback_text

;------------------------- INITIALISE CONTROL PANEL
	IF (TOTAL(verbosity[0:1]) GE 1) THEN CRISPEX_UPDATE_STARTUP_SETUP_FEEDBACK, $
                                        '(initialising control panel)', /WIDGET, /OVER
	feedback_text = [feedback_text,'> Initializing control panel... ']
	IF startupwin THEN CRISPEX_UPDATE_STARTUP_FEEDBACK, startup_im, xout, yout, feedback_text
	cpanel		    = WIDGET_BASE(TITLE = 'CRISPEX'+instance_label+': Control Panel', $
    TLB_FRAME_ATTR = 1, /ROW, /FRAME, KILL_NOTIFY = 'CRISPEX_CLOSE_CLEANUP', $
    APP_MBAR = menubar, TLB_SIZE_EVENTS = 1)
  control_panel       = WIDGET_BASE(cpanel, /COLUMN)

  ; CRISPEX
  crispex_menu        = WIDGET_BUTTON(menubar, VALUE='CRISPEX', /MENU, UVALUE='crispex')
	about			          = WIDGET_BUTTON(crispex_menu, VALUE='About CRISPEX', $
                          EVENT_PRO='CRISPEX_ABOUT_WINDOW')
	preferences		      = WIDGET_BUTTON(crispex_menu, VALUE='Preferences', /SEPARATOR, $
                          EVENT_PRO='CRISPEX_PREFERENCES_WINDOW', ACCELERATOR='Ctrl+P')
	exitmenu		        = WIDGET_BUTTON(crispex_menu, VALUE='Quit', /SEPARATOR, $
                          EVENT_PRO='CRISPEX_CLOSE', ACCELERATOR='Ctrl+Q')
  ; Submenus in menu bar
  ; File
	filemenu		        = WIDGET_BUTTON(menubar, VALUE='File', /MENU, UVALUE='file')
  openmenu            = WIDGET_BUTTON(filemenu, VALUE = 'Open', /MENU, $
                          /SENSITIVE)
  openrefim           = WIDGET_BUTTON(openmenu, VALUE='Reference image cube...', $
                          EVENT_PRO='CRISPEX_IO_OPEN_REFCUBE', $
                          /SENSITIVE)
  openrefimsp         = WIDGET_BUTTON(openmenu, VALUE='Reference image and spectral cube...', $
                          EVENT_PRO='CRISPEX_IO_OPEN_REFCUBE', $
                          /SENSITIVE)
  opensji             = WIDGET_BUTTON(openmenu, VALUE='Slit-jaw image cube...', $
                          EVENT_PRO='CRISPEX_IO_OPEN_SJICUBE', $
                          SENSITIVE=(hdr.imcube_compatibility EQ 0))
  header_sensitive = ((STRLEN((*hdr.hdrs_main[0])[0]) GT 0) OR $
                     (STRLEN((*hdr.hdrs_ref[0])[0]) GT 0))
  IF (hdr.nsjifiles GE 1) THEN $
    header_sensitive = (header_sensitive OR (STRLEN((*(*hdr.hdrs_sji[0])[0])[0]) GT 0))
  header_button       = WIDGET_BUTTON(filemenu, VALUE='Show file header(s)', $
                          EVENT_PRO='CRISPEX_DISPLAYS_HEADER', $
                          SENSITIVE=header_sensitive)
	restore_session		  = WIDGET_BUTTON(filemenu, VALUE='Load session...', $
                          EVENT_PRO='CRISPEX_SESSION_RESTORE')
	save_session		    = WIDGET_BUTTON(filemenu, VALUE='Save session...', $
                          EVENT_PRO='CRISPEX_SESSION_SAVE_WINDOW')
	save_as_menu		    = WIDGET_BUTTON(filemenu, VALUE='Save as', /SEPARATOR, /MENU)
	save_as_png_menu	  = WIDGET_BUTTON(save_as_menu, VALUE='PNG', /MENU)
	save_as_png_sns		  = WIDGET_BUTTON(save_as_png_menu, VALUE='Snapshot', $
                          EVENT_PRO='CRISPEX_SAVE_PNG_SNAPSHOT')
	save_as_png_all		  = WIDGET_BUTTON(save_as_png_menu, VALUE='All frames', $
                          EVENT_PRO='CRISPEX_SAVE_PNG_ALL_FRAMES', SENSITIVE=(hdr.mainnt GT 1))
	save_as_png_linescan= WIDGET_BUTTON(save_as_png_menu, VALUE='Line scan', $
                          EVENT_PRO='CRISPEX_SAVE_PNG_LINESCAN', SENSITIVE=(hdr.nlp GT 1))
	save_as_jpg_menu	  = WIDGET_BUTTON(save_as_menu, VALUE='JPEG', /MENU)
	save_as_jpg_sns 	  = WIDGET_BUTTON(save_as_jpg_menu, VALUE='Snapshot', $
                          EVENT_PRO='CRISPEX_SAVE_JPEG_SNAPSHOT')
	save_as_jpg_all		  = WIDGET_BUTTON(save_as_jpg_menu, VALUE='All frames', $
                          EVENT_PRO='CRISPEX_SAVE_JPEG_ALL_FRAMES', SENSITIVE=(hdr.mainnt GT 1))
	save_as_jpg_linescan= WIDGET_BUTTON(save_as_jpg_menu, VALUE='Linescan', $
                          EVENT_PRO='CRISPEX_SAVE_JPEG_LINESCAN', SENSITIVE=(hdr.nlp GT 1))
	save_as_mpeg		    = WIDGET_BUTTON(filemenu, VALUE='Save movie...', $
                          EVENT_PRO='CRISPEX_SAVE_MPEG', SENSITIVE=(hdr.mainnt GT 1))
  ; View
  viewmenu            = WIDGET_BUTTON(menubar, VALUE='View', /MENU)
	sh_zoom_in		      = WIDGET_BUTTON(viewmenu, VALUE='Zoom in', EVENT_PRO='CRISPEX_ZOOMFAC_INCR',$
                          ACCELERATOR='Ctrl+Shift+I')
	sh_zoom_out		      = WIDGET_BUTTON(viewmenu, VALUE='Zoom out', EVENT_PRO='CRISPEX_ZOOMFAC_DECR',$
                          ACCELERATOR='Ctrl+Shift+O')
  gather_seswins      = WIDGET_BUTTON(viewmenu, VALUE='Gather windows', $
                          /SEPARATOR, EVENT_PRO='CRISPEX_DISPLAYS_GATHER_ALL', $
                          ACCELERATOR='Ctrl+G')
	focus_session_windows= WIDGET_BUTTON(viewmenu, VALUE='Bring all to front', $
                          EVENT_PRO='CRISPEX_DISPLAYS_ALL_TO_FRONT', $
                          ACCELERATOR='Ctrl+F')
  ; Movie
  moviemenu           = WIDGET_BUTTON(menubar, VALUE='Movie', /MENU)
	sh_fbwd_button		  = WIDGET_BUTTON(moviemenu, VALUE='Step to previous frame', $
                          EVENT_PRO='CRISPEX_PB_FASTBACKWARD', ACCELERATOR='Shift+B')
	sh_backward_button	= WIDGET_BUTTON(moviemenu, VALUE='Play backwards', $
                          EVENT_PRO='CRISPEX_PB_BACKWARD', ACCELERATOR='Shift+Backspace')
	sh_pause_button		  = WIDGET_BUTTON(moviemenu, VALUE='Pause', $
                          EVENT_PRO='CRISPEX_PB_PAUSE', ACCELERATOR='Shift+Space')
	sh_forward_button	  = WIDGET_BUTTON(moviemenu, VALUE='Play forwards', $
                          EVENT_PRO='CRISPEX_PB_FORWARD', ACCELERATOR='Shift+Tab')
	sh_ffwd_button		  = WIDGET_BUTTON(moviemenu, VALUE='Step to next frame', $
                          EVENT_PRO='CRISPEX_PB_FASTFORWARD', ACCELERATOR='Shift+F')
	sh_lp_incr_button 	= WIDGET_BUTTON(moviemenu, VALUE='Main '+$
                          STRLOWCASE(sp_h[heightset])+' position +', $
                          EVENT_PRO='CRISPEX_SLIDER_LP_INCR', ACCELERATOR='Shift+S', /SEPARATOR)
	sh_lp_decr_button 	= WIDGET_BUTTON(moviemenu, VALUE='Main '+$
                          STRLOWCASE(sp_h[heightset])+' position -', $
                          EVENT_PRO='CRISPEX_SLIDER_LP_DECR', ACCELERATOR='Shift+A')
	sh_lp_ref_incr_button= WIDGET_BUTTON(moviemenu, VALUE='Reference '+$
                          STRLOWCASE(sp_h[refheightset])+' position +', $
                          EVENT_PRO='CRISPEX_SLIDER_LP_REF_INCR', ACCELERATOR='Ctrl+S', $
                          SENSITIVE=hdr.showref)
	sh_lp_ref_decr_button= WIDGET_BUTTON(moviemenu, VALUE='Reference '+$
                          STRLOWCASE(sp_h[refheightset])+' position -', $
                          EVENT_PRO='CRISPEX_SLIDER_LP_REF_DECR', ACCELERATOR='Ctrl+A', $
                          SENSITIVE=hdr.showref)
  ; Analysis                       
  analysismenu        = WIDGET_BUTTON(menubar, VALUE='Analysis', /MENU)
	int_toggle_but		  = WIDGET_BUTTON(analysismenu, VALUE = 'Lightcurve plot', $
                          EVENT_PRO='CRISPEX_DISPLAYS_INT_TOGGLE', $
                          SENSITIVE=(hdr.mainnt GT 1))
  spacetimemenu       = WIDGET_BUTTON(analysismenu, $
                          VALUE='Space-time diagram', /MENU)
  timeslicemenu		    = WIDGET_BUTTON(spacetimemenu, $
                          VALUE='Save current space-time diagram', $
                          /MENU, SENSITIVE=0)
	approxmenu		      = WIDGET_BUTTON(timeslicemenu, VALUE = 'Approximated loop', /MENU)
	save_app_slab_but	  = WIDGET_BUTTON(approxmenu, $
                          VALUE='All '+STRLOWCASE(sp_h[heightset])+$
                          ' positions', EVENT_PRO='CRISPEX_SAVE_APPROX_LOOPSLAB')
	save_app_slice_but	= WIDGET_BUTTON(approxmenu, $
                          VALUE='Current '+STRLOWCASE(sp_h[heightset])+$
                          ' position', EVENT_PRO='CRISPEX_SAVE_APPROX_LOOPSLICE')
	interpolmenu		    = WIDGET_BUTTON(timeslicemenu, VALUE='Interpolated loop', /MENU)
	save_ex_slab_but	  = WIDGET_BUTTON(interpolmenu, $
                          VALUE='All '+STRLOWCASE(sp_h[heightset])+$
                          ' positions', EVENT_PRO='CRISPEX_SAVE_EXACT_LOOPSLAB_CHECK')
	save_ex_slice_but	  = WIDGET_BUTTON(interpolmenu, $
                          VALUE='Current '+STRLOWCASE(sp_h[heightset])+$
                          ' position', EVENT_PRO='CRISPEX_SAVE_EXACT_LOOPSLICE')
	save_loop_pts		    = WIDGET_BUTTON(spacetimemenu, $
                          VALUE='Save current path for later retrieval', $
                          EVENT_PRO='CRISPEX_SAVE_LOOP_PTS', SENSITIVE=0)
	sel_saved_loop		  = WIDGET_BUTTON(spacetimemenu, $
                          VALUE='Save from selected path(s)', /SEPARATOR, $
                          EVENT_PRO='CRISPEX_RETRIEVE_LOOP_MENU', SENSITIVE=1)
	all_saved_loop		  = WIDGET_BUTTON(spacetimemenu, $
                          VALUE='Save from all paths', /MENU, SENSITIVE=0)
	all_saved_all_pos	  = WIDGET_BUTTON(all_saved_loop, $
                          VALUE='At all '+STRLOWCASE(sp_h[heightset])+$
                          ' positions', EVENT_PRO = 'CRISPEX_RETRIEVE_LOOP_ALL_LOOPSLAB')
	all_saved_sel_pos	  = WIDGET_BUTTON(all_saved_loop, VALUE = 'At saved '+$
                          STRLOWCASE(sp_h[heightset])+' position', $
                          EVENT_PRO='CRISPEX_RETRIEVE_LOOP_ALL_LOOPSLICE')
	det_file_loop		    = WIDGET_BUTTON(spacetimemenu, VALUE='Save from detection file...', $
                          EVENT_PRO='CRISPEX_RETRIEVE_DET_FILE_MENU')
	overlay_but 		    = WIDGET_BUTTON(spacetimemenu, VALUE='Overlay saved paths', $
                          EVENT_PRO='CRISPEX_RESTORE_LOOPS_MAIN', /SEPARATOR)
  ; Help
  helpmenu            = WIDGET_BUTTON(menubar, VALUE='Help', /MENU)
	open_help		        = WIDGET_BUTTON(helpmenu, VALUE='Open online help', $
                          EVENT_PRO='CRISPEX_HELP', ACCELERATOR='Ctrl+H')
	mailbugmenu		      = WIDGET_BUTTON(helpmenu, VALUE='Submit a bug report', $
                          EVENT_PRO='CRISPEX_HELP_MAIL_BUG')
	mailsugmenu		      = WIDGET_BUTTON(helpmenu, VALUE='Submit a suggestion', $
                          EVENT_PRO='CRISPEX_HELP_MAIL_SUGGESTION')
  shortcuts           = WIDGET_BUTTON(helpmenu, VALUE='Show shortcuts', /SEPARATOR, $
                          EVENT_PRO='CRISPEX_HELP_SHORTCUTS')
  ; Help: Developer
	developermenu   		= WIDGET_BUTTON(helpmenu, VALUE = 'Developer', /MENU, /SEPARATOR, $
                          UVALUE='developer')
	sh_runtime_interrupt= WIDGET_BUTTON(developermenu, VALUE='Interrupt', $
                          EVENT_PRO='CRISPEX_INTERRUPT', ACCELERATOR='Ctrl+Shift+C')
	sh_runtime_verb_menu= WIDGET_BUTTON(developermenu, VALUE='Verbosity', /MENU, UVALUE='verbosity')
	sh_verb_0		        = WIDGET_BUTTON(sh_runtime_verb_menu, VALUE='No verbosity', $
                          EVENT_PRO='CRISPEX_VERBOSE_SET', UVALUE=-1, /NO_RELEASE, /CHECKED_MENU, $
                          ACCELERATOR='Shift+0')
	sh_verb_4		        = WIDGET_BUTTON(sh_runtime_verb_menu, VALUE='Basic runtime verbosity', $
                          EVENT_PRO='CRISPEX_VERBOSE_SET', UVALUE=2, /NO_RELEASE, /CHECKED_MENU, $
                          ACCELERATOR='Shift+4')
	sh_verb_8		        = WIDGET_BUTTON(sh_runtime_verb_menu, VALUE='Extended runtime verbosity', $
                          EVENT_PRO='CRISPEX_VERBOSE_SET', UVALUE=3, /NO_RELEASE, /CHECKED_MENU, $
                          ACCELERATOR='Shift+8')
	sh_verb_16		      = WIDGET_BUTTON(sh_runtime_verb_menu, VALUE='Enable playback statistics', $
                          EVENT_PRO='CRISPEX_VERBOSE_SET', UVALUE=4, /NO_RELEASE, /CHECKED_MENU, $
                          ACCELERATOR='Shift+P')
  clear_menu		      = WIDGET_BUTTON(developermenu, VALUE='Clear', /MENU)
	clear_current_estimate= WIDGET_BUTTON(clear_menu, VALUE='Current time estimate', $
                          EVENT_PRO='CRISPEX_CLEAR_CURRENT_ESTIMATE', SENSITIVE=estimate_run)
	clear_current_cpft	= WIDGET_BUTTON(clear_menu, VALUE='CPFT file for current machine', $
                          EVENT_PRO='CRISPEX_CLEAR_CURRENT_CPFT', SENSITIVE=(cpftfilecount EQ 1))
	clear_current_inst	= WIDGET_BUTTON(clear_menu, VALUE='Instance file for current machine', $
                          EVENT_PRO='CRISPEX_CLEAR_CURRENT_INST', SENSITIVE=(instfilecount EQ 1))
	dispwid			        = WIDGET_BUTTON(developermenu, VALUE='Display window IDs', $
                          EVENT_PRO='CRISPEX_DISPWIDS', ACCELERATOR='Ctrl+I', /CHECKED_MENU)

  tab_width   = 384
  pad         = 3
  extra_pad   = 7*pad
;	tab_tlb			= WIDGET_TAB(control_panel, LOCATION=0, MULTILINE=4, XSIZE=tab_width+2*pad)
	tab_tlb			= WIDGET_TAB(control_panel, LOCATION=0, MULTILINE=5, XSIZE=tab_width+2*pad)
 
  ; ==================== Define and order tabs ====================
	playback_tab        = WIDGET_BASE(tab_tlb, TITLE='Temporal', /COLUMN, $
                          XSIZE=tab_width+extra_pad)
	spectral_tab		    = WIDGET_BASE(tab_tlb, TITLE=sp_h[heightset], /COLUMN, $
                          XSIZE=tab_width+extra_pad)
	spatial_tab		      = WIDGET_BASE(tab_tlb, TITLE='Spatial', /COLUMN, $
                          XSIZE=tab_width+extra_pad)
	stokes_tab		      = WIDGET_BASE(tab_tlb, TITLE='Stokes', /COLUMN, $
                          XSIZE=tab_width+extra_pad)
	scaling_tab 		    = WIDGET_BASE(tab_tlb, TITLE='Scaling', /COLUMN, $
                          XSIZE=tab_width+extra_pad)
  diagnostics_tab     = WIDGET_BASE(tab_tlb, TITLE='Diagnostics', /COLUMN, $
                          XSIZE=tab_width+extra_pad)
	analysis_tab		    = WIDGET_BASE(tab_tlb, TITLE='Analysis',/COLUMN, $
                          XSIZE=tab_width+extra_pad)
	overlays_tab        = WIDGET_BASE(tab_tlb, TITLE='Overlays', /COLUMN, $
                          XSIZE=tab_width+extra_pad)
	display_tab		      = WIDGET_BASE(tab_tlb, TITLE='Displays', /COLUMN, $
                          XSIZE=tab_width+extra_pad)
	plots_tab		        = WIDGET_BASE(tab_tlb, TITLE='Plots', /COLUMN, $
                          XSIZE=tab_width+extra_pad)
  
  ; ==================== Always visible controls ====================
  ; Playback controls
  extra_xpad          = 10
  ; Zoom controls
  zoom_contr          = WIDGET_BASE(control_panel, /ROW, FRAME=1)
  zoom_field_buts     = WIDGET_BASE(zoom_contr, FRAME=0, /GRID_LAYOUT, $
                          COLUMN=6, XPAD=extra_xpad)
  IF (zoomfactor LT 1) THEN $
    bmpbut_zoom_tofit = bmpbut_zoom_tofit_pressed $
  ELSE $
    bmpbut_zoom_tofit = bmpbut_zoom_tofit_idle
  zoom_to_fit         = WIDGET_BUTTON(zoom_field_buts, $
                          VALUE=bmpbut_zoom_tofit, $
                          EVENT_PRO='CRISPEX_ZOOM_TOFIT', $
                          TOOLTIP='Zoom to fit', $
                          SENSITIVE=(zoomfactor LT 1))
  zoom_to_scale       = WIDGET_BUTTON(zoom_field_buts, $
                          VALUE=bmpbut_zoom_toscale_idle, $
                          EVENT_PRO='CRISPEX_ZOOM_TOSCALE', $
                          TOOLTIP='Zoom to scale', $
                          SENSITIVE=(zoomfactor LT 1))
  zoom_in             = WIDGET_BUTTON(zoom_field_buts, $
                          VALUE=bmpbut_zoom_in_idle, $
                          EVENT_PRO='CRISPEX_ZOOMFAC_INCR', $
                          TOOLTIP='Zoom in')
  zoom_out            = WIDGET_BUTTON(zoom_field_buts, $
                          VALUE=bmpbut_zoom_out_idle, $
                          EVENT_PRO='CRISPEX_ZOOMFAC_DECR', $
                          TOOLTIP='Zoom out')
  zoom_field_buts2    = WIDGET_BASE(zoom_contr, FRAME=0, /GRID_LAYOUT, $
                          COLUMN=2, XPAD=extra_xpad)
  zoom_pan            = WIDGET_BUTTON(zoom_field_buts2, $
                          VALUE=bmpbut_zoom_pan_idle, $
                          EVENT_PRO='CRISPEX_ZOOM_PAN', $
                          TOOLTIP='Pan', SENSITIVE=0)
  zoom_select         = WIDGET_BUTTON(zoom_field_buts2, $
                          VALUE=bmpbut_zoom_select_pressed, $
                          EVENT_PRO='CRISPEX_ZOOM_SELECT', $
                          TOOLTIP='Select')
  zoom_field_buts3    = WIDGET_BASE(zoom_contr, FRAME=0, /GRID_LAYOUT, $
                          COLUMN=2, XPAD=extra_xpad)
  zoom_goto_cursor    = WIDGET_BUTTON(zoom_field_buts3, $
                          VALUE=bmpbut_zoom_goto_curs_idle, $
                          EVENT_PRO='CRISPEX_ZOOM_GOTO_CURSOR', $
                          TOOLTIP='Go to cursor', SENSITIVE=0)
  cursor_button       = WIDGET_BUTTON(zoom_field_buts3, $
                          VALUE=bmpbut_cursor_unlock, TOOLTIP='(Un)lock cursor',$
                          EVENT_PRO='CRISPEX_CURSOR_LOCK')
  zoom_field_basic    = WIDGET_BASE(zoom_contr, FRAME=0, XPAD=extra_xpad, /ROW,$
                          YPAD=extra_xpad*0.8)
  zoom_txt            = WIDGET_LABEL(zoom_field_basic, VALUE='Zoom:')
	zoom_val            = WIDGET_LABEL(zoom_field_basic, $
                          VALUE=STRING(zoomfactor*100.,FORMAT='(I4)')+'%', $
                          /DYNAMIC_RESIZE)

	playback_contr		  = WIDGET_BASE(control_panel, /GRID_LAYOUT, COLUMN=2, $
                          FRAME=1)
	playback_field_basic= WIDGET_BASE(playback_contr, FRAME=0, /GRID_LAYOUT, $
                          COLUMN=5, XPAD=extra_xpad) ;, $
	playback_field_add	= WIDGET_BASE(playback_contr, FRAME=0, $
                          GRID_LAYOUT=(bmpbut_add_failed EQ 0), COLUMN=3,  $
                          EXCLUSIVE=bmpbut_add_failed, XPAD=1.9*extra_xpad)
	fbwd_button		      = WIDGET_BUTTON(playback_field_basic, VALUE = bmpbut_fbwd_idle, $
                          EVENT_PRO='CRISPEX_PB_FASTBACKWARD', TOOLTIP = 'Move one frame backward')
	backward_button		  = WIDGET_BUTTON(playback_field_basic, VALUE = bmpbut_bwd_idle, $
                          EVENT_PRO='CRISPEX_PB_BACKWARD', TOOLTIP = 'Play backward')
	pause_button		    = WIDGET_BUTTON(playback_field_basic, VALUE = bmpbut_pause_pressed, $
                          EVENT_PRO='CRISPEX_PB_PAUSE', TOOLTIP = 'Pause')
	forward_button		  = WIDGET_BUTTON(playback_field_basic, VALUE = bmpbut_fwd_idle, $
                          EVENT_PRO='CRISPEX_PB_FORWARD', TOOLTIP = 'Play forward')
	ffwd_button		      = WIDGET_BUTTON(playback_field_basic, VALUE = bmpbut_ffwd_idle, $
                          EVENT_PRO='CRISPEX_PB_FASTFORWARD', TOOLTIP = 'Move one frame forward')
	loop_button		      = WIDGET_BUTTON(playback_field_add, VALUE = bmpbut_loop_pressed, $
                          EVENT_PRO='CRISPEX_PB_LOOP', TOOLTIP = 'Loop')
	WIDGET_CONTROL, loop_button, SET_BUTTON=bmpbut_add_failed 
	cycle_button		    = WIDGET_BUTTON(playback_field_add, VALUE = bmpbut_cycle_idle, $
                          EVENT_PRO='CRISPEX_PB_CYCLE', TOOLTIP = 'Cycle')
	blink_button		    = WIDGET_BUTTON(playback_field_add, VALUE = bmpbut_blink_idle, $
                          EVENT_PRO='CRISPEX_PB_BLINK', TOOLTIP = 'Blink')
  ; Sliders
  tlp_slider_base     = WIDGET_BASE(control_panel, /GRID_LAYOUT, COLUMN=2)
	t_slid			        = WIDGET_SLIDER(tlp_slider_base, TITLE = 'Frame number', MIN=t_first, $
                          MAX=(t_last>(t_first+1)), VALUE=t_start, EVENT_PRO='CRISPEX_SLIDER_T', /DRAG, $
                          SENSITIVE=t_slid_sens, $
                          XSIZE=FLOOR((tab_width+extra_pad+pad)/2.))
  ; Spectral control
	lp_slid			        = WIDGET_SLIDER(tlp_slider_base, $
                          TITLE = 'Main '+STRLOWCASE(sp_h[heightset])+' position', MIN = lp_first, $
                          MAX = lp_last_slid, VALUE = lp_start, EVENT_PRO = 'CRISPEX_SLIDER_LP', $
					                /DRAG, SENSITIVE = lp_slid_sens)
	
  ; ==================== Playback Tab ====================
  ; Temporal range base
  t_ranges		        = WIDGET_BASE(playback_tab, /COLUMN);, /FRAME, XSIZE=tab_width)
	t_range_field		    = WIDGET_BASE(t_ranges, /ROW, XSIZE=sub_tab_width)
	lower_t_label		    = WIDGET_LABEL(t_range_field, VALUE = 'Lower index:', /ALIGN_LEFT)
	lower_t_text		    = WIDGET_TEXT(t_range_field, VALUE = STRTRIM(t_first,2), /EDITABLE, $
                          XSIZE = 5, EVENT_PRO = 'CRISPEX_DISPRANGE_T_LOW', SENSITIVE = t_slid_sens)
	upper_t_label		    = WIDGET_LABEL(t_range_field, VALUE = 'Upper index:', /ALIGN_LEFT)
	upper_t_text		    = WIDGET_TEXT(t_range_field, VALUE = STRTRIM(t_last,2),  /EDITABLE, $
                          XSIZE = 5, EVENT_PRO = 'CRISPEX_DISPRANGE_T_UPP', SENSITIVE = t_slid_sens)
	reset_trange_but	  = WIDGET_BUTTON(t_range_field, VALUE = '  Reset  ', $
                          EVENT_PRO = 'CRISPEX_DISPRANGE_T_RESET', SENSITIVE = 0)
  playback_divider1   = CRISPEX_WIDGET_DIVIDER(playback_tab)
	slice_update_but	  = WIDGET_BUTTON(playback_tab, $
                          VALUE='Update '+STRLOWCASE(sp_h[heightset])+' windows', $
                          EVENT_PRO = 'CRISPEX_UPDATE_SLICES', SENSITIVE = 0)
  t_speed_step_base   = WIDGET_BASE(playback_tab, /GRID_LAYOUT, COLUMN=2)
	t_speed_slid		    = WIDGET_SLIDER(t_speed_step_base, $
                          TITLE='Animation speed [frame/s]', MIN=1, MAX=100, $
                          XSIZE=FLOOR((tab_width+extra_pad-2*pad)/2.), $
                          VALUE=t_speed, EVENT_PRO='CRISPEX_SLIDER_SPEED', /DRAG)
	t_step_slid		      = WIDGET_SLIDER(t_speed_step_base, $
                          TITLE='Frame increment', MIN=1, MAX=(t_last>2), $
                          VALUE=t_step, EVENT_PRO='CRISPEX_SLIDER_STEP', $
                          XSIZE=FLOOR((tab_width+extra_pad-2*pad)/2.), $
                          SENSITIVE=t_slid_sens)
	imref_blink_field	  = WIDGET_BASE(playback_tab, /ROW,/NONEXCLUSIVE)
	imref_blink_but		  = WIDGET_BUTTON(imref_blink_field, $
                          VALUE = 'Blink between main and reference image', $
                          EVENT_PRO = 'CRISPEX_DISPLAYS_IMREFBLINK_TOGGLE', SENSITIVE = hdr.showref)
  playback_divider2   = CRISPEX_WIDGET_DIVIDER(playback_tab)
  ; Master timing base
  master_time_base    = WIDGET_BASE(playback_tab, /COLUMN);, XSIZE=sub_tab_width)
  master_time_opts    = WIDGET_BASE(master_time_base, /ROW)
  master_time_lab     = WIDGET_LABEL(master_time_opts, VALUE='Master time:', /ALIGN_LEFT)
  master_time_labels  = ['Main', 'Reference', 'SJI']
  master_time_buts    = CW_BGROUP(master_time_opts, master_time_labels, $
                          BUTTON_UVALUE=INDGEN(N_ELEMENTS(master_time_labels)),$
                          IDS=master_time_ids, /EXCLUSIVE, /ROW, $
                          EVENT_FUNC='CRISPEX_BGROUP_MASTER_TIME', /NO_RELEASE)
  master_time_sjicbox = WIDGET_COMBOBOX(master_time_opts, $
                          VALUE=STRJOIN(sji_labels[*,0:(hdr.nsjifiles-1)>0],' '), $
                          EVENT_PRO='CRISPEX_MASTER_TIME_SJI_SELECT', $
                          SENSITIVE=0)  ; Insensitive until SJI selected
  ; Setting buttons and dropdown box
  showdata = [(hdr.showref OR hdr.sjifile), hdr.showref, hdr.sjifile]
  nrasterdims = [SIZE(hdr.tarr_full_main,/N_DIMENSIONS), $
                  SIZE(hdr.tarr_full_ref,/N_DIMENSIONS), 1]
  ; Fake is_raster setting for SJI to ensure button sensitivity if file supplied
  is_raster = [hdr.tfull_dims_main[0], hdr.tfull_dims_ref[0], 1] GE 1
  setbutton = [1,0,0]
  FOR i=0,N_ELEMENTS(master_time_labels)-1 DO $
    WIDGET_CONTROL, master_time_ids[i], SET_BUTTON=setbutton[i], $
    SENSITIVE=(showdata[i] AND is_raster[i])
  ; Raster (nx>1) without time evolution or raster/sit-and-stare with time evolution
  IF (((nrasterdims[0] EQ 1) AND (hdr.nx GT 1) AND (hdr.mainnt EQ 1)) OR $  
    (nrasterdims[0] GE 2)) THEN $                     
    toffset_max = N_ELEMENTS(hdr.tarr_full_main[*,0,0,0])-1 $
  ELSE $
    toffset_max = 1
  time_offset_slid  = WIDGET_SLIDER(playback_tab, $
                        TITLE='Raster timing offset [raster position]', $
                        VALUE=hdr.toffset_main, MIN=0, MAX=toffset_max>1,$
                        EVENT_PRO='CRISPEX_SLIDER_TIME_OFFSET', $
                        SENSITIVE=(is_raster[0] AND (TOTAL(showdata) GT 1)), /DRAG)
  playback_divider3 = CRISPEX_WIDGET_DIVIDER(playback_tab)

  ; ==================== Spectral Tab ====================
  ; Spectral range base
	lp_ranges		        = WIDGET_BASE(spectral_tab, /COLUMN)
  lp_range_sel_field  = WIDGET_BASE(lp_ranges, /ROW)
  lp_restrict_label   = WIDGET_LABEL(lp_range_sel_field, $
                          XSIZE=FLOOR((tab_width+extra_pad-2*pad)*0.42), $
                          VALUE='Restrict '+STRLOWCASE(sp_h[heightset])+$
                          ' range of:', /ALIGN_LEFT)
  lp_restrict_labels  = ['Main  ','Reference']
  lp_restrict_sel_buts= CW_BGROUP(lp_range_sel_field, lp_restrict_labels, $
                          BUTTON_UVALUE=INDGEN(N_ELEMENTS(lp_restrict_labels)),$
                          IDS=lp_restrict_button_ids, /EXCLUSIVE, /ROW, $
                          EVENT_FUNC='CRISPEX_BGROUP_LP_RESTRICT', /NO_RELEASE)
	reset_lprange_but	  = WIDGET_BUTTON(lp_range_sel_field, $
                          VALUE = '  Reset  ',$
                          EVENT_PRO = 'CRISPEX_DISPRANGE_LP_RESET', SENSITIVE = 0)
  WIDGET_CONTROL, lp_restrict_button_ids[0], /SET_BUTTON, $
    SENSITIVE=((hdr.nlp GT 1) AND (singlewav_windows EQ 0))
  WIDGET_CONTROL, lp_restrict_button_ids[1], $
    SENSITIVE=((hdr.refnlp GT 1) AND (refsinglewav_windows EQ 0))

  lp_globloc_base     = WIDGET_BASE(lp_ranges, /ROW, YPAD=-1*pad)
  lp_globloc_emptylab = WIDGET_LABEL(lp_globloc_base, VALUE=' ', $
                          XSIZE=FLOOR((tab_width+extra_pad-2*pad)*0.42))
  lp_globloc_labels   = ['Global','Local']
  lp_glboloc_sel_buts = CW_BGROUP(lp_globloc_base, lp_globloc_labels, $
                          BUTTON_UVALUE=INDGEN(N_ELEMENTS(lp_globloc_labels)),$
                          IDS=lp_globloc_button_ids, /EXCLUSIVE, /ROW, $
                          EVENT_FUNC='CRISPEX_BGROUP_LP_RESTRICT_GLOBLOC', /NO_RELEASE)
  WIDGET_CONTROL, lp_globloc_button_ids[0], /SET_BUTTON, SENSITIVE=$
    ((hdr.nlp GT 1) AND (singlewav_windows EQ 0) AND (hdr.ndiagnostics GT 1))
  WIDGET_CONTROL, lp_globloc_button_ids[1], SENSITIVE=$
    ((hdr.nlp GT 1) AND (singlewav_windows EQ 0) AND (hdr.ndiagnostics GT 1))

  ; Sliders
  restrict_sliders    = WIDGET_BASE(spectral_tab, /GRID_LAYOUT, COLUMN=2)
  lp_restr_slid_low   = WIDGET_SLIDER(restrict_sliders, $
                          TITLE=lp_min_lab[heightset], $
                          VALUE=hdr.v_dop_low_min[0], $
                          MIN=hdr.v_dop_low_min[0], MAX=hdr.v_dop_low_max[0], $
                          EVENT_PRO='CRISPEX_SLIDER_LP_RESTRICT_LOW', /DRAG,$
                          XSIZE=FLOOR((tab_width+extra_pad-2*pad)/2.), $
                          SENSITIVE=hdr.lp_restr_slid_low_sens)
  lp_restr_slid_upp   = WIDGET_SLIDER(restrict_sliders, $
                          TITLE=lp_max_lab[heightset], $
                          VALUE=hdr.v_dop_upp_max[0], $
                          MIN=hdr.v_dop_upp_min[0], MAX=hdr.v_dop_upp_max[0], $
                          EVENT_PRO='CRISPEX_SLIDER_LP_RESTRICT_UPP', /DRAG,$
                          XSIZE=FLOOR((tab_width+extra_pad-2*pad)/2.), $
                          SENSITIVE=hdr.lp_restr_slid_upp_sens)
  spectral_divider1   = CRISPEX_WIDGET_DIVIDER(spectral_tab)
  ; Spectral blink/lock base
  lp_blinklock_butbase= WIDGET_BASE(spectral_tab, /GRID_LAYOUT, COLUMN=2)
	lp_blinklock_field= WIDGET_BASE(lp_blinklock_butbase, /ROW,/NONEXCLUSIVE)
	lp_blink_but		    = WIDGET_BUTTON(lp_blinklock_field, $
                          VALUE='Start '+STRLOWCASE(sp_h[heightset])+' blink', $
                          XSIZE=FLOOR((tab_width+extra_pad-2*pad)/2.), $
                          EVENT_PRO='CRISPEX_PB_SPECTBLINK', $
                          SENSITIVE=lp_slid_sens)
	lp_ref_but		      = WIDGET_BUTTON(lp_blinklock_field, $
                          VALUE='Lock reference to main ', $
                          EVENT_PRO='CRISPEX_SLIDER_LP_REF_LOCK', SENSITIVE=lp_ref_lock) 
	WIDGET_CONTROL, lp_ref_but, SET_BUTTON=lp_ref_lock 
  lp_blinklock_slidbase= WIDGET_BASE(spectral_tab, /GRID_LAYOUT, COLUMN=2)
	lp_blink_slid		    = WIDGET_SLIDER(lp_blinklock_slidbase, $
                          TITLE='Position to blink against', $
                          MIN=lp_first, MAX=lp_last_slid, VALUE=lp_start, $
                          EVENT_PRO='CRISPEX_SLIDER_SPECTBLINK', $
                          XSIZE=FLOOR((tab_width+extra_pad-2*pad)/2.), $
                          /DRAG, SENSITIVE=lp_blink_vals_sens)
  ; Reference spectral base
	lp_ref_slid         = WIDGET_SLIDER(lp_blinklock_slidbase, $
                          TITLE='Reference '+STRLOWCASE(sp_h[refheightset])+' position', $
                          MIN=lp_ref_first, MAX=lp_ref_last, VALUE=lp_ref_start, $
                          EVENT_PRO='CRISPEX_SLIDER_LP_REF', /DRAG, $
                          XSIZE=FLOOR((tab_width+extra_pad-2*pad)/2.), $
                          SENSITIVE=(refslid_sens AND ABS(eqnlps-1)))
  spectral_divider3   = CRISPEX_WIDGET_DIVIDER(spectral_tab)
  ; Phi-slit base
  slit_label_move_base= WIDGET_BASE(spectral_tab, /ROW)
;	slit_label		      = WIDGET_LABEL(slit_label_move_base, VALUE = 'Slit controls:', $
;                          /ALIGN_LEFT)
  phi_slid_base       = WIDGET_BASE(spectral_tab, /GRID_LAYOUT, COLUMN=2, $
                          /ALIGN_CENTER) 
	phi_slid		        = WIDGET_SLIDER(phi_slid_base, $
                          TITLE='Slit angle [degrees]', MIN = 0, MAX = 179, $
                          VALUE=angle, EVENT_PRO='CRISPEX_SLIDER_PHI_ANGLE', $
                          SENSITIVE=0, /DRAG, XSIZE=FLOOR((tab_width+extra_pad-2*pad)/2.))
	nphi_slid		        = WIDGET_SLIDER(phi_slid_base, TITLE = 'Slit length [pixel]', MIN = 2, MAX = nphi, $
                          VALUE=LONG(hdr.ny/3.), EVENT_PRO = 'CRISPEX_SLIDER_NPHI', SENSITIVE = 0, /DRAG)
	slit_move_field		  = WIDGET_BASE(slit_label_move_base,/GRID_LAYOUT, COLUMN=2)

  ; ==================== Spatial Tab ====================
  ; Cursor base 
  main_slid_base      = WIDGET_BASE(spatial_tab, /GRID_LAYOUT, COLUMN=2)
	x_slid			        = WIDGET_SLIDER(main_slid_base, $
                          TITLE='Main X-position [pixel]', MIN=x_first, $
                          MAX=(x_last > 1), VALUE=x_start, $
                          EVENT_PRO='CRISPEX_SLIDER_X', /DRAG, $
                          SENSITIVE=(x_last GT x_first),$
                          XSIZE=FLOOR((tab_width+extra_pad-2*pad)/2.))
	y_slid			        = WIDGET_SLIDER(main_slid_base, $
                          TITLE='Main Y-position [pixel]', MIN=y_first, $
                          MAX=(y_last > 1), VALUE=y_start, $
                          EVENT_PRO='CRISPEX_SLIDER_Y', /DRAG, $
                          SENSITIVE=(y_last GT y_first),$
                          XSIZE=FLOOR((tab_width+extra_pad-2*pad)/2.))
  ref_slid_base       = WIDGET_BASE(spatial_tab, /GRID_LAYOUT, COLUMN=2)
	xref_slid			      = WIDGET_SLIDER(ref_slid_base, $
                          TITLE='Reference X-position [pixel]', MIN=xref_first, $
                          MAX=(xref_last > 1), VALUE=xref_start, $
                          EVENT_PRO='CRISPEX_SLIDER_XREF', /DRAG, $
                          SENSITIVE=((xref_last GT xref_first) AND $
                          (hdr.main2ref_no_map EQ 0)),$
                          XSIZE=FLOOR((tab_width+extra_pad-2*pad)/2.))
	yref_slid			      = WIDGET_SLIDER(ref_slid_base, $
                          TITLE='Reference Y-position [pixel]', MIN=yref_first, $
                          MAX=(yref_last > 1), VALUE=yref_start, $
                          EVENT_PRO='CRISPEX_SLIDER_YREF', /DRAG, $
                          SENSITIVE=((yref_last GT yref_first) AND $
                          (hdr.main2ref_no_map EQ 0)),$
                          XSIZE=FLOOR((tab_width+extra_pad-2*pad)/2.))
  spatial_divider1    = CRISPEX_WIDGET_DIVIDER(spatial_tab)

  ; ==================== Stokes Tab ====================
  stokes_dispsel_base = WIDGET_BASE(stokes_tab, /ROW)
	stokes_disp_label		= WIDGET_LABEL(stokes_dispsel_base, $
                          VALUE='Adjust settings for:', /ALIGN_LEFT)
  stokes_mainref_sel  = CW_BGROUP(stokes_dispsel_base, ['Main','Reference'], $
                          IDS=stokes_mainref_ids, /EXCLUSIVE, /ROW, $
                          EVENT_FUNC='CRISPEX_BGROUP_STOKES_SELECT_IMREF', $
                          /NO_RELEASE)
  stokes_button_sub   = WIDGET_BASE(stokes_tab, /GRID_LAYOUT, COLUMN=2)
  stokes_imbase       = WIDGET_BASE(stokes_button_sub, /COLUMN, $
                          XSIZE=FLOOR((tab_width+extra_pad+3*pad)/2.1))
  stokes_lsbase       = WIDGET_BASE(stokes_button_sub, /COLUMN)
	stokes_main_label		= WIDGET_LABEL(stokes_imbase, VALUE = 'Image:',$
                          /ALIGN_LEFT)
  stokes_button_labels= ['I','Q','U','V']
  stokes_xy_buts      = CW_BGROUP(stokes_imbase, stokes_button_labels, $
                          BUTTON_UVALUE=INDGEN(N_ELEMENTS(stokes_button_labels)),$
                          IDS=stokes_button_ids, /EXCLUSIVE, /ROW, $
                          EVENT_FUNC='CRISPEX_BGROUP_STOKES_SELECT_XY', $
                          /NO_RELEASE)
	stokes_sp_label		  = WIDGET_LABEL(stokes_lsbase, VALUE='Detailed spectra:',$
                          /ALIGN_LEFT)
  stokes_sp_buts      = CW_BGROUP(stokes_lsbase, stokes_button_labels, $
                          BUTTON_UVALUE=INDGEN(N_ELEMENTS(stokes_button_labels)), $
                          IDS=stokes_spbutton_ids, /NONEXCLUSIVE, /ROW, $
                          EVENT_FUNC = 'CRISPEX_BGROUP_STOKES_SELECT_SP')
  stokes_noise_buts   = WIDGET_BASE(stokes_lsbase, /ROW, /NONEXCLUSIVE)
  stokes_noise_but    = WIDGET_BUTTON(stokes_noise_buts, VALUE='Plot noise level', $
                          EVENT_PRO='CRISPEX_DISPLAYS_PLOT_NOISE_SELECT')
  WIDGET_CONTROL, stokes_noise_but, SET_BUTTON=(hdr.ns GT 1), SENSITIVE=(hdr.ns GT 1)
  stokes_divider1     = CRISPEX_WIDGET_DIVIDER(stokes_tab)
  ; Stokes scaling base
  stokes_mult_opts    = WIDGET_BASE(stokes_tab, /ROW)
  stokes_mult_label   = WIDGET_LABEL(stokes_mult_opts, $
                          VALUE='Apply Stokes scaling for:', /ALIGN_LEFT) 
  stokes_mult_buts    = CW_BGROUP(stokes_mult_opts, ['Main', 'Reference'], $
                          BUTTON_UVALUE=INDGEN(2), IDS=stokes_mult_button_ids, $
                          /NONEXCLUSIVE, /ROW, $
                          EVENT_FUNC='CRISPEX_BGROUP_STOKES_SCALING_SELECT')
  WIDGET_CONTROL, stokes_mult_button_ids[0], SENSITIVE=(hdr.ns GT 1), $
    SET_BUTTON=scalestokes[0]
  WIDGET_CONTROL, stokes_mult_button_ids[1], SENSITIVE=(hdr.refns GT 1), $
    SET_BUTTON=scalestokes[1]
  stokes_contpos_opts = WIDGET_BASE(stokes_tab, /ROW)
  stokes_contpos_label= WIDGET_LABEL(stokes_contpos_opts, $
                          VALUE='Continuum position:', $
                          SENSITIVE=((hdr.ns GT 1) OR (hdr.refns GT 1)))
  stokes_contpos_text = WIDGET_TEXT(stokes_contpos_opts, $
                          VALUE=STRTRIM(scale_stokes[0],2), /EDITABLE, XSIZE=5, $
                          EVENT_PRO='CRISPEX_SCALING_STOKES_CONTPOS', $
                          SENSITIVE=((hdr.ns GT 1) OR (hdr.refns GT 1)))
  stokes_contpos_butt = WIDGET_BUTTON(stokes_contpos_opts, $
                          VALUE='Use current', $
                          EVENT_PRO='CRISPEX_SCALING_STOKES_CONTPOS_CURRENT', $
                          SENSITIVE=((hdr.ns GT 1) OR (hdr.refns GT 1)))
  stokes_divider2     = CRISPEX_WIDGET_DIVIDER(stokes_tab)
  
  ; ==================== Diagnostics Tab ====================
  ; Setting Stokes buttons
	spconstraint		= (hdr.nlp GT 1)
  FOR i=0,N_ELEMENTS(stokes_mainref_ids)-1 DO $
    WIDGET_CONTROL, stokes_mainref_ids[i], $
      SENSITIVE=([hdr.multichannel,hdr.refmultichannel])[i], $
      SET_BUTTON=(i EQ 0)
  FOR i=0,N_ELEMENTS(stokes_button_labels)-1 DO BEGIN
    WIDGET_CONTROL, stokes_button_ids[i], SENSITIVE=hdr.stokes_enabled[i], $
      SET_BUTTON=(i EQ 0)
    IF (hdr.multichannel OR (i GT 0)) THEN $
      set_constraint = (spconstraint AND hdr.stokes_enabled[i]) $
    ELSE $
      set_constraint = spconstraint
    WIDGET_CONTROL, stokes_spbutton_ids[i], $
      SENSITIVE=(spconstraint AND hdr.stokes_enabled[i]), $
      SET_BUTTON=set_constraint
  ENDFOR
  ; Spectral window part
  specwin_ysize       = (hdr.ndiagnostics GT 1)*260
  specwin_xsize       = FLOOR((tab_width+extra_pad+3*pad)/2.5)
  specwin_disp_label  = WIDGET_LABEL(diagnostics_tab, $
                          VALUE='Spectral windows:', /ALIGN_LEFT)

  specwin_sub_frame   = WIDGET_BASE(diagnostics_tab, /GRID_LAYOUT, COLUMN=2)
  main_select_base    = WIDGET_BASE(specwin_sub_frame,/COLUMN,/FRAME, $
                          Y_SCROLL_SIZE=specwin_ysize, $
                          X_SCROLL_SIZE=specwin_xsize)
	main_specwin_label  = WIDGET_LABEL(main_select_base, $
                          VALUE='Main: Displaying all', /ALIGN_LEFT, $
                          /DYNAMIC_RESIZE)
  IF (hdr.ndiagnostics GT 1) THEN $
    vals = ['Display all',hdr.diagnostics] $
  ELSE $
    vals = 'N/A'
  specwin_buts        = CW_BGROUP(main_select_base, vals, $
                          BUTTON_UVALUE=INDGEN(N_ELEMENTS(vals)), IDS=specwin_button_ids, $
                          /NONEXCLUSIVE, /COLUMN, EVENT_FUNC='CRISPEX_BGROUP_DIAGNOSTICS_SELECT')
  FOR i=0,N_ELEMENTS(vals)-1 DO $
    WIDGET_CONTROL, specwin_button_ids[i], SENSITIVE=(i GT 0), /SET_BUTTON
  
  ref_select_base     = WIDGET_BASE(specwin_sub_frame,/COLUMN,/FRAME, $
                          Y_SCROLL_SIZE=specwin_ysize, $
                          X_SCROLL_SIZE=specwin_xsize)
  IF (hdr.nrefdiagnostics GT 1) THEN $
    vals = ['Display all', REPLICATE('Hide ',hdr.nrefdiagnostics)+$
            hdr.refdiagnostics] $
  ELSE $
    vals = 'N/A'
  IF (hdr.showref) THEN $
    label_text = 'Displaying all' $
  ELSE $
    label_text = 'N/A'
	ref_specwin_label   = WIDGET_LABEL(ref_select_base, $
                          VALUE='Reference: '+label_text, /ALIGN_LEFT, $
                          /DYNAMIC_RESIZE)
  ref_specwin_cbox    = WIDGET_COMBOBOX(ref_select_base, VALUE=vals, $
                          EVENT_PRO='CRISPEX_REFDIAGNOSTICS_SELECT', $
                          SENSITIVE=(hdr.nrefdiagnostics GT 1))
  diagnostics_divider2= CRISPEX_WIDGET_DIVIDER(diagnostics_tab)

  ; ==================== Displays Tab ====================
  ; Other displays base
	other_label		      = WIDGET_LABEL(display_tab, $
                          VALUE='Toggle displays:', /ALIGN_LEFT)
  displays_sub_frame  = WIDGET_BASE(display_tab, /ROW);/GRID_LAYOUT, COLUMN=3)
  ; Main displays
  main_select_base    = WIDGET_BASE(displays_sub_frame,/COLUMN)
	main_displays_label = WIDGET_LABEL(main_select_base, VALUE = 'Main:', /ALIGN_LEFT)
  vals = ['Doppler',lswintitle[heightset],but_tooltip[heightset]+'-time',$
          but_tooltip[heightset]+' along slit']
  displays_buts       = CW_BGROUP(main_select_base, vals, $
                          BUTTON_UVALUE=INDGEN(N_ELEMENTS(vals)), $
                          IDS=displays_button_ids, /NONEXCLUSIVE, /COLUMN, $
                          EVENT_FUNC='CRISPEX_BGROUP_DISPLAYS_SELECT')
  setbarr = [0, showls, (hdr.spfile AND (singlewav_windows EQ 0)), 0]
  sensarr = [(hdr.nlp GT 1), showls, hdr.spfile, (hdr.nlp GT 1)]
  sensarr = sensarr AND REPLICATE((singlewav_windows EQ 0), N_ELEMENTS(sensarr))
  FOR i=0,N_ELEMENTS(displays_button_ids)-1 DO $
    WIDGET_CONTROL, displays_button_ids[i], SET_BUTTON=(setbarr[i] EQ 1), $
      SENSITIVE=(sensarr[i] EQ 1)
  ; Reference displays 
  ref_select_base     = WIDGET_BASE(displays_sub_frame,/COLUMN)
	ref_displays_label  = WIDGET_LABEL(ref_select_base, VALUE = 'Reference:', $
                          /ALIGN_LEFT)
  refvals = ['Image',lswintitle[refheightset],$
              but_tooltip[refheightset]+'-time']
  refdisplays_buts    = CW_BGROUP(ref_select_base, refvals, $
                          BUTTON_UVALUE=INDGEN(N_ELEMENTS(refvals)), $
                          IDS=refdisplays_button_ids, /NONEXCLUSIVE, /COLUMN, $
                          EVENT_FUNC='CRISPEX_BGROUP_REFDISPLAYS_SELECT')
  ; For reference, set button and sensitivity are determined by the same
  ; parameters
  setbarr = [hdr.showref, showrefls, $
              (hdr.refspfile AND (refsinglewav_windows EQ 0))]
  FOR i=0,N_ELEMENTS(refdisplays_button_ids)-1 DO $
    WIDGET_CONTROL, refdisplays_button_ids[i], SET_BUTTON=(setbarr[i] EQ 1), $
      SENSITIVE=(setbarr[i] EQ 1)
  ; SJI displays
  sji_select_base     = WIDGET_BASE(displays_sub_frame,/COLUMN)
	sji_displays_label  = WIDGET_LABEL(sji_select_base, VALUE = 'Slit-jaw:', $
                          /ALIGN_LEFT)
  IF (hdr.nsjifiles NE 0) THEN $
    values = STRJOIN(sji_labels,' ') $
  ELSE $
    ; Adde extra spaces to accomodate label length when loading SJIs at runtime
    values = REPLICATE('N/A', hdr.nsjifiles_max)
  ; Add extra white-space to accomodate longer labels; take "Spectrum-time" as
  ; default
  tot_length = STRLEN(but_tooltip[heightset]+'-time')
  max_length = MAX(STRLEN(values))
  extra_length = (tot_length-max_length) > 0
  IF (extra_length GT 0) THEN $
    values += STRJOIN(REPLICATE(' ',extra_length))
  sji_button_base   = WIDGET_BASE(sji_select_base, /COLUMN)
  sjidisplays_but   = CW_BGROUP(sji_button_base, values, $
                        BUTTON_UVALUE=INDGEN(N_ELEMENTS(values)), $
                        IDS=sjidisplays_button_ids, /NONEXCLUSIVE, /COLUMN, $
                        EVENT_FUNC='CRISPEX_BGROUP_SJIDISPLAYS_SELECT')
  FOR i=0,hdr.nsjifiles_max-1 DO $
    WIDGET_CONTROL, sjidisplays_button_ids[i], $
    SET_BUTTON=(STRCOMPRESS(values[i],/REMOVE_ALL) NE 'N/A'), $
    SENSITIVE=(STRCOMPRESS(values[i],/REMOVE_ALL) NE 'N/A')
  displays_divider1   = CRISPEX_WIDGET_DIVIDER(display_tab)
  ; Color tables for image displays
  displays_ct_label   = WIDGET_LABEL(display_tab, $
                          VALUE='Image display color table:', /ALIGN_LEFT)
  ; Extra white-space needed to retain xsizes (IDL ignores XSIZE and
  ; DYNAMIC_RESIZE=0 when adding SJI labels during runtime)
  values =  ['All displays', 'Main image'+STRJOIN(REPLICATE(' ',52)),$
    'Reference image', 'Doppler image']
  IF (hdr.nsjifiles GT 1) THEN BEGIN
    FOR idx_sji=0,hdr.nsjifiles-1 DO $
      values = [values, 'Slit-jaw image: '+STRJOIN(sji_labels[*,idx_sji],' ')]
  ENDIF ELSE $
    values = [values, 'Slit-jaw image']
  displays_ct_disp    = WIDGET_COMBOBOX(display_tab, VALUE=values, $
                          EVENT_PRO='CRISPEX_DISPLAYS_CT_IMAGE_SELECT')
  displays_ct_cbox    = WIDGET_COMBOBOX(display_tab, $
                          VALUE=['Please select color table',ct_names_cbox], $
                          EVENT_PRO='CRISPEX_DISPLAYS_CT_SELECT')
  WIDGET_CONTROL, displays_ct_disp, SET_COMBOBOX_SELECT=1
  WIDGET_CONTROL, displays_ct_cbox, SET_COMBOBOX_SELECT=imct[0]+1
  displays_divider2   = CRISPEX_WIDGET_DIVIDER(display_tab)

  ; ==================== Scaling Tab ====================
  IF (hdr.nsjifiles GE 1) THEN $
    scaling_labels_sji = REPLICATE('Slit-jaw image: ',hdr.nsjifiles)+$
      STRJOIN(sji_labels,' ') $
  ELSE $
    scaling_labels_sji = 'Slit-jaw image'
  ; Extra white-space needed to retain xsizes (IDL ignores XSIZE and
  ; DYNAMIC_RESIZE=0 when adding SJI labels during runtime)
  scaling_labels = ['Main image'+STRJOIN(REPLICATE(' ',52)),'Reference image','Doppler image', $
    scaling_labels_sji]
  scaling_cbox        = WIDGET_COMBOBOX(scaling_tab, VALUE=scaling_labels, $
                          EVENT_PRO='CRISPEX_SCALING_SELECT_DATA', $
                          XSIZE=tab_width, DYNAMIC_RESIZE=0)
  imagescale_cbox     = WIDGET_COMBOBOX(scaling_tab, $
                          VALUE=['Based on first non-zero image','Based on current image','Per time step'],$
                          EVENT_PRO='CRISPEX_SCALING_SELECT_TYPE')
  diagscale_label_vals= REPLICATE('Spectral window: ',$
                          2*hdr.ndiagnostics+hdr.nrefdiagnostics+hdr.nsjifiles_max)+$
                          [hdr.diagnostics,hdr.refdiagnostics,hdr.diagnostics,$
                          REPLICATE('N/A',hdr.nsjifiles_max)]
  diagscale_label     = WIDGET_LABEL(scaling_tab, VALUE=diagscale_label_vals[0], /ALIGN_LEFT, $
                          /DYNAMIC_RESIZE)
  histo_base          = WIDGET_BASE(scaling_tab, /ROW)
  histo_opt_label     = WIDGET_LABEL(histo_base, VALUE='Histogram optimisation', /ALIGN_LEFT)
  histo_opt_txt       = WIDGET_TEXT(histo_base, VALUE=STRTRIM(histo_opt_val,2), /EDITABLE, $
                          XSIZE=11, EVENT_PRO='CRISPEX_SCALING_HISTO_OPT_VALUE')
  minmax_sliders      = WIDGET_BASE(scaling_tab, /GRID_LAYOUT, COLUMN=2)
  scalemin_slider     = WIDGET_SLIDER(minmax_sliders, TITLE='Image minimum [%]', MIN=0, MAX=99, $
                          VALUE=0, EVENT_PRO='CRISPEX_SCALING_SLIDER_MIN', /DRAG, $
                          XSIZE=FLOOR((tab_width+extra_pad-2*pad)/2.))
  scalemax_slider     = WIDGET_SLIDER(minmax_sliders, TITLE='Image maximum [%]', MIN=1, MAX=100, $
                          VALUE=100, EVENT_PRO='CRISPEX_SCALING_SLIDER_MAX', /DRAG)
  gamma_label         = WIDGET_LABEL(scaling_tab, VALUE=STRING(gamma_val, FORMAT='(F6.3)'), $
                          /ALIGN_CENTER,XSIZE=250)
  gamma_slider        = WIDGET_SLIDER(scaling_tab, TITLE='Gamma', MIN=0, MAX=1000, $
                          VALUE=500*(ALOG10(gamma_val)+1), EVENT_PRO='CRISPEX_SCALING_GAMMA_SLIDER', $
                          /SUPPRESS, /DRAG,XSIZE=250)
  reset_buts          = WIDGET_BASE(scaling_tab, /ROW, /GRID, /ALIGN_CENTER)
  scaling_reset_but   = WIDGET_BUTTON(reset_buts, VALUE='Reset current', $
                          EVENT_PRO='CRISPEX_SCALING_RESET_DEFAULTS', $
                          TOOLTIP='Reset scaling of current diagnostic to defaults')
  scaling_reset_all_but= WIDGET_BUTTON(reset_buts, VALUE='Reset all', $
                          EVENT_PRO='CRISPEX_SCALING_RESET_ALL_DEFAULTS', $
                          TOOLTIP='Reset scaling of all diagnostics to defaults', $
                          SENSITIVE=(hdr.ndiagnostics GT 1))
  scaling_divider1    = CRISPEX_WIDGET_DIVIDER(scaling_tab)
	
  ; ==================== Analysis Tab ====================
  ; Space-time diagram controls
	loop_label		      = WIDGET_LABEL(analysis_tab, VALUE = 'Space-time diagram along a path:', $
                          /ALIGN_LEFT)
	loop_but_frame		  = WIDGET_BASE(analysis_tab, /NONEXCLUSIVE, /GRID_LAYOUT, COLUMN=2)
	loop_slit_but		    = WIDGET_BUTTON(loop_but_frame, VALUE = 'Draw path  ', $
                          EVENT_PRO = 'CRISPEX_LOOP_DEFINE') 
	loop_feedb_but		  = WIDGET_BUTTON(loop_but_frame, VALUE = 'Path feedback', $
                          EVENT_PRO = 'CRISPEX_LOOP_FEEDBACK')
	WIDGET_CONTROL, loop_feedb_but, /SET_BUTTON
	loop_buts_frame		  = WIDGET_BASE(analysis_tab, /GRID_LAYOUT, COLUMN=2)
	rem_loop_pt_but		  = WIDGET_BUTTON(loop_buts_frame, VALUE = 'Remove last point', $
                          EVENT_PRO = 'CRISPEX_LOOP_REMOVE_POINT', SENSITIVE = 0)
	loop_slice_but		  = WIDGET_BUTTON(loop_buts_frame, VALUE = 'Get diagram along path', $
                          EVENT_PRO = 'CRISPEX_DISPLAYS_LOOPSLAB_GET', SENSITIVE = 0)
  analysis_divider1   = CRISPEX_WIDGET_DIVIDER(analysis_tab)
  ; Measurement tool controls
	measure_label	      = WIDGET_LABEL(analysis_tab, VALUE = 'Spatial measurement tool:', /ALIGN_LEFT)
	measure_buts	      = WIDGET_BASE(analysis_tab, /ROW, /NONEXCLUSIVE)
	measure_but		      = WIDGET_BUTTON(measure_buts, VALUE = 'Start measurement', $
                          EVENT_PRO = 'CRISPEX_MEASURE_ENABLE')
	apix_base		        = WIDGET_BASE(analysis_tab, /ROW)
	apix_label		      = WIDGET_LABEL(apix_base, VALUE = 'Pixel size:', /ALIGN_LEFT, SENSITIVE = 0)
  IF hdr.dx_fixed THEN BEGIN
  	dx_text		        = WIDGET_LABEL(apix_base, VALUE=STRTRIM(STRING(hdr.dx, $
                          FORMAT='(F5.3)'),2), /ALIGN_LEFT, SENSITIVE=0) 
	  x_label		        = WIDGET_LABEL(apix_base, VALUE = 'X', /ALIGN_CENTER, SENSITIVE = 0)
  	dy_text		        = WIDGET_LABEL(apix_base, VALUE=STRTRIM(STRING(hdr.dy, $
                          FORMAT='(F5.3)'),2), /ALIGN_LEFT, SENSITIVE = 0) 
  ENDIF ELSE BEGIN
  	dx_text		= WIDGET_TEXT(apix_base, VALUE = STRTRIM(hdr.dx,2), /EDITABLE, XSIZE=7, $
                    EVENT_PRO = 'CRISPEX_MEASURE_DX', SENSITIVE = 0)
	  x_label		        = WIDGET_LABEL(apix_base, VALUE = 'X', /ALIGN_CENTER, SENSITIVE = 0)
  	dy_text		= WIDGET_TEXT(apix_base, VALUE = STRTRIM(hdr.dy,2), /EDITABLE, XSIZE=7, $
                    EVENT_PRO = 'CRISPEX_MEASURE_DY', SENSITIVE = 0)
  ENDELSE
	apix_unit		        = WIDGET_LABEL(apix_base, VALUE = '['+hdr.xunit+']', /ALIGN_LEFT, SENSITIVE = 0)
	measure_asec		    = WIDGET_BASE(analysis_tab, /ROW)
	measure_asec_lab	  = WIDGET_LABEL(measure_asec, VALUE = 'Distance [arcsec]:', /ALIGN_LEFT, $
                          SENSITIVE = 0)
	measure_asec_text	  = WIDGET_LABEL(measure_asec, VALUE = '0.00', /DYNAMIC_RESIZE, SENSITIVE = 0)
	measure_km		      = WIDGET_BASE(analysis_tab, /ROW)
	measure_km_lab		  = WIDGET_LABEL(measure_km, VALUE = 'Distance [km]:', /ALIGN_LEFT, SENSITIVE = 0)
	measure_km_text		  = WIDGET_LABEL(measure_km, VALUE = '0.00', /DYNAMIC_RESIZE, SENSITIVE = 0)
  analysis_divider2   = CRISPEX_WIDGET_DIVIDER(analysis_tab)

  ; ==================== Overlays Tab ====================
  ; Color settings base
  colset_overlay_label= WIDGET_LABEL(overlays_tab, VALUE='Color settings:', $
                          /ALIGN_LEFT)
	masks_overlay_ct_cbox= WIDGET_COMBOBOX(overlays_tab, $
                          VALUE=ct_idl_names_cbox, $
                          EVENT_PRO='CRISPEX_MASK_OVERLAY_SELECT_COLOR_TABLE', $
                          SENSITIVE=maskfile)
	maskct = 13
	WIDGET_CONTROL, masks_overlay_ct_cbox, SET_COMBOBOX_SELECT=maskct
	masks_overlay_col_slid= WIDGET_SLIDER(overlays_tab, MIN=0, MAX=255, $
                            VALUE=255, TITLE='Color index', $
                            EVENT_PRO='CRISPEX_MASK_OVERLAY_COLOR_SLIDER',$
                            /DRAG, SENSITIVE = maskfile)
  overlays_divider1   = CRISPEX_WIDGET_DIVIDER(overlays_tab)
	overlay_label_width	= FLOOR((tab_width+extra_pad-2*pad)/5.*2.)
  ; Mask overlays base
	masks_overlay		    = WIDGET_BASE(overlays_tab, /ROW)
	masks_overlay_label	= WIDGET_LABEL(masks_overlay, VALUE='Toggle mask on:',$
                          XSIZE=overlay_label_width, /ALIGN_LEFT)
	masks_overlay_buts	= CW_BGROUP(masks_overlay, ['Main     ','Reference','Doppler'],$
                          BUTTON_UVALUE=INDGEN(3),IDS=mask_button_ids,/NONEXCLUSIVE, /ROW, $
                          EVENT_FUNC='CRISPEX_BGROUP_MASK_OVERLAY')
  ; Raster overlays base
  show_condition      = [hdr.showref,hdr.sjifile]
  raster_overlay      = WIDGET_BASE(overlays_tab, /ROW)
  raster_but_labels   = ['Reference', 'SJI']
  raster_label        = WIDGET_LABEL(raster_overlay, $
                          VALUE='Toggle slit positions on:', $
                          XSIZE=overlay_label_width, /ALIGN_LEFT)
  raster_buts         = CW_BGROUP(raster_overlay, raster_but_labels, $
                          BUTTON_UVALUE=INDGEN(N_ELEMENTS(raster_but_labels)), $
                          IDS=raster_button_ids, /NONEXCLUSIVE, /ROW, $
                          EVENT_FUNC='CRISPEX_BGROUP_RASTER_OVERLAY')
  FOR i=0,N_ELEMENTS(raster_but_labels)-1 DO $
    WIDGET_CONTROL, raster_button_ids[i], $
      SET_BUTTON=(show_condition[i] AND (is_raster[0] OR (hdr.nx EQ 1))), $
      SENSITIVE=(show_condition[i] AND (is_raster[0] OR (hdr.nx EQ 1)))
  show_condition      = [1,hdr.showref,hdr.sjifile]
  raster_timing_base  = WIDGET_BASE(overlays_tab, /ROW)
  raster_timing_label = WIDGET_LABEL(raster_timing_base, $
                          VALUE='Toggle timing marker on:', $
                          XSIZE=overlay_label_width, /ALIGN_LEFT)
  raster_timing_labels = ['Main     ','Reference','SJI']
  raster_timing_buts  = CW_BGROUP(raster_timing_base, raster_timing_labels, $
                          BUTTON_UVALUE=INDGEN(N_ELEMENTS(raster_timing_labels)),$
                          IDS=raster_timing_button_ids, /NONEXCLUSIVE, /ROW, $
                          EVENT_FUNC='CRISPEX_BGROUP_RASTER_TIMING_OVERLAY')
  FOR i=0,N_ELEMENTS(raster_timing_labels)-1 DO $
    WIDGET_CONTROL, raster_timing_button_ids[i], $
      SET_BUTTON=(is_raster[0] AND show_condition[i]), $
      SENSITIVE=(is_raster[0] AND show_condition[i])
  overlays_divider1   = CRISPEX_WIDGET_DIVIDER(overlays_tab)
  ; Loop overlays base                            
  overlay_toggle_base = WIDGET_BASE(overlays_tab, /ROW)
	overlay_label		    = WIDGET_LABEL(overlay_toggle_base, $
                          VALUE='Toggle paths:', /ALIGN_LEFT)
	loop_overlay_buts	  = CW_BGROUP(overlay_toggle_base, ['Always','At saved '+$
                          STRLOWCASE(wav_h[heightset])], $
                          BUTTON_UVALUE=INDGEN(2),IDS=loop_overlay_button_ids,$
                          /EXCLUSIVE, /ROW, /NO_RELEASE, $
                          EVENT_FUNC='CRISPEX_BGROUP_LOOP_OVERLAY')
  WIDGET_CONTROL, loop_overlay_button_ids[0], /SET_BUTTON, SENSITIVE=0
  WIDGET_CONTROL, loop_overlay_button_ids[1], SENSITIVE=0
	linestyle_base		  = WIDGET_BASE(overlays_tab, /ROW)
	linestyle_label		  = WIDGET_LABEL(linestyle_base, VALUE='Linestyle:   ', /ALIGN_LEFT)
  linestyles          = ['solid ','dotted','dashed']
	loop_linestyle_buts	= CW_BGROUP(linestyle_base, linestyles, $
                          BUTTON_UVALUE=INDGEN(N_ELEMENTS(linestyles)),$
                          IDS=loop_linestyle_button_ids, /EXCLUSIVE, /ROW,$
                          EVENT_FUNC='CRISPEX_BGROUP_LOOP_LINESTYLE', $
                          /NO_RELEASE)
  FOR i=0,N_ELEMENTS(linestyles)-1 DO $
    WIDGET_CONTROL, loop_linestyle_button_ids[i], SET_BUTTON=(i EQ 0), $
      /SENSITIVE
;  overlays_divider2   = CRISPEX_WIDGET_DIVIDER(overlays_tab)
  
  ; ==================== Plots Tab ====================
	detspect_label_imref= WIDGET_BASE(plots_tab, /ROW)
	detspect_label		  = WIDGET_LABEL(detspect_label_imref, VALUE = lswintitle[heightset]+':',$
                          /ALIGN_LEFT, /DYNAMIC_RESIZE)
	detspect_imref		  = WIDGET_BASE(detspect_label_imref, /ROW)
  detspect_imref_buts = CW_BGROUP(detspect_imref, lp_restrict_labels, $
                          BUTTON_UVALUE=INDGEN(N_ELEMENTS(lp_restrict_labels)),$
                          IDS=detspect_imref_button_ids, /EXCLUSIVE, /ROW, $
                          EVENT_FUNC='CRISPEX_BGROUP_DETSPECT_IMREF', /NO_RELEASE)
  WIDGET_CONTROL, detspect_imref_button_ids[0], SENSITIVE=showls, $
    SET_BUTTON=(hdr.nlp GT 1)
  WIDGET_CONTROL, detspect_imref_button_ids[1], SENSITIVE=showrefls
	detspect_range		  = WIDGET_BASE(plots_tab, /ROW)  ;/GRID_LAYOUT, COLUMN=4)
	lower_y_label		    = WIDGET_LABEL(detspect_range, VALUE='Plot range:', $
                          XSIZE=FLOOR((tab_width+extra_pad-2*pad)/5.),$
                          /ALIGN_LEFT)
	lower_y_text		    = WIDGET_TEXT(detspect_range, $
                          VALUE=STRTRIM(hdr.ls_low_y_init,2), /EDITABLE, $
                          XSIZE=6, SENSITIVE=showls, $
                          EVENT_PRO='CRISPEX_DISPRANGE_LS_LOW')
	upper_y_label		    = WIDGET_LABEL(detspect_range, VALUE=' to ', /ALIGN_LEFT)
	upper_y_text		    = WIDGET_TEXT(detspect_range, $
                          VALUE=STRTRIM(hdr.ls_upp_y_init,2), /EDITABLE, $
                          XSIZE=6, SENSITIVE=showls, $
                          EVENT_PRO='CRISPEX_DISPRANGE_LS_UPP')
  ; LS scaling base
  ls_mult_opts        = WIDGET_BASE(plots_tab, /ROW)
  ls_mult_label       = WIDGET_LABEL(ls_mult_opts, VALUE='Multiply:', /ALIGN_LEFT, $
                          XSIZE=FLOOR((tab_width+extra_pad-2*pad)/5.),$
                          SENSITIVE=( (hdr.ndiagnostics GT 1) OR $
                                      (hdr.nrefdiagnostics GT 1)))
  IF (hdr.refdiagnostics[0] NE 'N/A') THEN $
    ls_mult_list  = [REPLICATE('Main ',hdr.ndiagnostics)+hdr.diagnostics, $
                      REPLICATE('Reference ',hdr.nrefdiagnostics)+hdr.refdiagnostics] $
  ELSE $
    ls_mult_list  = [REPLICATE('Main ',hdr.ndiagnostics)+hdr.diagnostics]
  ls_mult_cbox        = WIDGET_COMBOBOX(ls_mult_opts, VALUE=ls_mult_list, $
                          EVENT_PRO='CRISPEX_SCALING_MULTIPLY_LS_SELECT', /DYNAMIC_RESIZE, $
                          SENSITIVE=((hdr.ndiagnostics GT 1) OR (hdr.nrefdiagnostics GT 1)))
  ls_mult_by          = WIDGET_LABEL(ls_mult_opts, VALUE=' by ', /ALIGN_CENTER, $
                          SENSITIVE=((hdr.ndiagnostics GT 1) OR (hdr.nrefdiagnostics GT 1)))
  ls_mult_txt         = WIDGET_TEXT(ls_mult_opts, VALUE=STRTRIM(hdr.main_mult_val[0],2), /EDITABLE, $
                          XSIZE=6, EVENT_PRO='CRISPEX_SCALING_MULTIPLY_LS_VALUE', $
                          SENSITIVE=((hdr.ndiagnostics GT 1) OR (hdr.nrefdiagnostics GT 1)))
;  scaling_divider2    = CRISPEX_WIDGET_DIVIDER(scaling_tab)
	scale_detspect_buts = WIDGET_BASE(plots_tab, /ROW, /NONEXCLUSIVE)
	scale_detspect_but  = WIDGET_BUTTON(scale_detspect_buts, $
                          VALUE='Scale to maximum of average',$
                          EVENT_PRO = 'CRISPEX_DISPRANGE_LS_SCALE_SELECT', $
					                SENSITIVE = (detspect_scale_enable AND showls), $
                          /DYNAMIC_RESIZE)
	subtract_but		    = WIDGET_BUTTON(scale_detspect_buts, $
                          VALUE='Subtract average', $
                          EVENT_PRO='CRISPEX_DISPRANGE_LS_SUBTRACT', $
                          SENSITIVE=showls, $
                          TOOLTIP='Subtract detailed spectrum from average spectrum')
	WIDGET_CONTROL, scale_detspect_but, SET_BUTTON = detspect_scale
  plots_divider1      = CRISPEX_WIDGET_DIVIDER(plots_tab)

  ; ==================== Parameters Overview ====================
    ; Position parameters
    params_position_base = WIDGET_BASE(control_panel, /ROW,/FRAME, /GRID_LAYOUT)
    verlabel_base = WIDGET_BASE(params_position_base, /COLUMN)
      no_label    = WIDGET_LABEL(verlabel_base, VALUE='Position', /ALIGN_LEFT)
      pixel_label = WIDGET_LABEL(verlabel_base, VALUE='Index [px]', /ALIGN_RIGHT)
      IF (hdr.wcs_set OR hdr.ref_wcs_set OR (TOTAL(hdr.sji_wcs_set) GE 1)) THEN $
        real_label_value = 'Solar XY ["]' $
      ELSE IF (STRCOMPRESS(hdr.xunit) EQ 'arcsec') THEN $
        real_label_value = 'Value ["]' $
      ELSE $
        real_label_value = 'Value ['+STRCOMPRESS(hdr.xunit)+']'
      real_label  = WIDGET_LABEL(verlabel_base, VALUE=real_label_value, $
        /ALIGN_RIGHT) 
    params_main_base = WIDGET_BASE(params_position_base, /COLUMN)
      main_label  = WIDGET_LABEL(params_main_base, VALUE='Main', /ALIGN_RIGHT)
        xcoord_format = '(I'+STRTRIM(FLOOR(ALOG10(hdr.nx))+1,2)+')'
        ycoord_format = '(I'+STRTRIM(FLOOR(ALOG10(hdr.ny))+1,2)+')'
        coord_txt = '    ('+STRING(LONG(x_start),FORMAT=xcoord_format)+$
          ','+STRING(LONG(y_start),FORMAT=ycoord_format)+')'
		    xycoord_val = WIDGET_LABEL(params_main_base, VALUE=coord_txt, $
          /ALIGN_RIGHT)
        IF hdr.wcs_set THEN BEGIN
          xy_real = CRISPEX_TRANSFORM_GET_WCS(x_start, y_start, hdr.wcs_main, $
            /COORD, /NO_ROUND)
          xcoord_real_format = '(F6.1)'
          ycoord_real_format = '(F6.1)'
          real_coord_txt = '('+STRING(xy_real.x,FORMAT=xcoord_real_format)+$
            ','+STRING(xy_real.y,FORMAT=ycoord_real_format)+')'
        ENDIF ELSE BEGIN
          xcoord_real_format = '(F'+STRTRIM(FLOOR(ALOG10(hdr.nx*hdr.dx))+3+$
            (hdr.nx*hdr.dx LT 1),2)+'.1)'
          ycoord_real_format = '(F'+STRTRIM(FLOOR(ALOG10(hdr.ny*hdr.dy))+3+$
            (hdr.ny*hdr.dy LT 1),2)+'.1)'
          real_coord_txt = '('+STRING(FLOAT(x_start*hdr.dx),FORMAT=xcoord_real_format)+$
            ','+STRING(FLOAT(y_start*hdr.dy),FORMAT=ycoord_real_format)+')' 
        ENDELSE
		    xycoord_real_val = WIDGET_LABEL(params_main_base, VALUE=real_coord_txt, $
          /ALIGN_RIGHT)
    params_ref_base = WIDGET_BASE(params_position_base, /COLUMN, /ALIGN_RIGHT)
      ref_label   = WIDGET_LABEL(params_ref_base, VALUE='Reference', /ALIGN_RIGHT)
      IF hdr.showref THEN BEGIN
        refxcoord_format = '(I'+STRTRIM(FLOOR(ALOG10(hdr.refnx))+1,2)+')'
        refycoord_format = '(I'+STRTRIM(FLOOR(ALOG10(hdr.refny))+1,2)+')'
        refcoord_txt = '    ('+STRING(LONG(xref_start),FORMAT=refxcoord_format)+$
          ','+STRING(LONG(yref_start),FORMAT=refycoord_format)+')'
        IF hdr.ref_wcs_set THEN BEGIN
          xyref_real = CRISPEX_TRANSFORM_GET_WCS(xref_start, yref_start, hdr.wcs_ref, $
            /COORD, /NO_ROUND)
          refxcoord_real_format = '(F6.1)'
          refycoord_real_format = '(F6.1)'
          refcoord_real_txt = '('+STRING(xyref_real.x,FORMAT=refxcoord_real_format)+$
            ','+STRING(xyref_real.y,FORMAT=refycoord_real_format)+')'
        ENDIF ELSE BEGIN
          refxcoord_real_format = '(F'+STRTRIM(FLOOR(ALOG10(hdr.refnx*hdr.dx))+3+$
            (hdr.refnx*hdr.dx LT 1),2)+'.1)'
          refycoord_real_format = '(F'+STRTRIM(FLOOR(ALOG10(hdr.refny*hdr.dy))+3+$
            (hdr.refny*hdr.dy LT 1),2)+'.1)'
          refcoord_real_txt = '('+STRING(FLOAT(xref_start*hdr.dx),FORMAT=refxcoord_real_format)+$
            ','+STRING(FLOAT(yref_start*hdr.dy),FORMAT=refycoord_real_format)+')'
        ENDELSE
      ENDIF ELSE BEGIN
        refcoord_txt = 'N/A'
        refxcoord_format = ''
        refycoord_format = ''
        refcoord_real_txt = 'N/A'
        refxcoord_real_format = ''
        refycoord_real_format = ''
      ENDELSE
		  refxycoord_val = WIDGET_LABEL(params_ref_base, VALUE=refcoord_txt, $
        /ALIGN_RIGHT, /DYNAMIC_RESIZE)
		  refxycoord_real_val = WIDGET_LABEL(params_ref_base, VALUE=refcoord_real_txt, $
        /ALIGN_RIGHT, /DYNAMIC_RESIZE)
    params_sji_base = WIDGET_BASE(params_position_base, /COLUMN, /ALIGN_RIGHT)
      sji_label   = WIDGET_LABEL(params_sji_base, VALUE='Slit-jaw', /ALIGN_RIGHT)
      IF hdr.sjifile THEN BEGIN
        sjixcoord_format = '(I'+STRTRIM(FLOOR(ALOG10(MAX(hdr.sjinx)))+1,2)+')'
        sjiycoord_format = '(I'+STRTRIM(FLOOR(ALOG10(MAX(hdr.sjiny)))+1,2)+')'
        sjicoord_txt = '    ('+STRING(LONG(xsji_start[0]),FORMAT=sjixcoord_format)+$
          ','+STRING(LONG(ysji_start[0]),FORMAT=sjiycoord_format)+')'
        IF (TOTAL(hdr.sji_wcs_set) GE 1) THEN BEGIN
          xysji_real = CRISPEX_TRANSFORM_GET_WCS(xsji_start[0], ysji_start[0], $
            *hdr.wcs_sji[0], /COORD, /NO_ROUND)
          sjixcoord_real_format = '(F6.1)'
          sjiycoord_real_format = '(F6.1)'
          sjicoord_real_txt = '('+STRING(xysji_real.x,FORMAT=sjixcoord_real_format)+$
            ','+STRING(xysji_real.y,FORMAT=sjiycoord_real_format)+')'
        ENDIF ELSE BEGIN
          sjixcoord_real_format = $
            '(F'+STRTRIM(FLOOR(ALOG10(MAX(hdr.sjinx*hdr.sjidx)))+3,2)+'.1)'
          sjiycoord_real_format = $
            '(F'+STRTRIM(FLOOR(ALOG10(MAX(hdr.sjiny*hdr.sjidy)))+3,2)+'.1)'
          sjicoord_real_txt = $
            '('+STRING(FLOAT(xsji_start[0]*hdr.sjidx[0]),$
              FORMAT=sjixcoord_real_format)+'",'+$
                STRING(FLOAT(ysji_start[0]*hdr.sjidy[0]),$
              FORMAT=sjiycoord_real_format)+'")'
        ENDELSE
      ENDIF ELSE BEGIN
        sjicoord_txt = 'N/A'
        sjixcoord_format = ''
        sjiycoord_format = ''
        sjicoord_real_txt = 'N/A'
        sjixcoord_real_format = ''
        sjiycoord_real_format = ''
      ENDELSE
		  sjixycoord_val = WIDGET_LABEL(params_sji_base, VALUE=sjicoord_txt, $
        /ALIGN_RIGHT, DYNAMIC_RESIZE=(hdr.sjifile EQ 0))
		  sjixycoord_real_val = WIDGET_LABEL(params_sji_base, VALUE=sjicoord_real_txt, $
        /ALIGN_RIGHT, DYNAMIC_RESIZE=(hdr.sjifile EQ 0))

    ; Spectral parameters
;      divider_label = WIDGET_LABEL(verlabel_base, VALUE=' ')
      no_label    = WIDGET_LABEL(verlabel_base, VALUE=wav_h[heightset[0]], /ALIGN_LEFT)
      pixel_label = WIDGET_LABEL(verlabel_base, VALUE='Index [px]', /ALIGN_RIGHT)
      show_lp_vdop_label = (TOTAL(hdr.v_dop_set) GE 1) 
      show_lp_val_label = ((TOTAL([heightset,refheightset]) GE 1) OR $
        show_lp_vdop_label)
      display_vdop = (hdr.v_dop_set[0] EQ 1)
      display_vals = ((heightset EQ 1) OR (hdr.v_dop_set[0] EQ 1))
		  IF display_vals THEN BEGIN
        real_label_value = 'Value ['
        IF (STRLOWCASE(STRCOMPRESS(hdr.lpunit)) EQ 'angstrom') THEN $
          real_label_value += STRMID(cgSymbol("angstrom"),2,1)+']' $
        ELSE $
          real_label_value += STRCOMPRESS(hdr.lpunit)+']'
        real_label  = WIDGET_LABEL(verlabel_base, VALUE=real_label_value, $
          /ALIGN_RIGHT)
      ENDIF
		  IF show_lp_vdop_label THEN $
        vdop_label  = WIDGET_LABEL(verlabel_base, VALUE='Doppler [km/s]', $
          /ALIGN_RIGHT)
      main_label  = WIDGET_LABEL(params_main_base, VALUE=' ', /ALIGN_RIGHT)
      lp_idx_format = '(I'+STRTRIM(FLOOR(ALOG10(hdr.nlp))+1,2)+')'
      IF display_vals THEN BEGIN
        lp_real_format = '(F'+STRTRIM(FLOOR(ALOG10(hdr.lps[lp_last]))+3,2)+'.1)'
        lp_real_txt = STRING(hdr.lps[lp_start], FORMAT=lp_real_format)
      ENDIF ELSE BEGIN
        lp_real_format = ''
        lp_real_val = 0
        lp_real_txt = 'N/A'
      ENDELSE
      IF display_vdop THEN BEGIN
        lp_vdop_format = '(F'+STRTRIM(FLOOR(ALOG10($
          MAX(ABS((*hdr.v_dop[0])[[0,lp_last]]))))+5,2)+'.2)'
        lp_vdop_txt = STRING((*hdr.v_dop[0])[lp_start-hdr.diag_start[0]],$
          FORMAT=lp_vdop_format)
      ENDIF ELSE BEGIN
        lp_vdop_format = ''
        lp_vdop_val = 0
        lp_vdop_txt = 'N/A'
      ENDELSE
		  lp_idx_val = WIDGET_LABEL(params_main_base, VALUE=STRING(LONG(lp_start),$
        FORMAT=lp_idx_format), /ALIGN_RIGHT)
      IF show_lp_val_label THEN $
		    lp_real_val = WIDGET_LABEL(params_main_base, VALUE=lp_real_txt, $
          /ALIGN_RIGHT)
      IF show_lp_vdop_label THEN $
        lp_vdop_val = WIDGET_LABEL(params_main_base, VALUE=lp_vdop_txt, /ALIGN_RIGHT)
      ; Reference
      display_vdop = (hdr.v_dop_set[1] EQ 1) 
      display_vals = ((refheightset EQ 1) OR display_vdop)
      ref_label   = WIDGET_LABEL(params_ref_base, VALUE=' ', /ALIGN_RIGHT)
      lp_ref_real_format = ''
      lp_ref_vdop_format = ''
      lp_ref_real_val = 0
      lp_ref_vdop_val = 0
      lp_ref_real_txt = 'N/A'
      lp_ref_vdop_txt = 'N/A'
      IF (hdr.refnlp GT 1) THEN BEGIN
        lp_ref_idx_format = '(I'+STRTRIM(FLOOR(ALOG10(hdr.refnlp))+1,2)+')'
        lp_ref_idx_txt = STRING(LONG(lp_ref_start), FORMAT=lp_ref_idx_format)
        IF display_vals THEN BEGIN
          lp_ref_real_format = $
            '(F'+STRTRIM(FLOOR(ALOG10(hdr.reflps[lp_ref_last]))+3,2)+'.1)'
          lp_ref_real_txt = STRING(hdr.reflps[lp_ref_start], $
            FORMAT=lp_ref_real_format)
        ENDIF
        IF display_vdop THEN BEGIN
          lp_ref_vdop_format = '(F'+STRTRIM(FLOOR(ALOG10($
            MAX(ABS((*hdr.v_dop_ref[0])[[0,lp_ref_last]]))))+5,2)+'.2)'
          lp_ref_vdop_txt = STRING((*hdr.v_dop_ref[0])[lp_ref_start-$
            hdr.diag_start[0]], FORMAT=lp_ref_vdop_format)
        ENDIF
      ENDIF ELSE BEGIN
        lp_ref_idx_format = ''
        lp_ref_idx_txt = 'N/A'
      ENDELSE
		  lp_ref_idx_val = WIDGET_LABEL(params_ref_base, VALUE=lp_ref_idx_txt,$
        /ALIGN_RIGHT, /DYNAMIC_RESIZE)
		  IF show_lp_val_label THEN $
        lp_ref_real_val = WIDGET_LABEL(params_ref_base, VALUE=lp_ref_real_txt, $
          /ALIGN_RIGHT, /DYNAMIC_RESIZE)
		  IF show_lp_vdop_label THEN $
        lp_ref_vdop_val = WIDGET_LABEL(params_ref_base, VALUE=lp_ref_vdop_txt, $
          /ALIGN_RIGHT, /DYNAMIC_RESIZE)
      ; SJI placeholders
      sji_label   = WIDGET_LABEL(params_sji_base, VALUE=' ', /ALIGN_RIGHT)
		  lp_sji_idx_val = WIDGET_LABEL(params_sji_base, VALUE=' ', /ALIGN_RIGHT)
		  IF ((TOTAL(heightset) GE 1) OR (TOTAL(hdr.v_dop_set) GE 1)) THEN $
        lp_sji_real_val = WIDGET_LABEL(params_sji_base, VALUE=' ', /ALIGN_RIGHT)
		  IF (TOTAL(hdr.v_dop_set) GE 1) THEN $
        lp_sji_vdop_val = WIDGET_LABEL(params_sji_base, VALUE=' ', /ALIGN_RIGHT)
    
    ; Time parameters
      no_label    = WIDGET_LABEL(verlabel_base, VALUE='Time', /ALIGN_LEFT)
      pixel_label = WIDGET_LABEL(verlabel_base, VALUE='Index [px]', /ALIGN_RIGHT)
      IF dt_set THEN BEGIN
        label_val = 'Value '
        IF ((hdr.date_obs_main NE '0') OR $
            (hdr.date_obs_ref NE '0') OR $
            (TOTAL(hdr.date_obs_sji NE '0') GE 1)) THEN $
          label_val += '(UTC)' $
        ELSE $
          label_val += '[s]'
        real_label  = WIDGET_LABEL(verlabel_base, VALUE=label_val, /ALIGN_RIGHT)
      ENDIF
      raster_time_fb = ((N_ELEMENTS(hdr.tarr_full_main) NE $
        N_ELEMENTS(hdr.tarr_main)))
      refraster_time_fb = ((N_ELEMENTS(hdr.tarr_full_ref) NE $
        N_ELEMENTS(hdr.tarr_ref)))
      IF (raster_time_fb OR refraster_time_fb) THEN BEGIN
        label_val = 'Local '
        IF ((hdr.date_obs_main NE '0') OR $
            (hdr.date_obs_ref NE '0') OR $
            (TOTAL(hdr.date_obs_sji NE '0') GE 1)) THEN $
          label_val += '(UTC)' $
        ELSE $
          label_val += '[s]'
        raster_label_fb = WIDGET_LABEL(verlabel_base, VALUE=label_val, /ALIGN_RIGHT)
      ENDIF
      ; ==================== Time feedback ==================== 
      main_label  = WIDGET_LABEL(params_main_base, VALUE=' ', /ALIGN_RIGHT)
      t_idx_format = '(I'+STRTRIM(FLOOR(ALOG10(hdr.mainnt))+1,2)+')'
		  t_idx_val = WIDGET_LABEL(params_main_base, VALUE=STRING(LONG(t_start),$
        FORMAT=t_idx_format), /ALIGN_RIGHT)
      ; -------------------- Main time feedback -------------------- 
      ; Define defaults
      t_real_format = ''
      t_real_txt = 'N/A'
      t_real_val = 0
      IF dt_set THEN BEGIN
        tmax = MAX(hdr.tarr_main, wheretmax, /NAN)
        IF ((hdr.date_obs_main NE '0') OR (hdr.startobs_main NE '0')) THEN $
          t_real_format = '(A'+STRTRIM(STRLEN(hdr.utc_main[wheretmax]),2)+')'  $
        ELSE $
          t_real_format = '(F'+STRTRIM(FLOOR(ALOG10(hdr.tarr_main[$
            wheretmax]))+3,2)+'.1)' 
        t_real_txt = STRING(hdr.utc_main[t_start], FORMAT=t_real_format)
		    t_real_val = WIDGET_LABEL(params_main_base, VALUE=t_real_txt, /ALIGN_RIGHT)
      ENDIF 
      ; -------------------- Main raster time feedback -------------------- 
      ; Define defaults
      t_raster_real_format = ''
      t_raster_real_txt = 'N/A'
      t_raster_real_val = 0
      IF raster_time_fb THEN BEGIN
        startidx = [x_start, lp_start, 0, t_start]
        initidx = INTARR(4)
        FOR i=0,N_ELEMENTS(startidx)-1 DO $
          IF hdr.update_tfull_main[i] THEN initidx[i] = startidx[i]
        tmax = MAX(hdr.tarr_full_main, wheretmax, /NAN)
        IF ((hdr.date_obs_main NE '0') OR (hdr.startobs_main NE '0')) THEN BEGIN
          dumval = hdr.utc_full_main[wheretmax]
          startval = hdr.utc_full_main[$
            initidx[0], initidx[1], initidx[2], initidx[3]]
          t_raster_real_format = '(A'+STRTRIM(STRLEN(dumval),2)+')' 
        ENDIF ELSE BEGIN
          dumval = hdr.tarr_full_main[wheretmax]
          startval = hdr.tarr_full_main[$
            initidx[0], initidx[1], initidx[2], initidx[3]]
          t_raster_real_format = '(F'+STRTRIM(FLOOR(ALOG10(dumval))+3,2)+'.1)'
        ENDELSE
        t_raster_real_txt = STRING(startval, FORMAT=t_raster_real_format)
      ENDIF 
      IF (raster_time_fb OR refraster_time_fb) THEN $
        t_raster_real_val = WIDGET_LABEL(params_main_base, $
          VALUE=t_raster_real_txt, /ALIGN_RIGHT) 
      ; -------------------- Reference time feedback --------------------
      ref_label   = WIDGET_LABEL(params_ref_base, VALUE=' ', /ALIGN_RIGHT)
      ; Define defaults
      t_ref_idx_format = ''
      t_ref_idx_txt = 'N/A'
      t_ref_real_format = ''
      t_ref_real_txt = 'N/A'
      t_ref_real_val = 0
      IF hdr.showref THEN BEGIN
        t_ref_idx_format = '(I'+STRTRIM(FLOOR(ALOG10(hdr.refnt))+1,2)+')'
        t_ref_idx_txt = STRING(LONG(t_start), FORMAT=t_ref_idx_format)
        IF dt_set THEN BEGIN
          tmax = MAX(hdr.tarr_ref, wheretmax, /NAN)
          IF ((hdr.date_obs_ref NE '0') OR (hdr.startobs_ref NE '0')) THEN $
            t_ref_real_format = '(A'+STRTRIM(STRLEN(hdr.utc_ref[wheretmax]),2)+')'  $
          ELSE $
            t_ref_real_format = '(F'+STRTRIM(FLOOR(ALOG10(hdr.tarr_ref[$
              wheretmax]))+3,2)+'.1)' 
            ; if nt = 1 ?-> t_ref_real_format = '(F3.1)'
          t_ref_real_txt = STRING(hdr.utc_ref[t_start], FORMAT=t_ref_real_format)
        ENDIF 
      ENDIF 
		  t_ref_idx_val = WIDGET_LABEL(params_ref_base, VALUE=t_ref_idx_txt, $
        /ALIGN_RIGHT, /DYNAMIC_RESIZE)
      IF dt_set THEN $
        t_ref_real_val = WIDGET_LABEL(params_ref_base, VALUE=t_ref_real_txt, $
          /ALIGN_RIGHT, /DYNAMIC_RESIZE)
      ; -------------------- Reference raster time feedback --------------------
      ; Define defaults
      t_raster_ref_real_format = ''
      t_raster_ref_real_txt = 'N/A'
      t_raster_ref_real_val = 0
      IF refraster_time_fb THEN BEGIN
        startidx = [xref_start, lp_ref_start, 0, t_start]
        initidx = INTARR(4)
        FOR i=0,N_ELEMENTS(startidx)-1 DO $
          IF hdr.update_tfull_ref[i] THEN initidx[i] = startidx[i]
        tmax = MAX(hdr.tarr_full_ref, wheretmax, /NAN)
        IF ((hdr.date_obs_ref NE '0') OR (hdr.startobs_ref NE '0')) THEN BEGIN
          dumval = hdr.utc_full_ref[wheretmax]
          startval = hdr.utc_full_ref[$
            initidx[0], initidx[1], initidx[2], initidx[3]]
          t_raster_ref_real_format = '(A'+STRTRIM(STRLEN(dumval),2)+')' 
        ENDIF ELSE BEGIN
          dumval = hdr.tarr_full_ref[wheretmax]
          startval = hdr.tarr_full_ref[$
            initidx[0], initidx[1], initidx[2], initidx[3]]
          t_raster_ref_real_format = '(F'+STRTRIM(FLOOR(ALOG10(dumval))+3,2)+'.1)'
        ENDELSE
        t_raster_ref_real_txt = STRING(dumval, FORMAT=t_raster_ref_real_format)
      ENDIF 
      IF (raster_time_fb OR refraster_time_fb) THEN $
        t_raster_ref_real_val = WIDGET_LABEL(params_ref_base, $
          VALUE=t_raster_ref_real_txt, /ALIGN_RIGHT, /DYNAMIC_RESIZE) 
      ; -------------------- SJI time feedback --------------------
      sji_label   = WIDGET_LABEL(params_sji_base, VALUE=' ', /ALIGN_RIGHT)
      IF (TOTAL(hdr.sjint) GT hdr.nsjifiles) THEN BEGIN
        t_sji_idx_format = '(I'+STRTRIM(FLOOR(ALOG10(MAX(hdr.sjint)))+1,2)+')'
        t_sji_idx_txt = STRING(LONG(t_start), FORMAT=t_sji_idx_format)
      ENDIF ELSE BEGIN
        t_sji_idx_format = ''
        t_sji_idx_txt = 'N/A'
      ENDELSE
      IF ((hdr.sjint[0] GT 1) AND dt_set) THEN BEGIN
        wheretgt0 = WHERE(*hdr.tarr_sji[0] GT 0, count)
        IF (count GT 0) THEN $
          t_sel = wheretgt0[count-1] $
        ELSE $
          t_sel = 0
        IF (hdr.date_obs_sji[0] NE '0') THEN $
          t_sji_real_format = '(A'+STRTRIM(STRLEN((*hdr.utc_sji[0])[t_sel]),2)+')'  $
        ELSE $
          t_sji_real_format = '(F'+STRTRIM(FLOOR(ALOG10((*hdr.tarr_sji[0])[$
            t_sel]))+3,2)+'.1)'
        t_sji_real_txt = STRING((*hdr.utc_sji[0])[(*hdr.tsel_sji[0])[t_start]], $
          FORMAT=t_sji_real_format)
      ENDIF ELSE BEGIN
        t_sji_real_format = ''
        t_sji_real_val = 0
        t_sji_real_txt = 'N/A'
      ENDELSE
		  t_sji_idx_val = WIDGET_LABEL(params_sji_base, VALUE=t_sji_idx_txt, $
        /ALIGN_RIGHT, DYNAMIC_RESIZE=(hdr.sjifile EQ 0))
		  IF dt_set THEN $
        t_sji_real_val = WIDGET_LABEL(params_sji_base, VALUE=t_sji_real_txt, $
          /ALIGN_RIGHT, DYNAMIC_RESIZE=(hdr.sjifile EQ 0))
      IF (raster_time_fb OR refraster_time_fb) THEN $
        t_sji_raster_real_val = WIDGET_LABEL(params_sji_base, VALUE='N/A', $
          /ALIGN_RIGHT, DYNAMIC_RESIZE=(hdr.sjifile EQ 0))

  ; Data value parameters
      no_label    = WIDGET_LABEL(verlabel_base, VALUE='Data values', /ALIGN_LEFT)
      real_label  = WIDGET_LABEL(verlabel_base, VALUE='Value', /ALIGN_RIGHT)
      main_label  = WIDGET_LABEL(params_main_base, VALUE=' ', /ALIGN_RIGHT)
      dataval_real_txt = STRING(((*hdr.imdata)[lp_start])[x_start,y_start], $
        FORMAT='(E11.4)')
		  dataval_real_val = WIDGET_LABEL(params_main_base, VALUE=dataval_real_txt, $
        /ALIGN_RIGHT)
      ref_label   = WIDGET_LABEL(params_ref_base, VALUE=' ', /ALIGN_RIGHT)
      IF hdr.showref THEN $
        dataval_ref_real_txt = STRING(((*hdr.refdata)[lp_ref_start])[$
          xref_start,yref_start], FORMAT='(E11.4)') $
      ELSE BEGIN
        dataval_ref_real_format = ''
        dataval_ref_real_txt = 'N/A'
      ENDELSE
		  dataval_ref_real_val = WIDGET_LABEL(params_ref_base, $
        VALUE=dataval_ref_real_txt, /ALIGN_RIGHT, /DYNAMIC_RESIZE)
      sji_label   = WIDGET_LABEL(params_sji_base, VALUE=' ', /ALIGN_RIGHT)
      IF (hdr.sjifile AND (xysji_out_of_range[0] EQ 0)) THEN $
        dataval_sji_real_txt = STRING(((*hdr.sjidata[0])[0])[$
          xsji_start[0],ysji_start[0]], FORMAT='(E11.4)') $
      ELSE BEGIN
        dataval_sji_real_format = ''
        dataval_sji_real_txt = 'N/A'
      ENDELSE
      dataval_sji_real_val = WIDGET_LABEL(params_sji_base, VALUE=dataval_sji_real_txt, $
        /ALIGN_RIGHT, DYNAMIC_RESIZE=(hdr.sjifile EQ 0))

   param_base = WIDGET_BASE(control_panel, /ROW)
    ; DATE_OBS
    date_base = WIDGET_BASE(param_base, /ROW, /FRAME)
    date_txt = WIDGET_LABEL(date_base, VALUE='Date:')
    IF (hdr.date_obs_main NE '0') THEN $
      dateval = STRMID(hdr.date_obs_main,0,STRPOS(hdr.date_obs_main,'T')) $
    ELSE IF (hdr.startobs_main NE '0') THEN $
      dateval = STRMID(hdr.startobs_main,0,STRPOS(hdr.startobs_main,'T')) $
    ELSE $
      dateval = 'N/A'
    date_val = WIDGET_LABEL(date_base, VALUE=dateval, /DYNAMIC_RESIZE)
    ; OBSID
		obsid_base = WIDGET_BASE(param_base, /ROW, /FRAME)
		obsid_txt = WIDGET_LABEL(obsid_base, VALUE = 'OBSID:')
    IF (hdr.obsid NE '0') THEN $
      obsidval = hdr.obsid $
    ELSE $
      obsidval = 'N/A'
		obsid_val = WIDGET_LABEL(obsid_base, VALUE = obsidval, /DYNAMIC_RESIZE)

	bg = WIDGET_BASE(cpanel, EVENT_PRO = 'CRISPEX_PB_BG')
	IF (TOTAL(verbosity[0:1]) GE 1) THEN CRISPEX_UPDATE_STARTUP_SETUP_FEEDBACK, $
                                        '(initialising control panel)', /WIDGET, /OVER, /DONE
	feedback_text = [feedback_text[0:N_ELEMENTS(feedback_text)-2],'> Initializing control panel... done!']
	IF startupwin THEN CRISPEX_UPDATE_STARTUP_FEEDBACK, startup_im, xout, yout, feedback_text

;------------------------- SETTING UP DATA POINTERS
	IF (TOTAL(verbosity[0:1]) GE 1) THEN CRISPEX_UPDATE_STARTUP_SETUP_FEEDBACK, $
                                        '(setting up data pointers)', /WIDGET, /OVER
	feedback_text = [feedback_text,'> Setting up data pointers... ']
	IF startupwin THEN CRISPEX_UPDATE_STARTUP_FEEDBACK, startup_im, xout, yout, feedback_text
	index = INTARR(hdr.nx,hdr.ny,2,/NOZERO)
	xarr = INDGEN(hdr.nx)
	yarr = INDGEN(hdr.ny)
	FOR i=0,hdr.nx-1 DO index[i,*,1] = yarr
	FOR j=0,hdr.ny-1 DO index[*,j,0] = xarr
	indexmap= PTR_NEW(index, /NO_COPY)
	indices = PTR_NEW(0)

	xyslice	= PTR_NEW(0)
	dopslice= PTR_NEW(0)
	emptydopslice= PTR_NEW(BYTARR(2,2))
	maskslice= PTR_NEW(0)

  phiscan = PTR_NEW(0)
  sspscan = PTR_NEW(0)
	phislice= PTR_NEW(0)
	IF ((hdr.spfile EQ 1) OR (hdr.single_cube[0] GE 1)) THEN BEGIN
		loopslab= PTR_NEW(0)
		loopslice = PTR_NEW(0)
		refloopslab= PTR_NEW(0)
		refloopslice = PTR_NEW(0)
		sjiloopslice = PTRARR(hdr.nsjifiles_max, /ALLOCATE_HEAP)
		crossloc = PTR_NEW(INTARR(nphi))
		exact_loopslab= PTR_NEW(0)
		exact_loopslice = PTR_NEW(BYTARR(nphi,hdr.mainnt))
		exact_crossloc= PTR_NEW(INTARR(nphi))
		rest_loopslab = PTRARR(nphi,/ALLOCATE_HEAP)
		rest_loopslice = PTRARR(nphi,/ALLOCATE_HEAP)
		rest_crossloc = PTRARR(nphi,/ALLOCATE_HEAP)
		FOR i=0,nphi-1 DO BEGIN
			*rest_loopslab[i]= PTR_NEW(0)
			*rest_loopslice[i] = PTR_NEW(0)
			*rest_crossloc[i]= PTR_NEW(0)
		ENDFOR
		det_loopslab= PTR_NEW(0)
		det_loopslice = PTR_NEW(BYTARR(nphi,hdr.mainnt))
		det_crossloc= PTR_NEW(INTARR(nphi))
	ENDIF ELSE BEGIN
		loopslab = 0		&	loopslice = 0		&	crossloc = 0
		rest_loopslab = 0	&	rest_loopslice = 0	& 	rest_crossloc = 0
		det_loopslab = 0	&	det_loopslice = 0	& 	det_crossloc = 0
		exact_loopslice = 0	& 	exact_loopslab = 0	&	exact_crossloc = 0
		refloopslab = 0		&	refloopslice = 0
    sjiloopslice = 0
		WIDGET_CONTROL, loop_slit_but, SENSITIVE = 0
		WIDGET_CONTROL, loop_feedb_but, SENSITIVE = 0
	ENDELSE
	xp = PTR_NEW(FLTARR(1))
	yp = PTR_NEW(FLTARR(1))
	sxp = PTR_NEW(FLTARR(1))
	syp = PTR_NEW(FLTARR(1))
	
  imwintitle = 'CRISPEX'+instance_label+': Main image'
  ; Create location for main image including scroll bars
  main = WIDGET_BASE(cpanel,/COLUMN)
  ; Prep for color bar
  IF (ctbar_init EQ 0) THEN BEGIN
    draw_ctbar_base = WIDGET_BASE(main,/ROW)
    ctbar_drawid = WIDGET_DRAW(draw_ctbar_base, XSIZE=ctbar_width, $
                    YSIZE=ctbar_height, RETAIN=2)
  ENDIF
  draw_verslid_base = WIDGET_BASE(main,/ROW)
  draw_horslid_base = WIDGET_BASE(main,/ROW)
	xydrawid = WIDGET_DRAW(draw_verslid_base, XSIZE=imwinx, YSIZE=imwiny, RETAIN=2)
  IF ctbar_init THEN $
    ctbar_drawid = WIDGET_DRAW(draw_verslid_base, XSIZE=ctbar_width, $
                    YSIZE=ctbar_height, RETAIN=2)
  ypos_slider = WIDGET_SLIDER(draw_verslid_base,VALUE=0,MIN=0,MAX=1,/SUPPRESS,/DRAG,$
                          EVENT_PRO='CRISPEX_SLIDER_YPOS',/VERTICAL, YSIZE=imwiny)
  xpos_slider = WIDGET_SLIDER(draw_horslid_base,VALUE=0,MIN=0,MAX=1,/SUPPRESS,/DRAG,$
                          EVENT_PRO='CRISPEX_SLIDER_XPOS', $
                          XSIZE=imwinx+ctbar_init*ctbar_width)
	WIDGET_CONTROL, cpanel, /REALIZE, TLB_GET_SIZE=cpanel_size
  ; Determine window offsets based on realised control panel size and position
  ; If reference cube present, check if it would fit next to main image
  IF (window_offsets.set NE 0) THEN BEGIN
    spxoffset = window_offsets.spxoffset
    spyoffset = window_offsets.spyoffset
    lsxoffset = window_offsets.lsxoffset
    lsyoffset = window_offsets.lsyoffset
    dopxoffset = window_offsets.dopxoffset
    dopyoffset = window_offsets.dopyoffset
    imrefxoffset = window_offsets.imrefxoffset
    imrefyoffset = window_offsets.imrefyoffset
    refxoffset = window_offsets.refxoffset
    refyoffset = window_offsets.refyoffset
    refspxoffset = window_offsets.refspxoffset
    refspyoffset = window_offsets.refspyoffset
    reflsxoffset = window_offsets.reflsxoffset
    reflsyoffset = window_offsets.reflsyoffset
    sjixoffset = window_offsets.sjixoffset
    sjiyoffset = window_offsets.sjiyoffset
    phisxoffset = window_offsets.phisxoffset
    phisyoffset = window_offsets.phisyoffset
    intxoffset = window_offsets.intxoffset
    intyoffset = window_offsets.intyoffset
    loopxoffset = window_offsets.loopxoffset
    loopyoffset = window_offsets.loopyoffset
  ENDIF ELSE BEGIN
    refxoffset = cpanel_size[0]
    refyoffset = ydelta
    IF hdr.showref THEN BEGIN
      windows_xextent = cpanel_size[0]+ spwinx + imwinx + lswinx + xdelta*3
      IF (windows_xextent LE x_scr_size) THEN refxoffset += xdelta 
    ENDIF 
  
    ; Set offsets for other windows
    showsp_local = ((hdr.nlp GT 1) AND (hdr.mainnt GT 1)) 
    spxoffset = refxoffset+(hdr.showref*imwinx)+xdelta
    spyoffset = lswiny + ydelta
    lsxoffset = spxoffset
    lsyoffset = 0
    phisxoffset = spxoffset 
    phisyoffset = (hdr.nlp GT 1) * lswiny + ydelta + showsp_local * ydelta
    dopxoffset = xdelta
    dopyoffset = ydelta
    intxoffset = lsxoffset
    intyoffset = 0
    loopxoffset = imwinx + xdelta
    loopyoffset = showsp_local * ydelta
    ; Reference related
    imrefxoffset = xdelta
    imrefyoffset = ydelta
    refspxoffset = spxoffset
    refspyoffset = spyoffset + showsp_local * ydelta
    reflsxoffset = lsxoffset
    reflsyoffset = showsp_local * ydelta
    ; SJI related
    sjixoffset = REPLICATE(lsxoffset + lswinx + xdelta, hdr.nsjifiles_max)
    sjiyoffset = INDGEN(hdr.nsjifiles_max) * ydelta
  ENDELSE
  
  WIDGET_CONTROL, xydrawid, GET_VALUE=imwid
  WIDGET_CONTROL, ctbar_drawid, GET_VALUE=imdrawid_ctbar

	WIDGET_CONTROL, xydrawid, EVENT_PRO = 'CRISPEX_CURSOR', /SENSITIVE, /DRAW_MOTION_EVENTS, $
    /TRACKING_EVENTS, /DRAW_BUTTON_EVENTS
	
	IF (TOTAL(verbosity[0:1]) GE 1) THEN CRISPEX_UPDATE_STARTUP_SETUP_FEEDBACK, $
                                        '(setting up data pointers)', /WIDGET, /OVER, /DONE
	IF startupwin THEN BEGIN
		WSET, startupwid
		WSHOW, startupwid
		feedback_text = [feedback_text[0:N_ELEMENTS(feedback_text)-2],'> Setting up data pointers... done!']
		CRISPEX_UPDATE_STARTUP_FEEDBACK, startup_im, xout, yout, feedback_text
	ENDIF

;------------------------- DEFINE INFO POINTER
	IF (TOTAL(verbosity[0:1]) GE 1) THEN CRISPEX_UPDATE_STARTUP_SETUP_FEEDBACK, $
                                        '(defining main pointer)', /WIDGET, /OVER
	feedback_text = [feedback_text,'> Defining info pointer... ']
	IF startupwin THEN CRISPEX_UPDATE_STARTUP_FEEDBACK, startup_im, xout, yout, feedback_text

;------------------------- CONTROL PANEL BUTTON/TEXT REFERENCES
	ctrlscp = { $
    tab_width:tab_width, $
    openrefim:openrefim, openrefimsp:openrefimsp, $
		save_loop_pts:save_loop_pts, timeslicemenu:timeslicemenu, clear_current_estimate:clear_current_estimate, $			
		sel_saved_loop:sel_saved_loop, all_saved_loop:all_saved_loop, det_file_but:det_file_loop, $
		fbwd_button:fbwd_button, bwd_button:backward_button, pause_button:pause_button, $
		fwd_button: forward_button, ffwd_button:ffwd_button, $
		loop_button:loop_button, blink_button:blink_button, cycle_button:cycle_button, $
		t_slider:t_slid, lower_t_text:lower_t_text, upper_t_text:upper_t_text, $		
		reset_trange_but:reset_trange_but, slice_button:slice_update_but, $			
		t_speed_slider:t_speed_slid, t_step_slider:t_step_slid, imref_blink_but:imref_blink_but, $					
    master_time_ids:master_time_ids, master_time_sjicbox:master_time_sjicbox, $
    time_offset_slider:time_offset_slid, $
		reset_lprange_but:reset_lprange_but,  $
    lp_restrict_button_ids:lp_restrict_button_ids, $
    lp_globloc_button_ids:lp_globloc_button_ids, $
    lp_restr_slider_low:lp_restr_slid_low,$
    lp_restr_slider_upp:lp_restr_slid_upp, $
    lp_slider:lp_slid, lp_blink_slider:lp_blink_slid, $	
		lp_blink_but:lp_blink_but, lp_ref_but:lp_ref_but, lp_ref_slider:lp_ref_slid, $
		x_slider:x_slid, y_slider:y_slid, xref_slider:xref_slid, $
    yref_slider:yref_slid, $
    zoom_to_fit:zoom_to_fit, zoom_to_scale:zoom_to_scale, zoom_in:zoom_in, $
    zoom_out:zoom_out, zoom_pan:zoom_pan, zoom_select:zoom_select, $
    zoom_goto_cursor:zoom_goto_cursor, cursor_button:cursor_button, $
    xpos_slider:xpos_slider, ypos_slider:ypos_slider, $			
    stokes_mainref_ids:stokes_mainref_ids, $
    stokes_button_ids:stokes_button_ids, stokes_spbutton_ids:stokes_spbutton_ids, $
    stokes_noise_button:stokes_noise_but, $
    stokes_mult_button_ids:stokes_mult_button_ids, $
    stokes_contpos_text:stokes_contpos_text, $
    specwin_button_ids:specwin_button_ids, $
    main_specwin_label:main_specwin_label, $
    ref_specwin_cbox:ref_specwin_cbox, ref_specwin_label:ref_specwin_label, $
		detspect_label:detspect_label, scale_detspect_but:scale_detspect_but, $
    detspect_imref_button_ids:detspect_imref_button_ids, $
    subtract_but:subtract_but, $		
		lower_y_text:lower_y_text, upper_y_text:upper_y_text, $	
    int_toggle_but:int_toggle_but, $
    displays_button_ids:displays_button_ids, refdisplays_button_ids:refdisplays_button_ids, $
    sjidisplays_button_ids:sjidisplays_button_ids, $  
    displays_ct_disp:displays_ct_disp, displays_ct_cbox:displays_ct_cbox, $
    scaling_cbox:scaling_cbox, imagescale_cbox:imagescale_cbox, $
    histo_opt_txt:histo_opt_txt, $
    gamma_label:gamma_label, gamma_slider:gamma_slider, scalemin_slider:scalemin_slider, $
    scalemax_slider:scalemax_slider, $
    scaling_reset_button:scaling_reset_but, scaling_reset_all_but:scaling_reset_all_but, $
    diagscale_label:diagscale_label, ls_mult_cbox:ls_mult_cbox, ls_mult_txt:ls_mult_txt, $
		phi_slider:phi_slid, nphi_slider:nphi_slid, loop_feedb_but:loop_feedb_but, $	
		loop_slit_but:loop_slit_but, rem_loop_pt_but:rem_loop_pt_but, loop_slice_but:loop_slice_but, $	
		overlay_but:overlay_but, loop_overlay_button_ids:loop_overlay_button_ids, $
    loop_linestyle_button_ids:loop_linestyle_button_ids, $
		measure_but:measure_but, apix_label:apix_label, apix_unit:apix_unit,$
    dx_text:dx_text, dy_text:dy_text, x_label:x_label, $
		measure_asec_lab:measure_asec_lab, measure_asec_text:measure_asec_text, $
		measure_km_lab:measure_km_lab, measure_km_text:measure_km_text, $					
		mask_button_ids:mask_button_ids, masks_overlay_ct_cbox:masks_overlay_ct_cbox, $
		masks_overlay_col_slid:masks_overlay_col_slid, $
    raster_label:raster_label, raster_button_ids:raster_button_ids,$
    raster_timing_label:raster_timing_label, $
    raster_timing_button_ids:raster_timing_button_ids,$
    dispwid:dispwid, clear_current_inst:clear_current_inst, $
		verbose_set:PTR_NEW([sh_verb_0,sh_verb_4,sh_verb_8,sh_verb_16]) $
	}
;------------------------- ABOUT WINDOW CONTROLS
  ctrlsabout = { $
    relnotes_button:0 $
  }
;------------------------- RETRIEVE LOOPS CONTROLS 
	ctrlsdet = { $
		sel_all:0, sel_none:0, disp_list:0, overlay_all:0, overlay_sel:0, all_pos:0, saved_pos:0, $
		sel_range_pos:0, save_imonly:0, save_refonly:0, save_imref:0, $
		dtmin_text:0, dtmax_text:0, dlpmin_text:0, dlpmax_text:0, refdlpmin_text:0, refdlpmax_text:0, $	
		width_slider:0, get_dets:0 $
	}
;------------------------- FEEDBACK CONTROLS
	ctrlsfeedb = { $
		estimate_label:0, feedback_text:0, close_button:0 $
	}
;------------------------- HEADER CONTROLS 
	ctrlshdr = { $
		header_select:0, header_txt:0 $
	}
;------------------------- INT CONTROLS 
	ctrlsint = { $
    sel_allnone_ids:[0,0], int_sel_save:0, lower_y_int_text:0, upper_y_int_text:0, $
    dg_box:0, lp_box:0, ls_box:0, cl_box:0, remove_button:0 $
	}
;------------------------- RETRIEVE DETECTIONS CONTROLS 
	ctrlsloop = { $
		get_loops:0, sel_all:0, sel_none:0, all_pos:0, saved_pos:0, del_files:0, keep_files:0, $
		save_imrefsji_ids:INTARR(3) $
	}
;------------------------- BMP BUTTON IMAGES
	ctrlspbbut = { $
		fbwd_pressed:bmpbut_fbwd_pressed, fbwd_idle:bmpbut_fbwd_idle, $
		bwd_pressed:bmpbut_bwd_pressed, bwd_idle:bmpbut_bwd_idle, $
		pause_pressed:bmpbut_pause_pressed, pause_idle:bmpbut_pause_idle, $
		fwd_pressed:bmpbut_fwd_pressed, fwd_idle:bmpbut_fwd_idle, $
		ffwd_pressed:bmpbut_ffwd_pressed, ffwd_idle:bmpbut_ffwd_idle, $
		loop_pressed:bmpbut_loop_pressed, loop_idle:bmpbut_loop_idle, $
		cycle_pressed:bmpbut_cycle_pressed, cycle_idle:bmpbut_cycle_idle, $
		blink_pressed:bmpbut_blink_pressed, blink_idle:bmpbut_blink_idle, $
    cursor_locked:bmpbut_cursor_lock, cursor_unlocked:bmpbut_cursor_unlock, $
    zoom_tofit_pressed:bmpbut_zoom_tofit_pressed, $
    zoom_tofit_idle:bmpbut_zoom_tofit_idle, $
    zoom_toscale_pressed:bmpbut_zoom_toscale_pressed, $
    zoom_toscale_idle:bmpbut_zoom_toscale_idle, $
    zoom_in_pressed:bmpbut_zoom_in_pressed, zoom_in_idle:bmpbut_zoom_in_idle, $
    zoom_out_pressed:bmpbut_zoom_out_pressed, $
    zoom_out_idle:bmpbut_zoom_out_idle, $
    zoom_goto_cursor_pressed:bmpbut_zoom_goto_curs_pressed, $
    zoom_goto_cursor_idle:bmpbut_zoom_goto_curs_idle, $
    zoom_pan_pressed:bmpbut_zoom_pan_pressed, $
    zoom_pan_idle:bmpbut_zoom_pan_idle, $
    zoom_select_pressed:bmpbut_zoom_select_pressed, $
    zoom_select_idle:bmpbut_zoom_select_idle $
	}
;------------------------- PARAMETER WINDOW REFERENCES
	ctrlsparam = { $
    xycoord_val:xycoord_val, xycoord_real_val:xycoord_real_val,  $
    refxycoord_val:refxycoord_val, refxycoord_real_val:refxycoord_real_val,  $
    sjixycoord_val:sjixycoord_val, sjixycoord_real_val:sjixycoord_real_val,  $
    lp_idx_val:lp_idx_val, lp_real_val:lp_real_val, lp_vdop_val:lp_vdop_val, $
    lp_ref_idx_val:lp_ref_idx_val, lp_ref_real_val:lp_ref_real_val, $
    lp_ref_vdop_val:lp_ref_vdop_val, $
    t_idx_val:t_idx_val, t_real_val:t_real_val, $ 
    t_raster_real_val:t_raster_real_val, $
    t_ref_idx_val:t_ref_idx_val, t_ref_real_val:t_ref_real_val, $
    t_raster_ref_real_val:t_raster_ref_real_val, $
    t_sji_idx_val:t_sji_idx_val, t_sji_real_val:t_sji_real_val, $
    dataval_real_val:dataval_real_val, dataval_ref_real_val:dataval_ref_real_val, $
    dataval_sji_real_val:dataval_sji_real_val, date_val:date_val, $
    zoom_val:zoom_val $
	}
;------------------------- PREFERENCE BUTTONS
	ctrlspref = { $
		startup_autopl:0, startup_win:0, displays_bgcols:0, displays_plcols:0, $
    displays_plthick:0, plthick_label:0, displays_interp:0, $
		displays_phislice:0, displays_slices:0, displays_offsets:0, $
    displays_overlays_symsize:0, displays_overlays_thick:0, $
    histo_opt_txt:0, gamma_slid:0, gamma_label:0,  $	
		paths_i_def_but:0, paths_i_sav_but:0, paths_ipath_text:0, $
		paths_o_def_but:0, paths_o_sav_but:0, paths_opath_text:0, $
		paths_i2opath:0, paths_o2ipath:0, save_defsaveid:0, save_defsaveid_sample:0, $
		set_defaults:0, warnings_cbox:0 $
	}
;------------------------- REFERENCE CONTROLS
	ctrlsref = { $
		xrefpos_slider:0, yrefpos_slider:0 $
	}
;------------------------- RESTORE LOOPS CONTROLS 
	ctrlsrestore = { $
		disp_list:0, sel_all:0, sel_none:0, open_tanat:0 $	
	}
;------------------------- SAVING CONTROLS 
	ctrlssav = { $
		path_textlab:0, savopt_path_textlab:0, overlays_num_but:0, overlays_curs_but:0, overlays_thick_slider:0, $
		overlays_pts_but:0, overlays_symsize_slider:0, overlays_asecbar_but:0, overlays_asecbar_slider:0 $
	}
;------------------------- SJI CONTROLS
	ctrlssji = { $
		xsjipos_slider:INTARR(hdr.nsjifiles_max), ysjipos_slider:INTARR(hdr.nsjifiles_max) $
	}
;------------------------- CONTROL SWITCHES
	ctrlsswitch = { $
		imrefdetspect:0, lp_ref_lock:lp_ref_lock, bwd_insensitive:1, $
    fwd_insensitive:1 $
	}
;------------------------- CURSOR 
	curs = { $
		sx:sx_start, sy:sy_start, sxlock:sx_start, sylock:sx_start, $		
    sxsji:sxsji_start, sysji:sysji_start, sxref:sxref_start, syref:syref_start,$
    sxreflock:sxref_start, syreflock:syref_start, xlock:x_start, ylock:y_start,$
    sxsjilock:sxsji_start, sysjilock:sysji_start, xsjilock:xsji_start, $
    ysjilock:ysji_start, xreflock:xref_start, yreflock:yref_start,  $
    image:cursim_default, mask:cursmk_default, lockset:0, $
    image_default:cursim_default, mask_default:cursmk_default, $
    mask_locked:cursmk_locked, $
    image_hand:cursim_hand, mask_hand:mask_hand, $
    image_grab:cursim_grab, mask_grab:mask_grab, $
    pan_init_x:0, pan_init_y:0, panselect:1B, pan_grab:0B $
	}
;------------------------- DATA 
	data = { $
    imagedata:hdr.imdata, xyslice:xyslice, refdata:hdr.refdata, $
    refslice:hdr.refslice, maskdata:hdr.maskdata, maskslice:maskslice, $
    dopslice:dopslice, spdata:hdr.spdata, $
    sspscan:sspscan, ssp_cur:PTRARR(hdr.imns), refspdata:hdr.refspdata, $
    refscan:hdr.refscan, refsspscan:hdr.refsspscan, refssp_cur:PTRARR(hdr.refns), $
    spslice:PTR_NEW(0), spslice_congrid:PTR_NEW(0), $
    refspslice:PTR_NEW(0), refspslice_congrid:PTR_NEW(0), $
		emptydopslice:emptydopslice, scan:hdr.scan, phiscan:phiscan, $
    phislice:phislice, sjidata:hdr.sjidata, sjislice:hdr.sjislice, $
		indexmap:indexmap, indices:indices, ratio:ratio, $
		lunsp:hdr.lunsp, lunim:hdr.lunim, lunrefim:hdr.lunrefim, $
    lunrefsp:hdr.lunrefsp, lunsji:hdr.lunsji, lunmask:hdr.lunmask $
	}
;------------------------- DATA PARAMETERS
	dataparams = { $    ; i.e., invariant
    ; Filenames
		imfilename:hdr.imfilename, spfilename:hdr.spfilename, $
    refimfilename:hdr.refimfilename, $
    refspfilename:hdr.refspfilename, maskfilename:hdr.maskfilename, $	
    sjifilename:hdr.sjifilename, $
    ; Headers, OBSID and DATE_OBS
    hdrs:hdr.hdrs, next:hdr.next, obsid:hdr.obsid, $
    date_obs_main:hdr.date_obs_main, date_obs_ref:hdr.date_obs_ref, $
    date_obs_sji:hdr.date_obs_sji, $
    startobs_main:hdr.startobs_main, startobs_ref:hdr.startobs_ref, $
    startobs_sji:hdr.startobs_sji, $
    ; Spatial dimensions
		x:DOUBLE(x_start), y:DOUBLE(y_start), d_nx:hdr.nx-1, d_ny:hdr.ny-1, $
    nx:hdr.nx, ny:hdr.ny, $
    sjinx:hdr.sjinx, sjiny:hdr.sjiny, sjidx:hdr.sjidx, sjidy:hdr.sjidy, $
    refnx:hdr.refnx, refny:hdr.refny, refdx:hdr.refdx, refdy:hdr.refdy, $
    d_refnx:hdr.refnx-1, d_refny:hdr.refny-1, $
    d_sjinx:hdr.sjinx-1, d_sjiny:hdr.sjiny-1, $
    xval:hdr.xval, yval:hdr.yval, xval_ref:hdr.xval_ref, yval_ref:hdr.yval_ref,$
    xval_sji:hdr.xval_sji, yval_sji:hdr.yval_sji, $
    xpix:hdr.xpix, ypix:hdr.ypix, xpix_ref:hdr.xpix_ref, ypix_ref:hdr.ypix_ref,$
    xpix_sji:hdr.xpix_sji, ypix_sji:hdr.ypix_sji, $
    xyoffset_sji:hdr.xyoffset_sji, $
    pix_main2ref:PTR_NEW(hdr.pix_main2ref), pix_ref2main:PTR_NEW(hdr.pix_ref2main), $
    pix_main2sji:hdr.pix_main2sji, pix_sji2main:hdr.pix_sji2main, $
    pix_ref2sji:hdr.pix_ref2sji, pix_sji2ref:hdr.pix_sji2ref, $
    pix_sji2sji:hdr.pix_sji2sji, $
    wcs_main:hdr.wcs_main, wcs_ref:PTR_NEW(hdr.wcs_ref), $
    wcs_sji:hdr.wcs_sji, $
    xref:DOUBLE(xref_start), yref:DOUBLE(yref_start), $
    xsji:DOUBLE(xsji_start), ysji:DOUBLE(ysji_start), $
    tarr_full_main:hdr.tarr_full_main, utc_full_main:hdr.utc_full_main, $
    date_full_main:hdr.date_full_main, tfull_dims_main:hdr.tfull_dims_main, $
    tarr_full_ref:hdr.tarr_full_ref, utc_full_ref:hdr.utc_full_ref, $
    date_full_ref:hdr.date_full_ref, tfull_dims_ref:hdr.tfull_dims_ref, $
    tarr_sji:hdr.tarr_sji, utc_sji:hdr.utc_sji, $
    date_sji:hdr.date_sji, $
    ; Spectral parameters
		lc:hdr.lc, lp:lp_start, lp_ref:lp_ref_start, lp_dop:lp_start, nlp:hdr.nlp,$
    refnlp:hdr.refnlp, ns:hdr.ns, s:0L, refns:hdr.refns, s_ref:0L, $					
		lps:hdr.lps, ms:hdr.ms, ms_orig:hdr.ms, spec:hdr.mainspec, $
    spec_orig:hdr.mainspec, $
		reflps:hdr.reflps, refms:hdr.refms, refms_orig:hdr.refms, refspec:hdr.refspec, $
    refspec_orig:hdr.refspec, $
    ; Doppler boundaries
    v_dop_low_min:hdr.v_dop_low_min, v_dop_low_max:hdr.v_dop_low_max,  $
    v_dop_upp_min:hdr.v_dop_upp_min, v_dop_upp_max:hdr.v_dop_upp_max,  $
    v_dop_ref_low_min:hdr.v_dop_ref_low_min, v_dop_ref_low_max:hdr.v_dop_ref_low_max,  $
    v_dop_ref_upp_min:hdr.v_dop_ref_upp_min, v_dop_ref_upp_max:hdr.v_dop_ref_upp_max,  $
    ; Time parameters
		nt:hdr.mainnt, mainnt:hdr.mainnt, refnt:hdr.refnt, masknt:hdr.masknt, $
    sjint:hdr.sjint, sji_labels:sji_labels, $		
    default_toffset_main:hdr.toffset_main, default_toffset_ref:hdr.toffset_ref, $
    dx:hdr.dx, dy:hdr.dy, pixelratio:pixelratio, refpixelratio:refpixelratio, $
    sjipixelratio:sjipixelratio, $
    bunit:[hdr.bunit,hdr.refbunit,hdr.sjibunit], $
    lpunit:[hdr.lpunit,hdr.reflpunit], $
    xunit:hdr.xunit, yunit:hdr.yunit, tunit:hdr.tunit, $
    nsjifiles:hdr.nsjifiles, nsjifiles_max:hdr.nsjifiles_max $
	}
;------------------------- DATA SWITCH
	dataswitch = { $
		onecube:hdr.onecube, reffile:hdr.showref, refspfile:hdr.refspfile, spfile:hdr.spfile, $
    maskfile:hdr.maskfile, sjifile:hdr.sjifile, wcs_set:hdr.wcs_set, ref_wcs_set:hdr.ref_wcs_set, $
    sji_wcs_set:hdr.sji_wcs_set $
	}
;------------------------- DET PARAMS
	detparams = { $
		nr_dets:0, sel_dets:PTR_NEW(INTARR(nphi*3)), t:PTR_NEW(0), $
		detfilename:'', idx:0, nr_sel_loops:0, sel_loops:PTR_NEW(INTARR(nphi)), $
    overlay_dets:PTR_NEW(0), $
		xlr:PTR_NEW(0), ylr:PTR_NEW(0), xlp:PTR_NEW(0), ylp:PTR_NEW(0), $	
		width:0, mid:0, delta_t_dn:10, delta_t_up:10, lp_dn:lp_first, lp_up:lp_last, $					
		lp_ref_dn:lp_ref_first, lp_ref_up:lp_ref_last, $
    w_lpts:PTR_NEW(0), ngaps:0, databounds:PTR_NEW(0), wdatabounds:PTR_NEW(0) $
	}
;------------------------- DATA DISPLAY PARAMETERS
	dispparams = { $    ; i.e., variable, in contrast to dataparams
		t_first:t_first, t_last:t_last, t_range:hdr.mainnt, t_low:t_first, t_upp:t_last, $	
		x_first:x_first, x_last:x_last, y_first:y_first, y_last:y_last, $				
		lp_first:lp_first, lp_last:lp_last, lp_range:hdr.nlp, lp_low:lp_first, lp_upp:lp_last, $
		lp_ref_first:lp_ref_first, lp_ref_last:lp_ref_last, lp_ref_low:lp_ref_first, $
    lp_ref_upp:(hdr.refnlp-1), lp_ref_range:hdr.refnlp, $
    v_dop_incr:[hdr.v_dop_incr[0], hdr.v_dop_ref_incr[0]], $
    v_dop_low:hdr.v_dop_low_min, v_dop_upp:hdr.v_dop_upp_max,  $
    v_dop_ref_low:hdr.v_dop_ref_low_min, v_dop_ref_upp:hdr.v_dop_ref_upp_max,  $
    lp_low_tmp:REPLICATE(0,hdr.ndiagnostics), lp_upp_tmp:hdr.diag_width-1, $
    lp_low_bounds:hdr.diag_start, $
    lp_upp_bounds:hdr.diag_start+(hdr.diag_width-1), $
    lp_ref_low_tmp:REPLICATE(0,hdr.nrefdiagnostics), $
    lp_ref_upp_tmp:hdr.refdiag_width-1, $
    lp_ref_low_bounds:hdr.refdiag_start, $
    lp_ref_upp_bounds:hdr.refdiag_start+(hdr.refdiag_width-1), $
		nlpreb:nlpreb, ntreb:ntreb, refnlpreb:nlpreb, refntreb:refntreb, $
    refloopnlxreb:nlpreb, refloopntreb:loopntreb, $
    sjiloopnlxreb:nlpreb, sjiloopntreb:loopntreb, $
		loopnlxreb:nlpreb, loopntreb:loopntreb, restloopnlxreb:nlpreb, restloopntreb:loopntreb, $
		retrdetnlxreb:nlpreb, retrdetntreb:loopntreb, phisnlpreb:nlpreb, nphireb:nphireb, $					
    xytri:hdr.xytri, xytri_ref:hdr.xytri_ref, $
    phisxytri:PTRARR(2,hdr.ndiagnostics, /ALLOCATE_HEAP), $
    xsji_first:REPLICATE(0L,hdr.nsjifiles_max), xsji_last:(hdr.sjinx-1), $
    ysji_first:REPLICATE(0L,hdr.nsjifiles_max), ysji_last:(hdr.sjiny-1),  $
    xref_first:xref_first, xref_last:xref_last, $
    yref_first:yref_first, yref_last:yref_last, $
		interpspslice:interpspslice, phislice_update:phislice_update, slices_imscale:slices_imscale, $
    tsel_main:PTR_NEW(hdr.tsel_main), tsel_ref:PTR_NEW(hdr.tsel_ref), $
    tsel_sji:hdr.tsel_sji, master_time:0, $
    tarr_main:PTR_NEW(hdr.tarr_main[hdr.tsel_main]), $
    tarr_ref:PTR_NEW(hdr.tarr_ref[hdr.tsel_ref]), $
    tarr_sji:disp_tarr_sji, $
    utc_main:PTR_NEW(hdr.utc_main[hdr.tsel_main]), $
    utc_ref:PTR_NEW(hdr.utc_ref[hdr.tsel_ref]), $
    utc_sji:disp_utc_sji, $
    date_arr:PTR_NEW(hdr.date_main[hdr.tsel_main]), $
    t:t_start, t_main:hdr.tsel_main[0], t_ref:hdr.tsel_ref[0],$
    t_sji:t_sji, $  
    t_low_main:hdr.tarr_main[0], t_upp_main:hdr.tarr_main[(hdr.mainnt-1)>0], $
    t_low_ref:hdr.tarr_ref[0], t_upp_ref:hdr.tarr_ref[(hdr.refnt-1)>0], $
    t_low_sji:t_low_sji, t_upp_sji:t_upp_sji, $
    toffset_main:hdr.toffset_main, toffset_ref:hdr.toffset_ref, $
    imbscale:hdr.imbscale, imbzero:hdr.imbzero, $
    spbscale:hdr.spbscale, spbzero:hdr.spbzero, $
    refimbscale:hdr.refimbscale, refimbzero:hdr.refimbzero, $
    refspbscale:hdr.refspbscale, refspbzero:hdr.refspbzero, $
    sjibscale:hdr.sjibscale, sjibzero:hdr.sjibzero, $
    x_main:x_main, y_main:y_main, x_ref:x_ref, y_ref:y_ref, $
    x_old:DOUBLE(x_start), y_old:DOUBLE(y_start), $
    xref_old:DOUBLE(xref_start), yref_old:DOUBLE(yref_start), $
    xsji_old:DOUBLE(xsji_start), ysji_old:DOUBLE(ysji_start), $
    lp_old:lp_start, lp_ref_old:lp_ref_start, $
    s_old:0L, s_ref_old:0L, $
    t_main_old:hdr.tsel_main[0], t_ref_old:hdr.tsel_ref[0], $
    t_sji_old:t_sji_old, $  
    date_old:hdr.date_main[hdr.tsel_main[0]], $
    xy_out_of_range_old:0, xyref_out_of_range_old:xyref_out_of_range $
	}
;------------------------- DATA DISPLAY SWITCHES
	dispswitch = { $
		restricted_t_range:PTR_NEW(0), restricted_lp_range:PTR_NEW(0), $
    restricted_lp_ref_range:PTR_NEW(0), exts:exts_set, refexts:refexts_set, $
    lp_restrict:[1B,0B], lp_restrict_globloc:[0B,0B], scalestokes:scalestokes, $
    sji_select:0, $
    warpspslice:hdr.warpspslice, warprefspslice:hdr.warprefspslice, $
		detspect_scale:detspect_scale, ref_detspect_scale:ref_detspect_scale, $
    drawdop:0, sjiscaled:hdr.sjiscaled, main2ref_no_map:hdr.main2ref_no_map, $
    imscaled:hdr.imscaled, spscaled:hdr.spscaled, $
    refimscaled:hdr.refimscaled, refspscaled:hdr.refspscaled, $
    xy_out_of_range:0, xyref_out_of_range:xyref_out_of_range, $
    xysji_out_of_range:xysji_out_of_range $
	}
;------------------------- FEEDBACK PARAMS
	feedbparams = { $
		estimate_lx:estimate_lx, estimate_time:estimate_time, $
    estimate_run:estimate_run, startup_im:startup_im, xout:xout, yout:yout, $
    relnotes:0, verbosity:verbosity, last_routine:'', last_routine_count:0, $
		pbstats:DOUBLE(SYSTIME(/SECONDS)), sum_pbstats:PTR_NEW(DBLARR(10)), $
    av_pbstats:0D, count_pbstats:0 $	
	}
;------------------------- INT PARAMS
	intparams = { $
		sel_diagnostics:PTR_NEW(hdr.sel_diagnostics), $ 
    seldisp_diagnostics:PTR_NEW(REPLICATE(1B,N_ELEMENTS(hdr.sel_diagnostics))), $
	  linlab_diagnostics:['Solid', 'Dotted', 'Dashed', 'Dash Dot', 'Dash Dot Dot', 'Long Dashes'],$
    sellines_diagnostics:PTR_NEW(hdr.sellines_diagnostics), $
	  colors_diagnostics:[0,200,135,120,100,90,230,40],$
	  collab_diagnostics:['Black', 'Red', 'Pink', 'Purple', 'Blue', 'Turquoise', 'Grey', 'Green'],$
    selcol_diagnostics:PTR_NEW(hdr.selcol_diagnostics), $
    sellp_diagnostics:PTR_NEW(hdr.sellp_diagnostics), $
    disp_diagnostics:REPLICATE(1,hdr.ndiagnostics), $
    ndisp_diagnostics:hdr.ndiagnostics, $
    disp_refdiagnostics:REPLICATE(1,hdr.nrefdiagnostics), $
    ndisp_refdiagnostics:hdr.nrefdiagnostics, $
		diagnostics:hdr.diagnostics, ndiagnostics:hdr.ndiagnostics, lock_t:1, $ 
    diag_start:hdr.diag_start, diag_width:hdr.diag_width, $
    diag_starts:PTR_NEW(hdr.diag_start), diag_widths:PTR_NEW(hdr.diag_width), $
    wheredispdiag:PTR_NEW(LONARR(hdr.ndiagnostics)), $
    refdiagnostics:hdr.refdiagnostics, $                   
    nrefdiagnostics:hdr.nrefdiagnostics, $
    refdiag_start:hdr.refdiag_start, $   
    refdiag_width:hdr.refdiag_width, $   
    refdiag_starts:PTR_NEW(hdr.refdiag_start), $
    refdiag_widths:PTR_NEW(hdr.refdiag_width), $
    wheredisprefdiag:PTR_NEW(LONARR(hdr.nrefdiagnostics)), $
    lp_diag_all:0, lp_ref_diag_all:0, $
    singlewav_windows:singlewav_windows,$
    refsinglewav_windows:refsinglewav_windows $
	}
;------------------------- I/O PARAMS
	ioparams = { $
		hdr:PTR_NEW(hdr) $
  }
;------------------------- LOOP PARAMS
	loopparams = { $
		xp:xp, yp:yp, xr:PTR_NEW(FLTARR(nphi)), yr:PTR_NEW(FLTARR(nphi)), np:0, $			
		xpdisp:xp, ypdisp:yp, xrdisp:PTR_NEW(FLTARR(nphi)), $
    yrdisp:PTR_NEW(FLTARR(nphi)), $
    npdisp:0, ngaps:0L, databounds:PTR_NEW(0L), wdatabounds:PTR_NEW(0L), $
		w_lpts:PTR_NEW(BYTARR(nphi)), nw_lpts:0, $						
    xp_ref:PTR_NEW(0), yp_ref:PTR_NEW(0), xr_ref:PTR_NEW(0.), $
    yr_ref:PTR_NEW(0.), np_ref:0, w_lpts_ref:PTR_NEW(0), nw_lpts_ref:0, $
		xpdisp_ref:PTR_NEW(0), ypdisp_ref:PTR_NEW(0), xrdisp_ref:PTR_NEW(0.), $
    yrdisp_ref:PTR_NEW(0.), $
    npdisp_ref:0, ngaps_ref:0L, databounds_ref:PTR_NEW(0L), $
    wdatabounds_ref:PTR_NEW(0L), $
    xp_sji:PTRARR(hdr.nsjifiles_max,/ALLOCATE_HEAP), $
    yp_sji:PTRARR(hdr.nsjifiles_max,/ALLOCATE_HEAP), $
    xr_sji:PTRARR(hdr.nsjifiles_max,/ALLOCATE_HEAP), $
    yr_sji:PTRARR(hdr.nsjifiles_max,/ALLOCATE_HEAP), $
    w_lpts_sji:PTRARR(hdr.nsjifiles_max,/ALLOCATE_HEAP), $
		xpdisp_sji:PTRARR(hdr.nsjifiles_max,/ALLOCATE_HEAP), $
    ypdisp_sji:PTRARR(hdr.nsjifiles_max,/ALLOCATE_HEAP), $
    xrdisp_sji:PTRARR(hdr.nsjifiles_max,/ALLOCATE_HEAP), $
    yrdisp_sji:PTRARR(hdr.nsjifiles_max,/ALLOCATE_HEAP), $
    np_sji:0, nw_lpts_sji:INTARR(hdr.nsjifiles_max), $
    npdisp_sji:INTARR(hdr.nsjifiles_max), ngaps_sji:LONARR(hdr.nsjifiles_max), $
    databounds_sji:PTRARR(hdr.nsjifiles_max,/ALLOCATE_HEAP), $
    wdatabounds_sji:PTRARR(hdr.nsjifiles_max,/ALLOCATE_HEAP) $
	}
;------------------------- LOOPS DATA
	loopsdata = { $
		loopsize:0, rest_loopsize:PTR_NEW(INTARR(10)), exact_loopsize:0, det_loopsize:0, $				
		crossloc:PTR_NEW(0), rest_crossloc:rest_crossloc, exact_crossloc:exact_crossloc, $		
		det_crossloc:det_crossloc, $
		loopslab:loopslab, loopslice:loopslice, $			
		refloopsize:0, refloopslab:refloopslab, refloopslice:refloopslice, $			
    sjiloopsize:INTARR(hdr.nsjifiles_max), sjiloopslice:sjiloopslice, $
    refcrossloc:PTR_NEW(0), sjicrossloc:PTRARR(hdr.nsjifiles_max,/ALLOCATE_HEAP), $
		rest_loopslab:rest_loopslab, rest_loopslice:rest_loopslice, $
		exact_loopslab:exact_loopslab, exact_loopslice:exact_loopslice, $	
		det_loopslab:det_loopslab, det_loopslice:det_loopslice, $	
    empty_slice:PTR_NEW(INTARR(10,10)), $
    empty_refslice:PTR_NEW(INTARR(10,10)), $
    empty_sjislice:PTR_NEW(INTARR(10,10)), $
    rest_empty_slice:PTR_NEW(INTARR(10,10)), $
    det_empty_slice:PTR_NEW(INTARR(10,10)) $
	}
;------------------------- LOOPS SWITCHES
	loopswitch = { $
		retrieve_loops:0, restore_loops:0, was_restore_loops:0, retrieve_detfile:0 $		
	}
;------------------------- MEASUREMENT
	meas = { $
		spatial_measurement:0, np:0, $					
		xp:PTR_NEW(0), yp:PTR_NEW(0), sxp:PTR_NEW(0), syp:PTR_NEW(0), $					
		xp_ref:PTR_NEW(0), yp_ref:PTR_NEW(0), sxp_ref:PTR_NEW(0), syp_ref:PTR_NEW(0), $					
		xp_sji:PTRARR(hdr.nsjifiles_max, /ALLOCATE_HEAP), $
    yp_sji:PTRARR(hdr.nsjifiles_max, /ALLOCATE_HEAP), $
    sxp_sji:PTRARR(hdr.nsjifiles_max, /ALLOCATE_HEAP), $
    syp_sji:PTRARR(hdr.nsjifiles_max, /ALLOCATE_HEAP) $					
	}
;------------------------- OVERLAY PARAMS
	overlayparams = { $
		sxp:sxp, syp:syp, sxr:PTR_NEW(FLTARR(nphi)), syr:PTR_NEW(FLTARR(nphi)), $
    sxp_ref:PTR_NEW(0.), syp_ref:PTR_NEW(0.), $
    sxr_ref:PTR_NEW(0.), syr_ref:PTR_NEW(0.), $
    sx_pts:PTR_NEW(0.), sy_pts:PTR_NEW(0.),$
    sx_pts_ref:PTR_NEW(0.), sy_pts_ref:PTR_NEW(0.),$
    sxp_sji:PTRARR(hdr.nsjifiles_max,/ALLOCATE_HEAP), $
    syp_sji:PTRARR(hdr.nsjifiles_max,/ALLOCATE_HEAP), $
    sxr_sji:PTRARR(hdr.nsjifiles_max,/ALLOCATE_HEAP), $
    syr_sji:PTRARR(hdr.nsjifiles_max,/ALLOCATE_HEAP), $
    sx_pts_sji:PTRARR(hdr.nsjifiles_max,/ALLOCATE_HEAP), $
    sy_pts_sji:PTRARR(hdr.nsjifiles_max,/ALLOCATE_HEAP),$
    symsize:overlays_symsize, thick:overlays_thick, $
    loop_linestyle:0, maskcolor:255, maskct:maskct $				
	}
;------------------------- OVERLAY SWITCHES
	overlayswitch = { $
		det_overlay_all:0, loopslit:0, overlalways:1, looppath_feedback:1, $
    mask:hdr.maskfile, maskim:[hdr.maskfile,(hdr.maskfile AND hdr.showref),0], $
    sjiraster:(hdr.sjifile AND (is_raster[0] OR (hdr.nx EQ 1))), $
    refraster:(hdr.showref AND (is_raster[0] OR (hdr.nx EQ 1))), $		
    rastertiming:REPLICATE(hdr.update_tfull_main[0],3) $
	}
;------------------------- PARAMETER WINDOW CONTROLS 
	paramparams = { $
		wav_h:wav_h, sp_h:sp_h, scale_cubes:scale_cubes_vals, $
    xcoord_format:xcoord_format, ycoord_format:ycoord_format, $
    xcoord_real_format:xcoord_real_format, ycoord_real_format:ycoord_real_format, $
    refxcoord_format:refxcoord_format, refycoord_format:refycoord_format, $
    refxcoord_real_format:refxcoord_real_format, $
    refycoord_real_format:refycoord_real_format, $
    sjixcoord_format:sjixcoord_format, sjiycoord_format:sjiycoord_format, $
    sjixcoord_real_format:sjixcoord_real_format, $
    sjiycoord_real_format:sjiycoord_real_format, $
    lp_idx_format:lp_idx_format, lp_real_format:lp_real_format, $
    lp_vdop_format:lp_vdop_format, $
    lp_ref_idx_format:lp_ref_idx_format, lp_ref_real_format:lp_ref_real_format, $
    lp_ref_vdop_format:lp_ref_vdop_format, $
    t_idx_format:t_idx_format, t_real_format:t_real_format, $
    t_raster_real_format:t_raster_real_format, $
    t_ref_idx_format:t_ref_idx_format, t_ref_real_format:t_ref_real_format, $
    t_raster_ref_real_format:t_raster_ref_real_format, $
    t_sji_idx_format:t_sji_idx_format, t_sji_real_format:t_sji_real_format $
	}
;------------------------- PARAM SWITCHES
	paramswitch = { $
    dt_set:dt_set, t_raster:raster_time_fb, t_raster_ref:refraster_time_fb, $ 
    update_tfull_main:hdr.update_tfull_main, $
    update_tfull_ref:hdr.update_tfull_ref $
	}
;------------------------- PATHS AND DIRECTORIES
	paths = { $
		ipath:ipath, opath:opath, opath_write:opath_write, hostname:hostname, $
    dir_settings:dir_settings, dir_settings_write:dir_settings_write, $
	  dir_resources:dir_resources, dir_aux:dir_aux, dir_tanat:dir_aux, $
    tanat_repointed:0 $
	}
;------------------------- PLAYBACK
	pbparams = { $
		t_step:t_step, t_speed:t_speed, direction:direction, bg:bg, mode:'PAUSE', lmode:'LOOP', $				
		imrefmode:0, lp_blink:lp_start, lp_blink_init:lp_start, spmode:0, spdirection:1 $						
	}
;------------------------- PHI SLIT VARIABLES 
	phiparams = { $
		d_nphi_set:nphi, nphi:nphi, angle:angle, nphi_set:LONG(hdr.ny/3.)-1, sphi:0, $
		x_pts:PTR_NEW(0.), y_pts:PTR_NEW(0.), $
    x_pts_ref:PTR_NEW(0.), y_pts_ref:PTR_NEW(0.), $
    x_pts_sji:PTRARR(hdr.nsjifiles_max,/ALLOCATE_HEAP),$
    y_pts_sji:PTRARR(hdr.nsjifiles_max,/ALLOCATE_HEAP),$
    nw_cur:LONG(hdr.ny/3.), curindex:0, maxindex:0 $				
	}
;------------------------- PLOTAXES
	plotaxes = { $
		ticklen:ticklen, lsxticklen:lsxticklen, lsyticklen:lsyticklen, $
		reflsxticklen:reflsxticklen, reflsyticklen:reflsyticklen, $
		spxticklen:spxticklen, spyticklen:spyticklen, $
		refspxticklen:spxticklen, refspyticklen:spyticklen, $
		phisxticklen:phisxticklen, phisyticklen:phisyticklen, $
		loopxticklen:spxticklen, loopyticklen:spyticklen, $
		refloopxticklen:spxticklen, refloopyticklen:spyticklen, $
		sjiloopxticklen:spxticklen, sjiloopyticklen:spyticklen, $
		restloopxticklen:spxticklen, restloopyticklen:spyticklen, $
		retrdetxticklen:spxticklen, retrdetyticklen:spyticklen, $
		intxticklen:intxticklen, intyticklen:intyticklen, $
    xtickinterval:PTR_NEW(0.), xdoptickinterval:PTR_NEW(0.), $
    xtickvals:PTRARR(hdr.ndiagnostics), $ 
    xdoptickvals:PTRARR(hdr.ndiagnostics), xdoptickloc:PTRARR(hdr.ndiagnostics), $
    xreftickinterval:PTR_NEW(0.), xrefdoptickinterval:PTR_NEW(0.), $
    xreftickvals:PTRARR(hdr.nrefdiagnostics), $ 
    xrefdoptickvals:PTRARR(hdr.nrefdiagnostics), $
    xrefdoptickloc:PTRARR(hdr.nrefdiagnostics), $
    ;ticknames
    lsxticknames:lsplotaxes.xticknames, lsyticknames:lsplotaxes.yticknames, $
    lsdopxticknames:lsdopxticknames, $
    reflsxticknames:reflsplotaxes.xticknames, reflsyticknames:reflsplotaxes.yticknames, $
    reflsdopxticknames:reflsdopxticknames, $
		ls_low_y:hdr.ls_low_y, ls_upp_y:hdr.ls_upp_y, ls_yrange:hdr.ls_yrange, $		
		ls_low_y_ref:hdr.ls_low_y_ref, ls_upp_y_ref:hdr.ls_upp_y_ref, $
    ls_yrange_ref:hdr.ls_yrange_ref, $
		int_low_y:hdr.int_low_y, int_upp_y:hdr.int_upp_y, int_low_t:t_first, int_upp_t:t_last, $
		dt:hdr.dt, v_dop:hdr.v_dop, v_dop_ref:hdr.v_dop_ref, $		
    diag_ratio:PTR_NEW(hdr.diag_width/FLOAT(hdr.diag_width)), $
    diag_range_sp:PTR_NEW((hdr.diag_width/FLOAT(TOTAL(hdr.diag_width)))*xplspw), $
    refdiag_ratio:PTR_NEW(hdr.refdiag_width/FLOAT(hdr.refdiag_width)), $
    refdiag_range_sp:PTR_NEW((hdr.refdiag_width/FLOAT(TOTAL(hdr.refdiag_width)))*xplspw), $
    diag_range_phis:PTR_NEW((hdr.diag_width/FLOAT(TOTAL(hdr.diag_width)))*phisxplspw), $
    phis_yrange:[-1.,1.] $
	}
;------------------------- PLOT PARAMETERS
	plotparams = { $
		bgplotcol:bgplotcol, plotcol:plotcol, plotthick:plotthick, $
    ct_idl_names:ct_idl_names, ct_iris_names:ct_iris_names, $
    ct_sdo_names:ct_sdo_names, ct_names:ct_names, $
    rgb_main:rgb_main, rgb_ref:rgb_ref, rgb_dop:rgb_dop, $
    rgb_sji:rgb_sji, imct:imct, imct_select:1 $
	}
;------------------------- PLOT POSITION
	plotpos = { $
		lsx0:lsx0, lsy0:lsy0, lsx1:lsx1, lsy1:lsy1, $
		reflsx0:reflsx0, reflsy0:reflsy0, reflsx1:reflsx1, reflsy1:reflsy1, $
		lsx0_all:lsx0_all, lsy0_all:lsy0_all, lsx1_all:lsx1_all, lsy1_all:lsy1_all, $
		reflsx0_all:reflsx0_all, reflsy0_all:reflsy0_all, $
    reflsx1_all:reflsx1_all, reflsy1_all:reflsy1_all, $
		spx0:spx0, spy0:spy0, spx1:spx1, spy1:spy1, $							
		refspx0:spx0, refspy0:refspy0, refspx1:spx1, refspy1:refspy1, $
		phisx0:phisx0, phisx1:phisx1, phisy0:phisy0, phisy1:phisy1, $
		loopx0:spx0, loopx1:spx1, loopy0:spy0, loopy1:loopy1, $
		refloopx0:spx0, refloopx1:spx1, refloopy0:spy0, refloopy1:loopy1, $
		sjiloopx0:spx0, sjiloopx1:spx1, sjiloopy0:spy0, sjiloopy1:loopy1, $
		restloopx0:spx0, restloopx1:spx1, restloopy0:spy0, restloopy1:loopy1, $
		retrdetx0:spx0, retrdetx1:spx1, retrdety0:spy0, retrdety1:loopy1, $
		intx0:intx0, intx1:intx1, inty0:inty0, inty1:inty1, $
		xplspw:xplspw, yplspw:yplspw, refxplspw:xplspw, refyplspw:refyplspw, $		
		phisxplspw:phisxplspw, phisyplspw:phisyplspw, loopxplspw:xplspw, loopyplspw:loopyplspw, $
		refloopxplspw:xplspw, refloopyplspw:loopyplspw, $
		sjiloopxplspw:xplspw, sjiloopyplspw:loopyplspw, $
    restloopxplspw:xplspw, restloopyplspw:loopyplspw, $
		retrdetxplspw:xplspw, retrdetyplspw:loopyplspw, $
		lsxmargin_init:lsxmargin_init, lsxwall_init:lsxwall_init, $
		reflsxmargin_init:lsxmargin_init, reflsxwall_init:lsxwall_init, $
		sjilsxmargin_init:lsxmargin_init, sjilsxwall_init:lsxwall_init, $
		spxmargin_init:spxmargin_init, spxwall_init:spxwall_init, $
		refspxmargin_init:spxmargin_init, refspxwall_init:spxwall_init, $
		sjispxmargin_init:spxmargin_init, sjispxwall_init:spxwall_init, $
		phisxmargin_init:spxmargin_init, phisxwall_init:spxwall_init, $
		loopxmargin_init:spxmargin_init, loopxwall_init:spxwall_init, $
		refloopxmargin_init:spxmargin_init, refloopxwall_init:spxwall_init, $
		sjiloopxmargin_init:spxmargin_init, sjiloopxwall_init:spxwall_init, $
		restloopxmargin_init:spxmargin_init, restloopxwall_init:spxwall_init, $
		retrdetxmargin_init:spxmargin_init, retrdetxwall_init:spxwall_init, $
		intxmargin_init:intxmargin_init, intxwall_init:intxwall_init $
	}
;------------------------- PLOT SWITCHES
	plotswitch = { $
		heightset:heightset, refheightset:refheightset, $
    multichannel:hdr.multichannel, refmultichannel:hdr.refmultichannel, $
		v_dop_set:hdr.v_dop_set[0], v_dop_set_ref:hdr.v_dop_set[1], $
    iris_lct_exist:iris_lct_exist, aia_lct_exist:aia_lct_exist, $
    subtract:0, ref_subtract:0, noise:(hdr.ns GT 1), ref_noise:(hdr.refns GT 1), $				
    xtick_reset:1, xdoptick_reset:1, xreftick_reset:1, xrefdoptick_reset:1 $
	}
;------------------------- PLOT TITLES
	plottitles = { $
		spxtitle:hdr.spxtitle, spytitle:spytitle, spwintitle:spwintitle, $
		refspxtitle:hdr.refspxtitle, refspwintitle:refspwintitle, $
		lsytitle:lsytitle, reflsytitle:reflsytitle, $
		lsxtitles:lsplotaxes.xtitles, reflsxtitles:reflsplotaxes.xtitles, $
		lsytitles:lsplotaxes.ytitles, reflsytitles:reflsplotaxes.ytitles, $
		lsdopxtitles:lsdopxtitles, reflsdopxtitles:reflsdopxtitles, $
    lsdopxtitle:lsdopxtitle, $
		lswintitle:lswintitle, reflswintitle:reflswintitle, phiswintitle:phiswintitle $
	}
;------------------------- PREFERENCE SETTINGS
	prefs = { $
		autoplay:autoplay, startupwin:startupwin, defsaveid:defsaveid,  $
		defipath:defipath, prefipath:prefipath, defopath:defopath, prefopath:prefopath, $
		bgplotcol_old:bgplotcol, plotcol_old:plotcol, interpspslice_old:interpspslice, $
    overlays_symsize_old:overlays_symsize, overlays_thick_old:overlays_thick, $
		slices_imscale_old:slices_imscale, histo_opt_val:histo_opt_val, $
    gamma_val:gamma_val, plotthick:plotthick, plotthick_old:plotthick, $
    overlays_symsize:overlays_symsize, overlays_thick:overlays_thick, $
    warnings:warnings, current_offsets:window_offsets.set, $
		tmp_autoplay:autoplay, tmp_startupwin:startupwin, tmp_defsaveid:defsaveid, $
		tmp_bgplotcol:bgplotcol, tmp_plotcol:plotcol, tmp_defipath:defipath, tmp_prefipath:prefipath, $
		tmp_defopath:defopath, tmp_prefopath:prefopath, tmp_interpspslice:interpspslice, $
		tmp_phislice_update:phislice_update, tmp_slices_imscale:slices_imscale, $								
    tmp_histo_opt_val:histo_opt_val, tmp_gamma_val:gamma_val, tmp_warnings:warnings, $
    tmp_plotthick:plotthick, tmp_overlays_symsize:overlays_symsize, $
    tmp_overlays_thick:overlays_thick, $
		default_autoplay:default_autoplay, default_startupwin:default_startupwin, $
		default_bgplotcol:default_bgplotcol, default_plotcol:default_plotcol, $
    default_plotthick:default_plotthick, $
    default_overlays_symsize:default_overlays_symsize, $
    default_overlays_thick:default_overlays_thick, $
		default_defipath:default_defipath, default_prefipath:default_prefipath, $
		default_defopath:default_defopath, default_prefopath:default_prefopath, $
		default_defsaveid:default_defsaveid, default_interpspslice:default_interpspslice, $
		default_phislice_update:default_phislice_update, default_slices_imscale:default_slices_imscale, $
    default_histo_opt_val:default_histo_opt_val, default_gamma_val:default_gamma_val, $
		default_warnings:default_warnings, preview:0 $					
	}
;------------------------- RESTORED LOOPS PARAMS
	restoreparams = { $
		cfilecount:0, cfiles:PTR_NEW(STRARR(nphi)), sel_loops:PTR_NEW(INTARR(nphi)), $		
		xr:PTR_NEW(0), yr:PTR_NEW(0), $
    xp:PTR_NEW(0), yp:PTR_NEW(0), $
    imref:PTR_NEW(0), lp:PTR_NEW(0), $
		disp_loopfile:'0', disp_loopnr:PTR_NEW(-1), disp_imref:PTR_NEW(-1), disp_slices:PTR_NEW(0), $
		disp_ref_slices:PTR_NEW(0), $
    ngaps:PTR_NEW(0), databounds:PTR_NEW(0), $
    wdatabounds:PTR_NEW(0), ndatabounds:PTR_NEW(0) $
	}
;------------------------- RETRIEVE LOOP PARAMS
	retrparams = { $
		clfilecount:0, clfiles:PTR_NEW(STRARR(nphi)), sel_loops:PTR_NEW(INTARR(nphi)), $	
		retrieve_files:PTR_NEW(STRARR(nphi)), retrieve_filecount:0, $			
		lpsizes:PTR_NEW(LONARR(nphi)), lrsizes:PTR_NEW(LONARR(nphi)), $					
		xlr:PTR_NEW(0), ylr:PTR_NEW(0), $
    xlp:PTR_NEW(0), ylp:PTR_NEW(0) $
	}
;------------------------- SAVING PARAMS
	savparams = { $
		savpro:'', snapshot:0, lp_orig:lp_start, lp_ref_orig:lp_ref_start, filename_text:0, overlays_incl:0, overlays_thick:1, $
		overlays_curs:1, overlays_num:1, overlays_pts:1, linescan_ls:0, overlays_symsize:1, $
		overlays_asecbar:0, overlays_asecbar_length:1, overlays_asecbar_pix:1. $
	}
;------------------------- SAVING SWITCHES
	savswitch = { $
		cont:0, delete_clsav:0, det_imref_only:1, $				
		all_pos_loops:1, pos_dets:1, imrefsji:[1,0,0] $							
	}
;------------------------- SESSION PARAMS
	sesparams = { $
		rest_sessions:0, sessions:PTR_NEW(INTARR(nphi)), $
		curr_instance_id:LONG(set_instance_id), instance_label:instance_label $		
	}
;------------------------- SCALING
	scaling = { $
		imagescale:hdr.imagescale, imagemin:hdr.immin[hdr.lc], imagemax:hdr.immax[hdr.lc], $
		refmin:hdr.refmin[hdr.reflc], refmax:hdr.refmax[hdr.reflc], imrefscaling:0, $
    tsel_scaling_main:hdr.tsel_scaling_main, tsel_scaling_ref:hdr.tsel_scaling_ref, $
    tsel_scaling_sji:hdr.tsel_scaling_sji, $
		dopmin:hdr.dopplermin[hdr.lc], dopmax:hdr.dopplermax[hdr.lc], $
    sjimin:hdr.sjimin, sjimax:hdr.sjimax, t_current:t_start, $
    imagemin_curr:hdr.immin[hdr.lc], imagemax_curr:hdr.immax[hdr.lc], $
		refmin_curr:hdr.refmin[hdr.reflc], refmax_curr:hdr.refmax[hdr.reflc], $
		dopmin_curr:hdr.dopplermin[hdr.lc], dopmax_curr:hdr.dopplermax[hdr.lc], $
    sjimin_curr:hdr.sjimin, sjimax_curr:hdr.sjimax, $
    gamma:REPLICATE(gamma_val,2*hdr.ndiagnostics+hdr.nrefdiagnostics+hdr.nsjifiles_max), $
    minimum:REPLICATE(0,2*hdr.ndiagnostics+hdr.nrefdiagnostics+hdr.nsjifiles_max),  $
    maximum:REPLICATE(100,2*hdr.ndiagnostics+hdr.nrefdiagnostics+hdr.nsjifiles_max),  $
    idx:0, diagscale_label_vals:diagscale_label_vals, $
    histo_opt_val:REPLICATE(histo_opt_val,2*hdr.ndiagnostics+hdr.nrefdiagnostics+hdr.nsjifiles_max),  $
    mult_val:[hdr.main_mult_val,hdr.ref_mult_val] $
	}
;------------------------- STOKES PARAMS
	stokesparams = { $
		labels:hdr.stokes_labels, labels_ref:hdr.stokes_labels_ref, $
    button_labels:stokes_button_labels, mainref_select:0, $
    select_sp:hdr.stokes_select_sp, prev_select_sp:hdr.stokes_select_sp, $
    nselect_sp:TOTAL(hdr.stokes_select_sp), $
    nselect_refsp:TOTAL(hdr.stokes_select_refsp), $
    select_refsp:hdr.stokes_select_refsp, noise:FLTARR(4), noise_ref:FLTARR(4), $
    prev_select_refsp:hdr.stokes_select_refsp, $
    contpos:scale_stokes $
	}
;------------------------- VERSION INFO
	versioninfo = { $
		version_number:version_number, revision_number:revision_number $				
	}
;------------------------- WINDOW IDs
	winids = { $
		root:cpanel, imwid:imwid, xydrawid:xydrawid, $		
		reftlb:0, refwid:0, refdrawid:0, refdrawbase:0, $				
		doptlb:0, dopwid:0, dopdrawid:0, dopdrawbase:0, $
		imrefdisp:0, imreftlb:0, imrefwid:0, imrefdrawid:0, imrefdrawbase:0, $					
    imdrawid_ctbar:[imdrawid_ctbar,ctbar_drawid], refdrawid_ctbar:[0,0], $
    dopdrawid_ctbar:[0,0], $
		lstlb:0, lswid:0, lsdrawid:0, reflstlb:0, reflswid:0, reflsdrawid:0, $
		sptlb:0, spwid:0, spdrawid:0, refsptlb:0, refspwid:0, refspdrawid:0, $
		phistlb:0, phiswid:0, phisdrawid:0, $				
		looptlb:0, loopwid:0, loopdrawid:0, $						
		reflooptlb:0, refloopwid:0, refloopdrawid:0, $						
		sjilooptlb:INTARR(hdr.nsjifiles_max), sjiloopwid:INTARR(hdr.nsjifiles_max), $
    sjiloopdrawid:INTARR(hdr.nsjifiles_max), $						
		restlooptlb:PTR_NEW(0), restloopwid:PTR_NEW(0), restloopdrawid:PTR_NEW(0), $					
		retrdettlb:0, retrdetwid:0, retrdetdrawid:0, $					
		intwid:0, inttlb:0, intdrawid:0, intmenutlb:0, $
    sjiwid:INTARR(hdr.nsjifiles_max), sjitlb:INTARR(hdr.nsjifiles_max), $
    sjidrawid:INTARR(hdr.nsjifiles_max), sjidrawbase:INTARR(hdr.nsjifiles_max), $
    sjidrawid_ctbar:PTRARR(hdr.nsjifiles_max,/ALLOCATE_HEAP), $
		savetlb:0, detsavetlb:0, restoretlb:0, preftlb:0, $							
		estimatetlb:0, savewintlb:0, saveoptwintlb:0, $
    paramtlb:0, $					
		feedbacktlb:0, abouttlb:0, aboutwid:0, errtlb:0, warntlb:0, restsesfeedbtlb:0, $
    shorttlb:0, headertlb:0, current_wid:0, $
		imwintitle:imwintitle, spwintitle:'',lswintitle:'',refwintitle:'',refspwintitle:'',reflswintitle:'', $
		imrefwintitle:'',dopwintitle:'',phiswintitle:'',restloopwintitle:PTR_NEW(''),retrdetwintitle:'',$
		loopwintitle:'',refloopwintitle:'',sjiloopwintitle:STRARR(hdr.nsjifiles_max),$
    intwintitle:'', sjiwintitle:STRARR(hdr.nsjifiles_max) $
	}
;------------------------- WINDOW (RE)SIZES 
	winsizes = { $
    ; window sizes
		aboutwinx:startup_nx, aboutwiny:startup_ny, xywinx:imwinx, xywiny:imwiny, $
    imrefwinx:imrefwinx, imrefwiny:imrefwiny, $
		lswinx:lswinx, lswiny:lswiny, lsxres:lswinx, lsyres:lswiny, $
		spwinx:spwinx, spwiny:spwiny, spxres:spwinx, spyres:spwiny, $
    refwinx:refwinx, refwiny:refwiny, reflsxres:reflswinx, $
    reflsyres:reflswiny, refspxres:spwinx, refspyres:refspwiny, $
		phisxres:phiswinx, phisyres:phiswiny, refloopxres:spwinx, sjiloopxres:spwinx, $
    refloopyres:spwiny, loopxres:spwinx, loopyres:spwiny, restloopxres:spwinx,$
    sjiloopyres:spwiny, restloopyres:spwiny, retrdetxres:spwinx, retrdetyres:spwiny, $
    intxres:lswinx, intyres:intwiny, sjiwinx:sjiwinx, sjiwiny:sjiwiny, $
    ; window offsets
		xdelta:xdelta, ydelta:ydelta,  $
    spxoffset:spxoffset, spyoffset:spyoffset, $
    lsxoffset:lsxoffset, lsyoffset:lsyoffset, $
    phisxoffset:phisxoffset, phisyoffset:phisyoffset, $
    refxoffset:refxoffset, refyoffset:refyoffset, $
    refspxoffset:refspxoffset, refspyoffset:refspyoffset, $
    reflsxoffset:reflsxoffset, reflsyoffset:reflsyoffset, $
    sjixoffset:sjixoffset, sjiyoffset:sjiyoffset, $
    dopxoffset:dopxoffset, dopyoffset:dopyoffset, $
    imrefxoffset:imrefxoffset, imrefyoffset:imrefyoffset, $
    intxoffset:intxoffset, intyoffset:intyoffset, $
    loopxoffset:loopxoffset, loopyoffset:loopyoffset, $
    aboutxoffset:startup_xpos, aboutyoffset:startup_ypos $
		}
;------------------------- WINDOW SWITCHES
	winswitch = { $
    showls:showls, showsp:0, showrefsp:hdr.refspfile, showrefls:showrefls, $
    showimref:0, $
    estimate_win:0, showphis:0, showref:hdr.showref, showparam:0, showint:0, $
		showloop:0, showrefloop:0, showsjiloop:0, showrestloop:0, $
    showretrdet:0, showdop:0, dispwids:0, $
    showsji:showsji, whereshowsji:whereshowsji, $
    nwhereshowsji:(hdr.sjifile*hdr.nsjifiles) $
	}
;------------------------- ZOOMING 
	zooming = { $
		factor:zoomfactor, factorswitch:factorswitch, factors:zoomfactors, $
    factor_old:zoomfactor, init_factor:zoomfactor, tofit:1B, $
    xpos:0L, ypos:0L, xypos_max:LONARR(2), $
    xrefpos:0L, yrefpos:0L, xyrefpos_max:LONARR(2), $
    xsjipos:LONARR(hdr.nsjifiles_max), ysjipos:LONARR(hdr.nsjifiles_max), $
    xysjipos_max:LONARR(2,hdr.nsjifiles_max) $
	}
;------------------------- DEFINE INFO POINTER
	info = { $
		ctrlscp:PTR_NEW(ctrlscp, /NO_COPY), $
		ctrlsabout:PTR_NEW(ctrlsabout, /NO_COPY), $
		ctrlsdet:PTR_NEW(ctrlsdet, /NO_COPY), $
		ctrlsfeedb:PTR_NEW(ctrlsfeedb, /NO_COPY), $
		ctrlshdr:PTR_NEW(ctrlshdr, /NO_COPY), $
		ctrlsint:PTR_NEW(ctrlsint, /NO_COPY), $
		ctrlsloop:PTR_NEW(ctrlsloop, /NO_COPY), $
		ctrlspbbut:PTR_NEW(ctrlspbbut, /NO_COPY), $
		ctrlsparam:PTR_NEW(ctrlsparam, /NO_COPY), $
		ctrlspref:PTR_NEW(ctrlspref, /NO_COPY), $
		ctrlsref:PTR_NEW(ctrlsref, /NO_COPY), $
		ctrlsrestore:PTR_NEW(ctrlsrestore, /NO_COPY), $
		ctrlssav:PTR_NEW(ctrlssav, /NO_COPY), $
		ctrlssji:PTR_NEW(ctrlssji, /NO_COPY), $
		ctrlsswitch:PTR_NEW(ctrlsswitch, /NO_COPY), $
		curs:PTR_NEW(curs, /NO_COPY), $
		data:PTR_NEW(data, /NO_COPY), $
		dataparams:PTR_NEW(dataparams, /NO_COPY), $
		dataswitch:PTR_NEW(dataswitch, /NO_COPY), $
		detparams:PTR_NEW(detparams, /NO_COPY), $
		dispparams:PTR_NEW(dispparams, /NO_COPY), $
		dispswitch:PTR_NEW(dispswitch, /NO_COPY), $
		feedbparams:PTR_NEW(feedbparams, /NO_COPY), $
		intparams:PTR_NEW(intparams, /NO_COPY), $
		ioparams:PTR_NEW(ioparams, /NO_COPY), $
		loopsdata:PTR_NEW(loopsdata, /NO_COPY), $
		loopparams:PTR_NEW(loopparams, /NO_COPY), $
		loopswitch:PTR_NEW(loopswitch, /NO_COPY), $
		meas:PTR_NEW(meas, /NO_COPY), $
		overlayparams:PTR_NEW(overlayparams, /NO_COPY), $
		overlayswitch:PTR_NEW(overlayswitch, /NO_COPY), $
		paramparams:PTR_NEW(paramparams, /NO_COPY), $
		paramswitch:PTR_NEW(paramswitch, /NO_COPY), $
		paths:PTR_NEW(paths, /NO_COPY), $
		pbparams:PTR_NEW(pbparams, /NO_COPY), $
		phiparams:PTR_NEW(phiparams, /NO_COPY), $
		plotaxes:PTR_NEW(plotaxes, /NO_COPY), $
		plotparams:PTR_NEW(plotparams, /NO_COPY), $
		plotpos:PTR_NEW(plotpos, /NO_COPY), $
		plotswitch:PTR_NEW(plotswitch, /NO_COPY), $
		plottitles:PTR_NEW(plottitles, /NO_COPY), $
		prefs:PTR_NEW(prefs, /NO_COPY), $
		restoreparams:PTR_NEW(restoreparams, /NO_COPY), $
		retrparams:PTR_NEW(retrparams, /NO_COPY), $
		savparams:PTR_NEW(savparams, /NO_COPY), $
		savswitch:PTR_NEW(savswitch, /NO_COPY), $
		sesparams:PTR_NEW(sesparams, /NO_COPY), $
		scaling:PTR_NEW(scaling, /NO_COPY), $
		stokesparams:PTR_NEW(stokesparams, /NO_COPY), $
		versioninfo:PTR_NEW(versioninfo, /NO_COPY), $
		winids:PTR_NEW(winids, /NO_COPY), $
		winsizes:PTR_NEW(winsizes, /NO_COPY), $
		winswitch:PTR_NEW(winswitch, /NO_COPY), $
		zooming:PTR_NEW(zooming, /NO_COPY) $
	}
	info = PTR_NEW(info, /NO_COPY)
	WIDGET_CONTROL, cpanel, SET_UVALUE = info

	pseudoevent = { WIDGET_BUTTON, id:cpanel, top:cpanel, handler:0L, select:1 }
	IF (TOTAL(verbosity[0:1]) GE 1) THEN CRISPEX_UPDATE_STARTUP_SETUP_FEEDBACK, $
                                        '(defining main pointer)', /WIDGET, /OVER, /DONE
	feedback_text = [feedback_text[0:N_ELEMENTS(feedback_text)-2],'> Defining main pointer... done!']
	IF startupwin THEN CRISPEX_UPDATE_STARTUP_FEEDBACK, startup_im, xout, yout, feedback_text

;------------------------- DETERMINE DISPLAY OF PLOTS
	IF (TOTAL(verbosity[0:1]) GE 1) THEN CRISPEX_UPDATE_STARTUP_SETUP_FEEDBACK, $
                                        '(determining display of plots)', /WIDGET, /OVER
	feedback_text = [feedback_text,'> Determining display of plots... ']
	IF startupwin THEN CRISPEX_UPDATE_STARTUP_FEEDBACK, startup_im, xout, yout, feedback_text
	IF (((*(*info).dataswitch).spfile EQ 1) AND ((*(*info).dataparams).mainnt GT 1)) THEN BEGIN
    WIDGET_CONTROL, displays_button_ids[2], /SET_BUTTON
		(*(*info).winswitch).showsp = 1
	ENDIF ELSE BEGIN
    ; If no spectral file is provided
		IF (hdr.single_cube[0] EQ 1) THEN BEGIN
			(*(*info).dispparams).lp_upp = (*(*info).dispparams).lp_low
			(*(*info).winswitch).showphis = 0
;			(*(*info).winswitch).showls = 0
			WIDGET_CONTROL, approxmenu, SENSITIVE = 0
			WIDGET_CONTROL, save_ex_slab_but, SENSITIVE = 0
			WIDGET_CONTROL, subtract_but, SENSITIVE = 0
			WIDGET_CONTROl, lower_y_text, SENSITIVE = 0
			WIDGET_CONTROL, upper_y_text, SENSITIVE = 0
      WIDGET_CONTROL, displays_button_ids[3], SENSITIVE=0
		ENDIF ELSE BEGIN
			IF (hdr.single_cube[0] GE 1) THEN WIDGET_CONTROL, approxmenu, SENSITIVE = 0
			WIDGET_CONTROL, (*(*info).ctrlscp).slice_button, SENSITIVE = 0
			(*(*info).winswitch).showphis = 0
		ENDELSE
    WIDGET_CONTROL, displays_button_ids[2], SENSITIVE=0
		IF (hdr.mainnt EQ 1) THEN BEGIN
			WIDGET_CONTROL, fbwd_button, SENSITIVE = 0, SET_VALUE = bmpbut_fbwd_idle
			WIDGET_CONTROL, backward_button, SENSITIVE = 0, SET_VALUE = bmpbut_bwd_idle
			WIDGET_CONTROL, pause_button, SENSITIVE = 0, SET_VALUE = bmpbut_pause_idle
			WIDGET_CONTROL, forward_button, SENSITIVE = 0, SET_VALUE = bmpbut_fwd_idle
			WIDGET_CONTROL, ffwd_button, SENSITIVE = 0, SET_VALUE = bmpbut_ffwd_idle
			WIDGET_CONTROL, loop_button, SENSITIVE = 0, SET_VALUE = bmpbut_loop_idle
			WIDGET_CONTROL, cycle_button, SENSITIVE = 0, SET_VALUE = bmpbut_cycle_idle
			WIDGET_CONTROL, blink_button, SENSITIVE = 0, SET_VALUE = bmpbut_blink_idle
			WIDGET_CONTROL, t_slid, SENSITIVE = 0
			WIDGET_CONTROL, t_step_slid, SENSITIVE = 0
			WIDGET_CONTROL, upper_t_text, SET_VALUE = '0', SENSITIVE = 0
			WIDGET_CONTROL, lower_t_text, SET_VALUE = '0', SENSITIVE = 0
			WIDGET_CONTROL, save_as_jpg_all, SENSITIVE = 0
			WIDGET_CONTROL, save_as_png_all, SENSITIVE = 0
			WIDGET_CONTROL, save_as_mpeg, SENSITIVE = 0
			WIDGET_CONTROL, sh_fbwd_button, SENSITIVE = 0
			WIDGET_CONTROL, sh_backward_button, SENSITIVE = 0
			WIDGET_CONTROL, sh_pause_button, SENSITIVE = 0
			WIDGET_CONTROL, sh_forward_button, SENSITIVE = 0
			WIDGET_CONTROL, sh_ffwd_button, SENSITIVE = 0
			WIDGET_CONTROL, timeslicemenu, SENSITIVE = 0
      WIDGET_CONTROL, det_file_loop, SENSITIVE=0
			*(*(*info).data).scan = (*(*(*info).data).scan)[0]
			*(*(*info).data).sspscan = *(*(*info).data).scan
		ENDIF 
		WIDGET_CONTROL, loop_slit_but, SENSITIVE = exts_set
		WIDGET_CONTROL, loop_feedb_but, SENSITIVE = exts_set
		WIDGET_CONTROL, timeslicemenu, SENSITIVE = 0 
	ENDELSE

	IF (TOTAL(verbosity[0:1]) GE 1) THEN CRISPEX_UPDATE_STARTUP_SETUP_FEEDBACK, $
                                        '(determining display of plots)', /WIDGET, /OVER, /DONE
	feedback_text = [feedback_text[0:N_ELEMENTS(feedback_text)-2],'> Determining display of plots... done!']
	IF startupwin THEN CRISPEX_UPDATE_STARTUP_FEEDBACK, startup_im, xout, yout, feedback_text
;------------------------- OPENING WINDOWS
	IF (TOTAL(verbosity[0:1]) GE 1) THEN CRISPEX_UPDATE_STARTUP_SETUP_FEEDBACK, $
                                        '(realising widget and updating windows)', $
                                        /WIDGET, /OVER
	feedback_text = [feedback_text,'> Realising widget and updating windows... ']
	IF startupwin THEN CRISPEX_UPDATE_STARTUP_FEEDBACK, startup_im, xout, yout, feedback_text
  IF restore_from_session THEN $
    *(*info).winswitch = override_winswitch
	CRISPEX_MASK_BUTTONS_SET, pseudoevent
;  set_zoomfac = CRISPEX_BGROUP_ZOOMFAC_SET(pseudoevent, /NO_DRAW, $
;    SET_FACTOR_IDX=0, INIT_FACTOR=zoomfactor)
  CRISPEX_ZOOM, pseudoevent, /NO_DRAW, SET_FACTOR_IDX=0
  IF (hdr.mainnt GT 1) THEN CRISPEX_DISPRANGE_T_RANGE, pseudoevent, /NO_DRAW
  IF ((*(*info).winswitch).showsp OR (*(*info).winswitch).showls OR $
    (*(*info).winswitch).showphis) THEN $
    CRISPEX_DRAW_GET_SPECTRAL_AXES, pseudoevent, /MAIN
    CRISPEX_UPDATE_SLICES, pseudoevent, /NO_DRAW, /NO_FEEDBACK, $
      NO_PHIS=((*(*info).winswitch).showphis EQ 0), $
      GET_PHISLIT_COORDS=((*(*info).winswitch).showphis AND $
        restore_from_session), $
		  SSP_UPDATE=(((*(*info).dataswitch).spfile EQ 0) AND $
                    (*(*info).winswitch).showls), $
      REFSSP_UPDATE=(((*(*info).dataswitch).reffile EQ 1) AND $
                     ((*(*info).dataswitch).refspfile EQ 0) AND $
                      (*(*info).winswitch).showrefls) 
	IF (*(*info).winswitch).showsp THEN BEGIN
		(*(*info).winswitch).showsp = 0
		CRISPEX_DISPLAYS_SP_TOGGLE, pseudoevent, /NO_DRAW
		IF startupwin THEN WSHOW, startupwid
	ENDIF
	IF (*(*info).winswitch).showls THEN BEGIN
		(*(*info).winswitch).showls = 0
		CRISPEX_DISPLAYS_IMREF_LS_TOGGLE, pseudoevent, /NO_DRAW ;$
;      NO_DRAW=(*(*info).winswitch).showrefls
    IF ((*(*info).dataparams).ns GT 1) THEN $
      dummy = CRISPEX_BGROUP_STOKES_SCALING_SELECT(INFO=info, $
        MAINREF_SELECT=0, /NO_DRAW)
		IF startupwin THEN WSHOW, startupwid
	ENDIF
	IF (*(*info).winswitch).showref THEN BEGIN
		(*(*info).winswitch).showref = 0
		CRISPEX_DISPLAYS_REF_TOGGLE, pseudoevent, /NO_DRAW
		IF startupwin THEN WSHOW, startupwid
	ENDIF
  IF ((*(*info).winswitch).showrefsp OR (*(*info).winswitch).showrefls) THEN $
    CRISPEX_DRAW_GET_SPECTRAL_AXES, pseudoevent, /REFERENCE
	IF (*(*info).winswitch).showrefsp THEN BEGIN
    WIDGET_CONTROL, (*(*info).ctrlscp).refdisplays_button_ids[2], /SET_BUTTON
		(*(*info).winswitch).showrefsp = 0
		CRISPEX_DISPLAYS_REFSP_TOGGLE, pseudoevent, /NO_DRAW
		IF startupwin THEN WSHOW, startupwid
	ENDIF ELSE  $
    WIDGET_CONTROL, (*(*info).ctrlscp).refdisplays_button_ids[2], SENSITIVE=0
	IF (*(*info).winswitch).showrefls THEN BEGIN
		IF ((*(*info).dataswitch).refspfile EQ 0) THEN $
      *(*(*info).data).refsspscan = (*(*(*info).data).refscan)[0]
		(*(*info).winswitch).showrefls = 0
		CRISPEX_DISPLAYS_IMREF_LS_TOGGLE, pseudoevent, /REFERENCE, /NO_DRAW
    IF ((*(*info).dataparams).refns GT 1) THEN $
      dummy = CRISPEX_BGROUP_STOKES_SCALING_SELECT(INFO=info, $
        MAINREF_SELECT=1, /NO_DRAW)
		IF startupwin THEN WSHOW, startupwid
	ENDIF
	IF (*(*info).winswitch).showphis THEN BEGIN
		(*(*info).winswitch).showphis = 0
		CRISPEX_DISPLAYS_PHIS_TOGGLE, pseudoevent, /NO_DRAW
		IF startupwin THEN WSHOW, startupwid
	ENDIF
  IF (TOTAL((*(*info).winswitch).showsji) GT 0) THEN BEGIN
    FOR idx_sji=0,(*(*info).dataparams).nsjifiles-1 DO BEGIN
      (*(*info).winswitch).showsji[idx_sji] = 0
  		CRISPEX_DISPLAYS_SJI_TOGGLE, pseudoevent, /NO_DRAW, $
        IDX_SJI=idx_sji
    ENDFOR
		IF startupwin THEN WSHOW, startupwid
  ENDIF

	CRISPEX_FIND_CLSAV, pseudoevent
	IF ((*(*info).retrparams).clfilecount NE 0) THEN BEGIN
		WIDGET_CONTROL, (*(*info).ctrlscp).sel_saved_loop, SENSITIVE = 1
		WIDGET_CONTROL, (*(*info).ctrlscp).all_saved_loop, SENSITIVE = 1
	ENDIF
  
	CRISPEX_UPDATE_T, pseudoevent
	IF showrefls THEN BEGIN
		IF (ref_detspect_scale EQ 0) THEN BEGIN
			CRISPEX_DISPRANGE_LS_SCALE_REF, pseudoevent
			CRISPEX_DISPRANGE_LS_RANGE, pseudoevent, /NO_DRAW
		ENDIF
    (*(*info).ctrlsswitch).imrefdetspect = 0
		CRISPEX_DISPLAYS_DETSPECT_SET_BUTTONS, pseudoevent
	ENDIF
	IF (detspect_scale EQ 0) THEN BEGIN
		CRISPEX_DISPRANGE_LS_SCALE_MAIN, pseudoevent
		CRISPEX_DISPRANGE_LS_RANGE, pseudoevent, /NO_DRAW
	ENDIF
  CRISPEX_SCALING_APPLY_SELECTED, pseudoevent
	CRISPEX_DRAW, pseudoevent, NO_TIMESLICES=restore_from_session
  CRISPEX_DRAW_CTBAR, pseudoevent, /INIT

	spwset = ((*(*info).winswitch).showsp OR (*(*info).winswitch).showphis OR $
            (*(*info).winswitch).showrefsp) 
	IF (*(*info).winswitch).showls THEN $
    lsoffset = (*(*info).winswitch).showls * ((*(*info).winsizes).lswiny + $
    (*(*info).winsizes).ydelta) + (*(*info).dataswitch).refspfile * (*(*info).winsizes).ydelta $
   ELSE $
		lsoffset = (*(*info).winswitch).showrefls * (reflswiny + (*(*info).winsizes).ydelta)
	IF (TOTAL(verbosity[0:1]) GE 1) THEN CRISPEX_UPDATE_STARTUP_SETUP_FEEDBACK, $
                                        '(realising widget and updating windows)', $
                                        /WIDGET, /OVER, /DONE
	IF startupwin THEN BEGIN
		WSET, startupwid
		feedback_text = [feedback_text[0:N_ELEMENTS(feedback_text)-2],$
      '> Realising widget and updating windows... done!']
		CRISPEX_UPDATE_STARTUP_FEEDBACK, startup_im, xout, yout, feedback_text
	ENDIF

;------------------------- START MANAGING
	IF (TOTAL(verbosity[0:1]) GE 1) THEN CRISPEX_UPDATE_STARTUP_SETUP_FEEDBACK, $
                                        '(start managing)', /WIDGET, /OVER
	feedback_text = [feedback_text,'> Start managing... ']
	IF startupwin THEN CRISPEX_UPDATE_STARTUP_FEEDBACK, startup_im, xout, yout, feedback_text
	XMANAGER, 'CRISPEX', cpanel, /NO_BLOCK
	WSHOW, (*(*info).winids).imwid
	IF (TOTAL(verbosity[0:1]) GE 1) THEN CRISPEX_UPDATE_STARTUP_SETUP_FEEDBACK, $
                                        '(start managing)', /WIDGET, /OVER, /DONE
	feedback_text = [feedback_text[0]+'done!',feedback_text[1:N_ELEMENTS(feedback_text)-2],$
    '> Start managing... done!']
	IF startupwin THEN CRISPEX_UPDATE_STARTUP_FEEDBACK, startup_im, xout, yout, feedback_text
	WAIT,0.1
	IF (*(*info).prefs).autoplay THEN CRISPEX_PB_FORWARD, pseudoevent
	IF resave_preferences THEN CRISPEX_PREFERENCES_SAVE_SETTINGS, pseudoevent, /RESAVE
	IF (TOTAL(verbosity[0:1]) GE 1) THEN BEGIN
    msg = 'Set-up done!'
    IF verbosity[1] THEN $
      msg += ' Finished in '+$
        STRTRIM(SYSTIME(/SECONDS)-setup_starttime,2)+' s.' 
    CRISPEX_UPDATE_STARTUP_SETUP_FEEDBACK, msg
  ENDIF
	IF startupwin THEN BEGIN
		WSET, startupwid
		CRISPEX_UPDATE_STARTUP_FEEDBACK, startup_im, xout, yout, 'Set-up done!'
		WAIT,0.25
		WIDGET_CONTROL, startuptlb, /DESTROY
	ENDIF
	CRISPEX_VERBOSE_SET_BUTTONS, pseudoevent

  ; Issue last warning/error messages before finishing setup
  ; Issue only if WARNINGS >= 1
  IF ((*(*info).prefs).warnings GE 1) THEN BEGIN
    msg = ''
    IF (extreme_aspect AND (hdr.nx EQ 1)) THEN $
      msg = 'Extreme aspect ratio detected with NX = 1. Stretching '+$
        'x-dimension for easier visualisation: note that the '+$
        'image pixel aspect ratio is now inaccurate.'
    IF (STRCOMPRESS(msg) NE '') THEN BEGIN
      IF ((*(*info).prefs).warnings EQ 1) THEN $
        CRISPEX_UPDATE_STARTUP_SETUP_FEEDBACK, msg, /WARNING, /NO_ROUTINE, /NEWLINE $
      ELSE $
        CRISPEX_WINDOW_OK, pseudoevent, 'WARNING!', msg, $
    			OK_EVENT='CRISPEX_CLOSE_EVENT_WINDOW',$;, /BLOCK
          NO_SHOW_EVENT='CRISPEX_PREFERENCES_SET_WARNINGS_SETUP', $
          NO_SHOW_CHOICES=['Do not show set-up warnings',$
            'Write set-up warnings to terminal only',$
            'Always pop-up set-up warnings'], $
          SET_CHOICE_IDX=(*(*info).prefs).warnings
    ENDIF
  ENDIF

  ; Show release notes when using release version for the first time
  IF dir_settings_write THEN BEGIN
    latest_release_file = dir_settings+'latest_release_version.idlsave'
    IF FILE_TEST(latest_release_file) THEN BEGIN
      RESTORE, latest_release_file
      show_release_notes = (release_base_version_number NE base_version_number) 
    ENDIF ELSE $
      show_release_notes = 1
    IF show_release_notes THEN BEGIN
      CRISPEX_ABOUT_WINDOW, pseudoevent
      CRISPEX_ABOUT_RELEASE_INFO, pseudoevent
      release_base_version_number = base_version_number
      SAVE, release_base_version_number, FILENAME=latest_release_file
    ENDIF
  ENDIF

  ; If restoring from session, do the restore
  IF restore_from_session THEN $
    CRISPEX_SESSION_RESTORE, pseudoevent, CSESFILE=restore_session_file

  ; Save successful initialisation to latest session save file
  IF dir_settings_write THEN $
    CRISPEX_SESSION_SAVE, pseudoevent, 'crispex_last_session', $
      /LAST_SESSION

END
