Mercurial > code > home > repos > light9
annotate flax/CueFaders.py @ 160:c1c0f5854f8f
uses real light names (for our current patch, anyway) so the dmx send will work
author | drewp |
---|---|
date | Mon, 07 Jul 2003 08:45:39 +0000 |
parents | 5c7ac46e33d3 |
children | 0803fb42109d |
rev | line source |
---|---|
0 | 1 from __future__ import division, nested_scopes |
2 import Tix as Tk | |
3 import time | |
4 from TreeDict import TreeDict, allow_class_to_be_pickled | |
5 | |
6 class LabelledScale(Tk.Frame): | |
7 """Scale with two labels: a name and current value""" | |
8 def __init__(self, master, label, **opts): | |
151
990a9474d0e7
early cue stuff. the CueList will supply the CueFader with the cues to
dmcc
parents:
0
diff
changeset
|
9 Tk.Frame.__init__(self, master, bd=2, relief='raised') |
0 | 10 opts.setdefault('variable', Tk.DoubleVar()) |
11 opts.setdefault('showvalue', 0) | |
12 self.scale_var = opts['variable'] | |
13 self.scale = Tk.Scale(self, **opts) | |
14 self.scale.pack(side='top', expand=1, fill='both') | |
151
990a9474d0e7
early cue stuff. the CueList will supply the CueFader with the cues to
dmcc
parents:
0
diff
changeset
|
15 self.name = Tk.Label(self, text=label) |
0 | 16 self.name.pack(side='bottom') |
151
990a9474d0e7
early cue stuff. the CueList will supply the CueFader with the cues to
dmcc
parents:
0
diff
changeset
|
17 self.scale_value = Tk.Label(self, width=6) |
0 | 18 self.scale_value.pack(side='bottom') |
19 self.scale_var.trace('w', self.update_value_label) | |
20 self.update_value_label() | |
158
5c7ac46e33d3
more disabling of stuff that make no sense at certain times and some
dmcc
parents:
157
diff
changeset
|
21 self.disabled = (self.scale['state'] == 'disabled') |
0 | 22 def set_label(self, label): |
23 self.name['text'] = label | |
24 def update_value_label(self, *args): | |
25 val = self.scale_var.get() * 100 | |
151
990a9474d0e7
early cue stuff. the CueList will supply the CueFader with the cues to
dmcc
parents:
0
diff
changeset
|
26 self.scale_value['text'] = "%0.2f" % val |
158
5c7ac46e33d3
more disabling of stuff that make no sense at certain times and some
dmcc
parents:
157
diff
changeset
|
27 def disable(self): |
5c7ac46e33d3
more disabling of stuff that make no sense at certain times and some
dmcc
parents:
157
diff
changeset
|
28 if not self.disabled: |
5c7ac46e33d3
more disabling of stuff that make no sense at certain times and some
dmcc
parents:
157
diff
changeset
|
29 self.scale['state'] = 'disabled' |
5c7ac46e33d3
more disabling of stuff that make no sense at certain times and some
dmcc
parents:
157
diff
changeset
|
30 self.scale_var.set(0) |
5c7ac46e33d3
more disabling of stuff that make no sense at certain times and some
dmcc
parents:
157
diff
changeset
|
31 self.disabled = 1 |
5c7ac46e33d3
more disabling of stuff that make no sense at certain times and some
dmcc
parents:
157
diff
changeset
|
32 def enable(self): |
5c7ac46e33d3
more disabling of stuff that make no sense at certain times and some
dmcc
parents:
157
diff
changeset
|
33 if self.disabled: |
5c7ac46e33d3
more disabling of stuff that make no sense at certain times and some
dmcc
parents:
157
diff
changeset
|
34 self.scale['state'] = 'normal' |
5c7ac46e33d3
more disabling of stuff that make no sense at certain times and some
dmcc
parents:
157
diff
changeset
|
35 self.disabled = 0 |
0 | 36 |
37 class TimedGoButton(Tk.Frame): | |
38 """Go button, fade time entry, and time fader""" | |
151
990a9474d0e7
early cue stuff. the CueList will supply the CueFader with the cues to
dmcc
parents:
0
diff
changeset
|
39 def __init__(self, master, name, scale_to_fade): |
990a9474d0e7
early cue stuff. the CueList will supply the CueFader with the cues to
dmcc
parents:
0
diff
changeset
|
40 Tk.Frame.__init__(self, master) |
0 | 41 self.name = name |
42 self.scale_to_fade = scale_to_fade | |
151
990a9474d0e7
early cue stuff. the CueList will supply the CueFader with the cues to
dmcc
parents:
0
diff
changeset
|
43 self.button = Tk.Button(self, text=name, command=self.start_fade) |
0 | 44 self.button.pack(fill='both', expand=1, side='left') |
151
990a9474d0e7
early cue stuff. the CueList will supply the CueFader with the cues to
dmcc
parents:
0
diff
changeset
|
45 self.timer_var = Tk.StringVar() |
990a9474d0e7
early cue stuff. the CueList will supply the CueFader with the cues to
dmcc
parents:
0
diff
changeset
|
46 self.timer_entry = Tk.Entry(self, textvariable=self.timer_var, width=5) |
0 | 47 self.timer_entry.pack(fill='y', side='left') |
151
990a9474d0e7
early cue stuff. the CueList will supply the CueFader with the cues to
dmcc
parents:
0
diff
changeset
|
48 self.timer_var.set("2") |
158
5c7ac46e33d3
more disabling of stuff that make no sense at certain times and some
dmcc
parents:
157
diff
changeset
|
49 self.disabled = (self.button['state'] == 'disabled') |
0 | 50 def start_fade(self, end_level=1): |
151
990a9474d0e7
early cue stuff. the CueList will supply the CueFader with the cues to
dmcc
parents:
0
diff
changeset
|
51 try: |
990a9474d0e7
early cue stuff. the CueList will supply the CueFader with the cues to
dmcc
parents:
0
diff
changeset
|
52 fade_time = float(self.timer_var.get()) |
990a9474d0e7
early cue stuff. the CueList will supply the CueFader with the cues to
dmcc
parents:
0
diff
changeset
|
53 except ValueError: |
990a9474d0e7
early cue stuff. the CueList will supply the CueFader with the cues to
dmcc
parents:
0
diff
changeset
|
54 # TODO figure out how to handle this |
990a9474d0e7
early cue stuff. the CueList will supply the CueFader with the cues to
dmcc
parents:
0
diff
changeset
|
55 print "can't fade -- bad time" |
990a9474d0e7
early cue stuff. the CueList will supply the CueFader with the cues to
dmcc
parents:
0
diff
changeset
|
56 return |
990a9474d0e7
early cue stuff. the CueList will supply the CueFader with the cues to
dmcc
parents:
0
diff
changeset
|
57 |
0 | 58 self.start_time = time.time() |
59 self.start_level = self.scale_to_fade.scale_var.get() | |
60 self.end_level = end_level | |
151
990a9474d0e7
early cue stuff. the CueList will supply the CueFader with the cues to
dmcc
parents:
0
diff
changeset
|
61 self.fade_length = fade_time |
990a9474d0e7
early cue stuff. the CueList will supply the CueFader with the cues to
dmcc
parents:
0
diff
changeset
|
62 self.do_fade() |
0 | 63 def do_fade(self): |
64 diff = time.time() - self.start_time | |
65 if diff < self.fade_length: | |
66 percent = diff / self.fade_length | |
67 newlevel = self.start_level + \ | |
68 (percent * (self.end_level - self.start_level)) | |
69 self.scale_to_fade.scale_var.set(newlevel) | |
70 | |
71 if newlevel != self.end_level: | |
151
990a9474d0e7
early cue stuff. the CueList will supply the CueFader with the cues to
dmcc
parents:
0
diff
changeset
|
72 self.after(10, self.do_fade) |
0 | 73 else: |
74 self.scale_to_fade.scale_var.set(self.end_level) | |
158
5c7ac46e33d3
more disabling of stuff that make no sense at certain times and some
dmcc
parents:
157
diff
changeset
|
75 def disable(self): |
5c7ac46e33d3
more disabling of stuff that make no sense at certain times and some
dmcc
parents:
157
diff
changeset
|
76 if not self.disabled: |
5c7ac46e33d3
more disabling of stuff that make no sense at certain times and some
dmcc
parents:
157
diff
changeset
|
77 self.button['state'] = 'disabled' |
5c7ac46e33d3
more disabling of stuff that make no sense at certain times and some
dmcc
parents:
157
diff
changeset
|
78 self.disabled = 1 |
5c7ac46e33d3
more disabling of stuff that make no sense at certain times and some
dmcc
parents:
157
diff
changeset
|
79 def enable(self): |
5c7ac46e33d3
more disabling of stuff that make no sense at certain times and some
dmcc
parents:
157
diff
changeset
|
80 if self.disabled: |
5c7ac46e33d3
more disabling of stuff that make no sense at certain times and some
dmcc
parents:
157
diff
changeset
|
81 self.button['state'] = 'normal' |
5c7ac46e33d3
more disabling of stuff that make no sense at certain times and some
dmcc
parents:
157
diff
changeset
|
82 self.disabled = 0 |
0 | 83 |
84 class CueFader(Tk.Frame): | |
85 def __init__(self, master, cuelist): | |
151
990a9474d0e7
early cue stuff. the CueList will supply the CueFader with the cues to
dmcc
parents:
0
diff
changeset
|
86 Tk.Frame.__init__(self, master) |
0 | 87 self.cuelist = cuelist |
155 | 88 self.auto_shift = Tk.IntVar() |
89 self.auto_shift.set(1) | |
0 | 90 |
91 self.scales = {} | |
92 self.shift_buttons = {} | |
158
5c7ac46e33d3
more disabling of stuff that make no sense at certain times and some
dmcc
parents:
157
diff
changeset
|
93 self.go_buttons = {} |
151
990a9474d0e7
early cue stuff. the CueList will supply the CueFader with the cues to
dmcc
parents:
0
diff
changeset
|
94 |
990a9474d0e7
early cue stuff. the CueList will supply the CueFader with the cues to
dmcc
parents:
0
diff
changeset
|
95 topframe = Tk.Frame(self) |
990a9474d0e7
early cue stuff. the CueList will supply the CueFader with the cues to
dmcc
parents:
0
diff
changeset
|
96 self.current_cues = Tk.Label(topframe) |
990a9474d0e7
early cue stuff. the CueList will supply the CueFader with the cues to
dmcc
parents:
0
diff
changeset
|
97 self.current_cues.pack() |
990a9474d0e7
early cue stuff. the CueList will supply the CueFader with the cues to
dmcc
parents:
0
diff
changeset
|
98 self.update_cue_display() |
990a9474d0e7
early cue stuff. the CueList will supply the CueFader with the cues to
dmcc
parents:
0
diff
changeset
|
99 topframe.pack() |
0 | 100 |
155 | 101 bottomframe = Tk.Frame(self) |
102 self.auto_shift_checkbutton = Tk.Checkbutton(self, | |
103 variable=self.auto_shift, text='Autoshift', | |
104 command=self.toggle_autoshift) | |
105 self.auto_shift_checkbutton.pack() | |
106 bottomframe.pack(side='bottom') | |
107 | |
108 middleframe = Tk.Frame(self) | |
151
990a9474d0e7
early cue stuff. the CueList will supply the CueFader with the cues to
dmcc
parents:
0
diff
changeset
|
109 for name, start, end, side in (('Prev', 1, 0, 'left'), |
990a9474d0e7
early cue stuff. the CueList will supply the CueFader with the cues to
dmcc
parents:
0
diff
changeset
|
110 ('Next', 0, 1, 'right')): |
990a9474d0e7
early cue stuff. the CueList will supply the CueFader with the cues to
dmcc
parents:
0
diff
changeset
|
111 frame = Tk.Frame(self) |
0 | 112 scale = LabelledScale(frame, name, from_=start, to_=end, |
151
990a9474d0e7
early cue stuff. the CueList will supply the CueFader with the cues to
dmcc
parents:
0
diff
changeset
|
113 res=0.01, orient='horiz') |
990a9474d0e7
early cue stuff. the CueList will supply the CueFader with the cues to
dmcc
parents:
0
diff
changeset
|
114 scale.pack(fill='both', expand=1) |
990a9474d0e7
early cue stuff. the CueList will supply the CueFader with the cues to
dmcc
parents:
0
diff
changeset
|
115 go = TimedGoButton(frame, 'Go %s' % name, scale) |
0 | 116 go.pack(fill='both', expand=1) |
117 frame.pack(side=side, fill='both', expand=1) | |
118 | |
155 | 119 shift = Tk.Button(frame, text="Shift %s" % name, state='disabled', |
120 command=lambda name=name: self.shift(name)) | |
121 | |
0 | 122 self.scales[name] = scale |
123 self.shift_buttons[name] = shift | |
158
5c7ac46e33d3
more disabling of stuff that make no sense at certain times and some
dmcc
parents:
157
diff
changeset
|
124 self.go_buttons[name] = go |
0 | 125 |
126 scale.scale_var.trace('w', \ | |
127 lambda x, y, z, name=name, scale=scale: self.xfade(name, scale)) | |
155 | 128 middleframe.pack(side='bottom', fill='both', expand=1) |
129 def toggle_autoshift(self): | |
130 for name, button in self.shift_buttons.items(): | |
131 if not self.auto_shift.get(): | |
132 button.pack(side='bottom', fill='both', expand=1) | |
133 else: | |
134 button.pack_forget() | |
135 | |
0 | 136 def shift(self, name): |
158
5c7ac46e33d3
more disabling of stuff that make no sense at certain times and some
dmcc
parents:
157
diff
changeset
|
137 print "shift", name |
5c7ac46e33d3
more disabling of stuff that make no sense at certain times and some
dmcc
parents:
157
diff
changeset
|
138 for scale_name, scale in self.scales.items(): |
151
990a9474d0e7
early cue stuff. the CueList will supply the CueFader with the cues to
dmcc
parents:
0
diff
changeset
|
139 scale.scale_var.set(0) |
0 | 140 self.cuelist.shift((-1, 1)[name == 'Next']) |
151
990a9474d0e7
early cue stuff. the CueList will supply the CueFader with the cues to
dmcc
parents:
0
diff
changeset
|
141 self.update_cue_display() |
990a9474d0e7
early cue stuff. the CueList will supply the CueFader with the cues to
dmcc
parents:
0
diff
changeset
|
142 def update_cue_display(self): |
990a9474d0e7
early cue stuff. the CueList will supply the CueFader with the cues to
dmcc
parents:
0
diff
changeset
|
143 current_cues = [cue.name for cue in self.cuelist.get_current_cues()] |
990a9474d0e7
early cue stuff. the CueList will supply the CueFader with the cues to
dmcc
parents:
0
diff
changeset
|
144 self.current_cues['text'] = ', '.join(current_cues) |
990a9474d0e7
early cue stuff. the CueList will supply the CueFader with the cues to
dmcc
parents:
0
diff
changeset
|
145 def xfade(self, name, scale): |
0 | 146 scale_val = scale.scale_var.get() |
158
5c7ac46e33d3
more disabling of stuff that make no sense at certain times and some
dmcc
parents:
157
diff
changeset
|
147 # print "xfade", name, scale_val |
0 | 148 |
149 if scale_val == 1: | |
155 | 150 if self.auto_shift.get(): |
158
5c7ac46e33d3
more disabling of stuff that make no sense at certain times and some
dmcc
parents:
157
diff
changeset
|
151 print "autoshifting", name |
0 | 152 self.shift(name) |
158
5c7ac46e33d3
more disabling of stuff that make no sense at certain times and some
dmcc
parents:
157
diff
changeset
|
153 scale_val = scale.scale_var.get() # this needs to be refreshed |
151
990a9474d0e7
early cue stuff. the CueList will supply the CueFader with the cues to
dmcc
parents:
0
diff
changeset
|
154 else: |
990a9474d0e7
early cue stuff. the CueList will supply the CueFader with the cues to
dmcc
parents:
0
diff
changeset
|
155 self.shift_buttons[name]['state'] = 'normal' |
0 | 156 else: |
151
990a9474d0e7
early cue stuff. the CueList will supply the CueFader with the cues to
dmcc
parents:
0
diff
changeset
|
157 # disable any dangerous shifting |
990a9474d0e7
early cue stuff. the CueList will supply the CueFader with the cues to
dmcc
parents:
0
diff
changeset
|
158 self.shift_buttons[name]['state'] = 'disabled' |
0 | 159 |
158
5c7ac46e33d3
more disabling of stuff that make no sense at certain times and some
dmcc
parents:
157
diff
changeset
|
160 d = self.opposite_direction(name) |
0 | 161 if scale_val != 0: |
162 # disable illegal three part crossfades | |
158
5c7ac46e33d3
more disabling of stuff that make no sense at certain times and some
dmcc
parents:
157
diff
changeset
|
163 self.scales[d].disable() |
5c7ac46e33d3
more disabling of stuff that make no sense at certain times and some
dmcc
parents:
157
diff
changeset
|
164 self.go_buttons[d].disable() |
0 | 165 else: |
158
5c7ac46e33d3
more disabling of stuff that make no sense at certain times and some
dmcc
parents:
157
diff
changeset
|
166 # undo above work |
5c7ac46e33d3
more disabling of stuff that make no sense at certain times and some
dmcc
parents:
157
diff
changeset
|
167 self.scales[d].enable() |
5c7ac46e33d3
more disabling of stuff that make no sense at certain times and some
dmcc
parents:
157
diff
changeset
|
168 self.go_buttons[d].enable() |
5c7ac46e33d3
more disabling of stuff that make no sense at certain times and some
dmcc
parents:
157
diff
changeset
|
169 def opposite_direction(self, d): |
5c7ac46e33d3
more disabling of stuff that make no sense at certain times and some
dmcc
parents:
157
diff
changeset
|
170 if d == 'Next': |
5c7ac46e33d3
more disabling of stuff that make no sense at certain times and some
dmcc
parents:
157
diff
changeset
|
171 return 'Prev' |
5c7ac46e33d3
more disabling of stuff that make no sense at certain times and some
dmcc
parents:
157
diff
changeset
|
172 else: |
5c7ac46e33d3
more disabling of stuff that make no sense at certain times and some
dmcc
parents:
157
diff
changeset
|
173 return 'Next' |
0 | 174 |
175 class Cue: | |
176 """A Cue has a name, a time, and any number of other attributes.""" | |
151
990a9474d0e7
early cue stuff. the CueList will supply the CueFader with the cues to
dmcc
parents:
0
diff
changeset
|
177 def __init__(self, name, time=3, **attrs): |
0 | 178 self.name = name |
179 self.time = time | |
180 self.__dict__.update(attrs) | |
181 def __repr__(self): | |
182 return "<Cue %s, length %s>" % (self.name, self.time) | |
183 | |
184 empty_cue = Cue('empty') | |
185 | |
186 allow_class_to_be_pickled(Cue) | |
187 | |
188 class CueList: | |
189 """Persistent list of Cues""" | |
190 def __init__(self, filename): | |
191 self.filename = filename | |
192 self.treedict = TreeDict() | |
193 try: | |
194 self.treedict.load(filename) | |
195 except IOError: | |
196 self.treedict.cues = [] | |
197 self.cues = self.treedict.cues | |
151
990a9474d0e7
early cue stuff. the CueList will supply the CueFader with the cues to
dmcc
parents:
0
diff
changeset
|
198 self.current_cue_index = 0 |
990a9474d0e7
early cue stuff. the CueList will supply the CueFader with the cues to
dmcc
parents:
0
diff
changeset
|
199 self.next_pointer = None |
0 | 200 self.prev_pointer = None |
201 | |
202 import atexit | |
203 atexit.register(self.save) | |
204 def add_cue(self, cue, index=None): | |
205 """Adds a Cue object to the list. If no index is specified, | |
206 the cue will be added to the end.""" | |
207 index = index or len(self.cues) | |
208 self.cues.insert(index, cue) | |
209 def shift(self, diff): | |
210 """Shift through cue history""" | |
211 old_index = self.current_cue_index | |
212 self.current_cue_index = None | |
213 if diff < 0: # if going backwards | |
214 if self.prev_pointer: # use a prev pointer if we have one | |
215 self.current_cue_index = self.prev_pointer | |
216 self.next_pointer = old_index | |
217 self.prev_pointer = None | |
218 else: | |
219 if self.next_pointer: # use a next pointer if we have one | |
220 self.current_cue_index = self.next_pointer | |
221 self.next_pointer = None | |
222 self.prev_pointer = old_index | |
223 if not self.current_cue_index: | |
224 self.current_cue_index = old_index + diff | |
225 def set_next(self, index): | |
226 self.next_pointer = index | |
227 def set_prev(self, index): | |
228 self.prev_pointer = index | |
229 def bound_index(self, index): | |
151
990a9474d0e7
early cue stuff. the CueList will supply the CueFader with the cues to
dmcc
parents:
0
diff
changeset
|
230 if not self.cues: |
0 | 231 return None |
232 else: | |
158
5c7ac46e33d3
more disabling of stuff that make no sense at certain times and some
dmcc
parents:
157
diff
changeset
|
233 return max(0, min(index, len(self.cues) - 1)) |
0 | 234 def get_current_cue_indices(self): |
235 cur = self.current_cue_index | |
236 return [self.bound_index(index) for index in | |
237 (self.prev_pointer or cur - 1, | |
238 cur, | |
239 self.next_pointer or cur + 1)] | |
240 def get_current_cues(self): | |
241 return [self.get_cue_by_index(index) | |
242 for index in self.get_current_cue_indices()] | |
243 def get_cue_by_index(self, index): | |
151
990a9474d0e7
early cue stuff. the CueList will supply the CueFader with the cues to
dmcc
parents:
0
diff
changeset
|
244 if index: |
0 | 245 return self.cues[self.bound_index(index)] |
151
990a9474d0e7
early cue stuff. the CueList will supply the CueFader with the cues to
dmcc
parents:
0
diff
changeset
|
246 else: |
0 | 247 return empty_cue |
248 def __del__(self): | |
249 self.save() | |
151
990a9474d0e7
early cue stuff. the CueList will supply the CueFader with the cues to
dmcc
parents:
0
diff
changeset
|
250 def save(self): |
990a9474d0e7
early cue stuff. the CueList will supply the CueFader with the cues to
dmcc
parents:
0
diff
changeset
|
251 self.treedict.save(self.filename) |
0 | 252 |
253 if __name__ == "__main__": | |
157 | 254 cl = CueList('cues/cuelist1') |
0 | 255 |
157 | 256 # to populate cue list |
257 if 0: | |
258 for x in range(20): | |
259 cl.add_cue(Cue('cue %d' % x, time=x, some_attribute=3)) | |
151
990a9474d0e7
early cue stuff. the CueList will supply the CueFader with the cues to
dmcc
parents:
0
diff
changeset
|
260 |
157 | 261 root = Tk.Tk() |
262 fader = CueFader(root, cl) | |
263 fader.pack(fill='both', expand=1) | |
264 Tk.mainloop() |