# HG changeset patch # User dmcc # Date 2002-07-07 15:40:45 # Node ID 71489bb7152875fdfd6ee9bf75d3fa85c1046c97 # Parent 5ff08b489693fd3fc3c5a3b6d603bc425543fd95 - Meet Fader. He is going to grow up and be a crossfader some day - Meet Fader. He is going to grow up and be a crossfader some day (tomarrow) - Tkinter -> Tix so we can use ScrolledListBox which has a command - Some improvements to Cue - Cues need to specify their final values - Cues are imported by subs. This should be fixed for style points. - Some other cleanups diff --git a/light8/Config.py b/light8/Config.py --- a/light8/Config.py +++ b/light8/Config.py @@ -3,6 +3,7 @@ from time import time from __future__ import generators,division from Subs import * +from Fader import fader patch = { @@ -260,12 +261,8 @@ subs = { 'god' : fulls((6,)), ('strobe', 'grey'):strobe, -# 'midstage' : dict([(r, 100) for r in range(11, 21)]), -# 'backstage' : dict([(r, 100) for r in range(21, 31)]), -# 'frontchase' : mr_effect, 'chase' : chase, 'chase2' : chase, -# 'random' : randomdimmer, } subs["ba outrs"] = fulls("b11 b12 b13 b14 b15 b16 b31 b32 b33 b34 b35 b36".split()) diff --git a/light8/ConfigDummy.py b/light8/ConfigDummy.py --- a/light8/ConfigDummy.py +++ b/light8/ConfigDummy.py @@ -2,7 +2,15 @@ from random import randrange from time import time from __future__ import generators,division from Subs import * +from Cue import * +f1 = Fade('red', 0, 2, 100) +f2 = Fade('green', 1, 3, 50) +f3 = Fade('blue', 0, 4, 0) +f4 = Fade('clear', 0, 8, 75) +c1 = Cue("Color shift", 0, 10, f1, f2, f3, f4) + +cues = [c1] patch = { @@ -241,7 +249,6 @@ def randomdimmer(params, slideradjuster) curtime = time() yield {dim : 100, 20 : params.get_param_value('magic')} - subs = { 'over pit sm' : levs(range(1, 13),(100,0,0,91,77,79,86,55,92,77,59,0)), 'over pit lg' : fulls(range(1, 13)), @@ -264,7 +271,7 @@ subs = { # 'backstage' : dict([(r, 100) for r in range(21, 31)]), # 'frontchase' : mr_effect, 'chase' : chase, - 'chase2' : chase, + # 'chase2' : chase, # 'random' : randomdimmer, } diff --git a/light8/Cue.py b/light8/Cue.py --- a/light8/Cue.py +++ b/light8/Cue.py @@ -7,10 +7,16 @@ class Cue: given time. They contain Fades, which are actually children of Cue, meaning that Cues can contain Cues. This is similar to the Light9 concept of Cues and Fades, but without all the Nodes.""" - def __init__(self, name, starttime, endtime, *fades): + def __init__(self, name, starttime, endtime=None, dur=None, *fades): 'Create a cue' + if not endtime: + endtime = starttime + dur + else: + dur = endtime - starttime + self.name = name self.starttime = starttime + self.dur = dur self.endtime = endtime self.fades = fades self.cuestart = None @@ -38,17 +44,22 @@ class Cue: for ch, lev in fade_d.items(): d[ch] = max(lev, d.get(ch, 0)) return d + def get_end_levels(self): + 'Returns the final levels' + d = {} + for fade in self.fades: + fade_d = fade.get_end_levels() + for ch, lev in fade_d.items(): + d[ch] = max(lev, d.get(ch, 0)) + return d class Fade(Cue): 'See Cue.__doc__' def __init__(self, channel, starttime, endtime=None, endlevel=0, dur=None, param=None): - 'Only specify an end time or a duration' - if not endtime: - endtime = starttime + dur - else: - dur = endtime - starttime - Cue.__init__(self, "%s -> %f" % (channel, endlevel), starttime, endtime) + 'Fades are simple Cues' + Cue.__init__(self, "%s -> %f" % (channel, endlevel), starttime, endtime, + dur) self.channel = channel self.endlevel = endlevel self.dur = dur @@ -71,6 +82,8 @@ class Fade(Cue): percent = float(elapsed) / self.dur return {self.channel : self.init_level + percent * (self.endlevel - self.init_level)} + def get_end_levels(self): + return {self.channel : self.endlevel} if __name__ == '__main__': f1 = Fade('red', 0, 2, 100) diff --git a/light8/Fader.py b/light8/Fader.py --- a/light8/Fader.py +++ b/light8/Fader.py @@ -1,13 +1,4 @@ from Tix import * -from time import time # time is on my side -from util import subsetdict -from FlyingFader import FlyingFader -from uihelpers import get_selection - -# statuses are: -# stopped - no cue is loaded or cue is stopped -# running - cue is running, not complete -# finished - cue is finished, next is loaded stdfont = ('Arial', 10) @@ -17,178 +8,47 @@ class Fader(Frame): self.master = master self.cues = cues self.scalelevels = scalelevels - self.time_start = 0 self.init_layout() - self.stop() def init_layout(self): Frame.__init__(self, self.master) - # info variables self.cuename = StringVar() self.cuelength = DoubleVar() - self.cuetarget = StringVar() - - # info about a running cue - self.cuestatus = StringVar() # text description - self.cuestatus.set("stopped") - - self.cuepercent = DoubleVar() # percent complete - self.cuepercent.set(0) - self.cuepercent.trace('w', self.update_percent) - self.cuetimeelapse = StringVar() # time elapsed - self.cuetimeelapse.set('0s') - self.cuetimeleft = StringVar() # time left - self.cuetimeleft.set('0s') + self.cueend = StringVar() buttonframe = Frame(self) - topframe = Frame(self) # to contain cue list and infoframe - infoframe = Frame(topframe) - topframe.pack() - self.listbox = ScrolledListBox(topframe, - command=self.update_selection) - self.listbox.listbox.configure({'exportselection' : 0, - 'selectmode' : EXTENDED}) + self.listbox = ScrolledListBox(buttonframe) + self.listbox.listbox.configure({'exportselection' : 0}) for c in self.cues: self.listbox.listbox.insert(END, c.name) - self.listbox.pack(side=LEFT) - self.listbox.listbox.bind("<>", self.update_selection, - add=1) - Button(buttonframe, text="Go", command=self.go, font=stdfont, - bg='green').pack(side=LEFT) - Button(buttonframe, text="Stop", command=self.stop, font=stdfont, - bg='red').pack(side=LEFT) - Button(buttonframe, text="Prev", command=self.prev, - font=stdfont).pack(side=LEFT) - nextbutton = Button(buttonframe, text="Next", command=self.next, - font=stdfont) - # Button(buttonframe, text="Load", command=self.mark_start, bg='grey80', - # font=stdfont).pack(side=LEFT) + self.listbox.pack(side=TOP) + Button(buttonframe, text="Go", command=self.go).pack(side=LEFT) + Button(buttonframe, text="Halt").pack(side=LEFT) + Button(buttonframe, text="Clear").pack(side=LEFT) + infoframe = Frame(self) Label(infoframe, textvariable=self.cuename, - font=('Arial', 12), bg='lightBlue').grid(columnspan=4, sticky=NE+SW) - + font=('Arial', 12), bg='lightBlue').grid(columnspan=2, sticky=NE+SW) Label(infoframe, text="Length", font=stdfont, bg='lightPink').grid(row=1, sticky=NE+SW) Label(infoframe, textvariable=self.cuelength, - font=stdfont).grid(row=1, column=1, columnspan=3, sticky=NE+SW) - + font=stdfont).grid(row=1, column=1, sticky=NE+SW) Label(infoframe, text="Target", font=stdfont, bg='lightPink').grid(row=2, sticky=NE+SW) - Label(infoframe, textvariable=self.cuetarget, - font=stdfont, wraplength=250).grid(row=2, column=1, columnspan=3, - sticky=NE+SW) - - Label(infoframe, text="Status", font=stdfont, - bg='lightPink').grid(row=3, sticky=NE+SW) - Label(infoframe, textvariable=self.cuestatus, - font=stdfont).grid(row=3, column=1, columnspan=3, sticky=NE+SW) - - Label(infoframe, text="Time Elapsed", font=stdfont, - bg='lightPink').grid(row=4, sticky=NE+SW) - Label(infoframe, textvariable=self.cuetimeelapse, - font=stdfont).grid(row=4, column=1, sticky=NE+SW) - - Label(infoframe, text="Time Remain", font=stdfont, - bg='lightPink').grid(row=4, column=2, sticky=NE+SW) - Label(infoframe, textvariable=self.cuetimeleft, - font=stdfont).grid(row=4, column=3, sticky=NE+SW) - - Label(infoframe, text="Percent Complete", font=stdfont, - bg='lightPink').grid(row=5, column=0, sticky=NE+SW) - self.percentlabel = Label(infoframe, - font=stdfont) - self.percentlabel.grid(row=5, column=1, columnspan=3, sticky=NE+SW) - - # s = Scale(infoframe, variable=self.cuepercent, - s = Scale(buttonframe, variable=self.cuepercent, - showvalue=0, length=220, - width=18, sliderlength=30, - to=100,res=.1,from_=0,bd=1, font=stdfont, - orient='horiz') - # s.grid(row=6, columnspan=4, sticky='ew') - nextbutton.pack(side=RIGHT) - s.pack(side=RIGHT, expand=1, fill=X) - + Label(infoframe, textvariable=self.cueend, + font=stdfont).grid(row=2, column=1, sticky=NE+SW) infoframe.pack(side=RIGHT, fill=BOTH, expand=1) - buttonframe.pack(side=BOTTOM, expand=1, fill=X) + buttonframe.pack(side=BOTTOM) self.listbox.listbox.select_set(0) self.update_selection() - def mark_start(self): - self.time_start = time() - startlevels = dict([(k, v.get()) for k, v in self.scalelevels.items()]) - # print "going to mark with", startlevels - self.current.start(startlevels, self.time_start) - def update_percent(self, *args): - if self.cuestatus.get() != 'running': - self.cuestatus.set("running") - self.mark_start() - - percent = self.cuepercent.get() - self.percentlabel.config(text='%.1f%%' % percent) - percent /= 100 - - elapsed = percent * self.current.dur - self.cuetimeelapse.set('%.1fs' % elapsed) - self.cuetimeleft.set('%.1fs' % (self.current.dur - elapsed)) - - newlevels = self.current.get_levels(self.time_start + elapsed) - # print "newlevels", newlevels - for ch, lev in newlevels.items(): - try: - self.scalelevels[ch].set(lev) - except KeyError: - pass - - def update_selection(self, *args): - self.cuestatus.set('stopped') - selection = get_selection(self.listbox.listbox) + def update_selection(self): + print self.listbox.listbox.curselection() + selection = int(self.listbox.listbox.curselection()[0]) # blech self.current = self.cues[selection] self.cuename.set(self.current.name) self.cuelength.set(self.current.dur) - target = ', '.join(['%s -> %.2f' % (n, lev) - for n, lev in self.current.get_end_levels().items()]) - self.cuetarget.set(target) - self.cuetimeelapse.set('0s') - self.cuetimeleft.set('%.1fs' % self.current.dur) - self.cuepercent.set(0) + self.cueend.set(str(self.current.get_end_levels())) def go(self): - self.update_selection() - self.cuestatus.set("running") - self.mark_start() - self.running_loop() - def stop(self): - self.cuestatus.set('stopped') - def prev(self): - self.stop() - selection = get_selection(self.listbox.listbox) - if selection != 0: - self.listbox.listbox.select_clear(selection) - self.listbox.listbox.select_set(selection - 1) - self.update_selection() - self.mark_start() - def next(self): - self.stop() - selection = get_selection(self.listbox.listbox) - if selection != self.listbox.listbox.size() - 1: - self.listbox.listbox.select_clear(selection) - self.listbox.listbox.select_set(selection + 1) - self.update_selection() - self.mark_start() - def running_loop(self): - if self.cuestatus.get() == 'stopped': - return - curtime = time() - elapsed = (curtime - self.time_start) - - if elapsed > self.current.dur: - self.cuestatus.set('stopped') - self.cuepercent.set(100) - - # advance cues if okay - self.next() - return - - self.cuepercent.set(100 * elapsed / self.current.dur) - self.after(30, self.running_loop) + print 'Fade to', self.current.name diff --git a/light8/Subs.py b/light8/Subs.py --- a/light8/Subs.py +++ b/light8/Subs.py @@ -1,6 +1,6 @@ from Patch import * from time import time -from Tkinter import * +from Tix import * from types import TupleType stdfont = ('Arial', 8) @@ -216,7 +216,7 @@ class Sub: def reload_data(dummy): - global subs + global subs, cues if dummy: import ConfigDummy as Config else: @@ -234,5 +234,8 @@ def reload_data(dummy): subs[name] = Sub(name, levels, color=color) # subs = dict([(name, Sub(levels)) for name, levels in Config.subs.items()]) + + cues = Config.cues + def longestsubname(): return max([len(x) for x in subs.keys()]) diff --git a/light8/Xfader.py b/light8/Xfader.py --- a/light8/Xfader.py +++ b/light8/Xfader.py @@ -1,4 +1,4 @@ -from Tkinter import * +from Tix import * from __future__ import division class Xfader(Canvas): diff --git a/light8/panels.py b/light8/panels.py --- a/light8/panels.py +++ b/light8/panels.py @@ -1,7 +1,7 @@ """some of the panels""" from __future__ import nested_scopes -from Tkinter import * +from Tix import * from uihelpers import * import Patch from FlyingFader import FlyingFader diff --git a/light8/rsn.py b/light8/rsn.py --- a/light8/rsn.py +++ b/light8/rsn.py @@ -1,7 +1,7 @@ #!/usr/bin/env python from __future__ import nested_scopes -from Tkinter import * +from Tix import * from time import sleep from signal import signal, SIGINT import sys, cPickle @@ -11,8 +11,10 @@ from uihelpers import * from panels import * from Xfader import * from subediting import Subediting +from Fader import Fader import stage + if len(sys.argv) >= 2: DUMMY = 0 print "This is the real thing, baby" @@ -68,7 +70,8 @@ class Lightboard: effect_tl = toplevelat(462,4) self.subpanels = Subpanels(sub_tl, effect_tl, self.scalelevels, Subs, - self.xfader, self.changelevel, self.subediting, Subs.longestsubname()) + self.xfader, self.changelevel, self.subediting, + Subs.longestsubname()) leveldisplay_tl = toplevelat(873,400) leveldisplay_tl.bind('', sys.exit) @@ -97,6 +100,10 @@ class Lightboard: self.xfader.setupwidget(xf) controlpanel.pack() + cuefader_tl = toplevelat(98, 480) + cuefader = Fader(cuefader_tl, Subs.cues, self.scalelevels) + cuefader.pack() + def refresh(self, *args): 'rebuild interface, reload data' get_data() diff --git a/light8/stage.py b/light8/stage.py --- a/light8/stage.py +++ b/light8/stage.py @@ -1,5 +1,4 @@ -from Tkinter import * - +from Tix import * def printevent(ev): for k in dir(ev): @@ -7,10 +6,8 @@ def printevent(ev): print k,getattr(ev,k) print "" - textstyle={'font':'arial 7','fill':'white'} - class Stage(Canvas): """a fancy widget that shows light locations (and optionally their diff --git a/light8/uihelpers.py b/light8/uihelpers.py --- a/light8/uihelpers.py +++ b/light8/uihelpers.py @@ -1,6 +1,8 @@ """all the tiny tk helper functions""" + from __future__ import nested_scopes from Tkinter import * +from Tix import * from types import StringType def make_frame(parent): @@ -14,11 +16,11 @@ def bindkeys(root,key, func): w.bind(key, func) def toplevelat(x,y,w=None,h=None): - tl=Toplevel() + tl = Toplevel() if w and h: - tl.wm_geometry("%dx%d+%d+%d"%(w,h,x,y)) + tl.wm_geometry("%dx%d+%d+%d" % (w,h,x,y)) else: - tl.wm_geometry("+%d+%d"%(x,y)) + tl.wm_geometry("+%d+%d" % (x,y)) return tl def toggle_slider(s): diff --git a/light8/util.py b/light8/util.py --- a/light8/util.py +++ b/light8/util.py @@ -15,8 +15,8 @@ def scaledict(d,scl): # class Setting that scales, maxes def subsetdict(d, dkeys, default=0): - 'Subset of dictionary d: only the keys in dkeys' - # print 'd', d, 'dkeys', dkeys + """Subset of dictionary d: only the keys in dkeys. If you plan on omitting + keys, make sure you like the default.""" newd = {} # dirty variables! for k in dkeys: newd[k] = d.get(k, default)