Mercurial > code > home > repos > light9
comparison flax/CueFaders.py @ 161:0803fb42109d
we now have TkCueList, which is really cool. it doesn't provide editing
we now have TkCueList, which is really cool. it doesn't provide editing
yet, but you could almost nearly probably maybe run a show with it.
heck, i hope so.
some of the shifting/drawing problems were probably fixed.
cuelist1 got more bogus data to help populate the TkCueList.
author | dmcc |
---|---|
date | Mon, 07 Jul 2003 17:18:26 +0000 |
parents | 5c7ac46e33d3 |
children | 6c5753bad783 |
comparison
equal
deleted
inserted
replaced
160:c1c0f5854f8f | 161:0803fb42109d |
---|---|
1 from __future__ import division, nested_scopes | 1 from __future__ import division, nested_scopes |
2 import Tix as Tk | 2 import Tix as Tk |
3 import time | 3 import time |
4 from TreeDict import TreeDict, allow_class_to_be_pickled | 4 from TreeDict import TreeDict, allow_class_to_be_pickled |
5 from TLUtility import enumerate | |
6 | |
7 cue_state_indicator_colors = { | |
8 # bg fg | |
9 'prev' : ('blue', 'white'), | |
10 'cur' : ('yellow', 'black'), | |
11 'next' : ('red', 'white'), | |
12 } | |
5 | 13 |
6 class LabelledScale(Tk.Frame): | 14 class LabelledScale(Tk.Frame): |
7 """Scale with two labels: a name and current value""" | 15 """Scale with two labels: a name and current value""" |
8 def __init__(self, master, label, **opts): | 16 def __init__(self, master, label, **opts): |
9 Tk.Frame.__init__(self, master, bd=2, relief='raised') | 17 Tk.Frame.__init__(self, master, bd=2, relief='raised') |
10 opts.setdefault('variable', Tk.DoubleVar()) | 18 opts.setdefault('variable', Tk.DoubleVar()) |
11 opts.setdefault('showvalue', 0) | 19 opts.setdefault('showvalue', 0) |
20 | |
21 self.normaltrough = opts.get('troughcolor', 'black') | |
22 self.flashtrough = opts.get('flashtroughcolor', 'red') | |
23 del opts['flashtroughcolor'] | |
24 | |
12 self.scale_var = opts['variable'] | 25 self.scale_var = opts['variable'] |
13 self.scale = Tk.Scale(self, **opts) | 26 self.scale = Tk.Scale(self, **opts) |
14 self.scale.pack(side='top', expand=1, fill='both') | 27 self.scale.pack(side='top', expand=1, fill='both') |
15 self.name = Tk.Label(self, text=label) | 28 self.name = Tk.Label(self, text=label) |
16 self.name.pack(side='bottom') | 29 self.name.pack(side='bottom') |
22 def set_label(self, label): | 35 def set_label(self, label): |
23 self.name['text'] = label | 36 self.name['text'] = label |
24 def update_value_label(self, *args): | 37 def update_value_label(self, *args): |
25 val = self.scale_var.get() * 100 | 38 val = self.scale_var.get() * 100 |
26 self.scale_value['text'] = "%0.2f" % val | 39 self.scale_value['text'] = "%0.2f" % val |
40 if val != 0: | |
41 self.scale['troughcolor'] = self.flashtrough | |
42 else: | |
43 self.scale['troughcolor'] = self.normaltrough | |
27 def disable(self): | 44 def disable(self): |
28 if not self.disabled: | 45 if not self.disabled: |
29 self.scale['state'] = 'disabled' | 46 self.scale['state'] = 'disabled' |
30 self.scale_var.set(0) | 47 self.scale_var.set(0) |
31 self.disabled = 1 | 48 self.disabled = 1 |
34 self.scale['state'] = 'normal' | 51 self.scale['state'] = 'normal' |
35 self.disabled = 0 | 52 self.disabled = 0 |
36 | 53 |
37 class TimedGoButton(Tk.Frame): | 54 class TimedGoButton(Tk.Frame): |
38 """Go button, fade time entry, and time fader""" | 55 """Go button, fade time entry, and time fader""" |
39 def __init__(self, master, name, scale_to_fade): | 56 def __init__(self, master, name, scale_to_fade, **kw): |
40 Tk.Frame.__init__(self, master) | 57 Tk.Frame.__init__(self, master) |
41 self.name = name | 58 self.name = name |
42 self.scale_to_fade = scale_to_fade | 59 self.scale_to_fade = scale_to_fade |
43 self.button = Tk.Button(self, text=name, command=self.start_fade) | 60 self.button = Tk.Button(self, text=name, command=self.start_fade, **kw) |
44 self.button.pack(fill='both', expand=1, side='left') | 61 self.button.pack(fill='both', expand=1, side='left') |
45 self.timer_var = Tk.StringVar() | 62 self.timer_var = Tk.StringVar() |
46 self.timer_entry = Tk.Entry(self, textvariable=self.timer_var, width=5) | 63 self.timer_entry = Tk.Entry(self, textvariable=self.timer_var, width=5) |
47 self.timer_entry.pack(fill='y', side='left') | 64 self.timer_entry.pack(fill='y', side='left') |
48 self.timer_var.set("2") | 65 self.timer_var.set("2") |
86 Tk.Frame.__init__(self, master) | 103 Tk.Frame.__init__(self, master) |
87 self.cuelist = cuelist | 104 self.cuelist = cuelist |
88 self.auto_shift = Tk.IntVar() | 105 self.auto_shift = Tk.IntVar() |
89 self.auto_shift.set(1) | 106 self.auto_shift.set(1) |
90 | 107 |
108 # this is a mechanism to stop Tk from autoshifting too much. | |
109 # if this variable is true, the mouse button is down. we don't want | |
110 # to shift until they release it. when it is released, we will | |
111 # set it to false and then call autoshift. | |
112 self.no_shifts_until_release = 0 | |
113 | |
91 self.scales = {} | 114 self.scales = {} |
92 self.shift_buttons = {} | 115 self.shift_buttons = {} |
93 self.go_buttons = {} | 116 self.go_buttons = {} |
94 | 117 |
95 topframe = Tk.Frame(self) | 118 topframe = Tk.Frame(self) |
96 self.current_cues = Tk.Label(topframe) | 119 |
97 self.current_cues.pack() | 120 self.set_prev_button = Tk.Button(topframe, text='Set Prev', |
98 self.update_cue_display() | 121 command=lambda: cuelist.set_selection_as_prev(), |
99 topframe.pack() | 122 fg='white', bg='blue') |
100 | 123 self.set_prev_button.pack(side='left') |
101 bottomframe = Tk.Frame(self) | 124 |
102 self.auto_shift_checkbutton = Tk.Checkbutton(self, | 125 self.auto_shift_checkbutton = Tk.Checkbutton(topframe, |
103 variable=self.auto_shift, text='Autoshift', | 126 variable=self.auto_shift, text='Autoshift', |
104 command=self.toggle_autoshift) | 127 command=self.toggle_autoshift) |
105 self.auto_shift_checkbutton.pack() | 128 self.auto_shift_checkbutton.pack(side='left') |
106 bottomframe.pack(side='bottom') | 129 |
107 | 130 self.set_next_button = Tk.Button(topframe, text='Set Next', |
108 middleframe = Tk.Frame(self) | 131 command=lambda: cuelist.set_selection_as_next(), |
109 for name, start, end, side in (('Prev', 1, 0, 'left'), | 132 fg='white', bg='red') |
110 ('Next', 0, 1, 'right')): | 133 self.set_next_button.pack(side='left') |
134 | |
135 topframe.pack(side='top') | |
136 | |
137 faderframe = Tk.Frame(self) | |
138 self.direction_info = (('Prev', 1, 0, 'left', 'blue'), | |
139 ('Next', 0, 1, 'right', 'red')) | |
140 for name, start, end, side, color in self.direction_info: | |
111 frame = Tk.Frame(self) | 141 frame = Tk.Frame(self) |
112 scale = LabelledScale(frame, name, from_=start, to_=end, | 142 scale = LabelledScale(frame, name, from_=start, to_=end, |
113 res=0.01, orient='horiz') | 143 res=0.0001, orient='horiz', flashtroughcolor=color) |
114 scale.pack(fill='both', expand=1) | 144 scale.pack(fill='x', expand=0) |
115 go = TimedGoButton(frame, 'Go %s' % name, scale) | 145 go = TimedGoButton(frame, 'Go %s' % name, scale, bg=color, |
146 fg='white') | |
116 go.pack(fill='both', expand=1) | 147 go.pack(fill='both', expand=1) |
117 frame.pack(side=side, fill='both', expand=1) | 148 frame.pack(side=side, fill='both', expand=1) |
118 | 149 |
119 shift = Tk.Button(frame, text="Shift %s" % name, state='disabled', | 150 shift = Tk.Button(frame, text="Shift %s" % name, state='disabled', |
120 command=lambda name=name: self.shift(name)) | 151 command=lambda name=name: self.shift(name), fg=color, |
152 bg='black') | |
121 | 153 |
122 self.scales[name] = scale | 154 self.scales[name] = scale |
123 self.shift_buttons[name] = shift | 155 self.shift_buttons[name] = shift |
124 self.go_buttons[name] = go | 156 self.go_buttons[name] = go |
125 | 157 |
126 scale.scale_var.trace('w', \ | 158 scale.scale_var.trace('w', \ |
127 lambda x, y, z, name=name, scale=scale: self.xfade(name, scale)) | 159 lambda x, y, z, name=name, scale=scale: self.xfade(name, scale)) |
128 middleframe.pack(side='bottom', fill='both', expand=1) | 160 |
161 def button_press(event, name=name, scale=scale): | |
162 self.no_shifts_until_release = 1 # prevent shifts until release | |
163 def button_release(event, name=name, scale=scale): | |
164 self.no_shifts_until_release = 0 | |
165 self.autoshift(name, scale) | |
166 | |
167 scale.scale.bind("<ButtonPress>", button_press) | |
168 scale.scale.bind("<ButtonRelease>", button_release) | |
169 faderframe.pack(side='bottom', fill='both', expand=1) | |
129 def toggle_autoshift(self): | 170 def toggle_autoshift(self): |
130 for name, button in self.shift_buttons.items(): | 171 for name, button in self.shift_buttons.items(): |
131 if not self.auto_shift.get(): | 172 if not self.auto_shift.get(): |
132 button.pack(side='bottom', fill='both', expand=1) | 173 button.pack(side='bottom', fill='both', expand=1) |
133 else: | 174 else: |
134 button.pack_forget() | 175 button.pack_forget() |
135 | |
136 def shift(self, name): | 176 def shift(self, name): |
137 print "shift", name | 177 # to prevent overshifting |
178 if self.no_shifts_until_release: | |
179 return | |
180 | |
138 for scale_name, scale in self.scales.items(): | 181 for scale_name, scale in self.scales.items(): |
139 scale.scale_var.set(0) | 182 scale.scale.set(0) |
140 self.cuelist.shift((-1, 1)[name == 'Next']) | 183 self.cuelist.shift((-1, 1)[name == 'Next']) |
141 self.update_cue_display() | 184 def autoshift(self, name, scale): |
142 def update_cue_display(self): | |
143 current_cues = [cue.name for cue in self.cuelist.get_current_cues()] | |
144 self.current_cues['text'] = ', '.join(current_cues) | |
145 def xfade(self, name, scale): | |
146 scale_val = scale.scale_var.get() | 185 scale_val = scale.scale_var.get() |
147 # print "xfade", name, scale_val | |
148 | 186 |
149 if scale_val == 1: | 187 if scale_val == 1: |
150 if self.auto_shift.get(): | 188 if self.auto_shift.get(): |
151 print "autoshifting", name | |
152 self.shift(name) | 189 self.shift(name) |
153 scale_val = scale.scale_var.get() # this needs to be refreshed | 190 def xfade(self, name, scale): |
191 if self.auto_shift.get(): | |
192 self.autoshift(name, scale) | |
193 scale_val = scale.scale_var.get() | |
194 else: | |
195 scale_val = scale.scale_var.get() | |
196 if scale_val == 1: | |
197 self.shift_buttons[name]['state'] = 'normal' | |
154 else: | 198 else: |
155 self.shift_buttons[name]['state'] = 'normal' | 199 # disable any dangerous shifting |
156 else: | 200 self.shift_buttons[name]['state'] = 'disabled' |
157 # disable any dangerous shifting | |
158 self.shift_buttons[name]['state'] = 'disabled' | |
159 | 201 |
160 d = self.opposite_direction(name) | 202 d = self.opposite_direction(name) |
161 if scale_val != 0: | 203 if scale_val != 0: |
162 # disable illegal three part crossfades | 204 # disable illegal three part crossfades |
163 self.scales[d].disable() | 205 self.scales[d].disable() |
247 return empty_cue | 289 return empty_cue |
248 def __del__(self): | 290 def __del__(self): |
249 self.save() | 291 self.save() |
250 def save(self): | 292 def save(self): |
251 self.treedict.save(self.filename) | 293 self.treedict.save(self.filename) |
294 def reload(self): | |
295 # TODO: we probably will need to make sure that indices still make | |
296 # sense, etc. | |
297 self.treedict.load(self.filename) | |
298 | |
299 class TkCueList(CueList, Tk.Frame): | |
300 def __init__(self, master, filename): | |
301 CueList.__init__(self, filename) | |
302 Tk.Frame.__init__(self, master) | |
303 | |
304 self.columns = ('name', 'time', 'page', 'desc') | |
305 | |
306 self.scrolled_hlist = Tk.ScrolledHList(self, | |
307 options='hlist.columns %d hlist.header 1' % len(self.columns)) | |
308 self.hlist = self.scrolled_hlist.hlist | |
309 self.hlist.configure(fg='white', bg='black', | |
310 command=self.select_callback) | |
311 self.scrolled_hlist.pack(fill='both', expand=1) | |
312 | |
313 boldfont = self.tk.call('tix', 'option', 'get', | |
314 'bold_font') | |
315 header_style = Tk.DisplayStyle('text', refwindow=self, | |
316 anchor='center', padx=8, pady=2, font=boldfont) | |
317 | |
318 for count, header in enumerate(self.columns): | |
319 self.hlist.header_create(count, itemtype='text', | |
320 text=header, style=header_style) | |
321 | |
322 self.cue_label_windows = {} | |
323 for count, cue in enumerate(self.cues): | |
324 self.display_cue(count, cue) | |
325 self.update_cue_indicators() | |
326 def display_cue(self, cue_count, cue): | |
327 # cue_count is the path in the hlist -- this probably isn't ideal | |
328 for col, header in enumerate(self.columns): | |
329 try: | |
330 text = getattr(cue, header) | |
331 except AttributeError: | |
332 text = '' | |
333 | |
334 if col == 0: | |
335 lab = Tk.Label(self.hlist, text=text, fg='white', bg='black') | |
336 def select_and_highlight(event): | |
337 self.select_callback(cue_count) | |
338 self.hlist.selection_clear() | |
339 self.hlist.selection_set(cue_count) | |
340 | |
341 lab.bind("<Double-1>", select_and_highlight) | |
342 self.hlist.add(cue_count, itemtype='window', window=lab) | |
343 self.cue_label_windows[cue_count] = lab | |
344 else: | |
345 self.hlist.item_create(cue_count, col, text=text) | |
346 def reset_cue_indicators(self, cue_indices=None): | |
347 """If cue_indices is None, we'll reset all of them.""" | |
348 cue_indices = cue_indices or self.cue_label_windows.keys() | |
349 for key in cue_indices: | |
350 window = self.cue_label_windows[key] | |
351 window.configure(fg='white', bg='black') | |
352 def update_cue_indicators(self): | |
353 states = dict(zip(self.get_current_cue_indices(), | |
354 ('prev', 'cur', 'next'))) | |
355 | |
356 for count, state in states.items(): | |
357 window = self.cue_label_windows[count] | |
358 bg, fg = cue_state_indicator_colors[state] | |
359 window.configure(bg=bg, fg=fg) | |
360 def shift(self, diff): | |
361 self.reset_cue_indicators(self.get_current_cue_indices()) | |
362 CueList.shift(self, diff) | |
363 self.update_cue_indicators() | |
364 # try to see all indices, but next takes priority over all, and cur | |
365 # over prev | |
366 for index in self.get_current_cue_indices(): | |
367 self.hlist.see(index) | |
368 def select_callback(self, index): | |
369 new_next = int(index) | |
370 self.set_next(new_next) | |
371 def set_next(self, index): | |
372 prev, cur, next = self.get_current_cue_indices() | |
373 self.reset_cue_indicators((next,)) | |
374 CueList.set_next(self, index) | |
375 self.update_cue_indicators() | |
376 def set_prev(self, index): | |
377 prev, cur, next = self.get_current_cue_indices() | |
378 self.reset_cue_indicators((prev,)) | |
379 CueList.set_prev(self, index) | |
380 self.update_cue_indicators() | |
381 def set_selection_as_prev(self): | |
382 sel = self.hlist.info_selection() | |
383 if sel: | |
384 self.set_prev(int(sel[0])) | |
385 def set_selection_as_next(self): | |
386 sel = self.hlist.info_selection() | |
387 if sel: | |
388 self.set_next(int(sel[0])) | |
252 | 389 |
253 if __name__ == "__main__": | 390 if __name__ == "__main__": |
254 cl = CueList('cues/cuelist1') | 391 root = Tk.Tk() |
392 cl = TkCueList(root, 'cues/cuelist1') | |
393 cl.pack(fill='both', expand=1) | |
255 | 394 |
256 # to populate cue list | 395 # to populate cue list |
257 if 0: | 396 if 0: |
258 for x in range(20): | 397 for x in range(20): |
259 cl.add_cue(Cue('cue %d' % x, time=x, some_attribute=3)) | 398 cl.add_cue(Cue('cue %d' % x, time=x, some_attribute=3)) |
260 | 399 |
261 root = Tk.Tk() | |
262 fader = CueFader(root, cl) | 400 fader = CueFader(root, cl) |
263 fader.pack(fill='both', expand=1) | 401 fader.pack(fill='both', expand=1) |
264 Tk.mainloop() | 402 Tk.mainloop() |