Files
@ e3a92ccea4be
Branch filter:
Location: light9/flax/CueFaders.py
e3a92ccea4be
8.2 KiB
text/x-python
add cuisine path
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 168 169 170 171 172 173 174 175 176 177 178 179 180 181 182 183 184 185 186 187 188 189 190 191 192 193 194 195 196 197 198 199 200 201 202 203 204 205 206 207 208 209 210 211 212 213 214 215 216 217 218 219 220 221 222 223 224 225 226 227 228 229 230 231 | from __future__ import division, nested_scopes
import Tix as Tk
import time
from TreeDict import TreeDict, allow_class_to_be_pickled
class LabelledScale(Tk.Frame):
"""Scale with two labels: a name and current value"""
def __init__(self, master, label, **opts):
Tk.Frame.__init__(self, master, bd=2, relief='raised')
opts.setdefault('variable', Tk.DoubleVar())
opts.setdefault('showvalue', 0)
self.scale_var = opts['variable']
self.scale = Tk.Scale(self, **opts)
self.scale.pack(side='top', expand=1, fill='both')
self.name = Tk.Label(self, text=label)
self.name.pack(side='bottom')
self.scale_value = Tk.Label(self, width=6)
self.scale_value.pack(side='bottom')
self.scale_var.trace('w', self.update_value_label)
self.update_value_label()
def set_label(self, label):
self.name['text'] = label
def update_value_label(self, *args):
val = self.scale_var.get() * 100
self.scale_value['text'] = "%0.2f" % val
class TimedGoButton(Tk.Frame):
"""Go button, fade time entry, and time fader"""
def __init__(self, master, name, scale_to_fade):
Tk.Frame.__init__(self, master)
self.name = name
self.scale_to_fade = scale_to_fade
self.button = Tk.Button(self, text=name, command=self.start_fade)
self.button.pack(fill='both', expand=1, side='left')
self.timer_var = Tk.StringVar()
self.timer_entry = Tk.Entry(self, textvariable=self.timer_var, width=5)
self.timer_entry.pack(fill='y', side='left')
self.timer_var.set("2")
def start_fade(self, end_level=1):
try:
fade_time = float(self.timer_var.get())
except ValueError:
# TODO figure out how to handle this
print "can't fade -- bad time"
return
self.start_time = time.time()
self.start_level = self.scale_to_fade.scale_var.get()
self.end_level = end_level
self.fade_length = fade_time
self.do_fade()
def do_fade(self):
diff = time.time() - self.start_time
if diff < self.fade_length:
percent = diff / self.fade_length
newlevel = self.start_level + \
(percent * (self.end_level - self.start_level))
self.scale_to_fade.scale_var.set(newlevel)
if newlevel != self.end_level:
self.after(10, self.do_fade)
else:
self.scale_to_fade.scale_var.set(self.end_level)
class CueFader(Tk.Frame):
def __init__(self, master, cuelist):
Tk.Frame.__init__(self, master)
self.cuelist = cuelist
self.auto_shift = 0
self.scales = {}
self.shift_buttons = {}
topframe = Tk.Frame(self)
self.current_cues = Tk.Label(topframe)
self.current_cues.pack()
self.update_cue_display()
topframe.pack()
for name, start, end, side in (('Prev', 1, 0, 'left'),
('Next', 0, 1, 'right')):
shift = Tk.Button(self, text="Shift %s" % name, state='disabled',
command=lambda name=name: self.shift(name))
shift.pack(side=side, fill='both', expand=1)
frame = Tk.Frame(self)
scale = LabelledScale(frame, name, from_=start, to_=end,
res=0.01, orient='horiz')
scale.pack(fill='both', expand=1)
go = TimedGoButton(frame, 'Go %s' % name, scale)
go.pack(fill='both', expand=1)
frame.pack(side=side, fill='both', expand=1)
self.scales[name] = scale
self.shift_buttons[name] = shift
scale.scale_var.trace('w', \
lambda x, y, z, name=name, scale=scale: self.xfade(name, scale))
def shift(self, name):
for scale in self.scales.values():
scale.scale_var.set(0)
if name == 'Next': scale.update()
print "shift", name
self.cuelist.shift((-1, 1)[name == 'Next'])
self.update_cue_display()
def update_cue_display(self):
current_cues = [cue.name for cue in self.cuelist.get_current_cues()]
self.current_cues['text'] = ', '.join(current_cues)
def xfade(self, name, scale):
scale_val = scale.scale_var.get()
if scale_val == 1:
if self.auto_shift:
self.shift(name)
else:
self.shift_buttons[name]['state'] = 'normal'
else:
# disable any dangerous shifting
self.shift_buttons[name]['state'] = 'disabled'
if scale_val != 0:
# disable illegal three part crossfades
# TODO:
# if name == 'Next':
# disable go_prev button and slider, lock slider at 0
pass
else:
# undo above changes
# Actually, TimedGoButton and LabelledScale can have enable/disable
# methods which will only do the Tk calls if necessary
pass
class Cue:
"""A Cue has a name, a time, and any number of other attributes."""
def __init__(self, name, time=3, **attrs):
self.name = name
self.time = time
self.__dict__.update(attrs)
def __repr__(self):
return "<Cue %s, length %s>" % (self.name, self.time)
empty_cue = Cue('empty')
allow_class_to_be_pickled(Cue)
class CueList:
"""Persistent list of Cues"""
def __init__(self, filename):
self.filename = filename
self.treedict = TreeDict()
try:
self.treedict.load(filename)
except IOError:
self.treedict.cues = []
self.cues = self.treedict.cues
self.current_cue_index = 0
self.next_pointer = None
self.prev_pointer = None
import atexit
atexit.register(self.save)
def add_cue(self, cue, index=None):
"""Adds a Cue object to the list. If no index is specified,
the cue will be added to the end."""
index = index or len(self.cues)
self.cues.insert(index, cue)
def shift(self, diff):
"""Shift through cue history"""
old_index = self.current_cue_index
self.current_cue_index = None
if diff < 0: # if going backwards
if self.prev_pointer: # use a prev pointer if we have one
self.current_cue_index = self.prev_pointer
self.next_pointer = old_index
self.prev_pointer = None
else:
if self.next_pointer: # use a next pointer if we have one
self.current_cue_index = self.next_pointer
self.next_pointer = None
self.prev_pointer = old_index
if not self.current_cue_index:
self.current_cue_index = old_index + diff
def set_next(self, index):
self.next_pointer = index
def set_prev(self, index):
self.prev_pointer = index
def bound_index(self, index):
if not self.cues:
return None
else:
return max(0, min(index, len(self.cues)))
def get_current_cue_indices(self):
cur = self.current_cue_index
return [self.bound_index(index) for index in
(self.prev_pointer or cur - 1,
cur,
self.next_pointer or cur + 1)]
def get_current_cues(self):
# print "get_current_cue_indices", self.get_current_cue_indices()
return [self.get_cue_by_index(index)
for index in self.get_current_cue_indices()]
def get_cue_by_index(self, index):
# print "get_cue_by_index", index
if index:
return self.cues[self.bound_index(index)]
else:
return empty_cue
def __del__(self):
self.save()
def save(self):
self.treedict.save(self.filename)
if __name__ == "__main__":
if 0:
z = CueList('cues/cuelist1')
z.add_cue(Cue('cue %s' % time.asctime(), time=2, a=7, b=8))
print 'cues', z.cues
else:
cl = CueList('cues/cuelist1')
# to populate cue list
if 0:
for x in range(20):
cl.add_cue(Cue('cue %d' % x, time=x, some_attribute=3))
root = Tk.Tk()
fader = CueFader(root, cl)
fader.pack(fill='both', expand=1)
Tk.mainloop()
|