# HG changeset patch # User drewp # Date 2002-07-07 06:16:11 # Node ID 7adc65771676b11000f5553c13fb14523ed1993f # Parent c65119b66b007f9e5612b8dce4640cb9b86f9ee0 big restructuring - moved lots of things (including most panels) to other files diff --git a/light8/io.py b/light8/io.py --- a/light8/io.py +++ b/light8/io.py @@ -1,109 +1,17 @@ - -class BaseIO: - def __init__(self): - self.dummy=1 - self.__name__ = 'BaseIO' - # please override and set __name__ to your class name - - def golive(self): - """call this if you want to promote the dummy object becomes a live object""" - print "IO: %s is going live" % self.__name__ - self.dummy=0 - # you'd override with additional startup stuff here, - # perhaps even loading a module and saving it to a class - # attr so the subclass-specific functions can use it - - def godummy(self): - print "IO: %s is going dummy" % self.__name__ - self.dummy=1 - # you might override this to close ports, etc - - def isdummy(self): - return self.dummy +DUMMY=1 - def __repr__(self): - if self.dummy: - return "" % self.__name__ - else: - return "" % self.__name__ - - # the derived class will have more methods to do whatever it does, - # and they should return dummy values if self.dummy==1. - -class ParportDMX(BaseIO): - def __init__(self, dimmers=68): - BaseIO.__init__(self) - self.__name__='ParportDMX' - self.dimmers = dimmers - - def golive(self): - BaseIO.golive(self) - import parport - self.parport = parport - self.parport.getparport() - - def sendlevels(self, levels): - if self.dummy: - return - - levels = list(levels) + [0] - # if levels[14] > 0: levels[14] = 100 # non-dim - self.parport.outstart() - for p in range(1, self.dimmers + 2): - self.parport.outbyte(levels[p-1]*255 / 100) +def init(DUMMY_in): + global DUMMY + if not DUMMY_in: + getparport() + DUMMY=0 -class SerialPots(BaseIO): - """ - this is a dummy object (that returns zeros forever) until you call startup() - which makes it bind to the port, etc - - """ - def __init__(self): - # no init here- call getport() to actually initialize - self.dummy=1 - self.__name__='SerialPots' # i thought this was automatic! - - def golive(self): - """ - ls -l /dev/i2c-0 - crw-rw-rw- 1 root root 89, 0 Jul 11 12:27 /dev/i2c-0 - """ - import serport - self.serport = serport - - self.f = open("/dev/i2c-0","rw") - - # this is for a chip with A0,A1,A2 lines all low: - port = 72 - - from fcntl import * - - I2C_SLAVE = 0x0703 #/* Change slave address */ - ioctl(self.f,I2C_SLAVE,port) - self.dummy=0 - - def godummy(self): - BaseIO.godummy(self) - self.f.close() - - def getlevels(self): - if self.dummy: - return (0,0,0,0) - else: - return self.serport.read_all_adc(self.f.fileno()) - - -if __name__=='__main__': - - """ tester program that just dumps levels for a while """ - from time import sleep - from serport import * - - i=0 - while i<100: - sleep(.033) - i=i+1 - - print read_all_adc(f.fileno()) - +def sendlevels(levels): + if DUMMY: return + levels = list(levels) + [0] + if levels[14] > 0: levels[14] = 100 + # print "levels", ' '.join(["%3.1f" % l for l in levels]) + outstart() + for p in range(1,70): + outbyte(levels[p-1]*255/100) diff --git a/light8/panels.py b/light8/panels.py --- a/light8/panels.py +++ b/light8/panels.py @@ -1,19 +1,18 @@ """some of the panels""" -from __future__ import nested_scopes -from Tix import * +from Tkinter import * from uihelpers import * import Patch -from FlyingFader import FlyingFader stdfont = ('Arial', 8) monofont = ('Courier', 8) + + class Controlpanel(Frame): - def __init__(self, parent, xfader, refresh_cb, quit_cb, jostle_cb, - whatsup_cb=None): - Frame.__init__(self,parent, bg='black') - controlpanel = self + def __init__(self,parent,xfader,refresh_cb,quit_cb): + Frame.__init__(self,parent) + controlpanel=self for txt,cmd in ( ('Quit', quit_cb), ('Refresh', refresh_cb), @@ -21,181 +20,92 @@ class Controlpanel(Frame): ('On -> X', lambda: xfader.grab('x')), ('Clear X', lambda: xfader.clearallbuttons('x')), ('On -> Y', lambda: xfader.grab('y')), - ('Clear Y', lambda: xfader.clearallbuttons('y')), - ("What's up?", whatsup_cb)): - Button(controlpanel, text=txt, command=cmd, bg='black', - fg='white',font=stdfont, padx=0, pady=0).pack(side='top', fill='x') - # jostle button - Checkbutton(controlpanel, text="Jostle", bg='black', fg='white', - command=jostle_cb).pack(side=TOP, fill=X) + ('Clear Y', lambda: xfader.clearallbuttons('y'))): + Button(controlpanel, text=txt, command=cmd).pack(side='top', fill='x') + class Console: - def __init__(self,lightboard): - t=toplevelat('console') - self.frame = Frame(t, bg='black') - self.entry=Entry(self.frame, bg='black', fg='white') + def __init__(self): + print "Light 8: Everything's under control" + t=toplevelat(267,717,w=599,h=19) + self.frame = Frame(t) + self.entry=Entry(self.frame) self.entry.pack(expand=1, fill='x') - self.entry.bind('', - lambda evt: self.execute(evt, self.entry.get())) + self.entry.bind('', lambda evt: self.execute(evt, self.entry.get())) self.frame.pack(fill=BOTH, expand=1) - self.lightboard=lightboard - def execute(self, evt, str): - if str[0] == '*': # make a new sub from the current levels - self.lightboard.save_sub(str,self.lightboard.stageassub()) + def execute(evt, str): + if str[0] == '*': # make a new sub + make_sub(str) else: print '>>>', str print eval(str) - self.frame.focus() + self.frame.focus() class Leveldisplay: - def __init__(self, parent, channel_levels, num_channels=68): + def __init__(self,parent,_oldlevels): + global channel_levels + frames = (make_frame(parent), make_frame(parent)) - channel_levels[:]=[] - self.number_labels = [] - for channel in range(1, num_channels+1): - - # frame for this channel - f = Frame(frames[channel > (num_channels/2)]) - # channel number -- will turn yellow when being altered - num_lab = Label(f, text=str(channel), width=3, bg='grey40', - fg='white', font=stdfont, padx=0, pady=0, bd=0, height=1) - num_lab.pack(side='left') - self.number_labels.append(num_lab) - - # text description of channel - Label(f, text=Patch.get_channel_name(channel), width=8, - font=stdfont, anchor='w', padx=0, pady=0, bd=0, - height=1, bg='black', fg='white').pack(side='left') - - # current level of channel, shows intensity with color - l = Label(f, width=3, bg='lightBlue', font=stdfont, anchor='e', - padx=1, pady=0, bd=0, height=1) + channel_levels=[] + for channel in range(1, 69): + f=Frame(frames[channel > 34]) + Label(f,text=str(channel), width=3, bg='lightPink', + font=stdfont, padx=0, pady=0, bd=0, height=1).pack(side='left') + Label(f,text=Patch.get_channel_name(channel), width=8, + font=stdfont, anchor='w', padx=0, pady=0, bd=0, height=1).pack(side='left') + l=Label(f,text=_oldlevels[channel-1], width=3, bg='lightBlue', + font=stdfont, anchor='e', padx=1, pady=0, bd=0, height=1) l.pack(side='left') colorlabel(l) channel_levels.append(l) f.pack(side='top') - self.channel_levels = channel_levels - # channel_levels is an output - changelevel will use it to access - # these labels - class Subpanels: - def __init__(self, scenesparent, effectsparent, scenes, lightboard, - scalelevels, Subs, xfader, - changelevel, subediting, longestname): + def __init__(self,scenesparent,effectsparent,scalelevels,Subs,xfader,changelevel): sublist = Subs.subs.items() sublist.sort() - for p in scenesparent,effectsparent,scenes: - sw = ScrolledWindow(p, bg='black') - for but,units in ( (4,-4),(5,4) ): - sw.window.bind(""%but,lambda ev,s=sw.vsb,u=units: s.tk.call('tkScrollByUnits',s,'hv',u)) - - sw.pack(expand=1,fill=BOTH) - if p==scenesparent: - scenesparent = sw.window - elif p==effectsparent: - effectsparent = sw.window - else: - scenes=sw.window - for name, sub in sublist: - # choose one of the sub panels to add to if sub.is_effect: parent=effectsparent - side1='bottom' - side2='left' - orient1='vert' - end1=0 - end2=1 - width1=len(name) - elif name.startswith("*") and name[1].isdigit(): - parent=scenes - side1='right' - side2='top' - orient1='horiz' - end1=1 - end2=0 - width1=longestname else: parent=scenesparent - side1='right' - side2='top' - orient1='horiz' - end1=1 - end2=0 - width1=longestname - # make frame that surrounds the whole submaster - f=Frame(parent, bd=1, relief='raised', bg='black') - f.pack(fill='both',exp=1,side=side2) - + f=Frame(parent, bd=1, relief='raised') + f.pack(fill='both',exp=1,side='left') - # make DoubleVar (there might be one left around from - # before a refresh) if name not in scalelevels: - # scalelevels[name]=FancyDoubleVar() scalelevels[name]=DoubleVar() sub.set_slider_var(scalelevels[name]) - scaleopts = {'troughcolor' : 'grey70'} + scaleopts = {} if sub.color: scaleopts['troughcolor'] = sub.color + s=Scale(f,command=lambda l,name=name: changelevel(name,l),showvalue=0, + length=300-17,variable=scalelevels[name],width=20, + to=0,res=.001,from_=1,bd=1, **scaleopts) + l=Label(f,text=str(name), font=stdfont, padx=0, pady=0) + v=Label(f,textvariable=scalelevels[name], font=stdfont, padx=0, pady=0) + l.pack(side='bottom') + v.pack(side='bottom') - s = FlyingFader(f, label=str(name), variable=scalelevels[name], - showvalue=0, length=100, - width=14, sliderlength=14, - to=end1,res=.001,from_=end2,bd=1, font=stdfont, - orient=orient1, - labelwidth=width1, - **scaleopts) - s.configure(bg='black') - s.label.configure(bg='black', fg='white') - s.vlabel.configure(bg='black', fg='white') - s.scale.configure(bg='black', fg='white') + for axis in ('y','x'): + cvar=IntVar() + cb=Checkbutton(f,text=axis,variable=cvar,font=stdfont, padx=0, pady=0, bd=1) + button = ('Alt','Control')[axis=='y'] # unused? + # s.bind(''%axis, lambda ev,cb=cb: cb.invoke) + cb.pack(side='bottom',fill='both', padx=0, pady=0) + xfader.registerbutton(name,axis,cvar) - # tell subediting what widgets to highlight when it's - # editing a sub - for w in (s,s.label,s.vlabel, s.scale): - subediting.register(subname=name,widget=w) - - if not sub.is_effect: - self.subeditingbuttons(f,side1,sub,name,lightboard,subediting) - - self.axisbuttons(f,s,xfader,stdfont,side1,name) - - s.pack(side='left', fill=BOTH, expand=1) + s.pack(side='left') + s.bind('<3>', lambda evt, v=scalelevels[name]: toggle_slider(v))\ # effects frame? sframe = Frame(f,bd=2,relief='groove') sub.draw_tk(sframe) sframe.pack(side='left',fill='y') - def subediting_edit(self,subediting,sub): - subediting.setsub(sub) - - def subediting_save(self,name,sub,lightboard): - lightboard.save_sub(name,sub.getlevels(),refresh=0) - - def subeditingbuttons(self,f,side1,sub,name,lightboard,subediting): - for txt,cmd in (("Edit",lambda subediting=subediting,sub=sub: self.subediting_edit(subediting,sub)), - ("Save",lambda sub=sub,name=name,lightboard=lightboard: self.subediting_save(name,sub,lightboard)), - ("SaveStg",lambda l=lightboard,name=name: l.save_sub(name,l.stageassub(),refresh=1)), - ): - eb = Button(f,text=txt,font=stdfont,padx=0,pady=0, - bd=1,command=cmd, bg='black', fg='white') - eb.pack(side=side1,fill='both',padx=0,pady=0) - - def axisbuttons(self,f,s,xfader,stdfont,side1,name): - for axis in ('y','x'): - cvar=IntVar() - eb_color = ('red', 'green')[axis == 'y'] - cb=Togglebutton(f,text=axis.upper(),variable=cvar,font=stdfont, - padx=3, pady=0, bd=1, downcolor=eb_color, - bg='black', fg='white') - cb.pack(side=side1,fill='both', padx=0, pady=0) - s.bind(''%axis, lambda ev,cb=cb: cb.invoke) - xfader.registerbutton(name,axis,cvar) + diff --git a/light8/rsn.py b/light8/rsn.py --- a/light8/rsn.py +++ b/light8/rsn.py @@ -7,7 +7,11 @@ from time import sleep from signal import * import sys, thread, cPickle +import io +from uihelpers import * +from panels import * from Xfader import * +import stage if len(sys.argv) >= 2: DUMMY = 0 @@ -32,32 +36,11 @@ def get_data(*args): get_data() -if not DUMMY: - getparport() - -def sendlevels(levels): - if DUMMY: return - levels = list(levels) + [0] - if levels[14] > 0: levels[14] = 100 - # print "levels", ' '.join(["%3.1f" % l for l in levels]) - outstart() - for p in range(1,70): - outbyte(levels[p-1]*255/100) +io.init(DUMMY) channel_levels = [] scalelevels = {} fades = {} -stdfont = ('Arial', 8) -monofont = ('Courier', 8) - -def colorlabel(label): - txt=label['text'] or "0" - lev=float(txt)/100 - low=(80,80,180) - high=(255,55,050) - out = [int(l+lev*(h-l)) for h,l in zip(high,low)] - col="#%02X%02X%02X" % tuple(out) - label.config(bg=col) _oldlevels=[None] * 68 @@ -80,45 +63,17 @@ def changelevel(*args): _oldlevels = levels[:] - sendlevels(levels) + io.sendlevels(levels) def backgroundloop(*args): root.after(50, backgroundloop, ()) changelevel() - -def make_frame(parent): - f = Frame(parent, bd=0) - f.pack(side='left') - return f - -def add_fade(slider, evt): - print 'b3!' - -def execute(evt, str): - if str[0] == '*': # make a new sub - make_sub(str) - else: - print '>>>', str - print eval(str) - console_frame.focus() - -def console(): - global console_entry, console_frame - print "Light 8: Everything's under control" - t=Toplevel(root) - console_frame = Frame(t) - console_entry=Entry(console_frame) - console_entry.pack(expand=1, fill='x') - console_entry.bind('', lambda evt: execute(evt, - console_entry.get())) - console_frame.pack(fill=BOTH, expand=1) - t.wm_geometry("599x19+267+717") buildinterface = None # temporary def refresh(*args): get_data() buildinterface() - bindkeys('', quit) + bindkeys(root,'', quit) def quit(*args): filename = '/tmp/light9.prefs' @@ -130,117 +85,42 @@ def quit(*args): root.destroy() sys.exit() -def bindkeys(key, func): - root.bind(key, func) - for w in root.winfo_children(): - w.bind(key, func) + +xfader=Xfader(scalelevels) -def toggle_slider(s): - if s.get() == 0: - s.set(100) - else: - s.set(0) -def printout(t): - print t - -xfader=Xfader(scalelevels) def buildinterface(*args): - global channel_levels, _oldlevels, leveldisplay, stdfont, monofnt, xfader + global channel_levels, _oldlevels, leveldisplay, xfader for w in root.winfo_children(): w.destroy() - sublist = Subs.subs.items() - sublist.sort() - - sub_tl = Toplevel() - sub_tl.wm_geometry("+0+0") - effect_tl = Toplevel() - effect_tl.wm_geometry("+0+352") - - for name, sub in sublist: - if sub.is_effect: - f=Frame(effect_tl, bd=1, relief='raised') - else: - f=Frame(sub_tl, bd=1, relief='raised') - - f.pack(fill='both',exp=1,side='left') - - if name not in scalelevels: - scalelevels[name]=DoubleVar() - - sub.set_slider_var(scalelevels[name]) + stage_tl=toplevelat(165,90) + s=stage.Stage(stage_tl) + stage.createlights(s) + s.pack() - scaleopts = {} - if sub.color: - scaleopts['troughcolor'] = sub.color - s=Scale(f,command=lambda l,name=name: changelevel(name,l),showvalue=0, - length=300-17,variable=scalelevels[name],width=20, - to=0,res=.001,from_=1,bd=1, **scaleopts) - l=Label(f,text=str(name), font=stdfont, padx=0, pady=0) - v=Label(f,textvariable=scalelevels[name], font=stdfont, padx=0, pady=0) - l.pack(side='bottom') - v.pack(side='bottom') + sub_tl = toplevelat(0,0) + effect_tl = toplevelat(0,352) - for axis in ('y','x'): - cvar=IntVar() - cb=Checkbutton(f,text=axis,variable=cvar,font=stdfont, padx=0, pady=0, bd=1) - button = ('Alt','Control')[axis=='y'] # unused? -# s.bind(''%axis, lambda ev,cb=cb: cb.invoke) - cb.pack(side='bottom',fill='both', padx=0, pady=0) - xfader.registerbutton(name,axis,cvar) - - s.pack(side='left') - s.bind('<3>', lambda evt, v=scalelevels[name]: toggle_slider(v))\ - - sframe = Frame(f,bd=2,relief='groove') - sub.draw_tk(sframe) - sframe.pack(side='left',fill='y') + Subpanels(sub_tl,effect_tl,scalelevels,Subs,xfader,changelevel) # def event_printer(evt): # print dir(evt) # sub_tl.bind('', event_printer) - leveldisplay=Toplevel(root) + leveldisplay=toplevelat(873,400) leveldisplay.bind('', sys.exit) - leveldisplay.wm_geometry('+873+400') - frames = (make_frame(leveldisplay), make_frame(leveldisplay)) - channel_levels=[] - for channel in range(1, 69): - f=Frame(frames[channel > 34]) - Label(f,text=str(channel), width=3, bg='lightPink', - font=stdfont, padx=0, pady=0, bd=0, height=1).pack(side='left') - Label(f,text=Patch.get_channel_name(channel), width=8, - font=stdfont, anchor='w', padx=0, pady=0, bd=0, height=1).pack(side='left') - l=Label(f,text=_oldlevels[channel-1], width=3, bg='lightBlue', - font=stdfont, anchor='e', padx=1, pady=0, bd=0, height=1) - l.pack(side='left') - colorlabel(l) - channel_levels.append(l) - f.pack(side='top') - - console() + + Leveldisplay(leveldisplay,_oldlevels) + + Console() # root frame - controlpanel = Frame(root) - xf=Frame(controlpanel) + controlpanel = Controlpanel(root,xfader,refresh,quit) + + xf=Frame(root) xf.pack(side='right') - for txt,cmd in ( - ('Quit', quit), - ('Refresh', refresh), - ('Clear all', xfader.clearallbuttons), - ('On -> X', lambda: xfader.grab('x')), - ('Clear X', lambda: xfader.clearallbuttons('x')), - ('On -> Y', lambda: xfader.grab('y')), - ('Clear Y', lambda: xfader.clearallbuttons('y'))): - Button(controlpanel, text=txt, command=cmd).pack(side='top', fill='x') - - # Button(controlpanel, text='Quit', command=quit).pack(side='left') - # Button(controlpanel, text='Refresh', command=refresh).pack(side='left') - # Button(controlpanel, text='Clearxfade', command=xfader.clearallbuttons).pack(side='left') - # Button(controlpanel, text='Grab x', command=lambda: xfader.grab('x')).pack(side='left') - # Button(controlpanel, text='Grab y', command=lambda: xfader.grab('y')).pack(side='left') root.bind('', quit) root.bind('', refresh) @@ -250,6 +130,7 @@ def buildinterface(*args): xfader.setupwidget(xf) controlpanel.pack() + buildinterface() class Pickles: @@ -304,11 +185,11 @@ def make_sub(name): load() signal(SIGINT, quit) -bindkeys('', quit) +bindkeys(root,'', quit) -# bindkeys('', quit) -# bindkeys('', refresh) -# bindkeys('', make_sub) +# bindkeys(root,'', quit) +# bindkeys(root,'', refresh) +# bindkeys(root,'', make_sub) backgroundloop() root.mainloop() # Receiver switches main diff --git a/light8/uihelpers.py b/light8/uihelpers.py --- a/light8/uihelpers.py +++ b/light8/uihelpers.py @@ -1,63 +1,27 @@ """all the tiny tk helper functions""" -from __future__ import nested_scopes from Tkinter import * -from Tix import * -from types import StringType - -windowlocations = { - 'sub' : '425x738+00+00', - 'console' : '168x24+848+000', - 'leveldisplay' : '144x340+870+400', - 'cuefader' : '314x212+546+741', - 'effect' : '24x24+0963+338', - 'stage' : '823x683+37+030', - 'scenes' : '504x198+462+12', -} def make_frame(parent): - f = Frame(parent, bd=0, bg='black') + f = Frame(parent, bd=0) f.pack(side='left') return f + def bindkeys(root,key, func): root.bind(key, func) for w in root.winfo_children(): w.bind(key, func) -def toplevel_savegeometry(tl,name): - try: - geo = tl.geometry() - if not geo.startswith("1x1"): - f=open(".light9-window-geometry-%s" % name.replace(' ','_'),'w') - f.write(tl.geometry()) - # else the window never got mapped - except: - # it's ok if there's no saved geometry - pass - - # this would get called repeatedly for each child of the window (i - # dont know why) so we unbind after the first Destroy event - tl.unbind("",tl._toplevelat_funcid) +def toplevelat(x,y,w=None,h=None): + tl=Toplevel() + if w and h: + tl.wm_geometry("%dx%d+%d+%d"%(w,h,x,y)) + else: + tl.wm_geometry("+%d+%d"%(x,y)) + return tl -def toplevelat(name, existingtoplevel=None): - tl = existingtoplevel or Toplevel() - tl.title(name) - - try: - f=open(".light9-window-geometry-%s" % name.replace(' ','_')) - windowlocations[name]=f.read() # file has no newline - except: - # it's ok if there's no saved geometry - pass - - if name in windowlocations: - tl.geometry(windowlocations[name]) - - tl._toplevelat_funcid=tl.bind("",lambda ev,tl=tl,name=name: toplevel_savegeometry(tl,name)) - - return tl def toggle_slider(s): if s.get() == 0: @@ -68,28 +32,7 @@ def toggle_slider(s): # for lambda callbacks def printout(t): print t - -def printevent(ev): - for k in dir(ev): - if not k.startswith('__'): - print k,getattr(ev,k) - print "" -def eventtoparent(ev,sequence): - "passes an event to the parent, screws up TixComboBoxes" - - wid_class = str(ev.widget.__class__) - if wid_class == 'Tix.ComboBox' or wid_class == 'Tix.TixSubWidget': - return - - evdict={} - for x in ['state', 'time', 'y', 'x', 'serial']: - evdict[x]=getattr(ev,x) -# evdict['button']=ev.num - par=ev.widget.winfo_parent() - if par!=".": - ev.widget.nametowidget(par).event_generate(sequence,**evdict) - #else the event made it all the way to the top, unhandled def colorlabel(label): """color a label based on its own text""" @@ -100,132 +43,3 @@ def colorlabel(label): out = [int(l+lev*(h-l)) for h,l in zip(high,low)] col="#%02X%02X%02X" % tuple(out) label.config(bg=col) - -# TODO: get everyone to use this -def colorfade(low, high, percent): - '''not foolproof. make sure 0 < percent < 1''' - out = [int(l+percent*(h-l)) for h,l in zip(high,low)] - col="#%02X%02X%02X" % tuple(out) - return col - -def colortotuple(anytkobj, colorname): - 'pass any tk object and a color name, like "yellow"' - rgb = anytkobj.winfo_rgb(colorname) - return [v / 256 for v in rgb] - -class Togglebutton(Button): - """works like a single radiobutton, but it's a button so the - label's on the button face, not to the side. the optional command - callback is called on button set, not on unset. takes a variable - just like a checkbutton""" - def __init__(self,parent,variable=None,command=None,downcolor='red',**kw): - - self.oldcommand = command - Button.__init__(self,parent,command=self.invoke,**kw) - - self._origbkg = self.cget('bg') - self.downcolor = downcolor - - self._variable = variable - if self._variable: - self._variable.trace('w',self._varchanged) - self._setstate(self._variable.get()) - else: - self._setstate(0) - - self.bind("",self.invoke) - self.bind("<1>",self.invoke) - self.bind("",self.invoke) - - def _varchanged(self,*args): - self._setstate(self._variable.get()) - - def invoke(self,*ev): - if self._variable: - self._variable.set(not self.state) - else: - self._setstate(not self.state) - - if self.oldcommand and self.state: # call command only when state goes to 1 - self.oldcommand() - return "break" - - def _setstate(self,newstate): - self.state = newstate - if newstate: # set - self.config(bg=self.downcolor,relief='sunken') - else: # unset - self.config(bg=self._origbkg,relief='raised') - return "break" - - -class FancyDoubleVar(DoubleVar): - def __init__(self,master=None): - DoubleVar.__init__(self,master) - self.callbacklist = {} # cbname : mode - self.namedtraces = {} # name : cbname - def trace_variable(self,mode,callback): - """Define a trace callback for the variable. - - MODE is one of "r", "w", "u" for read, write, undefine. - CALLBACK must be a function which is called when - the variable is read, written or undefined. - - Return the name of the callback. - """ - cbname = self._master._register(callback) - self._tk.call("trace", "variable", self._name, mode, cbname) - - # we build a list of the trace callbacks (the py functrions and the tcl functionnames) - self.callbacklist[cbname] = mode -# print "added trace:",callback,cbname - - return cbname - trace=trace_variable - def disable_traces(self): - for cb,mode in self.callbacklist.items(): -# DoubleVar.trace_vdelete(self,v[0],k) - self._tk.call("trace", "vdelete", self._name, mode,cb) - # but no master delete! - - def recreate_traces(self): - for cb,mode in self.callbacklist.items(): -# self.trace_variable(v[0],v[1]) - self._tk.call("trace", "variable", self._name, mode,cb) - - def trace_named(self, name, callback): - if name in self.namedtraces: - print "FancyDoubleVar: already had a trace named %s - replacing it" % name - self.delete_named(name) - - cbname = self.trace_variable('w',callback) # this will register in self.callbacklist too - - self.namedtraces[name] = cbname - return cbname - - def delete_named(self, name): - if name in self.namedtraces: - - cbname = self.namedtraces[name] - - self.trace_vdelete('w',cbname) - #self._tk.call("trace","vdelete",self._name,'w',cbname) - print "FancyDoubleVar: successfully deleted trace named %s" % name - else: - print "FancyDoubleVar: attempted to delete named %s which wasn't set to any function" % name - -def get_selection(listbox): - 'Given a listbox, returns first selection as integer' - selection = int(listbox.curselection()[0]) # blech - return selection - -if __name__=='__main__': - root=Tk() - root.tk_focusFollowsMouse() - iv=IntVar() - def cb(): - print "cb!" - t = Togglebutton(root,text="testbutton",command=cb,variable=iv) - t.pack() - Entry(root,textvariable=iv).pack() - root.mainloop()