from tkinter import *
from tkinter import ttk

def chooseKey(event):
    global myKey
    global key
    ans = KS2.get().lower
    keyS="??,E,A,D,G,C,F,Bb,Eb,Ab"
    if (ans =="e"):  #Key of E, 4 Sharps F,C,G,D
              # C D E F G A B 
       myKey = [1,3,4,6,8,9,11]
       keyS="Key: E <F# C# G# D#>"
    if (ans =="a"):  #Key of A, 3 Sharps F,C,G
       myKey = [1,2,4,6,8,9,11]
       keyS="Key: A <F# C# G#>"
    if (ans =="d"):  #key of D, 2 Sharps F,C 
       myKey = [1,2,4,6,7,9,11]
       keyS="Key: D <F# C#>"
    if (ans =="g"):  #key of G, 1 Sharp F 
       myKey = [0,2,4,5,7,9,11]
       keyS="Key: G <F#>"
    if (ans =="c"):  #Key of C, root scale
       myKey = [0,2,4,5,7,9,11]
       keyS="Key: C"
    if (ans =="f"): #Key of F, 1 flat B
       myKey = [0,2,4,5,7,9,10]
       keyS="Key: F <Bb>"
    if (ans =="bb"): #Key of Bb, 2 Flats B,E
       myKey = [0,2,3,5,7,9,10]
       keyS="Key: Bb <Bb Eb>"
    if (ans =="ab"): #Key of Eb, 3 Flats B,E,A 
       myKey = [0,2,3,5,7,8,10]
       keyS="Key: Eb <Bb Eb Ab>"
    if (ans =="eb"): #Key of Ab, 4 Flats B,E,A,D
       myKey = [0,1,3,5,7,8,10]
       keyS="Key: Ab <Bb Eb Ab Db>"
    loadMidi()
    KS1.set(keyS)

#Durations of standard notes
def semiquaver():
    print("semiquaver")
    global dur
    dur = 6
def quaver():        
    print("quaver")
    global dur
    dur = 12
def crochet():        
    print("crochet")
    global dur
    dur = 24
def semibreve():        
    print("semibreve")
    global dur
    dur = 48
def breve():        
    print("breve")
    global dur
    dur = 96


def loadMidi():
    global myMidi
    global myKey
    del myMidi[:]
    for notes in range(24,106,12):    #C1 to C8 in steps of 12
        myMidi.append(notes+myKey[0]) #C    skip C#,Db
        myMidi.append(notes+myKey[1]) #D    skip Eb,D#
        myMidi.append(notes+myKey[2]) #E	half tone
        myMidi.append(notes+myKey[3]) #F	skip F#, Gb
        myMidi.append(notes+myKey[4]) #G	skip G#, Ab
        myMidi.append(notes+myKey[5]) #A	skip Bb
        myMidi.append(notes+myKey[6]) #B    half tone
    #print 'Init loop',myMidi

#This is the handler for mouse click events. Note that it
#must take one parameter, a tuple of the position of the
#mouse click.
def canvas_click(event):
    #print ('Mouse x=', event.x," - ",event.y)
    global accidental
    global aNote
    global dotted
    global myMidi
    aNote = [int((event.x+5)/10)*10,int((event.y+5)/10)*10] #Quantise position, tuplet for X,Y of current note
    Y=int(((785-event.y)/10))
    #print ('Y-Coord ',Y)
    #print ('Midi = ',myMidi[Y])
    dummy = '"note"'+":["+str(int((aNote[0]-200)/10))+","+str(myMidi[Y]+accidental)+","+str(int(dur*dotted))+"],"
    NL1.set(dummy)
    #print (dummy)
    tune.append(dummy)#Main data list of note information
    #Push the Note Grahpic onto a list for redraw and also countback purposes for erasing notes and bars
    noteHist.append(([aNote[0],aNote[1]+10],[aNote[0],aNote[1]-10],[aNote[0]+10*dur*dotted,aNote[1]]))
    accidental=0 #reset accidentals 
    sharpS="Sharpen"
    natS="Natural True"
    flatS="Flatten"
    dotted = 1.0 #reset the dotted effect
    dotS="Dotted False"
    draw_note(canvas)
    
def draw_note(canvas):
   #Draw the note graphic
   canvas.delete("stem","oval1","oval2","flag1","flag2") # remove all items
   global dur
   global aNote
   #Draw history of notes entered
   for myNotes in range(0,len(noteHist)): #Nos of subdivisions in a bar
      canvas.create_polygon([(noteHist[myNotes][0]), (noteHist[myNotes][1]), (noteHist[myNotes][2])], width=2, fill="white", tag="noteHist")
   #draw where the current note  should be
   print("duration = ",dur," aNote[",aNote,"]")
   canvas.create_oval([aNote[0]-10,aNote[1]-8,aNote[0]+10,aNote[1]+8], width=3,tag="oval1",outline="black")#Oval filled in white, begin as a breve
   if (dur <96):
      #Draw a stem in black, all non-breves have a stem
      canvas.create_line((aNote[0]+10,aNote[1]), (aNote[0]+10,aNote[1]-60), width=3, fill="black",tag="stem")
   if (dur <48):
      #All notes less than sem-breve are filled with black
      canvas.create_oval([aNote[0]-10,aNote[1]-8,aNote[0]+10,aNote[1]+8],width=0, fill="black",tag="oval2")#Oval empty
   if (dur <24):
      #add one flag for a Quaver
      canvas.create_line((aNote[0]+10,aNote[1]-60), (aNote[0]+30,aNote[1]-45), width=3, fill="black", tag="flag1")
   if (dur<12):
      #add second line for a semi quaver
      canvas.create_line((aNote[0]+10,aNote[1]-45), (aNote[0]+30,aNote[1]-30), width=3, fill="black",tag="flag2")


def draw_handler(canvas):
   #Draw the titles on the canvas
   canvas.create_text((20, 400),text="Treble Clef", anchor="nw")
   canvas.create_text( (20, 520),text="Bass Clef",anchor="nw")
   canvas.create_text( (80, 50),text="Scheduler+Midi",anchor="nw")
   #draw the timing lines
   for lines in range(200,1180,20): #Nos of subdivisions in a bar
      lwidth = 1
      if (lines+40)%60 == 0:
          lwidth =2
      if (lines+40)%240 == 0:
          lwidth =3
      canvas.create_line((lines,280),(lines,680),width=lwidth,fill="yellow")
   #above treble cleff
   canvas.create_line((200, 300), (1160, 300), width=1,fill="blue")
   canvas.create_line((200, 320), (1160, 320), width=1, fill="blue")
   canvas.create_line((200, 340), (1160, 340), width=1, fill="blue")
   canvas.create_line((200, 360), (1160, 360), width=1, fill="blue")
   canvas.create_line((200, 380), (1160, 380), width=1, fill="blue")
   # Treble Clef Lines   
   canvas.create_line((100, 400), (1180, 400), width=3, fill="black")
   canvas.create_line((100, 420), (1180, 420), width=3, fill="black")
   canvas.create_line((100, 440), (1180, 440), width=3, fill="black")
   canvas.create_line((100, 460), (1180, 460), width=3, fill="black")
   canvas.create_line((100, 480), (1180, 480), width=3, fill="black")
   #middle "c"
   canvas.create_line((200, 500), (1160, 500), width=1, fill="blue")
   # Bass Clef Lines
   canvas.create_line((100, 520), (1180, 520), width=3, fill="black")
   canvas.create_line((100, 540), (1180, 540), width=3, fill="black")
   canvas.create_line((100, 560), (1180, 560), width=3, fill="black")
   canvas.create_line((100, 580), (1180, 580), width=3, fill="black")
   canvas.create_line((100, 600), (1180, 600), width=3, fill="black")
   #below the Bass Cleff
   canvas.create_line((200, 620), (1160, 620), width=1, fill="blue")
   canvas.create_line((200, 640), (1160, 640), width=1, fill="blue")
   canvas.create_line((200, 660), (1160, 660), width=1, fill="blue")
   #canvas.create_image(self.image,  image_center,          image_size,     pos,           image_size)
   #84 across by 232 Tcleff.png
   tcleff = PhotoImage(file="Tcleff.gif")
   canvas.create_image(110,390,image=tcleff, anchor="nw")
   #80 across by 97 Bcleff.png
   bcleff = PhotoImage(file="Bcleff.gif")
   canvas.create_image(110,523,image=bcleff,anchor="nw" )
   draw_note(canvas)
  
#core Bar editting                
def clearBar(): 
    global bar
    BN1.set("Bar Cleared:"+str(bar))
    if(len(noteHist)>0):
        for myNotes in range(0,len(noteHist)):
            noteHist.pop(len(noteHist)-1)
            tune.pop(len(tune)-1)
def incBar(): 
    global bar
    global noteHist
    bar=bar+1
    #print ('"bar":',str(bar))
    tune.append('"bars"'+":"+str(bar)+",")
    noteHist=[] #clear the graphics for the next bar
    BN1.set('Bar Selected:'+str(bar))
def decBar():
    global bar
    if (bar>1): #No negative bars please!!!
       bar=bar-1
       #print('"bar":',str(bar))
    BN1.set('Bar Selected:'+str(bar))
def erase(): #Erase the last entered note
    if (len(noteHist)>0):#only if the current bar has any history (left?)
        tune.pop(len(tune)-1)#removes notes off the main tune list
        noteHist.pop(len(noteHist)-1)#removes notes from previous history of current bar

#Control Accidentals        
def sharpen(): 
    global accidental
    accidental = 1
    AS1.set("Sharpen True")
    AS2.set("Natural")
    AS3.set("Flatten")
def natural(): 
    global accidental
    accidental=0
    AS1.set("Sharpen")
    AS2.set("Natural True")
    AS3.set("Flatten")
def flatten(): 
    global accidental
    accidental = -1
    AS1.set("Sharpen")
    AS2.set("Natural")
    AS3.set("Flatten True")
def dot():
    global dotted
    if (dotted==1.5):
        dotted = 1.0
        DS1.set("Dotted False")
    else:
        dotted = 1.5
        DS1.set("Dotted True")

#Other functions 
def chooseInstrument(temp):
    global instrument
    IN1.set("Instrument= "+IN2.get())
    instrument=int(IN2.get())
        
def save():
    midiWhole.append('"midi":'+str(instrument)+',')
    midiWhole.extend(tune)
    for myData in range(0,len(midiWhole)): #Nos of subdivisions in a bar
        print (midiWhole[myData])


#*****************************************
#*******   START OF MAIN PROGRAM   *******
#*****************************************    
frame   = Tk() #Establish main Frame
graphic = Frame(frame) #Master sub-Frame
graphic.grid()#Establish the Layout manager
butCol  = Frame(graphic,width=120,height=750)# A sub-sub-Frame to hold all the buttons down the LHS
canvas  = Canvas(graphic,width=1200,height=750,bg='gray')#sub-sub-frame should allow us to draw inside the frame 'graphic'?
#How to organise widgets within the grid
butCol.grid(column=1, row=1) #Down LHS
butCol.grid(sticky=(N, E, W), pady=5, padx=5 )
canvas.grid(column=2, row=1, sticky=(N, W, E, S)) #Rest of space the RHS
print("Layout widgets and plan established")
#Establish major lists and variables
tune = []
noteHist = []
midiWhole=[]
#Note presets
dur=0 #Length of a note
barNosS = "1"
barNos=str(barNosS)
myKey =[]
myMidi =[]
aNote = [200,500] #Middle C to begin with
noteFill = 'black'
bar = 1 #just to kick the bar nos off :-)
dur =24 #default Crochet note length
accidental = 0
dotted = 1.0 #the multiplier for 'dot'ing 1 = off, 1.5 = on
sharpS="Sharpen"
natS="Natural True"
flatS="Flatten"
dotted = 1.0 #reset the dotted effect
dotS="Dotted False"

print ("Globals established")

#draw the teble and bass cleff stave graphics on the canvas
draw_handler(canvas)
#define/draw the GUI elements to control editting
canvas.bind('<Button-1>', canvas_click)
#frame.bind('<Return>', frame.search)
nameLbl   =Label (butCol,text="Scheduler+Midi V1.7").grid(column=0, row=0, sticky=(N,W))
label1    =Label (butCol,text="Note Selection:??").grid(column=0, row=1, sticky=(N,W))
semiQaver =Button(butCol,text="SemiQuaver 6", command=semiquaver).grid(column=0, row=2, sticky=(N,W)) 
Quaver    =Button(butCol,text="Quaver 12", command=quaver).grid(column=0, row=3, sticky=(N,W))
Crochet   =Button(butCol,text="Crochet 24", command=crochet).grid(column=0,row=4, sticky=(N,W))
Semibreve =Button(butCol,text="SemiBreve 48", command=semibreve).grid(column=0, row=5, sticky=(N,W))
Breve     =Button(butCol,text="Breve 96", command=breve).grid(column=0, row=6, sticky=(N,W))

DS1      = StringVar()#Creates a special tkinter variable
DS1.set("Dotted False")
Dot       =Button(butCol,command=dot,textvariable=DS1).grid(column=0,row=7,sticky=(N,W))
Erase     =Button(butCol,text="Erase last Note", command=erase).grid(column=0, row=8, sticky=(N,W))
label2    =Label(butCol,text="Accidentals: ").grid(column=0, row=9, sticky=(N,W))
AS1      = StringVar()
AS1.set("Sharpen")
as1      =Button(butCol, command=sharpen,textvariable=AS1).grid(column=0, row=10, sticky=(N,W))
AS2      = StringVar()
AS2.set("Natural")
as2      =Button(butCol,text="Natural", command=natural,textvariable=AS2).grid(column=0, row=12, sticky=(N,W))
AS3      = StringVar()
AS3.set("Flatten")
as3      =Button(butCol,text="Flatten", command=flatten,textvariable=AS3).grid(column=0, row=13, sticky=(N,W))

BN1 = StringVar()
BN1.set("Bar Selected:"+str(barNos))
BarNos1   =Label(butCol,textvariable= BN1).grid(column=0,row=14,sticky=(N,W))
Incbar    =Button(butCol,text="IncBar & Clear", command=incBar).grid(column=0,row=15,sticky=(N,W))
Decbar    =Button(butCol,text="Dec Bar", command=decBar).grid(column=0,row=16,sticky=(N,W))
Clearbar  =Button(butCol,text="Clear Bar", command=clearBar).grid(column=0,row=17,sticky=(N,W))

KS1=StringVar()
KS1.set("Key is ??")
butCol.ks1       =Label(butCol,textvariable=KS1).grid(column=0,row=18,sticky=(N,W))

myKey = [0,2,4,5,7,9,11] #Begin in the key of C
KS2       =StringVar()
KS2.set("C")
butCol.ks2       =Entry(butCol,width=20,textvariable=KS2).grid(column=0,row=19,sticky=(N,W))
#butCol.ks2.bind("<Return>",chooseKey)



IN1       =StringVar()
IN1.set("Instrument is ??")
in1       =Label(butCol,textvariable=IN1).grid(column=0,row=20,sticky=(N,W))
IN2       =StringVar()
in2       =Entry(butCol,textvariable=IN2).grid(column=0,row=21,sticky=(N,W))
#in2.bind('<Return>',butCol.search)
Save      =Button(butCol,text="Dump to Debug", command=save).grid(column=0,row=22,sticky=(N,W))
NL1       =StringVar()
NL1.set("Note entered:")
nl1       =Label (butCol,textvariable=NL1).grid(column=0,row=23,sticky=(N,W))
print("Widgets established")

key='C'
instrumentS = "1" #Variable to interact with the entry widget
instrument = int(instrumentS)


#Establish midi note lookup list for a particular key
#print('myKey = ',myKey)
loadMidi()
#print("myMidi = ",myMidi)
#print("aNote = ",aNote)
print("Begin Event driven GUI")
frame.mainloop()

