#Created by dan december 2011. www.danomagnum.com from ttk import Label, Button#, Checkbutton, Style from Tkinter import StringVar, LEFT, RIGHT, BOTH, Frame, X, RAISED, IntVar, Menu, Checkbutton, Y, BooleanVar import tkMessageBox import tkSimpleDialog import block_functions TRUECOLOR = "green" FALSECOLOR = "red" LATCHCOLOR = "blue" DEFAULTCOLOR = "black" fix_scroll = lambda x:x remove_row = lambda x:x functionlist = block_functions.BLOCK_FUNCTION_LIST itemlist = [] #need to fill this in to add stuff I guess class IO(): def __init__(self,value,name,typedesc,input=False,description=""): self.latched = False self.input = input self.set(value) self.name=name self.displayvariable = StringVar() self.typedesc = typedesc if self.typedesc == 'bool': self.displayvalue = BooleanVar() elif self.typedesc == 'int': self.displayvalue = IntVar() else: self.displayvalue = StringVar() self.display = [] self.description = description def delifparent(self,parent): displays = self.display[:] for d in displays: if d.master == parent: #I am a child of you, so I wll delete myself self.display.remove(d) d.destroy() if not self.display: del(self) def set(self,value=0): if self.latched: return False self.value = value return True def latchon(self): self.latched = True self.value = True self.display_update() def latchoff(self): self.latched = True self.value = False self.display_update() def unlatch(self): self.latched = False self.display_update() def status(self): return self.value def __nonzero__(self):#evaluates the decision block if self.value: return True else: return False def __repr__(self): return str(self.value) + ' ' + self.name def __eq__(self,n): return self.value == n def __lt__(self,n): return self.value < n def __gt__(self,n): return self.value > n def __ge__(self,n): return self.value >= n def __le__(self,n): return self.value <= n def __trunc__(self): return self.value def __int__(self): try: i = int(self.value) except: i = 0 return i def toggle(self): if self.latched == False: self.value = not self.value def clicked(self): if self.typedesc == 'bool': self.toggle_and_display() def toggle_and_display(self): self.toggle() self.display_update() def display_new(self,parent): self.display_update() b = Checkbutton(parent,textvariable=self.displayvariable,command=self.clicked,variable=self.displayvalue,indicatoron=0) b.pack(side=LEFT) self.display.append(b) self.popup = Menu(parent,tearoff=0) self.popup.add_command(label="force on",command=self.latchon) self.popup.add_command(label="force off",command=self.latchoff) self.popup.add_command(label="remove force",command=self.unlatch) self.popup.add_separator() self.popup.add_command(label="properties",command=self.properties) self.popup.add_command(label="description",command=self.setdesc) b.bind("",self.popup_menu) return b def popup_menu(self,event): try: self.popup.tk_popup(event.x_root,event.y_root,0) finally: self.popup.grab_release() def properties(self): ds = self.name + "\n" + str(self.value) + "\n" ds += "Force: " if self.latched: ds += "on" else: ds += "off" ds += "\nDescription:" + self.description tkMessageBox.showinfo(self.name,ds) def display_update(self): if self.display: for d in self.display: if self.latched: d.configure(foreground=LATCHCOLOR) else: d.configure(foreground=DEFAULTCOLOR) ds = self.name + "\n" + str(self.value) if self.description: ds += "\n" + self.description if self.displayvariable: self.displayvariable.set(ds) dv = None if self.typedesc == 'bool': dv = bool(self.value) elif self.typedesc == 'int': dv = int(self.value) else: dv = str(self.value) self.displayvalue.set(dv) def setdesc(self): result = tkSimpleDialog.askstring(self.name,self.name,initialvalue=self.description) if result is not None: self.description = result self.display_update() class value_binary(IO): def __init__(self,value,name='Unnamed',input=False,description=""): self.latched = False self.input = input self.set(value) self.name=name self.displayvariable = StringVar() self.displayvalue = BooleanVar() self.display = [] self.description = description self.typedesc = 'bool' def bound(mn,var,mx): return max(mn,min(mx,var)) class value_word(IO): #0-1023 description = None def __init__(self,value,name='Unnamed',input=False,description=""): self.values = [] self.input = input self.name=name self.set(value) #self.display = False self.display = [] self.displayvariable = StringVar() self.display_update() self.description = description def delifparent(self,parent): displays = self.display[:] for d in displays: if d.master == parent: #I am a child of you, so I wll delete myself self.display.remove(d) d.destroy() if not self.display: del(self) def set(self,value): value = bound(0,value,1023) binstring = bin(value)[2:] #string starts with 0bxxxx if self.values: i = 0 for digit in binstring[::-1]: self.values[i].set(int(digit)) i += 1 while i < 10: self.values[i].set(False) i += 1 self.value = value #return True else: self.value = value self.values = [] i = 0 for digit in binstring[::-1]: self.values.append(value_binary(int(digit),self.name + '/' + str(i))) i += 1 while i < 10: self.values.append(value_binary(False,self.name + '/' + str(i))) i += 1 def status(self): return self.value def bits(self): return self.values def __repr__(self): return str(self.value) + ' ' + self.name def __eq__(self,n): return self.value == int(n) def __lt__(self,n): return self.value < int(n) def __gt__(self,n): return self.value > int(n) def __ge__(self,n): return self.value >= int(n) def __le__(self,n): return self.value <= int(n) def __trunc__(self): return self.value def __int__(self): return self.value def __add__(self,n): return self.value + int(n) def __sub__(self,n): return self.value - int(n) def __iadd__(self,n): self.value = self.value + int(n) return self def __isub__(self,n): self.value = self.value - int(n) return self def __int__(self): return int(self.value) def bits_display_new(self,parent): #labs = [] frm = Frame(parent,borderwidth=1) for bit in self.values: #labs.append(bit.display_new(frm)) bit.display_new(frm) frm.pack(side=LEFT) #return labs def bits_display_update(self): for bit in self.values: bit.display_update() def display_new(self,parent): self.display_update() l = Label(parent,textvariable=self.displayvariable,borderwidth=2,relief=RAISED) l.pack(side=LEFT) self.display.append(l) self.popup = Menu(parent,tearoff=0) self.popup.add_command(label="Value",command=self.prompt_for_value) self.popup.add_command(label="Description",command=self.setdesc) l.bind("",self.popup_menu) return l def popup_menu(self,event): try: self.popup.tk_popup(event.x_root,event.y_root,0) finally: self.popup.grab_release() def display_update(self): ds = self.name + '\n' + str(self.value) if self.description: ds += '\n' + self.description self.displayvariable.set(ds) def prompt_for_value(self): result = tkSimpleDialog.askinteger(self.name,self.name,initialvalue=self.value,minvalue=0,maxvalue=1023) if result is not None: self.set(result) self.display_update() def setdesc(self): result = tkSimpleDialog.askstring(self.name,self.name,initialvalue=self.description) if result is not None: self.description = result self.display_update() def create_binary_array(length,name): array = [] for i in xrange(length): assignedname = str(name) + str(i) array.append(value_binary(False, assignedname)) return array def display_binary_array(array,parent): #labs = [] for bit in array: #labs.append(bit.display_new(parent)) bit.display_new(parent) #return labs class block(): def __init__(self,function = block_functions.DEFAULT,parent=None,output=False,rung=None): self.function = function() self.name = self.function.name self.arguments = [] self.display = None self.frm2 = None self.rung=rung self.popupparent = None if parent: self.display_new(parent) if output: self.display_update_output() else: self.display_update() def delifparent(self,parent): if self.frm.master == parent: #I am a child of you, so I wll delete myself if self.frm2: self.frm2.destroy() for a in self.arguments: a.delifparent(self.frm) def status(self): return self.function.on(*self.arguments) def run(self,on=True): if on: self.function.on(*self.arguments) else: self.function.off(*self.arguments) def __nonzero__(self):#evaluates the decision block return self.status() def removeblock(self,child): if child in self.arguments: self.arguments.remove(child) def display_new(self,parent): #labs = [] frm = Frame(parent,border=2,relief=RAISED,pady=5) frm2 = Frame(frm,border=1,relief=RAISED,) frm2.pack(fill=X) l = Label(frm2,text=self.function.__name__()) l.pack() for bit in self.arguments: #labs.append(bit.display_new(frm)) bit.display_new(frm) frm.pack(side=LEFT) self.display = frm #return labs self.popupparent = parent self.popup = Menu(self.popupparent,tearoff=0,postcommand=self.updatemenu) addmenu = Menu(self.popup,tearoff=0) for item in itemlist: addmenu.add_command(label=item.name,command=self.additem(item)) self.popup.add_cascade(label="add argument",menu=addmenu) self.popup.add_command(label="add output") self.popup.add_separator() self.popup.add_command(label="remove block",command=self.delblock) self.popup.add_separator() self.updatemenu() self.frm = frm frm.bind("",self.popup_menu) fix_scroll() def testing(self): print self.arguments print self.status() print self.function.on def updatemenu(self): self.popup.delete(5) self.popup.delete(4) self.popup.delete(3) self.popup.delete(2) self.popup.delete(1) self.popup.delete(1) self.popup.delete(1) #self.popup = Menu(self.popupparent,tearoff=0,postcommand=self.updatemenu) addmenu = Menu(self.popup,tearoff=0) for item in itemlist: addmenu.add_command(label=item.name,command=self.additem(item)) for fnct in functionlist: addmenu.add_command(label=fnct.__name__,command=self.addsubblock(fnct)) self.popup.add_cascade(label="add argument",menu=addmenu) self.popup.add_command(label="add output") self.popup.add_command(label="test",command=self.testing) self.popup.add_separator() self.popup.add_command(label="remove block",command=self.delblock) self.popup.add_separator() #self.updatemenu() self.removeargsmenu = Menu(self.popup,tearoff=0) for item in self.arguments: self.removeargsmenu.add_command(label=item.name,command=self.removearg(item)) #self.popup.delete(5) self.popup.add_cascade(label="remove argument",menu=self.removeargsmenu,) #addmenu = Menu(self.popup,tearoff=0) #for item in itemlist: #addmenu.add_command(label=item.name,command=self.additem(item)) # #self.popup.delete(1) #self.popup.add_cascade(0,label="add argument",menu=addmenu) def addsubblock(self,fnct): return lambda:self.arguments.append(block(fnct,parent=self.frm,rung=self)) def removearg(self,item): return lambda:self.removearg2(item) def removearg2(self,item): item.delifparent(self.frm) self.arguments.remove(item) def additem(self,item): return lambda:self.additem2(item) def additem2(self,item): self.arguments.append(item) #self.removeargsmenu.add_command(label=item.name,command=self.removearg(item)) item.display_new(self.frm) fix_scroll() def delblock(self): self.rung.removeblock(self) for a in self.arguments: a.delifparent(self.frm) if self.frm2: self.frm2.destroy() self.frm.destroy() def popup_menu(self,event): try: self.popup.tk_popup(event.x_root,event.y_root,0) finally: self.popup.grab_release() def display_update(self): if self.display: if self.status(): self.display.configure(bg=TRUECOLOR) else: self.display.configure(bg=FALSECOLOR) for bit in self.arguments: bit.display_update() def display_update_output(self): for bit in self.arguments: bit.display_update() class rung(): def __init__(self): self.inputs = [] self.frminput = None self.frmoutput = None self.outputs = [] def __del__(self): for i in self.inputs: i.delifparent(self.frminput) for o in self.outputs: o.delifparent(self.frmoutput) self.frminput.destroy() self.frmoutput.destroy() self.frm.destroy() def run(self): conds = map(lambda x:x.status(),self.inputs) if all(conds) or not self.inputs: if self.frminput: self.frminput.configure(bg=TRUECOLOR) map(lambda x:x.run(),self.outputs) else: if self.frminput: self.frminput.configure(bg=FALSECOLOR) map(lambda x:x.run(on=False),self.outputs) def removeblock(self,child): if child in self.inputs: self.inputs.remove(child) elif child in self.outputs: self.outputs.remove(child) def display_new(self,parent): #labs = [] frm = Frame(parent,border=2,relief=RAISED) frmminheight = Frame(frm,height=20,width=1) frmminheight.pack(side=LEFT) self.frminput = Frame(frm,border=1,relief=RAISED) self.frmoutput = Frame(frm,border=1,relief=RAISED) self.frminput.pack(side=LEFT,fill=Y) self.frmoutput.pack(side=RIGHT,fill=Y) for inputblock in self.inputs: inputblock.display_new(self.frminput) for outputblock in self.outputs: outputblock.display_new(self.frmoutput) frm.pack(fill=X,expand=1) self.display = frm self.popup = Menu(parent,tearoff=0) self.inputmenu = Menu(self.popup,tearoff=0) self.outputmenu = Menu(self.popup,tearoff=0) for fnct in functionlist: self.inputmenu.add_command(label=fnct.__name__,command=self.addinput(fnct)) self.outputmenu.add_command(label=fnct.__name__,command=self.addoutput(fnct)) self.popup.add_cascade(label="add input",menu=self.inputmenu) self.popup.add_cascade(label="add output",menu=self.outputmenu) self.popup.add_separator() self.popup.add_command(label="remove rung",command=self.removerowclick) self.popup.add_command(label="new rung") self.popup.add_command(label="test",command=self.test) frm.bind("",self.popup_menu) self.frminput.bind("",self.popup_menu_input) fix_scroll() self.frm = frm def test(self): for i in self. inputs: i.test(self.frminput) def removerowclick(self): remove_row(self) def addinput(self,fnct): return lambda:self.inputs.append(block(fnct,parent=self.frminput,rung=self)) def addoutput(self,fnct): return lambda:self.outputs.append(block(fnct,parent=self.frmoutput,output=True)) def popup_menu(self,event): try: self.popup.tk_popup(event.x_root,event.y_root,0) finally: self.popup.grab_release() def popup_menu_input(self,event): try: self.inputmenu.tk_popup(event.x_root,event.y_root,0) finally: self.popup.grab_release() def display_update(self): for inputblock in self.inputs: inputblock.display_update() for outputblock in self.outputs: outputblock.display_update_output() def closeblock(bit): b = block() b.arguments.append(bit) return b if __name__ == '__main__': I1 = create_binary_array(10,'I1:0/') b1 = block() b1.function = func_and b1.arguments.append(I1[0]) b1.arguments.append(I1[1]) I1[0].set(True) I1[1].set(True) a = value_word(0) out1 = block() out1.function = func_add out1.arguments.append(a) out1.arguments.append(1) out1.run() r = rung() r.inputs += [b1] r.outputs += [out1] r.run() I1[0].set(False) r.run()