; $Id: opan__define.pro,v 1.124.2.2 2008/07/01 20:11:37 kneller Exp $
;###############################################################################
;
; NAME:
;  OPAN__DEFINE
;
; PURPOSE:
;  Object implementation of the analysis program called PAN
;  (Peak ANalysis).
;
; CATEGORY:
;  DAVE, Data Analysis, objects, widgets, curve 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.
;
;###############################################################################

pro opan::extractPanMask,davestr,pan_mask

    if n_elements(davestr) eq 0 then begin

        if ptr_valid(self.daveptr) gt 0 then begin
            davestr = *self.daveptr
        endif else begin
            bitmask = byte(0*(*self.dataPtr) + 1)
            pan_mask = bitmask
            if ptr_valid(self.maskPtr) then ptr_free,self.maskPtr
            self.maskPtr = ptr_new(bitmask)

            return
        endelse
    endif;n_elements(davestr) eq 0

;THIS SEEMS LIKE A BUG WAITING TO HAPPEN. WHAT IF QTY IS 1d???????????????????????????????
;    nc = (size(((*(((*(davestr).datastrptr).commonstr).histptr)).qty)))[1]
;    nr = (size(((*(((*(davestr).datastrptr).commonstr).histptr)).qty)))[2]

    szqty = (size(((*(((*(davestr).datastrptr).commonstr).histptr)).qty)))
    if szqty[0] eq 1 then begin
      nc = szqty[1]
      nr = 1
    endif else begin
      nc = szqty[1]
      nr = szqty[2]
    endelse


    if ptr_valid((*(davestr.datastrptr)).specificptr) eq 0 then begin

            ;NO SPECIFICSTR, CREATE A MASK
            bitmask = bytarr(nc,nr) + 1b
            pan_mask = bitmask

    endif else begin


            ;VALID SPECIFIC STRUCTURE, ATTEMPT TO EXTRACT MASK IF AVAILABLE.
            ;IF NOT AVAILABLE THEN CREATE A MASK

            ;NOW WHAT HAPPENS IF specificPtr IS A VALID POINTER BUT IT POINTS TO AN
            ;UNDEFINED VALUE?  USE HELP:
            help,(*(*(davestr).datastrptr).specificptr),output=out

            undefinedflag = 0
            for i=0,n_elements(out)-1 do begin
                if stregex(strupcase(out[i]),'UNDEFINED',/boolean) ne 0 then undefinedflag = 1
            endfor;i

            if undefinedflag eq 1 then begin
                ;SPECIFIC POINTER IS VALID BUT POINTS TO NOTHING.
                bitmask = bytarr(nc,nr) + 1b
                pan_mask = bitmask
            endif else begin

                sp_tag_names = tag_names((*(*(davestr).datastrptr).specificptr))
                if n_elements(sp_tag_names) gt 0 then begin
                    wh = where(strupcase(sp_tag_names) eq 'PAN_MASK',count)
                    if count gt 0 then begin

                            ;063008
                            ;ADD THE NEXT CHECK IN CASE THE PAN_MASK FIELD EXISTS BUT IS A NULL POINTER
                            if ptr_valid((*(*(davestr).datastrptr).specificptr).pan_mask) eq 0 then begin
                              maskundefinedflag = 1
                            endif else begin
                              help,(*(*(*(davestr).datastrptr).specificptr).pan_mask),output=out
                              maskundefinedflag = 0
                              for i=0,n_elements(out)-1 do begin
                                  if stregex(strupcase(out[i]),'UNDEFINED',/boolean) ne 0 then maskundefinedflag = 1
                              endfor;i
                            endelse

                            if maskundefinedflag eq 0 then begin

;063008
;SHOULD I PUT SOMETHING INTO THE DAVE_PTR MASK FIELD NOW??????
;WOULD IT AFFECT ANYTHING???
                                ;WHEN IT IS HERE THERE IS NO CRASH.
                                bytemask = (*(*(*(davestr).datastrptr).specificptr).pan_mask)

                                bitmask = bytes2bits(bytemask,nc,nr)
                            endif else begin
                                bitmask = bytarr(nc,nr) + 1b
                            endelse


                    endif else begin

                        ;IF MASK EXISTS IN SPECIFIC POINTER, BUT THE PAN_MASK DOES NOT, WE GET HERE.
                        wh = where(strupcase(sp_tag_names) eq 'MASK',count)
                        if count gt 0 then begin
                                help,(*(*(*(davestr).datastrptr).specificptr).mask),output=out
                                maskundefinedflag = 0
                                for i=0,n_elements(out)-1 do begin
                                    if stregex(strupcase(out[i]),'UNDEFINED',/boolean) ne 0 then maskundefinedflag = 1
                                endfor;i
                                if maskundefinedflag eq 0 then begin
                                    bytemask = (*(*(*(davestr).datastrptr).specificptr).mask)
                                    bitmask = bytes2bits(bytemask,nc,nr)
                                endif else begin
                                    bitmask = bytarr(nc,nr) + 1b
                                endelse
                        endif else begin
                            ;NO MASK, NO PAN_MASK, BUT SPECIFIC POINTER IS AVAILABLE AND VALID.
                            bitmask = bytarr(nc,nr) + 1b
                        endelse
                    endelse
                endif else begin
                        bitmask = bytarr(nc,nr) + 1b
                endelse
                pan_mask = bitmask
            endelse
    endelse

    if ptr_valid(self.maskPtr) then ptr_free,self.maskPtr
    self.maskPtr = ptr_new(bitmask)

end;opan::extractPanMask
pro opan::retrievePanMask,panMask

        if ptr_valid(self.maskPtr) eq 0 then begin
            panmask = byte(0*(*self.dataPtr) + 1)
        endif else begin
            help,*self.maskPtr,output=maskoutput

            maskundefinedflag = 0
            for i=0,n_elements(maskoutput)-1 do begin
                if stregex(strupcase(maskoutput[i]),'UNDEFINED',/boolean) ne 0 then maskundefinedflag = 1
            endfor;i

            if maskundefinedflag eq 0 then begin
                    panmask = *self.maskPtr
            endif else begin;maskundefinedflag eq 0

                    panmask = byte(0*(*self.dataPtr)) + 1b
            endelse

        endelse


end;opan::retrievePanMask
pro opan::clearOneRes_Ptr

;NEED UNDERSCORE IN NAME BECAUSE PAN AND MAYBE OTHER ROUTINES
;LOOK GLOBALLY FOR THINGS WITH "ResPtr" IN THEIR NAMES!!!!!!!!!
;
;THIS IS ESPECIALLY A PROBLEM WITH USER DEFINED FUNCTIONS WITH NO
;RESOLUTION WHICH FIND A ROUTINE WITH resPtr IN THE NAME AND THINK
;THEY HAVE A RESOUTION FILE WHICH TURNS OUT TO BE UNAVAILABLE!!!!! 

    ;020708
    ;EMPTY THE CONTENTS OF self.oneResPtr
    ;THIS IS ESPECIALLY USEFUL WHEN ALL THE POINTS IN THE RES DATA 
    ;ARE MASKED FOR THE CURRENT GROUP.
    if ptr_valid(self.oneResPtr) ne 0 then begin
        ptr_free,self.oneResPtr
        self.oneResPtr = ptr_new(/allocate_heap)
    endif
end;opan::clearOneRes_ptr

function opan::extractOneResStr,val,OneResStr,contentsMasked=contentsMasked

  ;GET oneResStr AND RETURN IT VIA THE ARGUMENT
  ;
  ;IF NO resStr FOR val THEN LEAVE IT EMPTY SO THAT CALLING ROUTINE CAN TEST
  ;FOR n_elements(OneResStr) eq 0
  ;
  ;
  ;NOTE:   y VARIABLE SHOULD NOT NEED MASKING!!!
  ;        PROBABLY ONLY y[val] SHOULD BE PASSED, BUT SELECTING THAT
  ;        COULD BE PROBLEMATIC IF THE y VARIABLE IS 2d FOR SOME REASON.
  ;
  ;        IN ALL CASES IN PAN IT APPEARS THAT THE y ARRAY IS PASSED IN ITS ENTIRETY, SO CONTINUE TO DO SO.
  ;
  ;RETURN 1 IF THERE IS res DATA AND 0 IF THERE IS NOT.

         contentsMasked = 0
         if n_elements(*self.resPtr) ne 0 then begin
                   resStr = (*self.resPtr)
                   if n_elements(val) eq 0 then val = 0

                   tags = tag_names(resStr)
                   whmask = where(stregex(tags,'MASK',/boolean,/fold_case) eq 1)

                   resSize = size((*self.resPtr).data)
                 
                   if whmask ne -1 then begin
                       if resSize[0] eq 2 then begin 
                         mask = (*self.resptr).mask[*,val]
                         whnotmasked = where(mask ne 0,notmaskcount)
                       endif else begin
                         mask = (*self.resptr).mask
                         whnotmasked = where(mask ne 0,notmaskcount)
                       endelse

                       ;063008
                       if n_elements(mask) gt notmaskcount then contentsMasked = 1

                       if notMaskCount eq 0 then begin
                           contentsMasked = 1

                           ;void = dialog_message('No Unmasked Resolution Data for Group #'+strtrim(string(val),2))
                           print,'opan::extractOneResStr No Unmasked Resolution Data for Group #'+strtrim(string(val),2)
                           print,'opan::extractOneResStr Defining a Dummy OneResStr which should not be used'
                           OneResStr = {x:[0.,1.],$
                                        y:[-1.],$
                                        data:[0.,0.],$
                                        rlimit:[0.,0.]}
                           ;self->clearOneRes_ptr
                           return,0
                       endif else begin

  ;021308
  ;HERE IS WHERE THE PROBLEM PROBABLY IS!!!!!
  
                          if resSize[0] eq 2 then begin
                             xOneRes = (*self.resPtr).x[whnotmasked]
                             yOneRes = (*self.resPtr).y;[whnotmasked]
                             dataOneRes = reform((*self.resPtr).data[whnotmasked,val])
                           endif else begin
                             xOneRes = (*self.resPtr).x[whnotmasked]
                             yOneRes = (*self.resPtr).y;[whnotmasked]
                             dataOneRes = reform((*self.resPtr).data[whnotmasked])
                           endelse
                           rlimitOneRes = (*self.resPtr).rlimit
                           OneResStr = {x:xOneRes,$
                                        y:yOneRes,$
                                        data:dataOneRes,$
                                        rlimit:rlimitOneRes}
                           return,1
                       endelse
                   endif else begin
                           ;print,'opan::extractOneResStr NO MASK, SO SET ALL OF THE DATA IN THE ONE RES STR!!!!'          
                           contentsMasked = 0
                           if resSize[0] eq 2 then begin
                             xOneRes = (*self.resPtr).x
                             yOneRes = (*self.resPtr).y
                             dataOneRes = reform((*self.resPtr).data[*,val])
                           endif else begin
                             xOneRes = (*self.resPtr).x
                             yOneRes = (*self.resPtr).y
                             dataOneRes = reform((*self.resPtr).data)
                           endelse
                           rlimitOneRes = (*self.resPtr).rlimit
                           OneResStr = {x:xOneRes,$
                                        y:yOneRes,$
                                        data:dataOneRes,$
                                        rlimit:rlimitOneRes}
                           return,1
                   endelse
         endif else begin
            ;void = dialog_message('opan::extractOneResStr   No Resolution Data Loaded')
            contentsMasked = 1
            print,'opan::extractOneResStr Defining a Dummy OneResStr which should not be used'
            OneResStr = {x:[0.,1.],$
                         y:[-1.],$
                         data:[0.,0.],$
                         rlimit:[0.,0.]}
            return,0
         endelse

end;opan::extractOneResStr

function opan::checkDataMasked

  self->retrievePanMask,panMask
  npts = n_elements(panMask)
  wh = where(panMask eq 1,count)
  if count eq npts then ret = 0 else ret = 1 

  return,ret
end;opan::checkDataMasked

function opan::checkResMasked

    ;TELL CALLER WHETHER THERE ARE MASKED POINTS IN THE RESOLUTION STRUCTURE.
    if n_elements(*self.resPtr) ne 0 then begin
              resStr = (*self.resPtr)
              resSize = size(resStr.data)
              nMasked = 0
              if resSize[0] eq 1 then begin
                dum = self->extractOneResStr(0,OneResStr,contentsMasked=contentsMasked)
                nmasked += contentsMasked
              endif else begin
                for i=0,resSize[2]-1 do begin
                  dum = self->extractOneResStr(i,OneResStr,contentsMasked=contentsMasked)
                  ;print,contentsMasked
                  nmasked += contentsMasked
                endfor;i
              endelse
              return,nMasked
    endif else begin
      return,0
    endelse
              
end;opan::checkResMasked


;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
pro opan::extractDataForPAN,dat=dat,derr=derr,x=x,y=y,erry=erry,val=val,dSize=dSize,$
                            allData=allData,allx=allx,panmask=panmask,group=group


;GETS DATA FOR THE CURRENT DATA GROUP.

if n_elements(group) eq 0 then begin
        widget_control,self.groupSlider,get_value = val
        val = fix(val[0])-1

        dSize = size(*self.dataPtr)

      if dSize[0] eq 1 then begin
                      dat = reform(*self.dataPtr)
                      derr = reform(*self.errorPtr)
                      allx = reform(*self.xvalsPtr)
          
                      y = (*self.yvalsPtr)
          
                      ;val WAS PUSHED FROM HERE TO THE dsize ne 1.
                      erry = reform(*self.errorPtr)
          
                      alldata = reform(*self.dataPtr)
          
          
                      self->retrievePanMask,panMask
          
                      whnotmasked = where(panmask eq 1,npts)
                      if npts gt 0 then begin
                          dat = dat[whnotmasked]
                          derr = derr[whnotmasked]
                          x = allx[whnotmasked]
          
                          ;DOES THIS STEP MAKE SENSE FOR THE y VALUES?????????
                          y = y[whnotmasked]
                          erry = erry[whnotmasked]
                      endif
                      val = 0
      endif else begin
            if n_elements(group) ne 0 then begin
                val = group[0]-1 > 0
            endif else begin
                widget_control,self.groupSlider,get_value = val
                val = fix(val[0])-1
            endelse

            dat = reform((*self.dataPtr)[*,val])
            derr = reform((*self.errorPtr)[*,val])
            allx = reform((*self.xvalsPtr)[*,val])
            y = reform((*self.yvalsPtr)[*,val])
            ;erry = reform(*self.errorPtr)
            erry = reform((*self.errorPtr)[*,val])

            alldata = reform(*self.dataPtr)

            self->retrievePanMask,panMask
            whnotmasked = where(panmask[*,val] eq 1,npts)
            if npts gt 0 then begin
                dat = dat[whnotmasked]
                derr = derr[whnotmasked]
                x = allx[whnotmasked]

                ;DOES THIS STEP MAKE SENSE FOR THE y VALUES?????????
                y = y[whnotmasked]
                erry = erry[whnotmasked]
            endif

      endelse

      datSize = size(*self.dataPtr)
      if datSize[0] eq 1 then val = 0
      xrange = self.xrange

      ;APPLY THE MASK BELOW WHEN READY

      ;020408
      ;UNCOMMENTING THE NEXT BLOCK AND WORKING WITH THE MASK!
      ;WORK WITH THE MASK IN THE SAME MANNER AS WITH THE DATA
      ;FOR  opan::rebinRes APPLY A WARNING MESSAGE TO MASKED DATA
      ;SO THE USER CAN DECIDE IF THE REBINNING IS APPROPRIATE.
      ;PERHAPS THE TEST WOULD BE:  IF ALL MASK VALUES ARE (0 or 1???)THEN ALLOW REBIN
      ;                            IF NOT THEN SAY REBIN WILL CAUSE PROBLEMS  
      ;


    
    ;#################################################################################################
    ;RESOLUTION DATA:
        ; If resolution is loaded then check if nos of groups is the same for
        ; resolution and signal datasets
        if (n_elements(*self.resPtr) gt 0) then begin
           dSize = size(*self.dataPtr)
           nd = (dSize[0] eq 2)? dSize[2] : 1
           rSize = size((*self.resPtr).data)
           nr = (rSize[0] eq 2)? rSize[2] : 1
           if (nr ne nd) then begin
              msg = ['Signal and resolution dataset groups do not match' $
                     ,'There are '+strtrim(string(nd),2)+' groups in signal dataset' $
                     ,'There are '+strtrim(string(nr),2)+' groups in resolution dataset' $
                     ,'Consider changing the signal OR the resolution data' $
                     ,'Fits will not be performed!' ]
              void = dialog_message(dialog_parent = event.top,msg,/error)
              return                    ; exit
           endif
;;        endif
;;    
;;    ;THIS EXTRACTION OF RESOLUTION DATA WILL ALSO NEED TO ACCOUNT FOR MASKING.
;;    ;RESOLUTION MASK IS SEPARATE FROM THE PAN MASK, SO IT MUST BE STORED
;;    ;SEPARATELY WHEN RESOLUTION DATA ARE READ IN.
;;    ;
;;    ;THE OTHER ASPECT TO THIS IS THAT THE DATA USED WITH
;;    ;RESOLUTION CALCULATIONS MUST EXTRACT THE DATA FOR EACH GROUP
;;    ;AND CONSIDER ITS MASK, THEREFORE I WILL PROBABLY HAVE TO WRITE 
;;    ;A METHOD TO EXTRACT RESOLUTION DATA FROM self.resPtr EACH TIME THE 
;;    ;oneResPtr IS FORMED.
;;
;;
;;        if n_elements(*self.resPtr) gt 0 then begin
;
;           ;ORIGINALLY HAD NEXT LINE ALREADY COMMENTED
;           ;*self.oneResPtr = reform((*self.resPtr).data[*,val])
;
;;020508
;           ;NOW COMMENT THE NEXT LINES AND REPLACE WITH METHOD CALL
;;           resStr = (*self.resPtr)
;;           (*self.oneResPtr) = {x:resStr.x, $
;;                                y:resStr.y, $    ;020408  HOW IS THIS USED???????
;;                                data:(reform(resStr.data[*,val])),$
;;                                rlimit:resStr.rlimit,$
;;                                mask:resStr.mask}


           resExists = self->extractOneResStr(val,OneResStr)
;print,'opan::extractDataForPAN'
;help,oneResStr
           if resExists ne 0 then begin
             (*self.oneResPtr) = OneResStr
           endif else begin
             self->clearOneRes_ptr
             ;print,'opan::extractDataForPAN NEED TO NULLIFY self.OneResPtr!!!!!! for group #'+strtrim(string(val),2)
             
             ;void = dialog_message('opan::extractDataForPAN resPtr EXISTS BUT NO unMasked res DATA FOR THIS GROUP!')
           endelse
        endif;(n_elements(*self.resPtr) gt 0)
    ;#################################################################################################

endif else begin   ;n_elements(group) ne 0


;        widget_control,self.groupSlider,get_value = val
;        val = fix(val[0])-1

        val = group-1

        dSize = size(*self.dataPtr)

        if ptr_valid(self.maskPtr) eq 0 then begin
            panmask = byte(0*(*self.dataPtr) + 1)

        endif else begin
            panmask = *self.maskPtr
        endelse

        if dSize[0] eq 1 then begin
            dat = reform(*self.dataPtr)
            derr = reform(*self.errorPtr)
            allx = reform(*self.xvalsPtr)

            y = (*self.yvalsPtr)
            erry = (*self.errorPtr)[*,val]

            alldata = reform(*self.dataPtr)


            whnotmasked = where(panmask eq 1,npts)
            if npts gt 0 then begin
                dat = dat[whnotmasked]
                derr = derr[whnotmasked]
                x = allx[whnotmasked]

                ;DOES THIS STEP MAKE SENSE FOR THE y VALUES?????????
                y = y[whnotmasked]
                erry = erry[whnotmasked]
            endif
            val = 0
        endif else begin
            dat = reform((*self.dataPtr)[*,val])
            derr = reform((*self.errorPtr)[*,val])
            allx = reform((*self.xvalsPtr)[*,val])
            y = reform((*self.yvalsPtr)[*,val])
            erry = reform(*self.errorPtr)

            alldata = reform(*self.dataPtr)

            whnotmasked = where(panmask[*,val] eq 1,npts)
            if npts gt 0 then begin
                dat = dat[whnotmasked]
                derr = derr[whnotmasked]
                x = allx[whnotmasked]

                ;DOES THIS STEP MAKE SENSE FOR THE y VALUES?????????
                y = y[whnotmasked]
                erry = erry[whnotmasked]
            endif

        endelse

        datSize = size(*self.dataPtr)
        if datSize[0] eq 1 then val = 0
        xrange = self.xrange

    ;APPLY THE MASK BELOW WHEN READY

;020408
;UNCOMMENTING THE NEXT BLOCK AND WORKING WITH THE MASK!
;WORK WITH THE MASK IN THE SAME MANNER AS WITH THE DATA
;FOR  opan::rebinRes APPLY A WARNING MESSAGE TO MASKED DATA
;SO THE USER CAN DECIDE IF THE REBINNING IS APPROPRIATE.
;PERHAPS THE TEST WOULD BE:  IF ALL MASK VALUES ARE (0 or 1???)THEN ALLOW REBIN
;                            IF NOT THEN SAY REBIN WILL CAUSE PROBLEMS  
;
;
    ;;;;;
    ;;;;;;#################################################################################################
    ;RESOLUTION DATA:
        ; If resolution is loaded then check if nos of groups is the same for
        ; resolution and signal datasets
        if (n_elements(*self.resPtr) gt 0) then begin
           dSize = size(*self.dataPtr)
           nd = (dSize[0] eq 2)? dSize[2] : 1
           rSize = size((*self.resPtr).data)
           nr = (rSize[0] eq 2)? rSize[2] : 1
           if (nr ne nd) then begin
              msg = ['Signal and resolution dataset groups do not match' $
                     ,'There are '+strtrim(string(nd),2)+' groups in signal dataset' $
                     ,'There are '+strtrim(string(nr),2)+' groups in resolution dataset' $
                     ,'Consider changing the signal OR the resolution data' $
                     ,'Fits will not be performed!' ]
              void = dialog_message(dialog_parent = event.top,msg,/error)
              return                    ; exit
           endif
        endif
    
    ;THIS EXTRACTION OF RESOLUTION DATA WILL ALSO NEED TO ACCOUNT FOR MASKING.
        if n_elements(*self.resPtr) gt 0 then begin
           ;*self.oneResPtr = reform((*self.resPtr).data[*,val])

;020508
;COMMENT OUT THE NEXT BLOCK AND REPLACE WITH THE METHOD CALL THAT FOLLOWS
;           resStr = (*self.resPtr)
;           (*self.oneResPtr) = {x:resStr.x,$
;                                y:resStr.y, $  ;020408  HOW IS THIS USED???????
;                                data:(reform(resStr.data[*,val])),$
;                                rlimit:resStr.rlimit,$
;                                mask:resStr.mask}
           resExists = self->ExtractOneResStr(val,OneResStr)
           if resExists ne 0 then begin
             (*self.oneResPtr) = OneResStr
           endif else begin
             self->clearOneRes_ptr
             ;print,'opan::extractDataForPAN NEED TO NULLIFY self.OneResPtr!!!!!! for group #'+strtrim(string(val),2)
             ;void = dialog_message('opan::extractDataForPAN resPtr EXISTS BUT NO unMasked res DATA FOR THIS GROUP!')
           endelse

        endif
    ;#################################################################################################

endelse;n_elements(group) ne 0

end;opan::extractDataForPAN


pro opanCleanup,tlb



widget_control,tlb,get_uvalue = self
if obj_valid(self) then begin
  s = size(self->getNotifyIds())
  if s[0] ne 0 then begin
    if s[0] eq 1 then count = 0 else count = s[2]-1
    for j = 0,count do begin
      OPANInfo = {OPANEvent,$
                            ID:(self->getNotifyIds())[0,j],$
                            Top:(self->getNotifyIds())[1,j],$
                            Handler:0l, $
                            object:self}
      if widget_info((self->getNotifyIds())[0,j],/valid_id) then begin $
        widget_control,(self->getNotifyIds())[0,j],send_event = OPANInfo
      endif
    endfor
  endif else begin
    obj_destroy,self
  endelse
endif
return
end
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
pro opan::aboutPAN,event = event

    strout = ['PAN: Peak Analysis','Written by R.M.Dimeo', $
              'October 11, 2002','','NIST Center for Neutron Research']
    void = dialog_message(strout,/information,dialog_parent = event.top)
    return
end;opan::aboutPAN
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
pro opan::quit,event = event

    if n_elements(*self.logStringPtr) ne 0 then begin
      self->closeHTMLFile,event = event
    endif
    widget_control,self.tlb,/destroy
    return
end;opan::quit
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
pro opan::cleanup

    tvlct,*self.rPtr,*self.gPtr,*self.bPtr
    self.ob_reg->remove,self
    if self.reg_present eq 0 then obj_destroy,self.ob_reg
    obj_destroy,self.otable
    ptr_free,self.xtabPtr,self.btabPtr,self.ttabPtr,self.ytabPtr
    ptr_free,self.resPtr,self.oneResPtr
    ptr_free,self.tasPathPtr
    ptr_free,self.rPtr,self.gPtr,self.bPtr
    ptr_free,self.curvenamesPtr, self.headerPtr
    ptr_free,self.davePtr,self.ktablePtr
    ptr_free,self.dataPtr,self.errorPtr
    ptr_free,self.xvalsPtr,self.yvalsPtr
    ptr_free,self.datxPtr,self.datyPtr
    ptr_free,self.resxPtr,self.resyPtr,self.color_ptr
    ptr_free,self.ocurrentPtr,self.prefs
    ptr_free,self.grpArrayPtr,self.goodParmPtr
    ptr_free,self.notifyIdPtr,self.tasFilePtr,self.logStringPtr
    ptr_free,self.oxvalsPtr,self.oyvalsPtr,self.oresPtr
    ptr_free,self.odataPtr,self.oerrorPtr

    if ptr_valid(self.maskPtr) then ptr_free,self.maskPtr
    if ptr_valid(self.omaskPtr) then ptr_free,self.omaskPtr

    wdelete,self.resPix,self.datPix
    ; Since we have a pointer to an array of object containers, destroy
    ; the object container array first, then free the pointer.
    if total(obj_valid(*self.ocurveGroup) ge 1) then obj_destroy,*self.ocurveGroup
    ptr_free,self.ocurveGroup
    return
end;opan::cleanup
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
pro opan::flashMessage_create,msg,base
    ; This method simply flashes a widget with a message that remains present
    ; until the flashMessage_destroy method is invoked.
    ;
    ; Center it.


    geom = widget_info(self.tlb, /geometry)
    xpos = geom.xoffset + geom.xsize/2 - 100
    ypos = geom.yoffset + geom.ysize/2 - 50

    base = widget_base(title='Please wait:',/row,xoffset=xpos,yoffset=ypos, $
          tlb_frame_attr = 3)
    void = widget_text(base,value = msg,xsize = strlen(msg),/editable)
    widget_control,base,/realize
    return
end;opan::flashMessage_create
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
pro opan::flashMessage_destroy,base
    widget_control,base,/destroy
    return
end;opan::flashMessage_destroy
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
pro fitfunction,xlim,parms,yfit,_Extra = extra

    ;THIS IS A WRAPPER FOR ALL THE FITTING FUNCTIONS. THIS WAY THE SELECTED
    ;FIT FUNCTION CAN BE MANAGED BY the ocurvegroup  AND mpcurvefit CAN
    ;SIMPLY CALL fitfunction TO ACCESS ALL OF THEM!



;print,'THIS IS A TEST!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!'
;help,extra
;help,_extra

;print,tag_names(extra[0])
;help,extra.lun
;print,'THIS 2 IS A TEST!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!'
wh = where(stregex(tag_names(extra),'LUN',/fold_case,/boolean),luncount)
;print,'THIS 3 IS A TEST!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!'
if luncount ne 0 then begin
;print,'THIS 4 IS A TEST!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!'
    printf,extra.lun,''
    printf,extra.lun,''
    printf,extra.lun,''
    printf,extra.lun,''
    printf,extra.lun,''
    printf,extra.lun,'################################################################'
    printf,extra.lun,'fitfunction:'
    printf,extra.lun,'oc->getparms=',(extra.oc)->getparms()
    printf,extra.lun,'input  parms=',parms
endif;luncount


;help,*extra.xPtr
    ; This is the function that can be used in curve fitting (using Markwardt's
    ; routines for instance).
    x = *extra.xPtr
;print,'THIS 4a IS A TEST!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!'
    oc = extra.oc
;print,'THIS 4b IS A TEST!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!'
    oc->setparms,parms
;print,'THIS 4c IS A TEST!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!'
if luncount ne 0 then begin
;print,'THIS 5 IS A TEST!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!'
    printf,extra.lun,'after oc->setparms:'
    printf,extra.lun,'oc->getparms=',oc->getparms()
    printf,extra.lun,'input  parms=',parms
endif;luncount


    resIndex = where(tag_names(extra) eq 'RESPTR',count)
    if count gt 0 then begin
      rlimit = extra.rlimit
      oc->evaluate,x,resPtr = extra.resPtr,yout = yout,rlimit = rlimit
    endif else begin
      oc->evaluate,x,yout = yout,_Extra = extra
    endelse
;print,'THIS 6 IS A TEST!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!'

    wherevalid = where(x ge min(xlim) and x le max(xlim),newpts)
    yfit = yout[wherevalid]
;print,'THIS 7 IS A TEST!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!'


    return
end;fitfunction
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
pro opan::initCleanup, event = event

    self->clearAllCurves

    if n_elements(*self.dataPtr) gt 0 then begin
      if n_elements(*self.ocurveGroup) gt 0 then begin
         obj_destroy,(*self.ocurveGroup)
      endif
    endif
    return

end;opan::initCleanup
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
pro opan::initNewDataObjects, event = event


;########################################
;020807
;POSSIBLE PROBLEM POINT FOR MASKING?????
;NO.  DATA POINTER SHOULD BE PROPERLY USED IN THIS SITUATION.
;########################################

    if n_elements(*self.dataPtr) eq 0 then return
    datSize = size(*self.dataPtr)
    if datSize[0] eq 2 then begin
      nq = (size(*self.dataPtr))[2]
      widget_control,self.groupSlider,set_slider_min = 1,set_slider_max = nq, $
                     sensitive = 1
    endif else begin
      nq = 1
      widget_control,self.groupSlider,set_value = 1
      widget_control,self.groupSlider,set_slider_min = 1,set_slider_max = 2,sensitive = 0
    endelse



    ;CREATE ONE CURVE GROUP (func_cont) PER GROUP
    ;
    ;THIS ALLOWS EACH GROUP TO DO THE FITTING WITH ITS OWN x,y,data,sdata VALUES
    *self.ocurveGroup = objarr(nq)
    for i = 0,nq-1 do begin
     (*self.ocurveGroup)[i] = obj_new("FUNC_CONT")
    endfor
    grpString = strtrim(string(1),2)+'-'+strtrim(string(nq),2)
    widget_control,self.groupField,set_value = grpString

    xmin = min((*self.xvalsPtr),max=xmax)
    (*self.prefs).xfitlo = xmin
    (*self.prefs).xfithi = xmax
    if ((*self.prefs).xmin eq 0.0) then (*self.prefs).xmin = xmin
    if ((*self.prefs).xmax eq 1.0) then (*self.prefs).xmax = xmax

    ymin = min((*self.dataPtr),max=ymax)
    if ((*self.prefs).ymin eq 0.0) then (*self.prefs).ymin = ymin
    if ((*self.prefs).ymax eq 1.0) then (*self.prefs).ymax = ymax

    *self.odataPtr = *self.dataPtr
    if n_elements(*self.maskPtr) eq 0 then begin
        *self.omaskPtr = byte(0*(*self.dataptr)) + 1b
    endif else begin
        *self.omaskPtr = *self.maskPtr
    endelse
    *self.oxvalsPtr = *self.xvalsPtr
    *self.oyvalsPtr = *self.yvalsPtr
    *self.oerrorPtr = *self.errorPtr



    ; If resolution is loaded,
    ; is the no. of groups the same for resolution and the dataset being
    ; loaded?
    if (n_elements(*self.resPtr) gt 0) then begin
       rsize = size((*self.resPtr).data)
       nr = (rsize[0] eq 2)? rsize[2] : 1
       if (nr ne nq) then begin
          msg = ['Signal and resolution dataset groups do not match' $
                 ,'There are '+strtrim(string(nq),2)+' groups in signal dataset' $
                 ,'There are '+strtrim(string(nr),2)+' groups in resolution dataset' $
                 ,'Fits cannot be performed!' $
                 ,'Consider changing the signal OR the resolution data']
          void = dialog_message(dialog_parent = event.top,msg)
       endif
    endif

    ;UPDATE THE AUTOSCALING STATE WHEN DATA ARE LOADED.
    self.autoscale = 1
    return
end;opan::initNewDataObjects
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
pro opan::clearAllCurves, event = event


    ; We can't just remove the objects from the container.  We actually have to
    ; free up each of the objects here...
    ngroups = n_elements(*self.ocurveGroup)

    if total(obj_valid(*self.ocurveGroup)) eq 0 then return

    for j = 0,ngroups-1 do begin
      ncurves = (*self.ocurveGroup)[j]->count()
      if ncurves ne 0 then begin
        oall = (*self.ocurveGroup)[j]->get(/all)
        obj_destroy,oall
        (*self.ocurveGroup)[j]->remove,/all
      endif
    endfor


    wset,self.resPix
    erase
    wset,self.resVis
    erase
    self->refresh

    ;wset,self.datPix
    ;self->displaydata
    ;wset,self.datVis
    ;device,copy = [0,0,!d.x_size,!d.y_size,0,0,self.datPix]

    widget_control,self.curveSlider,set_slider_max = 2

    return
end;opan::clearAllCurves
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
pro opan::clearCurrentCurves, event = event
    ; Clears the curves from those in the current slider position

    widget_control,self.groupSlider,get_value = val
    val = fix(val[0]) - 1
    if n_elements(*self.dataPtr) eq 0 then return
    datSize = size(*self.dataPtr)
    if datSize[0] eq 1 then val = 0
    oc = (*self.ocurveGroup)[val]


;CHECK THAT oc IS A VALID OBJECT!!!!!
;
;IS THERE A REASON THAT THIS SHOULD BE UNDEFINED???
;YES: self.oCurveGroup IS INITIALIZED AS A POINTER BUT MAY NOT YET POINT TO AN OBJECT.
;
;NOTE ALSO THAT THE CHECK IS DONE ABOVE IN opan::clearAllGroups!!!
    if obj_valid(oc) gt 0 then begin
      ncurves = oc->count()
    endif else begin
      ncurves = 0
    endelse
    if ncurves eq 0 then return

    ; We can't just remove the objects from the container.  We actually have to
    ; free up each of the objects here...
    oall = oc->get(/all)
    obj_destroy,oall
    oc->remove,/all

    wset,self.resVis
    erase

    self->refresh
    ;wset,self.datPix
    ;self->displaydata
    ;wset,self.datVis
    ;device,copy = [0,0,!d.x_size,!d.y_size,0,0,self.datPix]

    widget_control,self.curveSlider,set_slider_max = 2

    return
end;opan::clearCurrentCurves


pro opan::selectCurve, event = event
    ; Here I have used an unsatisfactory solution and implemented a modal
    ; widget dialog for parameter entry when the preferences are set
    ; such that the user can input only via a dialog or the type of
    ; curve demands it (i.e. it cannot be drawn with two clicks of the
    ; mouse or it is a user function).
    ncurvetypes = n_elements(*self.curvenamesPtr)

    ;#############  USER FUNCTION  ###################
    ; We begin by considering a user-defined function
    if event.value eq (ncurvetypes-2) then begin    ;USERFUNCTION
        if n_elements(*self.dataPtr) eq 0 then return

        out = enterfunction(group_leader = event.top,directory = self.workDir)
        if out.cancel eq 1 then return

        parmStr = getparmsfromexpr(out.expr)
        help,parmStr,output = output
        test = strpos(output,'STRING')
        if test[0] eq (-1L) then return

        nparms = n_elements(parmStr)
        parms = replicate(1d,nparms)
        name = 'pan_userfunction'


        self->extractDataForPAN,dat=dat,derr=daterr,x=x,y=y,val=val,dSize=datSize

        Qgroup = y[0]
        test = pan_userfunction(x,parms,QGroup=Qgroup,$
                                   expr = out.expr, $
                                   eval = eval)
        if eval ne 1 then return

        Qgroup = y[0]
        *self.ocurrentPtr = obj_new("func",name = name, $
                      xvalues = x, $
                      Qgroup=QGroup,$
                      expr = out.expr, $
                      parms = parms,$
                      xtabPtr = self.xtabPtr, $
                      ytabPtr = self.ytabPtr, $
                      btabPtr = self.btabPtr, $
                      ttabPtr = self.ttabPtr)

        (*self.ocurveGroup)[val] -> add,*self.ocurrentPtr
        parmInfo = self->packageParmInfo()

        oc = (*self.ocurveGroup)[val]
        ncurves = oc->count()
        widget_control,self.curveSlider,set_slider_max = (ncurves > 2)
    endif;event.value eq (ncurvetypes-2)   ;USERFUNCTION
    ;#############  END USER FUNCTION  ###################


    ;#############  USER MACRO  ###################
    if event.value eq (ncurvetypes-1) then begin ; user macro

        if n_elements(*self.dataPtr) eq 0 then return


        ;ENTER THE MACRO DEFINITION HERE:
        out = entermacro(group_leader = event.top,directory = self.workDir)
        ;      help,out
        ;      print,tag_names(out)
        if out.cancel eq 1 then return

        ; save the macro into a temporary file and then save the filename
        workDir = self.workDir
        macro = *out.pexpr
        ptr_free,out.pexpr
        date = systime()
        result = strsplit(date,' ',/extract)
        strout = strtrim(result[0],2)
        for j = 1,n_elements(result)-1 do begin
        strout = strout+strtrim(result[j],2)
        endfor
        result = strsplit(strout,':',/extract)
        strout = strtrim(result[0],2)
        for j = 1,n_elements(result)-1 do begin
        strout = strout+strtrim(result[j],2)
        endfor

        ;WRITE MACRO TO FILE AND SAVE FILENAME
        macro_file = workDir+strout+'.mf'
        openw,lun,macro_file,/get_lun
        for i = 0,n_elements(macro)-1 do printf,lun,macro[i]
        free_lun,lun,/force
        self.macro_file = macro_file

        ;CALL pan_macrofunction TO CREATE THE parmnames AND parms ARRAYS.
        ; Get the parameter names and generate a vector that is the same length as
        ; the parameter vector with ones in it.
        name = 'pan_macrofunction'
        ret = call_function(name,parmnames = parmnames,fit_fun_filename = self.macro_file)
        ;print,parmnames
        nparms = n_elements(parmnames)
        parms = replicate(1d,nparms)


        ;GET THE DATA FOR THE CURRENT GROUP
        self->extractDataForPAN,dat=dat,derr=daterr,x=x,y=y,val=val,dSize=datSize

        ;CHECK pan_macrofunction
        ;      test = pan_macrofunction(x,parms,fit_fun_filename = self.macro_file,eval = eval)

        ;040607
        ;LRK
        ;THIS IS WHERE THE Qvalue IS RETRIEVED AND INPUT INTO THE CURVE GROUP FOR opan::selectCurve
        ;SEE ALSO obj_new('func', . . .) below

        test = pan_macrofunction(x,parms,Qgroup=y[0],fit_fun_filename = self.macro_file,eval = eval)
        if eval ne 1 then return

        help,*self.ocurrentPtr,output=helpout
        undefinedflag = 0
        for i=0,n_elements(helpout)-1 do begin
            if stregex(strupcase(helpout[i]),'UNDEFINED',/boolean) ne 0 then undefinedflag = 1
        endfor;i


        if undefinedflag ne 0 then begin
            self.ocurrentPtr = ptr_new(obj_new("func",name = name, $
                                              xvalues = x, $
                                              qgroup = y[0],$
                                              fit_fun_filename = self.macro_file,   $
                                              parms = parms,$
                                              xtabPtr = self.xtabPtr, $
                                              ytabPtr = self.ytabPtr, $
                                              btabPtr = self.btabPtr, $
                                              ttabPtr = self.ttabPtr))
        endif else begin
            *self.ocurrentPtr = obj_new("func",name = name, $
                                          xvalues = x, $
                                          qgroup = y[0],$
                                          fit_fun_filename = self.macro_file,   $
                                          parms = parms,$
                                          xtabPtr = self.xtabPtr, $
                                          ytabPtr = self.ytabPtr, $
                                          btabPtr = self.btabPtr, $
                                          ttabPtr = self.ttabPtr)

        endelse

        (*self.ocurveGroup)[val] -> add,*self.ocurrentPtr

        parmInfo = self->packageParmInfo()

        oc = (*self.ocurveGroup)[val]
        ncurves = oc->count()
        widget_control,self.curveSlider,set_slider_max = (ncurves > 2)


    endif;event.value eq (ncurvetypes-1)   ; user macro



    if (event.value ne ncurvetypes-1) and $
       (event.value ne ncurvetypes-2) then begin
    ; Now consider any of the library of functions
       name = strlowcase((*self.curvenamesPtr)[event.value])
       if (name eq 'delta' and n_elements(*self.resPtr) eq 0) or $
         (name eq 'qens' and n_elements(*self.resPtr) eq 0) or $
         (name eq 'qens_kohlrausch' and n_elements(*self.resPtr) eq 0) then begin
         strout = 'You must load a resolution function first!'
         void = dialog_message(dialog_parent = event.top,strout)
         return
       endif
       name = strtrim('pan_'+name,2)
       if n_elements(*self.dataPtr) eq 0 then return


    self->extractDataForPAN,dat=dat,derr=daterr,x=x,y=y,val=val,dsize=datSize


       if (strupcase(name) eq 'PAN_KOHLRAUSCH') or $
        (strupcase(name) eq 'PAN_QENS_KOHLRAUSCH') then begin
         step = [0.0d,0.01d,0.01d]
         ; Now load in the Kohlrausch table (only if necessary) and
         ; scale the table
         ret = self.otable->is_ktable_loaded(loaded = loaded)
         if not loaded then begin
         msg = 'Reading in lookup tables'
         self->flashMessage_create,msg,base
         endif
         ret = self.otable->get_ktable(ktable_ptr = ktable_ptr)
         if not loaded then begin
            self->flashMessage_destroy,base
         endif
         *self.ktablePtr = *ktable_ptr
         self->scaleKtable
       endif

        if (n_elements(*self.resPtr) gt 0) then begin
    ;       *self.oneResPtr = (reform((*self.resPtr).data[*,val]))
    ;       rlimit = (*self.resPtr).rlimit
           resStr = (*self.resPtr)

           ;020508
           ;COMMENT OUT THE NEXT BLOCK AND REPLACE WITH
           ;THE METHOD CALL BELOW IT.  NOTE: IN THIS CASE I 
           ;NEED TO GET resStr
;           (*self.oneResPtr) = {x:resStr.x,y:resStr.y $
;                                ,data:(reform(resStr.data[*,val])) $
;                                ,rlimit:resStr.rlimit}
           resExists = self->ExtractOneResStr(val,OneResStr)
           rlimit = resStr.rlimit

           if resExists ne 0 then begin
             (*self.oneResPtr) = OneResStr
             ; Select parameters
             *self.ocurrentPtr = obj_new("func",name = name,xvalues = x,$
                                 xtabPtr = self.xtabPtr, $
                                 ytabPtr = self.ytabPtr, $
                                 ttabPtr = self.ttabPtr, $
                                 btabPtr = self.btabPtr, $
                                 resPtr = self.oneResPtr, $
                                 step = step, $
                                 rlimit = rlimit)
           endif else begin
             ;020508
             ;WARN USER AND PROCEED WITH NO RESOLUTION DATA FOR THIS GROUP.
             void_message = ['THERE IS NO RESOLUTION DATA FOR GROUP#'+strtrim(string(val),2),$
                             'PROCEEDING WITH NO RESOLUTION FOR GROUP#'+strtrim(string(val),2)]
             void = dialog_message(void_message)
             self->clearOneRes_ptr             
             *self.ocurrentPtr = obj_new("func",name = name,xvalues = x,$
                                 step = step, $
                                 xtabPtr = self.xtabPtr, $
                                 ytabPtr = self.ytabPtr, $
                                 ttabPtr = self.ttabPtr, $
                                 btabPtr = self.btabPtr)
           endelse 
           

        endif else begin
         ;NO RES DATA LOADED
         *self.ocurrentPtr = obj_new("func",name = name,xvalues = x,$
                             step = step, $
                             xtabPtr = self.xtabPtr, $
                             ytabPtr = self.ytabPtr, $
                             ttabPtr = self.ttabPtr, $
                             btabPtr = self.btabPtr)
        endelse
    endif

    ; Now check if we are adding the AUTOGAUSSIAN or AUTOLORENTZIAN function...
    if strupcase(name) eq 'PAN_AUTOGAUSSIAN' or $
       strupcase(name) eq 'PAN_AUTOLORENTZIAN'then begin
       ; Estimate the background
       ymin = dat[sort(dat)]

       if n_elements(ymin) gt 5 then $
          bg = (moment(ymin[0:4]))[0] else $
          bg = ymin[0]


;LRK NOTE:
;get_peak_pos REQUIRES A CERTAIN NUMBER OF POINTS.  IF IT DOESN'T GET THEM IT WILL CRASH.
       ; Estimate the peak parameters
       xpeaks = get_peak_pos(x,dat-bg,1,fwhm = fwhm)

       case strupcase(name) of
       'PAN_AUTOGAUSSIAN':  $
          begin
             sig = fwhm/2.354
;063008
;IT LOOKS LIKE THE USE OF y IN THE NEXT LINE WAS A MISTAKE, AND ymin IS THE CORRECT VARIABLE TO CHECK             
;GAUSSIAN FIT WOULD BE FAIRLY INSENSITIVE TO THE AREA INPUT PARAMETER IN MOST CASES, BUT NOT ALL.
             area = sqrt(2.0*!pi)*sig*(max(ymin)-bg)
;             area = sqrt(2.0*!pi)*sig*(max(y)-bg)
             parms = [area,xpeaks[0],fwhm,bg]
          end
       'PAN_AUTOLORENTZIAN':   $
          begin
             gam = 0.5*fwhm
;063008
;IT LOOKS LIKE THE USE OF y IN THE NEXT LINE WAS A MISTAKE, AND ymin IS THE CORRECT VARIABLE TO CHECK             
;LORENTZIAN FIT WOULD BE FAIRLY INSENSITIVE TO THE AREA INPUT PARAMETER IN MOST CASES, BUT NOT ALL.
             area = (max(ymin)-bg)*!pi*gam
;             area = (max(y)-bg)*!pi*gam
             parms = [area,xpeaks[0],fwhm,bg]
          end
       else:
       endcase


       ; Remove all of the function objects in the
       ; current object container
       oc = (*self.ocurveGroup)[val]

       self->clearCurrentCurves, event = event

;AT THIS STAGE, OC NEEDS TO BE A VALID OBJECT!!!!
       oc -> add,*self.ocurrentPtr

       parmInfo = self->packageParmInfo()

       oc->setparms,parms

       ; Now use least squares to fit it
       self->fitOneGroup,event = event

       return
    endif;strupcase(name) eq 'PAN_AUTOGAUSSIAN' or $
         ;strupcase(name) eq 'PAN_AUTOLORENTZIAN'then begin


    ; Ok...now do we add the curve using a mouse or using a dialog?
    initGuesses = (*self.prefs).initGuesses
    if initGuesses eq 1 and (name ne 'pan_userfunction') then begin
            ; Use dialog input
              (*self.ocurveGroup)[val] -> add,*self.ocurrentPtr
              parmInfo = self->packageParmInfo()

              enterparminfo,  parmInfo, $
                              group_leader = event.top, $
                              notifyIds = [event.id,event.top], $
                              modal = 1, $
                              parmInfoOut = parmInfoOut

              dummy = self->updateParmInfo(parmInfoOut)

              self->refresh

              return
    endif;initGuesses eq 1 and (name ne 'pan_userfunction')

    *self.ocurrentPtr->getProperty,canDraw = canDraw


    if (initGuesses eq 0) and (canDraw eq 1) then begin
            ; Use mouse input
              self.addcurve = 1
              drawMessage = *self.ocurrentPtr->getDrawMessage()
              widget_control,self.info,set_value = drawMessage[0:1]
              return
    endif;not INITGUESS AND CANDRAW

    if (initGuesses eq 0) and (canDraw eq 0) then begin
            ; Use dialog input
              if (name ne 'pan_userfunction') and (name ne 'pan_macrofunction') then begin
                  (*self.ocurveGroup)[val] -> add,*self.ocurrentPtr
                parmInfo = self->packageParmInfo()
              endif
              enterparminfo,  parmInfo, $
                              group_leader = event.top, $
                              notifyIds = [event.id,event.top], $
                              modal = 1, $
                              parmInfoOut = parmInfoOut
              dummy = self->updateParmInfo(parmInfoOut)

              self->refresh

              return
    endif;not INITGUESS AND not CANDRAW

    return
end;opan::selectCurve
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
pro opan::zoomEvents, event = event

    case event.type of
    0: begin    ; button press
         self.mouse = event.press
         if self.mouse eq 4 then begin
           self.autoscale = 1

           !x = *self.datxPtr
           !y = *self.datyPtr
           self->refresh
         endif
         if self.mouse eq 1 then begin
           self.xbox[0] = event.x
           self.ybox[0] = event.y
           !x = *self.datxPtr
           !y = *self.datyPtr
           self->refresh
           empty
           self.autoscale = 0
           widget_control,self.datWin,/draw_motion_events
         endif
       end
    1: begin ; button release
        if self.mouse eq 1 then begin
         xll = self.xbox[0] < self.xbox[1]
         yll = self.ybox[0] < self.ybox[1]
         w = abs(self.xbox[1] - self.xbox[0])
         h = abs(self.ybox[1] - self.ybox[0])
         xur = xll + w
         yur = yll + h
         !x = *self.datxPtr & !y = *self.datyPtr
         ll = convert_coord(xll,yll,/device,/to_data)
         ur = convert_coord(xur,yur,/device,/to_data)
         self.xrange = [ll[0],ur[0]]
         self.yrange = [ll[1],ur[1]]

         !x = *self.datxPtr
         !y = *self.datyPtr

         self->refresh

         self.mouse = 0B
         widget_control,self.datWin,draw_motion_events = 0
        endif
        if self.mouse eq 4 then begin
           self->refresh
         self.mouse = 0B
         widget_control,self.datWin,draw_motion_events = 0
        endif
       end
    2: begin ; mouse motion
         if self.mouse eq 1 then begin
            self.xbox[1] = event.x
            self.ybox[1] = event.y
            xc = [self.xbox[0],event.x,event.x,$
                  self.xbox[0],$
                  self.xbox[0]]
            yc = [self.ybox[0],self.ybox[0],$
                  event.y,event.y,$
                  self.ybox[0]]
         !x = *self.datxPtr & !y = *self.datyPtr
            wset,self.datVis
            device,copy = [0,0,!d.x_size,!d.y_size,0,0,self.datPix] ;THE datPix IMAGE IS SAVED, SO NO MODS NEEDED HERE.
            plots,xc,yc,/device,color=(*self.color_ptr).green


            empty
         endif
       end
    else:
    endcase
    return
end;opan::zoomEvents
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
pro opan::drawCurveEvents, event = event
;print,'opan::drawCurveEvents   020508'
;print,'I ENDED UP WORKING ON THE oneResStr EXTRACTION AT THIS POINT '

    widget_control,self.groupSlider,get_value = val
    val = fix(val[0])-1
    datSize = size(*self.dataPtr)
    if datSize[0] eq 1 then val = 0
    xrange = self.xrange

;THIS REQUIRES A CHANGE

    resExists = self->ExtractOneResStr(val,OneResStr)
    if resExists eq 0 then self->clearOneRes_ptr
    if n_elements(*self.resPtr) gt 0 then begin
       ;*self.oneResPtr = reform((*self.resPtr).data[*,val])

       ;020508
       ;REPLACE THE NEXT 4 LINES WITH THE METHOD CALL BELOW IT
;       resStr = (*self.resPtr)
;       (*self.oneResPtr) = {x:resStr.x,y:resStr.y $
;                            ,data:(reform(resStr.data[*,val])) $
;                            ,rlimit:resStr.rlimit}

           ;resExists = self->ExtractOneResStr(val,OneResStr)
           if resExists ne 0 then begin
             (*self.oneResPtr) = OneResStr
           endif else begin
             self->clearOneRes_ptr             
             ;print,'opan::drawCurveEvents NO resData For Group#'+strtrim(string(val),2) 
           endelse
                              
    endif


;030707
;
;NOTE: THE RES STUFF NEEDS TO BE UPDATED

    fg_color=(*self.color_ptr).black
    case event.type of
    0: begin    ; button press
         self.mouse = event.press
         if self.mouse eq 1 then begin
            dcoords = convert_coord(event.x,event.y,/device,/to_data)

           if self.addcurve eq 1 then begin
             (*self.ocurveGroup)[val] -> add,*self.ocurrentPtr
              *self.ocurrentPtr->changefirst,dcoords[0],dcoords[1],xrange
              widget_control,self.datWin,/draw_motion_events
           endif
           if self.addcurve eq 2 then begin
              *self.ocurrentPtr->changesecond,dcoords[0],dcoords[1],xrange
              widget_control,self.datWin,/draw_motion_events
           endif
            wset,self.datVis
           device,copy = [0,0,!d.x_size,!d.y_size,0,0,self.datPix]

;020608
;
;NOTE: func_cont::draw USES self.oneResPtr ONLY IF IT IS DEFINED, BUT THIS COULD BE A PROBLEM
;      IF IT WAS DEFINED FOR A GROUP WITH A RESOLUTION BUT NOT UNDEFINED.
;SO
;CHANGE THE NEXT LINE TO THE if-then-else BLOCK BELOW IT 

            ;021108
            ;CHANGE IT BACK BECAUSE func_cont DOES A TEST ON *self.oneResPtr AND NEEDS A VALID
            ;POINTER TO DEREFERENCE
            (*self.ocurveGroup)[val]->draw,overplot = 1,resPtr = self.oneResPtr,color=fg_color
;            if resExists ne 0 then begin
;              (*self.ocurveGroup)[val]->draw,overplot = 1,resPtr = self.oneResPtr,color=fg_color
;            endif else begin
;              (*self.ocurveGroup)[val]->draw,overplot = 1,color=fg_color
;            endelse
         endif
       end
    1: begin ; button release
         dcoords = convert_coord(event.x,event.y,/device,/to_data)
         if self.mouse eq 1 then begin
           if self.addcurve eq 1 then begin
             *self.ocurrentPtr->changefirst,dcoords[0],dcoords[1],xrange
          widget_control,self.datWin,draw_motion_events = 0
          drawMessage = *self.ocurrentPtr->getDrawMessage()
          widget_control,self.info,set_value = drawMessage[2:3]
             endif
           if self.addcurve eq 2 then begin
             *self.ocurrentPtr->changesecond,dcoords[0],dcoords[1],xrange
             widget_control,self.datWin,draw_motion_events = 0
             widget_control,self.info,set_value = ''
             endif
            endif
            wset,self.datVis
           device,copy = [0,0,!d.x_size,!d.y_size,0,0,self.datPix]

            ;020608 
            ;CHANGE NEXT LINE TO if-then-else STATEMENT BELOW IT
            ;021108
            ;CHANGE IT BACK BECAUSE func_cont DOES A TEST ON *self.oneResPtr AND NEEDS A VALID
            ;POINTER TO DEREFERENCE
            (*self.ocurveGroup)[val]->draw,overplot = 1,resPtr = self.oneResPtr,color=fg_color  
;            if resExists ne 0 then begin
;              (*self.ocurveGroup)[val]->draw,overplot = 1,resPtr = self.oneResPtr,color=fg_color
;            endif else begin
;              (*self.ocurveGroup)[val]->draw,overplot = 1,color=fg_color
;            endelse



         self.mouse = 0B
         self.addcurve = self.addcurve + 1
         if self.addcurve eq 3 then begin
           self.addcurve = 0
           wset,self.datPix
         self->displaydata
         wset,self.datVis
         device,copy = [0,0,!d.x_size,!d.y_size,0,0,self.datPix]
         oc = (*self.ocurveGroup)[val]
         ncurves = oc->count()
           widget_control,self.curveSlider,set_slider_max = (ncurves > 2)
         endif
       end
    2: begin ; mouse motion
         dcoords = convert_coord(event.x,event.y,/device,/to_data)
         if self.mouse eq 1 then begin
           if self.addcurve eq 1 then begin
             *self.ocurrentPtr->changefirst,dcoords[0],dcoords[1],xrange
             endif
           if self.addcurve eq 2 then begin
             *self.ocurrentPtr->changesecond,dcoords[0],dcoords[1],xrange
             endif
            endif
            wset,self.datVis
           device,copy = [0,0,!d.x_size,!d.y_size,0,0,self.datPix]
            ;020608 
            ;CHANGE NEXT LINE TO if-then-else STATEMENT BELOW IT
            ;021108
            ;CHANGE IT BACK - func_cont::draw CHECK FOR n_elements(*self.OneResPtr), SO 
            ;                 IT NEEDS A POINTER TO DEREFERENCE IN ITS ARGUMENT.
            (*self.ocurveGroup)[val]->draw,overplot = 1,resPtr = self.oneResPtr,color=fg_color  
;            if resExists ne 0 then begin
;              (*self.ocurveGroup)[val]->draw,overplot = 1,resPtr = self.oneResPtr,color=fg_color
;            endif else begin
;              (*self.ocurveGroup)[val]->draw,overplot = 1,color=fg_color
;            endelse

       end
    else:
    endcase
    return
end;opan::drawCurveEvents
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
pro opan::drawEvents, event = event

    if n_elements(*self.dataPtr) eq 0 then return
    !x = *self.datxPtr
    !y = *self.datyPtr
    case self.addcurve of
    0: begin
         self->zoomEvents,event = event
       end
    1: begin
         self->drawCurveEvents, event = event
       end
    2: begin
         self->drawCurveEvents, event = event
       end
    else:
    endcase

    return
end;opan::drawEvents
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
pro opan::resize,event = event
    ctrlgeom = widget_info(self.ctrlbase,/geometry)
    infogeom = widget_info(self.infobase,/geometry)
    xsize = event.x
    ysize = event.y

    if !version.os eq 'Win32' then begin
        xpad = 16 & ypad = 13
    endif else begin
        xpad = 18 & ypad = 47
    endelse



    if xsize lt ctrlgeom.xsize+infogeom.xsize then xsize = ctrlgeom.xsize+infogeom.xsize + 50
    if ysize lt ctrlgeom.ysize then ysize = ctrlgeom.ysize

    xsize = xsize-xpad
    ysize = ysize-ypad



    ; New data window dimensions
    newxsize = xsize-ctrlgeom.xsize-infogeom.xsize
    newysize = fix(ysize*(self.winRatio/(1.0+self.winRatio)))


    widget_control,self.datWin,draw_xsize = newxsize, $
                   draw_ysize = newysize
    wdelete,self.datPix
    window,/free,/pixmap,xsize = newxsize,ysize = newysize
    self.datPix = !d.window

    ; New residual window dimensions
    newysize = fix(ysize/(1.0+self.winRatio))

    widget_control,self.resWin,draw_xsize = newxsize, $
                   draw_ysize = newysize
    wdelete,self.resPix
    window,/free,/pixmap,xsize = newxsize,ysize = newysize
    self.resPix = !d.window

    self->refresh

    return
end;opan::resize
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
pro opanEvents,event



    ;CHECK FOR !debug IN CASE THIS WAS NOT STARTED FROM DAVE.

    ; RTA - Insert Basic error Handler
    defsysv,'!debug',exists=debugging
    if debugging eq 1 then begin
        if (n_elements(!debug) && (!debug eq 0)) then begin
            catch, catchError
            if (catchError ne 0) then begin
                ;;print, 'Error handled!'
                eTitle = 'PAN: 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
    endif else begin
            catch, catchError
            if (catchError ne 0) then begin
                ;;print, 'Error handled!'
                eTitle = 'PAN: 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
    endelse


    if dave_set_focus(event) then return
    if tag_names(event,/structure_name) eq 'WIDGET_BASE' then begin
      widget_control,event.top,get_uvalue = self
      self->resize,event = event
      return
    endif
    if tag_names(event,/structure_name) eq 'CORREL_EVENT' then return
    widget_control,event.id,get_uvalue = cmd
    if tag_names(event,/structure_name) eq 'CW_COLOR_BUTTON_EVENT' then begin
       print,cmd.method
       print,cmd.object
    endif
    call_method,cmd.method,cmd.object,event = event
    return
end;opanEvents
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
pro opan::displayFitParameters, event = event

;030707
;
;NO UPDATE NEEDED HERE, BUT WHAT ABOUT ocurveGroup???

    widget_control,self.groupSlider,get_value = val
    val = fix(val[0])-1
    if n_elements(*self.dataPtr) eq 0 then return
    datSize = size(*self.dataPtr)
    if datSize[0] eq 1 then val = 0
    oc = (*self.ocurveGroup)[val]
    oc->displayparms,output = output
    if n_elements(output) ne 0 then begin
       widget_control,self.info,set_value = output
    endif else begin
       widget_control,self.info,set_value = 'No curves selected'
    endelse
    return
end;opan::displayFitParameters
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
pro opan::displaydata,_Extra = extra,ps_out = ps_out

    ; If resolution is loaded then check if nos of groups is the same for
    ; resolution and signal datasets
    if (n_elements(*self.resPtr) gt 0) then begin
       dSize = size(*self.dataPtr)
       nd = (dSize[0] eq 2)? dSize[2] : 1
       rSize = size((*self.resPtr).data)
       nr = (rSize[0] eq 2)? rSize[2] : 1
       if (nr ne nd) then begin
          msg = ['Signal and resolution dataset groups do not match' $
                 ,'There are '+strtrim(string(nd),2)+' groups in signal dataset' $
                 ,'There are '+strtrim(string(nr),2)+' groups in resolution dataset' $
                 ,'Consider changing the signal OR the resolution data before proceeding' ]
          void = dialog_message(msg,/error)
          return                    ; exit
       endif
    endif

    if n_elements(ps_out) eq 0 then ps_out = 0

    if n_elements(*self.dataPtr) eq 0 then return
    self->extractDataForPAN,dat=dat,derr=daterr,x=x,y=y,val=val,dsize=datSize
;NOTE:  val = group# - 1 

    thisFormat = '(f10.5)'
    this = self.ytitle+'='
    ;self.title = '!6Q='+strtrim(string(y,format = thisformat),2)

;030807
;REPLACE THE NEXT LINE WITH THE ONE THAT FOLLOWS IT
;    self.title = this+strtrim(string(y,format = thisformat),2)
    self.title = this+strtrim(string(y[0],format = thisformat),2)

    if self.autoscale eq 1 then begin
      dx = 0.1*(max(x)-min(x))
      self.xrange = [min(x)-dx,max(x)+dx]
      dy = 0.1*(max(dat)-min(dat))
      self.yrange = [min(dat-daterr)-dy,max(dat+daterr)+dy]
    endif


    if (*self.prefs).xenforce eq 1 then begin
      self.xrange = [(*self.prefs).xmin,(*self.prefs).xmax]
    endif
    if (*self.prefs).yenforce eq 1 then begin
      self.yrange = [(*self.prefs).ymin,(*self.prefs).ymax]
    endif

    if ps_out then begin
      color_1 = (*self.color_ptr).black
      color_2 = color_1;
      color_3 = color_1;(*self.color_ptr).sky
      color_4 = color_1
      color_5 = color_1
      fg_color = color_1
      bg_color = (*self.color_ptr).white
    endif else begin
      color_1 = (*self.color_ptr).black
      color_2 = (*self.color_ptr).white
      color_3 = (*self.color_ptr).sky
      color_4 = (*self.color_ptr).red
      color_5 = (*self.color_ptr).blue
      fg_color = color_1
      bg_color = color_2
    endelse

    plot,x,dat,psym=4,symsize=1.5,xtitle=self.xtitle,ytitle=self.ztitle,title=self.title $
         ,xrange=self.xrange,yrange=self.yrange,xstyle=1,ystyle=1,_Extra=extra $
         ,color=fg_color,background=bg_color,charsize=1.25;,/nodata
    ;oplot,x,dat,psym = 4,color = color_2
    errplot,x,dat-daterr,dat+daterr,width=0.0,color=fg_color
    ;hfbs_cerrplot,x,dat-daterr,dat+daterr,width = 0.0,errcolors = {thisColor:color_2}
    ; Draw the fit range if in the viewable window
    xfitLo = (*self.prefs).xfitlo
    xfitHi = (*self.prefs).xfithi
    xdispLo = (!x.crange)[0]
    xdispHi = (!x.crange)[1]

    if xfitLo gt xdispLo then $
      plots,[xfitLo,xfitLo],!y.crange,linestyle = 2;,color = color_3

    if xfitHi lt xdispHi then $
      plots,[xfitHi,xfitHi],!y.crange,linestyle = 2;,color = color_3

    if obj_valid((*self.ocurveGroup)[val]) then begin

      ncurves = (*self.ocurveGroup)[val]->count()
      ocurves = (*self.ocurveGroup)[val]

      ;; If the nos of data points within the display range is less than
      ;; xLen, then increase the x values to xLen before evaluating the
      ;; model function for display.
      xIsModified = 0
      xLen = 100

      validIndex = where(x ge self.xrange[0] and x le self.xrange[1],count)
      xvalid = x
      oFuncs = ocurves->get(/all,count=nFuncs)

      if (count gt 2 && count lt xLen && nFuncs gt 0) then begin
         xlo = self.xrange[0] & xhi = self.xrange[1]
         
         ;013008
         ;ORIGINAL SETS THE NUMBER OF x VALUES TO 100; I WILL SIMPLY 
         ;SET xValid TO BE x BEFORE DOING IT FOR THE oFuncs 
         xValid = xlo + findgen(xLen)*(xhi-xlo)/(xLen -1)

         for i = 0,nFuncs-1 do begin
            oFuncs[i]->setproperty,xvalues = xValid, /calculate
         endfor

         xIsModified = 1
      endif

      ocurves->drawcomponents,linestyle = 2,thick = 2.5,color = color_4     ;RED

;012908
;
;resPtr:  Does resPtr cause Tim's problem with plotting and large eb?
      if n_elements(*self.resPtr) gt 0 then begin
        ;print,'EVALUATE oCurves WITH RESOLUTION'
 
 ;020508
 ;IF func_cont AND func ARE TO BE UNCHANGED, I HAVE TO GET THE MASKED RES DATA AT THIS POINT
 ;AND PASS THAT TO THE OCURVES HERE.
 ;
 ;NOTE: THERE IS ONE CURVE GROUP (func_cont) PER DATA GROUP, SO EACH CURVE GROUP HAS ITS OWN 
 ;      X, etc. VALUES FOR BOTH DATA AND RES!!! 
 ;

    ;    *self.oneResPtr = reform((*self.resPtr).data[*,val])
;020508
;REPLACE THE NEXT STATEMENT WITH THE COLLECTION IMMEDIATELY BELOW IT:
;         (*self.oneResPtr) = {x:(*self.resPtr).x $
;                              ,y:(*self.resPtr).y $
;                              ,data:reform((*self.resPtr).data[*,val]) $
;                              ,rlimit:(*self.resPtr).rlimit $
;                             }


           ;020508 THE NEXT BLOCK OF CODE SUPERCEDES THE ONE BELOW IT.
           resExists = self->ExtractOneResStr(val,OneResStr)
           if resExists ne 0 then begin
             ;(*self.oneResPtr) = OneResStr
             (*self.oneResPtr) = OneResStr
             ocurves->evaluate,xValid,yout = yout,resPtr = self.oneResPtr
           endif else begin
             ;void = dialog_message('opan::drawCurveEvents NO resData For Group#'+strtrim(string(val),2)) 
             ;void = dialog_message('opan::drawCurveEvents What do I do???????') 
             self->clearOneRes_ptr

             void = dialog_message('No Resolution Data for Group #'+strtrim(string(val+1),2))
             ocurves->evaluate,xValid,yout = yout             
           endelse
;020508 COMMENT OUT THE NEXT LONG BLOCK OF CODE.  IT IS SUPERCEDED BY THE BLOCK JUST ABOVE THIS LINE
;         mask = (*self.resptr).mask[*,val]
;         whnotmasked = where(mask ne 0,notmaskcount)
; 
;;print,'notmaskcount=',notmaskcount
;         if notMaskCount eq 0 then begin
;             void = dialog_message('No Resolution Data for Group #'+strtrim(string(val),2))
;         endif else begin
;             xOneRes = (*self.resPtr).x[whnotmasked]
;             yOneRes = (*self.resPtr).y[whnotmasked]
;             dataOneRes = reform((*self.resPtr).data[whnotmasked,val])
;             rlimitOneRes = (*self.resPtr).rlimit
;             (*self.oneResPtr) = {x:xOneRes,$
;                                  y:yOneRes,$
;                                  data:dataOneRes,$
;                                  rlimit:rlimitOneRes}
; 
;
;    
;    
;    ;help,xvalid
;    ;help,(*self.resPtr).x,(*self.resPtr).y,(*self.resPtr).data[*,val],(*self.resPtr).rlimit
;    ;help,ocurves
;            ocurves->evaluate,xValid,yout = yout,resPtr = self.oneResPtr
;         endelse
      endif else begin
      
        ;NO RESOLUTION
        ;print,'EVALUATE oCurves WITH NO RESOLUTION'
        ocurves->evaluate,xValid,yout = yout
      endelse


      if n_elements(yout) gt 1 then begin
        ; Is there a resolution function present?  Yes -> do the convolution!
       fitcolor = (*self.color_ptr).red

        ;020608
        ;REPLACE THE NEXT if-thenelse WITH THE ONE BELOW IT
;        if n_elements(*self.resPtr) gt 0 then begin
;    ;      *self.oneResPtr = (reform((*self.resPtr).data[*,val]))
;           (*self.oneResPtr) = {x:(*self.resPtr).x $
;                                ,y:(*self.resPtr).y $
;                                ,data:reform((*self.resPtr).data[*,val]) $
;                                ,rlimit:(*self.resPtr).rlimit $
;                               }
;          rlimit = (*self.resPtr).rlimit
;          ocurves->evaluate,xValid,yout = yout,resPtr = self.oneResPtr,rlimit = rlimit
;          oplot,xValid,yout,linestyle = 0,thick = 3.0,color = color_5       ;BLUE
;
;        endif else begin
;          oplot,xValid,yout,linestyle = 0,thick = 3.0,color = color_5       ;BLUE
;        endelse

         resExists = self->ExtractOneResStr(val,OneResStr)
         if resExists ne 0 then begin
           (*self.oneResPtr) = OneResStr
           rlimit=OneResStr.rlimit
           ocurves->evaluate,xValid,yout = yout,resPtr = self.oneResPtr,rlimit = rlimit
           oplot,xValid,yout,linestyle = 0,thick = 3.0,color = color_5       ;BLUE
         endif else begin
           if resExists eq 0 then self->clearOneRes_ptr
           ;AT THIS POINT I AM ASSUMING THAT yout CONTAINS THE DATA CALCULATED ABOVE.
           oplot,xValid,yout,linestyle = 0,thick = 3.0,color = color_5       ;BLUE
         endelse

      endif else begin
        if (!d.name ne 'PS') and (!d.name ne 'PRINTER') and (self.jpeg ne 1) then wset,self.resVis
        if self.jpeg eq 0 then erase
      endelse

      ;; if the x values of the model function was altered for display
      ;; purposes, revert to the original x.
      if (xIsModified) then begin
         for i = 0,nFuncs-1 do begin
            oFuncs[i]->setproperty,xvalues = x, /calculate
         endfor
      endif
    endif
    *self.datxPtr = !x
    *self.datyPtr = !y

    ;if ((!d.name ne 'PS') and (!d.name ne 'PRINTER') and (self.jpeg ne 1)) then begin
    ;   device, decomposed=old_dc
    ;endif
    return
end;opan::displaydata
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
pro opan::plotResiduals, event = event,_Extra = extra,ps_out = ps_out


    if n_elements(*self.dataPtr) eq 0 then return
    if n_elements(ps_out) eq 0 then ps_out = 0


    widget_control,self.groupSlider,get_value = val
    val = fix(val[0])-1
    datSize = size(*self.dataPtr)
    if datSize[0] eq 1 then val = 0
    if not obj_valid((*self.ocurveGroup)[val]) then return

    ncurves = (*self.ocurveGroup)[val]->count()
    if ncurves eq 0 then begin
      erase
      return
    endif

    self->extractDataForPAN,dat=dat,derr=daterr,x=x,y=y,val=val,dsize=datSize


;
;    if datSize[0] eq 2 then begin
;      dat = (*self.dataPtr)[*,val]
;      daterr = (*self.errorPtr)[*,val]
;      x = (*self.xvalsPtr)[*,val]
;    endif else begin
;      dat = reform(*self.dataPtr)
;      daterr = reform(*self.errorPtr)
;      x = reform(*self.xvalsPtr)
;    endelse



;020608
;
;THIS IS SET IN opan::extractDataForPAN, BUT IS THAT THE CASE
;FOR EVERY TIME self.oneResPtr IS SET??????  NO!!! SEE, e.g. opan::DisplayData  

    if n_elements(*self.resPtr) gt 0 then begin

;020708
;REPLACE THE REST OF THIS if BLOCK WITH THE resExists if-then-else BLOCK
         resExists = self->ExtractOneResStr(val,OneResStr)
         
         if resExists ne 0 then begin
           (*self.oneResPtr) = OneResStr
           rlimit=OneResStr.rlimit
           (*self.ocurveGroup)[val]->evaluate,xValid,yout = yout,resPtr = self.oneResPtr,rlimit = rlimit
         endif else begin
           self->clearOneRes_ptr
           (*self.ocurveGroup)[val]->evaluate,x,yout = yout
         endelse

;
;      if datSize[0] eq 2 then begin
;    ;    *self.oneResPtr = (reform((*self.resPtr).data[*,val]))
;         (*self.oneResPtr) = {x:(*self.resPtr).x $
;                              ,y:(*self.resPtr).y $
;                              ,data:reform((*self.resPtr).data[*,val]) $
;                              ,rlimit:(*self.resPtr).rlimit $
;                             }
;      endif else begin
;    ;    *self.oneResPtr = (reform((*self.resPtr).data[*]))
;         (*self.oneResPtr) = {x:(*self.resPtr).x $
;                              ,y:(*self.resPtr).y $
;                              ,data:(*self.resPtr).data $
;                              ,rlimit:(*self.resPtr).rlimit $
;                             }
;      endelse
;
;
;
;      rlimit = (*self.resPtr).rlimit
;      (*self.ocurveGroup)[val]->evaluate,x,yout = yout,resPtr = self.oneResPtr,rlimit = rlimit
    endif else begin
      (*self.ocurveGroup)[val]->evaluate,x,yout = yout
    endelse

    if ps_out then begin
      color_1 = (*self.color_ptr).black
      color_2 = (*self.color_ptr).black
      fg_color = (*self.color_ptr).black
      bg_color = (*self.color_ptr).white
    endif else begin
      color_1 = (*self.color_ptr).white
      color_2 = (*self.color_ptr).yellow
      fg_color = (*self.color_ptr).black
      bg_color = (*self.color_ptr).white
    endelse
    residuals = (yout-dat)/daterr
    plot,x,residuals,psym = 0,xrange = self.xrange,xstyle = 1,xtitle = self.xtitle $
         ,ytitle = '!6Residuals',_Extra = extra,color = fg_color,background=bg_color $
         ,charsize=1.25              ;,/nodata
    ;oplot,x,residuals,psym = 0,color = color_2
    plots,!x.crange,[1.0,1.0],/data,linestyle = 2,thick = 1.5,color = fg_color
    plots,!x.crange,[-1.0,-1.0],/data,linestyle = 2,thick = 1.5,color = fg_color
    return
end;opan::plotResiduals
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
pro opan::rebinRestore,event = event

    ; Restore the original binning
    *self.xvalsPtr = *self.oxvalsPtr
    *self.yvalsPtr = *self.oyvalsPtr


    *self.dataPtr = *self.odataPtr

    *self.maskPtr = *self.omaskPtr
    *self.errorPtr = *self.oerrorPtr
    ;if n_elements(*self.resPtr) ne 0 then begin
    ;   *self.resPtr = *self.oresPtr
    ;   resStr = *self.resPtr
    ;   self->interpSigRes, resStr, rlimit = resStr.rlimit, event = event
    ;endif


    ; Recalculate the functions
    data = *self.dataPtr
    datSize = size(data)
    if datSize[0] eq 1 then begin ; a single group

       x = *self.xvalsPtr
       oc = (*self.ocurveGroup)[0]
       ncurves = oc->count()
       if ncurves gt 0 then begin
         if n_elements(*self.resPtr) gt 0 then begin
           resPtr = ptr_new((*self.resPtr).data[*,0])
          oc->setxvalues,x,resPtr = resPtr,yout = yout
          ptr_free,resPtr
         endif else begin
          oc->setxvalues,x,yout = yout
         endelse
       endif
    endif else begin
       ngrps = datSize[2]
       for i = 0,ngrps-1 do begin
         oc = (*self.ocurveGroup)[i]
         ncurves = oc->count()
         if ncurves gt 0 then begin
           x = reform((*self.xvalsPtr)[*,i])
           if n_elements(*self.resPtr) gt 0 then begin
             resPtr = ptr_new((*self.resPtr).data[*,i])
            oc->setxvalues,x,resPtr = resPtr,yout = yout
            ptr_free,resPtr
              endif else begin
            oc->setxvalues,x,yout = yout
           endelse
         endif
       endfor
    endelse

    if n_elements(*self.xtabPtr) ne 0 then $
       self->scaleKtable   ; added 04/09/03

    ; Display the data
    ;wset,self.resPix
    ;self->plotResiduals
    ;wset,self.resVis
    ;device,copy = [0,0,!d.x_size,!d.y_size,0,0,self.resPix]
    ;wset,self.datPix
    ;self->displaydata
    ;wset,self.datVis
    ;device,copy = [0,0,!d.x_size,!d.y_size,0,0,self.datPix]
    self->refresh

    return
end;opan::rebinRestore
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
pro opan::rebinData,event = event

    ;void = dialog_message('opan::rebinData --- THIS DOES NOT YET ACCOUNT FOR MASKING OF DATA OR RESOLUTION!!!!!')

    datamasked = self->checkDataMasked()
    if dataMasked gt 0 then begin
      msg = ['There are masked data points.',$
             'This will likely have adverse affects your binning results.',$
             'Continue with rebin?']
      yn = dialog_message(msg,/question)
      if yn eq 'No' then return
    endif


    widget_control,self.groupSlider,get_value = val
    val = fix(val[0])-1
    if n_elements(*self.dataPtr) eq 0 then return
    datSize = size(*self.dataPtr)
    if datSize[0] eq 2 then begin
        dat = (*self.dataPtr)[*,val]
        daterr = (*self.errorPtr)[*,val]
        x = (*self.xvalsPtr)[*,val]
        y = (*self.yvalsPtr)[0,val]
    endif else begin
        dat = reform(*self.dataPtr)
        daterr = reform(*self.errorPtr)
        x = reform(*self.xvalsPtr)
        y = (*self.yvalsPtr)
        val = 0
    endelse
    nx = n_elements(x)
    result = widget_rebin(x,group_leader = event.top,title='Rebin Signal Data')
    if result.cancel then return

    xlo = min(float(x), max=xhi)
    xlo = result.min > xlo
    xhi = result.max < xhi
    dx = result.binw

    nbins = fix((xhi - xlo)/dx) + 1

    if nbins gt nx then begin
      strout = 'Number of desired bins cannot exceed the number of input bins'
      void = dialog_message(dialog_parent = event.top,strout)
      return
    endif
    ; Ok, we've done the error checking...now do the rebinning
    ;xlo = result.xlo & xhi = result.xhi
    ;nbins = result.nbins
    ;dx = (xhi-xlo)/(nbins-1.0)
    x_out = xlo+dx*findgen(nbins)

    (*self.prefs).xfitlo = (*self.prefs).xfitlo > xlo
    (*self.prefs).xfithi = (*self.prefs).xfithi < xhi

    ; Consider single group first
    if datSize[0] eq 1 then begin
      x_in = x
      z_in = dat
      dz_in = daterr
      if (n_elements(x_in) eq n_elements(z_in)) then begin
          drebin,x_in,z_in,dz_in,x_out,z_out,dz_out,$
          /points,/to_points,err=err,emsg=emsg
      endif else begin
          drebin,x_in,z_in,dz_in,x_out,z_out,dz_out,$
          /hist,/to_hist,err=err,emsg=emsg
      endelse
      print,'Error message: ',emsg
    ;  drebin_points_wrapper,x_in,z_in,dz_in,x_out,z_out,dz_out
      *self.dataPtr = z_out
      *self.errorPtr = dz_out
      *self.xvalsPtr = x_out

;070108
      *self.maskPtr = byte(0*(*self.dataptr)) + 1b



    ;  ; Do we need to do this with a resolution function?
    ;  if n_elements(*self.resPtr) gt 0 then begin
    ;      ores = *self.resPtr
    ;      resStr = *self.resPtr
    ;      z_in = resStr.data
    ;      dz_in = 1.0+0.0*findgen(n_elements(z_in))
    ;      if (n_elements(x_in) eq n_elements(z_in)) then begin
    ;          drebin,x_in,z_in,dz_in,x_out,z_out,dz_out,$
    ;                 /points,/to_points,err=err,emsg=emsg
    ;      endif else begin
    ;          drebin,x_in,z_in,dz_in,x_out,z_out,dz_out,$
    ;                 /hist,/to_hist,err=err,emsg=emsg
    ;      endelse
    ;                                ;drebin,x_in,z_in,dz_in,x_out,z_out,dz_out,$
    ;                                ;   /points,/to_points,err=err,emsg=emsg
    ;                                ;drebin_points_wrapper,x_in,z_in,dz_in,x_out,z_out,dz_out
    ;     outStr = {x:x_out,y:resStr.y,data:z_out,rlimit:resStr.rlimit}
    ;     *self.resPtr = outStr
    ;   endif
    endif else begin
    ; Ok, now consider the general case of multiple groups
       ngrps = datSize[2]
       old = *self.dataPtr
       errold = *self.errorPtr
       newerr = dblarr(nbins,ngrps)
       new = dblarr(nbins,ngrps)
       xnew = dblarr(nbins,ngrps)
       if n_elements(*self.resPtr) gt 0 then begin
         res = dblarr(nbins,ngrps)
         resStr = *self.resPtr
       endif

       for i = 0,ngrps-1 do begin

          z_in = old[*,i]
          dz_in = errold[*,i]

          ok = where(finite(z_in),count_ok)
          z_in = z_in[ok]
          dz_in = dz_in[ok]


          x_in = reform((*self.xvalsPtr)[ok,i])
          xin = x_in & zin = z_in & dzin = dz_in
          xout = x_out
            if (n_elements(xin) eq n_elements(zin[*,0])) then begin
                drebin,xin,zin,dzin,xout,z_out,dz_out,$
          /points,/to_points,err=err,emsg=emsg
            endif else begin
                drebin,xin,zin,dzin,xout,z_out,dz_out,$
          /hist,/to_hist,err=err,emsg=emsg
            endelse
       ; drebin,xin,zin,dzin,xout,z_out,dz_out,$
       ;    /points,/to_points,err=err,emsg=emsg
          ;drebin_points_wrapper,x_in,z_in,dz_in,x_out,z_out,dz_out
         new[*,i] = z_out[*]
         newerr[*,i] = dz_out[*]
         xnew[*,i] = x_out[*]

    ;  ; Do we need to do this with a resolution function?
    ;     if n_elements(*self.resPtr) gt 0 then begin
    ;          zr_in = reform(resStr.data[*,i])
    ;          resInterp = interpol(reform(resStr.data[*,i]),reform(resStr.x[*,i]),x_out)
    ;          res[*,i] = resInterp
    ;     endif
       endfor
    ;   if n_elements(*self.resPtr) gt 0 then begin
    ;     newResStr = {x:xnew,y:resStr,data:res,rlimit:resStr.rLimit}
    ;     *self.resPtr = newResStr
    ;   endif
       *self.dataPtr = new
       *self.errorPtr = newerr
       *self.xvalsPtr = xnew
       ;070108
       *self.maskPtr = byte(0*(*self.dataptr)) + 1b
    endelse

    if datSize[0] eq 2 then begin
      for i = 0,ngrps-1 do begin
       oc = (*self.ocurveGroup)[i]
       x_out = reform((*self.xvalsPtr)[*,i])
    ;   if n_elements(*self.resPtr) gt 0 then begin
    ;;       oneResPtr = ptr_new(res[*,i])
    ;      oneResPtr = {x:(*self.resPtr).x $
    ;                   ,y:(*self.resPtr).y $
    ;                   ,data:reform((*self.resPtr).data[*,i]) $
    ;                   ,rlimit:(*self.resPtr).rlimit $
    ;                  }
    ;      oc->setxvalues,x_out,resPtr = oneResPtr,yout = yout
    ;      ptr_free,oneResPtr
    ;   endif else begin
    ;      oc->setxvalues,x_out,yout = yout
    ;   endelse
       oc->setxvalues,x_out,yout = yout
      endfor
    endif
    if n_elements(*self.xtabPtr) ne 0 then $
       self->scaleKtable   ; added 04/09/03

    ; refresh display
    self->refresh

    return
end;opan::rebinData
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;



;###########################################################


;
;
;SET UP THE CROPPING STUFF.  THIS REQUIRES MODIFICATIONS.
;
;JUST SET UP CROPPING AS IS WITH THE INPUT MASK ACCOUNTED FOR.
;
;THEN UPDATE THE CROPPING APPLICATION TO EDIT THE MASK.
;
;



;###########################################################

pro opan::editPanMask,event = event


    qty = reform(*self.dataPtr)
    ;help,qty
    err = reform(*self.errorPtr)
    ;help,err

    self->retrievePanMask,panMask
    ;help,panmask

    allx = reform(*self.xvalsPtr)

    ally = (*self.yvalsPtr)

	sz = size(allx)

;print,'sz=',sz
	if sz[0] eq 2 then begin
		;MULTIPLE GROUPS
		x = reform(allx[*,0],n_elements(allx[*,0]))
		y = reform(ally[0,*],n_elements(ally[0,*]))
	endif else begin
		;ONE GROUP
		x = allx
		y = ally[0]
	endelse


;IS THERE A WAY TO GET THE FILLER VALUE FOR THE DATA??????????

	newmask = panmaskeditor(qty=qty,err=err,x=x,pan_mask=panmask,group_leader=self.tlb)

	;print,'pan_mask=',panmask
	;print,'newmask=',newmask

	*self.maskPtr = newmask
    self->refresh





;function panmaskeditor,qty=qty,err=err,x=x,y=y,pan_mask=pan_mask,$
;                        group_leader=group_leader,mode=mode,$
;                        filler=filler,$
;                        _extra=extra



;;;;;    widget_control,self.groupSlider,get_value = val
;;;;
;;;;;    val = fix(val[0])-1
;;;;;    if n_elements(*self.dataPtr) eq 0 then return
;;;;;    datSize = size(*self.dataPtr)
;;;;;    if datSize[0] eq 2 then begin
;;;;;       x = (*self.xvalsPtr)[*,val]
;;;;;       data = (*self.dataPtr)
;;;;;    endif else begin
;;;;;       x = reform(*self.xvalsPtr)
;;;;;       data = reform(*self.dataPtr)
;;;;;    endelse
;;;;;wh = where(panmask ne 1,count)
;;;;;if count ne 0 then begin
;;;;;    data[wh] = 0.0;!values.d_nan
;;;;;endif
;;;;;

;;;;;;;;;;;CHECK FOR nSec FOR NSE
;;;;;;;;;;;THIS IS NEEDED BECAUSE CROPXDATA DOES NOT HANDLE SMALL X VALUES.
;;;;;;;;;;nanosecondFlag = 0
;;;;;;;;;;if abs(max(x)) le 1.0e-6 then begin
;;;;;;;;;;    nanosecondFlag = 1
;;;;;;;;;;    print,'NANOSECONDS!!!!!!  IS THIS NSE I(Q,t) DATA? ;-)'
;;;;;;;;;;    x = x*1.0e9 ;CONVERT FROM SEC TO NS FOR NSE DATA.
;;;;;;;;;;    ;if n_elements(inlimits) ne 0 then inLimits = inLimits*10.0^9
;;;;;;;;;;endif
;;;;;;;;;;
;;;;;;;;;;    result = cropXData(x,data,mask=panMask,group_leader = event.top,title='Crop Signal data')
;;;;;;;;;;    if (result.cancel eq 1) then return
;;;;;;;;;;
;;;;;;;;;;
;;;;;;;;;;;UNDO THE NANOSECOND CONVERSION
;;;;;;;;;;if nanosecondFlag ne 0 then result.limits = 1.0e-9*result.limits

    ;result = opan_crop_widget(x,xcur,group_leader = event.top)
    ;if result.cancel then return

;    self->applyCrop, result.limits[0],result.limits[1],event.top

    ; refresh display
;    self->refresh

    return

end;opan::editPanMask
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;


pro opan::cropData,event = event



    self->extractDataForPAN,val=val,dSize=datSize,alldata=data,allx=x,panmask=panmask
    widget_control,self.groupSlider,get_value = val

    val = fix(val[0])-1
    if n_elements(*self.dataPtr) eq 0 then return
    datSize = size(*self.dataPtr)
    if datSize[0] eq 2 then begin
       x = (*self.xvalsPtr)[*,val]
       data = (*self.dataPtr)
    endif else begin
       x = reform(*self.xvalsPtr)
       data = reform(*self.dataPtr)
    endelse
wh = where(panmask ne 1,count)
if count ne 0 then begin
    data[wh] = 0.0;!values.d_nan
endif


;CHECK FOR nSec FOR NSE
;THIS IS NEEDED BECAUSE CROPXDATA DOES NOT HANDLE SMALL X VALUES.
nanosecondFlag = 0
if abs(max(x)) le 1.0e-6 then begin
    nanosecondFlag = 1
    print,'NANOSECONDS!!!!!!  IS THIS NSE I(Q,t) DATA? ;-)'
    x = x*1.0e9 ;CONVERT FROM SEC TO NS FOR NSE DATA.
    ;if n_elements(inlimits) ne 0 then inLimits = inLimits*10.0^9
endif

    result = cropXData(x,data,mask=panMask,group_leader = event.top,title='Crop Signal data')
    if (result.cancel eq 1) then return


;UNDO THE NANOSECOND CONVERSION
if nanosecondFlag ne 0 then result.limits = 1.0e-9*result.limits

    ;result = opan_crop_widget(x,xcur,group_leader = event.top)
    ;if result.cancel then return

    self->applyCrop, result.limits[0],result.limits[1],event.top

    ; refresh display
    self->refresh

    return

end;opan::cropData
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
pro opan::applyCrop, xlo,xhi,wTLB


;THIS MUST BE MODIFIED TO HANDLE MASK.
;SINCE DAVEPTR IS AVAILABLE, MASK SHOULD BE MODIFIED IN PLACE
;AND LATER RESTORED IF IT IS NECESSARY.


    datSize = size(*self.dataPtr)
    x = (datSize[0] eq 2)? (*self.xvalsPtr)[*,0] : (*self.xvalsPtr)

    limits = where((x ge xlo) and (x le xhi),count)
    nx = n_elements(x)
    if (count ge nx) then begin
      msg = 'New range is the same or larger than original'
      msg = [msg,'Data will not be modified']
      void = dialog_message(dialog_parent = wTLB,msg)
      return
    endif
    if (count le 5) then begin
      msg = 'New range has fewer than 5 data points'
      msg = [msg,'Data will not be modified']
      void = dialog_message(dialog_parent = wTLB,msg)
      return
    endif

    datSize = size(*self.dataPtr)
    if datSize[0] eq 2 then begin


       ;LRK
       ;I DON'T BELIEVE THE NEXT LINE WILL WORK PROPERLY, ALTHOUGH IT
       ;IS USED CONSISTENTLY THROUGHOUT PAN.
       ;I REPLACED IT WITH THE THREE LINES THAT FOLLOW AND DID THE SAME
       ;IN THIS ENTIRE SECTION.  THIS REPLACEMENT SEEMS TO HAVE
       ;FIXED A BUG THAT WAS OCCURRING WHEN THE CROP WAS APPLIED.

       ;(*self.dataPtr) = (*self.dataPtr)[limits,*]
       temp = (*self.dataPtr)
       if ptr_valid(self.dataPtr) gt 0 then ptr_free,self.dataPtr
       self.dataPtr = ptr_new(temp[limits,*])

       ;(*self.maskPtr) = (*self.maskPtr)[limits,*]
       temp = (*self.maskPtr)
       if ptr_valid(self.maskPtr) gt 0 then ptr_free,self.maskPtr
       self.maskPtr = ptr_new(temp[limits,*])



       ;(*self.errorPtr) = (*self.errorPtr)[limits,*]
       temp = (*self.errorPtr)
       if ptr_valid(self.errorPtr) gt 0 then ptr_free,self.errorPtr
       self.errorPtr = ptr_new(temp[limits,*])



       ;(*self.xvalsPtr) = (*self.xvalsPtr)[limits,*]
       temp = (*self.xvalsPtr)
       if ptr_valid(self.xvalsPtr) gt 0 then ptr_free,self.xvalsPtr
       self.xvalsPtr = ptr_new(temp[limits,*])


       ;x = (*self.xvalsPtr)[*,0]

       ngrps = datSize[2]
       for i = 0,ngrps-1 do begin

           self->extractDataForPAN,x=x,group=i+1 ;NOTE: GROUP IS 1-BASED LIST

          ;EACH ocurveGroup HAS ITS OWN X VALUES.  THIS MAKES THE ALTERATION HERE SLIGHTLY EASIER.
          oc = (*self.ocurveGroup)[i]


          if (obj_valid(oc)) then oc->setxvalues,x
       endfor
    endif else begin



       ;(*self.dataPtr) = (*self.dataPtr)[limits]
       temp = (*self.dataPtr)
       if ptr_valid(self.dataPtr) gt 0 then ptr_free,self.dataPtr
       self.dataPtr = ptr_new(temp[limits])

       ;(*self.maskPtr) = (*self.maskPtr)[limits]
       temp = (*self.maskPtr)
       if ptr_valid(self.maskPtr) gt 0 then ptr_free,self.maskPtr
       self.maskPtr = ptr_new(temp[limits])



       ;(*self.errorPtr) = (*self.errorPtr)[limits]
       temp = (*self.errorPtr)
       if ptr_valid(self.errorPtr) gt 0 then ptr_free,self.errorPtr
       self.errorPtr = ptr_new(temp[limits])



       ;(*self.xvalsPtr) = (*self.xvalsPtr)[limits]
       temp = (*self.xvalsPtr)
       if ptr_valid(self.xvalsPtr) gt 0 then ptr_free,self.xvalsPtr
       self.xvalsPtr = ptr_new(temp[limits])




       ;x = (*self.xvalsPtr)
       self->extractDataForPAN,x=x,group=1  ;THIS USES CURRENT VARIABLES JUST SET.

       oc = (*self.ocurveGroup)[0]
       if (obj_valid(oc)) then oc->setxvalues,x
    endelse


    ;(*self.prefs).xmin = xlo > (*self.prefs).xmin
    ;(*self.prefs).xmax = xhi < (*self.prefs).xmax
    (*self.prefs).xmin = xlo
    (*self.prefs).xmax = xhi

    (*self.prefs).xfitlo = (*self.prefs).xfitlo > xlo
    (*self.prefs).xfithi = (*self.prefs).xfithi < xhi


    if n_elements(*self.xtabPtr) ne 0 then $
       self->scaleKtable   ; added 04/09/03

    return
end;opan::applyCrop
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
pro opan::excludeData,event = event

void = dialog_message('opan::excludeData --- THIS DOES NOT YET ACCOUNT FOR MASKING OF DATA OR RESOLUTION!!!!!')


    widget_control,self.groupSlider,get_value = val
    grp = fix(val[0])-1

    if n_elements(*self.dataPtr) eq 0 then return
    datSize = size(*self.dataPtr)

    ;if datSize[0] eq 2 then begin
    ;    dat = (*self.dataPtr)[*,val]
    ;    daterr = (*self.errorPtr)[*,val]
    ;    x = (*self.xvalsPtr)[*,val]
    ;    y = (*self.yvalsPtr)[0,val]
    ;endif else begin
    ;    dat = reform(*self.dataPtr)
    ;    daterr = reform(*self.errorPtr)
    ;    x = reform(*self.xvalsPtr)
    ;    y = (*self.yvalsPtr)
    ;    val = 0
    ;endelse

    x = (datSize[0] eq 2)? (*self.xvalsPtr)[*,grp] : (*self.xvalsPtr)
    result = opan_removexrange_widget(x,group_leader = event.top)
    if result.cancel then return
    oxlo = min(x,max=oxhi)
    xlo = result.xlo
    xhi = result.xhi
    ; if xlo = xhi then exit
    if (xlo eq xhi) then return

    ; ensure xlo < xhi, if not, swap them
    if (xhi lt xlo) then begin
        tmp = xlo
        xlo = xhi
        xhi = tmp
    endif

    ; ensure range xlo->xhi intersects data
    if ((xhi lt oxlo) || (xlo gt oxhi)) then begin
      strout = 'Specified range does not intersect data!'
      void = dialog_message(dialog_parent = event.top,strout)
      return
    endif


    xv = (*self.xvalsPtr)
    dat = (*self.dataPtr)
    daterr = (*self.errorPtr)

    exInd = where((x ge xlo) and (x le xhi), complement=inInd, found)
    if (~found) then begin
        strout = 'No data points were excluded!'
        void = dialog_message(dialog_parent = event.top,strout)
        return
    endif

    (*self.xvalsPtr) = (datSize[0] eq 1)? xv[inInd] : xv[inInd,*]
    (*self.dataPtr) = (datSize[0] eq 1)? dat[inInd] : dat[inInd,*]
    (*self.errorPtr) = (datSize[0] eq 1)? daterr[inInd] : daterr[inInd,*]


    ; Consider single group first
    ;if (datSize[0] eq 1) then begin
    ;    exInd = where((x ge xlo) && (x le xhi), complement=inInd, found)
    ;    if (~found) then begin
    ;        strout = 'No data points were excluded!'
    ;        void = dialog_message(dialog_parent = event.top,strout)
    ;        return
    ;    endif
    ;
    ;    (*self.xvalsPtr) = x[inInd]
    ;    (*self.dataPtr) = dat[inInd]
    ;    (*self.errorPtr) = daterr[inInd];
    ;
    ;endif else begin
    ; Ok, now consider the general case of multiple groups
    ;    exInd = where((x ge xlo) && (x le xhi), complement=inInd, found)
    ;    if (~found) then begin
    ;        strout = 'No data points were excluded!'
    ;        void = dialog_message(dialog_parent = event.top,strout)
    ;        return
    ;    endif;
    ;
    ;    (*self.xvalsPtr) = x[inInd]
    ;    (*self.dataPtr) = dat[inInd,*]
    ;    (*self.errorPtr) = daterr[inInd,*]
    ;
    ;endelse

    if datSize[0] eq 2 then begin
        for i = 0,datSize[2]-1 do begin
            oc = (*self.ocurveGroup)[i]
            x_out = reform((*self.xvalsPtr)[*,i])
    ;        if n_elements(*self.resPtr) gt 0 then begin
    ;            oneResPtr = ptr_new(res[*,i])
    ;            oc->setxvalues,x_out,resPtr = oneResPtr,yout = yout
    ;            ptr_free,oneResPtr
    ;        endif else begin
                oc->setxvalues,x_out,yout = yout
    ;        endelse
        endfor
    endif
    if n_elements(*self.xtabPtr) ne 0 then $
      self->scaleKtable             ; added 04/09/03

    ;wset,self.resPix
    ;self->plotResiduals
    ;wset,self.resVis
    ;device,copy = [0,0,!d.x_size,!d.y_size,0,0,self.resPix]
    ;wset,self.datPix
    ;self->displaydata
    ;wset,self.datVis
    ;device,copy = [0,0,!d.x_size,!d.y_size,0,0,self.datPix]

    self->refresh

    return
end;opan::excludeData
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
pro opan::selectGroup, event = event
    ;wset,self.resPix
    ;self->plotResiduals
    ;wset,self.resVis
    ;device,copy = [0,0,!d.x_size,!d.y_size,0,0,self.resPix]
    ;wset,self.datPix
    ;self->displaydata
    ;wset,self.datVis
    ;device,copy = [0,0,!d.x_size,!d.y_size,0,0,self.datPix]
    self->refresh

    widget_control,self.groupSlider,get_value = val
    val = fix(val[0])-1
    if n_elements(*self.dataPtr) eq 0 then return
    datSize = size(*self.dataPtr)
    if datSize[0] eq 1 then val = 0
    oc = (*self.ocurveGroup)[val]
    oc->displayparms,output = output
    ncurves = oc->count()
    if ncurves gt 0 then begin
      widget_control,self.curveSlider,set_slider_max = (ncurves > 2)
    endif
    if n_elements(output) eq 0 then begin
      output = 'No curves present'
    endif
    widget_control,self.info,set_value = output
    return
end;opan::selectGroup
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
function opan_replaceSymbol,inText

    outText = inText
    invAngstromSym = '!3!sA!r!u!9 %!3!n!E-1!N'
    omegaSym = '!4x!3'
    if strpos(inText,'A-1') ne -1 then outText = invAngstromSym
    if strpos(inText,'ueV') ne -1 then outText = '!4l!6eV'
    if strpos(inText,'omega') ne -1 then outText = omegaSym
    return,outText
end;opan_replaceSymbol
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
pro opan::stuffDave, event = event,inFromDave = inFromDave

    ; This method stuffs the DAVE pointer into the PAN data format
    if n_elements(inFromDave) eq 0 then inFromDave = 0
    if inFromDave eq 0 then begin
      restore,self.filename ; Restores DAVEPTR
      state = *davePtr
      ok = where(strupcase(tag_names(state)) eq 'EXTRAPTR',count)
      if count gt 0 then begin
        obj_destroy,(*state.extraPtr).paninfo.panContainer
        ptr_free,state.extraPtr
      endif
    endif else begin
      state = *self.davePtr
    endelse

    self->extractPanMask,state,pan_mask

    instrument = (*state.dataStrPtr).commonStr.instrument


    energy = (*(*state.dataStrPtr).commonStr.histPtr).x
    xtype = (*state.dataStrPtr).commonStr.xtype
    q = (*(*state.dataStrPtr).commonStr.histPtr).y

    ;RTA - This check no longer required------------------
    ;; Check if the data are binned equally
    ;dx = deriv(energy)
    ;dx_moment = moment(dx)
    ;if sqrt(dx_moment[1]) gt (machar()).eps then begin
    ;   strout = strarr(4)
    ;   strout[0] = 'The binwidths for this data vary quite a bit.'
    ;   strout[1] = 'If you intend to use convolution in your analysis,'
    ;   strout[2] = 'please use the rebin tool within PAN or the '
    ;   strout[3] = 'general DAVE rebin tool.'
    ;   if (n_elements(event) ne 0) then $
    ;      void = dialog_message(dialog_parent = event.top,strout) $
    ;      else void = dialog_message(strout)
    ;endif
    ;------------------------------------------------------

    commonStr = (*state.dataStrPtr).commonStr

    data = (*commonStr.histPtr).qty
    error = (*commonStr.histPtr).err


    ytype = commonStr.ytype
    sx = size(energy)
    sy = size(q)
    if (sx[0] eq 1) and (sy[0] eq 1) then begin
      if strupcase(xtype[0]) eq 'HISTOGRAM' then begin
          nx = n_elements(energy)
          ;xaverage = fltarr(nx-1)
          xaverage = 0.5*(energy[1:nx-1]+energy[0:nx-2])
          energy = xaverage
      endif
      if strupcase(ytype[0]) eq 'HISTOGRAM' then begin
        ny = n_elements(q)
        ;qaverage = fltarr(ny-1)
        qaverage = 0.5*(q[1:ny-1]+q[0:ny-2])
        q = qaverage
      endif
      ; sort x - thus no need to do this later during fitting
      xsort = sort(energy)
      energy = energy[xsort]
      data = data[xsort,*]
      error = error[xsort,*]

      nx = n_elements(energy)
      nq = n_elements(q)

      uq = 1+bytarr(nq)
      ux = 1+bytarr(nx)
      xmat = energy#uq
      if n_elements(q) eq 1 then ymat = q else ymat = ux#q
    endif else begin
      xmat = energy
      ymat = q
      ; sort x - thus no need to do this later during fitting
      xsort = sort(energy)
      energy = energy[xsort]
      data = data[xsort]
      error = error[xsort]
    endelse

    *self.xvalsPtr = xmat

    *self.yvalsPtr = ymat

    self.ztitle = commonStr.histLabel

    dataSize = size(data)
    *self.dataPtr = data


    *self.maskPtr = pan_mask


    if n_elements(*commonStr.treatmentPtr) ne 0 then begin
      *self.headerPtr = *commonStr.treatmentPtr
    endif else begin
      *self.headerPtr = 'No information available'
    endelse

    ;rta - reset -ve or zero error values to 1
    invalidIndex = where(error le 0.0, invalidCnt)
    if (invalidCnt gt 0) then error[invalidIndex] = 1.0
    *self.errorPtr = error

    ;treatment = *(*state.dataStrPtr).commonStr.treatmentPtr
    xlabel = commonStr.xlabel
    xunits = commonStr.xunits
    yunits = commonStr.yunits
    ylabel = commonStr.ylabel

    self.xunits = xunits
    self.yunits = yunits

    xxunits = strtrim(strmid(xunits,strpos(xunits,':')+1))
    yyunits = strtrim(strmid(yunits,strpos(yunits,':')+1))
    xunits = opan_replaceSymbol(xxunits)
    yunits = opan_replaceSymbol(yyunits)

    xlabelDisp = xlabel+'('+xunits+')'
    ylabelDisp = ylabel+'('+yunits+')'

    self.xtitle = xlabelDisp
    self.ytitle = ylabelDisp
    self.title = ylabel

    (*self.prefs).xlabel = self.xtitle
    (*self.prefs).ylabel = self.ztitle


    if inFromDave eq 0 then $
       heap_free, davePtr
       ;dave_beast_ops,"rem",davePtr,show_commands = 0,show_analysis = 0

    return
end;opan::stuffDave
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
pro opan::scaleKtable, event = event
    ktable = *self.ktablePtr
    xmax = max(*self.xvalsPtr)
    xmin = min(*self.xvalsPtr)
    bigx = max([abs(xmax),abs(xmin)]) ; the maximum value in the dynamic range;
    ksize = size(ktable)
    npts = ksize[1]-1
    nb = ksize[2]-1
    nt = ksize[3]-1
    ytab = dblarr(npts,nb,nt)
    xtab = dblarr(npts)
    btab = dblarr(nb)
    ttab = dblarr(nt)
    ytab[0:npts-1,0:nb-1,0:nt-1] = ktable[0:npts-1,0:nb-1,0:nt-1]
    xtab[0:npts-1] = ktable[0:npts-1,nb,nt]
    btab[0:nb-1] = ktable[npts,0:nb-1,nt]
    ttab[0:nt-1] = ktable[npts,nb,0:nt-1]

    xtabmax = max([abs(min(xtab)),abs(max(xtab))])
    ; calculate the scaling factor
    lambda = xtabmax/bigx  ; scaling factor
    ; scale the tabulated values
    xtab[0:npts-1] = (xtab[0:npts-1]/lambda)
    ytab[0:npts-1,0:nb-1,0:nt-1] = lambda*ktable[0:npts-1,0:nb-1,0:nt-1]
    ttab[0:nt-1] = lambda*ktable[npts,nb,0:nt-1]
    *self.xtabPtr = xtab
    *self.btabPtr = btab
    *self.ttabPtr = ttab
    *self.ytabPtr = ytab
    return
end;opan::scaleKtable
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;

pro opan::clearDaveRes, event = event
    ; Free the resolution function pointer
    if n_elements(*self.resPtr) eq 0 then return
    ptr_free,self.resPtr,self.oneResPtr
    self.resPtr = ptr_new(/allocate_heap)
    self.oneResPtr = ptr_new(/allocate_heap)
    ; Now remove all of the delta functions from the function
    ; container
    ngroups = n_elements(*self.ocurveGroup)
    for i = 0,ngroups-1 do begin
      oc = (*self.ocurveGroup)[i]
      names = oc->getnames()
      isDelta = where(names eq 'pan_delta',countDelta)
      if countDelta gt 0 then begin
        oall = oc->get(/all)
        for j = 0,countDelta-1 do begin
          oDelta = oall[isDelta[j]]
          oc->remove,oDelta
          obj_destroy,oDelta
         ncurves = oc->count()
         widget_control,self.curveSlider,set_slider_max = (ncurves > 2)
        endfor
      endif
    endfor

    ;wset,self.datPix
    ;self->displaydata
    ;wset,self.datVis
    ;device,copy = [0,0,!d.x_size,!d.y_size,0,0,self.datPix]
    self->refresh

    return
end;opan::clearDaveRes
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
pro opan::saveDaveFits, event = event

    


    ; First test if there are fits present...
    if n_elements(*self.dataPtr) eq 0 then return
    datSize = size(*self.dataPtr)
    if datSize[0] eq 2 then begin
      ngroups = datSize[2]
      nchan = datSize[1]
    endif else begin
      ngroups = 1
      nchan = datSize[1]
    endelse
    sum = 0
    for i = 0,n_elements(*self.ocurveGroup)-1 do begin
      sum = sum + (*self.ocurveGroup)[i]->count()
    endfor

    if sum lt ngroups then begin
      strout = 'You must fit all groups!'
      void = dialog_message(dialog_parent = event.top,strout)
      return
    endif


  ;NOW, IF THE FITS ARE COMPLETE, WE CAN GO ON, OTHERWISE THE PROGRAM RETURNED ALREADY.
  

;LOOP THIS NEXT PART OVER ALL GROUPS, SINCE EACH GROUP CAN HAVE A DIFFERENT X VALUE 
    ;FIRST, GET THE DATA FOR THE FULL RANGE
;    self->extractDataForPAN,dat=dat,derr=derr,x=x,y=y,erry=erry,val=val,dSize=dSize,$
;                             allData=allData,allx=allx,panmask=panmask,group=group

;(group = index+1)
if ngroups gt 1 then begin
    qty = fltarr(nchan,ngroups)
    y = fltarr(ngroups)
    for i=0,ngroups-1 do begin

      self->extractDataForPAN,dat=dat,derr=derr,x=origx,$
                               ;y=y,$ ;THIS Y IS NOT NEEDED HERE BECAUSE IT IS CALCULATED BY oCurves!!!
                               erry=erry,val=val,dSize=dSize,$
                               allData=allData,allx=allx,panmask=panmask,group=i+1


;063008
;
;WHY IS THERE NO CHECK FOR A RESOLUTION FUNCTION HERE??????????????
;E.G. LOOK AT opan::displayData
;LOOKING AT THE ORIGINAL CODE BELOW, I DON'T SEE WHERE IT WAS DONE 
;ORIGINALLY EITHER.  WAS THAT AN OVERSIGHT THAT WAS NEVER CAUGHT?
;I BELIEVE SO AND I AM ADDING CODE TO CORRECT THAT NOW.


       ocurves = (*self.ocurveGroup)[i]
    ;SECOND GET THE CURRENT XVALUES IN EACH OF THE FIT CONTAINERS
         ;THESE ARE THE x VALUES EXTRACTED IN THE STATEMENT ABOVE.
    
    ;THIRD REPLACE THE X DATA IN EACH OF THE FIT CONTAINERS
         ocurves->setxvalues,allx
            
    ;FOURTH GET THE FIT DATA FOR THE FULL X RANGES

;063008
;COMMENT THIS LINE AND REPLACE WITH THE BLOCK BELOW IT.
;         ocurves->evaluate,allx,yout = yout

        ;063008
        ;ADDING THE NEXT BLOCK TO HANDLE THE RESOLUTION DATA BEFORE 
        ;SAVING TO FILE.
        if n_elements(*self.resPtr) gt 0 then begin
        
        
             ;020508 THE NEXT BLOCK OF CODE SUPERCEDES THE ONE BELOW IT.
             resExists = self->ExtractOneResStr(val,OneResStr)
             if resExists ne 0 then begin
               ;(*self.oneResPtr) = OneResStr
               (*self.oneResPtr) = OneResStr
               ocurves->evaluate,allx,yout = yout,resPtr = self.oneResPtr
             endif else begin
               self->clearOneRes_ptr
               void = dialog_message('No Resolution Data for Group #'+strtrim(string(val+1),2))
               ocurves->evaluate,allx,yout = yout             
             endelse
        endif else begin
        
          ;NO RESOLUTION
          ocurves->evaluate,allx,yout = yout
        endelse


;help,y,(*self.yvalsPtr),(*self.yvalsPtr)[0,i]
    ;FIFTH SAVE THE DATA
         x = reform((*self.xvalsPtr)[*,i])
         y[i] = (*self.yvalsPtr)[0,i]
         qty[*,i] = yout[*]
    
    ;SIXTH RESTORE THE X VALUES TO THE FIT CONTAINERS                            
         ocurves->setxvalues,origx
      
    endfor;i
endif else begin;ngroups
;       ocurves = (*self.ocurveGroup)[0]
;       x = reform((*self.xvalsPtr)[*,0])
;       y = (*self.yvalsPtr)[0]
;       ocurves->evaluate,x,yout = yout
;       qty = yout

      ocurves = (*self.ocurveGroup)[0]
      self->extractDataForPAN,dat=dat,derr=derr,x=origx,y=y,erry=erry,val=val,dSize=dSize,$
                               allData=allData,allx=allx,panmask=panmask,group=0+1
      ocurves->setxvalues,allx

      ;063008
      ;REPLACE THE FOLLOWING LINE WITH THE FOLLOWING BLOCK OF CODE
      ;JUST AS FOR MULTIPLE GROUPS ABOVE
;      ocurves->evaluate,allx,yout = yout

      ;063008
      ;ADDING THE NEXT BLOCK TO HANDLE THE RESOLUTION DATA BEFORE 
      ;SAVING TO FILE.
      if n_elements(*self.resPtr) gt 0 then begin
           resExists = self->ExtractOneResStr(0,OneResStr)
           if resExists ne 0 then begin
             (*self.oneResPtr) = OneResStr
             ocurves->evaluate,allx,yout = yout,resPtr = self.oneResPtr
           endif else begin
             self->clearOneRes_ptr
             void = dialog_message('No Resolution Data for Group #'+strtrim(string(val+1),2))
             ocurves->evaluate,allx,yout = yout             
           endelse
      endif else begin
        ;NO RESOLUTION
        ocurves->evaluate,allx,yout = yout
      endelse


      x = reform(allx)
      y = (*self.yvalsPtr)[0]
      qty[*,i] = yout[*]
      ocurves->setxvalues,origx

endelse
;print,'________________________________________________________'
;help,dsize,panmask,dat,derr,origx,y,erry,val,alldata,allx,group


;ORIGINALLY:
;
;;;    if ngroups gt 1 then begin
;;;       qty = fltarr(nchan,ngroups,/nozero)
;;;       for i = 0,ngroups-1 do begin
;;;         y = fltarr(ngroups)
;;;         ocurves = (*self.ocurveGroup)[i]
;;;         x = reform((*self.xvalsPtr)[*,i])
;;;         y[i] = (*self.yvalsPtr)[0,i]
;;;
;;;;THIS NEXT COMMAND ASSUMES THAT THE ocurves HAVE EXACTLY THE SAME x VALUES AS THE 
;;;;INPUT X VALUES.  THIS CAN BE AN INCORRECT ASSUMPTION.  SO DO I NEED TO CHANGE ocurves::evaluate
;;;;SO THAT IT ACTUALLY USES THE INPUT x VALUES?  
;;;         ocurves->evaluate,x,yout = yout
;;;         qty[*,i] = yout[*]
;;;       endfor
;;;    endif else begin
;;;       ocurves = (*self.ocurveGroup)[0]
;;;       x = reform((*self.xvalsPtr)[*,0])
;;;       y = (*self.yvalsPtr)[0]
;;;       ocurves->evaluate,x,yout = yout
;;;       qty = yout
;;;    endelse

;UNCHANGED
    orig_data = *self.dataPtr
    orig_err = *self.errorPtr;0.005*qty
    rel_err = orig_err/orig_data
    err = qty*rel_err

    ; Create the davePtr
    commonStr = {instrument:'',$
                 histPtr:ptr_new(/allocate_heap),$
                 xlabel:'',$
                 ylabel:'',$
                 xtype:'',$
                 ytype:'',$
                 xunits:self.xunits,$
                 yunits:self.yunits,$
                 histLabel:'',$
                 histUnits:'',$
                 treatmentPtr:ptr_new(/allocate_heap),$
                 commonStrPtr:ptr_new()}

    *commonStr.histPtr = {  qty:qty,err:err,x:(*self.xvalsptr)[*,0],y:reform((*self.yvalsptr)[0,*])}

    ;ADD SPECIFIC PTR WITH PAN_MASK POINTER
    specificPtr = ptr_new(/allocate_heap)
    *specificPtr = {pan_mask:ptr_new(bits2bytes(panmask))}
    
    dataStr = {commonStr:commonStr,$
               specificPtr:specificPtr}

    dataStrPtr = ptr_new(dataStr,/no_copy)

    daveStr =    {davePtrStr, $     ; RTA - make davePtr structure a named structure
                  dataStrPtr:dataStrPtr, $
                  descriPtr:ptr_new()} ; remove /allocate_heap flag

    davePtr = ptr_new(daveStr,/no_copy)

    thisPath = self.workDir
    filename = DIALOG_PICKFILE(dialog_parent = event.top,$
                   file = 'resolution.dave', $
                               title = 'DAVE resolution file name',$
                               /write,filter = '*.dave',$
                               path = thisPath)
    if filename[0] eq '' then return
    save, davePtr, filename = filename
    msg = 'Output save in: '+filename
    ok = dialog_message(/info,msg,dialog_parent=event.top)
    ; Now clean up the pointers we just made
    ptr_free,(*(*davePtr).dataStrPtr).commonStr.histPtr
    ptr_free,(*(*davePtr).dataStrPtr).commonStr.treatmentPtr
    ptr_free,(*(*davePtr).dataStrPtr).commonStr.commonStrPtr
    ptr_free,(*(*davePtr).dataStrPtr).specificPtr
    ptr_free,(*davePtr).dataStrPtr
    ptr_free,(*davePtr).descriPtr
    ptr_free,davePtr
end;opan::saveDaveFits
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
pro opan::loadDaveRes, event = event
print,'opan::loadDaveRes'
    thisPath = self.workDir
    filename = DIALOG_PICKFILE(dialog_parent = event.top,$
                               title = 'Select DAVE resolution file to restore',$
                               /read,filter = '*.dave',$
                               path = thisPath)
    if filename eq '' or filename eq ' ' then begin
      strout = 'No resolution file selected'
      void = dialog_message(dialog_parent = event.top,strout)
      return
    endif

    restore,filename  ; Restores DAVEPTR
    state = *davePtr
    
    
    
    ok = where(strupcase(tag_names(state)) eq 'EXTRAPTR',count)
    if count gt 0 then begin
 
        print,'ExtraPtr BEING REPLACED: Look at PanContainer------------------------'
 
        obj_destroy,(*state.extraPtr).paninfo.panContainer
        ptr_free,state.extraPtr
    endif



    x = (*(*state.dataStrPtr).commonStr.histPtr).x
    xtype = (*state.dataStrPtr).commonStr.xtype
    y = (*(*state.dataStrPtr).commonStr.histPtr).y
    ytype = (*state.dataStrPtr).commonStr.ytype

    resdata = (*(*state.dataStrPtr).commonStr.histPtr).qty

    self->extractPanMask,state,pan_mask
      

;print,'In opan::loadDaveRes'
;print,'ResData[*,0] ='
;print,resdata[*,0]



;How would mask affect this section????
    sx = size(x)
    sy = size(y)
    if (sx[0] eq 1) and (sy[0] eq 1) then begin
          ;BOTH 1 FOR HISTOGRAM DATA ONLY.

                if strupcase(xtype[0]) eq 'HISTOGRAM' then begin
print,'GET FEEDBACK TO VERIFY THAT HISTOGRAM DATA IS BEING HANDLED PROPERLY'
                    nx = n_elements(x)
                    xaverage = 0.5*(x[1:nx-1]+x[0:nx-2])
                    x = xaverage
                endif
                if strupcase(ytype[0]) eq 'HISTOGRAM' then begin
print,'GET FEEDBACK TO VERIFY THAT HISTOGRAM DATA IS BEING HANDLED PROPERLY'
                  ny = n_elements(y)
                  yaverage = 0.5*(y[1:ny-1]+y[0:ny-2])
                  y = yaverage
                endif
                nx = n_elements(x)
                ny = n_elements(y)
          
              ;  uy = 1+bytarr(ny)
              ;  ux = 1+bytarr(nx)
              ;  xmat = x#uy
              ;  ymat = ux#y
PRINT,'NOTE: THIS SORTING PROBABLY NEEDS TO HAPPEN FOR THE DATA AS WELL AS THE RESOLUTION!'          
PRINT,'E.G.  RICHARD"S TAS DATA???'
              ;sort x
                xsort = sort(x)
;063008
;SIMPLE SORTING OF x SHOULD SOLVE THE PROBLEM HERE SINCE THE pan_mask IS REFERENCED
;BY THE SAME SORTED x BELOW. 
                x = x[xsort]
                resdata = resData[xsort,*]          
          
                ;pan_mask SHOULD HAVE SAME DIMENSIONS AS DATA.  
                ;x,y MAY CHANGE DUE TO HISTOGRAMMING 

                pan_mask = pan_mask[xsort,*]


                 whmasked = where(pan_mask eq 0,maskcount)
                 whnotmasked = where(pan_mask ne 0,notmaskcount)

                 ;020408
                 ;ZERO DATA THAT IS MASKED TO FACILITATE PLOTTING
                 if maskcount ne 0 then begin
                   PRINT,'opan::loadDaveRes IT IS HERE THAT I PAD THE 2D RES DATA WITH ZEROES!!!!'
                   resdata[whmasked] = 0.0
                 endif



          ;print,'After sort: ResData[*,0] ='
          ;print,ResData[*,0]

          ;020408
          ;REPLACE THE NEXT BLOCK WITH THE ONE BELOW IT THAT INCLUDES THE PAN_MASK
          ;      for i=0,ny-1 do begin
          ;         ;; normalize the res function
          ;         scale = int_tabulated(x,resData[*,i])
          ;         resData[*,i] = resData[*,i]/scale
          ;      endfor



                for i=0,ny-1 do begin
                   ;; normalize the res function one group at a time                   
                   whmasked = where(pan_mask[*,i] eq 0,maskcount)
                   whnotmasked = where(pan_mask[*,i] ne 0,notmaskcount)

                   if notmaskcount eq 0 then begin
                      ;ALL DATA ARE MASKED FOR THIS GROUP
                      ;DO NOTHING TO THE DATA
                   endif else begin
                     scale = int_tabulated(x[whnotmasked],resData[whnotmasked,i])
                     resData[whnotmasked,i] = resData[whnotmasked,i]/scale
                   endelse
                endfor

          ;print,'After scale: ResData[*,0] ='
          ;print,ResData[*,0]
            
    endif else begin
    
              ;x AND y ARE probably 2D ARRAYS

              ;  xmat = x
              ;  ymat = y

                 whmasked = where(pan_mask eq 0,maskcount)
                 whnotmasked = where(pan_mask ne 0,notmaskcount)
          
                 ;020408
                 ;ZERO DATA THAT IS MASKED TO FACILITATE PLOTTING
                 if maskcount ne 0 then begin
                   ;PRINT,'opan::loadDaveRes IT IS HERE THAT I PAD THE 1D RES DATA WITH ZEROES!!!!'
                   ;NOTE: THIS HAPPENS PRIOR TO SORTING
                   resdata[whmasked] = 0
                 endif
          
          
                 if notmaskcount eq 0 then begin
                   ;ALL DATA ARE MASKED.  DO NOTHING.
                 endif else begin

                   ;063008
                   ;THIS NEEDS TO BE HANDLED DIFFERENTLY FOR 1D AND 2D DATA SETS:
                   if sx[0] eq 1 then begin
                       ;;sort x
                       xsort = sort(x)
                       ;x = x[xsort]


                       szres = size(resdata)

                       if szres[0] eq 1 then begin
                         resdata = resData[xsort]
                         pan_mask = pan_mask[xsort]
                         whnotmasked = where(pan_mask ne 0,notmaskcount)
      
                         ;; normalize the res function
                         scale = int_tabulated(x[whnotmasked],resData[whnotmasked])
                         resData = resData/scale
                       endif else begin
                          
                           ny = szres[2]
                           for ii = 0,ny - 1 do begin
                             resdata = resData[xsort,ii]
                             pan_mask = pan_mask[xsort,ii]
                             whnotmasked = where(pan_mask[*,ii] ne 0,notmaskcount)
          
                             ;; normalize the res function
                             scale = int_tabulated(x[whnotmasked],resData[whnotmasked,ii])
                             resData[*,ii] = resData[*,ii]/scale
                           endfor;ii
                       endelse
                   endif else begin
                       ny = sx[2]
                       for ii = 0,ny - 1 do begin
                          xsort = sort(x[*,ii])
                          x[*,ii] = x[xsort,ii]
                          resdata[*,ii] = resData[xsort,ii]
                          pan_mask[*,ii] = pan_mask[xsort,ii]
                          whnotmaskedii = where(pan_mask[*,ii] ne 0,notmaskcountii)

                          if notmaskcountii ne 0 then begin
                            scaleii = int_tabulated(x[whnotmaskedii,ii],resData[whnotmaskedii,ii])
                            resData[*,ii] = resData[*,ii]/scaleii
                          endif
                       endfor;ii 

                   endelse
  
                 endelse
    endelse

    ;resStr = {x:xmat,y:ymat,data:resdata,rlimit:max(xmat)}
    resStr = {x:x,y:y,data:resdata,rlimit:[min(x),max(x)],mask:pan_mask}

    ; Is there a data file present?
    ;if n_elements(*self.dataPtr) gt 0 then begin
    ;  ; Yes, stuff the resolution function contents into a structure
    ;  *self.resPtr = resStr
    ;  *self.oresPtr = resStr
    ;endif

    self->interpSigRes, resStr, event = event

;DETERMINE WHETHER davePtr IS A POINTER OR A STRUCTURE
    dave_beast_ops,"rem",davePtr,show_commands = 0,show_analysis = 0
;print,'After dave_beast_ops'

    return
end;opan::loadDaveRes
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
pro opan::load_3col_ascii_res, event = event
    thisPath = self.workDir
    if n_elements(*self.dataptr) eq 0 then begin
       void = dialog_message(dialog_parent = event.top,'Load signal data file first')
       return
    endif
    filename = DIALOG_PICKFILE(dialog_parent = event.top,$
                               title = 'Select 3-column ascii file',$
                               /read,filter = '*.txt',$
                               path = thisPath)
    if filename eq '' or filename eq ' ' then begin
      strout = 'No resolution file selected'
      void = dialog_message(dialog_parent = event.top,strout)
      return
    endif

    ; Read in the ascii file
    if file_test(filename) then begin
    ; Ok it is a valid filename, but can we read it in here?
       o = obj_new('ascii_data',filename = filename)
       ret = o->read_three_column_ascii(err = err,emsg = emsg)
       if err eq 1 then begin
          obj_destroy,o
          void = dialog_message(dialog_parent = event.top,emsg)
          return
       endif
    endif else begin
       void = dialog_message(dialog_parent = event.top,'Resolution file not found')
       return
    endelse

    ret = o->get_property(xvals = xvals, $
       filename = filename,zvals = zvals,dzvals = dzvals)
    obj_destroy,o

    xsort = sort(xvals)
    x = xvals[xsort]
    y = 0.0
    ;nx = n_elements(x) & ny = n_elements(y)
    ;xmat = rebin(x,nx,ny,/sample)
    ;ymat = (1+bytarr(nx))#y
    zvals = zvals[xsort]
    factor = int_tabulated(xvals,zvals)
    zvals = zvals/factor

    ;resStr = {x:xmat,y:ymat,data:zvals,rlimit:max(xmat)}
;020408
;ADD mask FIELD TO THE resStr
    resStr = {x:x,y:y,data:zvals,rlimit:[min(x),max(x)],mask:byte(0*zvals)+1b}

    ; Is there a data file present?
    ;if n_elements(*self.dataPtr) gt 0 then begin
    ;  ; Yes, stuff the resolution function contents into a structure
    ;  *self.resPtr = resStr
    ;  *self.oresPtr = resStr
    ;endif

    self->interpSigRes, resStr, event = event
end;opan::load_3col_ascii_res
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
pro opan::load_group_ascii_res, event = event
    thisPath = self.workDir
    if n_elements(*self.dataptr) eq 0 then begin
       void = dialog_message(dialog_parent = event.top,'Load signal data file first')
       return
    endif
    filename = DIALOG_PICKFILE(dialog_parent = event.top,$
                               title = 'Select grouped ascii file',$
                               /read,filter = '*.txt',$
                               path = thisPath)
    if filename eq '' or filename eq ' ' then begin
      strout = 'No resolution file selected'
      void = dialog_message(dialog_parent = event.top,strout)
      return
    endif

    if file_test(filename) then begin
    ; Ok it is a valid filename, but can we read it in here?
       o = obj_new('ascii_data',filename = filename)
       ret = o->read_group_ascii(err = err,emsg = emsg)
       if err eq 1 then begin
          obj_destroy,o
          void = dialog_message(dialog_parent = event.top,emsg)
          return
       endif
    endif

    ret = o->get_property(xvals = xvals,yvals = yvals, $
       filename = filename,zvals = zvals,dzvals = dzvals)
    obj_destroy,o
    delimiter = path_sep()
    dpos = strpos(filename,delimiter,/reverse_search)
    display_name = strmid(filename,dpos+1)

    ;nx = n_elements(xvals)
    ny = n_elements(yvals)
    ;ux = 1+bytarr(nx) & uy = 1+bytarr(ny)


    x = xvals
    y = yvals
    ;xmat = x#uy
    ;ymat = ux#y

;020408
;FOR ASCII FILES THERE WILL BE NO MASK, SO IT DOES NOT NEED TO BE USED HERE,
;BUT IT WILL BE ADDED FOR CONSISTENCY BELOW 
    for i = 0,ny-1 do begin
       factor = int_tabulated(x,zvals[*,i])
       zvals[*,i] = zvals[*,i]/factor
    endfor
    ;resdata = zvals
    ;resStr = {x:xmat,y:ymat,data:resdata,rlimit:max(xmat)}
;020408
;ADD mask FIELD TO THE resStr
    resStr = {x:x,y:y,data:zvals,rlimit:[min(x),max(x)],mask:byte(0*zvals)+1b}

    ; Is there a data file present?
    ;if n_elements(*self.dataPtr) gt 0 then begin
    ;  ; Yes, stuff the resolution function contents into a structure
    ;  *self.resPtr = resStr
    ;  *self.oresPtr = resStr
    ;endif

    self->interpSigRes, resStr, event = event

end;opan::load_group_ascii_res
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
pro opan::interpSigRes, resStr, rlimit = rlimit, event = event
    ; This method interpolates the signal and resolution data to the same
    ; x-axis.
    ; RTA - interpolation to the same grid is no longer performed but
    ;       other checks are made.
    ;

    xres = resStr.x
    resData = resStr.data
    
    ;020408
    ;GET THE MASK TOO
    pan_mask = resStr.mask

    rsize = size(resData)
    nrgroups = (rsize[0] eq 2)? rsize[2] : 1

    ;***** Perform this when loading datasets as well!***************
    ; If data is loaded,
    ; Are there the same number of yvalues in the data file and the
    ; resolution function?
    if (n_elements(*self.dataPtr) ne 0) then begin
    ;   data = *self.dataPtr
       dsize = size(*self.dataPtr)
       ndgroups = (dsize[0] eq 2)? dsize[2] : 1
       if nrgroups ne ndgroups then begin
                                    ; They have different sizes so tell user and get out

          msg = ['Signal and resolution dataset groups do not match' $
                 ,'There are '+strtrim(string(ndgroups),2)+' groups in signal dataset' $
                 ,'There are '+strtrim(string(nrgroups),2)+' groups in resolution dataset' $
                 ,'Fits cannot be performed!' $
                 ,'Consider changing the signal OR the resolution data']
          void = dialog_message(dialog_parent = event.top,msg)
       endif
    endif

    ; make backup copy of resPtr
    (*self.oresPtr) = resStr

;print,'ResData[*,0] ='
;print,'resdata[where(resStr.mask[*,0] ne 0),0]='
;print,resdata[where(resStr.mask[*,0] ne 0),0]

    ; Restrict resolution data to whithin the allowed limits specified by
    ; user
print,'opan::INTERPSIGRES CROPPING THE RES DATA'
    res = cropXData(xres,resData,rlimit,group_leader = event.top,mask=pan_mask)
print,'opan::INTERPSIGRES CROPPED THE RES DATA'

print,'APPLY CROP RANGE TO ALL DATA GROUPS'
    resLimit = res.limits
    i1 = where(xres ge resLimit[0] and xres le reslimit[1],count)
    if count gt 5 then begin
       xres = xres[i1]
       resData = (nrgroups eq 1)? resData[i1] : $
                 resData[i1,*]

       ;020408
       ;UPDATE THE mask BASED ON THE SELECTED RANGE
       pan_mask = (nrgroups eq 1)? pan_mask[i1] : $
                   pan_mask[i1,*]


;print,'THE MASK MUST BE CONSIDERED FOR THE RENORMALIZATION AFTER THE TRUCTATION IN opan::interpSigRes'
;       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;i

        ;020408
        for i=0,nrgroups-1 do begin
           ;; normalize the res function
           whmasked = where(pan_mask[*,i] eq 0,maskcount)
           whnotmasked = where(pan_mask[*,i] ne 0,notmaskcount)

           if notmaskcount eq 0 then begin
              ;ALL DATA ARE MASKED FOR THIS GROUP
              ;DO NOTHING TO THE DATA
           endif else begin
             ;021308
             ;THE ISSUE SEEMS TO BE TAKEN CARE OF HERE.  REGARDLESS OF THE NUMBER OF POINTS
             ;THE WORST THAT SHOULD HAPPEN IN THE NEXT STEP IS THAT SCALE IS 0, WHICH SHOULD
             ;RESULT IN AN INFINITY, BUT NO OTHER PROBLEMS.
             ;print,'opan::interpSigRes --- WHAT HAPPENS IF ALL OF THE POINTS ARE MASKED?????????'
             scale = int_tabulated(xres[whnotmasked],resData[whnotmasked,i])
             resData[whnotmasked,i] = resData[whnotmasked,i]/scale
           endelse
        endfor;i

       (*self.resPtr) = {x:xres,y:resStr.y,data:resdata,rlimit:reslimit,mask:pan_mask}
    endif else begin
       (*self.resPtr) = resStr
    endelse

    if n_elements(rlimit) eq 0 then begin
       self->refresh
    endif
    return
end;opan::interpSigRes


;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
pro opan::cropRes, event = event
    ; handler used to alter the useful limits of the resolution function
    ; (domain)

    if (n_elements(*self.oresPtr) eq 0 || $
        n_elements(*self.resPtr) eq 0) then begin
       msg = 'Resolution data is not available.'
       msg = [msg,'Please, load one first']
       okay = dialog_message(msg,/info,dialog_parent=event.top)
       return
    endif

    ; get info from original copy of resPtr
    xres = (*self.resPtr).x
    yres = (*self.resPtr).y
    resData = (*self.resPtr).data
    rsize = size(resData)
    nrgroups = (rsize[0] eq 2)? rsize[2] : 1

    ; get limit from current copy of resptr
    resLimit = (*self.resPtr).rLimit

;help,self.resPtr
;help,self.oresPtr

;help,resData
;print,resData[*,0]-(*self.resPtr).data[*,0]
    res = cropXData(xres,resData,reslimit,group_leader = event.top)
    resLimit = res.limits
    i1 = where(xres ge resLimit[0] and xres le reslimit[1],count)
    if count gt 5 then begin  ;021308  WHY DID THEY CHOOSE 5?
       xres = xres[i1]
       resData = (nrgroups eq 1)? resData[i1] : $
                 resData[i1,*]

       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:yres,data:resData,rlimit:reslimit}
    endif

    ; refresh display
    ;self->refresh

end;opan::cropRes


;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
pro opan::rebinRes, event = event
    ; handler used to alter the useful limits of the resolution function
    ; (domain)

   

;REBINNING RESOLUTION ELIMINATES THE res MASK, BUT THE USER MUST KNOW
;THAT THEY HAVE TO BE CAREFUL OF THE DATA IF THERE ARE INCOMPLETE RESOLUTION SETS!!!
;
    ;void = dialog_message('opan::rebinRes --- THIS DOES NOT YET ACCOUNT FOR MASKING OF DATA OR RESOLUTION!!!!!')

    if (n_elements(*self.oresPtr) eq 0 || $
        n_elements(*self.resPtr) eq 0) then begin
       msg = 'Resolution data is not available.'
       msg = [msg,'Please, load one first']
       okay = dialog_message(msg,/info,dialog_parent=event.top)
       return
    endif

    ; get info from resPtr
    x = (*self.resPtr).x
    ;yres = (*self.oresPtr).y
    qty = (*self.resPtr).data
    ;rsize = size(resData)
    ;nrgroups = (rsize[0] eq 2)? rsize[2] : 1
    err=0.1*qty


;063008
    contentsMasked = self->checkResMasked()

    if contentsMasked gt 0 then begin
      msg = ['There are masked resolution points.',$
             'This may adversely affect your results.',$
             'Continue with rebin?']
      yn = dialog_message(msg,/question)
      if yn eq 'No' then return
    endif



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


;063008
;FOR MASKED DATA I WILL HAVE TO INTERVENE HERE.  IF NOTHING IS MASKED IT CAN PROCEED AS
;BEFORE.  IF THERE ARE THINGS MASKED, I NEED TO WORK WITH THE CORRECT MASKED x VALUES FOR
;EACH GROUP.
;
;USE function opan::extractOneResStr,val,OneResStr TO GET THE INFORMATION FOR EACH GROUP.
;ZERO OUT ALL THE MASKED STUFF.
;RUN THE CALCULATION OVER THE NEW X VALUES USING DREBIN.

    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
    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
    endif

    ; store modified data
    (*self.resPtr) = {x:x1,y:(*self.resPtr).y,data:qty1,rlimit:[xmin,xmax]}

    ; refresh display
    ;self->refresh

end;opan::rebinRes




;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
pro opan::restoreRes, event = event
    ; handler used to alter the useful limits of the resolution function
    ; (domain)

    if (n_elements(*self.oresPtr) eq 0 || $
        n_elements(*self.resPtr) eq 0) then begin
       msg = 'Resolution data is not available.'
       msg = [msg,'Please, load one first']
       okay = dialog_message(msg,/info,dialog_parent=event.top)
       return
    endif

    ; get info from original copy of resPtr
    (*self.resPtr) = (*self.oresPtr)

    ; refresh display
    ;self->refresh

end;opan::restoreRes


;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
pro opan::loadDave, event = event

    self->initCleanup
    thisPath = self.workDir
    filename = DIALOG_PICKFILE(dialog_parent = event.top,$
                                                  title = 'Select data file to restore',$
                                                  /read,filter = '*.dave',$
                                                  path = thisPath, $
                                                  get_path = myPath)
    if filename eq '' then return

    self.filename = filename
    length = strlen(myPath)
    self.printFileName = strmid(filename, length)
    self->stuffDave,event = event

    self->initNewDataObjects, event=event


    ;self->scaleKtable
    ;wset,self.datPix
    ;self->displaydata
    ;wset,self.datVis
    ;device,copy = [0,0,!d.x_size,!d.y_size,0,0,self.datPix]
    self->refresh


    return
end;opan::loadDave
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
pro opan::loadgroupdata, event = event
    self->initCleanup

    catch,theError
    if theError ne 0 then begin
      catch,/cancel
      void = dialog_message(dialog_parent = event.top, $
             !error_state.msg+' Returning...')
      return
    endif

    filename = dialog_pickfile(path = self.workDir,/read, $
               dialog_parent = event.top,filter = '*.txt', $
               get_path = thisPath)

    if filename eq '' then return

    if file_test(filename) then begin
    ; Ok it is a valid filename, but can we read it in here?
       o = obj_new('ascii_data',filename = filename)
       ret = o->read_group_ascii(err = err,emsg = emsg)
       if err eq 1 then obj_destroy,o
    endif else begin
        void = dialog_message('Could not read file:   '+file_basename(filename)+', file not accessible.')
        return
    endelse

    if err eq 1 then begin
        void = dialog_message('Could not read file:   '+file_basename(filename)+', check file format.')
        return
    endif else begin

        ret = o->get_property(xvals = xvals,yvals = yvals, $
           filename = filename,zvals = zvals,dzvals = dzvals)
        obj_destroy,o
        delimiter = path_sep()
        dpos = strpos(filename,delimiter,/reverse_search)
        display_name = strmid(filename,dpos+1)

        nx = n_elements(xvals)
        ny = n_elements(yvals)
        ux = 1+bytarr(nx) & uy = 1+bytarr(ny)

        ;d = opan_readTextGroup(filename)
        ;ux = 1+bytarr(n_elements(d.x))
        ;uy = 1+bytarr(n_elements(d.y))
        ;length = strlen(thisPath)
        self.printFileName = display_name;strmid(filename, length)

        *self.dataPtr = zvals;d.z
        ;CREATE THE MASK POINTER
        *self.maskPtr = byte(0*zvals) + 1b
        *self.omaskPtr = byte(0*zvals) + 1b

        *self.errorPtr = dzvals;d.zerr
        *self.xvalsPtr = xvals#uy;(d.x)#uy
        *self.yvalsPtr = ux#yvals;(d.y)
        *self.headerPtr = filename
        self.xtitle = 'x';d.xlabel
        self.ytitle = 'y';d.ylabel

        self->initNewDataObjects, event=event

        ;wset,self.datPix
        ;self->displaydata
        ;wset,self.datVis
        ;device,copy = [0,0,!d.x_size,!d.y_size,0,0,self.datPix]
        self->refresh
    endelse

    return
end;opan::loadgroupdata
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
pro opan::loadgroupdata_old, event = event
    self->initCleanup

    catch,theError
    if theError ne 0 then begin
      catch,/cancel
      void = dialog_message(dialog_parent = event.top, $
             !error_state.msg+' Returning...')
      return
    endif

    filename = dialog_pickfile(path = self.workDir,/read, $
               dialog_parent = event.top,filter = '*.txt', $
               get_path = thisPath)

    if filename eq '' then return

    d = opan_readTextGroup(filename)
    ux = 1+bytarr(n_elements(d.x))
    uy = 1+bytarr(n_elements(d.y))
    length = strlen(thisPath)
    self.printFileName = strmid(filename, length)

    *self.dataPtr = d.z
    ;CREATE THE MASK POINTER
    *self.maskPtr = byte(0*d.z) + 1b
    *self.omaskPtr = byte(0*d.z) + 1b

    *self.errorPtr = d.zerr
    *self.xvalsPtr = (d.x)#uy
    *self.yvalsPtr = ux#(d.y)
    *self.headerPtr = filename
    self.xtitle = d.xlabel
    self.ytitle = d.ylabel
    self->initNewDataObjects, event=event

    ;wset,self.datPix
    ;self->displaydata
    ;wset,self.datVis
    ;device,copy = [0,0,!d.x_size,!d.y_size,0,0,self.datPix]
    self->refresh

    return
end;opan::loadgroupdata_old
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
pro opan::loadfcsdata, event = event
    self->initCleanup

    catch,theError
    if theError ne 0 then begin
      catch,/cancel
      void = dialog_message(dialog_parent = event.top, $
             !error_state.msg+' Returning...')
      return
    endif

    filename = dialog_pickfile(path = self.workDir,/read, $
               dialog_parent = event.top,filter = '*.xy', $
               get_path = thisPath)

    if filename eq '' then return

    read_fcs_xy,filename,e,q,qty,err
    nx = n_elements(e)
    ny = n_elements(q)
    ux = 1+bytarr(nx)
    uy = 1+bytarr(ny)

    ;d = opan_readTextGroup(filename)
    length = strlen(thisPath)
    self.printFileName = strmid(filename, length)

    *self.dataPtr = qty
    ;CREATE THE MASK POINTER
    *self.maskPtr = byte(0*qty) + 1b
    *self.omaskPtr = byte(0*qty) + 1b

    *self.errorPtr = 0.1*qty;err
    *self.xvalsPtr = e
    *self.yvalsPtr = ux#q
    *self.headerPtr = filename
    self.xtitle = 'E (meV)'
    self.ytitle = 'Intensity (arb units)'
    self->initNewDataObjects, event=event

    ;wset,self.datPix
    ;self->displaydata
    ;wset,self.datVis
    ;device,copy = [0,0,!d.x_size,!d.y_size,0,0,self.datPix]
    self->refresh

    return
end;opan::loadfcsdata
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
pro opan::loadasciidata, event = event

    self->initCleanup

    catch,theError
    if theError ne 0 then begin
      catch,/cancel
      void = dialog_message(dialog_parent = event.top, $
             !error_state.msg+' Returning...')
      return
    endif

    filename = dialog_pickfile(path = self.workDir,/read, $
               dialog_parent = event.top,filter = '*.txt', $
               get_path = thisPath)
    if filename eq '' then return
    if file_test(filename) then begin
    ; Ok it is a valid filename, but can we read it in here?
       o = obj_new('ascii_data',filename = filename)
       ret = o->read_three_column_ascii(err = err,emsg = emsg)
       if err eq 1 then obj_destroy,o
    endif else begin
        void = dialog_message('Could not read file:   '+file_basename(filename)+', file not accessible.')
        return
    endelse

    if err eq 1 then begin
        void = dialog_message('Could not read file:   '+file_basename(filename)+', check file format.')
        return
    endif else begin
        ret = o->get_property(xvals = xvals, $
           filename = filename,zvals = zvals,dzvals = dzvals)
        obj_destroy,o
        delimiter = path_sep()
        dpos = strpos(filename,delimiter,/reverse_search)
        display_name = strmid(filename,dpos+1)

        nx = n_elements(xvals)
        ux = 1+bytarr(nx)
        self.printFileName = display_name
        *self.dataPtr = zvals
        ;CREATE THE MASK POINTER
        *self.maskPtr = byte(0*zvals) + 1b
        *self.omaskPtr = byte(0*zvals) + 1b

        *self.errorPtr = dzvals
        *self.xvalsPtr = xvals
        *self.yvalsPtr = 0.0
        *self.headerPtr = filename

        self.xtitle = 'x'
        self.ytitle = 'y'
        self->initNewDataObjects, event=event
        ;wset,self.datPix
        ;self->displaydata
        ;wset,self.datVis
        ;device,copy = [0,0,!d.x_size,!d.y_size,0,0,self.datPix]
        self->refresh
    endelse

    return
end;opan::loadasciidata
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
pro opan::loadtasdata, event = event
    self->initCleanup
    ; Which browser should we run?
    if (!version).release lt 5.6 then begin
       filenames = dialog_pickfile(path = self.workDir,/read, $
               dialog_parent = event.top,/multiple_files,get_path = thisPath)
       if filenames[0] eq '' then return
       self.dataPath = thisPath
       nfiles = n_elements(filenames)
       if nfiles ge 21 then begin
       strout = ["Maximum number of files to open at once is 20.", $
                   "Opening the first 20 files you have selected..."]
        void = dialog_message(dialog_parent = event.top,strout)
       filenames = filenames[0:19]
       endif

       *self.tasfilePtr = filenames
       *self.tasPathPtr = thisPath
       dout = panReadMultTAS(*self.tasPathPtr,filenames,group_leader = event.top)
    endif else begin
       dout = tas_viewer(group_leader = event.top)
    endelse

    help,dout,output = output
    if (strpos(output,'LONG'))[0] ne (-1) then return
    x = dout.x
    if n_elements(x) eq 1 then begin
      output = 'Data must contain more than one point!'
      void = dialog_message(dialog_parent = event.top,output)
      return
    endif

    ; ok...now pull out the single filename
    length = strlen(self.dataPath)
    self.printFileName = strmid(dout.filesel, length)

    y = 0.0
    data = dout.y
    if (!version).release ge 5.6 then error = dout.yerr $
       else    $
       error = sqrt(dout.y)
    self.filename = dout.filesel
    ; For zero counts, force the error to 1
    zeros = where(error eq 0.,countZ)
    if countZ gt 0 then error[zeros] = 1.0

    self.autoscale = 1
    *self.dataPtr = data
    ;CREATE THE MASK POINTER
    *self.maskPtr = byte(0*data) + 1b
    *self.omaskPtr = byte(0*data) + 1b
    *self.errorPtr = error
    *self.xvalsPtr = x
    *self.yvalsPtr = y
    *self.headerPtr = dout.header
    self.xtitle = dout.xlabel
    self.ytitle = dout.ylabel
    self.ztitle = self.ytitle

    (*self.prefs).xlabel = self.xtitle
    (*self.prefs).ylabel = self.ztitle

    self->initNewDataObjects, event=event

    ;wset,self.datPix
    ;self->displaydata
    ;wset,self.datVis
    ;device,copy = [0,0,!d.x_size,!d.y_size,0,0,self.datPix]
    self->refresh

    return
end;opan::loadtasdata
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
pro opan::loadtasdatafromprevious, event = event
    self->initCleanup

    if n_elements(*self.tasfileptr) ne 0 then begin
      filenames = *self.tasfilePtr
    endif else begin
      filenames = dialog_pickfile(path = self.workDir,/read, $
                  dialog_parent = event.top,/multiple_files,get_path = thisPath)
      if filenames[0] eq '' then return
      *self.taspathptr = thispath
      self.dataPath = thisPath
    endelse

    nfiles = n_elements(filenames)
    if nfiles ge 21 then begin
      strout = ["Hello Jeff Lynn....", $
                "Please don't load so many files.", $
                "My limit is 20 files at once.", $
                "Are you trying to crash me?"]
      void = dialog_message(dialog_parent = event.top,strout)
      return
    endif

    *self.tasFilePtr = filenames

    dout = panReadMultTAS(*self.tasPathPtr,filenames,group_leader = event.top)
    help,dout,output = output
    if (strpos(output,'LONG'))[0] ne (-1) then return

    x = dout.x
    if n_elements(x) eq 1 then begin
      output = 'Data must contain more than one point!'
      void = dialog_message(dialog_parent = event.top,output)
      return
    endif

    ; ok...now pull out the single filename
    length = strlen(self.dataPath)
    self.printFileName = strmid(dout.filesel, length)

    y = 0.0
    data = dout.y
    error = sqrt(dout.y)
    self.filename = dout.filesel
    ; For zero counts, force the error to 1
    zeros = where(error eq 0.,countZ)
    if countZ gt 0 then error[zeros] = 1.0

    self.autoscale = 1
    *self.dataPtr = data
    ;CREATE THE MASK POINTER
    *self.maskPtr = byte(0*data) + 1b
    *self.omaskPtr = byte(0*data) + 1b

    *self.errorPtr = error
    *self.xvalsPtr = x
    *self.yvalsPtr = y
    *self.headerPtr = dout.header
    self.xtitle = dout.xlabel
    self.ytitle = dout.ylabel
    self->initNewDataObjects, event=event

    ;wset,self.datPix
    ;self->displaydata
    ;wset,self.datVis
    ;device,copy = [0,0,!d.x_size,!d.y_size,0,0,self.datPix]
    self->refresh

    return
end;opan::loadtasdatafromprevious
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
pro opan::loadtestdata, event = event
    self->initCleanup
    ; Create some fake data
    nchan = 170
    x = rmd_makepoints(xlo = -12d,xhi = 12d,npts = nchan)
    ux = 1+bytarr(nchan)

    nq = 20

    q = rmd_makepoints(xlo = 0.25,xhi = 1.75,npts = nq)
    ro = 1.73
    ao = (5.0+4.0*beselj(q*ro,0))/9.0
    uq = 1+bytarr(nq)

    area = 4500.0 & bg = 0.05*area
    yy = bg   + (pan_gaussian(x,[area,0d,1.0]))#ao + $
            0.5*(pan_lorentzian(x,[5.0*area,-3d,2d]))#(1.0-ao) + $
            0.5*(pan_lorentzian(x,[5.0*area,3d,2d]))#(1.0-ao)

    datmat = yy

    y = dblarr(nchan,nq)
    for j = 0,nq-1 do begin
      for i = 0,nchan-1 do begin
        y[i,j] = randomn(s,1,poisson = datmat[i,j])
      endfor
    endfor
    yerr = sqrt(y)

    ; Now create a matrix out of all of the data variables
    xmat = x#uq
    ymat = ux#q
    data = y
    error = yerr
    bigNum = 1.e7
    self.printFileName = 'testdata.txt'
    self.filename = 'testdata.txt'


;032007
;LRK FOR SOME REASON THE SIZE OF THE DATA IS LOST IF YOU LOAD
;TEST DATA AFTER ALREADY HAVING AN EXISTING DATA SET.
;THE FOLLOWING CALL TAKES CARE OF THE PROBLEM.  --- IS THIS NEEDED ELSEWHERE???
    if ptr_valid(self.dataPtr) gt 0 then ptr_free,self.dataPtr
    self.dataPtr = ptr_new(data/area)
    if ptr_valid(self.errorPtr) gt 0 then ptr_free,self.errorPtr
    self.errorPtr = ptr_new(error/area)
    if ptr_valid(self.xvalsPtr) gt 0 then ptr_free,self.xvalsPtr
    self.xvalsPtr = ptr_new(xmat)
    if ptr_valid(self.yvalsPtr) gt 0 then ptr_free,self.yvalsPtr
    self.yvalsPtr = ptr_new(ymat)

    if ptr_valid(self.maskptr) gt 0 then ptr_free,self.maskPtr
    self.maskptr = ptr_new(byte(0*data/area) + 1b)
    if ptr_valid(self.omaskptr) gt 0 then ptr_free,self.omaskPtr
    self.omaskptr = ptr_new(byte(0*data/area) + 1b)



;    *self.dataPtr = data/area
;    *self.errorPtr = error/area
;    *self.xvalsPtr = xmat
;    *self.yvalsPtr = ymat


    *self.headerPtr = ['Test data for demonstration purposes',$
                       'Simulated rotational tunneling']
    self.xtitle = '!6E (!4l!6eV)'
    self.ytitle = 'Q'
    self.ztitle = '!6Intensity (arb units)'
    self.title = '!6Neutron Spectrum'
    (*self.prefs).xlabel = self.xtitle
    (*self.prefs).ylabel = self.ztitle
    self->initNewDataObjects, event=event
    ;;self->scaleKtable
    ;wset,self.datPix
    ;self->displaydata
    ;wset,self.datVis
    ;device,copy = [0,0,!d.x_size,!d.y_size,0,0,self.datPix]
    self->refresh

    return
end;opan::loadtestdata
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
pro opan::loadtestres, event = event
    ; Create some fake data
    nchan = 170
    x = rmd_makepoints(xlo = -12d,xhi = 12d,npts = nchan)
    ux = 1+bytarr(nchan)

    nq = 20

    q = rmd_makepoints(xlo = 0.25,xhi = 1.75,npts = nq)
    ro = 1.73
    ao = 0.5*(1.0+beselj(q*ro,0))
    uq = 1+bytarr(nq)

    area = 4500.0 & bg = 0.05*area
    ;res = rmd_gaussian(x,area = 1d,center = 0d,width = 1d)
    ;resPtr = ptr_new(res,/no_copy)
    yy = bg   + (pan_gaussian(x,[area,0d,1.0]))#ao

    datmat = yy

    y = dblarr(nchan,nq)
    for j = 0,nq-1 do begin
      for i = 0,nchan-1 do begin
        y[i,j] = randomn(s,1,poisson = datmat[i,j])
      endfor
    endfor
    yerr = sqrt(y)

    ; Now create a matrix out of all of the data variables
    xmat = x#uq
    ymat = ux#q
    data = y
    error = yerr


    ;resStr = {x:xmat,y:ymat,data:data}
    resStr = {x:x,y:y,data:data,rlimit:[min(x),max(x)]}

    ;*self.resPtr = resStr

    self->interpSigRes, resStr, event = event

    return
end;opan::loadtestres
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
pro pan_iterproc,fnc,p,iter,fnorm,dof = dof, stopBut = stopBut,_Extra = extra
    if n_elements(stopBut) eq 0 then return
    if widget_info(stopBut,/valid_id) eq 0 then return
    event = widget_event(/nowait,stopBut)
    evname = tag_names(event,/structure_name)
    if evname eq '' or event.id eq 0 then return

    if evname eq 'WIDGET_BUTTON' and event.select then begin
      event1 = widget_event(/nowait,stopBut)
      common mpfit_error,mperr
      mperr = -1
    endif

    return
end;pan_iterproc
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
pro opan::fitOneGroup, event = event
    ; This method uses Craig Markwardt's suggestion for a curve-fit interrupt.
    ; This method is for single group fitting only.


    ; If resolution is loaded then check if nos of groups is the same for
    ; resolution and signal datasets
    if (n_elements(*self.resPtr) gt 0) then begin
       dSize = size(*self.dataPtr)
       nd = (dSize[0] eq 2)? dSize[2] : 1
       rSize = size((*self.resPtr).data)
       nr = (rSize[0] eq 2)? rSize[2] : 1
       if (nr ne nd) then begin
          msg = ['Signal and resolution dataset groups do not match' $
                 ,'There are '+strtrim(string(nd),2)+' groups in signal dataset' $
                 ,'There are '+strtrim(string(nr),2)+' groups in resolution dataset' $
                 ,'Consider changing the signal OR the resolution data' $
                 ,'Fits will not be performed!' ]
          void = dialog_message(dialog_parent = event.top,msg,/error)
          return                    ; exit
       endif
    endif

    widget_control,self.groupSlider,get_value = val
    val = fix(val[0])-1
    datSize = size(*self.dataPtr)
    if datSize[0] eq 1 then val = 0

    oc = (*self.ocurveGroup)[val]
    if oc->count() ne 0 then begin


;NOTE:  NAMES y AND yerr ARE GOING TO CONFLICT WRT KWD NAMES.
;       PERHAPS I SHOULD HAVE INDIVIDUAL METHODS FOR X,Y,YERR,DAT, DATSIZE, ETC. THAT CALL
;       THE MAIN extractDataForPAN METHOD WITH THE MORE CRYPTIC KEYWORDS.
      parms = oc->getparms()
      parinfo = oc->createParInfo()


      self->extractDataForPAN,dat=y,derr=yerr,$
                              x=x,$;,y=y,erry=yerr,
                              val=val,dSize=datSize

      xPtr = ptr_new(x)

      ; If there is a resolution function present then use it!

    ;020708
    ;SUBSTITUTE THE NEXT BLOCK FOR THE ONE AFTER IT.
       resExists = self->ExtractOneResStr(val,OneResStr)
       if resExists ne 0 then begin
         (*self.oneResPtr) = OneResStr
         rlimit=OneResStr.rlimit
       endif else begin
         self->clearOneRes_ptr
       endelse

;      if n_elements(*self.resPtr) ne 0 then begin
;
;    ;    *self.oneResPtr = reform((*self.resPtr).data[*,val])
;         (*self.oneResPtr) = {x:(*self.resPtr).x $
;                              ,y:(*self.resPtr).y $
;                              ,data:reform((*self.resPtr).data[*,val]) $
;                              ,rlimit:(*self.resPtr).rlimit $
;                             }
;        rLimit = (*self.oneResPtr).rlimit
;
;      endif

      widget_control,self.fitstatfield,set_value = self.fitstatus[1]
      widget_control,self.interrupt,sensitive = 1
      widget_control,self.interrupt,/clear_events

    ; Try to fit it...
        w = 1.0/yerr^2
        limits = where((x ge (*self.prefs).xfitlo) and (x le (*self.prefs).xfithi))
        xlim = x[limits]
        ylim = y[limits]
        wlim = w[limits]

        ;;RTA- Restrict the domain of the funtions to the x fit range only!
    ;    oc->setxvalues, xlim
    ;    xPtr = ptr_new(xlim)

       ; 12/20/2005 - EAB
       ; Problem: when given an error of 0 (most likely due to zero counts at a given point),
       ; the resulting weight comes out as infinity (1 divided by zero = "oh noes")
       ; Solution: As referenced by "Numerical Recipes in Fortran 77", 2nd Edition, Volume 1,
       ; Chapter 15 (page 658) - we are setting the weight to unity (1)
       ; thereby eliminating the problems with our curve fitter being given a non-number
       fixers = where(finite(wlim) ne 1,fixerscount)
       if fixerscount ne 0 then wlim[fixers] = 1


        iterargs = {stopBut:self.interrupt}
        iterProc = 'pan_iterproc'


        ;020708
        ;UPDATE THE NEXT LINE:
        ; 
        ;if n_elements(*self.resPtr) eq 0 then begin
        if (n_elements(*self.resPtr) eq 0)  or (resExists eq 0) then begin
          yf = mpcurvefit(xlim, ylim, wlim, parms, sigma, $
                          FUNCTION_NAME='fitfunction', $
                          status = status, $
                          quiet = 1,$
                          itmax = (*self.prefs).maxIter, $
                          chisq = chisq, $
                          parinfo = parinfo, $
                          functargs = {oc:oc,xPtr:xPtr},$
                          iterargs = iterargs, $
                          iterProc = iterProc, $
                          /autoderivative, $
                          covar = covar,   $
                          ERRMSG=errmsg)

        endif else begin
          yf = mpcurvefit(xlim, ylim, wlim, parms, sigma, $
                          FUNCTION_NAME='fitfunction', $
                          status = status, $
                          quiet = quiet, $
                          itmax = (*self.prefs).maxIter, $
                          chisq = chisq, $
                          parinfo = parinfo, $
                          iterargs = iterargs, $
                          iterProc = iterProc, $
                          functargs = {oc:oc,xPtr:xPtr,resPtr:self.oneResPtr, $
                                       rlimit:rlimit}, $
                          /autoderivative, $
                          covar = covar,   $
                          ERRMSG=errmsg)

        endelse

;help,self.oneResPtr,/traceback
        ptr_free,xPtr
        widget_control,self.interrupt,sensitive = 0
        widget_control,self.fitstatfield,set_value = self.fitstatus[0]
        widget_control,self.interrupt,/clear_events
        if status le 0 then begin
          self.status = 0
          strout = 'Fit cancelled'
          widget_control,self.fitStatField,set_value = strout
          return
        endif else begin
          self.status = 1
        endelse
        if n_elements(sigma) gt 0 then oc->setparmError,sigma
        dof = n_elements(xlim)-n_elements(parms)
        chi_reduced = chisq/dof
        oc->setchisq,chi_reduced
    ; calculate the correlation matrix
       PCOR = COVAR * 0
       FOR i = 0, n_elements(parms)-1 DO FOR j = 0, n_elements(parms)-1 DO $
         PCOR(i,j) = COVAR(i,j)/sqrt(COVAR(i,i)*COVAR(j,j))
        oc->set_pcor,pcor

        ;;RTA- undo the restricted domain
    ;    oc->setxvalues, x

    endif

    ; Plot the new fit with the data and plot the residuals
    ;wset,self.resPix
    ;self->plotresiduals
    ;wset,self.resVis
    ;device,copy = [0,0,!d.x_size,!d.y_size,0,0,self.resPix]
    ;
    ;wset,self.datPix
    ;self->displaydata
    ;wset,self.datVis
    ;device,copy = [0,0,!d.x_size,!d.y_size,0,0,self.datPix]
    self->refresh

    ; Display the parameters
    self->displayFitParameters
    return
end;opan::fitOneGroup
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
pro opan::fitAllGroups, event = event

    ; If resolution is loaded then check if nos of groups is the same for
    ; resolution and signal datasets
    if (n_elements(*self.resPtr) gt 0) then begin
       dSize = size(*self.dataPtr)
       nd = (dSize[0] eq 2)? dSize[2] : 1
       rSize = size((*self.resPtr).data)
       nr = (rSize[0] eq 2)? rSize[2] : 1
       if (nr ne nd) then begin
          msg = ['Signal and resolution dataset groups do not match' $
                 ,'There are '+strtrim(string(nd),2)+' groups in signal dataset' $
                 ,'There are '+strtrim(string(nr),2)+' groups in resolution dataset' $
                 ,'Consider changing the signal OR the resolution data' $
                 ,'Fits will not be performed!' ]
          void = dialog_message(dialog_parent = event.top,msg,/error)
          return                    ; exit
       endif
    endif


    ; Which groups do we want to fit?
    if n_elements(*self.dataPtr) eq 0 then return
    datSize = size(*self.dataPtr)
    if datSize[0] eq 1 then nq = 1 else nq = datSize[2]

    widget_control,self.groupField,get_value = groupString
    groupString = groupString[0]
    index = opan_selectgroups(groupString)
    *self.grpArrayPtr = index

    ; Will we be using the same parameters for all of the groups?
    if (*self.prefs).same eq 1 then begin
              ; Which of the current groups has at least an initial guess?
              ; Let's grab the first one...
              oc = -1L
              goodIndex = -1
              for i = 0,nq-1 do begin
                ncurves = (*self.ocurveGroup)[i]->count()
                if goodIndex eq -1 then begin
                  if ncurves gt 0 then begin
                    ;LRK 062708
                    ;CHECK THAT THE FIRST GOOD INDEX IS IN THE GROUPS TO BE FIT
                    ;(THIS LITTLE FIX MAKES THE test DATA MUCH EASIER TO WORK WITH!!!)
                    if i ge index[0]-1 then begin
                      goodIndex = i
                      oc = (*self.ocurveGroup)[goodIndex]
                    endif
                  endif;ncurves gt 0
                endif;goodIndex eq -1
              endfor;i

              nindex = n_elements(index)

              for i = 0,nindex-1 do begin
                    ind = index[i]-1
                    if (ind ne goodIndex) then begin

                            ;oc IS THE FIRST GROUP AMONG THOSE TO BE FITTED THAT HAS FIT PARAMETERS AVAILABLE.
                            ;(DETERMINED ABOVE)    
                            ;oall IS THE ARRAY OF ALL THE CURVES IN THE GROUP.  (ONE CURVE IS A "FUNC" OBJECT)
                              oall = oc->get(/all) ; oc is an instance of the FUNC_CONT object class.
                                          ; oall is an array of FUNC object references.
                              ncurves = oc->count()
                             ; Remove any existing objects in oc and destroy them
                             o_old = (*self.ocurveGroup)[ind]
                             o_old_all = o_old->get(/all)
                             nold = o_old->count()
                             if nold gt 0 then begin
                                   o_old->remove,/all
                                 for k = 0,nold-1 do begin
                                  obj_destroy,o_old_all[k]
                                 endfor;k
                             endif;nold gt 0


                ;040607
                ;LRK
                ;THIS IS WHERE THE Qvalue IS RETRIEVED AND INPUT INTO THE CURVE GROUPS FOR opan::fitAllGroups
                ;ALSO, SAVE EACH GROUP'S XVALUES SINCE THEY MAY BE UNIQUE FOR EACH GROUP WITH THE ADDITION OF MASKING. 042507 - LRK
                             self->extractDataForPAN,y=qvalues,group=ind+1,x=xvaluestemp ;group is a 1 based index
                             qvalue=qvalues[0]

                              for j = 0,ncurves-1 do begin

                                    ;DON'T GET qvalue FROM (*self.ocurveGroup)[goodIndex],
                                    ;GET THEM FROM THE CURRENT GROUP.

                                             ; Now extract the curve information
                                             oall[j]->getproperty,name = name, $
                                                                  xvalues = xvalues, $
                                                                  step = step, $
                                                                  parms = parms, $
                                                                  fixed = fixed, $
                                                                  fixvalues = fixvalues, $
                                                                  fit_fun_filename = fit_fun_filename,    $
                                                                  low = low, $
                                                                  lovalues = lovalues, $
                                                                  high = high, $
                                                                  hivalues = hivalues, $
                                                                  tied = tied, $
                                                                  parmError = parmError, $
                                                                  expr = expr

                                        ;020708
                                        ;UPDATING TO HANDLE MASKED RES FUNCTIONS
                                        ;
                                        ;
;062708                                        
                                         ;resExists = self->ExtractOneResStr(val,OneResStr)
                                         resExists = self->ExtractOneResStr(ind,OneResStr)
                                         if resExists ne 0 then begin
                                           (*self.oneResPtr) = OneResStr
                                           ;021308
                                           ;SET resptr TO BE A DIFFERENT ptr FROM self.OneResPtr
                                           resPtr = ptr_new(OneResStr)
                                           ;DOES THIS METHOD DO ANYTHING WITH rLimit????
                                           rlimit=OneResStr.rlimit
                                         endif else begin
                                           self->clearOneRes_ptr
                                         endelse

;020708
;THE NEXT BLOCK IS COMMENTED OUT.  IT IS SUPERCEDED BY THE if-then-else STATEMENT IMMEDIATELY ABOVE.
;                                        ;
;                                        ;
;                                        ;
;                                        ;  added this bit of code to remedy the problem with user-defined functions that
;                                        ;  require the resolution function
;                                           if n_elements(*self.resPtr) ne 0 then begin
;                                        ;      resPtr = ptr_new(reform((*self.resPtr).data[*,ind]))
;                                        ;      rLimit = (*self.resPtr).rlimit
;
;                                              resPtr = ptr_new({x:(*self.resPtr).x $
;                                                                ,y:(*self.resPtr).y $
;                                                                ,data:reform((*self.resPtr).data[*,ind]) $
;                                                                ,rlimit:(*self.resPtr).rlimit $
;                                                               })
;                                              rLimit = (*resPtr).rlimit
;                                           endif;n_elements(*self.resPtr)



                                             ; ...and make a copy of the object
                                             curveCopy = obj_new('FUNC',name = name, $                  ;042507 - LRK
                                                                  xvalues = xvaluestemp,$;xvalues, $    :USE THE STORED XVALUES
                                                                  $                                     ;FOR EACH GROUP.
                                                                  qgroup=qvalue,$
                                                                  step = step, $
                                                                  parms = parms, $
                                                                  fixed = fixed, $
                                                                  fixvalues = fixvalues, $
                                                                  low = low, $
                                                                  lovalues = lovalues, $
                                                                  high = high, $
                                                                  tied = tied, $
                                                                  hivalues = hivalues, $
                                                                  fit_fun_filename = fit_fun_filename,    $
                                                                  expr = expr,$
                                        ;                        rlimit = rlimit,   $
                                                                   xtabPtr = self.xtabPtr, $
                                                                   ytabPtr = self.ytabPtr, $
                                                                   ttabPtr = self.ttabPtr, $
                                                                   btabPtr = self.btabPtr)

                                                curveCopy->setproperty,resPtr = resPtr,rLimit = rLimit, $
                                                                       parmError = parmError,/calculate
                                                if ptr_valid(resptr) then ptr_free,resptr
                                                (*self.ocurveGroup)[ind]->add,curveCopy

                              endfor;j = 0,ncurves-1
                                if i gt 0 then begin
                                  ind1 = index[i-1]-1

                                  ;SINCE THE xvalues CAN GENERALLY BE DIFFERENT FOR DIFFERENT GROUPS,
                                  ;WE NEED TO ENSURE THAT THE GROUP KEEPS ITS OWN xvalues!!!!!

                                  (*self.ocurveGroup)[ind]->setparms,((*self.ocurveGroup)[ind1])->getparms()



                        ;          past_parms = ((*self.ocurveGroup)[ind1])->getparms()
                        ;          (*self.ocurveGroup)[ind]->setparms,past_parms
                                endif;i gt 0
                    endif;(index ne goodindex)

              endfor;i

    endif;(*self.prefs).same eq 1

    self.curIndex = 0
    widget_control,self.groupSlider, $
                   set_value = (*self.grpArrayPtr)[self.curIndex]

    self.status = 1
    while (self.status eq 1) and (self.curIndex le n_elements(*self.grpArrayPtr)-1) do begin
      ; # NEW CODE: 08/06/04
      ; If appropriate, copy the parameters from the previous fit into
      ; this one.




      ; # END NEW CODE

      self->fitOneGroup,event = event
      self.curIndex = self.curIndex + 1
      if (self.curIndex le n_elements(*self.grpArrayPtr)-1) then begin
        widget_control,self.groupSlider, $
                       set_value = (*self.grpArrayPtr)[self.curIndex]
      endif
    endwhile

    ; Ok, now go through and clear any fits that have a chi-squared of -1.0
    for i = 0,nq-1 do begin
      ncurves = (*self.ocurveGroup)[i]->count()
      if ncurves gt 0 then begin
        oc = (*self.ocurveGroup)[i]
        chisq = oc->getchisq()
        if chisq eq (-1.0) then begin   ; remove it
         oall = oc->get(/all)
         obj_destroy,oall
         oc->remove,/all
        endif
      endif
    endfor

    return
end;opan::fitAllGroups
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
pro opan::sliderCurveSel,event = event
    return
end;opan::sliderCurveSel
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
pro opan::remSelCurve,event = event
    widget_control,self.groupSlider,get_value = val
    val = fix(val[0])-1
    oc = (*self.ocurveGroup)[val]
    ncurves = oc->count()
    if ncurves eq 0 then return
    oall = oc->get(/all)

    widget_control,self.curveSlider,get_value = cval
    cval = fix(cval[0])
    cval = cval - 1   ; now it goes from 0 to ncurves-1
    if cval eq ncurves then begin
      return ; too big!
    endif
    oc->remove,oall[cval]
    obj_destroy,oall[cval]
    ncurves = oc->count()
    widget_control,self.curveSlider,set_slider_max = (ncurves > 2)

    ;wset,self.resPix
    ;self->plotResiduals
    ;wset,self.resVis
    ;device,copy = [0,0,!d.x_size,!d.y_size,0,0,self.resPix]
    ;
    ;wset,self.datPix
    ;self->displayData
    ;wset,self.datVis
    ;device,copy = [0,0,!d.x_size,!d.y_size,0,0,self.datPix]
    self->refresh

    return
end;opan::remSelCurve
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
pro opan::plotEISF, event = event
    ; No data?->Get out.
    if n_elements(*self.dataPtr) eq 0 then return

    ; Count how many groups of curves there are.  If there are less than two
    ; then get out.
    fitObject = *self.ocurveGroup
    ngroups = n_elements(fitObject)
    totalFits = 0
    for i = 0,ngroups-1 do begin
      oc = fitObject[i]
      ncurves = oc->count()
      if ncurves gt 0 then begin
        totalFits = totalFits + 1
        if (n_elements(okIndex) eq 0) then $
           okIndex = i else okIndex = [okIndex,i]
      endif
    endfor
    if totalFits lt 2 then return

    thisEvent = tag_names(event,/structure_name)
    case thisEvent of

    'WIDGET_BUTTON': $
      begin
        widget_control,self.logBase,sensitive = 0
        opan_plotEISF,   fitObject, $
                        *self.yvalsPtr, $
               group_leader = event.top, $
                         notifyIds = [event.id,event.top], $
                         xtitle = self.ytitle, $
                         ytitle = 'Value', $
                         title = '', $
                         workDir = self.workDir, $
                         logDirectory = self.logDirectory, $
                         stringPtr = self.logStringPtr

      end
    else:    widget_control,self.logBase,sensitive = 1
    endcase

    return
end;opan::plotEISF
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
pro opan::plotFitParameter, event = event
    ; No data?->Get out.
    if n_elements(*self.dataPtr) eq 0 then return

    ; Count how many groups of curves there are.  If there are less than two
    ; then get out.
    fitObject = *self.ocurveGroup
    ngroups = n_elements(fitObject)
    totalFits = 0
    for i = 0,ngroups-1 do begin
      oc = fitObject[i]
      ncurves = oc->count()
      if ncurves gt 0 then begin
        totalFits = totalFits + 1
        if n_elements(okIndex) eq 0 then okIndex = i else okIndex = [okIndex,i]
      endif
    endfor
    if totalFits lt 2 then return

    thisEvent = tag_names(event,/structure_name)
    case thisEvent of

    'WIDGET_BUTTON': $
      begin
        widget_control,self.logBase,sensitive = 0
        opan_plotParms,  fitObject, $
                        *self.yvalsPtr, $
               group_leader = event.top, $
                         notifyIds = [event.id,event.top], $
                         xtitle = self.ytitle, $
                         ytitle = 'Value', $
                         title = '', $
                         workDir = self.workDir, $
                         logDirectory = self.logDirectory, $
                         stringPtr = self.logStringPtr

      end
    ;'PLOTPARMSEVENT': $
    ;  begin
    ;  end
    else: widget_control,self.logBase,sensitive = 1
    endcase

    return
end;opan::plotFitParameter
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
pro opan::saveParmsAsText,event = event
    if n_elements(*self.dataPtr) eq 0 then return
    thisPath = self.workDir
    fitObject = *self.ocurveGroup
    ngroups = n_elements(fitObject)
    ncurves = 0
    for i = 0,ngroups-1 do begin
      oc = fitObject[i]
      ncurves = ncurves + (oc->count())
    endfor
    if ncurves eq 0 then return

    filename = DIALOG_PICKFILE(dialog_parent = event.top,$
                                                  title = 'Enter parameter text file name',$
                                                  /read,filter = '*.fit',$
                                                  path = thisPath)
    if filename eq '' then return
    ;RTA - fix problem with double extensions
    if (strpos(filename,'.') eq -1) then $
       filename = filename + '.fit'
    openw,lun,filename,/get_lun

    for i = 0,ngroups-1 do begin
      oc = fitObject[i]
      chisq = oc->getchisq()
      if chisq ne (-1.0) then begin
        ncurves = oc->count()
        if ncurves ne 0 then begin
          printf,lun,'###############################'
          printf,lun,'Group: ',strtrim(string(i+1),2)
          printf,lun,'###############################'
          oc->displayParmsAndConstraints,output = output
    ;      oc->displayparms,output = output
          nlines = n_elements(output)
          for j = 0,nlines-1 do begin
            printf,lun,output[j]
          endfor
          printf,lun,'###############################'
        endif
      endif
    endfor
    free_lun,lun

    msg = 'Output save in: '+filename
    ok = dialog_message(/info,msg,dialog_parent=event.top)

    return
end;opan::saveParmsAsText
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
pro opan::readParmsAsText,event = event
    if n_elements(*self.dataPtr) eq 0 then return
    thisPath = self.workDir

    filename = DIALOG_PICKFILE(dialog_parent = event.top,$
                                                  title = 'Enter parameter text file name',$
                                                  /read,filter = '*.fit',$
                                                  path = thisPath)

    if filename eq '' or filename eq ' ' then return

    ; RMD 07/01/03
    ; Replaced the following procedure with one that reads in ASCII fit parameter
    ; files and constraints.

    ;opanReadFitParms,filename,fitArray = fitArray,groups = groups, error = error

    opanReadFitParmsAndConstraints,filename,fitArray = fitArray, $
       groups = groups, error = error,ermsg = ermsg

    if error eq 1 then begin
       void = dialog_message(dialog_parent = event.top,ermsg,/error)
       return
    endif
    ngrps = n_elements(fitArray)

    ; How many groups are there in the current data set?
    dat = *self.dataPtr
    dsize = size(dat)
    nx = dsize[1]
    ny = dsize[2]
    if ny lt ngrps then begin
      ; Clean up the pointers
      for i = 0,ngrps-1 do begin
       ptr_free,(fitArray[j]).namePtr
       ptr_free,(fitArray[j]).parmPtr
       ptr_free,(fitArray[j]).parmErrPtr
       ptr_free,(fitArray[j]).fixPtr
       ptr_free,(fitArray[j]).tiePtr
       ptr_free,(fitArray[j]).lowCheckPtr
       ptr_free,(fitArray[j]).lowValuePtr
       ptr_free,(fitArray[j]).highCheckPtr
       ptr_free,(fitArray[j]).highValuePtr
       ptr_free,(fitArray[j]).nparmPtr
       ptr_free,(fitArray[j]).exprPtr
       ptr_free,(fitArray[j]).chisqPtr
      endfor
      return
    endif
    ;return

    ; Ok, now let's start building the fit objects
    for i = 0,ngrps-1 do begin
      thisGroup = groups[i] - 1
      oc = (*self.ocurveGroup)[thisGroup]
      ; First, if necessary, free up any existing curves in the current group
      ncurves = oc->count()
      if ncurves ne 0 then begin
       oall = oc->get(/all)
       obj_destroy,oall
       oc->remove,/all
      endif
      chi_value = *(fitArray[i]).chisqPtr
      names = *(fitArray[i]).namePtr
      parms = *(fitArray[i]).parmPtr
      sigma = *(fitArray[i]).parmErrPtr
      fixed_parms = *(fitArray[i]).fixPtr
      lowCheck = *(fitArray[i]).lowCheckPtr
      lowValues = *(fitArray[i]).lowValuePtr
      highCheck = *(fitArray[i]).highCheckPtr
      highValues = *(fitArray[i]).highValuePtr
      tied = *(fitArray[i]).tiePtr

      nparms = *(fitArray[i]).nparmPtr
      exprArray = *(fitArray[i]).exprPtr
      ncurves = n_elements(names)
      parmcount = 0

      dat = (*self.dataPtr)[*,thisGroup]
      daterr = (*self.errorPtr)[*,thisGroup]
      x = (*self.xvalsPtr)[*,thisGroup]
      y = (*self.yvalsPtr)[0,thisGroup]

      for j = 0,ncurves-1 do begin
        ; curParms contains the parameters for the current curve
        curParms = parms[parmCount:parmCount+nparms[j]-1]
        parmCount = parmCount + nparms[j]
       name = strlowcase(names[j])
       expr = exprArray[j]
        if strupcase(name) ne 'PAN_USERFUNCTION' then begin
    
           ;020708
           ;ADD THE NEXT BLOCK
           resExists = self->ExtractOneResStr(val,OneResStr)
           if resExists ne 0 then begin
             (*self.oneResPtr) = OneResStr
             rlimit=OneResStr.rlimit
           endif else begin
             self->clearOneRes_ptr
           endelse

          ;020708
          ;REPLACE THE NEXT LINE WITH THE ONE BELOW IT
          ;if (n_elements(*self.resPtr) gt 0) then begin
          if (n_elements(*self.resPtr) gt 0) and (resExists ne 0) then begin
    ;        *self.oneResPtr = (reform((*self.resPtr).data[*,thisGroup]))

             ;020708
             ;THE resExists BLOCK ABOVE SETS THES VALUES
;             (*self.oneResPtr) = {x:(*self.resPtr).x $
;                                  ,y:(*self.resPtr).y $
;                                  ,data:reform((*self.resPtr).data[*,thisGroup]) $
;                                  ,rlimit:(*self.resPtr).rlimit $
;                                 }
;            rlimit = (*self.resPtr).rlimit

    
           *self.ocurrentPtr = obj_new("func",name = name,xvalues = x,$
                               xtabPtr = self.xtabPtr,  $
                               ytabPtr = self.ytabPtr,  $
                               ttabPtr = self.ttabPtr,  $
                                  btabPtr = self.btabPtr,  $
                                  resPtr = self.oneResPtr, $
                                  rlimit = rlimit)
          endif else begin
           *self.ocurrentPtr = obj_new("func",name = name,xvalues = x,$
                               xtabPtr = self.xtabPtr, $
                               ytabPtr = self.ytabPtr, $
                               ttabPtr = self.ttabPtr, $
                                  btabPtr = self.btabPtr)
          endelse
        endif else begin ; Ok we have a USER-DEFINED FUNCTION

          parmStr = getparmsfromexpr(expr)
          ;numparms = n_elements(parmStr)
          test = pan_userfunction(x,curparms,expr = expr,eval = eval)
          if eval ne 1 then return
          *self.ocurrentPtr = obj_new("func",name = name, $
                              xvalues = x, $
                              expr = expr, $
                              parms = curparms,$
                              xtabPtr = self.xtabPtr, $
                              ytabPtr = self.ytabPtr, $
                              btabPtr = self.btabPtr, $
                              ttabPtr = self.ttabPtr)

        endelse
        oc -> add,*self.ocurrentPtr
        parmInfo = self->packageParmInfo()

      endfor
      oc->setparms,parms
      oc->setparmError,sigma
      oc->setfixed,fixed_parms
      oc->setlow,lowCheck
      oc->sethigh,highCheck
      oc->setlowvalues,lowValues
      oc->sethighvalues,highValues
      oc->settied,tied
      oc->setchisq,chi_value
    endfor

    ;wset,self.resPix
    ;self->plotResiduals
    ;wset,self.resVis
    ;device,copy = [0,0,!d.x_size,!d.y_size,0,0,self.resPix]
    ;
    ;wset,self.datPix
    ;self->displayData
    ;wset,self.datVis
    ;device,copy = [0,0,!d.x_size,!d.y_size,0,0,self.datPix]
    self->refresh

    ; Clean up the pointers
    for j = 0,ngrps-1 do begin
      ptr_free,(fitArray[j]).namePtr
      ptr_free,(fitArray[j]).parmPtr
      ptr_free,(fitArray[j]).parmErrPtr
      ptr_free,(fitArray[j]).fixPtr
      ptr_free,(fitArray[j]).tiePtr
      ptr_free,(fitArray[j]).lowCheckPtr
      ptr_free,(fitArray[j]).lowValuePtr
      ptr_free,(fitArray[j]).highCheckPtr
      ptr_free,(fitArray[j]).highValuePtr
      ptr_free,(fitArray[j]).nparmPtr
      ptr_free,(fitArray[j]).exprPtr
      ptr_free,(fitArray[j]).chisqPtr
    endfor

    return
end;opan::readParmsAsText
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
pro opan::print2text,event = event
    if n_elements(*self.dataPtr) eq 0 then return
    thisPath = self.workDir
    filename = DIALOG_PICKFILE(dialog_parent = event.top,$
                                                  title = 'Enter output text file name',$
                                                  /read,filter = '*.txt',$
                                                  path = thisPath)

    if filename ne '' then begin
        ;RTA - fix problem with double extensions
        if (strpos(filename,'.') eq -1) then $
           filename = filename + '.txt'

        fitObject = *self.ocurveGroup
        ngroups = n_elements(fitObject)

        openw,lun,filename,/get_lun

        for i = 0L,ngroups-1 do begin
          oc = fitObject[i]
          oall = oc->get(/all)
          ncurves = oc->count()


          ;040407
          ;LRK
          ;WITH MASKING TAKEN INTO ACCOUNT, THE NEXT LINE WILL PREVENT AN INCOMPATIBILITY
          ;BETWEEN ycomp AND yvalues, SINCE THE NUMBER OF yvalues IN EACH CURVE IS SET
          ;ELSEWHERE.

    ;      print,'opan::print2text before extraction',i
          self->extractDataForPAN,dat=dat,derr=daterr,x=x,group=i+1
    ;      dat = reform((*self.dataPtr)[*,i])
    ;      daterr = reform((*self.errorPtr)[*,i])
    ;      x = reform((*self.xvalsPtr)[*,i])
          nx = n_elements(x)
    ;      print,'opan::print2text after extraction',i,nx

          strout1 = '# Group '+string(i+1)
          strout2 = '# x y yerr'
          str = ['#','x','yerr']
          if ncurves gt 0 then begin



           ;020708
           ;ADD THE NEXT BLOCK TO REPLACE THE ONE BELOW IT (TO HANDLE RES MASKING)
           resExists = self->ExtractOneResStr(val,OneResStr)
           if resExists ne 0 then begin
             (*self.oneResPtr) = OneResStr
             rlimit=OneResStr.rlimit
              oc->evaluate,x,yout = yfit,resPtr = self.oneResPtr,rlimit = rlimit
           endif else begin
             self->clearOneRes_ptr
             oc->evaluate,x,yout = yfit
           endelse

;
;            if n_elements(*self.resPtr) gt 0 then begin
;        ;      *self.oneResPtr = (reform((*self.resPtr).data[*,i]))
;               (*self.oneResPtr) = {x:(*self.resPtr).x $
;                                    ,y:(*self.resPtr).y $
;                                    ,data:reform((*self.resPtr).data[*,i]) $
;                                    ,rlimit:(*self.resPtr).rlimit $
;                                   }
;
;              rlimit = (*self.resPtr).rlimit
;              oc->evaluate,x,yout = yfit,resPtr = self.oneResPtr,rlimit = rlimit
;            endif else begin
;              oc->evaluate,x,yout = yfit
;            endelse

            txt = replicate('  component: ',ncurves)
            txt = txt + strtrim(string(indgen(ncurves)+1),2)
            strout2 = strout2 + ' total fit '
            str = [str,'total fit']
            ycomp = fltarr(nx,ncurves)
            for j = 0,ncurves-1 do begin
              oall[j]->getProperty,xvalues = x,name = name
              if strupcase(name) eq 'PAN_DELTA' then begin

              oall[j]->getproperty,parms = theseparms,xvalues = xvalues
              yvalues = pan_delta(xvalues,theseparms,resPtr = self.oneResPtr,rlimit = rlimit)
              endif else begin
                oall[j]->setproperty,xvalues = x,/calculate
                oall[j]->getproperty,yvalues = yvalues
              endelse

              ycomp[*,j] = yvalues

              if j eq 0 then begin
                out = txt[j]
              endif else begin
             out = out + txt[j]
              endelse
              str = [str,txt[j]]
            endfor
            strout2 = strout2 + out
            printf,lun,strout1
            outFormat = '(A1,'+strtrim(string(3+ncurves),2)+'A20)'
            printf,lun,strout2;,format = outFormat

            thisFormat = '('+strtrim(string(4+ncurves),2)+'f15.5)'
            dataOut = fltarr(4+ncurves)
            for j = 0L,nx-1 do begin
              dataOut[0:4+ncurves-1] = [x[j],dat[j],daterr[j],yfit[j],transpose(ycomp[j,0:ncurves-1])]
              printf,lun,dataOut[0:4+ncurves-1],format = thisFormat
            endfor

          endif else begin
            printf,lun,strout1
            outFormat = '(A1,'+strtrim(string(2),2)+'A20)'
            printf,lun,strout2,format = outFormat
            thisFormat = '('+strtrim(string(3),2)+'f15.5)'
            dataOut = fltarr(3)
            for j = 0L,nx-1 do begin
              dataOut[0:2] = [x[j],dat[j],daterr[j]]
              printf,lun,dataOut[0:2],format = thisFormat
            endfor
          endelse
        printf,lun,''
        endfor

        free_lun,lun
        msg = 'Output save in: '+filename
        ok = dialog_message(/info,msg,dialog_parent=event.top)
    endif;filename ne ''
    return
end;opan::print2text
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
pro opan::print2text_as_excel,event = event
    if n_elements(*self.dataPtr) eq 0 then return
    thisPath = self.workDir
    filename = DIALOG_PICKFILE(dialog_parent = event.top,$
                                                  title = 'Enter output text file name',$
                                                  /read,filter = '*.txt',$
                                                  path = thisPath)

    if filename ne '' then begin
        ;RTA - fix problem with double extensions
        if (strpos(filename,'.') eq -1) then $
           filename = filename + '.txt'

        fitObject = *self.ocurveGroup
        ngroups = n_elements(fitObject)

    ;THE ncols DECISION MUST BE DONE MORE CAREFULLY WITH MASKING.
    ;SHOULD I GO WITH THE ORIGINAL EXTRACTION OF DATA THAT ROB USED AND
    ;MAKE AN ALTERED COPY OF THE curveGroup's AND THE CONTAINED func'S????

        ; How many columns do we need?
        ncols = 0
        for i = 0,ngroups-1 do begin

           oc = fitobject[i]
           ncurves = oc->count()
           ncols =  ncols  +    $  ;
                    3 +         $  ; the independent variable, the intensity, and the error bars
                    ncurves +   $  ; the number of curves
                    1              ; the overall fit


           ;HERE WE USE ALL X VALUES, NOT JUST THE UNMASKED ONES.
           ; How many rows do we need?
           x = reform((*self.xvalsPtr)[*,i])
           nx = n_elements(x)

        endfor

        format_statement = '('+strtrim(string(ncols),2)+'f15.5)'
        nrows = nx

        ; Create a data array with the required number of rows and columns
        ; Ultimately this will be the array that is written out to a file

        for i = 0,ngroups - 1 do begin
           oc = fitobject[i]
           oall = oc->get(/all)
           ncurves = oc->count()

           ;040407
           ;LRK
           ;self->extractDataForPAN,dat=dat,derr=daterr,x=x,group=i+1


;041107
;LRK
;HERE I WILL ALSO HAVE TO USE THE COMPLETE SET OF DATA TO MAKE THE RECTANGULAR GRID FOR EXCEL
           dat = reform((*self.dataPtr)[*,i])
           daterr = reform((*self.errorPtr)[*,i])
           x = reform((*self.xvalsPtr)[*,i])


           nx = n_elements(x)
           num_string = strtrim(string(i+1),2)
           if n_elements(d) eq 0 then begin
              d = [transpose(x),transpose(dat),transpose(daterr)]
              titles = ['x'+num_string,'y'+num_string,'yerr'+num_string]
           endif else begin
              d = [d,transpose(x),transpose(dat),transpose(daterr)]
              titles = [titles,'x'+num_string,'y'+num_string,'yerr'+num_string]
           endelse


;SINCE THE CURVEGROUP TAKES X AS AN ARGUMENT, I SHOULD JUST BE ABLE TO USE
;THE COMPLETE X RANGE HERE.  ---- DOES THE evaluate METHOD REPLACE VALUES IN THE OBJECT????
          if ncurves gt 0 then begin

           ;020708
           ;ADD THE NEXT BLOCK TO REPLACE THE ONE BELOW IT (TO HANDLE RES MASKING)
           resExists = self->ExtractOneResStr(val,OneResStr)
           if resExists ne 0 then begin
             (*self.oneResPtr) = OneResStr
             rlimit=OneResStr.rlimit
              oc->evaluateExcel,x,yout = yfit,resPtr = self.oneResPtr,rlimit = rlimit
           endif else begin
             self->clearOneRes_ptr
             oc->evaluateExcel,x,yout = yfit
           endelse
;            if n_elements(*self.resPtr) gt 0 then begin
;        ;      *self.oneResPtr = (reform((*self.resPtr).data[*,i]))
;             (*self.oneResPtr) = {x:(*self.resPtr).x $
;                                  ,y:(*self.resPtr).y $
;                                  ,data:reform((*self.resPtr).data[*,i]) $
;                                  ,rlimit:(*self.resPtr).rlimit $
;                                 }
;              rlimit = (*self.resPtr).rlimit
;              oc->evaluateExcel,x,yout = yfit,resPtr = self.oneResPtr,rlimit = rlimit
;            endif else begin
;              oc->evaluateExcel,x,yout = yfit
;            endelse
            titles = [titles,'ftotal']

    ;SO TO OVERCOME THIS I WILL NEED TO MATCH UP THE EXISTING X VALUES WITH THE TOTAL RANGE
    ;AVAILABLE IN THE ENTIRE SPREADSHEET.  I'LL FILL IN THE MISSING VALUES WITH NaN's OR
    ;SOME OTHER SUITABLE VALUE.
    ;print,'opan::print2text_as_excel',n_elements(x),ngroups,i
    ;print,'opan::print2text_as_excel',n_elements(yfit)
;print,'opan::print2text_as_excel '+string(i)+string(ngroups)

            d = [d,transpose(yfit)]

;print,'test'
;print,'opan::print2text_as_excel '+string(i)

        ;    data_array[
        ;    ycomp = fltarr(nx,ncurves)
            for j = 0,ncurves-1 do begin

            ;041107
            ;LRK
            ;SO HERE I WANT TO GET THE NAME, BUT NOT x.  SO CHANGE THE NEXT LINE TO THE ONE BELOW IT.
              ;oall[j]->getProperty,xvalues = x,name = name
              oall[j]->getProperty,name = name
              if strupcase(name) eq 'PAN_DELTA' then begin
                 ;041107
                 ;LRK
                 ;NOW I NEED TO USE THE FULL SET OF xvalues, SO CHANGE THE NEXT
                 ;LINE TO THE TWO BELOW IT TO GET theseparms, BUT NOT THE xvalues.
                 ;oall[j]->getproperty,parms = theseparms,xvalues = xvalues
                 oall[j]->getproperty,parms = theseparms
                 xvalues = x
                 yvalues = pan_delta(xvalues,theseparms,resPtr = self.oneResPtr,rlimit = rlimit)
              endif else begin
                ;041107
                ;LRK
                ;NOW THE NEXT LINE SHOULD BE CHANGED SO THAT IT FIRST STORES THE ORIGINAL
                ;XVALUES BEFORE SUBBING IN x.  AFTER CALCULATION IT SHOULD REPLACE THE
                ;ORIGINAL xvalues.
                ;oall[j]->setproperty,xvalues = x,/calculate
                oall[j]->getproperty,xvalues=xtempsave
                oall[j]->setproperty,xvalues = x,/calculate

                ;THE NEXT LINE IS THE ORIGINAL
                oall[j]->getproperty,yvalues = yvalues

                ;THE NEXT LINE IS NEW
                oall[j]->setproperty,xvalues = x,/calculate

              endelse
              num_string = strtrim(string(j+1),2)
              titles = [titles,+'fcomp'+num_string]
;print,'             opan::print2text_as_excel '+string(i)
              d = [d,transpose(reform(yvalues))]
;print,'             opan::print2text_as_excel '+string(i)
            endfor

          endif
        endfor
        text_format = '('+strtrim(string(ncols),2)+'A15)'
        number_format = '('+strtrim(string(ncols),2)+'g15.5)'

        openw,lun,filename,/get_lun,width = ncols
        printf,lun,titles,format = text_format
        for i = 0,nrows-1 do printf,lun,d[*,i],format = number_format
        free_lun,lun

        msg = 'Output save in: '+filename
        ok = dialog_message(/info,msg,dialog_parent=event.top)
    endif;filename ne ''

    return
end;opan::print2text_as_excel
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
;SAVE ORIGINAL VERSION.
;pro opan::print2text_as_excel,event = event
;    if n_elements(*self.dataPtr) eq 0 then return
;    thisPath = self.workDir
;    filename = DIALOG_PICKFILE(dialog_parent = event.top,$
;                                                  title = 'Enter output text file name',$
;                                                  /read,filter = '*.txt',$
;                                                  path = thisPath)
;    ;RTA - fix problem with double extensions
;    if (strpos(filename,'.') eq -1) then $
;       filename = filename + '.txt'
;
;    fitObject = *self.ocurveGroup
;    ngroups = n_elements(fitObject)
;
;    ; How many columns do we need?
;    ncols = 0
;    for i = 0,ngroups-1 do begin
;
;       oc = fitobject[i]
;       ncurves = oc->count()
;       ncols =  ncols  +    $  ;
;                3 +         $  ; the independent variable, the intensity, and the error bars
;                ncurves +   $  ; the number of curves
;                1              ; the overall fit
;
;       ; How many rows do we need?
;       x = reform((*self.xvalsPtr)[*,i])
;       nx = n_elements(x)
;
;    endfor
;
;    format_statement = '('+strtrim(string(ncols),2)+'f15.5)'
;    nrows = nx
;
;    ; Create a data array with the required number of rows and columns
;    ; Ultimately this will be the array that is written out to a file
;
;    for i = 0,ngroups - 1 do begin
;
;       oc = fitobject[i]
;       oall = oc->get(/all)
;       ncurves = oc->count()
;
;       dat = reform((*self.dataPtr)[*,i])
;       daterr = reform((*self.errorPtr)[*,i])
;       x = reform((*self.xvalsPtr)[*,i])
;       nx = n_elements(x)
;       num_string = strtrim(string(i+1),2)
;       if n_elements(d) eq 0 then begin
;          d = [transpose(x),transpose(dat),transpose(daterr)]
;          titles = ['x'+num_string,'y'+num_string,'yerr'+num_string]
;       endif else begin
;          d = [d,transpose(x),transpose(dat),transpose(daterr)]
;          titles = [titles,'x'+num_string,'y'+num_string,'yerr'+num_string]
;       endelse
;
;      if ncurves gt 0 then begin
;
;        if n_elements(*self.resPtr) gt 0 then begin
;    ;      *self.oneResPtr = (reform((*self.resPtr).data[*,i]))
;         (*self.oneResPtr) = {x:(*self.resPtr).x $
;                              ,y:(*self.resPtr).y $
;                              ,data:reform((*self.resPtr).data[*,i]) $
;                              ,rlimit:(*self.resPtr).rlimit $
;                             }
;          rlimit = (*self.resPtr).rlimit
;          oc->evaluate,x,yout = yfit,resPtr = self.oneResPtr,rlimit = rlimit
;        endif else begin
;          oc->evaluate,x,yout = yfit
;        endelse
;        titles = [titles,'ftotal']
;
;        d = [d,transpose(yfit)]
;
;    ;    data_array[
;    ;    ycomp = fltarr(nx,ncurves)
;        for j = 0,ncurves-1 do begin
;          oall[j]->getProperty,xvalues = x,name = name
;          if strupcase(name) eq 'PAN_DELTA' then begin
;             oall[j]->getproperty,parms = theseparms,xvalues = xvalues
;             yvalues = pan_delta(xvalues,theseparms,resPtr = self.oneResPtr,rlimit = rlimit)
;          endif else begin
;            oall[j]->setproperty,xvalues = x,/calculate
;            oall[j]->getproperty,yvalues = yvalues
;          endelse
;          num_string = strtrim(string(j+1),2)
;          titles = [titles,+'fcomp'+num_string]
;          d = [d,transpose(reform(yvalues))]
;        endfor
;
;      endif
;    endfor
;    text_format = '('+strtrim(string(ncols),2)+'A15)'
;    number_format = '('+strtrim(string(ncols),2)+'g15.5)'
;
;    openw,lun,filename,/get_lun,width = ncols
;    printf,lun,titles,format = text_format
;    for i = 0,nrows-1 do printf,lun,d[*,i],format = number_format
;    free_lun,lun
;
;    msg = 'Output save in: '+filename
;    ok = dialog_message(/info,msg,dialog_parent=event.top)
;
;    return
;end;opan::print2text_as_excel
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
function opan::packageParmInfo
    ; Get parameter information
    widget_control,self.groupSlider,get_value = val
    val = fix(val[0]) - 1
    datSize = size(*self.dataPtr)
    if datSize[0] eq 1 then val = 0
    oc = (*self.ocurveGroup)[val]
    ncurves = oc->count()
    if ncurves eq 0 then return,(-1L)
    names = oc->getnames()
    ncurves = n_elements(names)
    step = oc->getstep()
    fixed = oc->getfixed()
    lovalues = oc->getlowvalues()
    hivalues = oc->gethighvalues()
    parms = oc->getparms()
    parmnames = oc->getparmnames()
    high = oc->gethigh()
    low = oc->getlow()
    tied = oc->gettied()
    expr = oc->getExpr()

    oall = oc->get(/all)
    for i = 0,ncurves-1 do begin
       oall[i]->getproperty,parmnames = parmnames, name = name
       np = n_elements(parmnames)
       if i eq 0 then begin
            pn = parmnames
            nparms = np
       endif else begin
            nparms = [nparms,np]
            pn = [pn,parmnames]
       endelse
    endfor
    parmInfo = {  $
            nparms:nparms,names:names, step:step, fixed:fixed, $
                lovalues:lovalues, hivalues:hivalues, high:high, $
               low:low, parms:parms, parmnames:pn,tied:tied,expr:expr  $
               }
    return,parmInfo
end;opan::packageParmInfo
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
function opan::updateParmInfo,newParmInfo
    widget_control,self.groupSlider,get_value = val
    val = fix(val[0]) - 1
    datSize = size(*self.dataPtr)
    if datSize[0] eq 1 then val = 0
    oc = (*self.ocurveGroup)[val]
    oc->setparms,newParmInfo.parms
    oc->setlow,newParmInfo.low
    oc->sethigh,newParmInfo.high
    oc->setlowvalues,newParmInfo.lovalues
    oc->sethighvalues,newParmInfo.hivalues
    oc->setfixed,newParmInfo.fixed
    oc->settied,newParmInfo.tied
    return,1
end;opan::updateParmInfo
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
pro opan::parameterInfo, event = event
    if n_elements(*self.dataPtr) eq 0 then return
    ; Is there a curve present here?
    widget_control,self.groupSlider,get_value = val
    val = fix(val[0]) - 1
    datSize = size(*self.dataPtr)
    if datSize[0] eq 1 then val = 0
    oc = (*self.ocurveGroup)[val]
    ncurves = oc->count()
    if ncurves eq 0 then return
    ; Get parameter information

    thisEvent = tag_names(event,/structure_name)
    case thisEvent of
    '': $
      begin
        widget_control,event.top,sensitive = 0
        parmInfo = self->packageParmInfo()
       widget_control,self.modify,sensitive = 0
        enterparminfo,parmInfo, $
                      group_leader = event.top, $
                      notifyIds = [event.id,event.top]
      end
    'WIDGET_BUTTON': $
      begin
        widget_control,event.top,sensitive = 0
       parmInfo = self->packageParmInfo()
       widget_control,self.modify,sensitive = 0
        enterparminfo,parmInfo, $
                      group_leader = event.top, $
                      notifyIds = [event.id,event.top]
      end
    'PARMSEVENT': $
      begin
         dummy = self->updateParmInfo(*event.parmInfo)

    ;     wset,self.resPix
    ;     self->plotResiduals
    ;     wset,self.resVis
    ;     device,copy = [0,0,!d.x_size,!d.y_size,0,0,self.resPix]
    ;
    ;     wset,self.datPix
    ;     self->displayData
    ;     wset,self.datVis
    ;     device,copy = [0,0,!d.x_size,!d.y_size,0,0,self.datPix]
         self->refresh

      end
    'PARMSQUITEVENT': $
      begin
       widget_control,self.modify,sensitive = 1
       widget_control,event.top,sensitive = 1
       ; Empty placeholder.  We don't want to update any of the
       ; parameter information.
      end
    else:
    endcase

    return
end;opan::parameterInfo
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
pro opan::showFileInfo,event = event
    thisEvent = tag_names(event,/structure_name)
    if n_elements(*self.headerPtr) eq 0 then begin
      output = ['No data currently loaded']
      void = dialog_message(dialog_parent = event.top,output)
      return
    endif
    case thisEvent of
    'WIDGET_BUTTON': $
      begin
        opan_FileInfo,*self.headerPtr,group_leader = event.top, $
                  notifyIds = [event.id,event.top]

      end
    'FILEINFOEVENT': $   ; This case not really necessary
      begin
      end
    else:
    endcase

    return
end;opan::showFileInfo
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
pro opan::preferences, event = event
    thisEvent = tag_names(event,/structure_name)
    case thisEvent of
    'WIDGET_BUTTON': $
      begin
        enterPref,group_leader = event.top, $
                  notifyIds = [event.id,event.top], $
                  prefs = *self.prefs

      end
    'PREFSEVENT': $
      begin
        *self.prefs = event.prefs
        self.xtitle = (*self.prefs).xlabel
        self.ztitle = (*self.prefs).ylabel

        if (n_elements(*self.odataPtr) ne 0 && $
           event.prefs.xenforce) then $
           self->applyCrop, (*self.prefs).xmin, (*self.prefs).xmax, event.top

        self->refresh
    ;     wset,self.resPix
    ;     self->plotResiduals
    ;     wset,self.resVis
    ;     device,copy = [0,0,!d.x_size,!d.y_size,0,0,self.resPix];
    ;
    ;     wset,self.datPix
    ;     self->displayData
    ;     wset,self.datVis
    ;     device,copy = [0,0,!d.x_size,!d.y_size,0,0,self.datPix]
      end
    else:
    endcase

    return
end;opan::preferences
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
function html_header,title = title,username = username
    if n_elements(title) eq 0 then title = 'PAN Log Output'
    if n_elements(username) eq 0 then username = 'PAN User'

    strout = ['<!DOCTYPE html PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN"']
    strout = [strout,'<html>']
    strout = [strout,'<body>']
    strout = [strout,'<meta http-equiv="content-type" content="text/html; charset=ISO-8859-1">']
    strout = [strout,'<meta name="author" content="PAN">']
    strout = [strout,'<title>'+title+'</title>']
    strout = [strout,'</head>']
    strout = [strout,'<body>']
    strout = [strout,'<big><big><b>PAN Data Analysis Log</b></big></big><br>']
    strout = [strout,'<br>']

    strout = [strout,'User name:&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;'+username+'<br>']
    time = systime()
    strout = [strout,'Creation date:&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;'+time+'<br>']
    strout = [strout,'<br>']

    strout = [strout,'']
    return,strout
end;html_header
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
function html_comments,comments = comments,str_in
    if n_elements(comments) eq 0 then return,''
    strout = [str_in,'<p>',comments,'<p>']
    return,strout
end;html_comments
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
function html_finish,str_in
    strout = [str_in,'</body>','</html>']
    return,strout
end;html_finish
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
function html_open,filename = filename
    if n_elements(filename) eq 0 then return,''
    openr,lun,filename,/get_lun
    dummy = ''
    count = 0
    while not(eof(lun)) do begin
      readf,lun,dummy
      if count eq 0 then strout = dummy else strout = [strout,dummy]
      count = count + 1L
    endwhile
    free_lun,lun
    return,strout
end;html_open
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
function html_write,filename = filename,strout = strout
    nstr = n_elements(strout)
    openw,lun,filename,/get_lun
    for i = 0,nstr-1 do begin
      printf,lun,strout[i]
    endfor
    free_lun,lun
    return,0
end;html_write
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
pro opan::logComment,event = event
    if n_elements(*self.logStringPtr) eq 0 then return
    strout = *self.logStringPtr
    comments = opan_getcomments(group_leader = event.top,cancelled = cancel)
    if cancel eq 1 then return

    nc = n_elements(comments)

    end_of_html = where(strout eq '</body>')
    index = end_of_html[0] - 1
    nstr = n_elements(strout)
    strout1 = [strout[0:index],'<p>',comments[0:nc-1],'<p>',strout[index:nstr-1]]
    *self.logStringPtr = strout1
    return
end;opan::logComment
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
pro opan::logAddPlot,event = event
    if n_elements(*self.dataPtr) eq 0 then return
    if n_elements(*self.logStringPtr) eq 0 then return
    self.jpeg = 1
    thisDevice = !d.name
    h = 11.0 & w = 8.0 & aspect1 = h/w
    xsize = 600 & ysize = fix(aspect1*xsize)
    window,/free,/pixmap,xsize = xsize,ysize = ysize
    winPix = !d.window
    wset,winPix
    self->niceOutput,event = event

    device,get_visual_depth = thisDepth
    if thisDepth eq 8 then begin
      tvlct,r,g,b,/get
      image2d = tvrd()
      s = size(image2d,/dimensions)
      image24 = bytarr(3,s[0],s[1])
      tvlct,r,g,b,/get
      image24[0,*,*] = r[image2d]
      image24[1,*,*] = g[image2d]
      image24[2,*,*] = b[image2d]
    endif
    if thisDepth gt 8 then begin
      device,decomposed = 1
      image24=tvrd(true = 1)
    endif
    wdelete,winPix
    thisPath = self.workDir
    ; Create the filename
    counter = 0
    res = 1
    while res eq 1 do begin
      filename = 'panplot_'+strtrim(string(counter),2)+'.jpg'
      testFile = filepath(filename, ROOT_DIR=self.logDirectory)
      res = file_test(testFile)
      counter = counter + 1
    endwhile

    s = Size(image24, /Dimensions)
    newx = Round(150.0 * s[1] / 72)
    newy = Round(150.0 * s[2] / 72)
    highResImage = Congrid(image24, 3, newx, newy, /Interp)

    imgFile = filename

    write_jpeg,testFile,255-highResImage,true = 1,quality = 100
    ;write_jpeg,testFile,highResImage,true = 1,quality = 100
    Set_Plot, thisDevice

    ; Ok, the file has been written.  Now we must add the plot to the HTML file.
    strout = *self.logStringPtr
    end_of_html = where(strout eq '</body>')
    index = end_of_html[0] - 1
    nstr = n_elements(strout)

    read_jpeg,testFile,img
    imgSize = size(img)
    sx = imgSize[2] & sy = imgSize[3]
    aspect2 = 1.0*sy/(1.0*sx)
    outSx = 500 & outSy = fix(1.0*outSx*aspect2)
    imgLine = '<img src="'+imgFile+'" width="'+ $
              strtrim(string(outSx),2)+ $
              '" height="'+strtrim(string(outSy),2)+'"><br>'

    strout1 = [strout[0:index],'<p>',imgLine,strout[index:nstr-1],'<p>']
    *self.logStringPtr = strout1
    self.jpeg = 0

    ;wset,self.resPix
    ;self->plotResiduals
    ;wset,self.resVis
    ;device,copy = [0,0,!d.x_size,!d.y_size,0,0,self.resPix]
    ;
    ;wset,self.datPix
    ;self->displayData
    ;wset,self.datVis
    ;device,copy = [0,0,!d.x_size,!d.y_size,0,0,self.datPix]
    self->refresh

    return
end;opan::logAddPlot
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
pro opan::newHTMLFile,event = event
    ; This method asks the user to provide a new directory
    ; Change directories to the user's working directory
    cd,current = currentDir
    cd,self.workDir
    ; Get the user to enter a directory name
    result = opan_getdirectory(group_leader = event.top,cancelled = cancel)
    if cancel then return
    thisDir = result[0]
    user = result[1]
    title = result[2]
    if thisDir eq '' or thisDir eq ' ' then return
    ; Create the directory
    file_mkdir,thisDir
    cd,currentDir
    ;self.logDirectory = thisDir
    self.logDirectory = filepath('',root_dir = self.workDir,subdir = [thisDir])
    ; Create the log file name with a fully-qualified path
    *self.logStringPtr = html_header(title = title,username = user)
    *self.logStringPtr = html_finish(*self.logStringPtr)
    self.logFile =filepath('index.html',ROOT_DIR=self.workDir,subdir=[thisDir])
    widget_control,self.logFileDisplay,set_value = self.logFile
    widget_control,self.logFileStatus,set_value = 'open'

    ; Sensitize or desensitize the appropriate buttons
    widget_control,self.newHTML,sensitive = 0
    widget_control,self.existingHTML,sensitive = 0
    widget_control,self.closeHTML,sensitive = 1
    widget_control,self.plotHTML,sensitive = 1
    widget_control,self.commentHTML,sensitive = 1

    return
end;opan::newHTMLFile
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
pro opan::existingHTMLFile,event = event
    ; This method reads in an existing log file and allows the user to append
    ; more information to it.
    filename = dialog_pickfile(dialog_parent = event.top,file = 'index.html', $
               title = 'Select the HTML log file',filter = '*.html', $
               path = self.workDir,get_path = logDirectory)
    self.logDirectory = logDirectory
    if filename eq '' or filename eq ' ' or not(file_test(filename)) then begin
      strout = 'Not a valid file selection'
      void = dialog_message(dialog_parent = event.top,strout)
      return
    endif
    self.logFile = filename
    *self.logStringPtr = html_open(filename = filename)
    widget_control,self.logFileDisplay,set_value = self.logFile
    widget_control,self.logFileStatus,set_value = 'open'

    ; Sensitize or desensitize the appropriate buttons
    widget_control,self.newHTML,sensitive = 0
    widget_control,self.existingHTML,sensitive = 0
    widget_control,self.closeHTML,sensitive = 1
    widget_control,self.plotHTML,sensitive = 1
    widget_control,self.commentHTML,sensitive = 1

    return
end;opan::existingHTMLFile
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
pro opan::closeHTMLFile,event = event
    if n_elements(*self.logStringPtr) eq 0 then return
    ; Write the html file
    dummy = html_write(filename = self.logFile,strout = *self.logStringPtr)
    ptr_free,self.logStringPtr
    self.logStringPtr = ptr_new(/allocate_heap)
    widget_control,self.logFileDisplay,set_value = ''
    widget_control,self.logFileStatus,set_value = 'closed'

    ; Sensitize or desensitize the appropriate buttons
    widget_control,self.newHTML,sensitive = 1
    widget_control,self.existingHTML,sensitive = 1
    widget_control,self.closeHTML,sensitive = 0
    widget_control,self.plotHTML,sensitive = 0
    widget_control,self.commentHTML,sensitive = 0
    return
end;opan::closeHTMLFile
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
pro opan::refresh,_Extra = extra
    device, get_decomposed=old_dc
    device, decomposed=1

    wset,self.resPix
    self->plotResiduals
    wset,self.resVis
    device,copy = [0,0,!d.x_size,!d.y_size,0,0,self.resPix]

    wset,self.datPix


    self->displayData

    wset,self.datVis
    device,copy = [0,0,!d.x_size,!d.y_size,0,0,self.datPix]

    device, decomposed=old_dc
end;opan::refresh
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
pro opan::pan_help,event = event
;    pdf_file = !DAVE_AUXILIARY_DIR+'pandoc.pdf'
    pdf_file = !DAVE_AUXILIARY_DIR+'pandoc_DAVE.pdf'
    ;pdf_file = file_which('pandoc.pdf',/include_current_dir)
    void = launch_help(pdf_file,tlb = event.top)
end;opan::pan_help
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
pro opan::pan_user_macros_help,event = event
    pdf_file = !DAVE_AUXILIARY_DIR+'pan_user_macros.pdf'
    ;pdf_file = file_which('pan_user_macros.pdf',/include_current_dir)
    void = launch_help(pdf_file,tlb = event.top)
end;opan::pan_user_macros_help
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
pro opan::view_corr_matrix,event = event
    thisEvent = tag_names(event,/structure_name)
    case thisEvent of
    'WIDGET_BUTTON':  $
       begin
    ; Which detector/fit is currently selected?
         widget_control,self.groupSlider,get_value = val
         val = fix(val[0])-1
         if n_elements(*self.dataPtr) eq 0 then return
         datSize = size(*self.dataPtr)
         if datSize[0] eq 1 then val = 0
         oc = (*self.ocurveGroup)[val]
         oc->displayparms,output = output
         ncurves = oc->count()
         if ncurves gt 0 then begin
          widget_control,self.curveSlider,set_slider_max = (ncurves > 2)
         endif
         if n_elements(output) eq 0 then begin
           output = 'No curves present'
         endif
         oc->get_pcor,pcor
         if n_elements(pcor) eq 1 then return
         parmnames = oc->getparmnames()
         nparms = n_elements(parmnames)
         new_parmnames = strarr(nparms)
         for i = 0,nparms-1 do begin
          new_parmnames[i] = '#'+strtrim(string(i),2)+': '+parmnames[i]
         endfor
         bad_index = where(finite(pcor) ne 1, count_bad)
         if count_bad gt 0 then pcor[bad_index] = -1.e6

         rains_display_correlation,  pcor,            $
                      new_parmnames,       $
                      group_leader = event.top,  $
                      notify_ids = [event.id,event.top]
       end
    else:
    endcase
end;opan::view_corr_matrix
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
pro opan::mc_estimate,event = event
    widget_control,self.ndata_field,get_value = val
    self.ndata = fix(val) > 2
    ; Get the current data set
    widget_control,self.groupSlider,get_value = val
    val = fix(val[0])-1
    if n_elements(*self.ocurvegroup) eq 0 then return
    oc = (*self.ocurveGroup)[val]
    parms = oc->getparms()
    parinfo = oc->createparinfo()

    if oc->count() eq 0 then return
    datSize = size(*self.dataPtr)
    if datSize[0] eq 2 then begin
      y = (*self.dataPtr)[*,val]
      yerr = (*self.errorPtr)[*,val]
      x = (*self.xvalsPtr)[*,val]
    endif else begin
      y = reform(*self.dataPtr)
      yerr = reform(*self.errorPtr)
      x = reform(*self.xvalsPtr)
    endelse
    xptr = ptr_new(x)
    ; Get the current fitting range for the data
    limits = where((x ge (*self.prefs).xfitlo) and (x le (*self.prefs).xfithi))
    xlim = x[limits]
    ylim = y[limits]
    dylim = yerr[limits]
    nx = n_elements(xlim)

    msg = 'Estimating errors using the "bootstrap" Monte-Carlo method'
    title = 'Progress'
    progressBar = Obj_New("SHOWPROGRESS",message = msg,title = title, $
       event.top,/cancelbutton)
    progressBar->Start
    dy = dylim
    w = 1./dy^2

    iterargs = {stopBut:self.interrupt}
    iterproc = 'pan_iterproc'
    widget_control,self.fitstatfield,set_value = self.fitstatus[1]
    ;widget_control,self.interrupt,sensitive = 1
    ;widget_control,self.interrupt,/clear_events
    np = n_elements(parms)
    mc_parms = fltarr(np,self.ndata)

    for i = 0L,self.ndata-1 do begin
       r_normal = randomn(s,nx)
       derr = dylim*r_normal
       y = ylim+derr
       widget_control,self.interrupt,sensitive = 1
       widget_control,self.interrupt,/clear_events
       yf = mpcurvefit(xlim,y,w,parms,sigma,                                $
             function_name = 'fitfunction', status = status,                $
             parinfo = parinfo, itmax = (*self.prefs).maxiter,              $
             /quiet,chisq = chisq,iterargs = iterargs,iterproc = iterproc,  $
             functargs = {oc:oc,xptr:xptr}, covar = covar,/autoderivative,  $
             errmsg = errmsg                                                )
       widget_control,self.interrupt,sensitive = 0
       widget_control,self.fitstatfield,set_value = self.fitstatus[0]
       mc_parms[*,i] = parms
       progressBar->update,(i+1)*100/self.ndata

       cancelled = progressBar->CheckCancel()
       if cancelled then begin
          progressBar->Destroy
          i = self.ndata-1
       endif
    endfor

    ; Do the statistics on the parameters
    presult = fltarr(np)
    dpresult = fltarr(np)

    for i = 0,np-1 do begin
       p = mc_parms[i,*]
       pstats = moment(p)
       presult[i] = pstats[0]
       dpresult[i] = sqrt(pstats[1])
    endfor

    ; Put these results into the parameter
    oc->setparmerror,dpresult

    widget_control,self.interrupt,/clear_events
    if status le 0 then begin
       self.status = 0
       strout = 'Fit cancelled'
       widget_control,self.fitstatfield,set_value = strout
    endif else begin
       self.status = 1
    endelse
    ptr_free,xptr

    if obj_valid(progressBar) then progressBar->Destroy
    obj_destroy, progressBar

    oc->setparms,parms
    oc->evaluate,x,yout = yfit
    ; Calculate the residuals
    yfit = yfit[limits]
    dof = n_elements(yfit) - np
    chi_sq = (total(((yfit-ylim)/dy)^2))/dof
    oc->setchisq,chi_sq

    wset,self.resPix
    self->plotresiduals
    wset,self.resVis
    device,copy = [0,0,!d.x_size,!d.y_size,0,0,self.resPix]

    wset,self.datPix
    self->displaydata
    wset,self.datVis
    device,copy = [0,0,!d.x_size,!d.y_size,0,0,self.datPix]

    ; Display the parameters
    self->displayFitParameters

end;opan::mc_estimate
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
pro opan::createWidgets
    ; Widget creation module
    if self.group_leader eq (-1L) then begin
      tlb = widget_base(/row, $
            title = 'PAN: Peak Analysis',mbar = bar,/tlb_size_events)
    endif else begin
      tlb = widget_base(group_leader = self.group_leader,/row, $
            title = 'PAN: Peak Analysis',mbar = bar,/tlb_size_events);, $
    ;        /kbrd_focus_events)
    endelse
    self.tlb = tlb

    font = (!version.os_family eq 'Windows')? 'Courier New*16' : $
           '-adobe-courier-bold-r-normal--18-180-75-75-m-110-iso8859-1'

    filemenu = widget_button(bar,value = 'File',/menu,font=font)
    datmenu = widget_button(bar,value = 'Data',/menu,font=font)
    resmenu = widget_button(bar,value = 'Resolution',/menu,font=font)
    printmenu = widget_button(bar,value = 'Print',/menu,font=font)
    helpmenu = widget_button(bar,value = 'Help',/menu,font=font)
    ;miscmenu = widget_button(bar,value = 'Miscellaneous',/menu)
    void = widget_button(helpmenu,value = 'PAN Help', $
       uvalue = {object:self,method:'pan_help'})
    void = widget_button(helpmenu,value = 'PAN User Macros Help', $
       uvalue = {object:self,method:'pan_user_macros_help'},uname = 'PAN_HELP')
    void = widget_button(helpmenu,value = 'About PAN',$
           uvalue = {object:self,method:'aboutPAN'})

    ; File Menu
    void = widget_button(filemenu,value = 'Save fit function as DAVE data file', $
           uvalue = {object:self,method:'saveDaveFits'})
    void = widget_button(filemenu,value = 'Save fit parameters as text file',$
           uvalue = {object:self,method:'saveParmsAsText'})
    void = widget_button(filemenu,value = 'Read in fit parameters',$
           uvalue = {object:self,method:'readParmsAsText'})
    void = widget_button(filemenu,value = 'Preferences',$
           uvalue = {object:self,method:'preferences'},/separator)
    void = widget_button(filemenu,value = 'Quit',/separator,$
           uvalue = {object:self,method:'quit'})

    ; Data Menu
    void = widget_button(datmenu,value = 'Load DAVE file', $
           uvalue = {object:self,method:'loadDave'})


;031607
;ELIMINATING THIS BUTTON WHICH ALLOWS USER TO READ IN TAS DATA FILES.
;IT SEEMS TO CAUSE DAVE CRASHES, SO IT IS HIGHLY UNLIKELY TO BE USED
;BY ANYONE CURRENTLY.  THE NEW ICE FILES WILL ALSO MAKE THIS OBSOLETE.
;

;    tasMenu = widget_button(datmenu,value = 'TAS (ICP) files',/menu)
;
;    if (!version).release ge 5.6 then begin
;       tas_title = 'Browse and Load TAS data file'
;    endif else begin
;       tas_title = 'Load TAS data file'
;    endelse
;    void = widget_button(tasmenu,value = tas_title, $
;           uvalue = {object:self,method:'loadtasdata'})
;    if (!version).release lt 5.6 then begin
;       void = widget_button(tasmenu,value = 'Load TAS data file from previous list', $
;             uvalue = {object:self,method:'loadtasdatafromprevious'})
;    endif



    asciiMenu = widget_button(datmenu,value = 'ASCII files',/menu)
    void = widget_button(asciimenu,value = 'Load 3-col ascii data', $
           uvalue = {object:self,method:'loadasciidata'})
    void = widget_button(asciimenu,value = 'Load grouped ascii data', $
           uvalue = {object:self,method:'loadgroupdata'})
    void = widget_button(asciimenu,value = 'Load FCS data (SQW.XY)', $
           uvalue = {object:self,method:'loadfcsdata'})

    void = widget_button(datmenu,value = 'Load test data', $
           uvalue = {object:self,method:'loadtestdata'})
    void = widget_button(datmenu,value = 'Display current file information',$
           uvalue = {object:self,method:'showFileInfo'},/separator)
    void = widget_button(datmenu,value = 'Rebin data', $
           uvalue = {object:self,method:'rebinData'},/separator)
    void = widget_button(datmenu,value = 'Crop data', $
           uvalue = {object:self,method:'cropData'})




    void = widget_button(datmenu,value = 'Edit Pan Mask', $
           uvalue = {object:self,method:'editPanMask'})


    ;void = widget_button(datmenu,value = 'Exclude data', $
    ;       uvalue = {object:self,method:'excludeData'})
    void = widget_button(datmenu,value = 'Restore Original data', $
           uvalue = {object:self,method:'rebinRestore'})

    ; Resolution Menu
    void = widget_button(resmenu,value = 'Load DAVE data as resolution function', $
           uvalue = {object:self,method:'loadDaveRes'})
    void = widget_button(resmenu,value = 'Load 3-col ascii resolution function', $
           uvalue = {object:self,method:'load_3col_ascii_res'})
    void = widget_button(resmenu,value = 'Load grouped ascii resolution function', $
           uvalue = {object:self,method:'load_group_ascii_res'})
    void = widget_button(resmenu,value = 'Change resolution domain (crop)', $
           uvalue = {object:self,method:'cropRes'},/separator)
    void = widget_button(resmenu,value = 'Rebin Resolution data', $
           uvalue = {object:self,method:'rebinRes'})
    void = widget_button(resmenu,value = 'Restore Resolution data', $
           uvalue = {object:self,method:'restoreRes'})
    void = widget_button(resmenu,value = 'Clear resolution function', $
           uvalue = {object:self,method:'clearDaveRes'},/separator)
    ;void = widget_button(resmenu,value = 'Load test resolution function', $
    ;       uvalue = {object:self,method:'loadtestres'})


    ; Print menu
    void = widget_button(printmenu,value = 'Printer', $
           uvalue = {object:self,method:'print2Printer'})
    void = widget_button(printmenu,value = 'Print screen to .JPEG file', $
           uvalue = {object:self,method:'print2jpeg'})
    void = widget_button(printmenu,value = 'Print to PS file', $
           uvalue = {object:self,method:'print2ps'})
    void = widget_button(printmenu,value = 'Print data and fits to text file', $
           uvalue = {object:self,method:'print2text'})
    void = widget_button(printmenu,value = 'Print data and fits to EXCEL-readable ASCII', $
           uvalue = {object:self,method:'print2text_as_excel'})


    ctrlBase = widget_base(tlb,/col,/base_align_center);,uvalue = {object:self,method:'fitCurrent'})
    self.ctrlBase = ctrlBase
    self.timerID = ctrlBase

    curveNames =   [  'Select function',   $
                      'AutoGaussian',      $
                      'AutoLorentzian',    $
                      'qens',              $
                      'delta',             $
                      'gaussian',          $
                      'lorentzian',        $
                      'lognormal',         $
                      'DHO',               $
    ;                  'kohlrausch',        $
                      'step',              $
                      'background',        $
                      'decay',             $
                      'KWW',               $
                      'ft_KWW', $
                      ;'NSE_Deformation',$
                      'MeanfieldOrderParameter', $
                      'userfunction',      $
                      'user macro function']

    ncurves = n_elements(curveNames)
    *self.curvenamesPtr = curveNames

    desc = replicate({ flags:0, name:'' }, ncurves)
    desc.flags = [1,0*indgen(ncurves-1)]
    desc.name = curveNames

    butBase = widget_base(ctrlbase,/col,/frame,/base_align_center)

    drop = cw_pdmenu(butbase,desc,/return_index, $
           uvalue = {object:self,method:'selectCurve'})
    void = widget_label(butBase,value = '')
    groupSlider = widget_slider(butbase,value = 1,min = 1,max = 100, $
                  title = 'Group selection', $
                  uvalue = {object:self,method:'selectGroup'})

    self.modify = widget_button(butbase,value = 'Modify fit parameters', $
                  uvalue = {object:self,method:'parameterInfo'})
    bsize = 20
    ;self.modify = cw_color_button(ctrlbase,/row,value = 'Modify fit parameters', $
    ;              uvalue = {object:self,method:'parameterInfo'},/green,button_size = bsize)
    ;void = cw_color_button(butbase,/row,value = 'Clear current curves', $
    ;       uvalue = {object:self,method:'clearCurrentCurves'},/red,button_size = bsize)
    void = widget_button(butbase,value = 'Clear current curves', $
           uvalue = {object:self,method:'clearCurrentCurves'})
    ;void = cw_color_button(butbase,/row,value = 'Clear all curves', $
    ;       uvalue = {object:self,method:'clearAllCurves'},/red,button_size = bsize)
    void = widget_button(butbase,value = 'Clear all curves', $
           uvalue = {object:self,method:'clearAllCurves'})
    ;void = cw_color_button(butbase,/row,value = 'Remove selected curve', $
    ;       uvalue = {object:self,method:'remSelCurve'},/red,button_size = bsize)
    void = widget_button(butbase,value = 'Remove selected curve', $
           uvalue = {object:self,method:'remSelCurve'})

    self.curveSlider = widget_slider(butbase,value = 1, $
                       min = 1,max = 2,title = 'Curve selection', $
                       uvalue = {object:self,method:'sliderCurveSel'})

    ;void = widget_label(ctrlbaseFit,value = '')

    ctrlbaseFit = widget_base(ctrlbase,/col,/frame)
    void = widget_button(ctrlbaseFit,value = 'Fit current group', $
           uvalue = {object:self,method:'fitOneGroup'})
    ;void = cw_color_button(ctrlbase,/row,value = 'Fit current group', $
    ;       uvalue = {object:self,method:'fitOneGroup'},/green,button_size = bsize)
    void = widget_button(ctrlbaseFit,value = 'Fit all groups', $
           uvalue = {object:self,method:'fitAllGroups'})
    ;void = cw_color_button(ctrlbase,/row,value = 'Fit all groups', $
    ;       uvalue = {object:self,method:'fitAllGroups'},/green,button_size = bsize)
    self.interrupt = widget_button(ctrlbaseFit,value = 'Interrupt fit',sensitive = 0)

    self.groupSlider = groupSlider
    self.groupField = cw_field(ctrlbaseFit,/col,value = 1,/string, $
                      title = 'Groups to fit')
    self.fitStatField = cw_field(ctrlbaseFit,/col,value = self.fitStatus[0],$
                        title = 'Fitting status',/string,/noedit)

    ctrlbaseFitonfo = widget_base(ctrlbase,/col,/frame)
    void = widget_button(ctrlbaseFitonfo,value = 'View CORR matrix', $
           uvalue = {object:self,method:'view_corr_matrix'})
    void = widget_button(ctrlbaseFitonfo,value = 'Display fit parameters', $
           uvalue = {object:self,method:'displayFitParameters'})

    void = widget_button(ctrlbaseFitonfo,value = 'Plot fit parameter', $
           uvalue = {object:self,method:'plotFitParameter'})
    void = widget_button(ctrlbaseFitonfo,value = 'Plot EISF', $
           uvalue = {object:self,method:'plotEISF'})


    ;ctrlbaseModData = widget_base(ctrlbase,/col,/frame)
    ;ctrlbaseModData1 = widget_base(ctrlbaseModData,/row)
    ;void = widget_button(ctrlbaseModData1,value = 'Rebin data', $
    ;       uvalue = {object:self,method:'rebinData'})
    ;exclTT = 'Crop data (alter independent axis limits)'
    ;void = widget_button(ctrlbaseModData1,value = 'Crop data', $
    ;       uvalue = {object:self,method:'cropData'},tooltip=exclTT)
    ;;void = widget_button(ctrlbase1,value = 'Excl data', $
    ;;       uvalue = {object:self,method:'excludeData'},tooltip=exclTT)
    ;void = widget_button(ctrlbaseModData,value = 'Restore original data', $
    ;       uvalue = {object:self,method:'rebinRestore'})

    mc_base = widget_base(ctrlbase,/frame,/col)
    self.ndata_field = cw_field(mc_base,/col,value = strtrim(string(self.ndata),2), $
       title = '# of MC data sets')
    if !version.release gt 6.0 then begin
       tooltip = 'Perform Bootstrap Monte-Carlo Error Estimate'
       void = widget_button(mc_base,value = 'Monte-Carlo error estimate', $
              uvalue = {object:self,method:'mc_estimate'},tooltip = tooltip)
    endif else begin
       void = widget_button(mc_base,value = 'Monte-Carlo error estimate', $
              uvalue = {object:self,method:'mc_estimate'})
    endelse
    dispBase = widget_base(tlb,/col)
    self.dispBase = dispBase

    datxsize = 500 & datysize = 400
    resxsize = 500 & resysize = 200
    self.winratio = float(datysize/resysize)
    self.datwin = widget_draw(dispBase,xsize = datxsize,ysize = datysize,$
                  /button_events,uvalue = {object:self,method:'drawEvents'})
    self.reswin = widget_draw(dispBase,xsize = resxsize,ysize = resysize)

    self.infoBase = widget_base(tlb,/col)
    if !d.name eq 'WIN' then begin
      thisFont = "Comic Sans MS*16"
      self.info = widget_text(self.infoBase,font = thisFont, value = '', $
                  xsize = 40,ysize = 20,/scroll)
    endif else begin
      self.info = widget_text(self.infoBase,value = '', $
                  xsize = 40,ysize = 20,/scroll)
    endelse

    ; Now create a base for the HTML log controls
    logBase = widget_base(self.infoBase,/frame,/col)
    void = widget_label(logBase,value = 'HTML Log Controls')
    self.logBase = logBase
    self.newHTML = widget_button(logBase,value = 'Create new HTML log file', $
           uvalue = {object:self,method:'newHTMLFile'})
    self.existingHTML = widget_button(logBase,value = 'Open existing HTML log file', $
           uvalue = {object:self,method:'existingHTMLFile'})
    self.commentHTML = widget_button(logBase,value = 'Enter comment', $
           uvalue = {object:self,method:'logComment'},sensitive = 0)
    self.plotHTML = widget_button(logBase,value = 'Add plot to log', $
           uvalue = {object:self,method:'logAddPlot'},sensitive = 0)
    self.closeHTML = widget_button(logBase,value = 'Close HTML log file', $
           uvalue = {object:self,method:'closeHTMLFile'},sensitive = 0)

    void = widget_label(logBase,value = 'Log file status:')
    self.logFileStatus = widget_text(logBase,value = 'closed')
    void = widget_label(logBase,value = 'Log file name')
    self.logFileDisplay = widget_text(logBase,value = self.logFile)

    ; Center the interface in the screen
    ;geom = widget_info(self.tlb,/geometry)
    ;device,get_screen_size = sz
    ;sx = sz[0] & sy = sz[1]
    ;xoff = fix(0.5*(sx-geom.xsize))
    ;yoff = fix(0.5*(sy-geom.ysize))
    ;widget_control,self.tlb,xoffset = xoff,yoffset = yoff
    centertlb,self.tlb
    widget_control,tlb,/realize

    widget_control,self.datwin,get_value = datVis
    self.datVis = datVis
    widget_control,self.reswin,get_value = resVis
    self.resVis = resVis

    window,/free,/pixmap,xsize = datxsize,ysize = datysize
    self.datPix = !d.window
    window,/free,/pixmap,xsize = resxsize,ysize = resysize
    self.resPix = !d.window

    widget_control,tlb,set_uvalue = self

    ;LRK 032907
    defsysv,'!dave_e_window',exists=runningdave ;USED IN dave_set_focus
    if runningdave ne 0 then begin
        ret = dave_set_focus(self.tlb)
    endif;runningdave

    xmanager,'opan::createWidgets',self.tlb,event_handler = 'opanEvents',$
             cleanup = 'opanCleanup', /no_block

    return
end;opan::createWidgets
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
pro opan::niceOutput,event = event,ps_out = ps_out
    ; First let's position the plot at the top of the page
    ;ysize = 700
    ;xsize = fix(8.5*ysize/11.0)
    ;window,/free,xsize = xsize,ysize = ysize
    if n_elements(ps_out) eq 0 then ps_out = 0
    deltay = 0.20
    yreso = 0.25 & yresf = 0.40
    ydato = 0.45 & ydatf = 0.75
    pres = [0.15,yreso+deltay,0.9,yresf+deltay]
    pdat = [0.15,ydato+deltay,0.9,ydatf+deltay]
    self->plotresiduals,position = pres,ps_out = ps_out
    self->displaydata,position = pdat,/noerase,ps_out = ps_out

    ; Now annotate with the fit results
    widget_control,self.groupSlider,get_value = val
    val = fix(val[0])-1
    datSize = size(*self.dataPtr)
    if datSize[0] eq 1 then val = 0
    oc = (*self.ocurveGroup)[val]
    oc->displayparms,output = output
    chsize = 0.75
    nlines = n_elements(output)
    if nlines eq 0 then return
    if nlines lt 30 then begin
      ystart = 0.05 & yend = ydato-ystart
      dy = yend-ystart
      step = dy/30.0
      xstart = 0.05
      ypos = ystart+step*findgen(nlines)
      for i = 0,nlines-1 do begin
        xyouts,xstart,yend-ypos[i],output[i],/normal,charsize = chsize
      endfor
    endif
    if (nlines gt 29) and (nlines lt 59) then begin
      ; Print the first 30 lines
      ystart = 0.05 & yend = ydato-ystart
      dy = yend-ystart
      step = dy/30.0
      xstart = 0.05
      ypos = ystart+step*findgen(30)
      for i = 0,29 do begin
        xyouts,xstart,yend-ypos[i],output[i],/normal,charsize = chsize
      endfor
      ; Print the remainder
      ypos = ystart+step*findgen(30)
      ystart = 0.05 & yend = ydato-ystart
      xstart = 0.50
      ypos = ystart+step*findgen(30)
      count = 0
      for i = 30,nlines-1 do begin
        xyouts,xstart,yend-ypos[count],output[i],/normal,charsize = chsize
        count = count + 1
      endfor
    endif
    return
end;opan::niceOutput
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
pro opan::print2jpeg,event = event
    if n_elements(*self.dataPtr) eq 0 then return
    self.jpeg = 1
    thisDevice = !d.name
    h = 11.0 & w = 8.0 & aspect = h/w
    xsize = 600 & ysize = fix(aspect*xsize)
    window,/free,/pixmap,xsize = xsize,ysize = ysize
    winPix = !d.window
    self->niceOutput,event = event

    device,get_visual_depth = thisDepth
    if thisDepth eq 8 then begin
      tvlct,r,g,b,/get
      image2d = tvrd()
      s = size(image2d,/dimensions)
      image24 = bytarr(3,s[0],s[1])
      tvlct,r,g,b,/get
      image24[0,*,*] = r[image2d]
      image24[1,*,*] = g[image2d]
      image24[2,*,*] = b[image2d]
    endif
    if thisDepth gt 8 then begin
      device,decomposed = 1
      image24=tvrd(true = 1)
    endif
    wdelete,winPix

    myFileName = self.printFilename
    ppos = strpos(myFileName,'.')
    filename = strmid(myFileName,0,ppos)
    myFile = filename+'.jpg'

    thisPath = self.workDir
    filename = DIALOG_PICKFILE(dialog_parent = event.top,$
                               title = 'Enter output jpeg file name',$
                               /write,filter = '*.jpg',$
                               path = thisPath, $
                               file = myFile)

    if (filename eq '') or (filename eq ' ') then return
    s = Size(image24, /Dimensions)
    newx = Round(300.0 * s[1] / 72)
    newy = Round(300.0 * s[2] / 72)

    highResImage = Congrid(image24, 3, newx, newy, /Interp)

    write_jpeg,filename,255-highResImage,true = 1,quality = 100
    Set_Plot, thisDevice
    self.jpeg = 0

    self->refresh
    ;wset,self.resPix
    ;self->plotResiduals
    ;wset,self.resVis
    ;device,copy = [0,0,!d.x_size,!d.y_size,0,0,self.resPix]

    ;wset,self.datPix
    ;self->displayData
    ;wset,self.datVis
    ;device,copy = [0,0,!d.x_size,!d.y_size,0,0,self.datPix]

    msg = 'Output save in: '+filename
    ok = dialog_message(/info,msg,dialog_parent=event.top)

    return
end;opan::print2jpeg
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
pro opan::print2ps,event = event
    if n_elements(*self.dataPtr) eq 0 then return

    myFileName = self.printFilename
    ppos = strpos(myFileName,'.')
    filename = strmid(myFileName,0,ppos)

    myFile = filename+'.ps'
    filename = dialog_pickfile(dialog_parent = event.top, filter = '*.ps', $
                           title = 'Type in name of output postscript file', $
                           path = self.workDir, get_path = outPath,         $
                           file = myFile)

    if n_elements(filename) eq 0 or filename eq '' then return
    file = file_basename(filename)

    keywords = PSConfig(Cancel=cancelled,group_leader = event.top,$
               filename = file,color = 0,xsize = 8.0,ysize = 11.0, $
               directory = outPath,xoff = 0.0,yoff = 0.0)

    IF cancelled THEN RETURN
    self.workDir = outPath

    thisDevice = !D.Name
    Set_Plot, 'PS'
    Device, _Extra=keywords

    self->niceOutput,event = event,ps_out = 1

    Device, /Close_File
    Set_Plot, thisDevice
    msg = 'Output save in: '+filename
    ok = dialog_message(/info,msg,dialog_parent=event.top)

    return
end;opan::print2ps


;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
; Added: R Tumanjong Azuah. Jan 13, 06
pro opan::print2Printer, event=event

    if n_elements(*self.dataPtr) eq 0 then return

    okay = dialog_printersetup(dialog_parent=event.top)
    if (~okay) then return

    keywords = PSWindow(/printer,fudge=0.25)
    if (keywords.yoffset gt keywords.ysize) then begin
        tmp = keywords.ysize
        keywords.ysize = keywords.yoffset
        keywords.yoffset = tmp
    endif

    oldDevice = !D.name
    set_plot, 'PRINTER'
    device, _Extra=keywords

    self->niceOutput,event = event, ps_out = 0

    device, /close_document

    set_plot, oldDevice

    return
end;opan::print2Printer

;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
;function opan::getNotifyIds
;return,*self.notifyIdPtr
;end
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
function opan::getNotifyIds
    return,*self.notifyIdPtr
end;opan::getNotifyIds
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
function opan::init, group_leader = group_leader, $
            notifyId = notifyId, $
            davePtr = davePtr, $
            mydata = data, $
            mymask = mask,$ ;ALLOW USER TO ENTER A MASK HERE.
            error = error, $
            xvalues = xvalues, $
            yvalues = yvalues, $
            xtitle = xtitle, $
            ytitle = ytitle, $
            ztitle = ztitle, $
            header = header, $
            title = title, $
            workDir = workDir, $
            dataDir = dataDir, $
            ob_reg = ob_reg

   tvlct,r,g,b,/get
    self.macro_file = ''
    self.rPtr = ptr_new(r)
    self.gPtr = ptr_new(g)
    self.bPtr = ptr_new(b)
    self.color_ptr = ptr_new(/allocate_heap)
    device,get_decomposed=old_dc,decomposed = 1
    colors = hfbs_GetColor(/Load);, Start=1)
    *self.color_ptr = colors
    device, decomposed=old_dc

    self.ndata = 100

    if n_elements(ob_reg) ne 0 then begin
       self.ob_reg = ob_reg
       self.reg_present = 1
       self.ob_reg->add,self
    endif else begin
       self.ob_reg = obj_new('object_registry')
       self.reg_present = 0
       self.ob_reg->add,self
    endelse
    if n_elements(group_leader) eq 0 then group_leader = (-1L)
    cd,current = curDir
    if n_elements(workDir) eq 0 then self.workDir = curDir else self.workDir = workDir
    if n_elements(dataDir) eq 0 then self.dataDir = '' else self.dataDir = dataDir

    self.otable = obj_new('table_lookup')
    self.jpeg = 0
    self.iteration = 0L
    self.resPtr = ptr_new(/allocate_heap)
    self.oneResPtr = ptr_new(/allocate_heap)
    self.xtabPtr = ptr_new(/allocate_heap)
    self.ytabPtr = ptr_new(/allocate_heap)
    self.btabPtr = ptr_new(/allocate_heap)
    self.ttabPtr = ptr_new(/allocate_heap)
    self.ktablePtr = ptr_new(/allocate_heap)
    self.davePtr = ptr_new(/allocate_heap)
    self.notifyIdPtr = ptr_new(/allocate_heap)
    self.headerPtr = ptr_new(/allocate_heap)

    self.maskPtr = ptr_new(/allocate_heap)
    self.dataPtr = ptr_new(/allocate_heap)
    self.errorPtr = ptr_new(/allocate_heap)
    self.xvalsPtr = ptr_new(/allocate_heap)
    self.yvalsPtr = ptr_new(/allocate_heap)

    self.omaskPtr = ptr_new(/allocate_heap)
    self.odataPtr = ptr_new(/allocate_heap)
    self.oresPtr = ptr_new(/allocate_heap)
    self.oerrorPtr = ptr_new(/allocate_heap)
    self.oxvalsPtr = ptr_new(/allocate_heap)
    self.oyvalsPtr = ptr_new(/allocate_heap)

    self.resxPtr = ptr_new(/allocate_heap)
    self.resyPtr = ptr_new(/allocate_heap)
    self.datxPtr = ptr_new(/allocate_heap)
    self.datyPtr = ptr_new(/allocate_heap)
    self.goodParmPtr = ptr_new(/allocate_heap)
    self.curvenamesPtr = ptr_new(/allocate_heap)
    self.ocurveGroup = ptr_new(/allocate_heap)
    self.grpArrayPtr = ptr_new(/allocate_heap)
    self.status = 5
    self.fitloop = 0
    self.duration = 1.e-3
    self.curIndex = 0
    self.info = 0L
    self.groupField = 0L
    self.fitStatus = ['Resting', 'Fitting', 'Paused']
    self.fitStatField = 0L
    self.dataPath = ''

    self.printFileName = ''
    self.logStringPtr = ptr_new(/allocate_heap)
    self.logFile = ''
    self.logDirectory = ''
    self.tasFilePtr = ptr_new(/allocate_heap)

    self.xtitle = 'x'
    self.ytitle = 'y'
    self.ztitle = 'z'

    self.prefs = ptr_new({preferences, $
                          same:1, xenforce:0,yenforce:0, $
                          xmin:0.0,xmax:1.0,ymin:0.0,ymax:1.0, $
                          xfitlo:0.0,xfithi:1.0,initGuesses:0,tied:0, $
                          xlabel:self.xtitle,ylabel:self.ytitle, $
                          maxIter:200})
    self.fitgroup = 0
    self.addcurve = 0
    self.firstPoint = [0,0]
    self.secondPoint = [0,0]
    self.ocurrentPtr = ptr_new(/allocate_heap)
    self.taspathptr = ptr_new(/allocate_heap)
    self.autoscale = 1
    self.xbox = [0.0,1.0]
    self.xrange = [0.0,1.0]
    self.ybox = [0.0,1.0]
    self.yrange = [0.0,1.0]

    self.title = 'Data'
    self.filename = ''

    if n_elements(notifyId) ne 0 then *self.notifyIdPtr = notifyId
    self.group_leader = group_leader

    self->createWidgets
    ; Commented out the following lines to eliminated table loading upon
    ; program initialization.  Only done on an "as-needed" basis now with
    ; a new object class instantiation (TABLE_LOOKUP__DEFINE).
    ;
    ;msg = 'Reading in lookup tables'
    ;self->flashMessage_create,msg,base;,event = event
    ;pan_readKTable,ktablePtr
    ;self->flashMessage_destroy,base;,event = event
    ;widget_control,self.info,set_value = 'Lookup tables loaded'
    ;*self.ktablePtr = *ktablePtr
    ;ptr_free,ktablePtr


    if n_elements(data) ne 0 then begin
      datasize = size(data)

      *self.dataPtr = data


      ;STORE MASK IF ENTERED.  IF NOT CREATE ONE.
      if n_elements(mask) ne 0 then begin
          if n_elements(mask) ne n_elements(data) then begin
              ;ASSUMED TO BE IN COMPRESSED bytes FORMAT
              nc = (size(data))[1]
              nr = (size(data))[2]

              *self.maskPtr = bytes2bits(mask,nc,nr)
              *self.omaskPtr = bytes2bits(mask,nc,nr)
          endif else begin
              ;IN ARRAY OF 1/0 FORMAT.
              *self.maskPtr = mask
              *self.omaskPtr = mask
          endelse
      endif else begin
          ;NO MASK ENTERED SO CREATE ONE.
          *self.maskPtr = byte(0*data + 1)
          *self.omaskPtr = byte(0*data + 1)
      endelse

      if n_elements(error) ne 0 then *self.errorPtr = error
      if n_elements(header) ne 0 then *self.headerPtr = header
      if n_elements(xvalues) ne 0 then begin
        *self.xvalsPtr = xvalues
      endif else begin
        if datasize[0] eq 1 then begin
            *self.xvalsPtr = dindgen(datasize)
        endif else begin
            *self.xvalsPtr = dindgen(datasize[1])#(1+fltarr(datasize[2]))
        endelse
      endelse


      ;EDIT THE NEXT LINE SO THAT VALUES ARE APPLIED TO THE DATA.
      if n_elements(yvalues) ne 0 then begin
        *self.yvalsPtr = yvalues
      endif else begin
        if datasize[0] eq 1 then begin
            *self.yvalsPtr = dblarr(datasize)
        endif else begin
            *self.yvalsPtr = (1+fltarr(datasize[0]))#dindgen(datasize[2])
        endelse
      endelse

      if n_elements(ztitle) ne 0 then begin
        self.ztitle = ztitle
        (*self.prefs).ylabel = ztitle
      endif
      if n_elements(xtitle) ne 0 then begin
        self.xtitle = xtitle
        (*self.prefs).xlabel = xtitle
      endif
      if n_elements(ytitle) ne 0 then begin
        self.ytitle = ytitle

        (*self.prefs).ylabel = ytitle
      endif
      if n_elements(title) ne 0 then self.title = title
      self->initNewDataObjects, event=event
    ;  self->scaleKtable
    ;  wset,self.datPix
    ;  self->displayData
    ;  wset,self.datVis
    ;  device,copy = [0,0,!d.x_size,!d.y_size,0,0,self.datPix]
      self->refresh
    endif

    if n_elements(davePtr) ne 0 then begin
      *self.davePtr = *davePtr
      self->stuffDave,inFromDave = 1
      self->initNewDataObjects, event=event

    ;  self->scaleKtable
    ;  wset,self.datPix
    ;  self->displayData
    ;  wset,self.datVis
    ;  device,copy = [0,0,!d.x_size,!d.y_size,0,0,self.datPix]

      self->refresh
    endif

    return,1
end;opan::init
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
pro opan__define

    define =    {opan, $
           ob_reg:obj_new(),   $
           reg_present:0,     $
           dataDir:'', $
           workDir:'', $
           printFileName:'', $
           macro_file:'',   $
           color_ptr:ptr_new(), $
           dataPath:'', $
           jpeg:0, $
           davePtr:ptr_new(), $
           tasFilePtr:ptr_new(), $
           notifyIdPtr:ptr_new(), $
           headerPtr:ptr_new(), $
           prefs:ptr_new(), $
           fitgroup:0, $
           grpArrayPtr:ptr_new(), $
           curIndex:0, $
           goodParmPtr:ptr_new(), $
           ndata:0L,              $
           ndata_field:0L,        $
           iteration:0L, $
           filename:'', $
           xtitle:'', $
           ytitle:'', $
           ztitle:'', $
           title:'', $
           xunits:'', $
           yunits:'', $
           group_leader:0L, $
           fitStatus:strarr(3), $
           fitStatField:0L, $
           modify:0L, $
           groupField:0L, $
           interrupt:0L, $
           info:0L, $
           curveSlider:0L, $
           ocurveGroup:ptr_new(), $
           ocurrentPtr:ptr_new(), $
           addcurve:0, $
           curvenamesPtr:ptr_new(), $

           maskPtr:ptr_new(),$ ;SHOULD THERE BE AN ORIGINAL MASK AND A CURRENT MASK OR SHOULD WE
                               ;RELY ON THE DAVE PTR FOR THE ORIGINAL, SINCE WE STORE THE WHOLE DAVE PTR HERE????????
                               ;::stuffDave IS THE ENTRY POINT.


           dataPtr:ptr_new(), $
           errorPtr:ptr_new(), $
           xvalsPtr:ptr_new(), $
           yvalsPtr:ptr_new(), $
           resPtr:ptr_new(), $

           omaskPtr:ptr_new(),$
           odataPtr:ptr_new(), $
           oerrorPtr:ptr_new(), $
           oxvalsPtr:ptr_new(), $
           oyvalsPtr:ptr_new(), $
           oresPtr:ptr_new(), $

           oneResPtr:ptr_new(), $
           ktablePtr:ptr_new(), $
           xtabPtr:ptr_new(), $
           ytabPtr:ptr_new(), $
           btabPtr:ptr_new(), $
           ttabPtr:ptr_new(), $

           autoscale:0, $
           mouse:0B, $
           xrange:fltarr(2), $
           yrange:fltarr(2), $
           xbox:fltarr(2), $
           ybox:fltarr(2), $
           firstPoint:intarr(2), $
           secondPoint:intarr(2), $

           datWin:0L, $
           datVis:0L, $
           datPix:0L, $
           datxPtr:ptr_new(), $
           datyPtr:ptr_new(), $

           newHTML:0L, $
           existingHTML:0L, $
           commentHTML:0L, $
           plotHTML:0L, $
           closeHTML:0L, $
           logStringPtr:ptr_new(), $
           logDirectory:'', $
           logFile:'', $
           logBase:0L, $
           logFileStatus:0L, $
           logFileDisplay:0L, $

           resWin:0L, $
           resVis:0L, $
           resPix:0L, $
           resxPtr:ptr_new(), $
           resyPtr:ptr_new(), $

           winratio:0., $
           groupSlider:0L, $
           tlb:0L, $
           ctrlbase:0L, $
           dispBase:0L, $
           infoBase:0L, $
           duration:0.0, $
           status:0, $
           fitloop:0, $
           rPtr:ptr_new(), $
           gPtr:ptr_new(), $
           bPtr:ptr_new(), $
           tasPathPtr:ptr_new(),  $
           otable:obj_new(),   $
           timerID:0L}

end;opan__define
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
pro pan
    o = obj_new('opan')
end;pan
