Mercurial > code > home > repos > light9
annotate flax/CueFaders.py @ 2166:679cafb867b1
start cyclone removal project
author | drewp@bigasterisk.com |
---|---|
date | Thu, 18 May 2023 12:56:52 -0700 |
parents | 74a34c677588 |
children |
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 | |
161
0803fb42109d
we now have TkCueList, which is really cool. it doesn't provide editing
dmcc
parents:
158
diff
changeset
|
5 from TLUtility import enumerate |
168 | 6 import Submaster, dmxclient |
161
0803fb42109d
we now have TkCueList, which is really cool. it doesn't provide editing
dmcc
parents:
158
diff
changeset
|
7 |
0803fb42109d
we now have TkCueList, which is really cool. it doesn't provide editing
dmcc
parents:
158
diff
changeset
|
8 cue_state_indicator_colors = { |
0803fb42109d
we now have TkCueList, which is really cool. it doesn't provide editing
dmcc
parents:
158
diff
changeset
|
9 # bg fg |
0803fb42109d
we now have TkCueList, which is really cool. it doesn't provide editing
dmcc
parents:
158
diff
changeset
|
10 'prev' : ('blue', 'white'), |
0803fb42109d
we now have TkCueList, which is really cool. it doesn't provide editing
dmcc
parents:
158
diff
changeset
|
11 'cur' : ('yellow', 'black'), |
0803fb42109d
we now have TkCueList, which is really cool. it doesn't provide editing
dmcc
parents:
158
diff
changeset
|
12 'next' : ('red', 'white'), |
0803fb42109d
we now have TkCueList, which is really cool. it doesn't provide editing
dmcc
parents:
158
diff
changeset
|
13 } |
0 | 14 |
178 | 15 # TODO |
181 | 16 # FIXE pause fades, set new time to be remaining about of time in the fade so |
178 | 17 # fade can continue properly |
181 | 18 # FIXE make fades work properly: the set_next / prev bug |
178 | 19 # WONT find cue by page ("not necessawy!") |
20 # WONT CueFader controls KeyboardController? unlikely | |
185 | 21 # FIXE AutoSave loop |
176 | 22 |
0 | 23 class LabelledScale(Tk.Frame): |
24 """Scale with two labels: a name and current value""" | |
25 def __init__(self, master, label, **opts): | |
162
6c5753bad783
basic cue editing, darker colors, fade time selector is now a "TixControl"
dmcc
parents:
161
diff
changeset
|
26 Tk.Frame.__init__(self, master, bd=2, relief='raised', bg='black') |
163 | 27 self.labelformatter = opts.get('labelformatter') |
28 try: | |
29 del opts['labelformatter'] | |
30 except KeyError: | |
31 pass | |
32 | |
0 | 33 opts.setdefault('variable', Tk.DoubleVar()) |
34 opts.setdefault('showvalue', 0) | |
161
0803fb42109d
we now have TkCueList, which is really cool. it doesn't provide editing
dmcc
parents:
158
diff
changeset
|
35 |
0803fb42109d
we now have TkCueList, which is really cool. it doesn't provide editing
dmcc
parents:
158
diff
changeset
|
36 self.normaltrough = opts.get('troughcolor', 'black') |
0803fb42109d
we now have TkCueList, which is really cool. it doesn't provide editing
dmcc
parents:
158
diff
changeset
|
37 self.flashtrough = opts.get('flashtroughcolor', 'red') |
163 | 38 try: |
39 del opts['flashtroughcolor'] | |
40 except KeyError: | |
41 pass | |
161
0803fb42109d
we now have TkCueList, which is really cool. it doesn't provide editing
dmcc
parents:
158
diff
changeset
|
42 |
0 | 43 self.scale_var = opts['variable'] |
44 self.scale = Tk.Scale(self, **opts) | |
45 self.scale.pack(side='top', expand=1, fill='both') | |
162
6c5753bad783
basic cue editing, darker colors, fade time selector is now a "TixControl"
dmcc
parents:
161
diff
changeset
|
46 self.name = Tk.Label(self, text=label, bg='black', fg='white') |
0 | 47 self.name.pack(side='bottom') |
163 | 48 self.scale_value = Tk.Label(self, bg='black', fg='white') |
0 | 49 self.scale_value.pack(side='bottom') |
50 self.scale_var.trace('w', self.update_value_label) | |
51 self.update_value_label() | |
158
5c7ac46e33d3
more disabling of stuff that make no sense at certain times and some
dmcc
parents:
157
diff
changeset
|
52 self.disabled = (self.scale['state'] == 'disabled') |
0 | 53 def set_label(self, label): |
54 self.name['text'] = label | |
55 def update_value_label(self, *args): | |
56 val = self.scale_var.get() * 100 | |
163 | 57 if self.labelformatter: |
58 format = self.labelformatter(val) | |
59 else: | |
60 format = "%0.2f" % val | |
61 self.scale_value['text'] = format | |
161
0803fb42109d
we now have TkCueList, which is really cool. it doesn't provide editing
dmcc
parents:
158
diff
changeset
|
62 if val != 0: |
0803fb42109d
we now have TkCueList, which is really cool. it doesn't provide editing
dmcc
parents:
158
diff
changeset
|
63 self.scale['troughcolor'] = self.flashtrough |
0803fb42109d
we now have TkCueList, which is really cool. it doesn't provide editing
dmcc
parents:
158
diff
changeset
|
64 else: |
0803fb42109d
we now have TkCueList, which is really cool. it doesn't provide editing
dmcc
parents:
158
diff
changeset
|
65 self.scale['troughcolor'] = self.normaltrough |
158
5c7ac46e33d3
more disabling of stuff that make no sense at certain times and some
dmcc
parents:
157
diff
changeset
|
66 def disable(self): |
5c7ac46e33d3
more disabling of stuff that make no sense at certain times and some
dmcc
parents:
157
diff
changeset
|
67 if not self.disabled: |
5c7ac46e33d3
more disabling of stuff that make no sense at certain times and some
dmcc
parents:
157
diff
changeset
|
68 self.scale['state'] = 'disabled' |
5c7ac46e33d3
more disabling of stuff that make no sense at certain times and some
dmcc
parents:
157
diff
changeset
|
69 self.scale_var.set(0) |
5c7ac46e33d3
more disabling of stuff that make no sense at certain times and some
dmcc
parents:
157
diff
changeset
|
70 self.disabled = 1 |
5c7ac46e33d3
more disabling of stuff that make no sense at certain times and some
dmcc
parents:
157
diff
changeset
|
71 def enable(self): |
5c7ac46e33d3
more disabling of stuff that make no sense at certain times and some
dmcc
parents:
157
diff
changeset
|
72 if self.disabled: |
5c7ac46e33d3
more disabling of stuff that make no sense at certain times and some
dmcc
parents:
157
diff
changeset
|
73 self.scale['state'] = 'normal' |
5c7ac46e33d3
more disabling of stuff that make no sense at certain times and some
dmcc
parents:
157
diff
changeset
|
74 self.disabled = 0 |
0 | 75 |
76 class TimedGoButton(Tk.Frame): | |
77 """Go button, fade time entry, and time fader""" | |
161
0803fb42109d
we now have TkCueList, which is really cool. it doesn't provide editing
dmcc
parents:
158
diff
changeset
|
78 def __init__(self, master, name, scale_to_fade, **kw): |
162
6c5753bad783
basic cue editing, darker colors, fade time selector is now a "TixControl"
dmcc
parents:
161
diff
changeset
|
79 Tk.Frame.__init__(self, master, bg='black') |
0 | 80 self.name = name |
81 self.scale_to_fade = scale_to_fade | |
161
0803fb42109d
we now have TkCueList, which is really cool. it doesn't provide editing
dmcc
parents:
158
diff
changeset
|
82 self.button = Tk.Button(self, text=name, command=self.start_fade, **kw) |
0 | 83 self.button.pack(fill='both', expand=1, side='left') |
162
6c5753bad783
basic cue editing, darker colors, fade time selector is now a "TixControl"
dmcc
parents:
161
diff
changeset
|
84 |
6c5753bad783
basic cue editing, darker colors, fade time selector is now a "TixControl"
dmcc
parents:
161
diff
changeset
|
85 self.timer_var = Tk.DoubleVar() |
168 | 86 self.timer_entry = Tk.Control(self, step=0.5, min=0, integer=0, |
87 variable=self.timer_var, selectmode='immediate') | |
88 for widget in (self.timer_entry, self.timer_entry.entry, | |
89 self.timer_entry.incr, self.timer_entry.decr, self.button, self): | |
90 widget.bind("<4>", self.wheelscroll) | |
91 widget.bind("<5>", self.wheelscroll) | |
92 self.timer_entry.entry.configure(width=5, bg='black', fg='white') | |
0 | 93 self.timer_entry.pack(fill='y', side='left') |
168 | 94 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
|
95 self.disabled = (self.button['state'] == 'disabled') |
178 | 96 self.start_time = 0 |
167 | 97 self.fading = 0 |
178 | 98 self.last_after_key = 0 |
179 | 99 def manual_override(self, *args): |
100 self.end_fade() | |
168 | 101 def wheelscroll(self, event): |
102 """Mouse wheel increments or decrements timer.""" | |
103 if event.num == 4: # scroll up | |
104 self.timer_entry.increment() | |
105 else: # scroll down | |
106 self.timer_entry.decrement() | |
0 | 107 def start_fade(self, end_level=1): |
178 | 108 self.last_start_time = self.start_time |
0 | 109 self.start_time = time.time() |
110 self.start_level = self.scale_to_fade.scale_var.get() | |
111 self.end_level = end_level | |
178 | 112 |
113 if self.fading == 1: # if we're already fading | |
114 self.fading = 'paused' | |
179 | 115 # new fade should be as long as however much was left |
116 self.fade_length = self.fade_length - \ | |
117 (time.time() - self.last_start_time) | |
118 self.button['text'] = 'Unpause' | |
119 self.after_cancel(self.last_after_key) | |
178 | 120 else: |
121 try: | |
122 fade_time = float(self.timer_var.get()) | |
123 except ValueError: | |
124 # since we use a TixControl now, i don't think we need to worry | |
125 # about validation any more. | |
126 print ">>> Can't fade -- bad time", self.timer_var.get() | |
127 return | |
128 | |
179 | 129 # if we're not already fading, we get our time from the entry |
178 | 130 if self.fading != 'paused': |
131 self.fade_length = fade_time | |
179 | 132 |
178 | 133 self.button['text'] = 'Pause' |
134 self.fading = 1 | |
135 self.do_fade() | |
0 | 136 def do_fade(self): |
137 diff = time.time() - self.start_time | |
138 if diff < self.fade_length: | |
139 percent = diff / self.fade_length | |
140 newlevel = self.start_level + \ | |
141 (percent * (self.end_level - self.start_level)) | |
142 self.scale_to_fade.scale_var.set(newlevel) | |
143 | |
144 if newlevel != self.end_level: | |
178 | 145 self.last_after_key = self.after(10, self.do_fade) |
167 | 146 else: |
178 | 147 self.end_fade() |
0 | 148 else: |
149 self.scale_to_fade.scale_var.set(self.end_level) | |
178 | 150 self.end_fade() |
151 def end_fade(self): | |
152 self.button['text'] = self.name | |
153 self.fading = 0 | |
154 self.after_cancel(self.last_after_key) | |
158
5c7ac46e33d3
more disabling of stuff that make no sense at certain times and some
dmcc
parents:
157
diff
changeset
|
155 def disable(self): |
5c7ac46e33d3
more disabling of stuff that make no sense at certain times and some
dmcc
parents:
157
diff
changeset
|
156 if not self.disabled: |
5c7ac46e33d3
more disabling of stuff that make no sense at certain times and some
dmcc
parents:
157
diff
changeset
|
157 self.button['state'] = 'disabled' |
5c7ac46e33d3
more disabling of stuff that make no sense at certain times and some
dmcc
parents:
157
diff
changeset
|
158 self.disabled = 1 |
5c7ac46e33d3
more disabling of stuff that make no sense at certain times and some
dmcc
parents:
157
diff
changeset
|
159 def enable(self): |
5c7ac46e33d3
more disabling of stuff that make no sense at certain times and some
dmcc
parents:
157
diff
changeset
|
160 if self.disabled: |
5c7ac46e33d3
more disabling of stuff that make no sense at certain times and some
dmcc
parents:
157
diff
changeset
|
161 self.button['state'] = 'normal' |
5c7ac46e33d3
more disabling of stuff that make no sense at certain times and some
dmcc
parents:
157
diff
changeset
|
162 self.disabled = 0 |
162
6c5753bad783
basic cue editing, darker colors, fade time selector is now a "TixControl"
dmcc
parents:
161
diff
changeset
|
163 def set_time(self, time): |
6c5753bad783
basic cue editing, darker colors, fade time selector is now a "TixControl"
dmcc
parents:
161
diff
changeset
|
164 self.timer_var.set(time) |
163 | 165 def get_time(self): |
166 return self.timer_var.get() | |
167 | 167 def is_fading(self): |
168 return self.fading | |
0 | 169 |
170 class CueFader(Tk.Frame): | |
171 def __init__(self, master, cuelist): | |
162
6c5753bad783
basic cue editing, darker colors, fade time selector is now a "TixControl"
dmcc
parents:
161
diff
changeset
|
172 Tk.Frame.__init__(self, master, bg='black') |
0 | 173 self.cuelist = cuelist |
168 | 174 self.cuelist.set_fader(self) |
175 | |
176 self.last_levels_sent = 0 | |
177 self.current_dmx_levels = [0] * 68 | |
178 self.after(0, self.send_dmx_levels_loop) # start DMX sending loop | |
0 | 179 |
161
0803fb42109d
we now have TkCueList, which is really cool. it doesn't provide editing
dmcc
parents:
158
diff
changeset
|
180 # this is a mechanism to stop Tk from autoshifting too much. |
0803fb42109d
we now have TkCueList, which is really cool. it doesn't provide editing
dmcc
parents:
158
diff
changeset
|
181 # if this variable is true, the mouse button is down. we don't want |
0803fb42109d
we now have TkCueList, which is really cool. it doesn't provide editing
dmcc
parents:
158
diff
changeset
|
182 # to shift until they release it. when it is released, we will |
0803fb42109d
we now have TkCueList, which is really cool. it doesn't provide editing
dmcc
parents:
158
diff
changeset
|
183 # set it to false and then call autoshift. |
0803fb42109d
we now have TkCueList, which is really cool. it doesn't provide editing
dmcc
parents:
158
diff
changeset
|
184 self.no_shifts_until_release = 0 |
0803fb42109d
we now have TkCueList, which is really cool. it doesn't provide editing
dmcc
parents:
158
diff
changeset
|
185 |
0 | 186 self.scales = {} |
187 self.shift_buttons = {} | |
158
5c7ac46e33d3
more disabling of stuff that make no sense at certain times and some
dmcc
parents:
157
diff
changeset
|
188 self.go_buttons = {} |
161
0803fb42109d
we now have TkCueList, which is really cool. it doesn't provide editing
dmcc
parents:
158
diff
changeset
|
189 |
162
6c5753bad783
basic cue editing, darker colors, fade time selector is now a "TixControl"
dmcc
parents:
161
diff
changeset
|
190 topframe = Tk.Frame(self, bg='black') |
161
0803fb42109d
we now have TkCueList, which is really cool. it doesn't provide editing
dmcc
parents:
158
diff
changeset
|
191 |
0803fb42109d
we now have TkCueList, which is really cool. it doesn't provide editing
dmcc
parents:
158
diff
changeset
|
192 self.set_prev_button = Tk.Button(topframe, text='Set Prev', |
0803fb42109d
we now have TkCueList, which is really cool. it doesn't provide editing
dmcc
parents:
158
diff
changeset
|
193 command=lambda: cuelist.set_selection_as_prev(), |
0803fb42109d
we now have TkCueList, which is really cool. it doesn't provide editing
dmcc
parents:
158
diff
changeset
|
194 fg='white', bg='blue') |
0803fb42109d
we now have TkCueList, which is really cool. it doesn't provide editing
dmcc
parents:
158
diff
changeset
|
195 self.set_prev_button.pack(side='left') |
0803fb42109d
we now have TkCueList, which is really cool. it doesn't provide editing
dmcc
parents:
158
diff
changeset
|
196 |
168 | 197 self.auto_shift = Tk.IntVar() |
198 self.auto_shift.set(1) | |
199 | |
161
0803fb42109d
we now have TkCueList, which is really cool. it doesn't provide editing
dmcc
parents:
158
diff
changeset
|
200 self.auto_shift_checkbutton = Tk.Checkbutton(topframe, |
155 | 201 variable=self.auto_shift, text='Autoshift', |
163 | 202 command=self.toggle_autoshift, bg='black', fg='white', |
203 highlightbackground='black') | |
204 self.auto_shift_checkbutton.pack(fill='both', side='left') | |
161
0803fb42109d
we now have TkCueList, which is really cool. it doesn't provide editing
dmcc
parents:
158
diff
changeset
|
205 |
168 | 206 self.auto_load_times = Tk.IntVar() |
207 self.auto_load_times.set(1) | |
208 | |
209 self.auto_load_times_checkbutton = Tk.Checkbutton(topframe, | |
210 variable=self.auto_load_times, text='Autoload Times', | |
176 | 211 bg='black', fg='white', |
168 | 212 highlightbackground='black') |
213 self.auto_load_times_checkbutton.pack(fill='both', side='left') | |
214 | |
176 | 215 self.mute = Tk.IntVar() |
216 self.mute.set(0) | |
217 | |
218 self.mutebutton = Tk.Checkbutton(topframe, | |
219 variable=self.mute, text='Mute', | |
220 bg='black', fg='white', | |
221 highlightbackground='black', | |
222 command=self.send_dmx_levels) | |
223 self.mutebutton.pack(fill='both', side='left') | |
224 | |
161
0803fb42109d
we now have TkCueList, which is really cool. it doesn't provide editing
dmcc
parents:
158
diff
changeset
|
225 self.set_next_button = Tk.Button(topframe, text='Set Next', |
0803fb42109d
we now have TkCueList, which is really cool. it doesn't provide editing
dmcc
parents:
158
diff
changeset
|
226 command=lambda: cuelist.set_selection_as_next(), |
0803fb42109d
we now have TkCueList, which is really cool. it doesn't provide editing
dmcc
parents:
158
diff
changeset
|
227 fg='white', bg='red') |
0803fb42109d
we now have TkCueList, which is really cool. it doesn't provide editing
dmcc
parents:
158
diff
changeset
|
228 self.set_next_button.pack(side='left') |
155 | 229 |
161
0803fb42109d
we now have TkCueList, which is really cool. it doesn't provide editing
dmcc
parents:
158
diff
changeset
|
230 topframe.pack(side='top') |
0803fb42109d
we now have TkCueList, which is really cool. it doesn't provide editing
dmcc
parents:
158
diff
changeset
|
231 |
162
6c5753bad783
basic cue editing, darker colors, fade time selector is now a "TixControl"
dmcc
parents:
161
diff
changeset
|
232 faderframe = Tk.Frame(self, bg='black') |
161
0803fb42109d
we now have TkCueList, which is really cool. it doesn't provide editing
dmcc
parents:
158
diff
changeset
|
233 self.direction_info = (('Prev', 1, 0, 'left', 'blue'), |
0803fb42109d
we now have TkCueList, which is really cool. it doesn't provide editing
dmcc
parents:
158
diff
changeset
|
234 ('Next', 0, 1, 'right', 'red')) |
0803fb42109d
we now have TkCueList, which is really cool. it doesn't provide editing
dmcc
parents:
158
diff
changeset
|
235 for name, start, end, side, color in self.direction_info: |
162
6c5753bad783
basic cue editing, darker colors, fade time selector is now a "TixControl"
dmcc
parents:
161
diff
changeset
|
236 frame = Tk.Frame(self, bg='black') |
0 | 237 scale = LabelledScale(frame, name, from_=start, to_=end, |
163 | 238 res=0.0001, orient='horiz', flashtroughcolor=color, |
239 labelformatter=lambda val, name=name: self.get_scale_desc(val, | |
240 name)) | |
161
0803fb42109d
we now have TkCueList, which is really cool. it doesn't provide editing
dmcc
parents:
158
diff
changeset
|
241 scale.pack(fill='x', expand=0) |
0803fb42109d
we now have TkCueList, which is really cool. it doesn't provide editing
dmcc
parents:
158
diff
changeset
|
242 go = TimedGoButton(frame, 'Go %s' % name, scale, bg=color, |
178 | 243 fg='white', width=10) |
0 | 244 go.pack(fill='both', expand=1) |
245 frame.pack(side=side, fill='both', expand=1) | |
246 | |
155 | 247 shift = Tk.Button(frame, text="Shift %s" % name, state='disabled', |
161
0803fb42109d
we now have TkCueList, which is really cool. it doesn't provide editing
dmcc
parents:
158
diff
changeset
|
248 command=lambda name=name: self.shift(name), fg=color, |
0803fb42109d
we now have TkCueList, which is really cool. it doesn't provide editing
dmcc
parents:
158
diff
changeset
|
249 bg='black') |
155 | 250 |
0 | 251 self.scales[name] = scale |
252 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
|
253 self.go_buttons[name] = go |
0 | 254 |
255 scale.scale_var.trace('w', \ | |
256 lambda x, y, z, name=name, scale=scale: self.xfade(name, scale)) | |
168 | 257 go.timer_var.trace('w', |
258 lambda x, y, z, scale=scale: scale.update_value_label()) | |
161
0803fb42109d
we now have TkCueList, which is really cool. it doesn't provide editing
dmcc
parents:
158
diff
changeset
|
259 |
0803fb42109d
we now have TkCueList, which is really cool. it doesn't provide editing
dmcc
parents:
158
diff
changeset
|
260 def button_press(event, name=name, scale=scale): |
0803fb42109d
we now have TkCueList, which is really cool. it doesn't provide editing
dmcc
parents:
158
diff
changeset
|
261 self.no_shifts_until_release = 1 # prevent shifts until release |
0803fb42109d
we now have TkCueList, which is really cool. it doesn't provide editing
dmcc
parents:
158
diff
changeset
|
262 def button_release(event, name=name, scale=scale): |
0803fb42109d
we now have TkCueList, which is really cool. it doesn't provide editing
dmcc
parents:
158
diff
changeset
|
263 self.no_shifts_until_release = 0 |
0803fb42109d
we now have TkCueList, which is really cool. it doesn't provide editing
dmcc
parents:
158
diff
changeset
|
264 self.autoshift(name, scale) |
0803fb42109d
we now have TkCueList, which is really cool. it doesn't provide editing
dmcc
parents:
158
diff
changeset
|
265 |
0803fb42109d
we now have TkCueList, which is really cool. it doesn't provide editing
dmcc
parents:
158
diff
changeset
|
266 scale.scale.bind("<ButtonPress>", button_press) |
0803fb42109d
we now have TkCueList, which is really cool. it doesn't provide editing
dmcc
parents:
158
diff
changeset
|
267 scale.scale.bind("<ButtonRelease>", button_release) |
0803fb42109d
we now have TkCueList, which is really cool. it doesn't provide editing
dmcc
parents:
158
diff
changeset
|
268 faderframe.pack(side='bottom', fill='both', expand=1) |
168 | 269 |
270 self.current_dir = 'Next' | |
167 | 271 self.cues_as_subs = {} |
168 | 272 self.update_cue_cache() |
273 def reload_cue_times(self): | |
274 prev, cur, next = self.cuelist.get_current_cues() | |
275 self.go_buttons['Next'].set_time(next.time) | |
178 | 276 def update_cue_cache(self, compute_dmx_levels=1): |
168 | 277 """Rebuilds subs from the current cues. As this is expensive, we don't |
278 do it unless necessary (i.e. whenever we shift or a cue is edited)""" | |
178 | 279 # print "update_cue_cache" |
168 | 280 # load the subs to fade between |
281 for cue, name in zip(self.cuelist.get_current_cues(), | |
282 ('Prev', 'Cur', 'Next')): | |
283 self.cues_as_subs[name] = cue.get_levels_as_sub() | |
178 | 284 if compute_dmx_levels: |
285 self.compute_dmx_levels() | |
168 | 286 def compute_dmx_levels(self): |
287 """Compute the DMX levels to send. This should get called whenever the | |
288 DMX levels could change: either during a crossfade or when a cue is | |
289 edited. Since this is called when we know that a change might occur, | |
290 we will send the new levels too.""" | |
291 cur_sub = self.cues_as_subs.get('Cur') | |
292 if cur_sub: | |
293 scale = self.scales[self.current_dir] | |
294 scale_val = scale.scale_var.get() | |
295 | |
296 other_sub = self.cues_as_subs[self.current_dir] | |
297 current_levels_as_sub = cur_sub.crossfade(other_sub, scale_val) | |
298 self.current_dmx_levels = current_levels_as_sub.get_dmx_list() | |
299 self.send_dmx_levels() | |
178 | 300 |
301 # print "compute_dmx_levels: fade at", scale_val | |
302 # print "between", cur_sub.name, | |
303 # print "and", other_sub.name | |
304 # print | |
176 | 305 def send_dmx_levels(self, *args): |
168 | 306 # print "send_dmx_levels", self.current_dmx_levels |
176 | 307 if self.mute.get(): |
308 dmxclient.outputlevels([0] * 68) | |
309 else: | |
310 dmxclient.outputlevels(self.current_dmx_levels) | |
168 | 311 self.last_levels_sent = time.time() |
312 def send_dmx_levels_loop(self): | |
313 diff = time.time() - self.last_levels_sent | |
314 if diff >= 2: # too long since last send | |
315 self.send_dmx_levels() | |
316 self.after(200, self.send_dmx_levels_loop) | |
317 else: | |
318 self.after(int((2 - diff) * 100), self.send_dmx_levels_loop) | |
163 | 319 def get_scale_desc(self, val, name): |
168 | 320 """Returns a description to the TimedGoButton""" |
163 | 321 go_button = self.go_buttons.get(name) |
322 if go_button: | |
323 time = go_button.get_time() | |
324 return "%0.2f%%, %0.1fs left" % (val, time - ((val / 100.0) * time)) | |
325 else: | |
326 return "%0.2f%%" % val | |
155 | 327 def toggle_autoshift(self): |
328 for name, button in self.shift_buttons.items(): | |
329 if not self.auto_shift.get(): | |
330 button.pack(side='bottom', fill='both', expand=1) | |
331 else: | |
332 button.pack_forget() | |
161
0803fb42109d
we now have TkCueList, which is really cool. it doesn't provide editing
dmcc
parents:
158
diff
changeset
|
333 def shift(self, name): |
0803fb42109d
we now have TkCueList, which is really cool. it doesn't provide editing
dmcc
parents:
158
diff
changeset
|
334 # to prevent overshifting |
0803fb42109d
we now have TkCueList, which is really cool. it doesn't provide editing
dmcc
parents:
158
diff
changeset
|
335 if self.no_shifts_until_release: |
0803fb42109d
we now have TkCueList, which is really cool. it doesn't provide editing
dmcc
parents:
158
diff
changeset
|
336 return |
178 | 337 # print "shift", name |
155 | 338 |
178 | 339 self.cuelist.shift((-1, 1)[name == 'Next']) |
340 self.update_cue_cache(compute_dmx_levels=0) | |
158
5c7ac46e33d3
more disabling of stuff that make no sense at certain times and some
dmcc
parents:
157
diff
changeset
|
341 for scale_name, scale in self.scales.items(): |
178 | 342 # print "shift: setting scale to 0", scale_name |
161
0803fb42109d
we now have TkCueList, which is really cool. it doesn't provide editing
dmcc
parents:
158
diff
changeset
|
343 scale.scale.set(0) |
179 | 344 self.go_buttons[scale_name].manual_override() |
178 | 345 self.update_cue_cache(compute_dmx_levels=1) |
167 | 346 |
168 | 347 if self.auto_load_times.get(): |
348 self.reload_cue_times() | |
161
0803fb42109d
we now have TkCueList, which is really cool. it doesn't provide editing
dmcc
parents:
158
diff
changeset
|
349 def autoshift(self, name, scale): |
0 | 350 scale_val = scale.scale_var.get() |
351 | |
352 if scale_val == 1: | |
155 | 353 if self.auto_shift.get(): |
0 | 354 self.shift(name) |
161
0803fb42109d
we now have TkCueList, which is really cool. it doesn't provide editing
dmcc
parents:
158
diff
changeset
|
355 def xfade(self, name, scale): |
0803fb42109d
we now have TkCueList, which is really cool. it doesn't provide editing
dmcc
parents:
158
diff
changeset
|
356 if self.auto_shift.get(): |
0803fb42109d
we now have TkCueList, which is really cool. it doesn't provide editing
dmcc
parents:
158
diff
changeset
|
357 self.autoshift(name, scale) |
0803fb42109d
we now have TkCueList, which is really cool. it doesn't provide editing
dmcc
parents:
158
diff
changeset
|
358 scale_val = scale.scale_var.get() |
0803fb42109d
we now have TkCueList, which is really cool. it doesn't provide editing
dmcc
parents:
158
diff
changeset
|
359 else: |
0803fb42109d
we now have TkCueList, which is really cool. it doesn't provide editing
dmcc
parents:
158
diff
changeset
|
360 scale_val = scale.scale_var.get() |
0803fb42109d
we now have TkCueList, which is really cool. it doesn't provide editing
dmcc
parents:
158
diff
changeset
|
361 if scale_val == 1: |
0803fb42109d
we now have TkCueList, which is really cool. it doesn't provide editing
dmcc
parents:
158
diff
changeset
|
362 self.shift_buttons[name]['state'] = 'normal' |
151
990a9474d0e7
early cue stuff. the CueList will supply the CueFader with the cues to
dmcc
parents:
0
diff
changeset
|
363 else: |
161
0803fb42109d
we now have TkCueList, which is really cool. it doesn't provide editing
dmcc
parents:
158
diff
changeset
|
364 # disable any dangerous shifting |
0803fb42109d
we now have TkCueList, which is really cool. it doesn't provide editing
dmcc
parents:
158
diff
changeset
|
365 self.shift_buttons[name]['state'] = 'disabled' |
0 | 366 |
158
5c7ac46e33d3
more disabling of stuff that make no sense at certain times and some
dmcc
parents:
157
diff
changeset
|
367 d = self.opposite_direction(name) |
0 | 368 if scale_val != 0: |
369 # 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
|
370 self.scales[d].disable() |
5c7ac46e33d3
more disabling of stuff that make no sense at certain times and some
dmcc
parents:
157
diff
changeset
|
371 self.go_buttons[d].disable() |
0 | 372 else: |
158
5c7ac46e33d3
more disabling of stuff that make no sense at certain times and some
dmcc
parents:
157
diff
changeset
|
373 # undo above work |
5c7ac46e33d3
more disabling of stuff that make no sense at certain times and some
dmcc
parents:
157
diff
changeset
|
374 self.scales[d].enable() |
5c7ac46e33d3
more disabling of stuff that make no sense at certain times and some
dmcc
parents:
157
diff
changeset
|
375 self.go_buttons[d].enable() |
167 | 376 |
168 | 377 self.current_dir = name |
378 self.compute_dmx_levels() | |
158
5c7ac46e33d3
more disabling of stuff that make no sense at certain times and some
dmcc
parents:
157
diff
changeset
|
379 def opposite_direction(self, d): |
5c7ac46e33d3
more disabling of stuff that make no sense at certain times and some
dmcc
parents:
157
diff
changeset
|
380 if d == 'Next': |
5c7ac46e33d3
more disabling of stuff that make no sense at certain times and some
dmcc
parents:
157
diff
changeset
|
381 return 'Prev' |
5c7ac46e33d3
more disabling of stuff that make no sense at certain times and some
dmcc
parents:
157
diff
changeset
|
382 else: |
5c7ac46e33d3
more disabling of stuff that make no sense at certain times and some
dmcc
parents:
157
diff
changeset
|
383 return 'Next' |
0 | 384 |
385 class Cue: | |
386 """A Cue has a name, a time, and any number of other attributes.""" | |
167 | 387 def __init__(self, name, time=3, sub_levels='', **attrs): |
0 | 388 self.name = name |
389 self.time = time | |
167 | 390 self.sub_levels = sub_levels |
0 | 391 self.__dict__.update(attrs) |
392 def __repr__(self): | |
393 return "<Cue %s, length %s>" % (self.name, self.time) | |
167 | 394 def get_levels_as_sub(self): |
395 """Get this Cue as a combined Submaster, normalized. This method | |
396 should not be called constantly, since it is somewhat expensive. It | |
397 will reload the submasters from disk, combine all subs together, and | |
398 then compute the normalized form.""" | |
399 subdict = {} | |
168 | 400 for line in self.sub_levels.split(','): |
401 try: | |
167 | 402 line = line.strip() |
168 | 403 if not line: |
404 continue | |
167 | 405 sub, scale = line.split(':') |
406 sub = sub.strip() | |
407 scale = float(scale) | |
408 subdict[sub] = scale | |
168 | 409 except ValueError: |
410 print "Parsing error for '%s' in %s" % (self.sub_levels, self) | |
167 | 411 |
412 s = Submaster.Submasters() | |
413 newsub = Submaster.sub_maxes(*[s[sub] * scale | |
414 for sub, scale in subdict.items()]) | |
415 return newsub.get_normalized_copy() | |
0 | 416 |
417 empty_cue = Cue('empty') | |
418 | |
419 allow_class_to_be_pickled(Cue) | |
420 | |
421 class CueList: | |
422 """Persistent list of Cues""" | |
423 def __init__(self, filename): | |
424 self.filename = filename | |
425 self.treedict = TreeDict() | |
426 try: | |
427 self.treedict.load(filename) | |
428 except IOError: | |
429 self.treedict.cues = [] | |
430 self.cues = self.treedict.cues | |
167 | 431 self.current_cue_index = -1 |
432 self.next_pointer = 0 | |
0 | 433 self.prev_pointer = None |
434 | |
435 import atexit | |
436 atexit.register(self.save) | |
437 def add_cue(self, cue, index=None): | |
438 """Adds a Cue object to the list. If no index is specified, | |
439 the cue will be added to the end.""" | |
440 index = index or len(self.cues) | |
441 self.cues.insert(index, cue) | |
442 def shift(self, diff): | |
443 """Shift through cue history""" | |
444 old_index = self.current_cue_index | |
445 self.current_cue_index = None | |
446 if diff < 0: # if going backwards | |
447 if self.prev_pointer: # use a prev pointer if we have one | |
448 self.current_cue_index = self.prev_pointer | |
449 self.next_pointer = old_index | |
450 self.prev_pointer = None | |
451 else: | |
452 if self.next_pointer: # use a next pointer if we have one | |
453 self.current_cue_index = self.next_pointer | |
454 self.next_pointer = None | |
455 self.prev_pointer = old_index | |
456 if not self.current_cue_index: | |
457 self.current_cue_index = old_index + diff | |
458 def set_next(self, index): | |
459 self.next_pointer = index | |
460 def set_prev(self, index): | |
461 self.prev_pointer = index | |
462 def bound_index(self, index): | |
168 | 463 if not self.cues or index < 0: |
0 | 464 return None |
465 else: | |
168 | 466 return min(index, len(self.cues) - 1) |
0 | 467 def get_current_cue_indices(self): |
168 | 468 """Returns a list of the indices of three cues: the previous cue, |
469 the current cue, and the next cue.""" | |
0 | 470 cur = self.current_cue_index |
471 return [self.bound_index(index) for index in | |
472 (self.prev_pointer or cur - 1, | |
473 cur, | |
474 self.next_pointer or cur + 1)] | |
475 def get_current_cues(self): | |
168 | 476 """Returns a list of three cues: the previous cue, the current cue, |
477 and the next cue.""" | |
0 | 478 return [self.get_cue_by_index(index) |
479 for index in self.get_current_cue_indices()] | |
480 def get_cue_by_index(self, index): | |
168 | 481 try: |
0 | 482 return self.cues[self.bound_index(index)] |
168 | 483 except TypeError: |
0 | 484 return empty_cue |
485 def __del__(self): | |
486 self.save() | |
185 | 487 def save(self, backup=0): |
488 if backup: | |
489 | |
490 backupfilename = "%s-backup" % self.filename | |
491 print time.asctime(), "Saving backup version of cues to", \ | |
492 backupfilename | |
493 self.treedict.save(backupfilename) | |
494 else: | |
495 print time.asctime(), "Saving cues to", self.filename | |
496 self.treedict.save(self.filename) | |
161
0803fb42109d
we now have TkCueList, which is really cool. it doesn't provide editing
dmcc
parents:
158
diff
changeset
|
497 def reload(self): |
0803fb42109d
we now have TkCueList, which is really cool. it doesn't provide editing
dmcc
parents:
158
diff
changeset
|
498 # TODO: we probably will need to make sure that indices still make |
0803fb42109d
we now have TkCueList, which is really cool. it doesn't provide editing
dmcc
parents:
158
diff
changeset
|
499 # sense, etc. |
0803fb42109d
we now have TkCueList, which is really cool. it doesn't provide editing
dmcc
parents:
158
diff
changeset
|
500 self.treedict.load(self.filename) |
0803fb42109d
we now have TkCueList, which is really cool. it doesn't provide editing
dmcc
parents:
158
diff
changeset
|
501 |
0803fb42109d
we now have TkCueList, which is really cool. it doesn't provide editing
dmcc
parents:
158
diff
changeset
|
502 class TkCueList(CueList, Tk.Frame): |
0803fb42109d
we now have TkCueList, which is really cool. it doesn't provide editing
dmcc
parents:
158
diff
changeset
|
503 def __init__(self, master, filename): |
0803fb42109d
we now have TkCueList, which is really cool. it doesn't provide editing
dmcc
parents:
158
diff
changeset
|
504 CueList.__init__(self, filename) |
162
6c5753bad783
basic cue editing, darker colors, fade time selector is now a "TixControl"
dmcc
parents:
161
diff
changeset
|
505 Tk.Frame.__init__(self, master, bg='black') |
168 | 506 self.fader = None |
161
0803fb42109d
we now have TkCueList, which is really cool. it doesn't provide editing
dmcc
parents:
158
diff
changeset
|
507 |
162
6c5753bad783
basic cue editing, darker colors, fade time selector is now a "TixControl"
dmcc
parents:
161
diff
changeset
|
508 self.edit_tl = Tk.Toplevel() |
168 | 509 self.editor = CueEditron(self.edit_tl, |
510 changed_callback=self.cue_changed) | |
162
6c5753bad783
basic cue editing, darker colors, fade time selector is now a "TixControl"
dmcc
parents:
161
diff
changeset
|
511 self.editor.pack(fill='both', expand=1) |
6c5753bad783
basic cue editing, darker colors, fade time selector is now a "TixControl"
dmcc
parents:
161
diff
changeset
|
512 |
6c5753bad783
basic cue editing, darker colors, fade time selector is now a "TixControl"
dmcc
parents:
161
diff
changeset
|
513 def edit_cue(index): |
6c5753bad783
basic cue editing, darker colors, fade time selector is now a "TixControl"
dmcc
parents:
161
diff
changeset
|
514 index = int(index) |
6c5753bad783
basic cue editing, darker colors, fade time selector is now a "TixControl"
dmcc
parents:
161
diff
changeset
|
515 self.editor.set_cue_to_edit(self.cues[index]) |
6c5753bad783
basic cue editing, darker colors, fade time selector is now a "TixControl"
dmcc
parents:
161
diff
changeset
|
516 |
181 | 517 self.columns = ('name', 'time', 'page', 'cuenum', 'desc', 'sub_levels') |
161
0803fb42109d
we now have TkCueList, which is really cool. it doesn't provide editing
dmcc
parents:
158
diff
changeset
|
518 self.scrolled_hlist = Tk.ScrolledHList(self, |
0803fb42109d
we now have TkCueList, which is really cool. it doesn't provide editing
dmcc
parents:
158
diff
changeset
|
519 options='hlist.columns %d hlist.header 1' % len(self.columns)) |
0803fb42109d
we now have TkCueList, which is really cool. it doesn't provide editing
dmcc
parents:
158
diff
changeset
|
520 self.hlist = self.scrolled_hlist.hlist |
0803fb42109d
we now have TkCueList, which is really cool. it doesn't provide editing
dmcc
parents:
158
diff
changeset
|
521 self.hlist.configure(fg='white', bg='black', |
162
6c5753bad783
basic cue editing, darker colors, fade time selector is now a "TixControl"
dmcc
parents:
161
diff
changeset
|
522 command=self.select_callback, browsecmd=edit_cue) |
163 | 523 self.hlist.bind("<4>", self.wheelscroll) |
524 self.hlist.bind("<5>", self.wheelscroll) | |
161
0803fb42109d
we now have TkCueList, which is really cool. it doesn't provide editing
dmcc
parents:
158
diff
changeset
|
525 self.scrolled_hlist.pack(fill='both', expand=1) |
0803fb42109d
we now have TkCueList, which is really cool. it doesn't provide editing
dmcc
parents:
158
diff
changeset
|
526 |
0803fb42109d
we now have TkCueList, which is really cool. it doesn't provide editing
dmcc
parents:
158
diff
changeset
|
527 boldfont = self.tk.call('tix', 'option', 'get', |
0803fb42109d
we now have TkCueList, which is really cool. it doesn't provide editing
dmcc
parents:
158
diff
changeset
|
528 'bold_font') |
0803fb42109d
we now have TkCueList, which is really cool. it doesn't provide editing
dmcc
parents:
158
diff
changeset
|
529 header_style = Tk.DisplayStyle('text', refwindow=self, |
0803fb42109d
we now have TkCueList, which is really cool. it doesn't provide editing
dmcc
parents:
158
diff
changeset
|
530 anchor='center', padx=8, pady=2, font=boldfont) |
0803fb42109d
we now have TkCueList, which is really cool. it doesn't provide editing
dmcc
parents:
158
diff
changeset
|
531 |
0803fb42109d
we now have TkCueList, which is really cool. it doesn't provide editing
dmcc
parents:
158
diff
changeset
|
532 for count, header in enumerate(self.columns): |
0803fb42109d
we now have TkCueList, which is really cool. it doesn't provide editing
dmcc
parents:
158
diff
changeset
|
533 self.hlist.header_create(count, itemtype='text', |
0803fb42109d
we now have TkCueList, which is really cool. it doesn't provide editing
dmcc
parents:
158
diff
changeset
|
534 text=header, style=header_style) |
0803fb42109d
we now have TkCueList, which is really cool. it doesn't provide editing
dmcc
parents:
158
diff
changeset
|
535 |
0803fb42109d
we now have TkCueList, which is really cool. it doesn't provide editing
dmcc
parents:
158
diff
changeset
|
536 self.cue_label_windows = {} |
0803fb42109d
we now have TkCueList, which is really cool. it doesn't provide editing
dmcc
parents:
158
diff
changeset
|
537 for count, cue in enumerate(self.cues): |
0803fb42109d
we now have TkCueList, which is really cool. it doesn't provide editing
dmcc
parents:
158
diff
changeset
|
538 self.display_cue(count, cue) |
0803fb42109d
we now have TkCueList, which is really cool. it doesn't provide editing
dmcc
parents:
158
diff
changeset
|
539 self.update_cue_indicators() |
185 | 540 self.save_loop() |
168 | 541 def set_fader(self, fader): |
542 self.fader = fader | |
163 | 543 def wheelscroll(self, evt): |
544 """Perform mouse wheel scrolling""" | |
168 | 545 if evt.num == 4: # scroll down |
163 | 546 amount = -2 |
168 | 547 else: # scroll up |
548 amount = 2 | |
163 | 549 self.hlist.yview('scroll', amount, 'units') |
168 | 550 def cue_changed(self, cue): |
163 | 551 path = self.cues.index(cue) |
552 for col, header in enumerate(self.columns): | |
553 try: | |
554 text = getattr(cue, header) | |
555 except AttributeError: | |
556 text = '' | |
162
6c5753bad783
basic cue editing, darker colors, fade time selector is now a "TixControl"
dmcc
parents:
161
diff
changeset
|
557 |
163 | 558 if col == 0: |
559 self.cue_label_windows[path]['text'] = text | |
560 else: | |
561 self.hlist.item_configure(path, col, text=text) | |
168 | 562 |
563 if cue in self.get_current_cues() and self.fader: | |
564 self.fader.update_cue_cache() | |
565 self.fader.reload_cue_times() | |
162
6c5753bad783
basic cue editing, darker colors, fade time selector is now a "TixControl"
dmcc
parents:
161
diff
changeset
|
566 def display_cue(self, path, cue): |
161
0803fb42109d
we now have TkCueList, which is really cool. it doesn't provide editing
dmcc
parents:
158
diff
changeset
|
567 for col, header in enumerate(self.columns): |
0803fb42109d
we now have TkCueList, which is really cool. it doesn't provide editing
dmcc
parents:
158
diff
changeset
|
568 try: |
0803fb42109d
we now have TkCueList, which is really cool. it doesn't provide editing
dmcc
parents:
158
diff
changeset
|
569 text = getattr(cue, header) |
0803fb42109d
we now have TkCueList, which is really cool. it doesn't provide editing
dmcc
parents:
158
diff
changeset
|
570 except AttributeError: |
0803fb42109d
we now have TkCueList, which is really cool. it doesn't provide editing
dmcc
parents:
158
diff
changeset
|
571 text = '' |
0803fb42109d
we now have TkCueList, which is really cool. it doesn't provide editing
dmcc
parents:
158
diff
changeset
|
572 |
0803fb42109d
we now have TkCueList, which is really cool. it doesn't provide editing
dmcc
parents:
158
diff
changeset
|
573 if col == 0: |
0803fb42109d
we now have TkCueList, which is really cool. it doesn't provide editing
dmcc
parents:
158
diff
changeset
|
574 lab = Tk.Label(self.hlist, text=text, fg='white', bg='black') |
0803fb42109d
we now have TkCueList, which is really cool. it doesn't provide editing
dmcc
parents:
158
diff
changeset
|
575 def select_and_highlight(event): |
162
6c5753bad783
basic cue editing, darker colors, fade time selector is now a "TixControl"
dmcc
parents:
161
diff
changeset
|
576 self.select_callback(path) |
161
0803fb42109d
we now have TkCueList, which is really cool. it doesn't provide editing
dmcc
parents:
158
diff
changeset
|
577 self.hlist.selection_clear() |
162
6c5753bad783
basic cue editing, darker colors, fade time selector is now a "TixControl"
dmcc
parents:
161
diff
changeset
|
578 self.hlist.selection_set(path) |
161
0803fb42109d
we now have TkCueList, which is really cool. it doesn't provide editing
dmcc
parents:
158
diff
changeset
|
579 |
0803fb42109d
we now have TkCueList, which is really cool. it doesn't provide editing
dmcc
parents:
158
diff
changeset
|
580 lab.bind("<Double-1>", select_and_highlight) |
162
6c5753bad783
basic cue editing, darker colors, fade time selector is now a "TixControl"
dmcc
parents:
161
diff
changeset
|
581 self.hlist.add(path, itemtype='window', window=lab) |
6c5753bad783
basic cue editing, darker colors, fade time selector is now a "TixControl"
dmcc
parents:
161
diff
changeset
|
582 self.cue_label_windows[path] = lab |
161
0803fb42109d
we now have TkCueList, which is really cool. it doesn't provide editing
dmcc
parents:
158
diff
changeset
|
583 else: |
162
6c5753bad783
basic cue editing, darker colors, fade time selector is now a "TixControl"
dmcc
parents:
161
diff
changeset
|
584 self.hlist.item_create(path, col, text=text) |
161
0803fb42109d
we now have TkCueList, which is really cool. it doesn't provide editing
dmcc
parents:
158
diff
changeset
|
585 def reset_cue_indicators(self, cue_indices=None): |
0803fb42109d
we now have TkCueList, which is really cool. it doesn't provide editing
dmcc
parents:
158
diff
changeset
|
586 """If cue_indices is None, we'll reset all of them.""" |
0803fb42109d
we now have TkCueList, which is really cool. it doesn't provide editing
dmcc
parents:
158
diff
changeset
|
587 cue_indices = cue_indices or self.cue_label_windows.keys() |
0803fb42109d
we now have TkCueList, which is really cool. it doesn't provide editing
dmcc
parents:
158
diff
changeset
|
588 for key in cue_indices: |
168 | 589 if key is None: |
590 continue | |
161
0803fb42109d
we now have TkCueList, which is really cool. it doesn't provide editing
dmcc
parents:
158
diff
changeset
|
591 window = self.cue_label_windows[key] |
0803fb42109d
we now have TkCueList, which is really cool. it doesn't provide editing
dmcc
parents:
158
diff
changeset
|
592 window.configure(fg='white', bg='black') |
0803fb42109d
we now have TkCueList, which is really cool. it doesn't provide editing
dmcc
parents:
158
diff
changeset
|
593 def update_cue_indicators(self): |
0803fb42109d
we now have TkCueList, which is really cool. it doesn't provide editing
dmcc
parents:
158
diff
changeset
|
594 states = dict(zip(self.get_current_cue_indices(), |
0803fb42109d
we now have TkCueList, which is really cool. it doesn't provide editing
dmcc
parents:
158
diff
changeset
|
595 ('prev', 'cur', 'next'))) |
0803fb42109d
we now have TkCueList, which is really cool. it doesn't provide editing
dmcc
parents:
158
diff
changeset
|
596 |
0803fb42109d
we now have TkCueList, which is really cool. it doesn't provide editing
dmcc
parents:
158
diff
changeset
|
597 for count, state in states.items(): |
168 | 598 if count is None: |
599 continue | |
161
0803fb42109d
we now have TkCueList, which is really cool. it doesn't provide editing
dmcc
parents:
158
diff
changeset
|
600 window = self.cue_label_windows[count] |
0803fb42109d
we now have TkCueList, which is really cool. it doesn't provide editing
dmcc
parents:
158
diff
changeset
|
601 bg, fg = cue_state_indicator_colors[state] |
0803fb42109d
we now have TkCueList, which is really cool. it doesn't provide editing
dmcc
parents:
158
diff
changeset
|
602 window.configure(bg=bg, fg=fg) |
0803fb42109d
we now have TkCueList, which is really cool. it doesn't provide editing
dmcc
parents:
158
diff
changeset
|
603 def shift(self, diff): |
0803fb42109d
we now have TkCueList, which is really cool. it doesn't provide editing
dmcc
parents:
158
diff
changeset
|
604 self.reset_cue_indicators(self.get_current_cue_indices()) |
0803fb42109d
we now have TkCueList, which is really cool. it doesn't provide editing
dmcc
parents:
158
diff
changeset
|
605 CueList.shift(self, diff) |
0803fb42109d
we now have TkCueList, which is really cool. it doesn't provide editing
dmcc
parents:
158
diff
changeset
|
606 self.update_cue_indicators() |
0803fb42109d
we now have TkCueList, which is really cool. it doesn't provide editing
dmcc
parents:
158
diff
changeset
|
607 # try to see all indices, but next takes priority over all, and cur |
0803fb42109d
we now have TkCueList, which is really cool. it doesn't provide editing
dmcc
parents:
158
diff
changeset
|
608 # over prev |
0803fb42109d
we now have TkCueList, which is really cool. it doesn't provide editing
dmcc
parents:
158
diff
changeset
|
609 for index in self.get_current_cue_indices(): |
168 | 610 if index is not None: |
611 self.hlist.see(index) | |
161
0803fb42109d
we now have TkCueList, which is really cool. it doesn't provide editing
dmcc
parents:
158
diff
changeset
|
612 def select_callback(self, index): |
0803fb42109d
we now have TkCueList, which is really cool. it doesn't provide editing
dmcc
parents:
158
diff
changeset
|
613 new_next = int(index) |
0803fb42109d
we now have TkCueList, which is really cool. it doesn't provide editing
dmcc
parents:
158
diff
changeset
|
614 self.set_next(new_next) |
0803fb42109d
we now have TkCueList, which is really cool. it doesn't provide editing
dmcc
parents:
158
diff
changeset
|
615 def set_next(self, index): |
0803fb42109d
we now have TkCueList, which is really cool. it doesn't provide editing
dmcc
parents:
158
diff
changeset
|
616 prev, cur, next = self.get_current_cue_indices() |
0803fb42109d
we now have TkCueList, which is really cool. it doesn't provide editing
dmcc
parents:
158
diff
changeset
|
617 self.reset_cue_indicators((next,)) |
0803fb42109d
we now have TkCueList, which is really cool. it doesn't provide editing
dmcc
parents:
158
diff
changeset
|
618 CueList.set_next(self, index) |
0803fb42109d
we now have TkCueList, which is really cool. it doesn't provide editing
dmcc
parents:
158
diff
changeset
|
619 self.update_cue_indicators() |
178 | 620 |
621 if self.fader: # XXX this is untested | |
622 self.fader.update_cue_cache() | |
161
0803fb42109d
we now have TkCueList, which is really cool. it doesn't provide editing
dmcc
parents:
158
diff
changeset
|
623 def set_prev(self, index): |
0803fb42109d
we now have TkCueList, which is really cool. it doesn't provide editing
dmcc
parents:
158
diff
changeset
|
624 prev, cur, next = self.get_current_cue_indices() |
0803fb42109d
we now have TkCueList, which is really cool. it doesn't provide editing
dmcc
parents:
158
diff
changeset
|
625 self.reset_cue_indicators((prev,)) |
0803fb42109d
we now have TkCueList, which is really cool. it doesn't provide editing
dmcc
parents:
158
diff
changeset
|
626 CueList.set_prev(self, index) |
0803fb42109d
we now have TkCueList, which is really cool. it doesn't provide editing
dmcc
parents:
158
diff
changeset
|
627 self.update_cue_indicators() |
178 | 628 |
629 if self.fader: # XXX this is untested | |
630 self.fader.update_cue_cache() | |
161
0803fb42109d
we now have TkCueList, which is really cool. it doesn't provide editing
dmcc
parents:
158
diff
changeset
|
631 def set_selection_as_prev(self): |
0803fb42109d
we now have TkCueList, which is really cool. it doesn't provide editing
dmcc
parents:
158
diff
changeset
|
632 sel = self.hlist.info_selection() |
0803fb42109d
we now have TkCueList, which is really cool. it doesn't provide editing
dmcc
parents:
158
diff
changeset
|
633 if sel: |
0803fb42109d
we now have TkCueList, which is really cool. it doesn't provide editing
dmcc
parents:
158
diff
changeset
|
634 self.set_prev(int(sel[0])) |
0803fb42109d
we now have TkCueList, which is really cool. it doesn't provide editing
dmcc
parents:
158
diff
changeset
|
635 def set_selection_as_next(self): |
0803fb42109d
we now have TkCueList, which is really cool. it doesn't provide editing
dmcc
parents:
158
diff
changeset
|
636 sel = self.hlist.info_selection() |
0803fb42109d
we now have TkCueList, which is really cool. it doesn't provide editing
dmcc
parents:
158
diff
changeset
|
637 if sel: |
0803fb42109d
we now have TkCueList, which is really cool. it doesn't provide editing
dmcc
parents:
158
diff
changeset
|
638 self.set_next(int(sel[0])) |
185 | 639 def save_loop(self): |
640 """This saves the CueList every minute.""" | |
641 self.save(backup=1) | |
642 self.after(60000, self.save_loop) | |
0 | 643 |
162
6c5753bad783
basic cue editing, darker colors, fade time selector is now a "TixControl"
dmcc
parents:
161
diff
changeset
|
644 class CueEditron(Tk.Frame): |
6c5753bad783
basic cue editing, darker colors, fade time selector is now a "TixControl"
dmcc
parents:
161
diff
changeset
|
645 def __init__(self, master, changed_callback=None, cue=None): |
6c5753bad783
basic cue editing, darker colors, fade time selector is now a "TixControl"
dmcc
parents:
161
diff
changeset
|
646 Tk.Frame.__init__(self, master, bg='black') |
6c5753bad783
basic cue editing, darker colors, fade time selector is now a "TixControl"
dmcc
parents:
161
diff
changeset
|
647 self.master = master |
6c5753bad783
basic cue editing, darker colors, fade time selector is now a "TixControl"
dmcc
parents:
161
diff
changeset
|
648 self.cue = cue |
6c5753bad783
basic cue editing, darker colors, fade time selector is now a "TixControl"
dmcc
parents:
161
diff
changeset
|
649 self.changed_callback = changed_callback |
6c5753bad783
basic cue editing, darker colors, fade time selector is now a "TixControl"
dmcc
parents:
161
diff
changeset
|
650 self.enable_callbacks = 1 |
6c5753bad783
basic cue editing, darker colors, fade time selector is now a "TixControl"
dmcc
parents:
161
diff
changeset
|
651 |
6c5753bad783
basic cue editing, darker colors, fade time selector is now a "TixControl"
dmcc
parents:
161
diff
changeset
|
652 self.setup_editing_forms() |
6c5753bad783
basic cue editing, darker colors, fade time selector is now a "TixControl"
dmcc
parents:
161
diff
changeset
|
653 self.set_cue_to_edit(cue) |
6c5753bad783
basic cue editing, darker colors, fade time selector is now a "TixControl"
dmcc
parents:
161
diff
changeset
|
654 def set_cue_to_edit(self, cue): |
6c5753bad783
basic cue editing, darker colors, fade time selector is now a "TixControl"
dmcc
parents:
161
diff
changeset
|
655 if cue != self.cue: |
6c5753bad783
basic cue editing, darker colors, fade time selector is now a "TixControl"
dmcc
parents:
161
diff
changeset
|
656 self.cue = cue |
6c5753bad783
basic cue editing, darker colors, fade time selector is now a "TixControl"
dmcc
parents:
161
diff
changeset
|
657 self.fill_in_cue_info() |
6c5753bad783
basic cue editing, darker colors, fade time selector is now a "TixControl"
dmcc
parents:
161
diff
changeset
|
658 self.set_title() |
6c5753bad783
basic cue editing, darker colors, fade time selector is now a "TixControl"
dmcc
parents:
161
diff
changeset
|
659 def set_title(self): |
6c5753bad783
basic cue editing, darker colors, fade time selector is now a "TixControl"
dmcc
parents:
161
diff
changeset
|
660 try: |
6c5753bad783
basic cue editing, darker colors, fade time selector is now a "TixControl"
dmcc
parents:
161
diff
changeset
|
661 self.master.title("Editing '%s'" % self.cue.name) |
6c5753bad783
basic cue editing, darker colors, fade time selector is now a "TixControl"
dmcc
parents:
161
diff
changeset
|
662 except AttributeError: |
6c5753bad783
basic cue editing, darker colors, fade time selector is now a "TixControl"
dmcc
parents:
161
diff
changeset
|
663 pass |
6c5753bad783
basic cue editing, darker colors, fade time selector is now a "TixControl"
dmcc
parents:
161
diff
changeset
|
664 def setup_editing_forms(self): |
6c5753bad783
basic cue editing, darker colors, fade time selector is now a "TixControl"
dmcc
parents:
161
diff
changeset
|
665 self.variables = {} |
176 | 666 for row, field in enumerate(('name', 'time', 'page', 'cuenum', 'desc', |
168 | 667 'sub_levels')): |
162
6c5753bad783
basic cue editing, darker colors, fade time selector is now a "TixControl"
dmcc
parents:
161
diff
changeset
|
668 lab = Tk.Label(self, text=field, fg='white', bg='black') |
6c5753bad783
basic cue editing, darker colors, fade time selector is now a "TixControl"
dmcc
parents:
161
diff
changeset
|
669 lab.grid(row=row, column=0, sticky='nsew') |
6c5753bad783
basic cue editing, darker colors, fade time selector is now a "TixControl"
dmcc
parents:
161
diff
changeset
|
670 |
6c5753bad783
basic cue editing, darker colors, fade time selector is now a "TixControl"
dmcc
parents:
161
diff
changeset
|
671 entryvar = Tk.StringVar() |
6c5753bad783
basic cue editing, darker colors, fade time selector is now a "TixControl"
dmcc
parents:
161
diff
changeset
|
672 entry = Tk.Entry(self, fg='white', bg='black', |
176 | 673 textvariable=entryvar, insertbackground='white', |
178 | 674 highlightcolor='red') # TODO this red/black is backwards |
162
6c5753bad783
basic cue editing, darker colors, fade time selector is now a "TixControl"
dmcc
parents:
161
diff
changeset
|
675 entry.grid(row=row, column=1, sticky='nsew') |
6c5753bad783
basic cue editing, darker colors, fade time selector is now a "TixControl"
dmcc
parents:
161
diff
changeset
|
676 |
6c5753bad783
basic cue editing, darker colors, fade time selector is now a "TixControl"
dmcc
parents:
161
diff
changeset
|
677 self.variables[field] = entryvar |
6c5753bad783
basic cue editing, darker colors, fade time selector is now a "TixControl"
dmcc
parents:
161
diff
changeset
|
678 |
6c5753bad783
basic cue editing, darker colors, fade time selector is now a "TixControl"
dmcc
parents:
161
diff
changeset
|
679 def field_changed(x, y, z, field=field, entryvar=entryvar): |
6c5753bad783
basic cue editing, darker colors, fade time selector is now a "TixControl"
dmcc
parents:
161
diff
changeset
|
680 if self.cue: |
6c5753bad783
basic cue editing, darker colors, fade time selector is now a "TixControl"
dmcc
parents:
161
diff
changeset
|
681 setattr(self.cue, field, entryvar.get()) |
6c5753bad783
basic cue editing, darker colors, fade time selector is now a "TixControl"
dmcc
parents:
161
diff
changeset
|
682 if self.enable_callbacks and self.changed_callback: |
6c5753bad783
basic cue editing, darker colors, fade time selector is now a "TixControl"
dmcc
parents:
161
diff
changeset
|
683 self.changed_callback(self.cue) |
6c5753bad783
basic cue editing, darker colors, fade time selector is now a "TixControl"
dmcc
parents:
161
diff
changeset
|
684 if field == 'name': |
6c5753bad783
basic cue editing, darker colors, fade time selector is now a "TixControl"
dmcc
parents:
161
diff
changeset
|
685 self.set_title() |
6c5753bad783
basic cue editing, darker colors, fade time selector is now a "TixControl"
dmcc
parents:
161
diff
changeset
|
686 |
6c5753bad783
basic cue editing, darker colors, fade time selector is now a "TixControl"
dmcc
parents:
161
diff
changeset
|
687 entryvar.trace('w', field_changed) |
6c5753bad783
basic cue editing, darker colors, fade time selector is now a "TixControl"
dmcc
parents:
161
diff
changeset
|
688 self.columnconfigure(1, weight=1) |
6c5753bad783
basic cue editing, darker colors, fade time selector is now a "TixControl"
dmcc
parents:
161
diff
changeset
|
689 def fill_in_cue_info(self): |
6c5753bad783
basic cue editing, darker colors, fade time selector is now a "TixControl"
dmcc
parents:
161
diff
changeset
|
690 self.enable_callbacks = 0 |
176 | 691 for row, field in enumerate(('name', 'time', 'page', 'cuenum', 'desc', |
168 | 692 'sub_levels')): |
162
6c5753bad783
basic cue editing, darker colors, fade time selector is now a "TixControl"
dmcc
parents:
161
diff
changeset
|
693 text = '' |
6c5753bad783
basic cue editing, darker colors, fade time selector is now a "TixControl"
dmcc
parents:
161
diff
changeset
|
694 if self.cue: |
6c5753bad783
basic cue editing, darker colors, fade time selector is now a "TixControl"
dmcc
parents:
161
diff
changeset
|
695 try: |
6c5753bad783
basic cue editing, darker colors, fade time selector is now a "TixControl"
dmcc
parents:
161
diff
changeset
|
696 text = getattr(self.cue, field) |
6c5753bad783
basic cue editing, darker colors, fade time selector is now a "TixControl"
dmcc
parents:
161
diff
changeset
|
697 except AttributeError: |
6c5753bad783
basic cue editing, darker colors, fade time selector is now a "TixControl"
dmcc
parents:
161
diff
changeset
|
698 pass |
6c5753bad783
basic cue editing, darker colors, fade time selector is now a "TixControl"
dmcc
parents:
161
diff
changeset
|
699 self.variables[field].set(text) |
6c5753bad783
basic cue editing, darker colors, fade time selector is now a "TixControl"
dmcc
parents:
161
diff
changeset
|
700 self.enable_callbacks = 1 |
6c5753bad783
basic cue editing, darker colors, fade time selector is now a "TixControl"
dmcc
parents:
161
diff
changeset
|
701 |
0 | 702 if __name__ == "__main__": |
161
0803fb42109d
we now have TkCueList, which is really cool. it doesn't provide editing
dmcc
parents:
158
diff
changeset
|
703 root = Tk.Tk() |
162
6c5753bad783
basic cue editing, darker colors, fade time selector is now a "TixControl"
dmcc
parents:
161
diff
changeset
|
704 root.title("ShowMaster 9000") |
178 | 705 root.geometry("600x670") |
171 | 706 cl = TkCueList(root, 'cues/dolly') |
161
0803fb42109d
we now have TkCueList, which is really cool. it doesn't provide editing
dmcc
parents:
158
diff
changeset
|
707 cl.pack(fill='both', expand=1) |
0 | 708 |
157 | 709 fader = CueFader(root, cl) |
710 fader.pack(fill='both', expand=1) | |
162
6c5753bad783
basic cue editing, darker colors, fade time selector is now a "TixControl"
dmcc
parents:
161
diff
changeset
|
711 try: |
6c5753bad783
basic cue editing, darker colors, fade time selector is now a "TixControl"
dmcc
parents:
161
diff
changeset
|
712 Tk.mainloop() |
6c5753bad783
basic cue editing, darker colors, fade time selector is now a "TixControl"
dmcc
parents:
161
diff
changeset
|
713 except KeyboardInterrupt: |
6c5753bad783
basic cue editing, darker colors, fade time selector is now a "TixControl"
dmcc
parents:
161
diff
changeset
|
714 root.destroy() |