; $Id: dave_mdicer.pro,v 1.16 2005/02/03 18:04:12 azuah Exp $
;###############################################################################
;
; LICENSE:
;  The software in this file is written by an employee of 
;  National Institute of Standards and Technology 
;  as part of the DAVE software project.
;
;  The DAVE software package is not subject to copyright protection
;  and is in the public domain. It should be considered as an
;  experimental neutron scattering data reduction, visualization, and
;  analysis system. As such, the authors assume no responsibility
;  whatsoever for its use, and make no guarantees, expressed or
;  implied, about its quality, reliability, or any other
;  characteristic. The use of certain trade names or commercial
;  products does not imply any endorsement of a particular product,
;  nor does it imply that the named product is necessarily the best
;  product for the stated purpose. We would appreciate acknowledgment
;  if the DAVE software is used of if the code in this file is
;  included in another product.
;
;###############################################################################
;
; Written by J.R.D. Copley
;************************************************************************************************
pro show_ptrs,message
;************************************************************************************************
; Utility routine -- not really needed.
compile_opt strictarr
;
; Prints number of pointers.
result=ptr_valid(count=n)
if (n_elements(message) eq 0) then begin
	print,'There are ',n,' valid pointers.'
endif else begin
	print,'At ',message,',',n,' valid pointers.'
endelse
end


;************************************************************************************************
pro dave_mdicerQuit,event
;************************************************************************************************
; Trivial quit routine.
;
compile_opt strictarr
;
widget_control,event.top,/destroy
return
end


;************************************************************************************************
pro dave_mdicerCleanup,tlb
;************************************************************************************************
; Cleanup routine.
;
compile_opt strictarr
;
widget_control,tlb,get_uvalue = pState,/no_copy
;
; revert to existing colors prior to exiting dave_mdicer
tvlct, (*pState).default_colors

; Send one or more events to "calling" widgets.
s = size((*pState).notifyIDs)
if s[0] eq 1 then count = 0 else count = s[2]-1
for j = 0,count do begin
  mdcInfo = {mdcEvent,$
    ID:(*pState).notifyIDs[0,j],$
    Top:(*pState).notifyIDs[1,j],$
    Handler:0l,$
    inPtr:ptr_new(*(*pState).inPtr)}
  if widget_info((*pState).notifyIDs[0,j],/valid_id) then begin $
    widget_control,(*pState).notifyIDs[0,j],send_event = mdcInfo
  endif
endfor
;
DEVICE,DECOMPOSED=(*PSTATE).OLD_DECOMP
;
; Free some pointers.
if (ptr_valid(pState)) then begin
	if (ptr_valid((*pState).pqty)) then ptr_free,(*pState).pqty
	if (ptr_valid((*pState).perr)) then ptr_free,(*pState).perr
	if (ptr_valid((*pState).px)) then ptr_free,(*pState).px
	if (ptr_valid((*pState).py)) then ptr_free,(*pState).py
	if (ptr_valid((*pState).tchansPtr)) then ptr_free,(*pState).tchansPtr
	if (ptr_valid((*pState).timesPtr)) then ptr_free,(*pState).timesPtr
	if (ptr_valid((*pState).energiesPtr)) then ptr_free,(*pState).energiesPtr
	if (ptr_valid((*pState).activePtr)) then ptr_free,(*pState).activePtr
	if (ptr_valid((*pState).multiplierPtr)) then ptr_free,(*pState).multiplierPtr
	if (ptr_valid((*pState).filesPtr)) then ptr_free,(*pState).filesPtr
	if (ptr_valid((*pState).durationsPtr)) then ptr_free,(*pState).durationsPtr
	if (ptr_valid((*pState).srdenomsPtr)) then ptr_free,(*pState).srdenomsPtr
	if (ptr_valid((*pState).commentsPtr)) then ptr_free,(*pState).commentsPtr
	if (ptr_valid((*pState).winstate.xPtr)) then ptr_free,(*pState).winstate.xPtr
	if (ptr_valid((*pState).winstate.yPtr)) then ptr_free,(*pState).winstate.yPtr
	if ((*pState).nodavePtr) then begin
		ptr_free,(*(*(*pState).davePtr).dataStrPtr).commonStr.histPtr
		ptr_free,(*(*(*pState).davePtr).dataStrPtr).commonStr.treatmentPtr
		ptr_free,(*(*(*pState).davePtr).dataStrPtr).specificPtr
		ptr_free,(*(*pState).davePtr).dataStrPtr
		ptr_free,(*pState).davePtr
	endif
	ptr_free,pState
endif
;
return
end


;************************************************************************************************
pro dave_mdicer_populate,filename,pState=pState,davePtr=davePtr
;************************************************************************************************
; This routine populates portions of the structure (*pState).
compile_opt strictarr
;
; Determine whether the file is or is to be treated as a background file
averaging=0
if (strpos(strlowcase(filename),'bgdsum') gt 0) then begin
	answer=dialog_message(['This file appears to be a background file.',$
		'If so, it will be averaged over time channels.',$
		'Is that acceptable?'],/question)
	averaging=(answer eq "Yes")
endif
;
; If this is the first dataset, populate all relevant fields.
if ((*pState).ndatasets eq 1) then begin
; If the x array is 2-dimensional, set the number of datasets = 0 and return.
	ndx=size(((*(*(*davePtr).dataStrPtr).commonStr.histPtr).x),/n_dimensions)
	if (ndx gt 1) then begin
		res=dialog_message('The x array must be 1-dimensional.',/error)
		(*pState).ndatasets=0
		return
	endif
; If the y array is 2-dimensional, set the number of datasets = 0 and return.
	ndy=size(((*(*(*davePtr).dataStrPtr).commonStr.histPtr).y),/n_dimensions)
	if (ndy gt 1) then begin
		res=dialog_message('The y array must be 1-dimensional.',/error)
		(*pState).ndatasets=0
		return
	endif
	;
	if (not averaging) then begin
		*(*pState).pqty=((*(*(*davePtr).dataStrPtr).commonStr.histPtr).qty)
		*(*pState).perr=((*(*(*davePtr).dataStrPtr).commonStr.histPtr).err)
	endif else begin
		dims=size((*(*(*davePtr).dataStrPtr).commonStr.histPtr).qty,/dimensions)
		*(*pState).pqty=(intarr(dims[0])+1)#total((*(*(*davePtr).dataStrPtr).commonStr.histPtr).qty,1)/dims[0]
		*(*pState).perr=intarr(dims[0],dims[1])
	endelse
	*(*pState).px=((*(*(*davePtr).dataStrPtr).commonStr.histPtr).x)
	*(*pState).py=((*(*(*davePtr).dataStrPtr).commonStr.histPtr).y)
	(*pState).xlabel=(*(*davePtr).dataStrPtr).commonStr.xlabel
	(*pState).ylabel=(*(*davePtr).dataStrPtr).commonStr.ylabel
	(*pState).histlabel=(*(*davePtr).dataStrPtr).commonStr.histlabel
	(*pState).xunits=(*(*davePtr).dataStrPtr).commonStr.xunits
	(*pState).yunits=(*(*davePtr).dataStrPtr).commonStr.yunits
	(*pState).histunits=(*(*davePtr).dataStrPtr).commonStr.histunits
	(*pState).xtype=(*(*davePtr).dataStrPtr).commonStr.xtype
	(*pState).ytype=(*(*davePtr).dataStrPtr).commonStr.ytype
	*(*pState).activePtr=1
	*(*pState).multiplierPtr=1.0
	*(*pState).filesPtr=filename
	*(*pState).durationsPtr=(*(*(*davePtr).dataStrPtr).specificPtr).duration
	*(*pState).srdenomsPtr=(*(*(*davePtr).dataStrPtr).specificPtr).ch_srdenom
	*(*pState).commentsPtr=(*(*(*davePtr).dataStrPtr).specificPtr).comments
;
; If what's to be plotted is histogrammed in x, convert it to points format.
	if (strlowcase((*pState).xtype) eq "histogram") then begin
		npx=0.5*((*(*pState).px)[0:n_elements(*(*pState).px)-2]+$
			(*(*pState).px)[1:n_elements(*(*pState).px)-1])
		ptr_free,(*pState).px
		(*pState).px=ptr_new(npx)
	endif
;
; If it's histogrammed in y, convert it to points format.
	if (strlowcase((*pState).ytype) eq "histogram") then begin
		npy=0.5*((*(*pState).py)[0:n_elements(*(*pState).py)-2]+$
			(*(*pState).py)[1:n_elements(*(*pState).py)-1])
		ptr_free,(*pState).py
		(*pState).py=ptr_new(npy)
	endif
;
	return
endif
;
; If this is not the first dataset, populate the qty, err, active and file fields,
;	but first do some compatibility tests.
;
; First of all, if the dimensions of qty do not match, decrement the number of
; datasets and return.
dims=size((*(*(*davePtr).dataStrPtr).commonStr.histPtr).qty,/dimensions)
if ((dims[0] ne long((*pState).xdim)) or (dims[1] ne long((*pState).ydim))) then begin
	res=dialog_message('Dataset dimensions do not match.',/error)
	(*pState).ndatasets=(*pState).ndatasets-1
	return
endif
;
; If the x arrays do not match, decrement the number of datasets and return.
; If necessary, convert to points format before making the comparison.
; An exception is made if the run is a background run.
new=(*(*(*davePtr).dataStrPtr).commonStr.histPtr).x
if (strlowcase((*pState).xtype) eq "histogram") then $
	new=0.5*(new[0:n_elements(new)-2]+new[1:n_elements(new)-1])
nmatch=total(*(*pState).px eq new)
;
if (nmatch ne dims[0]) then begin
	if (not averaging) then begin
		res=dialog_message('x values do not match.',/error)
		(*pState).ndatasets=(*pState).ndatasets-1
		return
	endif
endif
;
; If the y arrays do not match, decrement the number of datasets and return.
; If necessary, convert to points format before making the comparison.
new=(*(*(*davePtr).dataStrPtr).commonStr.histPtr).y
if (strlowcase((*pState).ytype) eq "histogram") then $
	new=0.5*(new[0:n_elements(new)-2]+new[1:n_elements(new)-1])
nmatch=total(*(*pState).py eq new)
if (nmatch ne dims[1]) then begin
	res=dialog_message('y values do not match.',/error)
	(*pState).ndatasets=(*pState).ndatasets-1
	return
endif
;
; All is well, so append to the appropriate arrays.
oldptrs=[(*pState).pqty,$
	(*pState).perr,$
	(*pState).activePtr,$
	(*pState).multiplierPtr,$
	(*pState).filesPtr,$
	(*pState).durationsPtr,$
	(*pState).srdenomsPtr,$
	(*pState).commentsPtr]
if (not averaging) then begin
	(*pState).pqty=ptr_new([[[*(*pState).pqty]],[[(*(*(*davePtr).dataStrPtr).commonStr.histPtr).qty]]],/no_copy)
	(*pState).perr=ptr_new([[[*(*pState).perr]],[[(*(*(*davePtr).dataStrPtr).commonStr.histPtr).err]]],/no_copy)
endif else begin
	(*pState).pqty=ptr_new([[[*(*pState).pqty]],$
		[[(intarr(dims[0])+1)#total((*(*(*davePtr).dataStrPtr).commonStr.histPtr).qty,1)/dims[0]]]],/no_copy)
	(*pState).perr=ptr_new([[[*(*pState).perr]],[[intarr(dims[0],dims[1])]]],/no_copy)
endelse
(*pState).activePtr=ptr_new([*(*pState).activePtr,1])
(*pState).multiplierPtr=ptr_new([*(*pState).multiplierPtr,1.0])
(*pState).filesPtr=ptr_new([*(*pState).filesPtr,filename])
duration=(*(*(*davePtr).dataStrPtr).specificPtr).duration
srdenom=(*(*(*davePtr).dataStrPtr).specificPtr).ch_srdenom
(*pState).durationsPtr=ptr_new([*(*pState).durationsPtr,duration])
(*pState).srdenomsPtr=ptr_new([*(*pState).srdenomsPtr,srdenom])
(*pState).commentsPtr=ptr_new([*(*pState).commentsPtr,$
	(*(*(*davePtr).dataStrPtr).specificPtr).comments])
ptr_free,oldptrs
;
end


;************************************************************************************************
pro dave_mdicerRead,event
;************************************************************************************************
; This routine reads a DAVE file or a DCS raw data file.
;
compile_opt strictarr
;
widget_control,event.top,get_uvalue = pState
;
readDAVE=widget_info(event.top,find_by_uname="readDAVE")
readDCS=widget_info(event.top,find_by_uname="readDCS")
;
; Get the names of one or more DAVE files to be read.
if (event.id eq readDAVE) then begin
	widget_control,readDCS,sensitive=0
	filenames=dialog_pickfile(filter="*.dave",path=(*!dave_defaults).workdir,$
		/multiple_files)
endif
;
; Get the names of one or more DCS raw data files to be read.
if (event.id eq readDCS) then begin
	widget_control,readDAVE,sensitive=0
	widget_control,(*pState).rbutton,sensitive=1
	filenames=dialog_pickfile(filter="*.dcs*",path=(*!dave_defaults).datdir,$
		/multiple_files)
endif
;
; If there is no file (e.g. the "Cancel" button was pushed), and if
; no files have yet been read, destroy the widget. If there is no file
; but at least one file has been read, return.
if (filenames[0] eq "") then begin
	if ((*pState).ndatasets eq 0) then begin
		widget_control,event.top,set_uvalue = pState
		dave_mdicerQuit,event
	endif else widget_control,event.top,set_uvalue = pState
	return
endif
;
filenames=filenames[sort(filenames)]
nfiles=n_elements(filenames)
;
; Read one or more files.
for kfile=0,nfiles-1 do begin
	filename=filenames[kfile]
	if (event.id eq readDAVE) then restore,filename
	if (event.id eq readDCS) then begin
		dave_makeDavePtr,davePtr=davePtr
		dcs_definedavestructure,davePtr=davePtr
		dcs_read_binaryOctavefile,filename,0,0,variables_read,davePtr=davePtr,$
			histodata_floating=1
	endif
;
	(*pState).readingDCS=event.id eq readDCS
;
; If this is the first time around, define some additional quantities
; that may be needed at a later stage: time channel widths, times T_SD,
; and energy transfers. Also define the elastic channel and the
; corresponding time-of-flight T_SD(elastic).
	if ((*pState).readingDCS and (*pState).ndatasets eq 0) then begin
		*(*pState).tchansPtr=transpose($
			(*(*(*davePtr).dataStrPtr).specificPtr).tchanlook[0,0:999])*0.05
		*(*pState).timesPtr=$
			(*(*(*(*davePtr).dataStrPtr).specificPtr).time_propsPtr)[0:999]
		*(*pState).energiesPtr=$
			(*(*(*(*davePtr).dataStrPtr).specificPtr).energy_propsPtr)[0:999]
		elastic_channel=$
			where(abs(*(*pState).energiesPtr) eq min(abs(*(*pState).energiesPtr)))
		(*pState).elastic_time=(*(*pState).timesPtr)[elastic_channel]
	endif
;
; Having read in a file, sensitize most of the widgets.
	widget_control,(*pState).wprint,/sensitive
	widget_control,(*pState).wsplot,/sensitive
	widget_control,(*pState).wsdata,/sensitive
	widget_control,(*pState).xymenu,/sensitive
	widget_control,(*pState).gpmenu,/sensitive
	widget_control,(*pState).optmenu,/sensitive
	widget_control,(*pState).setmenu,/sensitive
	widget_control,(*pState).infmenu,/sensitive
	widget_control,(*pState).lpanbut,/sensitive
	widget_control,(*pState).rpanbut,/sensitive
	widget_control,(*pState).dpanbut,/sensitive
	widget_control,(*pState).upanbut,/sensitive
	widget_control,(*pState).zoinbut,/sensitive
	widget_control,(*pState).zootbut,/sensitive
	widget_control,(*pState).xyrbnbut,/sensitive
;
; Increment the number of datasets read in.
	(*pState).ndatasets=(*pState).ndatasets+1
	ndatasets=(*pState).ndatasets
;
; Call "dave_mdicer_populate" to populate pState.
	dave_mdicer_populate,filename,pState=pState,davePtr=davePtr
	free_all_ptrs,davePtr
;
; If the number of datasets has been decremented within the
; procedure "dave_mdicer_populate" (e.g. because dimensions
; do not match), return.
	if ((*pState).ndatasets lt ndatasets) then begin
		widget_control,event.top,set_uvalue = pState
		return
	endif
;
	dims=size(*(*pState).pqty,/dimensions)
;
	ndatasets=(*pState).ndatasets
;
; Populate the file information box.
	n=n_elements(*(*pState).filesPtr)
	information=strcompress(string(indgen(n)+1))+$
		"  "+*(*pState).filesPtr+"  "+*(*pState).commentsPtr
	widget_control,(*pState).info,set_value=information
	widget_control,(*pState).info,set_text_top_line=(n-4) > 0
;
; Fill in information for "Abscissa" menu items.
	widget_control,(*pState).xbutton,set_value='['+(*pState).xlabel+']'
	widget_control,(*pState).ybutton,set_value=(*pState).ylabel
;
; Use the x and y dimensions to set maximum slider values.
	plotx=(*pState).plot_vs_x
	widget_control,(*pState).xyvalbut,set_slider_max=dims[plotx]
	widget_control,(*pState).xyrngbut,set_slider_max=dims[plotx]/2
	widget_control,(*pState).xyrbnbut,set_slider_max=dims[1-plotx]/10 > 6
	widget_control,(*pState).grps,set_slider_max=dims[plotx]
;
	(*pState).xdim=dims[0]
	(*pState).ydim=dims[1]
;
;
endfor
;
; Update the plot.
wset,(*pState).winstate.winPix
widget_control,event.top,set_uvalue = pState
dave_mdicerPlot,event
widget_control,event.top,get_uvalue = pState
wset,(*pState).winstate.winVis
device,copy = [0,0,!d.x_size,!d.y_size,0,0,(*pState).winstate.winPix]
wshow,(*pState).winstate.winVis
widget_control,event.top,set_uvalue = pState
;
return
;
end


;************************************************************************************************
pro dave_mdicerSaveplot,event
;************************************************************************************************
; This routine saves the information required to restore the plot. This
; information is contained in pState.
;
compile_opt strictarr
;
filename=dialog_pickfile(title="Enter saved plot file name.",filter="*.plt",$
	path=(*!dave_defaults).workdir)
if (filename eq "") then return
if (strpos(filename,".plt") eq -1) then filename=filename+".plt"
;
widget_control,event.top,get_uvalue=pState
save,filename=filename,pState
;
widget_control,event.top,set_uvalue=pState
;
end


;************************************************************************************************
pro dave_mdicerRestoreplot,event
;************************************************************************************************
; This routine reads in a saved plot file, restores the information to the
; appropriate variables and resconstructs the plot.
;
compile_opt strictarr
;
widget_control,event.top,get_uvalue=pState
;
; First of all store the current values of the pixmap and screen windows,
; the draw window, and all the various widget IDs created in the widget
; definition module.
winPix=(*pState).winstate.winPix
winVis=(*pState).winstate.winVis
win=(*pState).winstate.win
wprint=(*pState).wprint
wsplot=(*pState).wsplot
wrplot=(*pState).wrplot
wsdata=(*pState).wsdata
xymenu=(*pState).xymenu
gpmenu=(*pState).gpmenu
optmenu=(*pState).optmenu
setmenu=(*pState).setmenu
infmenu=(*pState).infomenu
xbutton=(*pState).xbutton
ybutton=(*pState).ybutton
sgrpbut=(*pState).sgrpbut
mgrpbut=(*pState).mgrpbut
agrpbut=(*pState).agrpbut
ebutton=(*pState).ebutton
pbutton=(*pState).pbutton
nbutton=(*pState).nbutton
rbutton=(*pState).rbutton
tthbutt=(*pState).tthbutt
athbutt=(*pState).athbutt
itmbutt=(*pState).itmbutt
ienbutt=(*pState).ienbutt
it4butt=(*pState).it4butt
dosbutt=(*pState).dosbutt
revbutt=(*pState).revbutt
abutton=(*pState).abutton
mbutton=(*pState).mbutton
dbutton=(*pState).dbutton
xyvalbut=(*pState).xyvalbut
xyrngbut=(*pState).xyrngbut
xyrbnbut=(*pState).xyrbnbut
lpanbut=(*pState).lpanbut
rpanbut=(*pState).rpanbut
dpanbut=(*pState).dpanbut
upanbut=(*pState).upanbut
zoinbut=(*pState).zoinbut
zootbut=(*pState).zootbut
zfrcbut=(*pState).zfrcbut
pfrcbut=(*pState).pfrcbut
gbase=(*pState).gbase
grps=(*pState).grps
info=(*pState).info
cpos=(*pState).cpos
xlval=(*pState).xlval
xrval=(*pState).xrval
ydval=(*pState).ydval
yuval=(*pState).yuval
;
; Now restore the plot.
filename=dialog_pickfile(title="Enter name of plot file to be restored.",$
	filter="*.plt",path=(*!dave_defaults).workdir)
if (filename eq "") then return
restore,filename=filename
;
; Next, substitute, back into pState, the current values of the pixmap and
; screen windows, the draw window, and all the various widget IDs created in
; the widget definition module.
(*pState).winstate.winPix=winPix
(*pState).winstate.winVis=winVis
(*pState).winstate.win=win
(*pState).wprint=wprint
(*pState).wsplot=wsplot
(*pState).wrplot=wrplot
(*pState).wsdata=wsdata
(*pState).xymenu=xymenu
(*pState).gpmenu=gpmenu
(*pState).optmenu=optmenu
(*pState).setmenu=setmenu
(*pState).infmenu=infmenu
(*pState).xbutton=xbutton
(*pState).ybutton=ybutton
(*pState).sgrpbut=sgrpbut
(*pState).mgrpbut=mgrpbut
(*pState).agrpbut=agrpbut
(*pState).ebutton=ebutton
(*pState).pbutton=pbutton
(*pState).nbutton=nbutton
(*pState).rbutton=rbutton
(*pState).tthbutt=tthbutt
(*pState).athbutt=athbutt
(*pState).itmbutt=itmbutt
(*pState).ienbutt=ienbutt
(*pState).it4butt=it4butt
(*pState).dosbutt=dosbutt
(*pState).revbutt=revbutt
(*pState).abutton=abutton
(*pState).mbutton=mbutton
(*pState).dbutton=dbutton
(*pState).xyvalbut=xyvalbut
(*pState).xyrngbut=xyrngbut
(*pState).xyrbnbut=xyrbnbut
(*pState).lpanbut=lpanbut
(*pState).rpanbut=rpanbut
(*pState).dpanbut=dpanbut
(*pState).upanbut=upanbut
(*pState).zoinbut=zoinbut
(*pState).zootbut=zootbut
(*pState).zfrcbut=zfrcbut
(*pState).pfrcbut=pfrcbut
(*pState).gbase=gbase
(*pState).grps=grps
(*pState).info=info
(*pState).cpos=cpos
(*pState).xlval=xlval
(*pState).xrval=xrval
(*pState).ydval=ydval
(*pState).yuval=yuval
;
; Start sensitizing widgets.
;
; Sensitize the menu widgets.
readDAVE=widget_info(event.top,find_by_uname="readDAVE")
readDCS=widget_info(event.top,find_by_uname="readDCS")
widget_control,readDCS,sensitive=(*pState).readingDCS
widget_control,readDAVE,sensitive=not (*pState).readingDCS
widget_control,(*pState).rbutton,sensitive=(*pState).readingDCS
widget_control,(*pState).wprint,/sensitive
widget_control,(*pState).wsplot,/sensitive
widget_control,(*pState).wsdata,/sensitive
widget_control,(*pState).xymenu,/sensitive
widget_control,(*pState).gpmenu,/sensitive
widget_control,(*pState).optmenu,/sensitive
widget_control,(*pState).setmenu,/sensitive
widget_control,(*pState).infmenu,/sensitive
;
;	Sensitize the pan and zoom buttons.
widget_control,(*pState).lpanbut,/sensitive
widget_control,(*pState).rpanbut,/sensitive
widget_control,(*pState).dpanbut,/sensitive
widget_control,(*pState).upanbut,/sensitive
widget_control,(*pState).zoinbut,/sensitive
widget_control,(*pState).zootbut,/sensitive
;
; Sensitize the rebin button.
widget_control,(*pState).xyrbnbut,/sensitive
;
; Set the sensitivity of the "Number of groups" button.
if ((*pState).one) then widget_control,(*pState).gbase,sensitive=0
if ((*pState).some) then widget_control,(*pState).gbase,sensitive=1
if ((*pState).all) then widget_control,(*pState).gbase,sensitive=0
;
; Define slider maximum values and current values.
dims=[(*pState).xdim,(*pState).ydim]
plotx=(*pState).plot_vs_x
widget_control,(*pState).grps,set_slider_max=dims[plotx]
widget_control,(*pState).grps,set_value=(*pState).ngrps
;
widget_control,(*pState).pfrcbut,set_value=(*pState).pfrac
widget_control,(*pState).zfrcbut,set_value=(*pState).zfrac
;
widget_control,(*pState).xyvalbut,set_slider_max=dims[plotx]
widget_control,(*pState).xyrngbut,set_slider_max=dims[plotx]/2
widget_control,(*pState).xyrbnbut,set_slider_max=dims[1-plotx]/10 > 6
if (plotx) then begin
	widget_control,(*pState).xyvalbut,set_value=(*pState).yvalue
	widget_control,(*pState).xyrngbut,set_value=(*pState).ywidth
	widget_control,(*pState).xyrbnbut,set_value=(*pState).xrebin
endif else begin
	widget_control,(*pState).xyvalbut,set_value=(*pState).xvalue
	widget_control,(*pState).xyrngbut,set_value=(*pState).xwidth
	widget_control,(*pState).xyrbnbut,set_value=(*pState).yrebin
endelse
;
; Populate the file information box.
n=n_elements(*(*pState).filesPtr)
information=strcompress(string(indgen(n)+1))+"  "+*(*pState).filesPtr
widget_control,(*pState).info,set_value=information
;
; Update labels on certain menu items.
if (plotx) then begin
	widget_control,(*pState).xbutton,set_value='['+(*pState).xlabel+']'
	widget_control,(*pState).ybutton,set_value=(*pState).ylabel
endif else begin
	widget_control,(*pState).xbutton,set_value=(*pState).xlabel
	widget_control,(*pState).ybutton,set_value='['+(*pState).ylabel+']'
endelse
;
if ((*pState).one) then begin
	widget_control,(*pState).sgrpbut,set_value='[Single group]'
	widget_control,(*pState).mgrpbut,set_value='Several groups'
	widget_control,(*pState).agrpbut,set_value='All in one group'
endif
if ((*pState).some) then begin
	widget_control,(*pState).sgrpbut,set_value='Single group'
	widget_control,(*pState).mgrpbut,set_value='[Several groups]'
	widget_control,(*pState).agrpbut,set_value='All in one group'
endif
if ((*pState).all) then begin
	widget_control,(*pState).sgrpbut,set_value='Single group'
	widget_control,(*pState).mgrpbut,set_value='Several groups'
	widget_control,(*pState).agrpbut,set_value='[All in one group]'
endif
;
if ((*pState).plot_eb) then $
	widget_control,(*pState).ebutton,set_value="Hide error bars" $
else widget_control,(*pState).ebutton,set_value="Show error bars"
;
if ((*pState).join_pts eq 1) then $
	widget_control,(*pState).pbutton,set_value="Do not join points"
if ((*pState).join_pts eq -1) then $
	widget_control,(*pState).pbutton,set_value="Join points"
;
if ((*pState).norm_d) then $
	widget_control,(*pState).nbutton,set_value="Do not normalize to duration" $
else widget_control,(*pState).nbutton,set_value="Normalize to duration"
;
; Update the plot.
wset,(*pState).winstate.winPix
widget_control,event.top,set_uvalue=pState
dave_mdicerPlot,event
widget_control,event.top,get_uvalue=pState
wset,(*pState).winstate.winVis
device,copy = [0,0,!d.x_size,!d.y_size,0,0,(*pState).winstate.winPix]
wshow,(*pState).winstate.winVis
widget_control,event.top,set_uvalue=pState
;
end


;************************************************************************************************
pro dave_mdicerClear,event
;************************************************************************************************
; This routine is used to clear the plot window and reset everything to initial
; conditions.
;
compile_opt strictarr
;
widget_control,event.top,get_uvalue=pState
;
; Set the sensitivity of the menu widgets.
readDAVE=widget_info(event.top,find_by_uname="readDAVE")
readDCS=widget_info(event.top,find_by_uname="readDCS")
widget_control,readDCS,sensitive=1
widget_control,readDAVE,sensitive=1
widget_control,(*pState).rbutton,sensitive=0
widget_control,(*pState).wprint,sensitive=0
widget_control,(*pState).wsplot,sensitive=0
widget_control,(*pState).wsdata,sensitive=0
widget_control,(*pState).xymenu,sensitive=0
widget_control,(*pState).gpmenu,sensitive=0
widget_control,(*pState).optmenu,sensitive=0
widget_control,(*pState).setmenu,sensitive=0
widget_control,(*pState).infmenu,sensitive=0
;
;	Desensitize the pan and zoom buttons.
widget_control,(*pState).lpanbut,sensitive=0
widget_control,(*pState).rpanbut,sensitive=0
widget_control,(*pState).dpanbut,sensitive=0
widget_control,(*pState).upanbut,sensitive=0
widget_control,(*pState).zoinbut,sensitive=0
widget_control,(*pState).zootbut,sensitive=0
;
; Sensitize the rebin button.
widget_control,(*pState).xyrbnbut,sensitive=1
;
; Define slider maximum values and current values.
widget_control,(*pState).grps,set_slider_max=100
widget_control,(*pState).grps,set_value=1
;
widget_control,(*pState).pfrcbut,set_value=20
widget_control,(*pState).zfrcbut,set_value=80
;
widget_control,(*pState).xyvalbut,set_slider_max=100
widget_control,(*pState).xyrngbut,set_slider_max=100
widget_control,(*pState).xyrbnbut,set_slider_max=100
widget_control,(*pState).xyvalbut,set_value=1
widget_control,(*pState).xyrngbut,set_value=0
widget_control,(*pState).xyrbnbut,set_value=1
;
; Clear the file information box.
widget_control,(*pState).info,set_value=""
;
; Update labels on certain menu items.
widget_control,(*pState).xbutton,set_value='x: (not yet defined)'
widget_control,(*pState).ybutton,set_value='y: (not yet defined)'
;
widget_control,(*pState).sgrpbut,set_value='Single group'
widget_control,(*pState).mgrpbut,set_value='Several groups'
widget_control,(*pState).agrpbut,set_value='[All in one group]'
;
widget_control,(*pState).ebutton,set_value="Show error bars"
widget_control,(*pState).pbutton,set_value="Join points"
widget_control,(*pState).nbutton,set_value="Normalize to duration"
;
; Initialize variables in pState.
(*pState).ngrps=1
(*pState).ndatasets=0
(*pState).xvalue=1
(*pState).yvalue=1
(*pState).xwidth=0
(*pState).ywidth=0
(*pState).xrebin=1
(*pState).yrebin=1
(*pState).plot_vs_x=1
(*pState).plot_vs_y=0
(*pState).plot_eb=0
(*pState).join_pts=-1
(*pState).norm_d=0
(*pState).plotv2th=0
(*pState).plota2th=0
(*pState).plotvst=0
(*pState).plotvsE=0
(*pState).plott4E=0
(*pState).plotdos=0
(*pState).one=0
(*pState).some=0
(*pState).all=1
(*pState).pan=0
(*pState).pfrac=20
(*pState).zoom=0
(*pState).zfrac=80
(*pState).xdim=1
(*pState).ydim=1
;
; Clear the pixmap window and copy it to the screen window.
wset,(*pState).winstate.winPix
xsize=!d.x_size
ysize=!d.y_size
wdelete,(*pState).winstate.winPix
window,/free,/pixmap,xsize=xsize,ysize=ysize
winPix=!d.window
(*pState).winstate.winPix=winPix
wset,(*pState).winstate.winVis
device,copy = [0,0,!d.x_size,!d.y_size,0,0,(*pState).winstate.winPix]
wshow,(*pState).winstate.winVis
;
; Save everything in the pointer pState.
widget_control,event.top,set_uvalue=pState
;
end


;************************************************************************************************
pro dave_mdicerPlot,event
;************************************************************************************************
; As its name implies, this procedure does the actual plotting.
;
compile_opt strictarr
;
widget_control,event.top,get_uvalue=pState
;
; Define some variables, depending whether the abscissa is x or y.
plot_vs_x=(*pState).plot_vs_x
;
samedim =   (plot_vs_x) ? (*pState).xdim   : (*pState).ydim
samerebin = (plot_vs_x) ? (*pState).xrebin : (*pState).yrebin
samelabel = (plot_vs_x) ? (*pState).xlabel : (*pState).ylabel
;
othrvalue = (plot_vs_x) ? (*pState).yvalue : (*pState).xvalue
othrwidth = (plot_vs_x) ? (*pState).ywidth : (*pState).xwidth
othrdim =   (plot_vs_x) ? (*pState).ydim   : (*pState).xdim
othrlabel = (plot_vs_x) ? (*pState).ylabel : (*pState).xlabel
;
abscis =    (plot_vs_x) ? *(*pState).px    : *(*pState).py
tot_index = (plot_vs_x) ? 2                : 1
;
; If plotting vs 2theta or against abs(2theta), redefine the abscissa and
; its label.
if ((*pState).plotv2th) then begin
	dcs_getangles,nhedet=913,angles
	abscis=angles
	samelabel="Scattering angle"
endif
if ((*pState).plota2th) then begin
	dcs_getangles,nhedet=913,angles
	abscis=abs(angles)
	samelabel="ABS(Scattering angle)"
endif
;
; If plotting vs time (T_SD) or against energy transfer, redefine the abscissa
; and its label.
if ((*pState).plotvst) then begin
	abscis=*(*pState).timesPtr
	samelabel="Time sample-detector (us)"
endif
if ((*pState).plotvsE or (*pState).plott4E or (*pState).plotdos) then begin
	abscis=*(*pState).energiesPtr
	samelabel="Energy transfer (meV)"
endif
;
; Define the ordinate and its error when plotting the sum over the
; other dimension ("All in one group").
if ((*pState).all) then begin
	ordina=total((*(*pState).pqty),tot_index)/othrdim
	oerror=sqrt(total((*(*pState).perr)^2,tot_index))/othrdim
	title=(*pState).histlabel+": average over all "+othrlabel
endif
;
; Define the ordinate and its error when plotting "Several groups".
; This is only allowed if there is only one dataset.
if ((*pState).some) then begin
	if ((*pState).ndatasets ne 1) then begin
		res=dialog_message("Multiple groups cannot be plotted if "+$
			"there are multiple files.")
		widget_control,event.top,set_uvalue=pState
		return
	endif else begin
		ndim=othrdim/(*pState).ngrps
; Initialize the ordinate and its error as a 2-d array.
		ordina=fltarr(samedim,(*pState).ngrps)
		oerror=fltarr(samedim,(*pState).ngrps)
; Loop over the groups, generating lower and upper values
;	of the index of the third dimension.
		kc=othrdim-ndim*(*pState).ngrps
		ke=-1
		for k=0,(*pState).ngrps-1 do begin
			if (k lt kc) then begin
				ks=ke+1
				ke=ks+ndim
			endif else begin
				ks=ke+1
				ke=ks+ndim-1
			endelse
; Generate the ordinate and its error.
;	Treat separately the case where there is only one contribution to the group.
			if (ks eq ke) then begin
				if ((*pState).plot_vs_x) then begin
					ordina[*,k]=(*(*pState).pqty)[*,ks]
					oerror[*,k]=sqrt((*(*pState).perr)[*,ks]^2)
				endif else begin
					ordina[*,k]=(*(*pState).pqty)[ks,*]
					oerror[*,k]=sqrt((*(*pState).perr)[ks,*]^2)
				endelse
; Treat the case where there is more than one contribution to the group.
			endif else begin
				if ((*pState).plot_vs_x) then begin
					ordina[*,k]=total((*(*pState).pqty)[*,ks:ke],2)/(ke-ks+1);;
					oerror[*,k]=sqrt(total((*(*pState).perr)[*,ks:ke]^2,2))/(ke-ks+1);;
				endif else begin
					ordina[*,k]=total((*(*pState).pqty)[ks:ke,*],1)/(ke-ks+1)
					oerror[*,k]=sqrt(total((*(*pState).perr)[ks:ke,*]^2,1))/(ke-ks+1)
				endelse
			endelse
		endfor
; Define the plot title.
		title=(*pState).histlabel+": "+othrlabel+"-"+$
			strcompress((*pState).ngrps)+" groups"
	endelse
endif
;
; Define the ordinate and its error when plotting a "single group".
if ((*pState).one) then begin
; Generating lower and upper values of the index of the third dimension.
	othrval1=othrvalue-othrwidth > 1
	othrval2=othrvalue+othrwidth < othrdim
;	Generate the ordinate and its error.
; Treat separately the case where there is only one contribution to the group.
	if (othrval1 eq othrval2) then begin
		if ((*pState).plot_vs_x) then begin
			ordina=(*(*pState).pqty)[*,othrvalue-1,*]
			oerror=(*(*pState).perr)[*,othrvalue-1,*]
		endif else begin
			ordina=(*(*pState).pqty)[othrvalue-1,*,*]
			oerror=(*(*pState).perr)[othrvalue-1,*,*]
		endelse
		title=(*pState).histlabel+": "+othrlabel+" ="+strcompress(othrvalue)
; Treat the case where there is more than one contribution to the group.
	endif else begin
		if ((*pState).plot_vs_x) then begin
			ordina=total((*(*pState).pqty)[*,othrval1-1:othrval2-1,*],2)$
				/(othrval2-othrval1+1)
			oerror=sqrt(total((*(*pState).perr)[*,othrval1-1:othrval2-1,*]^2,2))$
				/(othrval2-othrval1+1)
		endif else begin
			ordina=total((*(*pState).pqty)[othrval1-1:othrval2-1,*,*],1)$
				/(othrval2-othrval1+1)
			oerror=sqrt(total((*(*pState).perr)[othrval1-1:othrval2-1,*,*]^2,1))$
				/(othrval2-othrval1+1)
		endelse
		title=(*pState).histlabel+": "+othrlabel+$
			" ="+strcompress(othrval1)+" to"+strcompress(othrval2)
	endelse
endif
;
;	If required, rebin the data.
; This is only allowed if there is only one dataset.
; This section will need more comments.
if (samerebin gt 1) then begin
	if ((*pState).ndatasets eq 1) then begin
		res=dialog_message("This feature is not yet implemented.")
		(*pState).xrebin=1
		(*pState).yrebin=1
		widget_control,(*pState).xyrbnbut,set_value=1
		widget_control,event.top,set_uvalue=pState
		return
		newdim=samedim/samerebin
		if (samedim gt samerebin*newdim) then $
			abscis=abscis[0:samerebin*newdim-1]
		abscis=total(reform(abscis,samerebin,newdim),1)/samerebin
		nd=size(ordina,/n_dimensions)
		if (nd eq 1) then begin
			ordina=reform(ordina)
			ordina=congrid(ordina,newdim)
			oerror=ordina*0.5
		endif else begin
			ordina=congrid(ordina,newdim,(*pState).ngrps)
			oerror=ordina*0.5
		endelse
; This section will need more comments.
	endif else begin
		res=dialog_message("This feature is not yet implemented.")
		(*pState).xrebin=1
		(*pState).yrebin=1
		widget_control,(*pState).xyrbnbut,set_value=1
		widget_control,event.top,set_uvalue=pState
		return
	endelse
endif
;
; If plotting raw DCS data in certain ways, involving transformation
; of the ordinate, construct a variable (*factorPtr) with the same
; length as the (modified) ordinate.
; The dimension of *unityPtr is the product of all but the first dimension
; of ordina.
;
; If plotting intensity versus t_SD or versus E_transfer, divide each ordinate
; value by the time width of the channel.
if ((*pState).plotvst or (*pState).plotvsE) then begin
	dims=size(ordina,/dimensions)
	unityPtr=ptr_new(bytarr(n_elements(ordina)/dims[0])+1)
	factorPtr=ptr_new((*(*pState).tchansPtr)#(*unityPtr))
	ordina=ordina[0:999,*,*]/(*factorPtr)
	oerror=oerror[0:999,*,*]/(*factorPtr)
	ptr_free,unityPtr
	ptr_free,factorPtr
endif
;
; If plotting "t^4*dsdt" vs E_transfer, multiply each ordinate value by
; (t_SD/t_elastic)^4 and divide by the time width of the channel.
if ((*pState).plott4E) then begin
	dims=size(ordina,/dimensions)
	unityPtr=ptr_new(bytarr(n_elements(ordina)/dims[0])+1)
	factorPtr=ptr_new( (((*(*pState).timesPtr)/(*pState).elastic_time)^4 $
		/(*(*pState).tchansPtr))#(*unityPtr))
	ordina=ordina[0:999,*,*]*(*factorPtr)
	oerror=oerror[0:999,*,*]*(*factorPtr)
	ptr_free,unityPtr
	ptr_free,factorPtr
endif
;
; If plotting "DOS" vs E_transfer, multiply each ordinate value by
; E_transfer^2*(t_SD/t_elastic)^4, and divide by the time width of the channel.
if ((*pState).plotdos) then begin
	dims=size(ordina,/dimensions)
	unityPtr=ptr_new(bytarr(n_elements(ordina)/dims[0])+1)
	factorPtr=ptr_new( (*(*pState).energiesPtr)^2*$
		(((*(*pState).timesPtr)/(*pState).elastic_time)^4/(*(*pState).tchansPtr))$
		#(*unityPtr))
	ordina=ordina[0:999,*,*]*(*factorPtr)
	oerror=oerror[0:999,*,*]*(*factorPtr)
	ptr_free,unityPtr
	ptr_free,factorPtr
endif
;
; Multiply each dataset ordinate and ordinate error by a multiplier.
if ((*pstate).ndatasets eq 1) then begin
	ordina=ordina*(*(*pstate).multiplierPtr)[0]
	oerror=oerror*(*(*pstate).multiplierPtr)[0]
endif else begin
	dims=size(ordina,/dimensions)
	ndims=size(ordina,/n_dimensions)
	unityPtr=ptr_new(bytarr(n_elements(ordina)/dims[ndims-1])+1)
	ordina=ordina*(*unityPtr#(*(*pstate).multiplierPtr))
	oerror=oerror*(*unityPtr#(*(*pstate).multiplierPtr))
	ptr_free,unityPtr
endelse
;
; If desired, divide each dataset ordinate and ordinate error by its effective
; duration, i.e. duration*srdenom/60.0.
if ((*pState).norm_d) then begin
	duration=(*(*pstate).durationsPtr)*(*(*pstate).srdenomsPtr)/60.0
	if ((*pstate).ndatasets eq 1) then begin
		ordina=ordina/duration[0]
		oerror=oerror/duration[0]
	endif else begin
		dims=size(ordina,/dimensions)
		ndims=size(ordina,/n_dimensions)
		unityPtr=ptr_new(bytarr(n_elements(ordina)/dims[ndims-1])+1)
		ordina=ordina/(*unityPtr#duration)
		oerror=oerror/(*unityPtr#duration)
		ptr_free,unityPtr
	endelse
endif
;
; The data to be plotted should now be fully defined.
; The following code (within the if ... endif) is executed if
; saving the data (rather than plotting it).
;
if ((*pState).savedata) then begin
	nvals=size(ordina,/dimension)
;
; Determine the number of points on each curve and the number of curves.
	npoints=nvals[0]
	if (n_elements(nvals) eq 1) then ncurves=1 else ncurves=nvals[1]
;
; Determine whether or not to include ordinate errors in the saved data.
	res=dialog_message([$
		"You may either OMIT the errors, writing the output as X, Y1, Y2, ...",$
		"or you may INCLUDE the errors, writing it as X, Y1, DY1, Y2, DY2, ... ",$
		" ",$
		"Do you wish to include the errors in the output file?"],/question)
	include_errors=res eq "Yes"
;
;	Determine formats for abscissa, ordinate and error (if included).
	fa='f8.3'
	fo='e13.4'
	minx=strcompress(string(min(abscis)))
	maxx=strcompress(string(max(abscis)))
	miny=strcompress(string(min(ordina)))
	maxy=strcompress(string(max(ordina)))
	mindy=strcompress(string(min(oerror)))
	maxdy=strcompress(string(max(oerror)))
	help=['The extreme values of X are'+minx+' and'+maxx+'.',$
		'The extreme values of Y are'+miny+' and'+maxy+'.',$
		'The extreme values of DY are'+mindy+' and'+maxdy+'.']
	if (not include_errors) then begin
		text=['format(X)','format(Y)']
		fe=''
		value=[fa,fo]
		if (ncurves eq 1) then begin
			form='('+text[0]+', '+text[1]+').'
		endif else begin
			form='('+text[0]+', '+strcompress(ncurves,/remove_all)+' '+text[1]+').'
		endelse
		help=['The output file will be written in the format '+form,'',$
			help,'','If appropriate, edit format(X) and/or format(Y).']
	endif else begin
		text=['format(X)','format(Y)','format(DY)']
		fe='e13.4'
		value=[fa,fo,fe]
		if (ncurves eq 1) then begin
			form='('+text[0]+', '+text[1]+','+text[2]+').'
		endif else begin
			form='('+text[0]+','+strcompress(ncurves,/remove_all)+' ('+text[1]+','+text[2]+')).'
		endelse
		help=['The output file will be written in the format '+form,'',$
			help,'','If appropriate, edit format(X), format(Y) and/or format(DY).']
	endelse
;
	dave_get_values,'Define formats',text,value,help=help,group_leader=event.top
	fa='('+value[0]+')'
	fo='('+value[1]+')'
;
; Start to construct output strings. First comes the abscissa value.
	str=string(abscis,format=fa)
;
;	Then come the ordinate(s) with or without the ordinate error(s).
	if (not include_errors) then begin
		for m=0,ncurves-1 do str=str+string(ordina[*,m],format=fo)
	endif else begin
		fe='('+value[2]+')'
		for m=0,ncurves-1 do str=str+string(ordina[*,m],format=fo)+string(oerror[*,m],format=fe)
	endelse
;
; Determine whether there are any asterissks in the output strings.
; If so issue a warning and ask whethr to continue.
	ast_flag=max(strpos(str,"*")) eq 0
	if (!debug and ast_flag) then begin
		response=dialog_message(["There are asterisks in the output file,",$
			"indicating that one or more of the formats is inadequate.","",$
			"Do you still wish to write the output file?"],/question,/default_no)
	endif else response="Yes"
;
; Request saved data file name and write the data to the file.
	if (response eq "Yes") then begin
		filename=dialog_pickfile(title="Enter saved data file name.",filter="*.dat",$
			path=(*!dave_defaults).workdir)
		if (filename eq "") then begin
			widget_control,event.top,set_uvalue=pState
			return
		endif
		if (strpos(filename,".dat") eq -1) then filename=filename+".dat"
		openw,unit,filename,/get_lun
		for k=0,npoints-1 do printf,unit,str[k]
		free_lun,unit
	endif
	res=dialog_message("Can I return here (line 965)?")
endif
;
; The remaining code is executed if plotting the data (rather than saving
; the plot).
;
;	If required, perform autoscaling.
if ((*pState).winstate.autoscale eq 1) then begin
	minabs=min(abscis)
	maxabs=max(abscis)
	absrange=maxabs-minabs
  (*pState).winstate.xrange = [minabs-absrange*0.05,maxabs+absrange*0.05]
	minord=min(ordina)
	maxord=max(ordina)
	ordrange=maxord-minord
  (*pState).winstate.yrange = [minord-ordrange*0.05,maxord+ordrange*0.05]
endif
;
; If required, perform panning operation.
; If panning do not autoscale.
if ((*pState).pan ne 0) then (*pState).winstate.autoscale=0
case (*pState).pan of
; Pan left.
	-1: begin
		move=(*pState).pfrac*0.01*$
			((*pState).winstate.xrange[1]-(*pState).winstate.xrange[0])
		(*pState).winstate.xrange=(*pState).winstate.xrange-move
	end
; Pan right.
	 1: begin
		move=(*pState).pfrac*0.01*$
			((*pState).winstate.xrange[1]-(*pState).winstate.xrange[0])
	 	(*pState).winstate.xrange=(*pState).winstate.xrange+move
	end
; Pan down.
	-2: begin
		move=(*pState).pfrac*0.01*$
			((*pState).winstate.yrange[1]-(*pState).winstate.yrange[0])
		(*pState).winstate.yrange=(*pState).winstate.yrange-move
	end
; Pan up.
	 2: begin
		move=(*pState).pfrac*0.01*$
			((*pState).winstate.yrange[1]-(*pState).winstate.yrange[0])
	 	(*pState).winstate.yrange=(*pState).winstate.yrange+move
	end
	else:
endcase
(*pState).pan=0
;
;	If required, perform zooming operation.
; If zooming, do not autoscale.
if ((*pState).zoom ne 0) then begin
	(*pState).winstate.autoscale=0
	hwid=0.5*((*pState).winstate.xrange[1]-(*pState).winstate.xrange[0])
	hhgt=0.5*((*pState).winstate.yrange[1]-(*pState).winstate.yrange[0])
	xcen=0.5*((*pState).winstate.xrange[1]+(*pState).winstate.xrange[0])
	ycen=0.5*((*pState).winstate.yrange[1]+(*pState).winstate.yrange[0])
	zfrac=(*pState).zfrac*0.01
	case (*pState).zoom of
; Zoom out.
		-1: begin
		(*pState).winstate.xrange=[xcen-hwid*zfrac,xcen+hwid*zfrac]
		(*pState).winstate.yrange=[ycen-hhgt*zfrac,ycen+hhgt*zfrac]
		end
; Zoom in.
		 1: begin
		(*pState).winstate.xrange=[xcen-hwid/zfrac,xcen+hwid/zfrac]
		(*pState).winstate.yrange=[ycen-hhgt/zfrac,ycen+hhgt/zfrac]
		end
		else:
	endcase
endif
(*pState).zoom=0
;
abscisrange=(*pState).winstate.xrange
ordinarange=(*pState).winstate.yrange
;
; Start the actual plotting.
; First plot the frame, ticks, labels etc, but no data.
plot,abscis,ordina,Xstyle=1,Ystyle=1,Xtitle=samelabel,Ytitle="",$
	Xrange=abscisrange,Yrange=ordinarange,title=title,color=1,/nodata
;
nd=size(ordina,/n_dimensions)
;
barpos=0.9
dbar=0.02
nbar=4
; Next, for each dataset, ...
for dataset=0,(*pState).ndatasets-1 do begin
	color=2 + dataset mod 8
	d=dataset
	symbol=(d-d mod 16)/16+(1-((d-d mod 8) eq fix((d-d mod 8)/16)*16))*5
; Check that the dataset is active. If not, skip to end of loop.
	if (not (*(*pState).activePtr)[dataset]) then continue
;
; If there is one curve to be plotted per dataset, construct the
; ordinate and its error as vectors "ordina1" and "oerror1", and then
; plot the ordinate and its error if (requested).
	if ( ((*pState).ndatasets eq 1 and nd eq 1) $
		or ((*pState).ndatasets gt 1 and nd eq 2)) then begin
		ordina1=ordina[*,dataset]
		oerror1=oerror[*,dataset]
		oplot,abscis,ordina1,psym=-dave_selsym(symbol)*(*pState).join_pts,$
			symsize=0.75,color=color
		if ((*pState).plot_eb) then dave_cerrplot,abscis,ordina1-oerror1,$
			ordina1+oerror1,color=color
	endif else begin
;
; If there is more than one curve to be plotted per dataset, construct
; the ordinate and its error as 2-d arrays "ordina1" and "oerror1", and
; then execute a loop to plot the ordinate and its error (if requested).
		ordina1=ordina[*,*,dataset]
		oerror1=oerror[*,*,dataset]
		for k=0,(*pState).ngrps-1 do begin
			oplot,abscis,ordina1[*,k],psym=-dave_selsym(k)*(*pState).join_pts,$
				symsize=0.5,color=color
			if ((*pState).plot_eb) then dave_cerrplot,abscis,$
				ordina1[*,k]-oerror1[*,k],ordina1[*,k]+oerror1[*,k],$
				color=color
		endfor
	endelse
;
	barpos=barpos-dbar
	if (fix(dataset/nbar)*nbar eq dataset) then barpos=barpos-dbar
	plots,[0.01,0.04],[1,1]*barpos,psym=-dave_selsym(symbol),color=color,/normal
endfor
;
; Write the abscissa and ordinate extrema in appropriate places in the widget.
widget_control,(*pState).xlval,set_value=strcompress(!x.crange[0])
widget_control,(*pState).xrval,set_value=strcompress(!x.crange[1])
widget_control,(*pState).ydval,set_value=strcompress(!y.crange[0])
widget_control,(*pState).yuval,set_value=strcompress(!y.crange[1])
;
widget_control,event.top,set_uvalue=pState
;
end


;************************************************************************************************
pro dave_mdicerPrint,event
;************************************************************************************************
; Standard procedure to print to a postscript file.
compile_opt strictarr
;
thisDevice = !d.name
;deviceKeywords = ps_form(Cancel = canceled,parent = event.top)
device_keywords = PSConfig(Cancel=canceled,group_leader = event.top)
if canceled ne 1 then begin
  SET_PLOT, 'PS'
  DEVICE, _Extra = device_keywords
  dave_mdicerPlot,event
  DEVICE, /CLOSE_FILE
  set_plot,thisDevice
endif
return
end


;************************************************************************************************
pro dave_mdicerSavedata,event
;************************************************************************************************
; This routine is used to save the data to a file. This is done by calling the
; plotting routine having first set the variable (*pState).savedata.
compile_opt strictarr
;
widget_control,event.top,get_uvalue = pState
;
; Set the "savedata" variable.
(*pState).savedata=1
;
; Update the plot.
wset,(*pState).winstate.winPix
widget_control,event.top,set_uvalue = pState
dave_mdicerPlot,event
widget_control,event.top,get_uvalue = pState
wset,(*pState).winstate.winVis
device,copy = [0,0,!d.x_size,!d.y_size,0,0,(*pState).winstate.winPix]
wshow,(*pState).winstate.winVis
;
; Clear the "savedata" variable.
(*pState).savedata=0
widget_control,event.top,set_uvalue = pState
return
end


;************************************************************************************************
pro dave_mdicerDraw,event
;************************************************************************************************
; This relatively standard routine is used to handle zoom operations and to
;	detect and display the cursor coordinates.
;
compile_opt strictarr
;
widget_control,event.top,get_uvalue = pState
;
case event.type of
; Respond to a button press.
0:	begin
	  (*pState).winState.mouse = event.press
;
; If the right button was pressed, set the autoscale flag and exit.
		if (*pState).winState.mouse eq 4 then begin
	    (*pState).winState.autoscale = 1
			widget_control,event.top,set_uvalue = pState
	    return
	  endif
;
; If the left button was pressed, record the cursor' coordinates.
	  if (*pState).winState.mouse eq 1 then begin
	    (*pState).winState.xbox[0] = event.x
	    (*pState).winState.ybox[0] = event.y
	    wset,(*pState).winState.winVis
	    device,copy = [0,0,!d.x_size,!d.y_size,0,0,(*pState).winState.winPix]
	    empty
	    (*pState).winState.autoscale = 0
	  endif
	end
;
; Respond to a button release, presumably the left button.
1:	begin
;
; Determine lower left and upper right coordinates of zoom window.
	  xll = (*pState).winState.xbox[0] < (*pState).winState.xbox[1]
	  yll = (*pState).winState.ybox[0] < (*pState).winState.ybox[1]
	  w = abs((*pState).winState.xbox[1] - (*pState).winState.xbox[0])
	  h = abs((*pState).winState.ybox[1] - (*pState).winState.ybox[0])
	  xur = xll + w
	  yur = yll + h
	  ll = convert_coord(xll,yll,/device,/to_data,/double)
	  ur = convert_coord(xur,yur,/device,/to_data,/double)
;
; Define new ranges for abscissa and ordinate, and replot.
	  (*pState).winState.xrange = [ll[0],ur[0]]
	  (*pState).winState.yrange = [ll[1],ur[1]]
	  wset,(*pState).winState.winPix
	  widget_control,event.top,set_uvalue = pState
	  dave_mdicerPlot,event
	  widget_control,event.top,get_uvalue = pState
	  wset,(*pState).winState.winVis
	  device,copy = [0,0,!d.x_size,!d.y_size,0,0,(*pState).winState.winPix]
	  (*pState).winState.mouse = 0B
	end
;
; Respond to mouse motion.
2:	begin
  	result=convert_coord(event.x,event.y,/device,/to_data)
;
; Test whether the cursor is inside the plot. If so display its coordinates
; in data units.
		if (result[0] gt !x.crange[0] and result[0] lt !x.crange[1] and $
				result[1] gt !y.crange[0] and result[1] lt !y.crange[1] and $
				(*pState).ndatasets gt 0) then $
		  widget_control,(*pState).cpos,set_value=["COORDINATES",string(result[0:1])] else $
		  widget_control,(*pState).cpos,set_value=""
;
; As long as the left button is depressed, determine the coordinates of
; the instantaneous zoom rectangle and plot it.
	  if (*pState).winState.mouse eq 1 then begin
	  	(*pState).winState.xbox[1] = event.x
	  	(*pState).winState.ybox[1] = event.y
	  	xc = [(*pState).winState.xbox[0],event.x,event.x,(*pState).winState.xbox[0],$
	  	      (*pState).winState.xbox[0]]
	  	yc = [(*pState).winState.ybox[0],(*pState).winState.ybox[0],event.y,event.y,$
	  	      (*pState).winState.ybox[0]]
 	  	wset,(*pState).winState.winVis
	  	device,copy = [0,0,!d.x_size,!d.y_size,0,0,(*pState).winState.winPix]
	  	plots,xc,yc,/device,color=1
	  	empty
	  endif
	end
else:
endcase
;
widget_control,event.top,set_uvalue = pState
;
return
end


;************************************************************************************************
pro dave_mdicer_setops_activator,event
;************************************************************************************************
;
compile_opt strictarr
;
widget_control,event.top,get_uvalue=setupState
;
if (event.id eq setupState.done) then begin
	*(setupState.ptr)=widget_info(setupState.list,/list_select)
	widget_control,event.top,/destroy
	return
endif
;
widget_control,event.top,set_uvalue=setupState
;
end


;************************************************************************************************
pro dave_mdicer_setops,event
;************************************************************************************************
;
compile_opt strictarr
;
widget_control,event.top,get_uvalue=pState
;
; Obtain indices of active datasets. There must be at least one active dataset.
case event.id of
	(*pState).abutton: begin
		repeat begin
			tlb=widget_base(title="Select active sets (minimum 1)",$
				group_leader=event.top,/modal,/col)
			n=n_elements(*(*pState).filesPtr)
			information=strcompress(string(indgen(n)+1))+"  "+*(*pState).filesPtr
			list=widget_list(tlb,value=information,/multiple,ysize=8)
			done=widget_button(tlb,value='done')
			ptr=ptr_new(/allocate_heap)
			widget_control,list,set_list_select=where(*(*pState).activePtr)
			widget_control,tlb,/realize
			setupState={list:list,done:done,ptr:ptr}
			widget_control,tlb,set_uvalue=setupState
			xmanager,'dave_mdicer_setops',tlb,$
				event_handler='dave_mdicer_setops_activator'
			chosen=*(setupState.ptr)
			ptr_free,ptr
			if (chosen[0] eq -1) then $
				res=dialog_message("At least one dataset must be active.",/error)
		endrep until (chosen[0] ne -1)
			*(*pState).activePtr=intarr((*pState).ndatasets)
			(*(*pState).activePtr)[chosen]=1
	end
	(*pState).mbutton: begin
		title="Enter a multiplier for each dataset"
		text=strarr((*pState).ndatasets)+"Multiplier:"
		value=*(*pState).multiplierPtr
		dave_get_values,title,text,value,group_leader=event.top,checkall=1
		*(*pState).multiplierPtr=float(value)
	end
	else:
endcase
;
; Update the plot.
wset,(*pState).winstate.winPix
widget_control,event.top,set_uvalue=pState
dave_mdicerPlot,event
widget_control,event.top,get_uvalue=pState
wset,(*pState).winstate.winVis
device,copy = [0,0,!d.x_size,!d.y_size,0,0,(*pState).winstate.winPix]
wshow,(*pState).winstate.winVis
widget_control,event.top,set_uvalue=pState
;
end


;************************************************************************************************
pro dave_mdicer_handler,event
;************************************************************************************************
; Handle miscellaneous button presses etc.
;
compile_opt strictarr
;
widget_control,event.top,get_uvalue=pState
;
case event.id of
;
; Handle the error bars menu item.
	(*pState).ebutton: begin
		(*pState).plot_eb=1-(*pState).plot_eb
		if ((*pState).plot_eb) then $
			widget_control,(*pState).ebutton,set_value="Hide error bars" $
		else widget_control,(*pState).ebutton,set_value="Show error bars"
	end
;
; Handle the join points menu item.
	(*pState).pbutton: begin
		(*pState).join_pts=-(*pState).join_pts
		if ((*pState).join_pts eq 1) then $
			widget_control,(*pState).pbutton,set_value="Do not join points"
		if ((*pState).join_pts eq -1) then $
			widget_control,(*pState).pbutton,set_value="Join points"
	end
;
; Handle the normalize to duration menu item.
	(*pState).nbutton: begin
		(*pState).norm_d=1-(*pState).norm_d
		if ((*pState).norm_d) then $
			widget_control,(*pState).nbutton,set_value="Do not normalize to duration" $
		else widget_control,(*pState).nbutton,set_value="Normalize to duration"
	end
;
; Handle the show durations menu item.
	(*pState).dbutton: begin
		md=strjoin(['Durations:',string(fix(*(*pState).durationsPtr),format='(i6)')])
		ms=strjoin(['SR denoms:',string(*(*pState).srdenomsPtr,format='(i6)')])
		message=[md,ms]
		if (not (*pState).norm_d) then begin
			message=[message,"N.B.  Data are not normalized"]
		endif
		res=dialog_message(message,/information)
	end
;
;	Handle the plot vs 2theta menu item.
	(*pState).tthbutt: begin
		ybutton=(*pState).ybutton
		widget_control,event.top,set_uvalue=pState
		dave_mdicer_handler,{top:event.top,id:ybutton,handler:0l}
		widget_control,event.top,get_uvalue=pState
		(*pState).plotv2th=1
		(*pState).plota2th=0
		(*pState).plotvst=0
		(*pState).plotvsE=0
		(*pState).plott4E=0
		(*pState).plotdos=0
		(*pState).winstate.autoscale=1
	end
;
;	Handle the plot vs abs(2theta) menu item.
	(*pState).athbutt: begin
		ybutton=(*pState).ybutton
		widget_control,event.top,set_uvalue=pState
		dave_mdicer_handler,{top:event.top,id:ybutton,handler:0l}
		widget_control,event.top,get_uvalue=pState
		(*pState).plotv2th=0
		(*pState).plota2th=1
		(*pState).plotvst=0
		(*pState).plotvsE=0
		(*pState).plott4E=0
		(*pState).plotdos=0
		(*pState).winstate.autoscale=1
	end
;
;	Handle the Plot dsdt vs T_SD menu item.
	(*pState).itmbutt: begin
		xbutton=(*pState).xbutton
		widget_control,event.top,set_uvalue=pState
		dave_mdicer_handler,{top:event.top,id:xbutton,handler:0l}
		widget_control,event.top,get_uvalue=pState
		(*pState).plotv2th=0
		(*pState).plota2th=0
		(*pState).plotvst=1
		(*pState).plotvsE=0
		(*pState).plott4E=0
		(*pState).plotdos=0
		(*pState).winstate.autoscale=1
	end
;
;	Handle the Plot dsdt vs E transfer menu item.
	(*pState).ienbutt: begin
		xbutton=(*pState).xbutton
		widget_control,event.top,set_uvalue=pState
		dave_mdicer_handler,{top:event.top,id:xbutton,handler:0l}
		widget_control,event.top,get_uvalue=pState
		(*pState).plotv2th=0
		(*pState).plota2th=0
		(*pState).plotvst=0
		(*pState).plotvsE=1
		(*pState).plott4E=0
		(*pState).plotdos=0
		(*pState).winstate.autoscale=1
	end
;
;	Handle the Plot t^4*dsdt vs E transfer menu item.
	(*pState).it4butt: begin
		xbutton=(*pState).xbutton
		widget_control,event.top,set_uvalue=pState
		dave_mdicer_handler,{top:event.top,id:xbutton,handler:0l}
		widget_control,event.top,get_uvalue=pState
		(*pState).plotv2th=0
		(*pState).plota2th=0
		(*pState).plotvst=0
		(*pState).plotvsE=0
		(*pState).plott4E=1
		(*pState).plotdos=0
		(*pState).winstate.autoscale=1
	end
;
;	Handle the Plot E_transfer^2*t^4*dsdt vs E transfer menu item.
	(*pState).dosbutt: begin
		xbutton=(*pState).xbutton
		widget_control,event.top,set_uvalue=pState
		dave_mdicer_handler,{top:event.top,id:xbutton,handler:0l}
		widget_control,event.top,get_uvalue=pState
		(*pState).plotv2th=0
		(*pState).plota2th=0
		(*pState).plotvst=0
		(*pState).plotvsE=0
		(*pState).plott4E=0
		(*pState).plotdos=1
		(*pState).winstate.autoscale=1
	end

;	Handle the "revert" menu item.
	(*pState).revbutt: begin
		(*pState).plotv2th=0
		(*pState).plota2th=0
		(*pState).plotvst=0
		(*pState).plotvsE=0
		(*pState).plott4E=0
		(*pState).plotdos=0
		(*pState).winstate.autoscale=1
	end
;
; Handle the group center slider button.
	(*pState).xyvalbut: begin
		if ((*pState).plot_vs_x) then begin
			(*pState).yvalue=event.value
		endif else begin
			(*pState).xvalue=event.value
		endelse
	end
;
; Handle the group half-width slider button.
	(*pState).xyrngbut: begin
		width=event.value
		if ((*pState).plot_vs_x) then (*pState).ywidth=width
		if ((*pState).plot_vs_y) then (*pState).xwidth=width
	end
;
; Handle the abscissa rebinning slider button.
	(*pState).xyrbnbut: begin
		if ((*pState).plot_vs_x) then begin
			(*pState).xrebin=event.value
		endif else begin
			(*pState).yrebin=event.value
		endelse
	end
;
; Handle the menu item that makes x the abscissa.
	(*pState).xbutton: begin
		widget_control,(*pState).xbutton,get_value=tmp
		if (strmid(tmp,0,1) ne '[') then begin
			widget_control,(*pState).xbutton,set_value='['+tmp+']'
		endif
		widget_control,(*pState).ybutton,get_value=tmp
		if (strmid(tmp,0,1) eq '[') then begin
			tmp=strmid(tmp,1,strlen(tmp)-2)
			widget_control,(*pState).ybutton,set_value=tmp
		endif
		if (not (*pState).plot_vs_x) then (*pState).winstate.autoscale=1
		(*pState).plot_vs_x=1
		(*pState).plot_vs_y=0
		widget_control,(*pState).xyvalbut,set_value=(*pState).yvalue
		widget_control,(*pState).xyrngbut,set_value=(*pState).ywidth
		widget_control,(*pState).xyrbnbut,set_value=(*pState).xrebin
		widget_control,(*pState).xyvalbut,set_slider_max=(*pState).ydim
		widget_control,(*pState).xyrngbut,set_slider_max=(*pState).ydim
		widget_control,(*pState).xyrbnbut,set_slider_max=(*pState).xdim/10 > 6
		widget_control,(*pState).grps,set_slider_max=(*pState).ydim
	end
;
; Handle the menu item that makes y the abscissa.
	(*pState).ybutton: begin
		widget_control,(*pState).ybutton,get_value=tmp
		if (strmid(tmp,0,1) ne '[') then begin
			widget_control,(*pState).ybutton,set_value='['+tmp+']'
		endif
		widget_control,(*pState).xbutton,get_value=tmp
		if (strmid(tmp,0,1) eq '[') then begin
			tmp=strmid(tmp,1,strlen(tmp)-2)
			widget_control,(*pState).xbutton,set_value=tmp
		endif
		if (not (*pState).plot_vs_y) then (*pState).winstate.autoscale=1
		(*pState).plot_vs_x=0
		(*pState).plot_vs_y=1
		widget_control,(*pState).xyvalbut,set_value=(*pState).xvalue
		widget_control,(*pState).xyrngbut,set_value=(*pState).xwidth
		widget_control,(*pState).xyrbnbut,set_value=(*pState).yrebin
		widget_control,(*pState).xyvalbut,set_slider_max=(*pState).xdim
		widget_control,(*pState).xyrngbut,set_slider_max=(*pState).xdim
		widget_control,(*pState).xyrbnbut,set_slider_max=(*pState).ydim/10 > 6
		widget_control,(*pState).grps,set_slider_max=(*pState).xdim
	end
;
; Handle the single group menu item.
	(*pState).sgrpbut: begin
		widget_control,(*pState).sgrpbut,get_value=tmp
		if (strmid(tmp,0,1) ne '[') then begin
			widget_control,(*pState).sgrpbut,set_value='['+tmp+']'
		endif
		widget_control,(*pState).mgrpbut,get_value=tmp
		if (strmid(tmp,0,1) eq '[') then begin
			tmp=strmid(tmp,1,strlen(tmp)-2)
			widget_control,(*pState).mgrpbut,set_value=tmp
		endif
		widget_control,(*pState).agrpbut,get_value=tmp
		if (strmid(tmp,0,1) eq '[') then begin
			tmp=strmid(tmp,1,strlen(tmp)-2)
			widget_control,(*pState).agrpbut,set_value=tmp
		endif
		(*pState).one=1
		(*pState).some=0
		(*pState).all=0
	end
;
; Handle the multiple group menu item.
	(*pState).mgrpbut: begin
		widget_control,(*pState).mgrpbut,get_value=tmp
		if (strmid(tmp,0,1) ne '[') then begin
			widget_control,(*pState).mgrpbut,set_value='['+tmp+']'
		endif
		widget_control,(*pState).agrpbut,get_value=tmp
		if (strmid(tmp,0,1) eq '[') then begin
			tmp=strmid(tmp,1,strlen(tmp)-2)
			widget_control,(*pState).agrpbut,set_value=tmp
		endif
		widget_control,(*pState).sgrpbut,get_value=tmp
		if (strmid(tmp,0,1) eq '[') then begin
			tmp=strmid(tmp,1,strlen(tmp)-2)
			widget_control,(*pState).sgrpbut,set_value=tmp
		endif
		(*pState).one=0
		(*pState).some=1
		(*pState).all=0
	end
;
; Handle the all-in-one group menu item.
	(*pState).agrpbut: begin
		widget_control,(*pState).agrpbut,get_value=tmp
		if (strmid(tmp,0,1) ne '[') then begin
			widget_control,(*pState).agrpbut,set_value='['+tmp+']'
		endif
		widget_control,(*pState).sgrpbut,get_value=tmp
		if (strmid(tmp,0,1) eq '[') then begin
			tmp=strmid(tmp,1,strlen(tmp)-2)
			widget_control,(*pState).sgrpbut,set_value=tmp
		endif
		widget_control,(*pState).mgrpbut,get_value=tmp
		if (strmid(tmp,0,1) eq '[') then begin
			tmp=strmid(tmp,1,strlen(tmp)-2)
			widget_control,(*pState).mgrpbut,set_value=tmp
		endif
		(*pState).one=0
		(*pState).some=0
		(*pState).all=1
	end
;
; Handle the pan and zoom buttons ("direction" and magnitude)
	(*pState).lpanbut: (*pState).pan=-1
	(*pState).rpanbut: (*pState).pan=1
	(*pState).dpanbut: (*pState).pan=-2
	(*pState).upanbut: (*pState).pan=2
	(*pState).zoinbut: (*pState).zoom=-1
	(*pState).zootbut: (*pState).zoom=1
	(*pState).pfrcbut: (*pState).pfrac=event.value
	(*pState).zfrcbut: (*pState).zfrac=event.value
;
; Handle the minimum abscissa value box.
	(*pState).xlval: begin
		if (event.type eq 0) then begin
			widget_control,(*pState).xlval,get_value=tmpval
			(*pState).winstate.autoscale=0
			(*pState).winstate.xrange[0]=tmpval
		endif
	end
;
; Handle the maximum abscissa value box.
	(*pState).xrval: begin
		if (event.type eq 0) then begin
			widget_control,(*pState).xrval,get_value=tmpval
			(*pState).winstate.autoscale=0
			(*pState).winstate.xrange[1]=tmpval
		endif
	end
;
; Handle the minimum ordinate value box.
	(*pState).ydval: begin
		if (event.type eq 0) then begin
			widget_control,(*pState).ydval,get_value=tmpval
			(*pState).winstate.autoscale=0
			(*pState).winstate.yrange[0]=tmpval
		endif
	end
;
; Handle the maximum ordinate value box.
	(*pState).yuval: begin
		if (event.type eq 0) then begin
			widget_control,(*pState).yuval,get_value=tmpval
			(*pState).winstate.autoscale=0
			(*pState).winstate.yrange[1]=tmpval
		endif
	end
;
; Handle the number of groups slider.
	(*pState).grps: begin
		widget_control,event.id,get_value=ngrps
		(*pState).ngrps=ngrps[0]
	end

	else:
endcase
;
; As needed, modify sensitivities of buttons.
if ((*pState).one) then begin
	widget_control,(*pState).xyvalbut,sensitive=1
	widget_control,(*pState).xyrngbut,sensitive=1
	widget_control,(*pState).gbase,sensitive=0
endif
;
if ((*pState).some) then begin
	widget_control,(*pState).xyvalbut,sensitive=0
	widget_control,(*pState).xyrngbut,sensitive=0
	widget_control,(*pState).gbase,sensitive=1
endif
;
if ((*pState).all) then begin
	widget_control,(*pState).xyvalbut,sensitive=0
	widget_control,(*pState).xyrngbut,sensitive=0
	widget_control,(*pState).gbase,sensitive=0
endif
;
; If there is something to plot, plot it.
doplot=(*pState).ndatasets gt 0
if (doplot) then begin
	wset,(*pState).winstate.winPix
	widget_control,event.top,set_uvalue=pState
	dave_mdicerPlot,event
	widget_control,event.top,get_uvalue=pState
	wset,(*pState).winstate.winVis
	device,copy = [0,0,!d.x_size,!d.y_size,0,0,(*pState).winstate.winPix]
	wshow,(*pState).winstate.winVis
endif
;
widget_control,event.top,set_uvalue=pState
;
end


;************************************************************************************************
pro dave_mdicer,notifyIDs,inPtr,group_leader = group_leader
;************************************************************************************************
; This is the widget definition module

compile_opt strictarr
;
DEVICE,GET_DECOMPOSED=OLD_DECOMP
DEVICE,DECOMPOSED=0
;
nodavePtr=not dave_valid(davePtr)
;
dave_makeDavePtr,davePtr=davePtr
;
davesysvars
;
dcs_sysvars,davePtr=davePtr
;
; Use Alan's routine to load some colors.
default_colors=bindgen(256,3)
colorset
tvlct,default_colors,/get       ; get current color settings
tvlct,!dave_colors.red,!dave_colors.green,!dave_colors.blue
;
; Define top level widget.
tlb=widget_base(title="DAVE multiple dataset slicer",/col,mbar = bar)
;
; Define file menu.
filemenu = widget_button(bar,value = 'File',/menu)
	void = widget_button(filemenu,value = 'Select one or more DAVE data files',$
		event_pro = 'dave_mdicerRead',uname='readDAVE')
	void = widget_button(filemenu,value = 'Select one or more DCS raw data files',$
		event_pro = 'dave_mdicerRead',uname='readDCS')
	wprint = widget_button(filemenu,value = 'Print to a postscript file',$
		event_pro = 'dave_mdicerPrint',sensitive=0)
	wsplot = widget_button(filemenu,value = 'Save plot',$
		event_pro = 'dave_mdicerSaveplot',sensitive=0)
	wrplot = widget_button(filemenu,value = 'Restore plot',$
		event_pro = 'dave_mdicerRestoreplot')
	wsdata = widget_button(filemenu,value = 'Save plotted data',$
		event_pro = 'dave_mdicerSavedata',sensitive=0)
	void = widget_button(filemenu,value = 'Clear/reset',event_pro = 'dave_mdicerClear')
	void = widget_button(filemenu,value = 'Quit',event_pro = 'dave_mdicerQuit')
;
; Define abscissa menu.
xymenu=widget_button(bar,value='Abscissa',/menu,sensitive=0)
	xbutton=widget_button(xymenu,value='x: (not yet defined)')
	ybutton=widget_button(xymenu,value='y: (not yet defined)')
;
; Define grouping menu.
gpmenu=widget_button(bar,value='Grouping',/menu,sensitive=0)
	sgrpbut=widget_button(gpmenu,value='Single group')
	mgrpbut=widget_button(gpmenu,value='Several groups')
	agrpbut=widget_button(gpmenu,value='[All in one group]')
;
; Define options menu.
optmenu = widget_button(bar,value = 'Options',/menu,sensitive=0)
	ebutton = widget_button(optmenu,value = 'Show error bars')
	pbutton = widget_button(optmenu,value = 'Join points')
	nbutton = widget_button(optmenu,value = 'Normalize to duration')
	rbutton = widget_button(optmenu,value = 'DCS raw data options',/menu,sensitive=0)
		tthbutt = widget_button(rbutton,value = 'Plot vs 2theta')
		athbutt = widget_button(rbutton,value = 'Plot vs abs(2theta)')
		itmbutt = widget_button(rbutton,value = 'Plot dsdt vs T_SD')
		ienbutt = widget_button(rbutton,value = 'Plot dsdt vs E transfer')
		it4butt = widget_button(rbutton,value = 'Plot t^4*dsdt vs E transfer')
		dosbutt = widget_button(rbutton,value = 'Plot omega^2*t^4*dsdt vs E transfer')
		revbutt = widget_button(rbutton,value = 'Revert to normal plot')
;
; Define set operations menu.
setmenu = widget_button(bar,value = 'Set ops',/menu,sensitive=0)
	abutton = widget_button(setmenu,value = 'Activate',$
		event_pro = 'dave_mdicer_setops')
	mbutton = widget_button(setmenu,value = 'Renormalize',$
		event_pro = 'dave_mdicer_setops')
;
; Define settings menu.
infmenu = widget_button(bar,value = 'Info',/menu,sensitive=0)
	dbutton = widget_button(infmenu,value = 'Show durations etc')
;
; Create widget sub-base plus pan and zoom buttons.
bas0=widget_base(tlb,/row,/align_center)
	col1=widget_base(bas0,/col,/frame)
		row1a=widget_base(col1,/row)
			lpanbut=widget_button(row1a,value="Pan left",sensitive=0)
			rpanbut=widget_button(row1a,value="Pan right",sensitive=0)
		row1b=widget_base(col1,/row)
			dpanbut=widget_button(row1b,value="Pan down",sensitive=0)
			upanbut=widget_button(row1b,value="Pan up",sensitive=0)
		geometry=widget_info(rpanbut,/geometry)
		xs=geometry.xsize
		widget_control,lpanbut,xsize=xs
		widget_control,rpanbut,xsize=xs
		widget_control,dpanbut,xsize=xs
		widget_control,upanbut,xsize=xs
		pfrcbut=widget_slider(col1,title="Pan percent",$
			minimum=0,maximum=90,value=20)
	col2=widget_base(bas0,/col,/frame)
		row2a=widget_base(col2,/row)
			zoinbut=widget_button(row2a,value="Zoom in",sensitive=0)
		row2b=widget_base(col2,/row)
			zootbut=widget_button(row2b,value="Zoom out",sensitive=0)
		geometry=widget_info(zootbut,/geometry)
		xs=geometry.xsize
		widget_control,zoinbut,xsize=xs
		widget_control,zootbut,xsize=xs
		zfrcbut=widget_slider(col2,title="Zoom percent",$
			minimum=10,maximum=100,value=80)
;
;	Create some sliders, plus text widgets that define x and y limits.
	bas1=widget_base(bas0,/col)
		xyrow=widget_base(bas1,/row,sensitive=1,/frame)
			xyvalbut=widget_slider(xyrow,title="Group center",minimum=1,value=1)
			xyrngbut=widget_slider(xyrow,title="Halfwidth of group",minimum=0,value=0)
			xyrbnbut=widget_slider(xyrow,title="Abscissa rebinning",minimum=1,value=1)
		corns=widget_base(bas1,/row,/frame)
			xlpos=widget_base(corns,/col)
				xllab=widget_label(xlpos,value='xmin')
				xlval=widget_text(xlpos,xsize=10,/editable)
			xrpos=widget_base(corns,/col)
				xrlab=widget_label(xrpos,value='xmax')
				xrval=widget_text(xrpos,xsize=10,/editable)
			ydpos=widget_base(corns,/col)
				ydlab=widget_label(ydpos,value='ymin')
				ydval=widget_text(ydpos,xsize=10,/editable)
			yupos=widget_base(corns,/col)
				yulab=widget_label(yupos,value='ymax')
				yuval=widget_text(yupos,xsize=10,/editable)
;
;	Create some more widgets.
	bas2=widget_base(bas0,/col)
	gbase=widget_base(bas2,sensitive=0,/frame,/align_center)
	grps=widget_slider(gbase,title="Number of groups",minimum=1,value=1)
	void=widget_base(bas2,ysize=4) ; (spacer)
	cpos=widget_text(bas2,ysize=3);,/editable)
;
; Create an information section.
	infobase=widget_base(tlb,/row,/align_center)
	info=widget_text(infobase,xsize=104,ysize=4,/editable,/scroll)
;
; Create the plot window itself.
	geometry=widget_info(tlb,/geometry)
	winxsize=geometry.xsize
	winysize=400
;
	bottom=widget_base(tlb,/row)
		win=widget_draw(bottom,xsize=winxsize,ysize=winysize,$
			/button_events,/motion_events,event_pro="dave_mdicerdraw")
;
; Center the widget and realize it.
centertlb,tlb
widget_control,tlb,/realize
;
; Define some sensitivities.
widget_control,xyvalbut,sensitive=0
widget_control,xyrngbut,sensitive=0
;
; Create a pixmap window for later use, the same size as the screen window.
window,/free,/pixmap,xsize=winxsize,ysize=winysize
winPix = !d.window
widget_control,win,get_value = winVis
;
; Define winstate.
winState =  {winPix:winPix,$
             winVis:winVis,$
             win:win,$
             xbox:[0.0,1.0],$
             xrange:[0.0d0,1.0d0],$
             ybox:[0.0,1.0],$
             yrange:[0.0d0,1.0d0],$
             xPtr:ptr_new(/allocate_heap),$
             yPtr:ptr_new(/allocate_heap),$
             xtitle:'',$
             ytitle:'',$
             title:'',$
             mouse:0B,$
             autoscale:1}
;
; Define the state variable.
state={winstate:winstate,$
; Widget IDs
	wprint:wprint,$
	wsplot:wsplot,$
	wrplot:wrplot,$
	wsdata:wsdata,$
	xymenu:xymenu,$
	gpmenu:gpmenu,$
	optmenu:optmenu,$
	setmenu:setmenu,$
	infmenu:infmenu,$
	xbutton:xbutton,$
	ybutton:ybutton,$
	sgrpbut:sgrpbut,$
	mgrpbut:mgrpbut,$
	agrpbut:agrpbut,$
	ebutton:ebutton,$
	pbutton:pbutton,$
	nbutton:nbutton,$
	rbutton:rbutton,$
	tthbutt:tthbutt,$
	athbutt:athbutt,$
	itmbutt:itmbutt,$
	ienbutt:ienbutt,$
	it4butt:it4butt,$
	dosbutt:dosbutt,$
	revbutt:revbutt,$
	abutton:abutton,$
	mbutton:mbutton,$
	dbutton:dbutton,$
	xyvalbut:xyvalbut,$
	xyrngbut:xyrngbut,$
	xyrbnbut:xyrbnbut,$
	lpanbut:lpanbut,$
	rpanbut:rpanbut,$
	dpanbut:dpanbut,$
	upanbut:upanbut,$
	zoinbut:zoinbut,$
	zootbut:zootbut,$
	zfrcbut:zfrcbut,$
	pfrcbut:pfrcbut,$
	xyrow:xyrow,$
	gbase:gbase,$
	grps:grps,$
	ngrps:1,$
	info:info,$
	cpos:cpos,$
	xlval:xlval,$
	xrval:xrval,$
	ydval:ydval,$
	yuval:yuval,$
; Initial values
	readingDCS:1,$
	xvalue:1,$
	yvalue:1,$
	xwidth:0,$
	ywidth:0,$
	xrebin:1,$
	yrebin:1,$
	plot_vs_x:1,$
	plot_vs_y:0,$
	plot_eb:0,$
	join_pts:-1,$
	norm_d:0,$
	plotv2th:0,$
	plota2th:0,$
	plotvst:0,$
	plotvsE:0,$
	plott4E:0,$
	plotdos:0,$
	one:0,$
	some:0,$
	all:1,$
	pan:0,$
	pfrac:20,$
	zoom:0,$
	zfrac:80,$
	xdim:1,$
	ydim:1,$
;	Defined when data are read in.
	pqty:ptr_new(/allocate_heap),$
	perr:ptr_new(/allocate_heap),$
	px:ptr_new(/allocate_heap),$
	py:ptr_new(/allocate_heap),$
	xlabel:'',$
	ylabel:'',$
	histlabel:'',$
	xunits:'',$
	yunits:'',$
	histunits:'',$
	xtype:'',$
	ytype:'',$
	tchansPtr:ptr_new(/allocate_heap),$
	timesPtr:ptr_new(/allocate_heap),$
	energiesPtr:ptr_new(/allocate_heap),$
	elastic_time:4000.0,$
	ndatasets:0,$
	activePtr:ptr_new(/allocate_heap),$
	multiplierPtr:ptr_new(/allocate_heap),$
	filesPtr:ptr_new(/allocate_heap),$
	durationsPtr:ptr_new(/allocate_heap),$
	srdenomsPtr:ptr_new(/allocate_heap),$
	commentsPtr:ptr_new(/allocate_heap),$
	notifyIDs:notifyIDs,$
	savedata:0,$
	inPtr:inPtr, $
	default_colors:default_colors,$
	OLD_DECOMP:OLD_DECOMP,$
	davePtr:davePtr,$
	nodavePtr:nodavePtr}
;
widget_control,tlb,set_uvalue=ptr_new(state)
;
; xmanage.
xmanager,'dave_mdicer',tlb,event_handler='dave_mdicer_handler',$
	cleanup='dave_mdicerCleanup'
;
end
