diff light8/uihelpers.py @ 0:45b12307c695

Initial revision
author drewp
date Wed, 03 Jul 2002 09:37:57 +0000
parents
children 7adc65771676
line wrap: on
line diff
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/light8/uihelpers.py	Wed Jul 03 09:37:57 2002 +0000
@@ -0,0 +1,231 @@
+"""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.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("<Destroy>",tl._toplevelat_funcid)
+
+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("<Destroy>",lambda ev,tl=tl,name=name: toplevel_savegeometry(tl,name))
+
+    return tl
+
+def toggle_slider(s):
+    if s.get() == 0:
+        s.set(100)
+    else:
+        s.set(0)
+
+# 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"""
+    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)
+
+# 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("<Return>",self.invoke)
+        self.bind("<1>",self.invoke)
+        self.bind("<space>",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()