# Data Plotter

from Tkinter import *
import Pmw
from spglobalfuncs import *
import tkFileDialogDir
import os

if os.name=='nt':os.sep='/'

###############################################################
##
## Plotter Widget 
##
###############################################################


class SPPlotter:
    def __init__(self,parent,**args):
        #determine if plotter open already
        self.root=parent
        wmname="SIXPack Plotter"
        wids=parent.winfo_children()
        self.bswin=0
        for w in wids:
            try:
                t=w.title()
            except:
                t=''
            if t==wmname:
                pwin=w
            #for BS routine
            if t=="Background Subtraction Dialog":
                self.bswin=w
        try:
            #raise window
            pwin.focus_set()
            ex=1
        except:
            #make plotter window
            dialog = Pmw.Dialog(parent,
                buttons = (),
                command = self.killgraph,
                title = wmname)
            self.dlog=dialog
            self.dint=dialog.interior()
            self.makewidgets()
            ex=0
        if ex:  #map widgets!  ugh!
            t=pwin.winfo_children()
            self.dlog=t
            s0=t[1]   #frame 2 in dialog
            t=s0.winfo_children()
            sg=t[1]   #graph frame
            ss=t[2]   #status frame
            t=sg.winfo_children()
            self.graph=t[0]
            t=ss.winfo_children()
            self.status=t[0]
            self.xcoord=t[2]
            self.ycoord=t[1]          
        self.makegraph(args)

    def killgraph(self,event):
        #delete widget
        self.dlog.destroy()
        
    def makegraph(self,args):
        global sampleenot
        #required options:
            #cmd=new/stack
            #lt=string
            #xd,yd=data tuple
        #optional:
            #title=string
            #xt,yt=string, axes text
            #xmin,xmax, float, x-axis limits
            #symbol=''=line,'circle'=points
            #pixels=number -- size of data points
            #color=color string
            #hideleg=1/0 for hiding legend display
        if args=={}:
            return
        #required options
        try:
            cmd=args['cmd']
            lt=args['lt']
            xd=args['xd']
            if type(xd)!=type(()):xd=tuple(xd)
            yd=args['yd']
            if type(yd)!=type(()):yd=tuple(yd)
        except:
            print 'Need required plot commands'
            return
        #optional options
        try:
            tt=args['title']
        except:
            tt=''
        try:
            xt=args['xt']
        except:
            xt=''
        try:
            yt=args['yt']
        except:
            yt=''
        try:
            xmin=args['xmin']
            xmin=float(xmin)
        except:
            xmin=''
        try:
            xmax=args['xmax']
            xmax=float(xmax)
        except:
            xmax=''
        try:
            sym=args['symbol']
        except:
            sym=''
        try:
            px=args['pixels']
        except:
            px=0
        try:
            pc=args['color']
        except:
            pc=''
        try:
            hideleg=args['hideleg']
        except:
            hideleg=0
        try:
            sampleenot=args['SAMEz']
        except:
            self.sampleenot=0
        if upper(cmd) not in ('NEW','STACK'):
            print 'invalid plot command'
            return
        if upper(cmd)=='NEW':
            #clear graphs
            glist=self.graph.element_names()
            if glist != ():
                for g in glist:
                    self.graph.element_delete(g)
            self.graph.xaxis_configure(min='',max='')
            self.graph.yaxis_configure(min='',max='')
            self.zoomstack=[]
        #default color scheme order
        colors=['blue','red','midnightblue','darkgreen','firebrick4','orange','black','green','purple4','cyan','steel blue','yellow4','peru']
        cnum=len(colors)
        #determine color if not given
        if pc=='':
            #determine number of elements
            gnum=len(self.graph.element_names())
            pc=colors[int(fmod(gnum,cnum))]
        #plot
        self.graph.line_create(lt,xdata=xd,ydata=yd,symbol=sym,color=pc,pixels=px)
        #xlimits
        self.graph.xaxis_configure(min=xmin,max=xmax)
        #legend deactivate?
        if hideleg:
            self.graph.element_configure(lt,label='')
        #add axes text if opted
        self.graph.xaxis_configure(title=xt)
        self.graph.yaxis_configure(title=yt)
        #add title text if opted
        self.graph.configure(title=tt)
        setstatus(self.status,"Graph constructed")
        
    def makewidgets(self):
        #Menu bar
        pw=self.dint
        menubar=Pmw.MenuBar(pw)
        #file menu
        menubar.addmenu('Copy','')
        menubar.addmenuitem('Copy','command',label='Set Dump Directory',command=self.setdir)
        menubar.addmenuitem('Copy','command',label='Graph to File',command=self.clipgraph)
        menubar.addmenuitem('Copy','separator')
        menubar.addmenuitem('Copy','command',label='Copy Data to Clipboard',command=self.graphtextport)
        menubar.addmenu('Help','',side=RIGHT)
        menubar.addmenuitem('Help','command',label='About SixPack',command=self.callprogramabout)
        menubar.pack(side=TOP,fill=X)
        #Container frames
        gfr=Frame(pw,relief=SUNKEN,bd=2)
        gfr.pack(side=TOP,fill='both',expand=1)
        sfr=Frame(pw)
        sfr.pack(side=TOP,fill=X)
        #Graph Window
        self.graph=Pmw.Blt.Graph(gfr,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.grid_toggle()
        self.graph.pack(expand=1,fill='both')
        #Status Bar
        self.status=Label(sfr,text="",bd=2,relief=RAISED,anchor=W,fg='blue')
        self.status.pack(side=LEFT,fill=X,expand=1)
        setstatus(self.status,"Ready")
        self.xcoord=Label(sfr,text="X=      ",width=15,bd=2,relief=RIDGE,anchor=W,fg='red')
        self.ycoord=Label(sfr,text="Y=      ",width=15,bd=2,relief=RIDGE,anchor=W,fg='red')
        self.ycoord.pack(side=RIGHT,fill=X)
        self.xcoord.pack(side=RIGHT,fill=X)
        #init stack
        self.zoomstack=[]
        self.dumpdir=''

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

    def setdir(self):
        #set graph-dump directory
        self.dumpdir=tkFileDialogDir.choose_directory()

    def clipgraph(self):
        if self.dumpdir=='':self.setdir()
        img = PhotoImage()
        self.graph.snap(img)
        fn=self.dumpdir+os.sep+"graph_dump.gif"
        img.write(fn,format='gif')
        setstatus(self.status,"Graph copied to dump_graph.gif")
        
    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)
    
    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
        global sampleenot
        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
            if event.num==3:
                self.unzoom() # zoom out
            if event.num==2 and self.bswin!=0:
                try:
                    wid=self.bswin.focus_lastfor()
                    widend=wid.winfo_name()
                    mk=wid.master.children.keys()
                    for w in mk:
                        if w!=widend:
                            lab=w
                    labtxt=wid.master.children[lab].cget('text')
                    status=0
                    if labtxt=='E0: ' and x0>500: status=1
                    if labtxt=='Rbkg: ' and x0<10: status=1
                    if labtxt=='k: ' and x0<20: status=1
                    if labtxt=='to k: ' and x0<20: status=1
                    if labtxt=='PreEdg: ' or labtxt=='Norm: ' or labtxt=='E: ' or labtxt=="to E: ": status=2
                    if status==1: entry_replace_d(wid,x0,4)
                    if status==2 and x0>500:
                        #recalc x0
                        newX=x0-float(sampleenot)
                        entry_replace_d(wid,newX,4)
                except:
                    return
                           
    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 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")