;$Id: refine_app__define.pro,v 1.32 2006/09/29 18:53:43 azuah Exp $
;###############################################################################
;
; NAME:
;  REFINE_APP__DEFINE
;
; PURPOSE:
;  Object class definition of the GUI for RAINS.
;
; CATEGORY:
;  DAVE, Data Analysis, RAINS, surface fitting
;
; AUTHOR:
;   Robert M. Dimeo, Ph.D.
;   NIST Center for Neutron Research
;   100 Bureau Drive
;   Gaithersburg, MD 20899
;   Phone: (301) 975-8135
;   E-mail: robert.dimeo@nist.gov
;   http://www.ncnr.nist.gov/staff/dimeo
;
; 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.
;
;###############################################################################
;+
; NAME:
;       REFINE_APP__DEFINE
;   A.K.A. RAINS (for Refinement Application for Inelastic Neutron Scattering)
;
; PURPOSE:
;
;   Allow users to fit neutron scattering data as a function
;   of both Q and hw.  Surface models are selected from a library.
;
;
; AUTHOR:
;
;       Robert M. Dimeo, Ph.D.
;   NIST Center for Neutron Research
;       100 Bureau Drive
;   Gaithersburg, MD 20899
;       Phone: (301) 975-8135
;       E-mail: robert.dimeo@nist.gov
;       http://www.ncnr.nist.gov/staff/dimeo
;
; CATEGORY:
;
;       Data analysis, DAVE, Surface/model fitting
;
; CALLING SEQUENCE:
;
;
;
; KEYWORD PARAMETERS
;
;   GROUP_LEADER:  The group leader of this widget application (optional).
;
; COMMON BLOCKS:
;
;   NONE
;
; REQUIREMENTS:
;
;   MPCURVEFIT.PRO, MPFIT.PRO by Craig Markwardt
;   REFINE_FUNCTION__DEFINE.PRO
;   REFINE_FUNCTION_CONT__DEFINE.PRO
;   REFINEMENT__DEFINE.PRO
;   CREATE_GAUSS_RES.PRO
;
;   ...and all of the routines required for the above
;   (see individual headers)!
;
;
; MODIFICATION HISTORY:
;
;   Written 4/25/04 (RMD)
;-
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
pro win_info__define
; Definition of the named structure that contains all of the fields necessary
; to perform zooming operation in any of the draw widgets.
define =    { win_info,      $
         win:0L,       $
         autoscale:1,   $
         winVis:0L,      $
         winPix:0L,      $
         xPtr:ptr_new(),   $
         yPtr:ptr_new(),   $
         mouse:0B,      $
         xrange:fltarr(2),   $
         yrange:fltarr(2),   $
         xpos:0.0,      $
         ypos:0.0      $
      }
end
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
pro refine_app::cleanup
compile_opt idl2,hidden
wdelete,(*self.im_win_info_ptr).winpix
wdelete,(*self.imres_win_info_ptr).winpix
wdelete,(*self.plot_win_info_ptr).winpix
wdelete,(*self.plotres_win_info_ptr).winpix
ptr_free,(*self.im_win_info_ptr).xPtr,(*self.im_win_info_ptr).yPtr
ptr_free,(*self.imres_win_info_ptr).xPtr,(*self.imres_win_info_ptr).yPtr
ptr_free,(*self.plot_win_info_ptr).xPtr,(*self.plot_win_info_ptr).yPtr
ptr_free,(*self.plotres_win_info_ptr).xPtr,(*self.plotres_win_info_ptr).yPtr
ptr_free,self.im_win_info_ptr,self.imres_win_info_ptr
ptr_free,self.plot_win_info_ptr,self.plotres_win_info_ptr
ptr_free,self.sel_leaf_ptr,self.pfun_sel,self.pdata_sel,self.pmodel_sel
ptr_free,self.current_file_id_ptr
obj_destroy,[self.file_container,self.test_data_container]
end
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
function refine_app::free_uvalue_heap,event = event
; Free up any heap memory associated with the user-values of the
; existing leaves
nobj = self.file_container->count()
if nobj ne 0 then begin
   oall = self.file_container->get(/all)
   for i = 0,nobj-1 do begin
     ret = oall[i]->get(wid = leaf_id)
     if widget_info(leaf_id,/valid_id) then begin
      widget_control,leaf_id,get_uvalue = cmd
      ptr_free,cmd.res_ptr
      ptr_free,cmd.res_ptr_orig
      ; Must descend down the tree and free up the heap variables
      first_child_id = widget_info(leaf_id,/child)
      if widget_info(first_child_id,/valid_id) then begin
         widget_control,first_child_id,get_uvalue = cmd
         obj_destroy,cmd.omodel
         if obj_valid(cmd.orefine) then obj_destroy,cmd.orefine
         sibling_id = widget_info(first_child_id,/sibling)
         widget_control,first_child_id,/destroy
         while widget_info(sibling_id,/valid_id) do begin
           widget_control,sibling_id,get_uvalue = cmd
           obj_destroy,cmd.omodel
           if obj_valid(cmd.orefine) then obj_destroy,cmd.orefine
           new_sibling_id = widget_info(sibling_id,/sibling)
           widget_control,sibling_id,/destroy
           sibling_id = new_sibling_id
         endwhile
      endif
     endif
   endfor
endif
return,1
end
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
function refine_app::about,event = event
compile_opt idl2,hidden
strout = ['RAINS written by R.M.Dimeo','for the DAVE software package', $
     ' ','NIST Center for Neutron Research',' ', $
     'Version 0.1 deployed May 21, 2003']
void = dialog_message(/information,strout,dialog_parent = event.top)
end
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
function refine_app::get,  workdir = workdir
compile_opt idl2,hidden
workdir = self.workdir
end
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
function refine_app::get_notify_ids
compile_opt idl2,hidden
return,self.notify_ids
end
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
pro rafins_cleanup,tlb
compile_opt idl2,hidden
widget_control,tlb,get_uvalue = self
notify_ids = self->get_notify_ids()
if obj_valid(self) then begin
   rainsinfo = { RAINSEVENT,$
           ID:notify_ids[0],$
           Top:notify_ids[1],$
           Handler:0l}
   if widget_info(notify_ids[0],/valid_id) then begin $
     widget_control,notify_ids[0],send_event = rainsInfo
   endif
endif
if obj_valid(self) then obj_destroy,self
help,/heap,/brief
end
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
function refine_app::desensitize_model_menus,event = event
compile_opt idl2,hidden
diffusion_id = widget_info(self.tlb,find_by_uname = 'DIFFUSION_MENU')
tunneling_id = widget_info(self.tlb,find_by_uname = 'TUNNELING_MENU')
misc_id = widget_info(self.tlb,find_by_uname = 'MISC_MENU')
widget_control,diffusion_id,sensitive = 0
widget_control,tunneling_id,sensitive = 0
widget_control,misc_id,sensitive = 0
return,1
end
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
function refine_app::sensitize_model_menus,event = event
compile_opt idl2,hidden
diffusion_id = widget_info(self.tlb,find_by_uname = 'DIFFUSION_MENU')
tunneling_id = widget_info(self.tlb,find_by_uname = 'TUNNELING_MENU')
misc_id = widget_info(self.tlb,find_by_uname = 'MISC_MENU')
widget_control,diffusion_id,sensitive = 1
widget_control,tunneling_id,sensitive = 1
widget_control,misc_id,sensitive = 1
return,1
end
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
function refine_app::quit,event = event
compile_opt idl2,hidden
; We have to free all of the resolution function pointers that are currently
; stored in the user-value of the existing leaves of the tree widget.  This
; must be done prior to destroying the top-level base in order to ensure that
; the widget ids are valid.
ret = self->free_uvalue_heap(event = event)
widget_control,self.tlb,/destroy
return,1
end
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
function refine_app::display_model_parameters,event = event
compile_opt idl2,hidden
n_model = n_elements(*self.pmodel_sel)
if n_model eq 0 then return,0
widget_control,(*self.pmodel_sel)[0],get_uvalue = uval
nobj = uval.omodel->count()
if nobj eq 0 then return,0

; Call the non-modal widget and detect events coming from it
if n_elements(*self.pmodel_sel) eq 0 then return,0
this_event = tag_names(event,/structure_name)
case this_event of
'RAFINS_FILE_INFO_EVENT':
'WIDGET_BUTTON':   $
   begin
     model_id = (*self.pmodel_sel)[0]
     widget_control,model_id,get_uvalue = uval
     omodel = uval.omodel
     parms = omodel->getparms()
     parmnames = omodel->getparmnames()
     nparms = n_elements(parms)
     strout = strarr(nparms)
     for i = 0,nparms-1 do begin
      strout[i] = 'p['+strtrim(string(i),2)+']: '+$
            parmnames[i]+'='+strtrim(string(parms[i]),2)
     endfor
     rafins_file_info,  strout,                 $
               group_leader = event.top,      $
               notify_ids = [event.id,event.top], $
               title = 'Parameter values'
   end
else:
endcase

return,1
end
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
function refine_app::show_context_menu,event = event

if (tag_names(event,/struct) ne 'WIDGET_CONTEXT') then return, 0 ;RTA-other events seem to be getting here!

uname = widget_info(event.id,/uname)
; Which leaves if any have been selected?
if n_elements(*self.sel_leaf_ptr) eq 0 then return,0
nleaves = n_elements(*self.sel_leaf_ptr)
nfun = n_elements(*self.pfun_sel)
ndata = n_elements(*self.pdata_sel)
nmodel = n_elements(*self.pmodel_sel)
if nfun ne 0 then $
   context_base = widget_info(event.top,find_by_uname = 'FUNCTION_MENU')
if ndata ne 0 then $
   context_base = widget_info(event.top,find_by_uname = 'DATA_MENU')
if nmodel ne 0 then $
   context_base = widget_info(event.top,find_by_uname = 'MODEL_MENU')
if (nfun+nmodel+ndata ne 0) then $
   widget_displaycontextmenu, event.id, event.x, event.y, context_base

return,1
end
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
function refine_app::plot_image_window,event = event
compile_opt idl2,hidden
if n_elements(*self.current_file_id_ptr) eq 0 then return,0
sel_leaves = *self.current_file_id_ptr
if n_elements(sel_leaves) eq 1 then begin
   widget_control,sel_leaves[0],get_uvalue = cmd
   odata = cmd.data_object
endif
win_info = *self.im_win_info_ptr
ret = odata->plot_image(   autoscale = win_info.autoscale, $
               xrange = win_info.xrange,    $
               yrange = win_info.yrange)

; Is there a model or function selected?
nmodel = n_elements(*self.pmodel_sel)
nfun = n_elements(*self.pfun_sel)
if nmodel eq 1 then begin
   if widget_info((*self.pmodel_sel)[0],/parent) eq sel_leaves[0] then begin
     widget_control,(*self.pmodel_sel)[0],get_uvalue = model_cmd
     omodel = model_cmd.omodel
     orefine = model_cmd.orefine
     ret = orefine->get(xindex = xindex,yindex = yindex)
     if omodel->count() gt 0 then begin
      ret = odata->get(position = position,xrange = xrange,yrange = yrange)
      ret = omodel->display_contour(   nlevels = 6,        $
                       ;xrange = win_info.xrange,  $
                       ;yrange = win_info.yrange,  $
                       xrange = xrange,   $
                       yrange = yrange,   $
                       xstyle = 5,ystyle = 5,/noerase, $
                       position = position,  $
                       autoscale = win_info.autoscale,   $
                       xindex = xindex,         $
                       yindex = yindex          )
     endif
   endif
endif
if nfun eq 1 then begin
   if widget_info(widget_info((*self.pfun_sel)[0],/parent),/parent) $
     eq sel_leaves[0] then begin
     model_id = widget_info((*self.pfun_sel)[0],/parent)
     widget_control,model_id,get_uvalue = model_cmd
     omodel = model_cmd.omodel
     orefine = model_cmd.orefine
     ret = orefine->get(xindex = xindex,yindex = yindex)
     if omodel->count() gt 0 then begin
      ret = odata->get(position = position,xrange = xrange,yrange = yrange)
      ret = omodel->display_contour(   nlevels = 6,        $
;                     xrange = win_info.xrange,  $
;                     yrange = win_info.yrange,  $
                       xrange = xrange,   $
                       yrange = yrange,   $
                       xstyle = 5,ystyle = 5,/noerase, $
                       position = position,  $
                       autoscale = win_info.autoscale,   $
                       xindex = xindex,         $
                       yindex = yindex          )
     endif
   endif
endif
*(*self.im_win_info_ptr).xptr = !x
*(*self.im_win_info_ptr).yptr = !y
return,1
end
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
function refine_app::plot_imageres_window,event = event
compile_opt idl2,hidden
if n_elements(*self.current_file_id_ptr) eq 0 then return,0
sel_leaves = *self.current_file_id_ptr
if n_elements(sel_leaves) eq 1 then begin
   widget_control,sel_leaves[0],get_uvalue = cmd
   odata = cmd.data_object
endif
win_info = *self.im_win_info_ptr
; Get the data out
ret = odata->get(qty = qty,err = err,xvals = xvals,yvals = yvals)

; Is there a model or function selected?
nmodel = n_elements(*self.pmodel_sel)
nfun = n_elements(*self.pfun_sel)
if nmodel eq 1 then begin
   if widget_info((*self.pmodel_sel)[0],/parent) eq sel_leaves[0] then begin
     widget_control,(*self.pmodel_sel)[0],get_uvalue = model_cmd
     omodel = model_cmd.omodel
     if omodel->count() gt 0 then begin
      ret = odata->get(position = position,xlabel = xlabel, $
         ylabel = ylabel, qtlabel = qtlabel)
      ret = omodel->evaluate(zvalues = yfit)
      residuals = (yfit-qty)/err
      if win_info.autoscale eq 1 then begin
         xrange = [min(xvals),max(xvals)]
         yrange = [min(yvals),max(yvals)]
      endif else begin
         xrange = win_info.xrange
         yrange = win_info.yrange
      endelse
      disp_qty = abs(min(residuals))+0.1+residuals
      contour,bytscl(alog10(disp_qty)),   $
         xvals,yvals,xrange = xrange, yrange = yrange, $
         xstyle = 1,ystyle = 1,position = position, $
         nlevels = 10,/fill,xtitle = xlabel,ytitle = ylabel, $
         title = 'Residuals'
     endif
   endif
endif
if nfun eq 1 then begin
   if widget_info(widget_info((*self.pfun_sel)[0],/parent),/parent) $
     eq sel_leaves[0] then begin
     model_id = widget_info((*self.pfun_sel)[0],/parent)
     widget_control,model_id,get_uvalue = model_cmd
     omodel = model_cmd.omodel
     if omodel->count() gt 0 then begin
      ret = odata->get(position = position,xlabel = xlabel, $
         ylabel = ylabel,qtlabel = qtlabel)
      ret = omodel->evaluate(zvalues = yfit)
      residuals = (yfit-qty)/err
      if win_info.autoscale eq 1 then begin
         xrange = [min(xvals),max(xvals)]
         yrange = [min(yvals),max(yvals)]
      endif else begin
         xrange = win_info.xrange
         yrange = win_info.yrange
      endelse
      disp_qty = abs(min(residuals))+0.1+residuals
      contour,bytscl(alog10(disp_qty)),   $
         xvals,yvals,xrange = xrange, yrange = yrange, $
         xstyle = 1,ystyle = 1,position = position, $
         nlevels = 20,/fill,xtitle = xlabel,ytitle = ylabel, $
         title = 'Residuals'
     endif
   endif
endif
return,1
end
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
function refine_app::plot_plot_window,event = event
compile_opt idl2,hidden
if n_elements(*self.current_file_id_ptr) eq 0 then return,0
sel_leaves = *self.current_file_id_ptr
;sel_leaves = *self.sel_leaf_ptr
if n_elements(sel_leaves) eq 1 then begin
   widget_control,sel_leaves[0],get_uvalue = cmd
   odata = cmd.data_object
endif
plot_info = *self.plot_win_info_ptr

; Retrieve slider info
; Reset it's limits incase data has been cropped in y
widget_control,self.group_slider,get_value = val & index = val[0]-1
ovoid = odata->get(yvals=y)
ny = n_elements(y)
index = index < (ny-1)
widget_control, self.group_slider, set_slider_max=ny, set_value=(index+1)

ret = odata->plot_group(index,xrange = plot_info.xrange,    $
                 yrange = plot_info.yrange,     $
                 autoscale = plot_info.autoscale)
ret = odata->get(xrange = xrange,yrange = yrange,qty = qty,err = err)

; Is there a model or function selected?
nmodel = n_elements(*self.pmodel_sel)
nfun = n_elements(*self.pfun_sel)
if nmodel eq 1 then begin
   if widget_info((*self.pmodel_sel)[0],/parent) eq sel_leaves[0] then begin
     widget_control,(*self.pmodel_sel)[0],get_uvalue = model_cmd
     omodel = model_cmd.omodel
     if omodel->count() gt 0 then begin
      ret = omodel->overplot( index,         $
                  xrange = xrange,  $
                  yrange = yrange,  $
                  xstyle = 5,ystyle = 5,/noerase);, $
;                  autoscale = plot_info.autoscale)
     endif
   endif
endif
if nfun eq 1 then begin
   if widget_info(widget_info((*self.pfun_sel)[0],/parent),/parent) $
     eq sel_leaves[0] then begin
     model_id = widget_info((*self.pfun_sel)[0],/parent)
     widget_control,model_id,get_uvalue = model_cmd
     omodel = model_cmd.omodel
     if omodel->count() gt 0 then begin
      ret = omodel->overplot( index,         $
                  xrange = xrange,  $
                  yrange = yrange,  $
                  xstyle = 5,ystyle = 5,/noerase);, $
;                  autoscale = plot_info.autoscale)
     endif
   endif
endif

*(*self.plot_win_info_ptr).xptr = !x
*(*self.plot_win_info_ptr).yptr = !y
return,1
end
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
function refine_app::plot_plotres_window,event = event
compile_opt idl2,hidden
if n_elements(*self.current_file_id_ptr) eq 0 then return,0
sel_leaves = *self.current_file_id_ptr
;sel_leaves = *self.sel_leaf_ptr
if n_elements(sel_leaves) eq 1 then begin
   widget_control,sel_leaves[0],get_uvalue = cmd
   odata = cmd.data_object
endif
plot_info = *self.plot_win_info_ptr
widget_control,self.group_slider,get_value = val & index = val[0]-1
; Get the data...
ret = odata->get(qty = qty,xvals = xvals,yvals = yvals,err = err,xrange = xrange, $
   xlabel = xlabel,ylabel = ylabel,qtlabel = qtlabel)
ydat = reform(qty[*,index]) & dydat = reform(err[*,index]) & y = yvals[index]

; Is there a model or function selected?
nmodel = n_elements(*self.pmodel_sel)
nfun = n_elements(*self.pfun_sel)
if nmodel eq 1 then begin
   if widget_info((*self.pmodel_sel)[0],/parent) eq sel_leaves[0] then begin
     widget_control,(*self.pmodel_sel)[0],get_uvalue = model_cmd
     omodel = model_cmd.omodel
     if omodel->count() gt 0 then begin
      ret = omodel->evaluate(zvalues = yfit)
      residuals = (reform(yfit[*,index])-ydat)/dydat
      if plot_info.autoscale eq 1 then xrange = [min(xvals),max(xvals)] else $
         xrange = plot_info.xrange

; Calculate the residuals
      dof = n_elements(yfit[*,index])-n_elements(omodel->getparms())
      chisq = (1.0/dof)*total(residuals^2)

      this_str_out = '!4v!3!E2!N= '+strtrim(string(chisq),2)
      plot,xvals,residuals,psym = 0,xrange = xrange,xstyle = 1, $
         xtitle = xlabel,ytitle = 'Residuals',title = this_str_out
      plots,!x.crange,[-1.0,-1.0],thick = 2.0,linestyle = 2,/data
      plots,!x.crange,[1.0,1.0],thick = 2.0,linestyle = 2,/data
     endif
   endif
endif
if nfun eq 1 then begin
   if widget_info(widget_info((*self.pfun_sel)[0],/parent),/parent) $
     eq sel_leaves[0] then begin
     model_id = widget_info((*self.pfun_sel)[0],/parent)
     widget_control,model_id,get_uvalue = model_cmd
     omodel = model_cmd.omodel
     if omodel->count() gt 0 then begin
      omodel->setxvalues,xvals
      ret = omodel->evaluate(zvalues = yfit)
      residuals = (reform(yfit[*,index])-ydat)/dydat
      if plot_info.autoscale eq 1 then xrange = [min(xvals),max(xvals)] else $
         xrange = plot_info.xrange
; Calculate the residuals
      dof = n_elements(yfit[*,index])-n_elements(omodel->getparms())
      chisq = (1.0/dof)*total(residuals^2)

      this_str_out = '!4v!3!E2!N= '+strtrim(string(chisq),2)
      plot,xvals,residuals,psym = 0,xrange = xrange,xstyle = 1, $
         xtitle = xlabel,ytitle = 'Residuals',title = this_str_out
      plots,!x.crange,[-1.0,-1.0],thick = 2.0,linestyle = 2,/data
      plots,!x.crange,[1.0,1.0],thick = 2.0,linestyle = 2,/data
     endif
   endif
endif

;*(*self.plotres_win_info_ptr).xptr = !x
;*(*self.plotres_win_info_ptr).yptr = !y
return,1
end
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
function refine_app::refresh_image_window,event = event
compile_opt idl2,hidden
win_info = *self.im_win_info_ptr
winpix = win_info.winpix
winvis = win_info.winvis
wset,winpix
ret = self->plot_image_window(event = event)
wset,winvis
device,copy = [0,0,!d.x_size,!d.y_size,0,0,winpix]
return,1
end
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
function refine_app::refresh_imageres_window,event = event
compile_opt idl2,hidden
win_info = *self.imres_win_info_ptr
winpix = win_info.winpix
winvis = win_info.winvis
wset,winpix
ret = self->plot_imageres_window(event = event)
wset,winvis
device,copy = [0,0,!d.x_size,!d.y_size,0,0,winpix]
return,1
end
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
function refine_app::refresh_plot_window,event = event
compile_opt idl2,hidden
win_info = *self.plot_win_info_ptr
winpix = win_info.winpix
winvis = win_info.winvis
wset,winpix
ret = self->plot_plot_window(event = event)
wset,winvis
device,copy = [0,0,!d.x_size,!d.y_size,0,0,winpix]
return,1
end
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
function refine_app::refresh_plotres_window,event = event
compile_opt idl2,hidden
win_info = *self.plotres_win_info_ptr
winpix = win_info.winpix
winvis = win_info.winvis
wset,winpix
ret = self->plot_plotres_window(event = event)
wset,winvis
device,copy = [0,0,!d.x_size,!d.y_size,0,0,winpix]
return,1
end
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
function refine_app::select_data,event = event
compile_opt idl2,hidden
sel_leaves = widget_info(self.file_tree,/tree_select)
if n_elements(sel_leaves) eq 0 then return,0
*self.sel_leaf_ptr = sel_leaves

if (n_elements(sel_leaves) eq 1) and widget_info(sel_leaves[0],/valid_id) then begin
   widget_control,sel_leaves[0],get_uvalue = cmd
   wh = where(tag_names(cmd) eq 'DATA_OBJECT',count)
   if count eq 0 then return,0
   *self.pdata_sel = sel_leaves[0]
   *self.current_file_id_ptr = sel_leaves[0]
   ptr_free,self.pfun_sel & self.pfun_sel = ptr_new(/allocate_heap)
   ptr_free,self.pmodel_sel & self.pmodel_sel = ptr_new(/allocate_heap)
   odata = cmd.data_object
   ret = self->refresh_image_window(event = event)
   ret = self->refresh_imageres_window(event = event)
   ; Change the slider widget's maximum value
   ret = odata->get(ny = ny)
   widget_control,self.group_slider,get_value = old_index
   old_index = old_index[0]
   widget_control,self.group_slider,set_value = old_index < ny
   widget_control,self.group_slider,set_slider_max = ny > 1
   ret = self->refresh_plot_window(event = event)
   ret = self->refresh_plotres_window(event = event)
endif
if n_elements(sel_leaves) gt 1 and widget_info(sel_leaves[0],/valid_id) then begin
   count = 0
   for i = 0,n_elements(sel_leaves)-1 do begin
     uname = widget_info(sel_leaves[i],/uname)
     if uname eq 'DATA' then begin
      if count eq 0 then id_array = sel_leaves[i] else $
         id_array = [id_array,sel_leaves[i]]
      count = count + 1
     endif
   endfor
   if count gt 0 then begin
     *self.pdata_sel = id_array
     ptr_free,self.pfun_sel & self.pfun_sel = ptr_new(/allocate_heap)
     ptr_free,self.pmodel_sel & self.pmodel_sel = ptr_new(/allocate_heap)
   endif
endif
; Desensitize the model menus
ret = self->desensitize_model_menus()
return,1
end
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
function refine_app::select_model,event = event
compile_opt idl2,hidden

;ret = self->refresh_image_window(event = event)
;ret = self->refresh_imageres_window(event = event)
;ret = self->refresh_plot_window(event = event)
;ret = self->refresh_plotres_window(event = event)

sel_leaves = widget_info(self.file_tree,/tree_select)
if n_elements(sel_leaves) eq 0 then return,0
if not widget_info(sel_leaves[0],/valid_id) then return,0
*self.sel_leaf_ptr = sel_leaves
if n_elements(sel_leaves) gt 0 then begin
   count = 0
   for i = 0,n_elements(sel_leaves)-1 do begin
     if widget_info(sel_leaves[i],/valid_id) then begin
      uname = widget_info(sel_leaves[i],/uname)
      if uname eq 'MODEL' then begin
         if count eq 0 then id_array = sel_leaves[i] else $
           id_array = [id_array,sel_leaves[i]]
         count = count + 1
      endif
     endif
   endfor
   if count gt 0 then begin
     *self.pmodel_sel = id_array
     ptr_free,self.pfun_sel & self.pfun_sel = ptr_new(/allocate_heap)
     ptr_free,self.pdata_sel & self.pdata_sel = ptr_new(/allocate_heap)
   endif
   ; Now set the checks appropriately based on the current set values
   if count gt 0 then begin
     widget_control,id_array[0],get_uvalue = uval
     ret = uval.orefine->get(algorithm = alg)
     case alg of
     'LS':   button_set = [1,0,0]
     'GA':   button_set = [0,1,0]
     'GA/LS':  button_set = [0,0,1]
     else:
     endcase
     ls_id = widget_info(self.tlb,find_by_uname = 'LS')
     ga_id = widget_info(self.tlb,find_by_uname = 'GA')
     gals_id = widget_info(self.tlb,find_by_uname = 'GA/LS')
     widget_control,ls_id,set_button = button_set[0]
     widget_control,ga_id,set_button = button_set[1]
     widget_control,gals_id,set_button = button_set[2]
   endif
endif

if n_elements(*self.pmodel_sel) ne 0 then begin
   ret = self->sensitize_model_menus()

   ;; update the y values for the functions in the selected model, in case
   ;; the data yvalues have changed
   widget_control, (*self.pmodel_sel), get_uvalue=uval
   oModel = uval.oModel
   oChild = oModel->get(/all,count=nChild)
   if (nChild gt 0) then begin
      wParent = widget_info((*self.pmodel_sel),/parent)
      widget_control, wParent, get_uvalue=puval
      oData = puval.data_object
      ovoid = oData->get(yvals=yvals,xvals=xvals)
      for i=0,nChild-1 do $
         void = oChild[i]->set(yvalues=yvals,xvalues=xvals,/calculate)
   endif
endif

ret = self->refresh_image_window(event = event)
ret = self->refresh_imageres_window(event = event)
ret = self->refresh_plot_window(event = event)
ret = self->refresh_plotres_window(event = event)
return,1
end
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
function refine_app::read_dave,filename,path,event = event
compile_opt idl2,hidden
; check to see if this file has already been loaded
nobj = self.file_container->count()
if nobj gt 0 then begin
   oall = self.file_container->get(/all)
   for i = 0,nobj-1 do begin
     ret = oall[i]->get(filename = old_name)
     if old_name eq filename then return,0
   endfor
endif
self.workdir = path
odata = obj_new('model_data',filename = filename,path = self.workdir)
if not obj_valid(odata) then return,0

self.file_container->add,odata
; Add a leaf to the file tree
ret = odata->get(display_name = display_name,qty = qty,xvals = x,err=err)
qty_size = size(qty)
if qty_size[0] ne 2 then begin
   self.file_container->remove,odata
   obj_destroy,odata
   return,0
endif

; RTA - remove equally-spaced bin requirement for x
; Ok now determine if the independent variable x is equally-spaced
;nx = n_elements(x)
;diff = x[1:nx-1]-x[0:nx-2]
;s_dev = (moment(diff))[1]
;mean = (moment(diff))[0]
;rel_dev = s_dev/mean
;if rel_dev gt 0.01 then begin
;   strout = ['Data is irregularly spaced','Please rebin it before using RAINS']
;   void = dialog_message(dialog_parent = event.top,strout)
;   self.file_container->remove,odata
;   obj_destroy,odata
;   return,0
;endif

; RTA - add option for user to crop data
;res = getResLimits(x,qty,group_leader = event.top,title='Crop Signal data')
res = cropXData(x,qty,group_leader = event.top,title='Crop Signal data')
resLimit = res.limits 
i1 = where(x ge resLimit[0] and x le reslimit[1],count)
if count gt 5 then begin
   x = x[i1]
   qty = qty[i1,*]
   err = err[i1,*]
   ret = oData->set(qty=qty,xvals=x,err=err,/setOrig)
endif

folder_name = 'DATA'
; We're going to need to extract a lot of information from the leaf
; of the tree widget so we'll stuff it all into its user-value.
new_folder = widget_tree(self.file_root,value = display_name, $
                         uname = folder_name,/folder,        $
                         uvalue = {object:self, $ 
                                   method:'select_data', $
                                   data_object:odata, $
                                   res_ptr:ptr_new(/allocate_heap), $
                                   res_ptr_orig:ptr_new(/allocate_heap) $
                                  } $
                        )
;geom_1 = widget_info(self.file_tree,/geometry)
;print,geom_1

*self.current_file_id_ptr = new_folder
ret = odata->get(ny = ny)
widget_control,self.group_slider,get_value = old_index
old_index = old_index[0]
widget_control,self.group_slider,set_value = old_index < ny
widget_control,self.group_slider,set_slider_max = ny > 1
ret = self->refresh_image_window(event = event)
ret = self->refresh_imageres_window(event = event)
ret = self->refresh_plot_window(event = event)
ret = self->refresh_plotres_window(event = event)
; Set the widget id data field in the data object equal to the
; new leaf id created here.  This makes it easy to manipulate
; the widget tree with only the data object reference.
ret = odata->set(wid = new_folder)
; Now create a "MODEL_FOLDER" which is a child of the "FILE_FOLDER"
omodel = obj_new('refine_function_cont')
orefine = obj_new('refinement',omodel = omodel,odata = odata)
new_model_folder = widget_tree(new_folder,value = 'Model',   $
                               uname = 'MODEL', /folder,/expanded,               $
                               uvalue = {object:self, $ 
                                         method:'select_model', $
                                         omodel:omodel, $
                                         orefine:orefine} $
                              )
ret = omodel->setwid(wid = new_model_folder)

return,1
end

;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
function refine_app::load_dave,event = event
compile_opt idl2,hidden
filenames = DIALOG_PICKFILE(dialog_parent =  event.top,$
                 title = 'Select data file to restore',$
                 /read,filter = '*.dave',$
                 path = self.workdir,  $
                 get_path = path, $
                 /multiple_files)
; check if user has actually selected a file first
if filenames[0] eq '' then return,0
nfiles = n_elements(filenames)
for i = 0,nfiles-1 do begin
   ret = self->read_dave(filenames[i],path,event = event)
endfor

return,1
end
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
function qens_gaussian,x,area,center,fwhm
sig = fwhm/2.354
ygauss = (area/sqrt(2.0*!dpi*sig^2))*exp(-0.5*((x-center)/sig)^2)
return,ygauss
end
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
function qens_lorentzian,x,area,center,fwhm
gamma = 0.5*fwhm
ylorentz = (area*gamma/!dpi)/((x-center)^2+gamma^2)
return,ylorentz
end
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
function refine_app::load_test,event = event
compile_opt idl2,hidden

; Create the fake data set
; Create the resolution function
nx = 200 & xlo = -10.0 & xhi = 10.0 & dx = (xhi-xlo)/(nx-1.0)
x = xlo+dx*findgen(nx)
ny = 15 & ylo = 0.2 & yhi = 3.0 & dy = (yhi-ylo)/(ny-1.0)
q = ylo+dy*findgen(ny)
ux = 1+bytarr(nx) & uy = 1+bytarr(ny)
res = qens_gaussian(x,1.0,0.0,0.8)
resmat = res#uy
resptr = ptr_new(res)

; Create the data
; Define the EISF
radius = 0.7
eisf = ((1.0+2.0*sph_bessel(sqrt(3.0)*radius*q,0))/3.0)
yqens = (qens_lorentzian(x,1.0,0.0,4.0))#(1.0-eisf)
; Define the model function
ymodel = dblarr(nx,ny)
for i = 0,ny-1 do begin
   ymodel[*,i] = rmd_convol(x,resptr,yqens[*,i],pseudo_delta = [eisf[i],0.0])
endfor
ptr_free,resptr

; Now cycle through and create the data colored with Poisson noise
counts = 800.0
ymodel = ymodel*counts + 0.05*counts
ydata = dblarr(nx,ny)
for i = 0,ny-1 do begin
   for j = 0,nx-1 do begin
     ydata[j,i] = randomn(s,1,poisson = ymodel[j,i])
   endfor
endfor
y = ydata
dy = sqrt(y)
; Create the dave pointer
RET = CREATE_DAVE_POINTER( DAVEPTR,          $
               QTY = y,           $
               ERR = dy,         $
               XVALS = x,          $
               SPECIFICSTR = {x:x},     $
               XLABEL='E',       $
               XUNITS='energy:ueV',    $
               QTLABEL = 'Intensity (arb units)',  $
               YLABEL = 'Q',     $
               YUNITS = 'wavevector:A-1',  $
               YVALS = q         )
odata = obj_new('model_data',daveptr = daveptr)
heap_free,daveptr

if not obj_valid(odata) then return,0

self.file_container->add,odata
; Add a leaf to the file tree
ret = odata->get(display_name = display_name,qty = qty,xvals = x)
qty_size = size(qty)
if qty_size[0] ne 2 then begin
   self.file_container->remove,odata
   obj_destroy,odata
   return,0
endif

; Ok now determine if the independent variable x is equally-spaced
;nx = n_elements(x)
;diff = x[1:nx-1]-x[0:nx-2]
;s_dev = (moment(diff))[1]
;mean = (moment(diff))[0]
;rel_dev = s_dev/mean
;if rel_dev gt 0.01 then begin
;   strout = ['Data is irregularly spaced','Please rebin it before using RAINS']
;   void = dialog_message(dialog_parent = event.top,strout)
;   self.file_container->remove,odata
;   obj_destroy,odata
;   return,0
;endif

folder_name = 'DATA'
; We're going to need to extract a lot of information from the leaf
; of the tree widget so we'll stuff it all into its user-value.
new_folder = widget_tree(self.file_root,value = display_name, $
                         uname = folder_name,/folder,        $
                         uvalue = {object:self,            $
                                   method:'select_data',        $
                                   data_object:odata,         $
                                   res_ptr:ptr_new(/allocate_heap),    $
                                   res_ptr_orig:ptr_new(/allocate_heap)    $
                                  } $
                        )
;geom_1 = widget_info(self.file_tree,/geometry)
;print,geom_1

*self.current_file_id_ptr = new_folder
ret = odata->get(ny = ny)
widget_control,self.group_slider,get_value = old_index
old_index = old_index[0]
widget_control,self.group_slider,set_value = old_index < ny
widget_control,self.group_slider,set_slider_max = ny > 1
ret = self->refresh_image_window(event = event)
ret = self->refresh_imageres_window(event = event)
ret = self->refresh_plot_window(event = event)
ret = self->refresh_plotres_window(event = event)
; Set the widget id data field in the data object equal to the
; new leaf id created here.  This makes it easy to manipulate
; the widget tree with only the data object reference.
ret = odata->set(wid = new_folder)
; Now create a "MODEL_FOLDER" which is a child of the "FILE_FOLDER"
omodel = obj_new('refine_function_cont')
orefine = obj_new('refinement',omodel = omodel,odata = odata)
new_model_folder = widget_tree(new_folder,value = 'Model',   $
                               uname = 'MODEL', /folder,/expanded, $
                               uvalue = {object:self, $
                                         method:'select_model', $
                                         omodel:omodel, $
                                         orefine:orefine} $
                              )
ret = omodel->setwid(wid = new_model_folder)
return,1
end
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
function refine_app::clear_windows,event = event
wset,(*self.im_win_info_ptr).winvis
erase
wset,(*self.imres_win_info_ptr).winvis
erase
wset,(*self.plot_win_info_ptr).winvis
erase
wset,(*self.plotres_win_info_ptr).winvis
erase
return,1
end
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
function refine_app::show_function_definition,event = event
compile_opt idl2,hidden
nfun = n_elements(*self.pfun_sel)
if nfun eq 0 then return,0
fun_id = (*self.pfun_sel)[0]
if not widget_info(fun_id,/valid_id) then return,0
widget_control,fun_id,get_value = name
function_name = name + '.png'
filename = !DAVE_AUXILIARY_DIR+function_name
;if file_which(function_name) eq '' then begin
;  filename = function_name
;endif else begin
;  filename = file_which(function_name)
;endelse

if file_test(filename) then begin
   rains_disp_equation,   group_leader = event.top,      $
               png_image = filename
endif
return,1
end
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
function refine_app::remove_function,event = event
compile_opt idl2,hidden
nfun = n_elements(*self.pfun_sel)
if nfun eq 0 then return,0
fun_leaves = *self.pfun_sel

for i = 0,nfun-1 do begin
   ; Extract the function object
   if widget_info(fun_leaves[i],/valid_id) then begin
     widget_control,fun_leaves[i],get_uvalue = cmd
     ; Remove the function object from the model object
     parent_id = widget_info(fun_leaves[i],/parent)
     widget_control,parent_id,get_uvalue = model_cmd
     omodel = model_cmd.omodel
     omodel->remove,cmd.ofun
     obj_destroy,cmd.ofun
     widget_control,fun_leaves[i],/destroy
   endif
endfor

ptr_free,self.pfun_sel
self.pfun_sel = ptr_new(/allocate_heap)
return,1
end
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
function refine_app::remove_model,event = event
compile_opt idl2,hidden
nmodel = n_elements(*self.pmodel_sel)
if nmodel eq 0 then return,0
model_folders = *self.pmodel_sel

for i = 0,nmodel-1 do begin
   ; Extract the model object
   widget_control,model_folders[i],get_uvalue = model_cmd
   obj_destroy,model_cmd.omodel
   if obj_valid(model_cmd.orefine) then obj_destroy,model_cmd.orefine
   ; If there are any function children of this model folder then
   ; descend down the tree and destroy them
   first_child_id = widget_info(model_folders[i],/child)
   if widget_info(first_child_id,/valid_id) then begin
     sibling_id = widget_info(first_child_id,/sibling)
     while widget_info(sibling_id,/valid_id) do begin
      new_sibling_id = widget_info(sibling_id,/sibling)
      widget_control,sibling_id,/destroy
      sibling_id = new_sibling_id
     endwhile
   endif
   widget_control,model_folders[i],/destroy
endfor
ptr_free,self.pmodel_sel
self.pmodel_sel = ptr_new(/allocate_heap)
return,1
end
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
function refine_app::remove_file,event = event
compile_opt idl2,hidden
; This method removes the data object from memory and destroys all of the
; child widgets and the heap memory associated with them.
ndata = n_elements(*self.pdata_sel)
if ndata eq 0 then return,0
data_folders = *self.pdata_sel

for i = 0,ndata-1 do begin
   ; Extract the data object
   widget_control,data_folders[i],get_uvalue = data_cmd
   self.file_container->remove,data_cmd.data_object
   obj_destroy,data_cmd.data_object
   if ptr_valid(data_cmd.res_ptr) then ptr_free,data_cmd.res_ptr
   ; Now descend down the tree hierarchy destroying widgets and freeing up
   ; heap memory associated with each of them.

   model_id = widget_info(data_folders[i],/child)
   if widget_info(model_id,/valid_id) then begin
     msibling_id = model_id

     while widget_info(msibling_id,/valid_id) do begin

      new_msibling_id = widget_info(msibling_id,/sibling)

      function_id = widget_info(msibling_id,/child)
      if widget_info(function_id,/valid_id) then begin
         fsibling_id = function_id
         while widget_info(fsibling_id,/valid_id) do begin
           new_fsibling_id = widget_info(fsibling_id,/sibling)
           ; Destroy the function widget
           widget_control,fsibling_id,/destroy
           fsibling_id = new_fsibling_id
         endwhile
      endif

      ; Free up the heap memory for the model widget
      widget_control,msibling_id,get_uvalue = model_cmd
      obj_destroy,model_cmd.omodel
      if obj_valid(model_cmd.orefine) then obj_destroy,model_cmd.orefine

      ; Destroy the model widget
      widget_control,msibling_id,/destroy
      msibling_id = new_msibling_id

     endwhile

   endif
   widget_control,data_folders[i],/destroy
endfor
ptr_free,self.current_file_id_ptr
self.current_file_id_ptr = ptr_new(/allocate_heap)
ptr_free,self.sel_leaf_ptr
self.sel_leaf_ptr = ptr_new(/allocate_heap)
ret = self->clear_windows()
return,1
end
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
function refine_app::remove_file_highlight,event = event
ptr_free,self.sel_leaf_ptr
self.sel_leaf_ptr = ptr_new(/allocate_heap)
return,1
end
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
function refine_app::show_file_info,event = event
compile_opt idl2,hidden
; Call the non-modal widget and detect events coming from it
if n_elements(*self.pdata_sel) eq 0 then return,0
this_event = tag_names(event,/structure_name)
case this_event of
'RAFINS_FILE_INFO_EVENT':
'WIDGET_BUTTON':   $
   begin
     widget_control,(*self.pdata_sel)[0],get_uvalue = cmd
     odata = cmd.data_object
     ret = odata->get(treatment = treatment)
     rafins_file_info,  treatment,           $
               group_leader = event.top, $
               notify_ids = [event.id,event.top], $
               title = 'DAVE file information'
   end
else:
endcase
return,1
end
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
function refine_app::select_function,event = event
compile_opt idl2,hidden
ret = self->refresh_image_window(event = event)
ret = self->refresh_imageres_window(event = event)
ret = self->refresh_plot_window(event = event)
ret = self->refresh_plotres_window(event = event)
sel_leaves = widget_info(self.file_tree,/tree_select)
if n_elements(sel_leaves) eq 0 then return,0
*self.sel_leaf_ptr = sel_leaves
if n_elements(sel_leaves) gt 0 then begin
   count = 0
   for i = 0,n_elements(sel_leaves)-1 do begin
     if widget_info(sel_leaves[i],/valid_id) then begin
      uname = widget_info(sel_leaves[i],/uname)
      if uname eq 'FUNCTION' then begin
         if count eq 0 then id_array = sel_leaves[i] else $
           id_array = [id_array,sel_leaves[i]]
         count = count + 1
      endif
     endif
   endfor
   if count gt 0 then begin
     *self.pfun_sel = id_array
     ptr_free,self.pmodel_sel & self.pmodel_sel = ptr_new(/allocate_heap)
     ptr_free,self.pdata_sel & self.pdata_sel = ptr_new(/allocate_heap)
   endif
endif

widget_control, (*self.pfun_sel), get_uvalue=uval
wData = widget_info(widget_info((*self.pfun_sel),/parent),/parent)
widget_control, wData, get_uvalue=puval
oData = puval.data_object
oFun = uval.ofun
void = oData->get(yvals=yvals,xvals=xvals)
void = oFun->set(yvalues=yvals,xvalues=xvals,/calculate)

ret = self->refresh_image_window(event = event)
ret = self->refresh_imageres_window(event = event)
ret = self->refresh_plot_window(event = event)
ret = self->refresh_plotres_window(event = event)
; desensitize the model menus
ret = self->desensitize_model_menus()
return,1
end
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
function refine_app::pick_model,event = event
compile_opt idl2,hidden
if n_elements(*self.pmodel_sel) eq 0 then begin
   strout = 'You must highlight the model first!'
   void = dialog_message(dialog_parent = event.top,strout)
   return,0
endif
widget_control,event.id,get_value = val
; The actual function name is stored in the user-name of the
; widget.
uname = widget_info(event.id,/uname)
val = val[0] & uname = uname[0]

; Now get the data object
data_id = widget_info(*self.pmodel_sel,/parent)
widget_control,data_id,get_uvalue = cmd
odata = cmd.data_object
; Get the initial guesses from the function (and data) itself
ret = odata->get( qty = qty,      $
           nx = nx,      $
           ny = ny,      $
           xvals = xvals,   $
           yvals = yvals,   $
           xunits = xunits    )
ret = call_function(uname,       $
           [xvals,yvals],   $
           qty = qty,      $
           xunits = strmid(xunits,7),  $
           init_guess = init_guess,    $
           nx = nx,ny = ny,all_y = 0)

; Has the user entered a resolution function?  If not then we'll let
; him do it here with the Gaussian resolution function utility.
if n_elements(*cmd.res_ptr) eq 0 then begin
   void = self->create_gauss_res(event=event)
;   new_info = create_gauss_res_fun(odata,            $
;                  group_leader = event.top,  $
;                  cancel = cancel         )
;   if cancel then begin
;      heap_free, new_info
;      return,0
;   endif
;   (*cmd.res_ptr) = (*new_info.resptr)
;   heap_free, new_info          ;new_info.resptr
;   widget_control,data_id,set_uvalue = cmd
endif
widget_control,data_id,get_uvalue = cmd

; Create the function object
ofun = obj_new('refine_function',   name = uname,            $
                  xvalues = xvals,         $
                  yvalues = yvals,         $
                  res_ptr = cmd.res_ptr,        $
                  params = init_guess,       $
                  xunits = strmid(xunits,7),      $
                  all_y = 0               )
dx = xvals[1]-xvals[0]
ny = n_elements(yvals)

; Now add a function leaf to the currently selected model
model_id = *self.pmodel_sel
widget_control,model_id,get_uvalue = cmd
omodel = cmd.omodel
omodel->add,ofun
f_display_name = strmid(uname,4)
new_function = widget_tree(model_id,value = f_display_name,    $
   uname = 'FUNCTION', /folder,/expanded,            $
   uvalue =   { object:self,                 $
           method:'select_function',           $
           ofun:ofun                  })
ret = ofun->set(wid = new_function)
return,1
end


;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
function refine_app::restoreData,event = event
compile_opt idl2
if n_elements(*self.current_file_id_ptr) eq 0 then return,0

wData = *self.current_file_id_ptr ;*self.pdata_sel
if (~widget_info(wData,/valid)) then return, 0
                                ; Extract the data object
widget_control, wData, get_uvalue = data_cmd
oData = data_cmd.data_object
if (~obj_valid(oData) && ~obj_isa(oData,'MODEL_DATA')) then return, 0

void = oData->restore_data()

; also update grps to fit for resolution, if loaded
res_ptr = data_cmd.res_ptr
ores_ptr = data_cmd.res_ptr_orig
if (ptr_valid(res_ptr) && (n_elements(*res_ptr) ne 0)) then begin
   void = oData->get(fitGrps=curGrps)
   i0 = curGrps - 1
   (*res_ptr) = {x:(*res_ptr).x,y:(*ores_ptr).y[i0],z:(*ores_ptr).z[*,i0]}
endif

;; update the y values for the functions in the selected model, in case
;; the data yvalues have changed
;wChild = widget_info(wData,/child)
;widget_control, (wChild), get_uvalue=uval
;oModel = uval.oModel
;oChild = oModel->get(/all,count=nChild)
;if (nChild gt 0) then begin
;   ovoid = oData->get(yvals=yvals,xvals=xvals)
;   for i=0,nChild-1 do $
;      void = oChild[i]->set(yvalues=yvals,xvalues=xvals,/calculate)
;endif

ret = self->refresh_image_window(event = event)
ret = self->refresh_imageres_window(event = event)
ret = self->refresh_plot_window(event = event)
ret = self->refresh_plotres_window(event = event)

return, 1
end

;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
function refine_app::rebinData,event = event
compile_opt idl2
if n_elements(*self.current_file_id_ptr) eq 0 then return,0

wData = *self.current_file_id_ptr ;*self.pdata_sel
if (~widget_info(wData,/valid)) then return, 0

widget_control, wData, get_uvalue = uval
oData = uval.data_object
if (~obj_valid(oData) && ~obj_isa(oData,'MODEL_DATA')) then return, 0

void = oData->get(xvals=x,yvals=y,qty=qty,err=err,/getOrig)

res = widget_rebin(x,group_leader=event.top,title='Rebin Signal Data')
if (res.cancel eq 1) then return, 0

xmin = min(float(x), max=xmax)
xmin = res.min > xmin
xmax = res.max < xmax
xbin = res.binw

nx1 = fix((xmax - xmin)/xbin) + 1
if (nx1 le 5) then begin
   msg = ['New bin settings contains less than 5 points!','Rebinning not performed']
   void = dialog_message(/info,msg,dialog_parent=event.top)
   return, 0
endif
x1 = xmin + findgen(nx1)*xbin

; rebin the data
drebin,x,qty,err,x1,qty1,err1,/points,/to_points,err=ierr,emsg=msg
if (ierr ne 0) then begin
   void = dialog_message(/error,msg,dialog_parent=event.top)
   return, 0
endif

; modify data object with rebinned data
void = oData->set(qty=qty1,xvals=x1,err=err1,/setOrig)

; refresh displays
ret = self->refresh_image_window(event = event)
ret = self->refresh_imageres_window(event = event)
ret = self->refresh_plot_window(event = event)
ret = self->refresh_plotres_window(event = event)

return, 1
end

;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
function refine_app::cropXData,event = event
compile_opt idl2
if n_elements(*self.current_file_id_ptr) eq 0 then return,0

wData = *self.current_file_id_ptr ;*self.pdata_sel
if (~widget_info(wData,/valid)) then return, 0
                                ; Extract the data object
widget_control, wData, get_uvalue = data_cmd
oData = data_cmd.data_object
if (~obj_valid(oData) && ~obj_isa(oData,'MODEL_DATA')) then return, 0
void = oData->get(xvals=x,qty=qty,err=err,/getOrig)
void = oData->get(xvals=x1)
xmin = min(x1,max=xmax)

;res = getResLimits(x,qty,[xmin,xmax],group_leader =event.top,title='Crop Signal data')
res = cropXData(x,qty,[xmin,xmax],group_leader = event.top,title='Crop Signal data')
if (res.cancel eq 1) then return, 0

resLimit = res.limits           ;
i1 = where(x ge resLimit[0] and x le reslimit[1],count)
if count gt 5 then $
   ret = oData->set(qty=qty[i1,*],xvals=x[i1],err=err[i1,*],/setOrig)

ret = self->refresh_image_window(event = event)
ret = self->refresh_imageres_window(event = event)
ret = self->refresh_plot_window(event = event)
ret = self->refresh_plotres_window(event = event)

return, 1
end

;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
function refine_app::cropYData,event = event
compile_opt idl2
if n_elements(*self.current_file_id_ptr) eq 0 then return,0

wData = *self.current_file_id_ptr ;*self.pdata_sel
if (~widget_info(wData,/valid)) then return, 0
                                ; Extract the data object
widget_control, wData, get_uvalue = data_cmd
oData = data_cmd.data_object
if (~obj_valid(oData) && ~obj_isa(oData,'MODEL_DATA')) then return, 0
void = oData->get(yvals=y,qty=qty,err=err,/getOrig)
;void = oData->get(yvals=y1)
;ymin = min(y,max=ymax)
ny = n_elements(y)

res = cropydata(y,qty,[1,ny],group_leader = event.top,title='Crop Signal data in y')
if (res.cancel eq 1) then return, 0

grpLimits = res.limits 
i0 = (grpLimits[0]-1) > 0
i1 = (grpLimits[1]-1) < (ny-1)
if (i0 gt i1) then begin
   void = i0
   i0 = i1
   i1 = void
endif
count = i1 - i0 + 1
if count gt 2 then $
   ret = oData->set(qty=qty[*,i0:i1],yvals=y[i0:i1],err=err[*,i0:i1],/setOrig)

ret = self->refresh_image_window(event = event)
ret = self->refresh_imageres_window(event = event)
ret = self->refresh_plot_window(event = event)
ret = self->refresh_plotres_window(event = event)

return, 1
end

;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
function refine_app::grpsToFit,event = event
compile_opt idl2
if n_elements(*self.current_file_id_ptr) eq 0 then return,0

wData = *self.current_file_id_ptr ;*self.pdata_sel
if (~widget_info(wData,/valid)) then return, 0
                                ; Extract the data object
widget_control, wData, get_uvalue = uval
oData = uval.data_object
if (~obj_valid(oData) && ~obj_isa(oData,'MODEL_DATA')) then return, 0
void = oData->get(yvals=y,qty=qty,err=err,fitGrps=curGrps,/getCopy)
;void = oData->get(yvals=y1)
;ymin = min(y,max=ymax)
ny = n_elements(y)
res = widget_selectGroups(ny,curGrps=curGrps,group_leader = event.top,title='Select Groups to fit')
if (res.cancel eq 1) then return, 0

newGrps = res.groups
i0 = newGrps - 1                ;convert to indices
if (n_elements(newGrps) gt 1) then begin
   ret = oData->set(qty=qty[*,i0],yvals=y[i0],err=err[*,i0],fitGrps=newGrps,/setOrig)

   ; also update resolution if loaded
   res_ptr = uval.res_ptr
   ores_ptr = uval.res_ptr_orig
   if (ptr_valid(res_ptr) && (n_elements(*res_ptr) ne 0)) then begin
      (*res_ptr) = {x:(*res_ptr).x,y:(*ores_ptr).y[i0],z:(*ores_ptr).z[*,i0]}
   endif
endif

ret = self->refresh_image_window(event = event)
ret = self->refresh_imageres_window(event = event)
ret = self->refresh_plot_window(event = event)
ret = self->refresh_plotres_window(event = event)

return, 1
end

;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
function refine_app::rebinRes,event = event
compile_opt idl2
if n_elements(*self.current_file_id_ptr) eq 0 then return,0

wData = *self.current_file_id_ptr ;*self.pdata_sel
if (~widget_info(wData,/valid)) then return, 0

widget_control, wData, get_uvalue = uval
res_ptr = uval.res_ptr
if (~ptr_valid(res_ptr) || (n_elements(*res_ptr) eq 0)) then begin
   msg = ['No resolution data found']
   void = dialog_message(/info,msg,dialog_parent=event.top)
   return, 0
endif

x=(*res_ptr).x
qty=(*res_ptr).z
err=0.1*qty

res = widget_rebin(x,group_leader=event.top,title='Rebin Resolution Data')
if (res.cancel eq 1) then return, 0

xmin = min(float(x), max=xmax)
xmin = res.min > xmin
xmax = res.max < xmax
xbin = res.binw

nx1 = fix((xmax - xmin)/xbin) + 1
if (nx1 le 5) then begin
   msg = ['New bin settings contains less than 5 points!','Rebinning not performed']
   void = dialog_message(/info,msg,dialog_parent=event.top)
   return, 0
endif
x1 = xmin + findgen(nx1)*xbin

; rebin the data
drebin,x,qty,err,x1,qty1,err1,/points,/to_points,err=ierr,emsg=msg
if (ierr ne 0) then begin
   void = dialog_message(/error,msg,dialog_parent=event.top)
   return, 0
endif

; modify data object with rebinned data
(*res_ptr) = {x:x1,y:(*res_ptr).y,z:qty1}

; refresh displays
ret = self->refresh_image_window(event = event)
ret = self->refresh_imageres_window(event = event)
ret = self->refresh_plot_window(event = event)
ret = self->refresh_plotres_window(event = event)

return, 1
end

;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
function refine_app::restoreRes,event = event
compile_opt idl2
if n_elements(*self.current_file_id_ptr) eq 0 then return,0

wData = *self.current_file_id_ptr ;*self.pdata_sel
if (~widget_info(wData,/valid)) then return, 0

widget_control, wData, get_uvalue = uval
res_ptr = uval.res_ptr
res_ptr_orig = uval.res_ptr_orig
if (~ptr_valid(res_ptr) || ~ptr_valid(res_ptr_orig) || $
    (n_elements(*res_ptr) eq 0) || (n_elements(*res_ptr_orig) eq 0)) then begin
   msg = ['No resolution data found']
   void = dialog_message(/info,msg,dialog_parent=event.top)
   return, 0
endif

(*res_ptr) = (*res_ptr_orig) 

ret = self->refresh_image_window(event = event)
ret = self->refresh_imageres_window(event = event)
ret = self->refresh_plot_window(event = event)
ret = self->refresh_plotres_window(event = event)

return, 1
end

;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
function refine_app::cropXRes,event = event
compile_opt idl2
if n_elements(*self.current_file_id_ptr) eq 0 then return,0

wData = *self.current_file_id_ptr ;*self.pdata_sel
if (~widget_info(wData,/valid)) then return, 0
                                ; Extract the data object
widget_control, wData, get_uvalue = uval
res_ptr = uval.res_ptr
res_ptr_orig = uval.res_ptr_orig
if (~ptr_valid(res_ptr) || (n_elements(*res_ptr) eq 0)) then begin
   msg = ['No resolution data found']
   void = dialog_message(/info,msg,dialog_parent=event.top)
   return, 0
endif

x=(*res_ptr).x
qty=(*res_ptr).z
;x1 = (*res_ptr).x
xmin = min(x,max=xmax)

;res = getResLimits(x,qty,[xmin,xmax],group_leader = event.top,title='Crop Resolution data')
res = cropXData(x,qty,[xmin,xmax],group_leader = event.top,title='Crop Resolution data')

if (res.cancel eq 1) then return, 0

resLimit = res.limits 
i1 = where(x ge resLimit[0] and x le reslimit[1],count)
if count gt 5 then (*res_ptr) = {x:x[i1],y:(*res_ptr).y,z:qty[i1,*]}

ret = self->refresh_image_window(event = event)
ret = self->refresh_imageres_window(event = event)
ret = self->refresh_plot_window(event = event)
ret = self->refresh_plotres_window(event = event)

return, 1
end

;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
function refine_app::cropYRes,event = event
compile_opt idl2
if n_elements(*self.current_file_id_ptr) eq 0 then return,0

wData = *self.current_file_id_ptr ;*self.pdata_sel
if (~widget_info(wData,/valid)) then return, 0
                                ; Extract the data object
widget_control, wData, get_uvalue = uval
res_ptr = uval.res_ptr
res_ptr_orig = uval.res_ptr_orig
if (~ptr_valid(res_ptr) || (n_elements(*res_ptr) eq 0)) then begin
   msg = ['No resolution data found']
   void = dialog_message(/info,msg,dialog_parent=event.top)
   return, 0
endif

y=(*res_ptr).y
qty=(*res_ptr).z
ny = n_elements(y)

res = cropydata(y,qty,[1,ny],group_leader = event.top,title='Crop Resolution data in y')
if (res.cancel eq 1) then return, 0

grpLimits = res.limits 
i0 = (grpLimits[0] - 1) > 0
i1 = (grpLimits[1] - 1) < (ny-1)
if (i0 gt i1) then begin
   void = i0
   i0 = i1
   i1 = void
endif
count = i1 - i0 + 1
if count gt 2 then $
   (*res_ptr) = {x:(*res_ptr).x,y:y[i0:i1],z:qty[*,i0:i1]}

ret = self->refresh_image_window(event = event)
ret = self->refresh_imageres_window(event = event)
ret = self->refresh_plot_window(event = event)
ret = self->refresh_plotres_window(event = event)

return, 1
end


;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
function refine_app::load_dave_res,event = event
compile_opt idl2,hidden
if n_elements(*self.current_file_id_ptr) eq 0 then return,0
; Open up a dialog for user to select the dave file
filename = DIALOG_PICKFILE(dialog_parent =   event.top,$
                 title = 'Select DAVE data file for resolution',$
                 /read,filter = '*.dave',$
                 path = self.workdir,  $
                 get_path = path)
; check if user has actually selected a file first
if filename[0] eq '' then return,0
restore,filename

; Get the resolution function data out
ret_val = get_dave_ptr_contents(            $
               daveptr,           $
               instrument = instrument,  $
               qty = qty,          $
               qtunits = qtunits,      $
               qtlabel = qtlabel,      $
               err = err,          $
               xvals = xvals,         $
               xtype = xtype,         $
               xunits = xunits,      $
               xlabel = xlabel,      $
               yvals = yvals,         $
               ytype = ytype,         $
               yunits = yunits,      $
               ylabel = ylabel,      $
;               specificstr = specificstr,   $
               treatment = treatment,    $
               ermsg = errmsg         )
; Free up the dave data pointer
heap_free,daveptr
; Compare the independent variables of the resolution function to that
; of the current data set
ny = n_elements(yvals) & nx = n_elements(xvals)

; if histogram data, convert to point mode
if n_elements(xvals) gt (size(qty))[1] then begin
   nx = n_elements(xvals)
   x = 0.5*(xvals[1:nx-1]+xvals[0:nx-2])
   xvals = x
   nx = n_elements(xvals)
endif

leaf_id = (*self.current_file_id_ptr)
widget_control,leaf_id,get_uvalue = cmd
; Get out the x,y,qty, and dqty from the "data"
ret = cmd.data_object->get(ny=ndy,/getCopy)
if (ndy ne ny) then begin
   msg = ['Signal and resolution dataset groups do not match' $
          ,'There are '+strtrim(string(ndy),2)+' groups in signal dataset' $
          ,'There are '+strtrim(string(ny),2)+' groups in resolution dataset' $
          ,'Resolution and signal must have the same number of groups!']
   void = dialog_message(dialog_parent = event.top,msg)
   return,0
endif

; RTA - no need to interpolate resolution to the same x as the
; signal. Store res in its own structure, {x,y,qty,limits}
;rinterp = dblarr(ndx,ndy)
;for i = 0,ny-1 do begin
;   rinterp[*,i] = interpol(qty[*,i],xvals,xdata_vals)
;endfor

; store original data
xmin = min(xvals,max=xmax)
(*cmd.res_ptr_orig) = {x:xvals,y:yvals,z:qty} ;rinterp;qty

; Restrict resolution data to whithin the allowed limits specified by
; user
;res = getResLimits(xvals,qty,group_leader = event.top,title='Crop Resolution data')
res = cropXData(xvals,qty,group_leader = event.top,title='Crop Resolution data')
resLimit = res.limits 
i1 = where(xvals ge resLimit[0] and xvals le reslimit[1],count)
if count gt 5 then begin
   xvals = xvals[i1]
   qty = qty[i1,*]   
endif
;    for i=0,nrgroups-1 do begin
;       ;; B/c of truncation, normalize the res function again
;       resData[*,i] = resData[*,i]/int_tabulated(xres,resData[*,i])
;    endfor

;    (*self.resPtr) = {x:xres,y:resStr.y,data:resdata,rlimit:reslimit}
; endif else $
;    (*self.resPtr) = resStr


; Ok, it looks ok now so we normalize the resolution function data
for i = 0,ny-1 do begin
   ;sf = int_tabulated(xdata_vals,rinterp[*,i])
   ;rinterp[*,i] = rinterp[*,i]/sf
   qty[*,i] = qty[*,i]/int_tabulated(xvals,qty[*,i])
endfor


; ...and finally stuff the resolution function pointer into the leaf widget id
xmin = min(xvals,max=xmax)
(*cmd.res_ptr) = {x:xvals,y:yvals,z:qty} ;rinterp;qty

widget_control,leaf_id,set_uvalue = cmd

; make restore, crop and rebin buttons sensitive
;unames = ['CROPRES','REBRES','RESRES']
;for i=0,n_elements(unames)-1 do begin
;   wID = widget_info(event.top,find_by_uname=unames[i])
;   if (widget_info(wID,/valid)) then widget_control, wID, sensitive = 1
;endfor

return,1
end
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
function refine_app::create_gauss_res,event = event
compile_opt idl2,hidden

; Call the non-modal widget and detect events coming from it
if n_elements(*self.current_file_id_ptr) eq 0 then return,0
;if n_elements(*self.sel_leaf_ptr) eq 0 then return,0
leaf_id = (*self.current_file_id_ptr);(*self.sel_leaf_ptr)[0]
widget_control,leaf_id,get_uvalue = cmd
odata = cmd.data_object
new_info = create_gauss_res_fun(odata,            $
                 group_leader = event.top,   $
                 cancel = cancel       )

if cancel then return,0
(*cmd.res_ptr) = (*new_info.resptr)
(*cmd.res_ptr_orig) = (*new_info.resptr)

ptr_free,new_info.resptr

widget_control,leaf_id,set_uvalue = cmd
return,1
end
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
function refine_app::change_group,event = event
compile_opt idl2,hidden
nobj = self.file_container->count()
if nobj eq 0 then return,0
ret = self->refresh_plot_window(event = event)
ret = self->refresh_plotres_window(event = event)
return,1
end
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
function refine_app::im_win_events,event = event
compile_opt idl2,hidden
nobj = self.file_container->count()
if nobj eq 0 then return,0
iminfo = *self.im_win_info_ptr
case event.type of
0: begin    ; button press
     (*self.im_win_info_ptr).mouse = event.press
     if (*self.im_win_info_ptr).mouse eq 4 then begin
      (*self.im_win_info_ptr).autoscale = 1

       !x = *(*self.im_win_info_ptr).xPtr
       !y = *(*self.im_win_info_ptr).yPtr
     ret = self->refresh_image_window()
     ret = self->refresh_imageres_window()
     endif
     if (*self.im_win_info_ptr).mouse eq 1 then begin
       (*self.im_win_info_ptr).xPos = event.x
       (*self.im_win_info_ptr).yPos = event.y
       !x = *(*self.im_win_info_ptr).xPtr
       !y = *(*self.im_win_info_ptr).yPtr
       wset,(*self.im_win_info_ptr).winvis
       device,copy = [0,0,!d.x_size,!d.y_size,0,0,(*self.im_win_info_ptr).winpix]
       (*self.im_win_info_ptr).autoscale = 0
     endif
   end
1: begin ; button release
    if (*self.im_win_info_ptr).mouse eq 1 then begin
     !x = *(*self.im_win_info_ptr).xPtr
     !y = *(*self.im_win_info_ptr).yPtr
      xll = Min([(*self.im_win_info_ptr).xpos, event.x], Max=xur)
      yll = Min([(*self.im_win_info_ptr).ypos, event.y], Max=yur)
     ll = convert_coord(xll,yll,/device,/to_data)
     ur = convert_coord(xur,yur,/device,/to_data)
     (*self.im_win_info_ptr).xrange = [ll[0],ur[0]]
     (*self.im_win_info_ptr).yrange = [ll[1],ur[1]]
     ret = self->refresh_image_window()
     ret = self->refresh_imageres_window(event = event)
     (*self.im_win_info_ptr).mouse = 0B
    endif
    if (*self.im_win_info_ptr).mouse eq 4 then begin
     !x = *(*self.im_win_info_ptr).xPtr
     !y = *(*self.im_win_info_ptr).yPtr
     ret = self->refresh_image_window()
     (*self.im_win_info_ptr).mouse = 0B
    endif
   end
2: begin ; mouse motion
     if (*self.im_win_info_ptr).mouse eq 1 then begin
        xc = [(*self.im_win_info_ptr).xpos,event.x,event.x,$
              (*self.im_win_info_ptr).xpos,$
              (*self.im_win_info_ptr).xpos]
        yc = [(*self.im_win_info_ptr).ypos,(*self.im_win_info_ptr).ypos,$
              event.y,event.y,$
              (*self.im_win_info_ptr).ypos]
        wset,(*self.im_win_info_ptr).winVis
        device,copy = [0,0,!d.x_size,!d.y_size,0,0,(*self.im_win_info_ptr).winPix]
        plots,xc,yc,/device
     endif
   end
else:
endcase
return,1
end
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
function refine_app::plot_win_events,event = event
compile_opt idl2,hidden
nobj = self.file_container->count()
if nobj eq 0 then return,0
plotinfo = *self.plot_win_info_ptr
case event.type of
0: begin    ; button press
     (*self.plot_win_info_ptr).mouse = event.press
     if (*self.plot_win_info_ptr).mouse eq 4 then begin
      (*self.plot_win_info_ptr).autoscale = 1

       !x = *(*self.plot_win_info_ptr).xPtr
       !y = *(*self.plot_win_info_ptr).yPtr
     ret = self->refresh_plot_window()
     ret = self->refresh_plotres_window(event = event)
     endif
     if (*self.plot_win_info_ptr).mouse eq 1 then begin
       (*self.plot_win_info_ptr).xPos = event.x
       (*self.plot_win_info_ptr).yPos = event.y
       !x = *(*self.plot_win_info_ptr).xPtr
       !y = *(*self.plot_win_info_ptr).yPtr
       wset,(*self.plot_win_info_ptr).winvis
       device,copy = [0,0,!d.x_size,!d.y_size,0,0,(*self.plot_win_info_ptr).winpix]
       (*self.plot_win_info_ptr).autoscale = 0
     endif
   end
1: begin ; button release
    if (*self.plot_win_info_ptr).mouse eq 1 then begin
     !x = *(*self.plot_win_info_ptr).xPtr
     !y = *(*self.plot_win_info_ptr).yPtr
      xll = Min([(*self.plot_win_info_ptr).xpos, event.x], Max=xur)
      yll = Min([(*self.plot_win_info_ptr).ypos, event.y], Max=yur)
     ll = convert_coord(xll,yll,/device,/to_data)
     ur = convert_coord(xur,yur,/device,/to_data)
     (*self.plot_win_info_ptr).xrange = [ll[0],ur[0]]
     (*self.plot_win_info_ptr).yrange = [ll[1],ur[1]]
     ret = self->refresh_plot_window()
     ret = self->refresh_plotres_window(event = event)
     (*self.plot_win_info_ptr).mouse = 0B
    endif
    if (*self.plot_win_info_ptr).mouse eq 4 then begin
     !x = *(*self.plot_win_info_ptr).xPtr
     !y = *(*self.plot_win_info_ptr).yPtr
     ret = self->refresh_plot_window()
     ret = self->refresh_plotres_window(event = event)
     (*self.plot_win_info_ptr).mouse = 0B
    endif
   end
2: begin ; mouse motion
     if (*self.plot_win_info_ptr).mouse eq 1 then begin
        xc = [(*self.plot_win_info_ptr).xpos,event.x,event.x,$
              (*self.plot_win_info_ptr).xpos,$
              (*self.plot_win_info_ptr).xpos]
        yc = [(*self.plot_win_info_ptr).ypos,(*self.plot_win_info_ptr).ypos,$
              event.y,event.y,$
              (*self.plot_win_info_ptr).ypos]
        wset,(*self.plot_win_info_ptr).winVis
        device,copy = [0,0,!d.x_size,!d.y_size,0,0,(*self.plot_win_info_ptr).winPix]
        plots,xc,yc,/device
     endif
   end
else:
endcase
return,1
end
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
function refine_app::add_model,event = event
compile_opt idl2,hidden
; Has the user selected a data folder
ndata = n_elements(*self.pdata_sel)
if ndata eq 0 then begin
   strout = 'A model can only be added to a data folder!'
   void = dialog_message(dialog_parent = event.top,strout)
   return,0
endif
data_folder = (*self.pdata_sel)[0]
widget_control,data_folder,get_uvalue = data_cmd
odata = data_cmd.data_object
; Add the new model folder
omodel = obj_new('refine_function_cont')
orefine = obj_new('refinement',odata = odata,omodel = omodel)
model_folder = widget_tree(data_folder,value = 'Model',      $
   uname = 'MODEL', /folder,/expanded,               $
   uvalue =   { object:self,                 $
           method:'select_model',            $
           omodel:omodel,               $
           orefine:orefine})

ret = omodel->setwid(wid = model_folder)
return,1
end
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
function refine_app::ls_params,event = event
compile_opt idl2,hidden
; Launch a modal dialog containing the least-squares information
n_model = n_elements(*self.pmodel_sel)
if n_model eq 0 then return,0
widget_control,(*self.pmodel_sel)[0],get_uvalue = uval
omodel = uval.omodel
orefine = uval.orefine
ret = orefine->get_ls_parms(xtol = xtol,gtol = gtol,ftol = ftol,itmax = itmax)
info = {xtol:xtol,gtol:gtol,ftol:ftol,itmax:itmax}
new_info = ls_dialog(group_leader = event.top,info)
ret = orefine->set_ls_parms   ( xtol = new_info.xtol,      $
                 itmax = new_info.itmax,      $
                 gtol = new_info.gtol,      $
                 ftol = new_info.ftol      )
return,1
end
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
function refine_app::modify_function,event = event
compile_opt idl2,hidden
; Call the non-modal widget and detect events coming from it
if n_elements(*self.pfun_sel) eq 0 then return,0
widget_control,(*self.pfun_sel)[0],get_uvalue = cmd
ofunction = cmd.ofun
this_event = tag_names(event,/structure_name)
case this_event of
'RAFINS_PINFO_EVENT':   $
   begin
     if event.cancel ne 1 then begin   ; update the display
      ret = self->refresh_plot_window(event = event)
      ret = self->refresh_plotres_window(event = event)
      ret = self->refresh_image_window(event = event)
      ret = self->refresh_imageres_window(event = event)

     endif
   end
'WIDGET_BUTTON':   $
   begin
     rafins_pinfo,   ofunction,             $
            group_leader = event.top,      $
            notify_ids = [event.id,event.top]
   end
else:
endcase

return,1
end
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
function refine_app::show_fit_report,event = event
compile_opt idl2,hidden
; Which model is currently selected?
n_model = n_elements(*self.pmodel_sel)
if n_model eq 0 then return,0
widget_control,(*self.pmodel_sel)[0],get_uvalue = uval
if not obj_valid(uval.orefine) then return,0
orefine = uval.orefine
ret = orefine->fit_report(output = output)
if n_elements(output) eq 0 then return,0
rafins_file_info, output,               $
           group_leader = event.top,       $
           notify_ids = [event.id,event.top],   $
           title = 'Fit information',      $
           modal = 1
return,1
end
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
function refine_app::show_correl_report,event = event
thisEvent = tag_names(event,/structure_name)
case thisEvent of
'WIDGET_BUTTON':  $
   begin
; Which model is currently selected?
     n_model = n_elements(*self.pmodel_sel)
     if n_model eq 0 then return,0
     widget_control,(*self.pmodel_sel)[0],get_uvalue = uval
     if not obj_valid(uval.orefine) then return,0
     orefine = uval.orefine
     ret = orefine->get(pcor = pcor)
     if ret eq 0 then return,0

     nmax = 10
     parmnames = uval.omodel->getparmnames()
     bad_index = where(finite(pcor) ne 1, count_bad)
     if count_bad gt 0 then pcor[bad_index] = -1.e6

     rains_display_correlation,  pcor,   $
                  parmnames,  $
                  group_leader = event.top,  $
                  notify_ids = [event.id,event.top]
   end
else:
endcase


return,1
end
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
function refine_app::select_ls,event = event
compile_opt idl2,hidden
; Has a model been selected?
nmodel = n_elements(*self.pmodel_sel)
if n_elements(nmodel) eq 0 then return,0
model_id = *self.pmodel_sel
widget_control,model_id,get_uvalue = uval
omodel = uval.omodel
orefine = uval.orefine
ret = orefine->set(algorithm = 'LS')

; Now set the checks appropriately
ls_id = widget_info(self.tlb,find_by_uname = 'LS')
ga_id = widget_info(self.tlb,find_by_uname = 'GA')
gals_id = widget_info(self.tlb,find_by_uname = 'GA/LS')
button_set = [1,0,0]
widget_control,ls_id,set_button = button_set[0]
widget_control,ga_id,set_button = button_set[1]
widget_control,gals_id,set_button = button_set[2]
return,1
end
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
function refine_app::select_ga,event = event
compile_opt idl2,hidden
; Has a model been selected?
nmodel = n_elements(*self.pmodel_sel)
if n_elements(nmodel) eq 0 then return,0
model_id = *self.pmodel_sel
widget_control,model_id,get_uvalue = uval
omodel = uval.omodel
orefine = uval.orefine
ret = orefine->set(algorithm = 'GA')
; Now set the checks appropriately
ls_id = widget_info(self.tlb,find_by_uname = 'LS')
ga_id = widget_info(self.tlb,find_by_uname = 'GA')
gals_id = widget_info(self.tlb,find_by_uname = 'GA/LS')
button_set = [0,1,0]
widget_control,ls_id,set_button = button_set[0]
widget_control,ga_id,set_button = button_set[1]
widget_control,gals_id,set_button = button_set[2]
return,1
end
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
function refine_app::select_gals,event = event
compile_opt idl2,hidden
; Has a model been selected?
nmodel = n_elements(*self.pmodel_sel)
if n_elements(nmodel) eq 0 then return,0
model_id = *self.pmodel_sel
widget_control,model_id,get_uvalue = uval
omodel = uval.omodel
orefine = uval.orefine
; Now set the checks appropriately
ls_id = widget_info(self.tlb,find_by_uname = 'LS')
ga_id = widget_info(self.tlb,find_by_uname = 'GA')
gals_id = widget_info(self.tlb,find_by_uname = 'GA/LS')
button_set = [0,0,1]
widget_control,ls_id,set_button = button_set[0]
widget_control,ga_id,set_button = button_set[1]
widget_control,gals_id,set_button = button_set[2]
ret = orefine->set(algorithm = 'GA/LS')
return,1
end
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
function refine_app::fit_model,event = event
compile_opt idl2,hidden
; Has a model been selected?
nmodel = n_elements(*self.pmodel_sel)
if nmodel gt 0 then begin
   widget_control,(*self.pmodel_sel)[0],get_uvalue = uval
   count = uval.omodel->count()
   if count eq 0 then return,0
   stop_base = widget_base(group_leader = event.top,title = 'RAINS',/col,modal=1) ;RTA make modal
   ;centertlb,stop_base ; RTA - remove centering
   if !d.name eq 'WIN' then begin
      thisFont = "Comic Sans MS*Bold*20"
     stop_but = widget_button(stop_base,value = 'Interrupt fitting', $
      xsize = 150,ysize = 50,font = thisFont)
     void = widget_label(stop_base,value = 'Iteration',font = thisFont)
      txt_field = widget_text(stop_base,value = '',xsize = 5,font = thisFont)
      void = widget_label(stop_base,value = 'chi-squared',font = thisFont)
      chisq_field = widget_text(stop_base,value = '',font = thisFont)
   endif else begin
     stop_but = widget_button(stop_base,value = 'Interrupt fitting', $
      xsize = 150,ysize = 50)
     void = widget_label(stop_base,value = 'Fit iteration')
     txt_field = widget_text(stop_base,value = '',xsize = 5)
      void = widget_label(stop_base,value = 'chi-squared')
      chisq_field = widget_text(stop_base,value = '')
   endelse

   widget_control,stop_base,/realize
   for i = 0,nmodel-1 do begin
     ; Get the model information
     model_id = (*self.pmodel_sel)[i]
     widget_control,model_id,get_uvalue = model_cmd
     omodel = model_cmd.omodel
     nfuns = omodel->count()
     if nfuns eq 0 then return,0
     ; Get the data information
     data_id = widget_info(model_id,/parent)
     widget_control,data_id,get_uvalue = data_cmd
     odata = data_cmd.data_object
     res_ptr = data_cmd.res_ptr
     orefine = model_cmd.orefine
     ret = orefine->set(   resolution = *res_ptr,                $
               algorithm = 'LS',                  $
               iterargs = {stopBut:stop_but,            $
                     txt_field:txt_field,           $
                     chisq_field:chisq_field}        $
               )

     ret = orefine->fit()
     ; get the correlation matrix
     ret = orefine->get(pcor = pcor)
     ret = self->refresh_image_window(event = event)
     ret = self->refresh_imageres_window(event = event)
     ret = self->refresh_plot_window(event = event)
     ret = self->refresh_plotres_window(event = event)
   endfor
   if widget_info(stop_base,/valid_id) then widget_control,stop_base,/destroy
endif

return,1
end
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
function refine_app::select_fit_range,event = event
compile_opt idl2,hidden
; Determine what the currently selected data set is...
ndata = n_elements(*self.current_file_id_ptr)
if ndata eq 0 then return,0
; Has the user selected a model_id?
nmodel = n_elements(*self.pmodel_sel)
if nmodel eq 0 then return,0
; Are the data id and model id valid widgets?
data_id = (*self.current_file_id_ptr)[0]
model_id = (*self.pmodel_sel)[0]
if not widget_info(data_id,/valid_id) then return,0
if not widget_info(model_id,/valid_id) then return,0
; Is the parent of the model ID identical to the data ID?
if widget_info(model_id,/parent) ne data_id then return,0
; Ok...now we may proceed...
widget_control,model_id,get_uvalue = model_val
widget_control,data_id,get_uvalue = data_val

new_info = refine_sel_range(data_val.data_object,   $
               model_val.orefine,      $
               group_leader = event.top  )

xindex = *new_info.xptr & yindex = *new_info.yptr
ptr_free,new_info.xptr,new_info.yptr
ret = model_val.orefine->set(xindex = xindex,yindex = yindex)
ret = self->refresh_image_window(event = event)
ret = self->refresh_imageres_window(event = event)
ret = self->refresh_plot_window(event = event)
ret = self->refresh_plotres_window(event = event)
return,1
end
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
function refine_app::display_help,event = event
;pdf_file = file_which('rains_models.pdf',/include_current_dir)
pdf_file = !DAVE_AUXILIARY_DIR+'rains_models.pdf'
void = launch_help(pdf_file,tlb = event.top)
return,1
end
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
function refine_app::save_current_config,event = event
compile_opt idl2,hidden
save,self,filename = 'c:\bhd\dave_demo\test_config.sav'
return,1
end
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
function refine_app::restore_config,event = event
compile_opt idl2,hidden
restore,filename = 'c:\bhd\dave_demo\test_config.sav'

return,1
end
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
function create_rains_test_data,event = event
compile_opt idl2,hidden
if n_elements(event) eq 0 then begin
   info = get_test_model_data()
endif else begin
   info = get_test_model_data(group_leader = event.top)
endelse
qty = fltarr(info.nx,info.ny)
err = fltarr(info.ny,info.ny)
dx = (info.xhi-info.xlo)/(info.nx-1.0)
dy = (info.yhi-info.ylo)/(info.ny-1.0)
x = info.xlo+dx*findgen(info.nx)
y = info.ylo+dy*findgen(info.ny)
; Create a DAVE pointer
xunits = 'energy:'+strtrim(info.xunits,2)
yunits = 'wavevector:A-1'
qtunits = 'arb units'
qtlabel = 'Intensity (arb units)'
if info.xunits eq 'meV' then xlabel = '!6E (meV)' else $
   xlabel = '!6E (!4l!6eV)'
instrument = 'Simulated data'
ylabel = '!6Q (!6!sA!r!u!9 %!6!n!E-1!N)'
ret = create_dave_pointer( $
               daveptr,           $
               instrument = instrument,  $
               qty = qty,          $
               qtunits = qtunits,      $
               qtlabel = qtlabel,      $
               err = err,          $
               xvals = x,          $
               xtype = 'POINTS',      $
               xunits = xunits,      $
               xlabel = xlabel,      $
               yvals = y,          $
               ytype = 'POINTS',      $
               yunits = yunits,      $
               ylabel = ylabel,      $
               specificstr = {x:x,y:y},  $
               treatment = 'None')
;; Now pass this DAVE pointer into the MODEL_DATA object class
otestdata = obj_new('model_data',daveptr = daveptr)
heap_free,daveptr
return,otestdata
end
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
function refine_app::build_gui
compile_opt idl2,hidden
; This GUI is composed of a main panel that displays the tree widget and
; image of the data (with the the residuals) and a detached panel displays
; the data one group at a time (user controls the display with a slider
; determining the group he/she wants to display).
register_name = 'RAINS'
if xregistered(register_name) then return,0
title = 'RAINS (Refinement Application for Inelastic Neutron Scattering)'
self.tlb = widget_base(group_leader = self.group_leader,/row, $
   title = title,mbar = bar,uname = 'TLB', $
   tlb_size_events = 1,tlb_frame_attr = 8)

; Build the file menu
file_menu = widget_button(bar,value = 'File',/menu)
save_button = widget_button(file_menu,value = 'Save current config', $
   uvalue = {object:self,method:'save_current_config'},sensitive = 0)
restore_button = widget_button(file_menu,value = 'Restore config', $
   uvalue = {object:self,method:'restore_config'},sensitive = 0)
model_menu = widget_button(bar,value = 'Models',/menu)
print_menu = widget_button(bar,value = 'Printing options',/menu)
help_menu = widget_button(bar,value = 'Help',/menu)
void = widget_button(help_menu,value = 'Display PDF help', $
   uvalue = {object:self,method:'display_help'})
void = widget_button(help_menu,value = 'About RAINS', $
   uvalue = {object:self,method:'about'})
; Populate the FILE menu
void = widget_button(file_menu,value = 'Load test data', $
   uvalue = {object:self,method:'load_test'})
void = widget_button(file_menu,value = 'Load DAVE file', $
   uvalue = {object:self,method:'load_dave'})
void = widget_button(file_menu,value = 'QUIT',  $
   uvalue = {object:self,method:'quit'})
; Populate the FUNCTION menu
void = widget_button(model_menu,value = 'Add a new model', $
   uvalue = {object:self,method:'ADD_MODEL'}, $
   uname = 'ADD_MODEL')
selection_method = 'pick_model'
diffusion_menu = widget_button(model_menu,value = 'Diffusion functions',/menu, $
   uname = 'DIFFUSION_MENU',sensitive = 0)
; We will store the function name (a string) in the user-name of the
; widget id for easy retrieval upon selection.
void = widget_button(diffusion_menu,value = '2-fold jump on a circle', $
   uvalue = {object:self,method:selection_method}, $
   uname = 'ref_two_fold_jump')
void = widget_button(diffusion_menu,value = '3-fold jump on a circle', $
   uvalue = {object:self,method:selection_method}, $
   uname = 'ref_three_fold_jump')
void = widget_button(diffusion_menu,value = 'N-fold jump on a circle', $
   uvalue = {object:self,method:selection_method}, $
   uname = 'ref_n_fold_jump_diffusion')
void = widget_button(diffusion_menu,value = 'Translational diffusion', $
   uvalue = {object:self,method:selection_method}, $
   uname = 'ref_translational_diffusion')
void = widget_button(diffusion_menu,value = 'Bounded jump diffusion', $
   uvalue = {object:self,method:selection_method}, $
   uname = 'ref_bounded_jump_diffusion',sensitive = 1)
void = widget_button(diffusion_menu,value = 'Diffusion in a sphere', $
   uvalue = {object:self,method:selection_method}, $
   uname = 'ref_diffusion_in_a_sphere',sensitive = 1)
void = widget_button(diffusion_menu,value = 'Isotropic rotational diffusion', $
   uvalue = {object:self,method:selection_method}, $
   uname = 'ref_isotropic_rotational_diffusion',sensitive = 1)
void = widget_button(diffusion_menu,value = 'Random jump diffusion', $
   uvalue = {object:self,method:selection_method}, $
   uname = 'ref_random_jump',sensitive = 1)
;void = widget_button(diffusion_menu,value = 'Jump diffusion on a honeycomb lattice (constant EISF)', $
;   uvalue = {object:self,method:selection_method}, $
;   uname = 'ref_honeycomb',sensitive = 1)
;void = widget_button(diffusion_menu,value = 'Jump diffusion on a honeycomb lattice (varying EISF)', $
;   uvalue = {object:self,method:selection_method}, $
;   uname = 'ref_honeycomb_vary',sensitive = 1)

tunneling_menu = widget_button(model_menu,value = 'Tunneling functions',/menu, $
   uname = 'TUNNELING_MENU',sensitive = 0)
void = widget_button(tunneling_menu,value = '3-fold tunneling', $
   uvalue = {object:self,method:selection_method}, $
   uname = 'ref_three_fold_tunneling')
void = widget_button(tunneling_menu,value = 'Broadened 3-fold tunneling', $
   uvalue = {object:self,method:selection_method}, $
   uname = 'ref_broad_three_fold_tunneling')
misc_menu = widget_button(model_menu,value = 'Miscellaneous functions',/menu, $
   uname = 'MISC_MENU',sensitive = 0)
void = widget_button(misc_menu,value = 'Dirac delta', $
   uvalue = {object:self,method:selection_method}, $
   uname = 'ref_dirac_delta')
void = widget_button(misc_menu,value = 'Background', $
   uvalue = {object:self,method:selection_method}, $
   uname = 'ref_background')
void = widget_button(misc_menu,value = 'Gaussian', $
   uvalue = {object:self,method:selection_method}, $
   uname = 'ref_gaussian')
void = widget_button(misc_menu,value = 'Lorentzian', $
   uvalue = {object:self,method:selection_method}, $
   uname = 'ref_lorentzian')
; Put in the tree widget.  First determine how wide we want the widget based on
; the screen size (make it 20% of the screen width)
device,get_screen_size = scr_size
imysize = 300 & imxsize = 300
tree_xsize = fix(0.2*scr_size[0])
tree_ysize = 2*imysize
self.tree_base = widget_base(self.tlb,/col)
file_tree = widget_tree(self.tree_base,/context_events,/multiple,uname = 'FILE_TREE', $
   scr_xsize = tree_xsize,scr_ysize = tree_ysize, $
   uvalue = {object:self,method:'show_context_menu'})
self.file_tree = file_tree
file_root = widget_tree(self.file_tree,value = 'DAVE DATA',/folder,/expanded, $
   uname = 'FILE_ROOT',uvalue = {object:self,method:'remove_file_highlight'})
self.file_root = file_root

;model_root = widget_tree(self.file_tree,value = 'MODEL DISPLAY',/folder,/expanded, $
;  uname = 'MODEL_ROOT',uvalue = {object:self,method:'do_nothing'})
self.model_root = 0L;model_root
; Put a folder underneath the model root folder for a first set of test data
; This will contain model data in its user-value
pseudo_event = {my_event,id:file_root,top:self.tlb,handler:0L}
otestdata = create_rains_test_data()
self.test_data_container->add,otestdata
;model_folder = widget_tree(model_root,value = 'Model Data',     $
;  uname = 'MODEL_DATA', /folder,/expanded,           $
;  uvalue =  {   object:self,               $
;         method:'do_nothing',            $
;         otestdata:otestdata})


im_col_base = widget_base(self.tlb,/col)
self.im_col_base = im_col_base

image_win = widget_draw(im_col_base,xsize = imxsize,ysize = imysize,/motion_events, $
   /button_events,uvalue = {object:self,method:'im_win_events'})
imageres_win = widget_draw(im_col_base,xsize = imxsize,ysize = imysize)

self.plot_base = widget_base(group_leader = self.tlb,/col,title = 'RAINS', $
   uname = 'PLOT_BASE',tlb_size_events = 1,tlb_frame_attr = 8,mbar = plot_bar)
plot_file_menu = widget_button(plot_bar,value = 'File',/menu)
plot_print_menu = widget_button(plot_bar,value = 'Printing options',/menu)

; Put the draw widgets in the plot tab,one on top of the other
pxsize = 400 & pysize = 300
prxsize = pxsize & prysize = fix(0.5*pysize)
plot_win = widget_draw(self.plot_base,xsize = pxsize,ysize = pysize,/motion_events, $
   /button_events,uvalue = {object:self,method:'plot_win_events'})
plotres_win = widget_draw(self.plot_base,xsize = prxsize,ysize = prysize)
self.group_slider = widget_slider(self.plot_base,value = 1,min = 1,max = 2, $
   uvalue = {object:self,method:'change_group'})
; Build the context_sensitive menus
; First build the data context-sensitive menu
single_base = widget_base(self.tlb,/context_menu,uname = 'DATA_MENU')
void = widget_button(single_base,value = 'Add a new model folder', $
                     uvalue = {object:self,method:'add_model'})
void = widget_button(single_base,value='Crop Data',uname='CROPXDATA',$
                     uvalue={object:self,method:'cropXData'})
;void = widget_button(single_base,value='Crop Data (in y)',uname='CROPYDATA',$
;                     uvalue={object:self,method:'cropYData'})
void = widget_button(single_base,value='Groups to include in fit',uname='GRPSTOFIT',$
                     uvalue={object:self,method:'grpsToFit'})
void = widget_button(single_base,value='Rebin Data',uname='REBDATA',$
                     uvalue={object:self,method:'rebinData'})
void = widget_button(single_base,value='Restore Original Data',uname='RESDATA',$
                     uvalue={object:self,method:'restoreData'})
void = widget_button(single_base,value = 'Create Gaussian resolution function', $
   uvalue = {object:self,method:'create_gauss_res'},/separator)
void = widget_button(single_base,value = 'Load DAVE file as resolution function', $
   uvalue = {object:self,method:'load_dave_res'})
void = widget_button(single_base,value='Crop Resolution Data',uname='CROPXRES',$
                     uvalue={object:self,method:'cropXRes'})
;void = widget_button(single_base,value='Crop Resolution Data (in y)',uname='CROPYRES',$
;                     uvalue={object:self,method:'cropYRes'})
void = widget_button(single_base,value='Rebin Resolution Data',uname='REBRES',$
                     uvalue={object:self,method:'rebinRes'})
void = widget_button(single_base,value='Restore Original Resolution',uname='RESRES',$
                     uvalue={object:self,method:'restoreRes'})
void = widget_button(single_base,value = 'Delete selected file', $
   uvalue = {object:self,method:'remove_file'},/separator)
void = widget_button(single_base,value = 'Display file information', $
   uvalue = {object:self,method:'show_file_info'})

; Build the model context-sensitive menu
menu_base = widget_base(self.tlb,/context_menu,uname = 'MODEL_MENU')
fit_menu = widget_button(menu_base,value = 'Fitting',/menu)

alg_sel = widget_button(fit_menu,value = 'Algorithm selection', /menu)
void = widget_button(alg_sel,value = 'Least-squares', $
   uvalue = {object:self,method:'select_ls'},uname = 'LS',/checked_menu)
void = widget_button(alg_sel,value = 'Genetic algorithm', $
   uvalue = {object:self,method:'select_ga'},sensitive = 0, $
   uname = 'GA',/checked_menu)
void = widget_button(alg_sel,value = 'Genetic algorithm/Least-squares hybrid', $
   uvalue = {object:self,method:'select_gals'},sensitive = 0, $
   uname = 'GA/LS',/checked_menu)
;void = widget_button(fit_menu,value = 'Select fit range(s)', $
;   uvalue = {object:self,method:'select_fit_range'})
void = widget_button(fit_menu,value = 'Display all model parameters', $
   uvalue = {object:self,method:'display_model_parameters'})
void = widget_button(fit_menu,value = 'Display fit report', $
   uvalue = {object:self,method:'show_fit_report'})
void = widget_button(fit_menu,value = 'View correlation matrix', $
   uvalue = {object:self,method:'show_correl_report'})
void = widget_button(fit_menu,value = 'Start fitting', $
   uvalue = {object:self,method:'fit_model'})
void = widget_button(fit_menu,value = 'Least-squares algorithm control',   $
   uvalue = {object:self,method:'ls_params'}   )
void = widget_button(menu_base,value = 'Remove model', $
   uvalue = {object:self,method:'remove_model'})

; Build the function context-sensitive menu
menu_base = widget_base(self.tlb,/context_menu,uname = 'FUNCTION_MENU')
void = widget_button(menu_base,value = 'Show function definition', $
   uvalue = {object:self,method:'show_function_definition'})
void = widget_button(menu_base,value = 'Remove function', $
   uvalue = {object:self,method:'remove_function'})
void = widget_button(menu_base,value = 'Modify function', $
   uvalue = {object:self,method:'modify_function'})

; Now build the multiple-selection menu
multi_base = widget_base(self.tlb,/context_menu,uname = 'MULTI_SEL')
void = widget_button(multi_base,value = 'Delete selected files', $
   uvalue = {object:self,method:'remove_file'})
void = widget_button(multi_base,value='QUIT',   $
   uvalue = {object:self,method:'quit'})
; Now let's get the horizontal extents of each of the widgets and arrange
; them on the screen to look nice.
tlb_geom = widget_info(self.tlb,/geom)
plot_geom = widget_info(self.plot_base,/geom)
wx = scr_size[0] & xs = tlb_geom.xsize+plot_geom.xsize
xo = fix(0.5*(wx-xs))
widget_control,self.tlb,xoffset = xo
widget_control,self.plot_base,xoffset = xo+tlb_geom.xsize+10
widget_control,self.plot_base,/realize
widget_control,self.tlb,/realize
; Now populate the plot window structure with the appropriate information
widget_control,image_win,get_value = image_winvis
(*self.im_win_info_ptr).win = image_win
(*self.im_win_info_ptr).winvis = image_winvis
window,/free,/pixmap,xsize = imxsize,ysize = imysize
(*self.im_win_info_ptr).winpix = !d.window

widget_control,imageres_win,get_value = imageres_winvis
(*self.imres_win_info_ptr).win = imageres_win
(*self.imres_win_info_ptr).winvis = imageres_winvis
window,/free,/pixmap,xsize = imxsize,ysize = imysize
(*self.imres_win_info_ptr).winpix = !d.window

widget_control,plot_win,get_value = plot_winvis
(*self.plot_win_info_ptr).win = plot_win
(*self.plot_win_info_ptr).winvis = plot_winvis
window,/free,/pixmap,xsize = pxsize,ysize = pysize
(*self.plot_win_info_ptr).winpix = !d.window

widget_control,plotres_win,get_value = plotres_winvis
(*self.plotres_win_info_ptr).win = plotres_win
(*self.plotres_win_info_ptr).winvis = plotres_winvis
window,/free,/pixmap,xsize = prxsize,ysize = prysize
(*self.plotres_win_info_ptr).winpix = !d.window

ls_id = widget_info(self.tlb,find_by_uname = 'LS')
widget_control,ls_id,set_button = 1
ga_id = widget_info(self.tlb,find_by_uname = 'GA')
widget_control,ga_id,set_button = 0
gals_id = widget_info(self.tlb,find_by_uname = 'GA/LS')
widget_control,gals_id,set_button = 0

; Stuff the self object reference into the user-value of the TLB
widget_control,self.tlb,set_uvalue = self
widget_control,self.plot_base,set_uvalue = self
ret = dave_set_focus(self.tlb)
xmanager,register_name,self.tlb,event_handler = 'rafins_event', $
   cleanup = 'rafins_cleanup',/no_block
ret = dave_set_focus(self.plot_base)
xmanager,'plot_base',self.plot_base,event_handler = 'rafins_event', $
   ;cleanup = 'rafins_cleanup', $
   /no_block
return,1
end
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
function refine_app::resize_tlb,event = event
compile_opt idl2,hidden
xsize = event.x & ysize = event.y
tlb_geom = widget_info(self.tlb,/geom)
tree_geom = widget_info(self.tree_base,/geom)
w = tree_geom.xsize
im_y_min = 50 & im_x_min = im_y_min

new_im_ysize = fix(0.5*event.y) > im_y_min
new_im_xsize = (event.x - w)>im_x_min;new_im_ysize
im_col_base = self.im_col_base
tlb = self.tlb
im_info = *self.im_win_info_ptr
imres_info = *self.imres_win_info_ptr


; Resize the image windows
widget_control,im_info.win,draw_xsize = new_im_xsize,draw_ysize = new_im_ysize
widget_control,imres_info.win,draw_xsize = new_im_xsize,draw_ysize = new_im_ysize
wdelete,im_info.winpix,imres_info.winpix
window,/free,/pixmap,xsize = new_im_xsize,ysize = new_im_ysize
(*self.im_win_info_ptr).winpix = !d.window
window,/free,/pixmap,xsize = new_im_xsize,ysize = new_im_ysize
(*self.imres_win_info_ptr).winpix = !d.window

if n_elements(*self.current_file_id_ptr) ne 0 then begin
   ret = self->refresh_image_window()
   ret = self->refresh_imageres_window()
endif
; Resize the tree base
widget_control,self.tree_base,scr_ysize = fix(2.0*new_im_ysize)
device,get_screen_size = scr_size
widget_control,self.tree_base,scr_xsize = fix(0.2*scr_size[0])
end
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
function refine_app::resize_plot_base,event = event
compile_opt idl2,hidden
xsize = event.x & ysize = event.y
geom = widget_info(self.tlb,/geom)

plot_x_min = 50 & plot_y_min = fix(0.75*plot_x_min)
device,get_screen_size = scr_size
new_plot_xsize = (event.x > plot_x_min) < 0.75*scr_size[1]
new_plot_ysize = fix(0.75*new_plot_xsize)
new_plotres_xsize = new_plot_xsize
new_plotres_ysize = fix(0.5*new_plot_ysize)
tlb = self.tlb
plot_info = *self.plot_win_info_ptr
plotres_info = *self.plotres_win_info_ptr
; Resize the image windows
widget_control,plot_info.win,draw_xsize = new_plot_xsize,   $
   draw_ysize = new_plot_ysize
widget_control,plotres_info.win,draw_xsize = new_plotres_xsize,   $
   draw_ysize = new_plotres_ysize
wdelete,plot_info.winpix,plotres_info.winpix
window,/free,/pixmap,xsize = new_plot_xsize,ysize = new_plot_ysize
(*self.plot_win_info_ptr).winpix = !d.window
window,/free,/pixmap,xsize = new_plotres_xsize,ysize = new_plotres_ysize
(*self.plotres_win_info_ptr).winpix = !d.window
if n_elements(*self.current_file_id_ptr) ne 0 then $
   ret = self->refresh_plot_window()
end
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
function refine_app::do_nothing,event = event
; This method is simply a placeholder used for debugging purposes during the
; application development phase.
return,1
end
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
pro rafins_event,event
compile_opt idl2,hidden

; RTA - Insert Generic error Handler
if (n_elements(!debug) && (!debug eq 0)) then begin
    catch, catchError
    if (catchError ne 0) then begin
        ;;print, 'Error handled!'
        eTitle = 'RAINS: Error encountered'
        eMsg = 'An error or unusual condition was encountered!'
        eMsg = [eMsg,'Please, report the following to the DAVE team:']
        eMsg = [eMsg,!error_state.msg]
        void = dialog_message(/error,eMsg,title=eTitle,dialog_parent=event.top)
        catch, /cancel
        return
    endif
endif



if dave_set_focus(event) then return
;  main event handler
; First test for context-sensitive events
this_event = tag_names(event,/structure)
if (this_event eq 'WIDGET_TAB') then return  ; just swallow tab events
; Next test for resizing events
if this_event eq 'WIDGET_BASE' then begin
   uname = widget_info(event.id,/uname)
   case uname of
   'TLB':  $
     begin
      widget_control,event.top,get_uvalue = self
      ret = self->resize_tlb(event = event)
     end
   'PLOT_BASE':  $
     begin
      widget_control,event.top,get_uvalue = self
      ret = self->resize_plot_base(event = event)
     end
   else:
   endcase
   return
endif
if this_event eq 'CORREL_EVENT' then return
widget_control,event.id,get_uvalue = cmd
result = call_method(cmd.method,cmd.object,event = event)
end
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
function refine_app::init,    group_leader = group_leader,      $
                 working_directory = working_directory,  $
                 notify_ids = notify_ids
compile_opt idl2,hidden
; Initialize the class data
self.pfun_sel = ptr_new(/allocate_heap)
self.pdata_sel = ptr_new(/allocate_heap)
self.pmodel_sel = ptr_new(/allocate_heap)
self.current_file_id_ptr = ptr_new(/allocate_heap)
self.im_win_info_ptr = ptr_new({win_info})
(*self.im_win_info_ptr).xPtr = ptr_new(/allocate_heap)
(*self.im_win_info_ptr).yPtr = ptr_new(/allocate_heap)
(*self.im_win_info_ptr).autoscale = 1
self.imres_win_info_ptr = ptr_new({win_info})
(*self.imres_win_info_ptr).xPtr = ptr_new(/allocate_heap)
(*self.imres_win_info_ptr).yPtr = ptr_new(/allocate_heap)
self.plot_win_info_ptr = ptr_new({win_info})
(*self.plot_win_info_ptr).xPtr = ptr_new(/allocate_heap)
(*self.plot_win_info_ptr).yPtr = ptr_new(/allocate_heap)
(*self.plot_win_info_ptr).autoscale = 1
self.plotres_win_info_ptr = ptr_new({win_info})
(*self.plotres_win_info_ptr).xPtr = ptr_new(/allocate_heap)
(*self.plotres_win_info_ptr).yPtr = ptr_new(/allocate_heap)
self.sel_leaf_ptr = ptr_new(/allocate_heap)
self.file_container = obj_new('IDL_CONTAINER')
self.test_data_container = obj_new('IDL_CONTAINER')
if n_elements(notify_ids) eq 0 then notify_ids = [0L,0L]
self.notify_ids = notify_ids
if n_elements(group_leader) eq 0 then group_leader = 0L
self.group_leader = group_leader
if n_elements(working_directory) eq 0 then $
   working_directory = 'c:\dimeo\hfbs\data\ch3i\bulk\reduced\'
self.workdir = working_directory
; Build the GUI
ret = self->build_gui()
self.colortable = 15
device,decomposed = 0
loadct,self.colortable,/silent
return,1
end
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
pro refine_app__define
compile_opt idl2,hidden
define = {refine_app,                    $
          tlb:0L,                      $
          plot_base:0L,                  $
          notify_ids:lonarr(2),              $
          current_file_id_ptr:ptr_new(),         $
          pfun_sel:ptr_new(),                $
          pmodel_sel:ptr_new(),              $
          pdata_sel:ptr_new(),               $
          im_col_base:0L,                  $
          tree_base:0L,                  $
          group_leader:0L,                $
          group_slider:0L,                $
          im_win_info_ptr:ptr_new(),            $
          imres_win_info_ptr: ptr_new(),         $
          plot_win_info_ptr:ptr_new(),          $
          plotres_win_info_ptr:ptr_new(),          $
          file_container:obj_new(),            $
          test_data_container:obj_new(),         $
          workdir:'',                     $
          file_tree:0L,                  $
          file_root:0L,                  $
          model_root:0L,                  $
          colortable:0,                  $
          sel_leaf_ptr:ptr_new()             $
         }


end
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
pro rains
o = obj_new('refine_app')
end
