diff flax/KeyboardComposer.py @ 0:45b12307c695

Initial revision
author drewp
date Wed, 03 Jul 2002 09:37:57 +0000
parents
children 0c619695d6c6
line wrap: on
line diff
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/flax/KeyboardComposer.py	Wed Jul 03 09:37:57 2002 +0000
@@ -0,0 +1,251 @@
+from __future__ import nested_scopes
+import sys, time
+sys.path.append('..')
+from Widgets.Fadable import Fadable
+
+from Tix import *
+import math, atexit, pickle
+from Submaster import Submasters, sub_maxes
+import dmxclient
+from uihelpers import toplevelat
+
+nudge_keys = {
+    'up' : list('qwertyuiop'),
+    'down' : list('asdfghjkl')
+}
+nudge_keys['down'].append('semicolon')
+
+class SubScale(Scale, Fadable):
+    def __init__(self, master, *args, **kw):
+        self.scale_var = kw.get('variable') or DoubleVar()
+        kw.update({'variable' : self.scale_var,
+                   'from' : 1, 'to' : 0, 'showvalue' : 0,
+                   'sliderlength' : 15, 'res' : 0.01,
+                   'width' : 40, 'troughcolor' : 'black', 'bg' : 'grey40',
+                   'highlightthickness' : 1, 'bd' : 1,
+                   'highlightcolor' : 'red', 'highlightbackground' : 'black',
+                   'activebackground' : 'red'})
+        Scale.__init__(self, master, *args, **kw)
+        Fadable.__init__(self, var=self.scale_var, wheel_step=0.05)
+        self.draw_indicator_colors()
+    def draw_indicator_colors(self):
+        if self.scale_var.get() == 0:
+            self['troughcolor'] = 'black'
+        else:
+            self['troughcolor'] = 'blue'
+
+class SubmasterTk(Frame):
+    def __init__(self, master, name, current_level):
+        Frame.__init__(self, master, bd=1, relief='raised', bg='black')
+        self.slider_var = DoubleVar()
+        self.slider_var.set(current_level)
+        self.scale = SubScale(self, variable=self.slider_var, width=20)
+        namelabel = Label(self, text=name, font="Arial 8", bg='black',
+            fg='white')
+        namelabel.pack(side=TOP)
+        levellabel = Label(self, textvariable=self.slider_var, font="Arial 8",
+            bg='black', fg='white')
+        levellabel.pack(side=TOP)
+        self.scale.pack(side=BOTTOM, expand=1, fill=BOTH)
+
+class KeyboardComposer(Frame):
+    def __init__(self, root, submasters, current_sub_levels=None, dmxdummy=0):
+        Frame.__init__(self, root, bg='black')
+        self.submasters = submasters
+        self.dmxdummy = dmxdummy
+
+        self.current_sub_levels = {}
+        if current_sub_levels:
+            self.current_sub_levels = current_sub_levels
+        else:
+            try:
+                self.current_sub_levels = \
+                    pickle.load(file('.keyboardcomposer.savedlevels'))
+            except IOError:
+                pass
+
+        self.draw_ui()
+        self.send_levels_loop()
+    def draw_ui(self):
+        self.rows = [] # this holds Tk Frames for each row
+        self.slider_vars = {} # this holds subname:sub Tk vars
+        self.slider_table = {} # this holds coords:sub Tk vars
+        self.current_row = 0
+        
+        self.make_key_hints()
+        self.draw_sliders()
+        self.highlight_row(self.current_row)
+        self.rows[self.current_row].focus()
+
+        self.buttonframe = Frame(self, bg='black')
+        self.buttonframe.pack(side=BOTTOM)
+        self.refreshbutton = Button(self.buttonframe, text="Refresh", 
+            command=self.refresh, bg='black', fg='white')
+        self.refreshbutton.pack(side=LEFT)
+        self.save_stage_button = Button(self.buttonframe, text="Save", 
+            command=lambda: self.save_current_stage(self.sub_name.get()), 
+            bg='black', fg='white')
+        self.save_stage_button.pack(side=LEFT)
+        self.sub_name = Entry(self.buttonframe, bg='black', fg='white')
+        self.sub_name.pack(side=LEFT)
+        self.stop_frequent_update_time = 0
+    def make_key_hints(self):
+        keyhintrow = Frame(self)
+
+        col = 0
+        for upkey, downkey in zip(nudge_keys['up'],
+                                  nudge_keys['down']):
+            # what a hack!
+            downkey = downkey.replace('semicolon', ';')
+            upkey, downkey = (upkey.upper(), downkey.upper())
+
+            # another what a hack!
+            keylabel = Label(keyhintrow, text='%s\n%s' % (upkey, downkey), 
+                width=1, font=('Arial', 10), bg='red', fg='white', anchor='c')
+            keylabel.pack(side=LEFT, expand=1, fill=X)
+            col += 1
+
+        keyhintrow.pack(fill=X, expand=0)
+        self.keyhints = keyhintrow
+    def setup_key_nudgers(self, tkobject):
+        for d, keys in nudge_keys.items():
+            for key in keys:
+                # lowercase makes full=0
+                keysym = "<KeyPress-%s>" % key
+                tkobject.bind(keysym, \
+                    lambda evt, num=keys.index(key), d=d: \
+                        self.got_nudger(num, d))
+
+                # uppercase makes full=1
+                keysym = "<KeyPress-%s>" % key.upper()
+                keysym = keysym.replace('SEMICOLON', 'colon')
+                tkobject.bind(keysym, \
+                    lambda evt, num=keys.index(key), d=d: \
+                        self.got_nudger(num, d, full=1))
+
+        # page up and page down change the row
+        for key in '<Prior> <Next> <Control-n> <Control-p>'.split():
+            tkobject.bind(key, self.change_row)
+
+    def change_row(self, event):
+        diff = 1
+        if event.keysym in ('Prior', 'p'):
+            diff = -1
+        old_row = self.current_row
+        self.current_row += diff
+        self.current_row = max(0, self.current_row)
+        self.current_row = min(len(self.rows) - 1, self.current_row)
+        self.unhighlight_row(old_row)
+        self.highlight_row(self.current_row)
+        row = self.rows[self.current_row]
+        self.keyhints.pack_configure(before=row)
+    def got_nudger(self, number, direction, full=0):
+        subtk = self.slider_table[(self.current_row, number)]
+        if direction == 'up':
+            if full:
+                subtk.scale.fade(1)
+            else:
+                subtk.scale.increase()
+        else:
+            if full:
+                subtk.scale.fade(0)
+            else:
+                subtk.scale.decrease()
+    def draw_sliders(self):
+        self.tk_focusFollowsMouse()
+
+        rowcount = -1
+        col = 0
+        for sub in self.submasters.get_all_subs():
+            if col == 0: # make new row
+                row = self.make_row()
+                rowcount += 1
+            current_level = self.current_sub_levels.get(sub.name, 0)
+            subtk = self.draw_sub_slider(row, col, sub.name, current_level)
+            self.slider_table[(rowcount, col)] = subtk
+            col += 1
+            col %= 10
+
+            def slider_changed(x, y, z, subtk=subtk):
+                subtk.scale.draw_indicator_colors()
+                self.send_levels()
+
+            subtk.slider_var.trace('w', slider_changed)
+    def make_row(self):
+        row = Frame(self, bd=2, bg='black')
+        row.pack(expand=1, fill=BOTH)
+        self.setup_key_nudgers(row)
+        self.rows.append(row)
+        return row
+    def draw_sub_slider(self, row, col, name, current_level):
+        subtk = SubmasterTk(row, name, current_level)
+        subtk.place(relx=col * 0.1, rely=0, relwidth=0.1, relheight=1)
+        self.setup_key_nudgers(subtk.scale)
+
+        self.slider_vars[name] = subtk.slider_var
+        return subtk
+    def highlight_row(self, row):
+        row = self.rows[row]
+        row['bg'] = 'red'
+    def unhighlight_row(self, row):
+        row = self.rows[row]
+        row['bg'] = 'black'
+    def get_levels(self):
+        return dict([(name, slidervar.get()) 
+            for name, slidervar in self.slider_vars.items()])
+    def get_levels_as_sub(self):
+        scaledsubs = [self.submasters.get_sub_by_name(sub) * level \
+            for sub, level in self.get_levels().items()]
+
+        maxes = sub_maxes(*scaledsubs)
+        return maxes
+    def save_current_stage(self, subname):
+        print "saving current levels as", subname
+        sub = self.get_levels_as_sub()
+        sub.name = subname
+        sub.save()
+
+    def save(self):
+        pickle.dump(self.get_levels(), 
+                    file('.keyboardcomposer.savedlevels', 'w'))
+    def send_frequent_updates(self):
+        """called when we get a fade -- send events as quickly as possible"""
+        if time.time() <= self.stop_frequent_update_time:
+            self.send_levels()
+            self.after(10, self.send_frequent_updates)
+
+    def get_dmx_list(self):
+        maxes = self.get_levels_as_sub()
+        return maxes.get_dmx_list()
+    def send_levels(self):
+        if not self.dmxdummy:
+            levels = self.get_dmx_list()
+            dmxclient.outputlevels(levels)
+        # print "sending levels", levels
+    def send_levels_loop(self):
+        self.send_levels()
+        self.after(1000, self.send_levels_loop)
+    def refresh(self):
+        self.save()
+        self.submasters = Submasters()
+        self.current_sub_levels = \
+            pickle.load(file('.keyboardcomposer.savedlevels'))
+        for r in self.rows:
+            r.destroy()
+        self.keyhints.destroy()
+        self.buttonframe.destroy()
+        self.draw_ui()
+
+if __name__ == "__main__":
+    s = Submasters()
+
+    root = Tk()
+    tl = toplevelat("Keyboard Composer", existingtoplevel=root)
+    kc = KeyboardComposer(tl, s, dmxdummy=0)
+    kc.pack(fill=BOTH, expand=1)
+    atexit.register(kc.save)
+    try:
+        mainloop()
+    except KeyboardInterrupt:
+        tl.destroy()
+        sys.exit()