# Data Viewer

import xasinput
from spdirvars import *
from spglobalfuncs import *
from Numeric import *
from Tkinter import *
import Pmw
import Tix
import tkFileDialog
import tkMessageBox
import tkSimpleDialog
import os
import math
from string import *
import MLab
from Scientific.Functions.LeastSquares import leastSquaresFit

#root=Tix.Tk()
#root.title("SamView")
#Pmw.initialise(root)
if os.name=='nt':os.sep='/'
filepath=os.getcwd()+os.sep
#global lastsavedir,lastreaddir
#lastsavedir=''
#lastreaddir=''


#deatime model   SCA=kappa*ICR*exp(-ICR*tau) tau in usecs
def dteqn(pars,point):
    #return pars[0]*point*exp(-pars[1]/point)
    return pars[2]+pars[0]*point*exp(-pars[1]*point*1e-6)
   

###############################################################
##
## Main Program Class
##
###############################################################

class Main:
    global starte,ende
    global edge
    global lastsavedir,lastreaddir
    def __init__(self,master,root):
        self.vwww=vwww=master
        self.root=root
        #define scrollable frame
        if root.winfo_screenheight()<860:
            self.sf=Pmw.ScrolledFrame(vwww,usehullsize=1,hull_width=800,hull_height=720)
            self.vw=vw=self.sf.interior()
            self.sf.pack(side=TOP)
        else:
            self.vw=vw=vwww
        #GUI for data viewer window
        menubar=Pmw.MenuBar(vw)
        #file menu
        menubar.addmenu('File','')
        menubar.addmenuitem('File','command',label='Open Dataset',command=self.loaddatafile)
        menubar.addmenuitem('File','command',label='Open Multiple Datasets',command=self.loadmultdatafile)
        menubar.addmenuitem('File','separator')    
        menubar.addmenuitem('File','command',label='Clear Datasets',command=self.clearfilelist)
        menubar.addmenuitem('File','separator')
        menubar.addmenuitem('File','command',label='Edit Default Directories',command=self.callchangedefdirs)
        menubar.addmenuitem('File','separator')
        menubar.addmenuitem('File','command',label='Close',command=self.closemod)        
        menubar.addmenuitem('File','command',label='Quit',command=self.root.quit)
        menubar.addmenu('Copy','')
        menubar.addmenuitem('Copy','command',label='Copy Plot Data to Clipboard',command=self.graphtextport) 
        menubar.addmenu('Save','')
        menubar.addmenuitem('Save','command',label='Averaged Spectra',command=self.averagescans)
        menubar.addmenu('CSXAS','')
        menubar.addmenuitem('CSXAS','command',label='Change Data Spacing',command=self.changespacing)
        menubar.addmenu('Comments','')    
        menubar.addmenuitem('Comments','command',label='View File Comments',command=self.viewcomments)
        menubar.addmenu('FluoChans','')
        menubar.addmenuitem('FluoChans','command',label='Set all fluo channels to current',command=self.setallfluochannels)
        menubar.addmenuitem('FluoChans','command',label='Reset all fluo channels',command=self.resetallfluochannels)
        menubar.addmenu('Gains','')
        menubar.addmenuitem('Gains','command',label='Change I0 Gain',command=self.editi0gain)
        menubar.addmenu('Help','',side=RIGHT)
        menubar.addmenuitem('Help','command',label='About SixPack',command=self.callprogramabout)
        menubar.grid(row=0,columnspan=25,sticky=W+E)
        #Add project manager window
        pmwin=Frame(vw,relief=SUNKEN,bd=2)
        l=Label(pmwin,text='Project Files',relief=RAISED,bd=2)
        l.pack(side=TOP,fill=X,padx=2,pady=4)
        act=Frame(pmwin)
        w=16
        b=Button(act,text="Add File",width=w,command=self.loaddatafile,bg='steel blue',fg='white')
        b.pack(side=LEFT,padx=2,pady=2)
        b=Button(act,text="Add Many Files",width=w,command=self.loadmultdatafile,bg='darkblue',fg='white')
        b.pack(side=LEFT,padx=2,pady=2)
        act.pack(side=TOP,fill=X,padx=2)
        act=Frame(pmwin)
        b=Button(act,text="Remove File",width=w,command=self.removefile,bg='red',fg='white')
        b.pack(side=LEFT,padx=2,pady=2)
        b=Button(act,text="Clear All",width=w,command=self.clearfilelist,bg='brown',fg='white')
        b.pack(side=LEFT,padx=2,pady=2)    
        act.pack(side=TOP,fill=X,padx=2)
        #Add btree
        tree=Tix.ScrolledHList(pmwin)
        self.phlist=tree.hlist
        self.phlist.config(separator='-',width=25, drawbranch=0, indent=10,itemtype=Tix.TEXT,browsecmd=self.selectfile)
        tree.pack(side=TOP,fill=BOTH,expand=1,padx=2,pady=2)
        #Add average button
        b=Button(pmwin,text="Average Scans",command=self.averagescans,bg='darkgreen',fg='snow')
        b.pack(side=BOTTOM,fill=X,padx=2,pady=2)
        pmwin.grid(row=1,column=0,columnspan=5,rowspan=15,sticky=W+E+N+S)
        #Add graph window
        grwin=Frame(vw,relief=SUNKEN,bd=2)
        self.graph=Pmw.Blt.Graph(grwin,plotbackground='white')
        self.graph.bind(sequence="<ButtonPress>",   func=self.mouseDown)
        self.graph.bind(sequence="<ButtonRelease>", func=self.mouseUp  )
        self.graph.bind(sequence="<Motion>", func=self.coordreport)
        self.graph.pack(expand=1,fill='both')
        grwin.grid(row=1,column=5,columnspan=20,rowspan=15,sticky=W+E+N+S)
        #Add E0 Calibration Window
        e0win=Frame(vw,relief=SUNKEN,bd=2)
        l=Label(e0win,text='E0 Calibration',relief=RAISED,bd=2)
        l.pack(side=TOP,fill=X,padx=2,pady=2)
        f1=Frame(e0win)
        f1.pack(side=TOP,padx=5,pady=2)
        b=Button(f1,text='prev',bitmap="@"+filepath+"xbms"+os.sep+"previous.xbm")
        b.bind("<Button-1>",self.e0moveline)
        b.pack(side=LEFT,padx=2,pady=5)
        b=Button(f1,text="Find Data E0",width=20,command=self.findenot,bg='darkblue',fg='snow')
        b.pack(side=LEFT,padx=5,pady=5)
        b=Button(f1,text='next',bitmap="@"+filepath+"xbms"+os.sep+"next.xbm")
        b.bind("<Button-1>",self.e0moveline)
        b.pack(side=LEFT,padx=2,pady=5)
        self.e0app=Pmw.EntryField(e0win,labelpos='w',label_text='Apparent: ',value='0',validate='real')
        self.e0act=Pmw.EntryField(e0win,labelpos='w',label_text='Actual: ',value='0',validate='real',command=self.enotcalcshift)
        self.e0shift=Pmw.EntryField(e0win,labelpos='w',label_text='Shift: ',value='0',validate='real')
        e0fields=(self.e0app,self.e0act,self.e0shift)
        for fld in e0fields:
            fld.pack(side=TOP,fill=X,padx=10,pady=2)
        Pmw.alignlabels(e0fields)
        b=Button(e0win,text="Apply Shift to Data",width=20,command=self.enotapplyshift,bg='brown',fg='snow')
        b.pack(side=TOP,padx=2,pady=5)
        e0win.grid(row=16,column=0,columnspan=5,rowspan=6,sticky=W+E+N+S)    
        #Add Deatime Correction Window
        dtwin=Frame(vw,relief=SUNKEN,bd=2)
        l=Label(dtwin,text='Deadtime Corrections',relief=RAISED,bd=2)
        l.pack(side=TOP,fill=X,padx=2,pady=2)
        self.dodt=IntVar()
        cb=Checkbutton(dtwin,text="Do the deatime correction?",variable=self.dodt,anchor=W,command=self.dodeadtime)
        cb.pack(side=TOP,padx=2,pady=2)
        self.dtfile=Tix.FileEntry(dtwin,label="Deadtime File: ",dialogtype="tk_getOpenFile")
        self.dtfile.pack(side=TOP,padx=2,pady=2)
        b=Button(dtwin,text="New DT file",width=20,command=self.getnewdtfile,bg='darkseagreen4',fg='ivory')
        b.pack(side=TOP,padx=2,pady=5)
        dtwin.grid(row=22,column=0,columnspan=5,rowspan=6,sticky=W+E+N+S)    
        #Add Plot control window
        plotwin=Frame(vw,relief=SUNKEN,bd=2)
        l=Label(plotwin,text='Plot Control',relief=RAISED,bd=2)
        l.pack(side=TOP,fill=X,padx=2,pady=2)
        lhs=Frame(plotwin)
        rhs=Frame(plotwin)
        lhs.pack(side=LEFT,fill=BOTH,padx=1,pady=1)
        rhs.pack(side=LEFT,fill=BOTH,padx=1,pady=1)
        self.plotlist=('muF','muT1','muT2','Column')
        self.plottype=Pmw.ScrolledListBox(lhs,items=self.plotlist,labelpos=N,label_text='Plot Type',
                                        listbox_height=4,selectioncommand=self.selectnewplot,
                                        vscrollmode='static',listbox_exportselection=0)
        self.plottype.select_set(0)
        self.plottype.pack(side=TOP,fill=X,padx=2,pady=5)
        b=Button(lhs,text="Stack All Plots?",width=15,command=self.stackplot,bg='darkblue',fg='snow')
        b.pack(side=TOP,padx=2,pady=3)
        self.derivlist=('None','First','Second')
        self.deriv=Pmw.RadioSelect(lhs,labelpos=N,label_text='Derivative',buttontype='radiobutton',orient='vertical',pady=1)
        for but in self.derivlist:
            self.deriv.add(but)
        self.deriv.invoke('None')    
        self.deriv.pack(side=TOP,fill=X,padx=2,pady=30)      
        self.collist=('i0','i1','i2','iFsum','iFind','iFall','ICRind','ICRall')
        self.plotcol=Pmw.ScrolledListBox(rhs,items=self.collist,labelpos=N,label_text='Column Selection',
                                       listbox_height=6,selectioncommand=self.selectnewcolumn,
                                       vscrollmode='static',listbox_exportselection=0,
                                       listbox_selectbackground='grey',listbox_fg='grey')
        self.plotcol.select_set(0)
        self.plotcol.pack(side=TOP,fill=X,padx=2,pady=5)
        bb=Pmw.ButtonBox(rhs,orient='vertical',pady=5)
        bb.pack(side=TOP,padx=2,pady=20)
        bb.add("Replot",width=15,command=self.makeplot,bg='darkgreen',fg='ivory')
        bb.add("Rescale",width=15,command=self.rescaleplot,bg='brown',fg='ivory')
        self.smoothpts=Pmw.Counter(rhs,labelpos=N,label_text='# Pts to Smooth',entryfield_value=0,
                                   entryfield_validate={'validator':'integer','min':0},datatype='integer',
                                   entryfield_entry_width=2)
        self.smoothpts.pack(side=TOP,padx=2,pady=2)
        plotwin.grid(row=16,column=5,columnspan=10,rowspan=12,sticky=W+E+N+S)    
        #Add Fluorescence control window
        flwin=Frame(vw,relief=SUNKEN,bd=2)
        l=Label(flwin,text='Fluorescence Channels',relief=RAISED,bd=2)
        l.pack(side=TOP,fill=X,padx=2,pady=2)
        tree=Tix.ScrolledHList(flwin)
        self.fhlist=tree.hlist
        self.fhlist.config(separator='-',width=25, drawbranch=1, indent=30,itemtype=Tix.TEXT,browsecmd=self.makeplot)
        tree.pack(side=TOP,fill=BOTH,expand=1,padx=2,pady=2)
        bb=Pmw.ButtonBox(flwin,orient='horizontal',pady=5)
        bb.pack(side=TOP,padx=2,pady=5)
        bb.add("Zero Sel. Chan.",width=15,command=self.deleteffchan,bg='darkorange4',fg='snow')
        bb.add("Reload Channels",width=15,command=self.restoreffchan,bg='goldenrod',fg='snow')
        flwin.grid(row=16,column=15,columnspan=5,rowspan=12,sticky=W+E+N+S)    
        #Status Bar
        self.status=Label(vw,text="",bd=2,relief=RAISED,anchor=W,fg='blue')
        self.status.grid(row=30,columnspan=15,sticky=W+E)
        setstatus(self.status,"Ready")
        self.xcoord=Label(vw,text="X=      ",bd=2,relief=RIDGE,anchor=W,fg='red')
        self.ycoord=Label(vw,text="Y=      ",bd=2,relief=RIDGE,anchor=W,fg='red')
        self.xcoord.bind("<Double-Button-1>",self.opencoordwin)
        self.ycoord.bind("<Double-Button-1>",self.opencoordwin)
        self.xcoord.grid(row=30,column=15,columnspan=2,sticky=W+E)
        self.ycoord.grid(row=30,column=17,columnspan=2,sticky=W+E)
        #Coordinates window
        self.coordwin=Pmw.Dialog(vw,title='SV Coord')
        self.winxcoord=Label(self.coordwin.interior(),text="X=      ",bd=2,relief=RIDGE,anchor=W,fg='red')
        self.winycoord=Label(self.coordwin.interior(),text="Y=      ",bd=2,relief=RIDGE,anchor=W,fg='red')
        self.winxcoord.pack(side=LEFT,fill=X,padx=2,pady=2)
        self.winycoord.pack(side=LEFT,fill=X,padx=2,pady=2)
        self.coordwin.iconname('SV Coord')
        self.coordwin.withdraw()        
        #init new vars
        self.datfiles=[]
        self.datvars={}
        self.ffchan={}
        self.icrchan={}
        self.dtcvar={}
        self.plotstk=0
        self.curmax=0
        self.maxima=[]
        self.zoomstack=[]
        self.fluochannelsremoved={}

    def opencoordwin(self,args):
        self.coordwin.deiconify()

    def closemod(self):
        self.root.deiconify()
        self.vw.destroy()

    def viewcomments(self):
        #get data
        cur=self.phlist.info_selection()
        if len(cur)!=0:
            #show box
            self.dialog.activate()
        
    def selectnewplot(self):
        cur=self.plottype.getcurselection()[0]
        if cur=='Column':
            #return defaults
            self.plotcol.configure(listbox_selectbackground='midnight blue',listbox_fg='black')
        else:
            #turn colors to "off"
            self.plotcol.configure(listbox_selectbackground='grey',listbox_fg='grey')
        self.rescaleplot()

    def selectnewcolumn(self):
        cur=self.plottype.getcurselection()[0]
        if cur=='Column':
            self.rescaleplot()
            
    def clearfilelist(self):
        #reset all
        xasinput.PsCLEAR()
        self.datfiles=[]
        self.fflist=[]
        self.datvars={}
        self.ffchan={}
        self.fluochannelsremoved={}
        self.phlist.delete_all()
        self.fhlist.delete_all()
        #clear graph
        glist=self.graph.element_names()
        if glist != ():
            for g in glist:
                self.graph.element_delete(g)        

    def removefile(self):
        #clear graph
        glist=self.graph.element_names()
        if glist != ():
            for g in glist:
                self.graph.element_delete(g)
        #get current selection
        cur=self.phlist.info_selection()
        if cur != ():
            cur=cur[0]            
            #remove all associated vars
            ind=self.datfiles.index(cur)
            self.datfiles.remove(cur)
            self.phlist.delete_entry(cur)
            del self.datvars[cur]
            del self.fluochannelsremoved[cur]
            #reselect
            if len(self.datfiles)==0:
                self.fhlist.delete_all()
            elif ind != 0:
                new=self.datfiles[ind-1]
                self.phlist.selection_set(new)
                self.selectfile()            
            else:
                new=self.datfiles[0]
                self.phlist.selection_set(new)
                self.selectfile()            

    def loadmultdatafile(self):
        global lastsavedir,lastreaddir
        self.multifd=Tix.ExFileSelectDialog(self.root)
        if lastreaddir!='':
            lastreaddir=replace(lastreaddir,'/','\\')            
            self.multifd.fsbox.configure(directory=lastreaddir)
        self.multifd.fsbox.filelist.listbox.configure(selectmode=MULTIPLE)
        #setup ok button...
        self.multifd.fsbox.ok.configure(command=self.getmultilist)        
        self.multifd.popup()

    def getmultilist(self):
        global lastsavedir,lastreaddir
        multfn=self.multifd.fsbox.filelist.listbox.curselection()
        multdlist=self.multifd.fsbox.filelist.listbox.get(0,END)
        curdir=self.multifd.fsbox.dir.entry.get()
        lastreaddir=curdir
        self.multifd.popdown()
        if multfn !=():
            for sel in multfn:
                curfil=multdlist[int(sel)]
                fulpath=curdir+os.sep+curfil
                #get file data
                f=xasinput.XASget(fulpath,self.vw)
                if len(f.eV)==0:return
                f.restore=tuple(reshape(f.iF,(-1,)))
                f.restoreshape=shape(f.iF)
                self.datfiles.append(curfil)
                self.datvars.update({curfil:f})
                self.fluochannelsremoved.update({curfil:[]})
                self.phlist.add(curfil,text=curfil,state=NORMAL)
                self.phlist.selection_clear()
                self.phlist.selection_set(curfil)
                #call selection routine
                self.selectfile()                
                
    def loaddatafile(self):
        global lastsavedir,lastreaddir
        infile=ask_for_file([("all files","*"),("data files","*.dat")],lastreaddir)
        if infile !='':
            indir=rfind(infile,os.sep)
            lastreaddir=infile[:indir]
            #get file data
            f=xasinput.XASget(infile,self.vw)
            if len(f.eV)==0:return
            f.restore=tuple(reshape(f.iF,(-1,)))
            f.restoreshape=shape(f.iF)
            #append lists/update tree            
            treefile=trimdir(infile)        
            self.datfiles.append(treefile)
            self.datvars.update({treefile:f})
            self.fluochannelsremoved.update({treefile:[]})
            self.phlist.add(treefile,text=treefile,state=NORMAL)
            self.phlist.selection_clear()
            self.phlist.selection_set(treefile)
            #call selection routine
            self.selectfile()

    def selectfile(self, *arg):
        #get data
        cur=self.phlist.info_selection()[0]
        dat=self.datvars.get(cur)
        #update status
        npts=len(dat.i0)
        setstatus(self.status,"File "+cur+" contains "+str(npts)+" data points")
        #comment box
        self.dialog=Pmw.TextDialog(self.vw,title='File Comments',defaultbutton=0,scrolledtext_usehullsize=1,
                                   scrolledtext_hull_width=500,scrolledtext_hull_height=100)
        self.dialog.withdraw()
        self.dialog.clear()
        if dat.type[0]=='S':
            if len(dat.comment)==6:
                for j in dat.comment:
                    self.dialog.insert('end',j)
            else:
                self.dialog.insert('end',dat.comment)
        else:
            self.dialog.insert('end','No comments available')
        #update fluobox
        #delete all children
        self.fhlist.delete_all()
        self.ffchan.clear()
        self.icrchan.clear()
        #add rootlevel
        self.fhlist.add(cur,text=cur+" SUM",state=NORMAL)
        #add children
        self.fflist=[]
        nfc=shape(dat.iF)
        if shape(nfc)[0]==1:
            #only one FF channel
            self.fhlist.add(cur+'-FF0',text='FF1',state=NORMAL)
            self.ffchan.update({cur+'-FF0':dat.iF})
            self.ffchan.update({cur:dat.iF})
            self.icrchan.update({cur:dat.ICR})
            self.icrchan.update({cur+'-FF0':dat.ICR})
            self.fflist.append('FF0')
        else:
            #multiple FF channels
            ncols=nfc[1]
            i=0
            while i<ncols:
                self.fflist.append('FF'+str(i+1))
                i=i+1
            i=0
            for ch in self.fflist:
                self.fhlist.add(cur+'-'+ch,text=ch,state=NORMAL)
                self.ffchan.update({cur+'-'+ch:dat.iF[:,i]})
                self.icrchan.update({cur+'-'+ch:dat.ICR[:,i]})
                i=i+1
            self.ffchan.update({cur:self.sumFFdata(dat.iF,dat.ICR,dat.rtc)})
        self.fhlist.selection_set(cur)
        #call plotting routine
        if self.plotstk!=-1:
            self.rescaleplot()

    def setallfluochannels(self):
        cur=self.phlist.info_selection()[0]
        masterlist=self.fluochannelsremoved.get(cur)
        for nextfil in self.datfiles:
            self.phlist.selection_clear()
            self.phlist.selection_set(nextfil)
            self.selectfile()
            #reset
            self.restoreffchan()
            #delete chans
            for fullkey in masterlist:
                goneind=rfind(fullkey,'-')
                goneend=fullkey[goneind:]
                gone=nextfil+goneend
                self.deletingchannelmain(gone,nextfil)
        self.phlist.selection_clear()
        self.phlist.selection_set(cur)
        self.selectfile()            

    def resetallfluochannels(self):
        cur=self.phlist.info_selection()[0]
        for nextfil in self.datfiles:
            self.phlist.selection_clear()
            self.phlist.selection_set(nextfil)
            self.selectfile()
            self.restoreffchan()
        self.phlist.selection_clear()
        self.phlist.selection_set(cur)
        self.selectfile()        

    def editi0gain(self):
        #get data
        cur=self.phlist.info_selection()[0]
        dat=self.datvars.get(cur)
        #get factor
        factor=tkSimpleDialog.askfloat('Gains','Multiply i0 by what factor?',parent=self.vw,initialvalue=1.0)
        dat.i0=dat.i0*factor
        self.selectfile()

    def deleteffchan(self):
        chdel=self.fhlist.info_selection()[0]
        cur=self.phlist.info_selection()[0]
        byebye=self.fluochannelsremoved.get(cur)
        byebye.append(chdel)
        self.fluochannelsremoved.update({cur:byebye})
        self.deletingchannelmain(chdel,cur)

    def deletingchannelmain(self,chdel,cur):        
        if chdel != cur:
            dat=self.datvars.get(cur)        
            #if dat.iF==dat.restore:print 'ok'
            ind=rfind(chdel,'F')+1
            cnum=int(chdel[ind:])-1
            #zero channel out
            z=zeros(shape(self.ffchan[chdel]),Float32)
            self.ffchan.update({chdel:z})
            #zero it in iF too
            npts=shape(dat.iF)[0]
            if shape(shape(dat.iF))[0] != 1:
                i=0
                while i<npts:
                    dat.iF[i,cnum]=0
                    i=i+1
                self.ffchan.update({cur:self.sumFFdata(dat.iF,dat.ICR,dat.rtc)})
            else:
                dat.iF=z
                self.ffchan.update({cur:z})
            #update lists
            #if dat.iF==dat.restore:print 'come again'
            self.datvars.update({cur:dat})
            #if dat.iF==dat.restore:print 'huh'
            #replot
            self.makeplot()
        
    def restoreffchan(self):
        cur=self.phlist.info_selection()[0]
        dat=self.datvars.get(cur)
        self.fluochannelsremoved.update({cur:[]})
        #if dat.iF==dat.restore: print 'what?'
        dat.iF=reshape(array(dat.restore),dat.restoreshape)
        self.selectfile()

    def rescaleplot(self):
        self.graph.xaxis_configure(min="",max="")
        self.graph.yaxis_configure(min="",max="")
        self.zoomstack=[]
        self.makeplot()

    def stackplot(self):
        self.plotstk=0
        #remember curent selection
        if self.phlist.info_selection()==():
            return
        if self.plottype.getcurselection()[0]=='Column':
            if self.plotcol.getcurselection()[0]=='iFall' or self.plotcol.getcurselection()[0]=='ICRall':
                return
        temp=self.phlist.info_selection()[0]
        #plot the first one
        #select first file
        self.phlist.selection_clear()
        self.phlist.selection_set(self.datfiles[0])
        self.selectfile()
        #plot the rest
        for nextfil in self.datfiles:
            if nextfil!=self.datfiles[0]:
                self.plotstk=self.plotstk+1
                self.phlist.selection_clear()
                self.phlist.selection_set(nextfil)
                self.selectfile()
        #restore selection
        self.plotstk=-1
        self.phlist.selection_clear()
        self.phlist.selection_set(temp)
        self.selectfile()
        self.plotstk=0        
       
    def makeplot(self, *args):
        #update graph
        #first remove current plot(s) if not stacking
        if self.plotstk==0:
            glist=self.graph.element_names()
            if glist != ():
                for g in glist:
                    self.graph.element_delete(g)
        if self.phlist.info_selection()==():
            return
        #get data
        colors=['red4','red','orange','yellow4','peru','darkseagreen4','green','darkgreen','cyan','steel blue','blue','blue violet','purple4']
        cur=self.phlist.info_selection()[0]
        dat=self.datvars.get(cur)
        #determine plot type
        pt=self.plottype.getcurselection()[0]
        mf=0
        endtext=cur[len(cur)-7:]
        if endtext[4:]=='dat':
            lt=endtext[:3]
        else:
            lt=endtext
        tt=pt
        if pt=='muF':
            #mu fluo-sum
            xd=tuple(dat.eV)
            yd=tuple(self.ffchan.get(cur)/dat.i0)
        if pt=='muT1':
            #mu I1/I0
            xd=tuple(dat.eV)
            yd=tuple(log(dat.i0/dat.i1))
        if pt=='muT2':
            #mu I2/I1
            xd=tuple(dat.eV)
            yd=tuple(log(dat.i1/dat.i2))
        if pt=='Column':
            #go to column selection
            ct=self.plotcol.getcurselection()[0]
            tt=ct
            if ct=='i0':
                #plot i0/rtc
                xd=tuple(dat.eV)
                yd=tuple(dat.i0/dat.rtc)
            if ct=='i1':
                #plot i1/rtc
                xd=tuple(dat.eV)
                yd=tuple(dat.i1/dat.rtc)
            if ct=='i2':
                #plot i2/rtc
                xd=tuple(dat.eV)
                yd=tuple(dat.i2/dat.rtc)
            if ct=='iFsum':
                #plot iFsum/rtc
                xd=tuple(dat.eV)
                yd=tuple(self.ffchan.get(cur)/dat.rtc)
            if ct=='iFall':
                #plot all iFF's/rtc
                mf=1
                xd=tuple(dat.eV)
                clen=len(colors)
                c=0
                for ch in self.fflist:
                    try:
                        tau=self.dtcvar[ch]
                    except:
                        tau=0
                    icrhz=self.icrchan[cur+'-'+ch]/dat.rtc
                    sca=self.ffchan.get(cur+'-'+ch)*exp(1e-6*tau*icrhz)
                    yd=tuple(sca/dat.rtc)
                    self.graph.line_create(ch,xdata=xd,ydata=yd,symbol='',color=colors[int(fmod(c,clen))])
                    c=c+1                
                self.graph.configure(title='All iF')
            if ct=='iFind':
                #plot FFselected/rtc
                xd=tuple(dat.eV)
                ffsel=self.fhlist.info_selection()[0]
                if ffsel != cur:
                    try:
                        tau=self.dtcvar[ffsel[rfind(ffsel,'-')+1:]]
                    except:
                        tau=0
                    icrhz=self.icrchan[ffsel]/dat.rtc
                    sca=self.ffchan.get(ffsel)*exp(1e-6*tau*icrhz)
                else:
                    sca=self.ffchan.get(ffsel)
                yd=tuple(sca/dat.rtc)
            if ct=='ICRind':
                #plot ICRselected/rtc
                xd=tuple(dat.eV)
                ffsel=self.fhlist.info_selection()[0]
                if ffsel==cur:
                    mf=1
                else:
                    yd=tuple(self.icrchan.get(ffsel)/dat.rtc)
            if ct=='ICRall':
                mf=1
                #plot all ICR channels/rtc
                xd=tuple(dat.eV)
                clen=len(colors)
                c=0
                for ch in self.fflist:
                    yd=tuple(self.icrchan.get(cur+'-'+ch)/dat.rtc)
                    self.graph.line_create('ICR'+ch[2:],xdata=xd,ydata=yd,symbol='',color=colors[int(fmod(c,clen))])
                    c=c+1                
                self.graph.configure(title='All ICR')
        if mf==0:
            #NOW... calculate derivative if needed!
            dsel=self.deriv.getcurselection()
            if dsel=='None':
                pxd=xd
                pyd=yd
            if dsel=='First':
                new=self.getderiv(xd,yd)
                pyd=tuple(new[1])
                pxd=tuple(new[0])
            if dsel=='Second':
                new1=self.getderiv(xd,yd)
                new=self.getderiv(new1[0],new1[1])
                pyd=tuple(new[1])
                pxd=tuple(new[0])
            numsmpts=int(self.smoothpts.get())
            pyd=tuple(self.datasmooth(pyd,numsmpts))
            if self.plotstk==0:
                pc='blue'
            else:
                pc=colors[int(fmod(self.plotstk,len(colors)))]
            try:
                self.graph.line_create(lt,xdata=pxd,ydata=pyd,symbol='',color=pc)
            except:
                lt=str(self.plotstk)+lt
                self.graph.line_create(lt,xdata=pxd,ydata=pyd,symbol='',color=pc)
            self.graph.configure(title=tt)

    def graphtextport(self):
        #export all data in tab delimited text to clipboard
        text=''
        datay=[]
        datax=[]
        allnames=self.graph.element_names()
        print allnames
        for name in allnames:
            temp=self.graph.element_configure(name,'xdata')
            datax.append(temp[4])
            temp=self.graph.element_configure(name,'ydata')
            datay.append(temp[4])
            text=text+name+'\t\t\t'
        text=text+'\n'
        #parse list now
        pdatax=[]
        pdatay=[]
        alllen=[]
        maxlen=0
        for i in range(len(datax)):
            temp=datax[i]
            pdatax.append(split(temp))
            temp=datay[i]
            temp2=split(temp)
            if maxlen<len(temp2):maxlen=len(temp2)
            alllen.append(len(temp2))
            pdatay.append(temp2)
        #setup text
        for j in range(maxlen):
            for i in range(len(pdatax)):
                if j<alllen[i]:
                    text=text+pdatax[i][j]+'\t'+pdatay[i][j]+'\t\t'
                else:
                    text=text+'\t\t\t'
            text=text+'\n'
        #export to clipboard
        self.root.clipboard_clear()
        self.root.clipboard_append(text)
        setstatus(self.status,"Graph data copied to clipboard")
                
    def getderiv(self,x,y):
        #returns deriv in ans(x,y)
        ans=[]
        difx=MLab.diff(x,n=1)
        dify=MLab.diff(y,n=1)
        ans.append(self.dxdata(x))
        ans.append(dify/difx)
        return ans

    def dxdata(self,x):
        i=0
        avgd=[]
        while i<len(x)-1:
            avgd.append((x[i]+x[i+1])/2)
            i=i+1
        return avgd

    def datasmooth(self,x,numpts):
        if numpts==0:
            return x
        else:
            i=0
            smoo=[]
            while i<len(x):
                if i<numpts:
                    sr=range(0,i+numpts+1,1)
                elif i>len(x)-numpts-1:
                    sr=range(i-numpts,len(x),1)
                else:
                    sr=range(i-numpts,i+numpts+1,1)
                temp=0
                for ind in sr:
                    temp=temp+x[ind]
                smoo.append(temp/len(sr))
                i=i+1
            return smoo

    def coordreport(self,event):
        (x,y)=self.graph.invtransform(event.x,event.y)
        xtext="X="+str(x)
        ytext="Y="+str(y)
        xtext=xtext[:12]
        ytext=ytext[:12]
        setstatus(self.xcoord,xtext)
        setstatus(self.ycoord,ytext)
        setstatus(self.winxcoord,xtext)
        setstatus(self.winycoord,ytext)
    
    def zoom(self, x0, y0, x1, y1):
        #add last to zoomstack
        a0=self.graph.xaxis_cget("min")
        a1=self.graph.xaxis_cget("max")
        b0=self.graph.yaxis_cget("min")
        b1=self.graph.yaxis_cget("max")        
        self.zoomstack.append((a0,a1,b0,b1))
        #configure
        self.graph.xaxis_configure(min=x0, max=x1)
        self.graph.yaxis_configure(min=y0, max=y1)

    def unzoom(self):
        #get last off stack
        if self.zoomstack==[]:
            return
        limit=self.zoomstack.pop()
        self.graph.xaxis_configure(min=limit[0],max=limit[1])
        self.graph.yaxis_configure(min=limit[2],max=limit[3])

    def mouseDrag(self,event):
        global x0, y0, x1, y1, druged
        druged = 1
        (x1, y1) = self.graph.invtransform(event.x, event.y)             
        self.graph.marker_configure("marking rectangle", 
            coords = (x0, y0, x1, y0, x1, y1, x0, y1, x0, y0))
        self.coordreport(event)
    
    def mouseUp(self,event):
        global dragging, druged
        global x0, y0, x1, y1        
        if dragging:
            self.graph.unbind(sequence="<Motion>")
            self.graph.bind(sequence="<Motion>", func=self.coordreport)
            self.graph.marker_delete("marking rectangle")           
            if event.num==1 and druged:
                if x0 <> x1 and y0 <> y1:   
                    # make sure the coordinates are sorted
                    if x0 > x1: x0, x1 = x1, x0
                    if y0 > y1: y0, y1 = y1, y0         
                    self.zoom(x0, y0, x1, y1) # zoom in
            else:
                self.unzoom() # zoom out
                           
    def mouseDown(self,event):
        global dragging, druged, x0, y0
        dragging = 0
        druged = 0
        if self.graph.inside(event.x, event.y):
            dragging = 1
            (x0, y0) = self.graph.invtransform(event.x, event.y)
            self.graph.marker_create("line", name="marking rectangle", dashes=(2, 2))
            self.graph.bind(sequence="<Motion>",  func=self.mouseDrag)        

    def averagescans(self):
        global lastsavedir,lastreaddir
        #average all active scans
        allscans=list(self.phlist.info_children())      
        nscans=len(allscans)
        #check lengths for each file 
        lenlist=[]
        for d in allscans:
            lenlist.append(len(self.datvars[d].i0))
        match=1
        maxlen=max(lenlist)
        maxlenind=lenlist.index(maxlen)
        for m in lenlist:
            if m != lenlist[0]:match=0
        if match==0:
            #ask if truncation, full averaging, or cancel of averaging is desired...
            mtext="Files not of equal length! \nTruncate, Continue or Cancel? \n"
            lengtherror=Pmw.MessageDialog(self.vw,message_text=mtext,buttonboxpos='s',iconpos='w',icon_bitmap='warning',
                                          buttons=('Truncate','Continue','Cancel'),defaultbutton='Cancel')
            lengtherror.iconname=('Averaging Error')
            lengthtype=lengtherror.activate()
            if lengthtype=='Cancel':return
            mtext="WARNING: All files MUST have same intial energy spacings! \n Continue?"
            lengthwarning=Pmw.MessageDialog(self.vw,message_text=mtext,buttonboxpos='s',iconpos='w',icon_bitmap='warning',
                                          buttons=('Continue','Cancel'),defaultbutton='Cancel')
            lengthwarning.iconname=('Averaging Error')
            lengthwtype=lengthwarning.activate()
            if lengthwtype=='Cancel':return
            #tkMessageBox.showwarning(title="Averaging Error",parent=self.vw,
            #                         message='Not implemented yet')
            #return
        if self.plottype.getcurselection()[0]=='Column':
            #trap for no selection of average type
            tkMessageBox.showwarning(title="Averaging Error",parent=self.vw,
                                     message='Please select mu type to average')
            return
        #do averaging all files same length
        if match==1:
            total=[]
            if self.plottype.getcurselection()[0]=='muF':
                atype='_fl'
                #put all data in a list...
                fchnlist=[]
                for d in allscans:
                    #calcualte sum
                    fdat=self.datvars[d].iF
                    nfc=shape(fdat)
                    if shape(nfc)[0]==1:
                        #only one FF channel
                        fchnlist.append(fdat)
                    else:
                        #multiple FF channels
                        fchnlist.append(self.sumFFdata(fdat,self.datvars[d].ICR,self.datvars[d].rtc))
                for pt in range(lenlist[0]):
                    temp=0
                    for d in allscans:
                        ind=allscans.index(d)
                        tiFsum=fchnlist[ind]
                        temp=temp+(tiFsum[pt]/self.datvars[d].i0[pt])
                    total.append(temp/nscans)
            if self.plottype.getcurselection()[0]=='muT1':
                atype='_tr'
                for pt in range(lenlist[0]):
                    temp=0
                    for d in allscans:
                        temp=temp+log(self.datvars[d].i0[pt]/self.datvars[d].i1[pt])
                    total.append(temp/nscans)
            if self.plottype.getcurselection()[0]=='muT2':
                atype='_t2'
                for pt in range(lenlist[0]):
                    temp=0
                    for d in allscans:
                        temp=temp+log(self.datvars[d].i1[pt]/self.datvars[d].i2[pt])
                    total.append(temp/nscans)
            energy=self.datvars[allscans[0]].eV
            total=array(total,Float32)
        else: #average scans for unequal lengths -- didn't want to mess with what worked above.
            #choose eV from longest scan
            energy=self.datvars[allscans[maxlenind]].eV
            temp=zeros((len(energy),len(allscans)),Float32)
            if self.plottype.getcurselection()[0]=='muF':
                atype='_fl'
                #put all data in a list...
                fchnlist=[]
                for d in allscans:
                    #calcualte sum
                    fdat=self.datvars[d].iF
                    nfc=shape(fdat)
                    if shape(nfc)[0]==1:
                        #only one FF channel
                        fchnlist.append(fdat)
                    else:
                        #multiple FF channels
                        fchnlist.append(self.sumFFdata(fdat,self.datvars[d].ICR,self.datvars[d].rtc))
                #for pt in range(lenlist[0]):
                for d in allscans:
                    for pt in range(len(self.datvars[d].i0)):
                        ind=allscans.index(d)
                        tiFsum=fchnlist[ind]
                        temp[pt,ind]=(tiFsum[pt]/self.datvars[d].i0[pt])
            if self.plottype.getcurselection()[0]=='muT1':
                atype='_tr'
                for d in allscans:
                    for pt in range(len(self.datvars[d].i0)):
                        temp[pt,allscans.index(d)]=log(self.datvars[d].i0[pt]/self.datvars[d].i1[pt])
            if self.plottype.getcurselection()[0]=='muT2':
                atype='_t2'
                for d in allscans:
                    for pt in range(len(self.datvars[d].i0)):
                        temp[pt,allscans.index(d)]=log(self.datvars[d].i0[pt]/self.datvars[d].i1[pt])
            #compile array
            noelems=[]
            for pt in range(len(energy)):
                i=0
                for d in allscans:
                    if temp[pt,allscans.index(d)]!=0:i=i+1
                noelems.append(i)
            #add columns
            temp=sum(temp,1)
            #divide by noelems
            total=temp/noelems
            #deal with truncation/averaging
            if lengthtype=='Truncate':
                minlen=min(lenlist)
                tlen=tkSimpleDialog.askinteger('Averaging','Truncate to which point?',parent=self.vw,initialvalue=minlen)
                if tlen==None:return
                energy=energy[0:tlen]
                total=total[0:tlen]
        #now plot the average
        #first remove current plot(s)
        glist=self.graph.element_names()
        if glist != ():
            for g in glist:
                self.graph.element_delete(g)
        self.graph.line_create('avg',xdata=tuple(energy),ydata=tuple(total),symbol='',color='blue')        
        #ask to save file...
        sf=tkMessageBox.askyesno(title='Continue',parent=self.vw,message='Save this average?')
        if sf:
            default=trimdirext(allscans[0])+atype+".avg"                
            fname=ask_save_file(default,lastsavedir)
            if fname != '':
                sdir=rfind(fname,os.sep)
                lastsavedir=fname[:sdir]
                #save two column ascii w/ brief header
                fid=open(fname,"w")
                fid.write("# Averaged Data "+fname+" created by SamView\n")
                try:
                    for pt in range(tlen): #lenlist[0]):
                        fid.write(str(energy[pt])+"\t"+str(total[pt])+"\n")
                except:
                    for pt in range(lenlist[0]):
                        fid.write(str(energy[pt])+"\t"+str(total[pt])+"\n")
                fid.close()

    def findenot(self):
        #find all local maxima of data at current derivative level
        dsel=self.deriv.getcurselection()
        #get data
        cur=self.phlist.info_selection()[0]
        dat=self.datvars.get(cur)
        #determine plot type
        pt=self.plottype.getcurselection()[0]
        xd=tuple(dat.eV)
        if pt=='muF':
            #mu fluo-sum
            yd=tuple(self.ffchan.get(cur)/dat.i0)
        if pt=='muT1':
            #mu I1/I0
            yd=tuple(log(dat.i0/dat.i1))
        if pt=='muT2':
            #mu I2/I1
            yd=tuple(log(dat.i1/dat.i2))
        if dsel=='None':
            #take first deriv
            new=self.getderiv(xd,yd)
            pyd=tuple(new[1])
            pxd=tuple(new[0])
        if dsel=='First':
            #take second deriv
            new1=self.getderiv(xd,yd)
            new=self.getderiv(new1[0],new1[1])
            pyd=tuple(new[1])
            pxd=tuple(new[0])
        if dsel=='Second':
            #take yet another deriv
            new2=self.getderiv(xd,yd)
            new1=self.getderiv(new2[0],new2[1])
            new=self.getderiv(new1[0],new1[1])
            pyd=tuple(new[1])
            pxd=tuple(new[0])
        numsmpts=int(self.smoothpts.get())
        pyd=tuple(self.datasmooth(pyd,numsmpts))        
        #find all zeros in pyd
        self.curmax=self.getalllocalmax(pxd,pyd)
        #add lines to plot
        self.drawe0lines()

    def e0moveline(self,event):
        dir=event.widget.cget('text')
        if self.maxima != []:
            if dir=='prev':self.curmax=self.curmax-1
            if dir=='next':self.curmax=self.curmax+1
            if self.curmax<0:self.curmax=len(self.maxima)-1
            if self.curmax>len(self.maxima)-1:self.curmax=0
            self.drawe0lines()

    def drawe0lines(self):
        enot=self.maxima[self.curmax]
        entry_replace_d(self.e0app,enot,5)
        if float(self.e0act.get()) != 0:self.enotcalcshift()
        #add lines to plot
        self.makeplot()
        (dmin,dmax)=self.graph.yaxis_limits()
        ind=0
        for ex in self.maxima:
            ind=ind+1
            if ex==self.maxima[self.curmax]:
                self.graph.line_create('e0',xdata=(ex,ex),ydata=(dmin,dmax),symbol='',color='red')              
            else:
                self.graph.line_create('max'+str(ind),xdata=(ex,ex),ydata=(dmin,dmax),symbol='',color='green')              
                
    def getalllocalmax(self,xd,yd):
        self.maxima=[]
        maxin=0
        maxdel=0
        s=1 #positive
        ind=0
        for p in yd:
            if ind>1 and ind<len(yd)-2:
                #compare to last point and next point... (make sure its not noise)
                sn=1
                if p<0:sn=0
                if s==1 and sn==0 and yd[ind-2]>0 and yd[ind+1]<0:
                    #cross a zero as a maxima
                    #calculate average of last two points
                    xcross=(xd[ind]+xd[ind-1])/2
                    #only collect first 10...
                    if len(self.maxima)<10:
                        self.maxima.append(xcross)
                        #save the index of the biggest...
                        delta=yd[ind-1]-yd[ind]
                        if delta>maxdel:
                            maxdel=delta
                            maxin=len(self.maxima)-1
                s=sn
            ind=ind+1
        return maxin

    def enotcalcshift(self):
        #calculate shift on entry
        app=float(self.e0app.get())
        act=float(self.e0act.get())
        shift=act-app
        entry_replace_d(self.e0shift,shift,4)

    def enotapplyshift(self):
        #apply energy shift
        #get data
        cur=self.phlist.info_selection()[0]
        dat=self.datvars.get(cur) 
        dat.eV=dat.eV+float(self.e0shift.get())
        self.makeplot()

    def changespacing(self):
        global chespcing,chkstart,chkspcing,chedge
        #routine to average CSXAS data points...
        chespcing=1
        chkstart=2
        chkspcing=0.05
        chedge=float(self.e0act.get())        
        #ask to do all data sets same?
        #get data
        cur=self.phlist.info_selection()[0]
        dat=self.datvars.get(cur)
        #need to know... e spacing, begin k, k spacing, edge
        chespcing=tkSimpleDialog.askfloat('Input for CS-XAS Change','Enter energy spacing (eV)',initialvalue=chespcing,parent=self.vw)
        chkstart=tkSimpleDialog.askfloat('Input for CS-XAS Change','Enter start of k range',initialvalue=chkstart,parent=self.vw)           
        chkspcing=tkSimpleDialog.askfloat('Input for CS-XAS Change','Enter k-spacing',initialvalue=chkspcing,parent=self.vw)
        chedge=tkSimpleDialog.askfloat('Input for CS-XAS Change','Enter edge (eV)',initialvalue=chedge,parent=self.vw)
        #if edge is 0 or not valid, then exit
        if chedge==0 or None in (chespcing,chkstart,chkspcing,chedge):
            tkMessageBox.showerror(title='CSXAS Operation Cancelled',parent=self.vw,message='Invalid Entries')
            return
        #start at first E...        
        datadelE=dat.eV[1]-dat.eV[0]
        #if spacing is wrong...
        if chespcing<abs(datadelE):
            tkMessageBox.showerror(title='CSXAS Operation Cancelled',parent=self.vw,message='Energy spacing is less than original data')
            return            
        #init new arrays
        # dat.rtc = clock normalizing counts
        # dat.eV, dat.i0, dat.i1, dat.i2, dat.iF, dat.ICR
        neweV=[]
        newi0=[]
        newi1=[]
        newi2=[]
        newiF=[]
        newICR=[]
        newrtc=[]
        #set markers for k-space
        kst=chkstart-chkspcing/2
        kestart=(kst/0.51233)**2+chedge
        curk=chkstart-chkspcing
        inkland=0
        #begin da rebin loop...
        lastind=len(dat.eV)
        firstind=0
        firste=dat.eV[firstind]
        nexte=firste+chespcing
        #find next index
        for i in range(firstind,lastind):
            if dat.eV[i]<nexte:
                nextind=i
        while nextind<lastind:
            #set up arrays
            trtc=dat.rtc[firstind:nextind+1]
            ti0=dat.i0[firstind:nextind+1]
            ti1=dat.i1[firstind:nextind+1]
            ti2=dat.i2[firstind:nextind+1]
            tif=dat.iF[firstind:nextind+1]
            ticr=dat.ICR[firstind:nextind+1]
            #add values to arrays
            newi0.append(sum(ti0))
            newi1.append(sum(ti1))
            newi2.append(sum(ti2))
            newiF.append(sum(tif))
            newICR.append(sum(ticr))            
            newrtc.append(sum(trtc))
            #new eV
            tev=(firste+nexte)/2
            neweV.append(tev)
            #advance to next point
            if nexte<kestart:
                firste=nexte
                nexte=nexte+chespcing
                firstind=nextind
            else:
                #in k-space land
                curk=curk+chkspcing
                firste=((curk-(chkspcing/2))/0.51233)**2+chedge
                nexte=((curk+(chkspcing/2))/0.51233)**2+chedge
                if inkland==0:
                    for i in range(0,lastind):
                        if dat.eV[i]<firste:
                            firstind=i
                else:
                    firstind=nextind
                inkland=1                    
            #find next index
            for i in range(firstind,lastind):
                if dat.eV[i]<nexte:
                    nextind=i
                if nextind==lastind-1:
                    nextind=lastind
        #now replace data...
        dat.eV=array(neweV)
        dat.i0=array(newi0)
        dat.i1=array(newi1)
        dat.i2=array(newi2)
        dat.iF=array(newiF)
        dat.ICR=array(newICR)
        dat.rtc=array(newrtc)
        #redraw...
        self.rescaleplot()
        print 'done'

    def dodeadtime(self):
        #do deattime corrections
        #check to see if file is present
        action=0
        dtf=self.dtfile.entry.get()
        if dtf=='':
            #put up message box
            tkMessageBox.showwarning(title="Deadtime Error",parent=self.vw,
                                     message='Choose deadtime correction file first')
            #reselect no dt
            self.dodt.set(0)
        else:
            if self.dodt.get()==1:
                #apply deadtimes
                #read first line of file -- make sure its valid
                fid=open(dtf,'r')
                lines=fid.read().split('\n')
                test=split(lines[0])
                if test[0] in ('FF','7','9'):
                    #read in channel values 
                    action=1
                    self.dtcvar={}
                    i=1
                    for line in lines:
                        if line[:2] not in ('FF',''):
                            self.dtcvar.update({'FF'+str(i):float(split(line)[1])})
                            i=i+1
                else:
                    tkMessageBox.showwarning(title="Deadtime Error",parent=self.vw,
                                             message='Invalid Deadtime File')
            else:
                #remove deadtimes
                action=1
                self.dtcvar={}
            #apply corrections to current data by reloading all
            if action==1:
                allscans=self.phlist.info_children()
                if allscans != ():
                    cur=self.phlist.info_selection()[0]
                    for d in allscans:
                        self.phlist.selection_clear()
                        self.phlist.selection_set(d)
                        self.selectfile()
                    self.phlist.selection_clear()
                    self.phlist.selection_set(cur)
                    self.selectfile()

    def sumFFdata(self,FF,ICR,rtc):
        #calculate a sum
        nfc=shape(FF)
        if shape(nfc)[0]==1:
            #only one FF channel
            try:
                tau=self.dtcvar['FF1']
            except:
                tau=0
            return FF*exp(1e-6*tau*ICR/rtc)
        else:
            #multiple FF channels
            ncols=nfc[1]
            temp=zeros(nfc[0])
            i=0
            while i<ncols:
                try:
                    tau=self.dtcvar['FF'+str(i+1)]
                except:
                    tau=0
                temp=temp+FF[:,i]*exp(1e-6*tau*ICR[:,i]/rtc)
                i=i+1
            return array(temp)
                        
    def getnewdtfile(self):
        GetNewDTFile(self.dtfile.entry,self.root)

    def callprogramabout(self):
        programabout(self.root)

    def callchangedefdirs(self):
        global lastsavedir,lastreaddir
        s=changedefdirs(self.vw)
        lastreaddir=s.newdir
        lastsavedir=s.newdir

class GetNewDTFile:
    def __init__(self,placement,root):
        self.root=root
        #start new deatime fitting procedure
        dt=self.root.dt=Toplevel(self.root)
        self.dt=dt
        dt.title("Deadtimes Fitting Dialog")
        dt.focus_set()
        menubar=Pmw.MenuBar(dt)
        #file menu
        menubar.addmenu('File','')
        menubar.addmenuitem('File','command',label='Open DT Dataset',command=self.loaddts)
        menubar.addmenuitem('File','separator')    
        menubar.addmenuitem('File','command',label='Fit Dataset',command=self.fitdt)
        menubar.addmenuitem('File','separator')
        menubar.addmenuitem('File','command',label='Close',command=self.root.dt.destroy)
        menubar.addmenu('Save','')
        menubar.addmenuitem('Save','command',label='Save Deadtime Fits',command=self.savefitresults)
        menubar.addmenu('Help','',side=RIGHT)
        menubar.addmenuitem('Help','command',label='About SamView',command=programabout)
        menubar.grid(row=0,columnspan=25,sticky=W+E)
        #file/FF control window
        fcwin=Frame(dt,relief=SUNKEN,bd=2)
        l=Label(fcwin,text='Deadtime Channels',relief=RAISED,bd=2)
        l.pack(side=TOP,fill=X,padx=2,pady=4)
        b=Button(fcwin,text="Load File",command=self.loaddts,bg='brown',fg='snow')
        b.pack(side=TOP,padx=20,pady=2,fill=X)
        b=Button(fcwin,text="Fit Deadtimes",command=self.fitdt,bg='darkgreen',fg='snow')
        b.pack(side=TOP,padx=20,pady=2,fill=X)  
        #Add btree
        tree=Tix.ScrolledHList(fcwin)
        self.dfhlist=tree.hlist
        self.dfhlist.config(separator='-',width=25, drawbranch=1, indent=30,itemtype=Tix.TEXT,browsecmd=self.plotdt)
        tree.pack(side=TOP,fill=BOTH,expand=1,padx=2,pady=2)
        #add ICR cutoff
        self.icrcutoff=Pmw.EntryField(fcwin,labelpos='n',label_text='ICR Cutoff Hz',value='400000',validate='numeric',command=self.reloaddts)
        self.icrcutoff.pack(side=BOTTOM,fill=X,padx=4,pady=2)
        self.icrbotoff=Pmw.EntryField(fcwin,labelpos='n',label_text='ICR Bottom Hz',value='0',validate='numeric',command=self.reloaddts)
        self.icrbotoff.pack(side=BOTTOM,fill=X,padx=4,pady=2)
        fcwin.grid(row=1,columnspan=5,rowspan=20,sticky=N+S+W+E)
        #Add graph window
        dgrwin=Frame(dt,relief=SUNKEN,bd=2)
        self.dgraph=Pmw.Blt.Graph(dgrwin,plotbackground='white')
        self.dgraph.xaxis_configure(title='ICR')
        self.dgraph.yaxis_configure(title='SCA')
        self.dgraph.pack(expand=1,fill='both')
        dgrwin.grid(row=1,column=5,columnspan=15,rowspan=15,sticky=W+E+N+S)                   
        #Add results window
        frwin=Frame(dt,relief=SUNKEN,bd=2)
        frwin.grid(row=16,column=5,columnspan=15,rowspan=5,sticky=W+E+N+S)
        l=Label(frwin,text='Fitting Results',relief=RAISED,bd=2)
        l.pack(side=TOP,fill=X,padx=2,pady=4)
        b=Button(frwin,text="Save\nDT\nFit\n",command=self.savefitresults,bg='darkorange4',fg='snow')
        b.pack(side=LEFT,fill=Y,padx=2,pady=10)
        self.restext=Pmw.ScrolledText(frwin,hscrollmode='none',vscrollmode='static',borderframe=1,
                                    text_font="Courier 9",usehullsize=1,hull_width=400,hull_height=150)
        self.restext.configure(text_state=DISABLED)
        self.restext.pack(fill='both',padx=2,pady=4)
        #init vars
        self.dffchan={}
        self.dicrchan={}
        self.dtfits={}
        self.dtfitvars={}
        self.dfflist=[]
        self.plc=placement
        
    def loaddts(self):
        global lastsavedir,lastreaddir
        #load deadtime file
        self.infile=ask_for_file([("all files","*")],lastreaddir)
        self.reloaddts()

    def reloaddts(self):        
        global lastsavedir,lastreaddir
        if self.infile !='':
            indir=rfind(self.infile,os.sep)
            lastreaddir=self.infile[:indir]
            #get file data
            dat=self.dat=xasinput.XASget(self.infile,self.dt)
            self.root.dt.focus_set()
            if len(dat.eV)==0:return
            #append lists/update tree            
            self.dfhlist.delete_all()
            cur=self.datfile=trimdir(self.infile)        
            self.dfhlist.add(cur,text=cur,state=NORMAL)
            self.dfhlist.selection_clear()
            self.dfhlist.selection_set(cur)
            #clear then load FF chans
            self.dffchan={}
            self.dicrchan={}
            self.dfflist=[]
            self.dtfits={}
            self.dtfitvars={}
            #add children
            nfc=shape(dat.iF)
            if shape(nfc)[0]==1:
                #only one FF channel
                self.dfhlist.add(cur+'-FF0',text='FF1',state=NORMAL)
                #edit for ICR cutoff
                tempf=[]
                tempi=[]
                cutoff=0
                for i in range(len(dat.iF)):
                    if dat.ICR[i]<int(self.icrcutoff.get()) and dat.ICR[i]>int(self.icrbotoff.get()) and cutoff==0:
                        tempf.append(dat.iF[i])
                        tempi.append(dat.ICR[i])
                    if dat.ICR[i]>int(self.icrcutoff.get()): cutoff=1
                dat.iF=array(tempf)
                dat.ICR=array(tempi)
                self.dffchan.update({cur+'-FF0':dat.iF})
                self.dicrchan.update({cur+'-FF0':dat.ICR})
                self.dfflist.append('FF0')
            else:
                #multiple FF channels
                ncols=nfc[1]
                i=0
                while i<ncols:
                    self.dfflist.append('FF'+str(i+1))
                    i=i+1
                i=0
                for ch in self.dfflist:
                    #edit for ICR cutoff
                    a=dat.iF[:,i]
                    b=dat.ICR[:,i]
                    tempf=[]
                    tempi=[]
                    cutoff=0
                    for j in range(len(a)):
                        if b[j]<int(self.icrcutoff.get()) and b[j]>int(self.icrbotoff.get()) and cutoff==0:
                            tempf.append(a[j])
                            tempi.append(b[j])
                        if b[j]>int(self.icrcutoff.get()): cutoff=1
                    a=array(tempf)
                    b=array(tempi)
                    self.dfhlist.add(cur+'-'+ch,text=ch,state=NORMAL)
                    self.dffchan.update({cur+'-'+ch:a})
                    self.dicrchan.update({cur+'-'+ch:b})
                    i=i+1
            self.dfhlist.selection_set(cur)
            self.plotdt()

    def plotdt(self, *arg):
        #plot dt SCA vs ICR and fits if present
        #first remove all plot elements
        glist=self.dgraph.element_names()
        if glist != ():
            for g in glist:
                self.dgraph.element_delete(g)
        #now get currently chosen element
        chan=self.dfhlist.info_selection()[0]
        #make plot of data
        if chan != self.datfile:
            flt=chan[rfind(chan,'-')+1:]
            self.dgraph.line_create(flt,xdata=tuple(self.dicrchan[chan]),ydata=tuple(self.dffchan[chan]),symbol='circle',color='blue',pixels=".05i",linewidth=0)
            #make plot of fit if it exists
            try:
                self.dgraph.line_create('Fit',xdata=tuple(self.dicrchan[chan]),ydata=tuple(self.dtfits[chan]),symbol='',color='red')        
            except:
                pass
        
    def fitdt(self):
        #fit the deadtime curves!  use SCA=kappa*ICR*exp(-ICR*tau) taus in usec
        self.dtfits={} #clear data fits
        self.dtfitvars={} #clear fit params
        cur=self.datfile
        self.restext.configure(text_state=NORMAL)
        self.restext.clear()
        self.restext.insert(END,'FF\ttau\t\toffset\t\tkappa\n')
        self.restext.configure(text_state=DISABLED)
        for ch in self.dfflist:
            #construct fitting parameters
            initguess=(0.5,1,0)  #kappa,tau(usec)
            passdata=[]
            for i in range(len(self.dffchan[cur+'-'+ch])):
                passdata.append((self.dicrchan[cur+'-'+ch][i],self.dffchan[cur+'-'+ch][i]))
            try:
                result=leastSquaresFit(dteqn,initguess,passdata)
                fp=result[0]
            except:
                fp=(0,0,0)
            self.dtfitvars.update({cur+'-'+ch:fp})
            f=dteqn(fp,self.dicrchan[cur+'-'+ch])
            self.dtfits.update({cur+'-'+ch:f})
            self.restext.configure(text_state=NORMAL)
            sca=ch[2:]
            self.restext.insert(END,sca+'\t'+str(fp[1])+'\t'+str(fp[2])+'\t'+str(fp[0])+'\n')
            self.restext.configure(text_state=DISABLED)
            self.restext.update_idletasks()
        self.plotdt()

    def savefitresults(self):
        global lastsavedir,lastreaddir
        #save fit window
        default="deadtime.dat"                
        savedname=ask_save_file(default,lastsavedir)
        self.root.dt.focus_set()
        if savedname != '':
            sdir=rfind(savedname,os.sep)
            lastsavedir=savedname[:sdir]
            self.restext.exportfile(savedname)
            self.plc.delete(0,END)
            self.plc.insert(END,savedname)
     
#start event handler
#Main(root)
#root.mainloop()